aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.git-blame-ignore-revs2
-rw-r--r--Makefile.inc15
-rw-r--r--UPDATING11
-rw-r--r--bin/date/date.18
-rw-r--r--bin/sh/Makefile2
-rw-r--r--bin/timeout/tests/timeout_test.sh2
-rw-r--r--contrib/jemalloc/INSTALL.md425
-rw-r--r--contrib/jemalloc/Makefile.in627
-rw-r--r--contrib/jemalloc/TUNING.md133
-rw-r--r--contrib/jemalloc/bin/jeprof.in5629
-rwxr-xr-xcontrib/jemalloc/build-aux/config.guess1466
-rwxr-xr-xcontrib/jemalloc/build-aux/config.sub1829
-rw-r--r--contrib/jemalloc/configure.ac2410
-rw-r--r--contrib/jemalloc/doc/jemalloc.xml.in3542
-rw-r--r--contrib/jemalloc/include/jemalloc/internal/jemalloc_internal_defs.h.in370
-rw-r--r--contrib/jemalloc/include/jemalloc/internal/jemalloc_preamble.h.in216
-rw-r--r--contrib/jemalloc/include/jemalloc/internal/tsd_win.h143
-rw-r--r--contrib/jemalloc/include/jemalloc/jemalloc_defs.h.in52
-rw-r--r--contrib/jemalloc/include/jemalloc/jemalloc_macros.h.in133
-rw-r--r--contrib/jemalloc/include/jemalloc/jemalloc_protos.h.in70
-rw-r--r--contrib/jemalloc/m4/ax_cxx_compile_stdcxx.m4566
-rwxr-xr-xcontrib/jemalloc/scripts/gen_run_tests.py130
-rwxr-xr-xcontrib/jemalloc/scripts/gen_travis.py153
-rw-r--r--contrib/jemalloc/src/jemalloc_cpp.cpp145
-rw-r--r--contrib/tzcode/localtime.c10
-rw-r--r--kerberos5/lib/Makefile.inc2
-rw-r--r--kerberos5/lib/libasn1/Makefile2
-rw-r--r--kerberos5/lib/libgssapi_krb5/Makefile2
-rw-r--r--kerberos5/lib/libgssapi_ntlm/Makefile2
-rw-r--r--kerberos5/lib/libgssapi_spnego/Makefile2
-rw-r--r--kerberos5/lib/libhdb/Makefile2
-rw-r--r--kerberos5/lib/libheimbase/Makefile2
-rw-r--r--kerberos5/lib/libheimipcc/Makefile2
-rw-r--r--kerberos5/lib/libheimipcs/Makefile2
-rw-r--r--kerberos5/lib/libheimntlm/Makefile2
-rw-r--r--kerberos5/lib/libhx509/Makefile2
-rw-r--r--kerberos5/lib/libkadm5clnt/Makefile2
-rw-r--r--kerberos5/lib/libkadm5srv/Makefile2
-rw-r--r--kerberos5/lib/libkafs5/Makefile2
-rw-r--r--kerberos5/lib/libkdc/Makefile2
-rw-r--r--kerberos5/lib/libkrb5/Makefile2
-rw-r--r--kerberos5/lib/libroken/Makefile2
-rw-r--r--kerberos5/lib/libsl/Makefile2
-rw-r--r--kerberos5/lib/libvers/Makefile2
-rw-r--r--kerberos5/lib/libwind/Makefile2
-rw-r--r--lib/clang/freebsd_cc_version.h2
-rw-r--r--lib/clang/include/lld/Common/Version.inc2
-rw-r--r--lib/libc/tests/stdtime/detect_tz_changes_test.c60
-rw-r--r--lib/libcom_err/Makefile3
-rw-r--r--lib/libgpio/Makefile4
-rw-r--r--lib/libgpio/gpio.368
-rw-r--r--lib/libgpio/gpio.c20
-rw-r--r--lib/libgpio/libgpio.h13
-rw-r--r--lib/libifconfig/Makefile1
-rw-r--r--lib/libifconfig/libifconfig.h11
-rw-r--r--lib/libifconfig/libifconfig_nl.c72
-rw-r--r--lib/libjail/jail.c64
-rw-r--r--lib/libpfctl/libpfctl.c6
-rw-r--r--lib/libpfctl/libpfctl.h4
-rw-r--r--lib/libsys/Symbol.sys.map2
-rw-r--r--lib/libsys/_libsys.h4
-rw-r--r--lib/libsys/jail.2267
-rw-r--r--lib/libsys/kqueue.258
-rw-r--r--lib/libsys/syscalls.map4
-rw-r--r--libexec/rc/rc.conf8
-rw-r--r--libexec/rc/rc.d/Makefile1
-rwxr-xr-xlibexec/rc/rc.d/bluetooth13
-rwxr-xr-xlibexec/rc/rc.d/moused1
-rwxr-xr-xlibexec/rc/rc.d/msconvd61
-rwxr-xr-xlibexec/rc/rc.d/serial13
-rwxr-xr-xlibexec/rc/rc.d/syscons2
-rw-r--r--release/tools/azure.conf3
-rw-r--r--release/tools/ec2.conf3
-rw-r--r--release/tools/vagrant.conf3
-rw-r--r--sbin/comcontrol/comcontrol.818
-rw-r--r--sbin/comcontrol/comcontrol.c30
-rw-r--r--sbin/pfctl/parse.y54
-rw-r--r--sbin/pfctl/pfctl_parser.c14
-rw-r--r--sbin/pfctl/tests/files/pf1073.in1
-rw-r--r--sbin/pfctl/tests/files/pf1073.ok1
-rw-r--r--sbin/pfctl/tests/files/pf1074.fail1
-rw-r--r--sbin/pfctl/tests/files/pf1074.in1
-rw-r--r--sbin/pfctl/tests/pfctl_test_list.inc2
-rw-r--r--sbin/recoverdisk/recoverdisk.16
-rw-r--r--sbin/recoverdisk/recoverdisk.c72
-rw-r--r--sbin/veriexec/veriexec.82
-rw-r--r--secure/lib/libcrypto/Makefile3
-rw-r--r--secure/lib/libcrypto/modules/legacy/Makefile7
-rw-r--r--secure/lib/libssl/Makefile2
-rw-r--r--share/man/man4/Makefile3
-rw-r--r--share/man/man4/dtrace_lockstat.44
-rw-r--r--share/man/man4/epair.425
-rw-r--r--share/man/man4/pci.413
-rw-r--r--share/man/man4/syncache.429
-rw-r--r--share/man/man4/tcp.410
-rw-r--r--share/man/man4/umb.43
-rw-r--r--share/man/man4/vtnet.429
-rw-r--r--share/man/man5/pf.conf.518
-rw-r--r--share/man/man7/arch.75
-rw-r--r--share/sendmail/Makefile4
-rw-r--r--share/vt/fonts/gallant.hex4121
-rw-r--r--stand/defaults/loader.conf.55
-rw-r--r--sys/amd64/conf/GENERIC2
-rw-r--r--sys/arm/arm/generic_timer.c22
-rw-r--r--sys/arm64/arm64/cpu_feat.c29
-rw-r--r--sys/arm64/arm64/elf32_machdep.c2
-rw-r--r--sys/arm64/arm64/identcpu.c51
-rw-r--r--sys/arm64/arm64/machdep.c23
-rw-r--r--sys/arm64/arm64/pmap.c140
-rw-r--r--sys/arm64/arm64/ptrauth.c23
-rw-r--r--sys/arm64/conf/std.arm641
-rw-r--r--sys/arm64/include/cpu.h26
-rw-r--r--sys/arm64/include/cpu_feat.h46
-rw-r--r--sys/arm64/include/pmap.h3
-rw-r--r--sys/arm64/include/proc.h1
-rw-r--r--sys/compat/freebsd32/freebsd32_syscall.h4
-rw-r--r--sys/compat/freebsd32/freebsd32_syscalls.c2
-rw-r--r--sys/compat/freebsd32/freebsd32_sysent.c2
-rw-r--r--sys/compat/freebsd32/freebsd32_systrace_args.c44
-rw-r--r--sys/compat/lindebugfs/lindebugfs.c8
-rw-r--r--sys/compat/linprocfs/linprocfs.c256
-rw-r--r--sys/compat/linsysfs/linsysfs.c159
-rw-r--r--sys/compat/linsysfs/linsysfs_net.c24
-rw-r--r--sys/compat/linuxkpi/common/include/linux/ieee80211.h28
-rw-r--r--sys/compat/linuxkpi/common/include/linux/skbuff.h18
-rw-r--r--sys/compat/linuxkpi/common/include/linux/string_helpers.h2
-rw-r--r--sys/compat/linuxkpi/common/include/net/mac80211.h2
-rw-r--r--sys/compat/linuxkpi/common/src/linux_80211.c581
-rw-r--r--sys/compat/linuxkpi/common/src/linux_80211.h21
-rw-r--r--sys/conf/files1
-rw-r--r--sys/conf/newvers.sh4
-rw-r--r--sys/conf/options2
-rw-r--r--sys/contrib/dev/rtw88/main.c57
-rw-r--r--sys/contrib/dev/rtw89/fw.c4
-rw-r--r--sys/dev/ath/ath_rate/sample/sample.c8
-rw-r--r--sys/dev/ath/if_ath_tx_ht.c6
-rw-r--r--sys/dev/cxgbe/t4_main.c2
-rw-r--r--sys/dev/cyapa/cyapa.c95
-rw-r--r--sys/dev/mpr/mpr.c10
-rw-r--r--sys/dev/mpr/mpr_mapping.c18
-rw-r--r--sys/dev/mpr/mprvar.h1
-rw-r--r--sys/dev/mwl/if_mwl.c2
-rw-r--r--sys/dev/nvme/nvme_ctrlr.c98
-rw-r--r--sys/dev/nvme/nvme_util.c23
-rw-r--r--sys/dev/pci/pci_user.c121
-rw-r--r--sys/dev/rtwn/rtl8812a/r12a_tx.c4
-rw-r--r--sys/dev/sound/pci/hda/hdac.c10
-rw-r--r--sys/dev/tpm/tpm_tis_core.c7
-rw-r--r--sys/dev/ufshci/ufshci.h69
-rw-r--r--sys/dev/ufshci/ufshci_ctrlr.c45
-rw-r--r--sys/dev/ufshci/ufshci_dev.c355
-rw-r--r--sys/dev/ufshci/ufshci_pci.c3
-rw-r--r--sys/dev/ufshci/ufshci_private.h15
-rw-r--r--sys/dev/ufshci/ufshci_reg.h2
-rw-r--r--sys/dev/ufshci/ufshci_sysctl.c20
-rw-r--r--sys/dev/ufshci/ufshci_uic_cmd.c19
-rw-r--r--sys/dev/usb/controller/xhci.c85
-rw-r--r--sys/dev/usb/controller/xhcireg.h5
-rw-r--r--sys/dev/usb/net/if_umb.c4
-rw-r--r--sys/dev/usb/usb_hub.c3
-rw-r--r--sys/dev/virtio/network/if_vtnet.c231
-rw-r--r--sys/dev/virtio/network/if_vtnetvar.h2
-rw-r--r--sys/fs/nfsserver/nfs_nfsdport.c3
-rw-r--r--sys/fs/procfs/procfs.c68
-rw-r--r--sys/fs/pseudofs/pseudofs.c69
-rw-r--r--sys/fs/pseudofs/pseudofs.h19
-rw-r--r--sys/fs/tarfs/tarfs_vnops.c4
-rw-r--r--sys/kern/init_main.c9
-rw-r--r--sys/kern/init_sysent.c2
-rw-r--r--sys/kern/kern_descrip.c2
-rw-r--r--sys/kern/kern_event.c139
-rw-r--r--sys/kern/kern_jail.c460
-rw-r--r--sys/kern/kern_jaildesc.c337
-rw-r--r--sys/kern/kern_thread.c6
-rw-r--r--sys/kern/subr_witness.c134
-rw-r--r--sys/kern/syscalls.c2
-rw-r--r--sys/kern/syscalls.master10
-rw-r--r--sys/kern/systrace_args.c44
-rw-r--r--sys/kern/uipc_usrreq.c4
-rw-r--r--sys/kern/vfs_init.c21
-rw-r--r--sys/kern/vfs_subr.c8
-rw-r--r--sys/modules/sound/driver/hda/Makefile4
-rw-r--r--sys/net/if.c26
-rw-r--r--sys/net/if_bridge.c34
-rw-r--r--sys/net/if_epair.c61
-rw-r--r--sys/net/if_ethersubr.c2
-rw-r--r--sys/net/iflib.c13
-rw-r--r--sys/net/pfvar.h9
-rw-r--r--sys/net80211/ieee80211_ddb.c2
-rw-r--r--sys/net80211/ieee80211_freebsd.h11
-rw-r--r--sys/net80211/ieee80211_ht.c16
-rw-r--r--sys/net80211/ieee80211_node.c4
-rw-r--r--sys/net80211/ieee80211_node.h34
-rw-r--r--sys/net80211/ieee80211_phy.c30
-rw-r--r--sys/net80211/ieee80211_phy.h8
-rw-r--r--sys/net80211/ieee80211_sta.c2
-rw-r--r--sys/net80211/ieee80211_vht.c20
-rw-r--r--sys/net80211/ieee80211_vht.h4
-rw-r--r--sys/netgraph/ng_parse.c4
-rw-r--r--sys/netinet/in.c15
-rw-r--r--sys/netinet/tcp_sack.c21
-rw-r--r--sys/netinet/tcp_syncache.c103
-rw-r--r--sys/netinet/udp_usrreq.c45
-rw-r--r--sys/netinet6/in6.c21
-rw-r--r--sys/netpfil/pf/if_pfsync.c16
-rw-r--r--sys/netpfil/pf/pf.c105
-rw-r--r--sys/netpfil/pf/pf.h1
-rw-r--r--sys/netpfil/pf/pf_ioctl.c180
-rw-r--r--sys/netpfil/pf/pf_lb.c151
-rw-r--r--sys/netpfil/pf/pf_nl.c10
-rw-r--r--sys/netpfil/pf/pf_nl.h2
-rw-r--r--sys/netpfil/pf/pf_nv.c7
-rw-r--r--sys/netpfil/pf/pf_ruleset.c10
-rw-r--r--sys/sys/event.h19
-rw-r--r--sys/sys/exterrvar.h2
-rw-r--r--sys/sys/file.h1
-rw-r--r--sys/sys/jail.h20
-rw-r--r--sys/sys/jaildesc.h85
-rw-r--r--sys/sys/param.h2
-rw-r--r--sys/sys/pciio.h5
-rw-r--r--sys/sys/syscall.h4
-rw-r--r--sys/sys/syscall.mk4
-rw-r--r--sys/sys/sysproto.h10
-rw-r--r--sys/sys/ttycom.h4
-rw-r--r--sys/sys/user.h4
-rw-r--r--sys/vm/vm_extern.h2
-rw-r--r--sys/vm/vm_fault.c4
-rw-r--r--tests/atf_python/sys/net/vnet.py1
-rw-r--r--tests/sys/common/vnet.subr5
-rw-r--r--tests/sys/kern/unix_stream.c24
-rwxr-xr-xtests/sys/net/if_bridge_test.sh19
-rw-r--r--tests/sys/net/if_ovpn/if_ovpn.sh2
-rw-r--r--tests/sys/net/if_ovpn/utils.subr19
-rw-r--r--tests/sys/netpfil/pf/igmp.py6
-rw-r--r--tests/sys/netpfil/pf/route_to.sh716
-rw-r--r--tests/sys/netpfil/pf/sctp.sh3
-rwxr-xr-xtests/sys/netpfil/pf/src_track.sh36
-rw-r--r--tests/sys/netpfil/pf/utils.subr4
-rw-r--r--tools/build/mk/OptionalObsoleteFiles.inc7
-rw-r--r--tools/coccinelle/pseudofs-create.cocci35
-rw-r--r--usr.bin/awk/awk.1136
-rw-r--r--usr.bin/mandoc/Makefile2
-rw-r--r--usr.bin/netstat/inet.c13
-rwxr-xr-xusr.bin/patch/tests/unified_patch_test.sh18
-rw-r--r--usr.bin/w/pr_time.c26
-rw-r--r--usr.sbin/bhyve/rfb.c19
-rw-r--r--usr.sbin/ctld/ctld.hh6
-rw-r--r--usr.sbin/ctld/iscsi.hh2
-rw-r--r--usr.sbin/devinfo/devinfo.843
-rw-r--r--usr.sbin/fwget/pci/pci6
-rw-r--r--usr.sbin/fwget/pci/pci_video_amd11
-rw-r--r--usr.sbin/moused/Makefile12
-rw-r--r--usr.sbin/moused/Makefile.depend17
-rw-r--r--usr.sbin/moused/moused/Makefile28
-rw-r--r--usr.sbin/moused/moused/event-names.h1656
-rw-r--r--usr.sbin/moused/moused/moused.8538
-rw-r--r--usr.sbin/moused/moused/moused.c3205
-rw-r--r--usr.sbin/moused/moused/moused.conf43
-rw-r--r--usr.sbin/moused/moused/moused.conf.5422
-rw-r--r--usr.sbin/moused/moused/quirks.c2033
-rw-r--r--usr.sbin/moused/moused/quirks.h369
-rw-r--r--usr.sbin/moused/moused/quirks/5-generic-touchpad.quirks9
-rw-r--r--usr.sbin/moused/moused/util-evdev.c173
-rw-r--r--usr.sbin/moused/moused/util-evdev.h35
-rw-r--r--usr.sbin/moused/moused/util-list.c86
-rw-r--r--usr.sbin/moused/moused/util-list.h194
-rw-r--r--usr.sbin/moused/moused/util.c423
-rw-r--r--usr.sbin/moused/moused/util.h413
-rw-r--r--usr.sbin/moused/msconvd/Makefile8
-rw-r--r--usr.sbin/moused/msconvd/msconvd.8 (renamed from usr.sbin/moused/moused.8)395
-rw-r--r--usr.sbin/moused/msconvd/msconvd.c (renamed from usr.sbin/moused/moused.c)1212
-rw-r--r--usr.sbin/newsyslog/newsyslog.822
-rw-r--r--usr.sbin/newsyslog/newsyslog.c29
-rw-r--r--usr.sbin/newsyslog/newsyslog.conf.584
-rw-r--r--usr.sbin/ngctl/Makefile5
-rw-r--r--usr.sbin/ngctl/main.c41
-rw-r--r--usr.sbin/ngctl/ngctl.825
-rw-r--r--usr.sbin/tcpdump/Makefile.inc4
-rw-r--r--usr.sbin/tcpdump/tcpdump/Makefile14
-rw-r--r--usr.sbin/vidcontrol/vidcontrol.115
280 files changed, 20352 insertions, 21021 deletions
diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs
index 31b6fb8eb33f..7b832c253b56 100644
--- a/.git-blame-ignore-revs
+++ b/.git-blame-ignore-revs
@@ -8,6 +8,8 @@
#
# This file is sorted in git log order (newest commits first).
+# witness white space cleanup and style(9) tweeks
+f5377665253b2b107ee8a4690ad2e6682375b304
# style fixes for device_if.m
ab43dbe0187ecdf1697726170fd4e19c373effcc
# iflib style tweaks
diff --git a/Makefile.inc1 b/Makefile.inc1
index 3bbc4afed3fd..01866f949e49 100644
--- a/Makefile.inc1
+++ b/Makefile.inc1
@@ -2714,9 +2714,10 @@ _basic_bootstrap_tools+=usr.sbin/tzsetup
# certctl is needed as an install tool. libcrypto is rather heavy, so we'll
# build that alongside it only for platforms that don't expose headers for
-# OpenSSL, like macOS.
+# OpenSSL, like macOS, or when building on releases with OpenSSL 1.x.
.if ${MK_CAROOT} != "no" && ${MK_OPENSSL} != "no"
-.if ${.MAKE.OS} == "Darwin"
+.if ${.MAKE.OS} == "Darwin" || \
+ (${.MAKE.OS} == "FreeBSD" && ${BOOTSTRAPPING} < 1400000)
_bootstrap_libcrypto=secure/lib/libcrypto
${_bt}-usr.sbin/certctl: ${_bt}-secure/lib/libcrypto
.endif
diff --git a/UPDATING b/UPDATING
index 34f71af5464e..57f6b2e66387 100644
--- a/UPDATING
+++ b/UPDATING
@@ -12,8 +12,8 @@ Items affecting the ports and packages system can be found in
/usr/ports/UPDATING. Please read that file before updating system packages
and/or ports.
-NOTE TO PEOPLE WHO THINK THAT FreeBSD 15.x IS SLOW:
- FreeBSD 15.x has many debugging features turned on, in both the kernel
+NOTE TO PEOPLE WHO THINK THAT FreeBSD 16.x IS SLOW:
+ FreeBSD 16.x has many debugging features turned on, in both the kernel
and userland. These features attempt to detect incorrect use of
system primitives, and encourage loud failure through extra sanity
checking and fail stop semantics. They also substantially impact
@@ -27,6 +27,13 @@ NOTE TO PEOPLE WHO THINK THAT FreeBSD 15.x IS SLOW:
world, or to merely disable the most expensive debugging functionality
at runtime, run "ln -s 'abort:false,junk:false' /etc/malloc.conf".)
+20250905:
+ FreeBSD 16.0-CURRENT.
+
+20250903:
+ The BLOAT_KERNEL_WITH_EXTERR kernel config option has been renamed to
+ EXTERR_STRINGS.
+
20250827:
The names of pkg repositories defined in /etc/pkg/FreeBSD.conf have
changed: "FreeBSD" is now "FreeBSD-ports", and "FreeBSD-kmods" is now
diff --git a/bin/date/date.1 b/bin/date/date.1
index 62d28a7df0a0..b86a660a924d 100644
--- a/bin/date/date.1
+++ b/bin/date/date.1
@@ -29,7 +29,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd September 10, 2024
+.Dd September 1, 2025
.Dt DATE 1
.Os
.Sh NAME
@@ -129,7 +129,7 @@ format.
Parsing is done using
.Xr strptime 3 .
.It Fl I Ns Op Ar FMT
-Use
+Use extended
.St -iso8601
output format.
.Ar FMT
@@ -154,9 +154,9 @@ is
.Cm seconds ,
or
.Cm ns Pc ,
-the
+the extended
.St -iso8601
-format includes the timezone.
+format includes the timezone offset.
.It Fl j
Do not try to set the date.
This allows you to use the
diff --git a/bin/sh/Makefile b/bin/sh/Makefile
index 087dbf40c3bd..916bb88b57fa 100644
--- a/bin/sh/Makefile
+++ b/bin/sh/Makefile
@@ -74,6 +74,6 @@ beforeinstallconfig:
LINKMODE=${CONFMODE}
afterinstallconfig:
- ${INSTALL_LINK} ${TAG_ARGS} ${DESTDIR}/root/.profile ${DESTDIR}/.profile
+ ${INSTALL_LINK} ${TAG_ARGS:D${TAG_ARGS},config} ${DESTDIR}/root/.profile ${DESTDIR}/.profile
.include <bsd.prog.mk>
diff --git a/bin/timeout/tests/timeout_test.sh b/bin/timeout/tests/timeout_test.sh
index b1bf69968e84..88dbaa808043 100644
--- a/bin/timeout/tests/timeout_test.sh
+++ b/bin/timeout/tests/timeout_test.sh
@@ -1,3 +1,5 @@
+# SPDX-License-Identifier: BSD-2-Clause
+# Copyright (c) 2014 Baptiste Daroussin <bapt@FreeBSD.org>
atf_test_case nominal
nominal_head()
diff --git a/contrib/jemalloc/INSTALL.md b/contrib/jemalloc/INSTALL.md
index 9701364041c8..90da718d2b6a 100644
--- a/contrib/jemalloc/INSTALL.md
+++ b/contrib/jemalloc/INSTALL.md
@@ -1,4 +1,3 @@
-<<<<<<< HEAD
Building and installing a packaged release of jemalloc can be as simple as
typing the following while in the root directory of the source tree:
@@ -423,427 +422,3 @@ can be used to view the html manual. The roff manual page can be formatted
prior to installation via the following command:
nroff -man -t doc/jemalloc.3
-||||||| dec341af7695
-=======
-Building and installing a packaged release of jemalloc can be as simple as
-typing the following while in the root directory of the source tree:
-
- ./configure
- make
- make install
-
-If building from unpackaged developer sources, the simplest command sequence
-that might work is:
-
- ./autogen.sh
- make dist
- make
- make install
-
-Note that documentation is not built by the default target because doing so
-would create a dependency on xsltproc in packaged releases, hence the
-requirement to either run 'make dist' or avoid installing docs via the various
-install_* targets documented below.
-
-
-## Advanced configuration
-
-The 'configure' script supports numerous options that allow control of which
-functionality is enabled, where jemalloc is installed, etc. Optionally, pass
-any of the following arguments (not a definitive list) to 'configure':
-
-* `--help`
-
- Print a definitive list of options.
-
-* `--prefix=<install-root-dir>`
-
- Set the base directory in which to install. For example:
-
- ./configure --prefix=/usr/local
-
- will cause files to be installed into /usr/local/include, /usr/local/lib,
- and /usr/local/man.
-
-* `--with-version=(<major>.<minor>.<bugfix>-<nrev>-g<gid>|VERSION)`
-
- The VERSION file is mandatory for successful configuration, and the
- following steps are taken to assure its presence:
- 1) If --with-version=<major>.<minor>.<bugfix>-<nrev>-g<gid> is specified,
- generate VERSION using the specified value.
- 2) If --with-version is not specified in either form and the source
- directory is inside a git repository, try to generate VERSION via 'git
- describe' invocations that pattern-match release tags.
- 3) If VERSION is missing, generate it with a bogus version:
- 0.0.0-0-g0000000000000000000000000000000000000000
-
- Note that --with-version=VERSION bypasses (1) and (2), which simplifies
- VERSION configuration when embedding a jemalloc release into another
- project's git repository.
-
-* `--with-rpath=<colon-separated-rpath>`
-
- Embed one or more library paths, so that libjemalloc can find the libraries
- it is linked to. This works only on ELF-based systems.
-
-* `--with-mangling=<map>`
-
- Mangle public symbols specified in <map> which is a comma-separated list of
- name:mangled pairs.
-
- For example, to use ld's --wrap option as an alternative method for
- overriding libc's malloc implementation, specify something like:
-
- --with-mangling=malloc:__wrap_malloc,free:__wrap_free[...]
-
- Note that mangling happens prior to application of the prefix specified by
- --with-jemalloc-prefix, and mangled symbols are then ignored when applying
- the prefix.
-
-* `--with-jemalloc-prefix=<prefix>`
-
- Prefix all public APIs with <prefix>. For example, if <prefix> is
- "prefix_", API changes like the following occur:
-
- malloc() --> prefix_malloc()
- malloc_conf --> prefix_malloc_conf
- /etc/malloc.conf --> /etc/prefix_malloc.conf
- MALLOC_CONF --> PREFIX_MALLOC_CONF
-
- This makes it possible to use jemalloc at the same time as the system
- allocator, or even to use multiple copies of jemalloc simultaneously.
-
- By default, the prefix is "", except on OS X, where it is "je_". On OS X,
- jemalloc overlays the default malloc zone, but makes no attempt to actually
- replace the "malloc", "calloc", etc. symbols.
-
-* `--without-export`
-
- Don't export public APIs. This can be useful when building jemalloc as a
- static library, or to avoid exporting public APIs when using the zone
- allocator on OSX.
-
-* `--with-private-namespace=<prefix>`
-
- Prefix all library-private APIs with <prefix>je_. For shared libraries,
- symbol visibility mechanisms prevent these symbols from being exported, but
- for static libraries, naming collisions are a real possibility. By
- default, <prefix> is empty, which results in a symbol prefix of je_ .
-
-* `--with-install-suffix=<suffix>`
-
- Append <suffix> to the base name of all installed files, such that multiple
- versions of jemalloc can coexist in the same installation directory. For
- example, libjemalloc.so.0 becomes libjemalloc<suffix>.so.0.
-
-* `--with-malloc-conf=<malloc_conf>`
-
- Embed `<malloc_conf>` as a run-time options string that is processed prior to
- the malloc_conf global variable, the /etc/malloc.conf symlink, and the
- MALLOC_CONF environment variable. For example, to change the default decay
- time to 30 seconds:
-
- --with-malloc-conf=decay_ms:30000
-
-* `--enable-debug`
-
- Enable assertions and validation code. This incurs a substantial
- performance hit, but is very useful during application development.
-
-* `--disable-stats`
-
- Disable statistics gathering functionality. See the "opt.stats_print"
- option documentation for usage details.
-
-* `--enable-prof`
-
- Enable heap profiling and leak detection functionality. See the "opt.prof"
- option documentation for usage details. When enabled, there are several
- approaches to backtracing, and the configure script chooses the first one
- in the following list that appears to function correctly:
-
- + libunwind (requires --enable-prof-libunwind)
- + libgcc (unless --disable-prof-libgcc)
- + gcc intrinsics (unless --disable-prof-gcc)
-
-* `--enable-prof-libunwind`
-
- Use the libunwind library (http://www.nongnu.org/libunwind/) for stack
- backtracing.
-
-* `--disable-prof-libgcc`
-
- Disable the use of libgcc's backtracing functionality.
-
-* `--disable-prof-gcc`
-
- Disable the use of gcc intrinsics for backtracing.
-
-* `--with-static-libunwind=<libunwind.a>`
-
- Statically link against the specified libunwind.a rather than dynamically
- linking with -lunwind.
-
-* `--disable-fill`
-
- Disable support for junk/zero filling of memory. See the "opt.junk" and
- "opt.zero" option documentation for usage details.
-
-* `--disable-zone-allocator`
-
- Disable zone allocator for Darwin. This means jemalloc won't be hooked as
- the default allocator on OSX/iOS.
-
-* `--enable-utrace`
-
- Enable utrace(2)-based allocation tracing. This feature is not broadly
- portable (FreeBSD has it, but Linux and OS X do not).
-
-* `--enable-xmalloc`
-
- Enable support for optional immediate termination due to out-of-memory
- errors, as is commonly implemented by "xmalloc" wrapper function for malloc.
- See the "opt.xmalloc" option documentation for usage details.
-
-* `--enable-lazy-lock`
-
- Enable code that wraps pthread_create() to detect when an application
- switches from single-threaded to multi-threaded mode, so that it can avoid
- mutex locking/unlocking operations while in single-threaded mode. In
- practice, this feature usually has little impact on performance unless
- thread-specific caching is disabled.
-
-* `--disable-cache-oblivious`
-
- Disable cache-oblivious large allocation alignment for large allocation
- requests with no alignment constraints. If this feature is disabled, all
- large allocations are page-aligned as an implementation artifact, which can
- severely harm CPU cache utilization. However, the cache-oblivious layout
- comes at the cost of one extra page per large allocation, which in the
- most extreme case increases physical memory usage for the 16 KiB size class
- to 20 KiB.
-
-* `--disable-syscall`
-
- Disable use of syscall(2) rather than {open,read,write,close}(2). This is
- intended as a workaround for systems that place security limitations on
- syscall(2).
-
-* `--disable-cxx`
-
- Disable C++ integration. This will cause new and delete operator
- implementations to be omitted.
-
-* `--with-xslroot=<path>`
-
- Specify where to find DocBook XSL stylesheets when building the
- documentation.
-
-* `--with-lg-page=<lg-page>`
-
- Specify the base 2 log of the allocator page size, which must in turn be at
- least as large as the system page size. By default the configure script
- determines the host's page size and sets the allocator page size equal to
- the system page size, so this option need not be specified unless the
- system page size may change between configuration and execution, e.g. when
- cross compiling.
-
-* `--with-lg-hugepage=<lg-hugepage>`
-
- Specify the base 2 log of the system huge page size. This option is useful
- when cross compiling, or when overriding the default for systems that do
- not explicitly support huge pages.
-
-* `--with-lg-quantum=<lg-quantum>`
-
- Specify the base 2 log of the minimum allocation alignment. jemalloc needs
- to know the minimum alignment that meets the following C standard
- requirement (quoted from the April 12, 2011 draft of the C11 standard):
-
- > The pointer returned if the allocation succeeds is suitably aligned so
- that it may be assigned to a pointer to any type of object with a
- fundamental alignment requirement and then used to access such an object
- or an array of such objects in the space allocated [...]
-
- This setting is architecture-specific, and although jemalloc includes known
- safe values for the most commonly used modern architectures, there is a
- wrinkle related to GNU libc (glibc) that may impact your choice of
- <lg-quantum>. On most modern architectures, this mandates 16-byte
- alignment (<lg-quantum>=4), but the glibc developers chose not to meet this
- requirement for performance reasons. An old discussion can be found at
- <https://sourceware.org/bugzilla/show_bug.cgi?id=206> . Unlike glibc,
- jemalloc does follow the C standard by default (caveat: jemalloc
- technically cheats for size classes smaller than the quantum), but the fact
- that Linux systems already work around this allocator noncompliance means
- that it is generally safe in practice to let jemalloc's minimum alignment
- follow glibc's lead. If you specify `--with-lg-quantum=3` during
- configuration, jemalloc will provide additional size classes that are not
- 16-byte-aligned (24, 40, and 56).
-
-* `--with-lg-vaddr=<lg-vaddr>`
-
- Specify the number of significant virtual address bits. By default, the
- configure script attempts to detect virtual address size on those platforms
- where it knows how, and picks a default otherwise. This option may be
- useful when cross-compiling.
-
-* `--disable-initial-exec-tls`
-
- Disable the initial-exec TLS model for jemalloc's internal thread-local
- storage (on those platforms that support explicit settings). This can allow
- jemalloc to be dynamically loaded after program startup (e.g. using dlopen).
- Note that in this case, there will be two malloc implementations operating
- in the same process, which will almost certainly result in confusing runtime
- crashes if pointers leak from one implementation to the other.
-
-* `--disable-libdl`
-
- Disable the usage of libdl, namely dlsym(3) which is required by the lazy
- lock option. This can allow building static binaries.
-
-The following environment variables (not a definitive list) impact configure's
-behavior:
-
-* `CFLAGS="?"`
-* `CXXFLAGS="?"`
-
- Pass these flags to the C/C++ compiler. Any flags set by the configure
- script are prepended, which means explicitly set flags generally take
- precedence. Take care when specifying flags such as -Werror, because
- configure tests may be affected in undesirable ways.
-
-* `EXTRA_CFLAGS="?"`
-* `EXTRA_CXXFLAGS="?"`
-
- Append these flags to CFLAGS/CXXFLAGS, without passing them to the
- compiler(s) during configuration. This makes it possible to add flags such
- as -Werror, while allowing the configure script to determine what other
- flags are appropriate for the specified configuration.
-
-* `CPPFLAGS="?"`
-
- Pass these flags to the C preprocessor. Note that CFLAGS is not passed to
- 'cpp' when 'configure' is looking for include files, so you must use
- CPPFLAGS instead if you need to help 'configure' find header files.
-
-* `LD_LIBRARY_PATH="?"`
-
- 'ld' uses this colon-separated list to find libraries.
-
-* `LDFLAGS="?"`
-
- Pass these flags when linking.
-
-* `PATH="?"`
-
- 'configure' uses this to find programs.
-
-In some cases it may be necessary to work around configuration results that do
-not match reality. For example, Linux 4.5 added support for the MADV_FREE flag
-to madvise(2), which can cause problems if building on a host with MADV_FREE
-support and deploying to a target without. To work around this, use a cache
-file to override the relevant configuration variable defined in configure.ac,
-e.g.:
-
- echo "je_cv_madv_free=no" > config.cache && ./configure -C
-
-
-## Advanced compilation
-
-To build only parts of jemalloc, use the following targets:
-
- build_lib_shared
- build_lib_static
- build_lib
- build_doc_html
- build_doc_man
- build_doc
-
-To install only parts of jemalloc, use the following targets:
-
- install_bin
- install_include
- install_lib_shared
- install_lib_static
- install_lib_pc
- install_lib
- install_doc_html
- install_doc_man
- install_doc
-
-To clean up build results to varying degrees, use the following make targets:
-
- clean
- distclean
- relclean
-
-
-## Advanced installation
-
-Optionally, define make variables when invoking make, including (not
-exclusively):
-
-* `INCLUDEDIR="?"`
-
- Use this as the installation prefix for header files.
-
-* `LIBDIR="?"`
-
- Use this as the installation prefix for libraries.
-
-* `MANDIR="?"`
-
- Use this as the installation prefix for man pages.
-
-* `DESTDIR="?"`
-
- Prepend DESTDIR to INCLUDEDIR, LIBDIR, DATADIR, and MANDIR. This is useful
- when installing to a different path than was specified via --prefix.
-
-* `CC="?"`
-
- Use this to invoke the C compiler.
-
-* `CFLAGS="?"`
-
- Pass these flags to the compiler.
-
-* `CPPFLAGS="?"`
-
- Pass these flags to the C preprocessor.
-
-* `LDFLAGS="?"`
-
- Pass these flags when linking.
-
-* `PATH="?"`
-
- Use this to search for programs used during configuration and building.
-
-
-## Development
-
-If you intend to make non-trivial changes to jemalloc, use the 'autogen.sh'
-script rather than 'configure'. This re-generates 'configure', enables
-configuration dependency rules, and enables re-generation of automatically
-generated source files.
-
-The build system supports using an object directory separate from the source
-tree. For example, you can create an 'obj' directory, and from within that
-directory, issue configuration and build commands:
-
- autoconf
- mkdir obj
- cd obj
- ../configure --enable-autogen
- make
-
-
-## Documentation
-
-The manual page is generated in both html and roff formats. Any web browser
-can be used to view the html manual. The roff manual page can be formatted
-prior to installation via the following command:
-
- nroff -man -t doc/jemalloc.3
->>>>>>> main
diff --git a/contrib/jemalloc/Makefile.in b/contrib/jemalloc/Makefile.in
index 121297702bcc..1193cd859c49 100644
--- a/contrib/jemalloc/Makefile.in
+++ b/contrib/jemalloc/Makefile.in
@@ -1,4 +1,3 @@
-<<<<<<< HEAD
# Clear out all vpaths, then set just one (default vpath) for the main build
# directory.
vpath
@@ -761,629 +760,3 @@ $(objroot)config.stamp : $(cfgoutputs_in) $(cfghdrs_in) $(srcroot)configure
$(cfgoutputs_out) $(cfghdrs_out) : $(objroot)config.stamp
@true
endif
-||||||| dec341af7695
-=======
-# Clear out all vpaths, then set just one (default vpath) for the main build
-# directory.
-vpath
-vpath % .
-
-# Clear the default suffixes, so that built-in rules are not used.
-.SUFFIXES :
-
-SHELL := /bin/sh
-
-CC := @CC@
-CXX := @CXX@
-
-# Configuration parameters.
-DESTDIR =
-BINDIR := $(DESTDIR)@BINDIR@
-INCLUDEDIR := $(DESTDIR)@INCLUDEDIR@
-LIBDIR := $(DESTDIR)@LIBDIR@
-DATADIR := $(DESTDIR)@DATADIR@
-MANDIR := $(DESTDIR)@MANDIR@
-srcroot := @srcroot@
-objroot := @objroot@
-abs_srcroot := @abs_srcroot@
-abs_objroot := @abs_objroot@
-
-# Build parameters.
-CPPFLAGS := @CPPFLAGS@ -I$(objroot)include -I$(srcroot)include
-CONFIGURE_CFLAGS := @CONFIGURE_CFLAGS@
-SPECIFIED_CFLAGS := @SPECIFIED_CFLAGS@
-EXTRA_CFLAGS := @EXTRA_CFLAGS@
-CFLAGS := $(strip $(CONFIGURE_CFLAGS) $(SPECIFIED_CFLAGS) $(EXTRA_CFLAGS))
-CONFIGURE_CXXFLAGS := @CONFIGURE_CXXFLAGS@
-SPECIFIED_CXXFLAGS := @SPECIFIED_CXXFLAGS@
-EXTRA_CXXFLAGS := @EXTRA_CXXFLAGS@
-CXXFLAGS := $(strip $(CONFIGURE_CXXFLAGS) $(SPECIFIED_CXXFLAGS) $(EXTRA_CXXFLAGS))
-LDFLAGS := @LDFLAGS@
-EXTRA_LDFLAGS := @EXTRA_LDFLAGS@
-LIBS := @LIBS@
-RPATH_EXTRA := @RPATH_EXTRA@
-SO := @so@
-IMPORTLIB := @importlib@
-O := @o@
-A := @a@
-EXE := @exe@
-LIBPREFIX := @libprefix@
-REV := @rev@
-install_suffix := @install_suffix@
-ABI := @abi@
-XSLTPROC := @XSLTPROC@
-XSLROOT := @XSLROOT@
-AUTOCONF := @AUTOCONF@
-_RPATH = @RPATH@
-RPATH = $(if $(1),$(call _RPATH,$(1)))
-cfghdrs_in := $(addprefix $(srcroot),@cfghdrs_in@)
-cfghdrs_out := @cfghdrs_out@
-cfgoutputs_in := $(addprefix $(srcroot),@cfgoutputs_in@)
-cfgoutputs_out := @cfgoutputs_out@
-enable_autogen := @enable_autogen@
-enable_doc := @enable_doc@
-enable_shared := @enable_shared@
-enable_static := @enable_static@
-enable_prof := @enable_prof@
-enable_zone_allocator := @enable_zone_allocator@
-enable_experimental_smallocx := @enable_experimental_smallocx@
-MALLOC_CONF := @JEMALLOC_CPREFIX@MALLOC_CONF
-link_whole_archive := @link_whole_archive@
-DSO_LDFLAGS = @DSO_LDFLAGS@
-SOREV = @SOREV@
-PIC_CFLAGS = @PIC_CFLAGS@
-CTARGET = @CTARGET@
-LDTARGET = @LDTARGET@
-TEST_LD_MODE = @TEST_LD_MODE@
-MKLIB = @MKLIB@
-AR = @AR@
-ARFLAGS = @ARFLAGS@
-DUMP_SYMS = @DUMP_SYMS@
-AWK := @AWK@
-CC_MM = @CC_MM@
-LM := @LM@
-INSTALL = @INSTALL@
-
-ifeq (macho, $(ABI))
-TEST_LIBRARY_PATH := DYLD_FALLBACK_LIBRARY_PATH="$(objroot)lib"
-else
-ifeq (pecoff, $(ABI))
-TEST_LIBRARY_PATH := PATH="$(PATH):$(objroot)lib"
-else
-TEST_LIBRARY_PATH :=
-endif
-endif
-
-LIBJEMALLOC := $(LIBPREFIX)jemalloc$(install_suffix)
-
-# Lists of files.
-BINS := $(objroot)bin/jemalloc-config $(objroot)bin/jemalloc.sh $(objroot)bin/jeprof
-C_HDRS := $(objroot)include/jemalloc/jemalloc$(install_suffix).h
-C_SRCS := $(srcroot)src/jemalloc.c \
- $(srcroot)src/arena.c \
- $(srcroot)src/background_thread.c \
- $(srcroot)src/base.c \
- $(srcroot)src/bin.c \
- $(srcroot)src/bitmap.c \
- $(srcroot)src/ckh.c \
- $(srcroot)src/ctl.c \
- $(srcroot)src/div.c \
- $(srcroot)src/extent.c \
- $(srcroot)src/extent_dss.c \
- $(srcroot)src/extent_mmap.c \
- $(srcroot)src/hash.c \
- $(srcroot)src/hook.c \
- $(srcroot)src/large.c \
- $(srcroot)src/log.c \
- $(srcroot)src/malloc_io.c \
- $(srcroot)src/mutex.c \
- $(srcroot)src/mutex_pool.c \
- $(srcroot)src/nstime.c \
- $(srcroot)src/pages.c \
- $(srcroot)src/prng.c \
- $(srcroot)src/prof.c \
- $(srcroot)src/rtree.c \
- $(srcroot)src/safety_check.c \
- $(srcroot)src/stats.c \
- $(srcroot)src/sc.c \
- $(srcroot)src/sz.c \
- $(srcroot)src/tcache.c \
- $(srcroot)src/test_hooks.c \
- $(srcroot)src/ticker.c \
- $(srcroot)src/tsd.c \
- $(srcroot)src/witness.c
-ifeq ($(enable_zone_allocator), 1)
-C_SRCS += $(srcroot)src/zone.c
-endif
-ifeq ($(IMPORTLIB),$(SO))
-STATIC_LIBS := $(objroot)lib/$(LIBJEMALLOC).$(A)
-endif
-ifdef PIC_CFLAGS
-STATIC_LIBS += $(objroot)lib/$(LIBJEMALLOC)_pic.$(A)
-else
-STATIC_LIBS += $(objroot)lib/$(LIBJEMALLOC)_s.$(A)
-endif
-DSOS := $(objroot)lib/$(LIBJEMALLOC).$(SOREV)
-ifneq ($(SOREV),$(SO))
-DSOS += $(objroot)lib/$(LIBJEMALLOC).$(SO)
-endif
-ifeq (1, $(link_whole_archive))
-LJEMALLOC := -Wl,--whole-archive -L$(objroot)lib -l$(LIBJEMALLOC) -Wl,--no-whole-archive
-else
-LJEMALLOC := $(objroot)lib/$(LIBJEMALLOC).$(IMPORTLIB)
-endif
-PC := $(objroot)jemalloc.pc
-MAN3 := $(objroot)doc/jemalloc$(install_suffix).3
-DOCS_XML := $(objroot)doc/jemalloc$(install_suffix).xml
-DOCS_HTML := $(DOCS_XML:$(objroot)%.xml=$(objroot)%.html)
-DOCS_MAN3 := $(DOCS_XML:$(objroot)%.xml=$(objroot)%.3)
-DOCS := $(DOCS_HTML) $(DOCS_MAN3)
-C_TESTLIB_SRCS := $(srcroot)test/src/btalloc.c $(srcroot)test/src/btalloc_0.c \
- $(srcroot)test/src/btalloc_1.c $(srcroot)test/src/math.c \
- $(srcroot)test/src/mtx.c $(srcroot)test/src/mq.c \
- $(srcroot)test/src/SFMT.c $(srcroot)test/src/test.c \
- $(srcroot)test/src/thd.c $(srcroot)test/src/timer.c
-ifeq (1, $(link_whole_archive))
-C_UTIL_INTEGRATION_SRCS :=
-C_UTIL_CPP_SRCS :=
-else
-C_UTIL_INTEGRATION_SRCS := $(srcroot)src/nstime.c $(srcroot)src/malloc_io.c
-C_UTIL_CPP_SRCS := $(srcroot)src/nstime.c $(srcroot)src/malloc_io.c
-endif
-TESTS_UNIT := \
- $(srcroot)test/unit/a0.c \
- $(srcroot)test/unit/arena_reset.c \
- $(srcroot)test/unit/atomic.c \
- $(srcroot)test/unit/background_thread.c \
- $(srcroot)test/unit/background_thread_enable.c \
- $(srcroot)test/unit/base.c \
- $(srcroot)test/unit/bitmap.c \
- $(srcroot)test/unit/bit_util.c \
- $(srcroot)test/unit/binshard.c \
- $(srcroot)test/unit/ckh.c \
- $(srcroot)test/unit/decay.c \
- $(srcroot)test/unit/div.c \
- $(srcroot)test/unit/emitter.c \
- $(srcroot)test/unit/extent_quantize.c \
- $(srcroot)test/unit/extent_util.c \
- $(srcroot)test/unit/fork.c \
- $(srcroot)test/unit/hash.c \
- $(srcroot)test/unit/hook.c \
- $(srcroot)test/unit/huge.c \
- $(srcroot)test/unit/junk.c \
- $(srcroot)test/unit/junk_alloc.c \
- $(srcroot)test/unit/junk_free.c \
- $(srcroot)test/unit/log.c \
- $(srcroot)test/unit/mallctl.c \
- $(srcroot)test/unit/malloc_io.c \
- $(srcroot)test/unit/math.c \
- $(srcroot)test/unit/mq.c \
- $(srcroot)test/unit/mtx.c \
- $(srcroot)test/unit/pack.c \
- $(srcroot)test/unit/pages.c \
- $(srcroot)test/unit/ph.c \
- $(srcroot)test/unit/prng.c \
- $(srcroot)test/unit/prof_accum.c \
- $(srcroot)test/unit/prof_active.c \
- $(srcroot)test/unit/prof_gdump.c \
- $(srcroot)test/unit/prof_idump.c \
- $(srcroot)test/unit/prof_log.c \
- $(srcroot)test/unit/prof_reset.c \
- $(srcroot)test/unit/prof_tctx.c \
- $(srcroot)test/unit/prof_thread_name.c \
- $(srcroot)test/unit/ql.c \
- $(srcroot)test/unit/qr.c \
- $(srcroot)test/unit/rb.c \
- $(srcroot)test/unit/retained.c \
- $(srcroot)test/unit/rtree.c \
- $(srcroot)test/unit/safety_check.c \
- $(srcroot)test/unit/seq.c \
- $(srcroot)test/unit/SFMT.c \
- $(srcroot)test/unit/sc.c \
- $(srcroot)test/unit/size_classes.c \
- $(srcroot)test/unit/slab.c \
- $(srcroot)test/unit/smoothstep.c \
- $(srcroot)test/unit/spin.c \
- $(srcroot)test/unit/stats.c \
- $(srcroot)test/unit/stats_print.c \
- $(srcroot)test/unit/test_hooks.c \
- $(srcroot)test/unit/ticker.c \
- $(srcroot)test/unit/nstime.c \
- $(srcroot)test/unit/tsd.c \
- $(srcroot)test/unit/witness.c \
- $(srcroot)test/unit/zero.c
-ifeq (@enable_prof@, 1)
-TESTS_UNIT += \
- $(srcroot)test/unit/arena_reset_prof.c
-endif
-TESTS_INTEGRATION := $(srcroot)test/integration/aligned_alloc.c \
- $(srcroot)test/integration/allocated.c \
- $(srcroot)test/integration/extent.c \
- $(srcroot)test/integration/malloc.c \
- $(srcroot)test/integration/mallocx.c \
- $(srcroot)test/integration/MALLOCX_ARENA.c \
- $(srcroot)test/integration/overflow.c \
- $(srcroot)test/integration/posix_memalign.c \
- $(srcroot)test/integration/rallocx.c \
- $(srcroot)test/integration/sdallocx.c \
- $(srcroot)test/integration/slab_sizes.c \
- $(srcroot)test/integration/thread_arena.c \
- $(srcroot)test/integration/thread_tcache_enabled.c \
- $(srcroot)test/integration/xallocx.c
-ifeq (@enable_experimental_smallocx@, 1)
-TESTS_INTEGRATION += \
- $(srcroot)test/integration/smallocx.c
-endif
-ifeq (@enable_cxx@, 1)
-CPP_SRCS := $(srcroot)src/jemalloc_cpp.cpp
-TESTS_INTEGRATION_CPP := $(srcroot)test/integration/cpp/basic.cpp
-else
-CPP_SRCS :=
-TESTS_INTEGRATION_CPP :=
-endif
-TESTS_STRESS := $(srcroot)test/stress/microbench.c \
- $(srcroot)test/stress/hookbench.c
-
-
-TESTS := $(TESTS_UNIT) $(TESTS_INTEGRATION) $(TESTS_INTEGRATION_CPP) $(TESTS_STRESS)
-
-PRIVATE_NAMESPACE_HDRS := $(objroot)include/jemalloc/internal/private_namespace.h $(objroot)include/jemalloc/internal/private_namespace_jet.h
-PRIVATE_NAMESPACE_GEN_HDRS := $(PRIVATE_NAMESPACE_HDRS:%.h=%.gen.h)
-C_SYM_OBJS := $(C_SRCS:$(srcroot)%.c=$(objroot)%.sym.$(O))
-C_SYMS := $(C_SRCS:$(srcroot)%.c=$(objroot)%.sym)
-C_OBJS := $(C_SRCS:$(srcroot)%.c=$(objroot)%.$(O))
-CPP_OBJS := $(CPP_SRCS:$(srcroot)%.cpp=$(objroot)%.$(O))
-C_PIC_OBJS := $(C_SRCS:$(srcroot)%.c=$(objroot)%.pic.$(O))
-CPP_PIC_OBJS := $(CPP_SRCS:$(srcroot)%.cpp=$(objroot)%.pic.$(O))
-C_JET_SYM_OBJS := $(C_SRCS:$(srcroot)%.c=$(objroot)%.jet.sym.$(O))
-C_JET_SYMS := $(C_SRCS:$(srcroot)%.c=$(objroot)%.jet.sym)
-C_JET_OBJS := $(C_SRCS:$(srcroot)%.c=$(objroot)%.jet.$(O))
-C_TESTLIB_UNIT_OBJS := $(C_TESTLIB_SRCS:$(srcroot)%.c=$(objroot)%.unit.$(O))
-C_TESTLIB_INTEGRATION_OBJS := $(C_TESTLIB_SRCS:$(srcroot)%.c=$(objroot)%.integration.$(O))
-C_UTIL_INTEGRATION_OBJS := $(C_UTIL_INTEGRATION_SRCS:$(srcroot)%.c=$(objroot)%.integration.$(O))
-C_TESTLIB_STRESS_OBJS := $(C_TESTLIB_SRCS:$(srcroot)%.c=$(objroot)%.stress.$(O))
-C_TESTLIB_OBJS := $(C_TESTLIB_UNIT_OBJS) $(C_TESTLIB_INTEGRATION_OBJS) $(C_UTIL_INTEGRATION_OBJS) $(C_TESTLIB_STRESS_OBJS)
-
-TESTS_UNIT_OBJS := $(TESTS_UNIT:$(srcroot)%.c=$(objroot)%.$(O))
-TESTS_INTEGRATION_OBJS := $(TESTS_INTEGRATION:$(srcroot)%.c=$(objroot)%.$(O))
-TESTS_INTEGRATION_CPP_OBJS := $(TESTS_INTEGRATION_CPP:$(srcroot)%.cpp=$(objroot)%.$(O))
-TESTS_STRESS_OBJS := $(TESTS_STRESS:$(srcroot)%.c=$(objroot)%.$(O))
-TESTS_OBJS := $(TESTS_UNIT_OBJS) $(TESTS_INTEGRATION_OBJS) $(TESTS_STRESS_OBJS)
-TESTS_CPP_OBJS := $(TESTS_INTEGRATION_CPP_OBJS)
-
-.PHONY: all dist build_doc_html build_doc_man build_doc
-.PHONY: install_bin install_include install_lib
-.PHONY: install_doc_html install_doc_man install_doc install
-.PHONY: tests check clean distclean relclean
-
-.SECONDARY : $(PRIVATE_NAMESPACE_GEN_HDRS) $(TESTS_OBJS) $(TESTS_CPP_OBJS)
-
-# Default target.
-all: build_lib
-
-dist: build_doc
-
-$(objroot)doc/%.html : $(objroot)doc/%.xml $(srcroot)doc/stylesheet.xsl $(objroot)doc/html.xsl
-ifneq ($(XSLROOT),)
- $(XSLTPROC) -o $@ $(objroot)doc/html.xsl $<
-else
-ifeq ($(wildcard $(DOCS_HTML)),)
- @echo "<p>Missing xsltproc. Doc not built.</p>" > $@
-endif
- @echo "Missing xsltproc. "$@" not (re)built."
-endif
-
-$(objroot)doc/%.3 : $(objroot)doc/%.xml $(srcroot)doc/stylesheet.xsl $(objroot)doc/manpages.xsl
-ifneq ($(XSLROOT),)
- $(XSLTPROC) -o $@ $(objroot)doc/manpages.xsl $<
-else
-ifeq ($(wildcard $(DOCS_MAN3)),)
- @echo "Missing xsltproc. Doc not built." > $@
-endif
- @echo "Missing xsltproc. "$@" not (re)built."
-endif
-
-build_doc_html: $(DOCS_HTML)
-build_doc_man: $(DOCS_MAN3)
-build_doc: $(DOCS)
-
-#
-# Include generated dependency files.
-#
-ifdef CC_MM
--include $(C_SYM_OBJS:%.$(O)=%.d)
--include $(C_OBJS:%.$(O)=%.d)
--include $(CPP_OBJS:%.$(O)=%.d)
--include $(C_PIC_OBJS:%.$(O)=%.d)
--include $(CPP_PIC_OBJS:%.$(O)=%.d)
--include $(C_JET_SYM_OBJS:%.$(O)=%.d)
--include $(C_JET_OBJS:%.$(O)=%.d)
--include $(C_TESTLIB_OBJS:%.$(O)=%.d)
--include $(TESTS_OBJS:%.$(O)=%.d)
--include $(TESTS_CPP_OBJS:%.$(O)=%.d)
-endif
-
-$(C_SYM_OBJS): $(objroot)src/%.sym.$(O): $(srcroot)src/%.c
-$(C_SYM_OBJS): CPPFLAGS += -DJEMALLOC_NO_PRIVATE_NAMESPACE
-$(C_SYMS): $(objroot)src/%.sym: $(objroot)src/%.sym.$(O)
-$(C_OBJS): $(objroot)src/%.$(O): $(srcroot)src/%.c
-$(CPP_OBJS): $(objroot)src/%.$(O): $(srcroot)src/%.cpp
-$(C_PIC_OBJS): $(objroot)src/%.pic.$(O): $(srcroot)src/%.c
-$(C_PIC_OBJS): CFLAGS += $(PIC_CFLAGS)
-$(CPP_PIC_OBJS): $(objroot)src/%.pic.$(O): $(srcroot)src/%.cpp
-$(CPP_PIC_OBJS): CXXFLAGS += $(PIC_CFLAGS)
-$(C_JET_SYM_OBJS): $(objroot)src/%.jet.sym.$(O): $(srcroot)src/%.c
-$(C_JET_SYM_OBJS): CPPFLAGS += -DJEMALLOC_JET -DJEMALLOC_NO_PRIVATE_NAMESPACE
-$(C_JET_SYMS): $(objroot)src/%.jet.sym: $(objroot)src/%.jet.sym.$(O)
-$(C_JET_OBJS): $(objroot)src/%.jet.$(O): $(srcroot)src/%.c
-$(C_JET_OBJS): CPPFLAGS += -DJEMALLOC_JET
-$(C_TESTLIB_UNIT_OBJS): $(objroot)test/src/%.unit.$(O): $(srcroot)test/src/%.c
-$(C_TESTLIB_UNIT_OBJS): CPPFLAGS += -DJEMALLOC_UNIT_TEST
-$(C_TESTLIB_INTEGRATION_OBJS): $(objroot)test/src/%.integration.$(O): $(srcroot)test/src/%.c
-$(C_TESTLIB_INTEGRATION_OBJS): CPPFLAGS += -DJEMALLOC_INTEGRATION_TEST
-$(C_UTIL_INTEGRATION_OBJS): $(objroot)src/%.integration.$(O): $(srcroot)src/%.c
-$(C_TESTLIB_STRESS_OBJS): $(objroot)test/src/%.stress.$(O): $(srcroot)test/src/%.c
-$(C_TESTLIB_STRESS_OBJS): CPPFLAGS += -DJEMALLOC_STRESS_TEST -DJEMALLOC_STRESS_TESTLIB
-$(C_TESTLIB_OBJS): CPPFLAGS += -I$(srcroot)test/include -I$(objroot)test/include
-$(TESTS_UNIT_OBJS): CPPFLAGS += -DJEMALLOC_UNIT_TEST
-$(TESTS_INTEGRATION_OBJS): CPPFLAGS += -DJEMALLOC_INTEGRATION_TEST
-$(TESTS_INTEGRATION_CPP_OBJS): CPPFLAGS += -DJEMALLOC_INTEGRATION_CPP_TEST
-$(TESTS_STRESS_OBJS): CPPFLAGS += -DJEMALLOC_STRESS_TEST
-$(TESTS_OBJS): $(objroot)test/%.$(O): $(srcroot)test/%.c
-$(TESTS_CPP_OBJS): $(objroot)test/%.$(O): $(srcroot)test/%.cpp
-$(TESTS_OBJS): CPPFLAGS += -I$(srcroot)test/include -I$(objroot)test/include
-$(TESTS_CPP_OBJS): CPPFLAGS += -I$(srcroot)test/include -I$(objroot)test/include
-ifneq ($(IMPORTLIB),$(SO))
-$(CPP_OBJS) $(C_SYM_OBJS) $(C_OBJS) $(C_JET_SYM_OBJS) $(C_JET_OBJS): CPPFLAGS += -DDLLEXPORT
-endif
-
-# Dependencies.
-ifndef CC_MM
-HEADER_DIRS = $(srcroot)include/jemalloc/internal \
- $(objroot)include/jemalloc $(objroot)include/jemalloc/internal
-HEADERS = $(filter-out $(PRIVATE_NAMESPACE_HDRS),$(wildcard $(foreach dir,$(HEADER_DIRS),$(dir)/*.h)))
-$(C_SYM_OBJS) $(C_OBJS) $(CPP_OBJS) $(C_PIC_OBJS) $(CPP_PIC_OBJS) $(C_JET_SYM_OBJS) $(C_JET_OBJS) $(C_TESTLIB_OBJS) $(TESTS_OBJS) $(TESTS_CPP_OBJS): $(HEADERS)
-$(TESTS_OBJS) $(TESTS_CPP_OBJS): $(objroot)test/include/test/jemalloc_test.h
-endif
-
-$(C_OBJS) $(CPP_OBJS) $(C_PIC_OBJS) $(CPP_PIC_OBJS) $(C_TESTLIB_INTEGRATION_OBJS) $(C_UTIL_INTEGRATION_OBJS) $(TESTS_INTEGRATION_OBJS) $(TESTS_INTEGRATION_CPP_OBJS): $(objroot)include/jemalloc/internal/private_namespace.h
-$(C_JET_OBJS) $(C_TESTLIB_UNIT_OBJS) $(C_TESTLIB_STRESS_OBJS) $(TESTS_UNIT_OBJS) $(TESTS_STRESS_OBJS): $(objroot)include/jemalloc/internal/private_namespace_jet.h
-
-$(C_SYM_OBJS) $(C_OBJS) $(C_PIC_OBJS) $(C_JET_SYM_OBJS) $(C_JET_OBJS) $(C_TESTLIB_OBJS) $(TESTS_OBJS): %.$(O):
- @mkdir -p $(@D)
- $(CC) $(CFLAGS) -c $(CPPFLAGS) $(CTARGET) $<
-ifdef CC_MM
- @$(CC) -MM $(CPPFLAGS) -MT $@ -o $(@:%.$(O)=%.d) $<
-endif
-
-$(C_SYMS): %.sym:
- @mkdir -p $(@D)
- $(DUMP_SYMS) $< | $(AWK) -f $(objroot)include/jemalloc/internal/private_symbols.awk > $@
-
-$(C_JET_SYMS): %.sym:
- @mkdir -p $(@D)
- $(DUMP_SYMS) $< | $(AWK) -f $(objroot)include/jemalloc/internal/private_symbols_jet.awk > $@
-
-$(objroot)include/jemalloc/internal/private_namespace.gen.h: $(C_SYMS)
- $(SHELL) $(srcroot)include/jemalloc/internal/private_namespace.sh $^ > $@
-
-$(objroot)include/jemalloc/internal/private_namespace_jet.gen.h: $(C_JET_SYMS)
- $(SHELL) $(srcroot)include/jemalloc/internal/private_namespace.sh $^ > $@
-
-%.h: %.gen.h
- @if ! `cmp -s $< $@` ; then echo "cp $< $<"; cp $< $@ ; fi
-
-$(CPP_OBJS) $(CPP_PIC_OBJS) $(TESTS_CPP_OBJS): %.$(O):
- @mkdir -p $(@D)
- $(CXX) $(CXXFLAGS) -c $(CPPFLAGS) $(CTARGET) $<
-ifdef CC_MM
- @$(CXX) -MM $(CPPFLAGS) -MT $@ -o $(@:%.$(O)=%.d) $<
-endif
-
-ifneq ($(SOREV),$(SO))
-%.$(SO) : %.$(SOREV)
- @mkdir -p $(@D)
- ln -sf $(<F) $@
-endif
-
-$(objroot)lib/$(LIBJEMALLOC).$(SOREV) : $(if $(PIC_CFLAGS),$(C_PIC_OBJS),$(C_OBJS)) $(if $(PIC_CFLAGS),$(CPP_PIC_OBJS),$(CPP_OBJS))
- @mkdir -p $(@D)
- $(CC) $(DSO_LDFLAGS) $(call RPATH,$(RPATH_EXTRA)) $(LDTARGET) $+ $(LDFLAGS) $(LIBS) $(EXTRA_LDFLAGS)
-
-$(objroot)lib/$(LIBJEMALLOC)_pic.$(A) : $(C_PIC_OBJS) $(CPP_PIC_OBJS)
-$(objroot)lib/$(LIBJEMALLOC).$(A) : $(C_OBJS) $(CPP_OBJS)
-$(objroot)lib/$(LIBJEMALLOC)_s.$(A) : $(C_OBJS) $(CPP_OBJS)
-
-$(STATIC_LIBS):
- @mkdir -p $(@D)
- $(AR) $(ARFLAGS)@AROUT@ $+
-
-$(objroot)test/unit/%$(EXE): $(objroot)test/unit/%.$(O) $(C_JET_OBJS) $(C_TESTLIB_UNIT_OBJS)
- @mkdir -p $(@D)
- $(CC) $(LDTARGET) $(filter %.$(O),$^) $(call RPATH,$(objroot)lib) $(LDFLAGS) $(filter-out -lm,$(LIBS)) $(LM) $(EXTRA_LDFLAGS)
-
-$(objroot)test/integration/%$(EXE): $(objroot)test/integration/%.$(O) $(C_TESTLIB_INTEGRATION_OBJS) $(C_UTIL_INTEGRATION_OBJS) $(objroot)lib/$(LIBJEMALLOC).$(IMPORTLIB)
- @mkdir -p $(@D)
- $(CC) $(TEST_LD_MODE) $(LDTARGET) $(filter %.$(O),$^) $(call RPATH,$(objroot)lib) $(LJEMALLOC) $(LDFLAGS) $(filter-out -lm,$(filter -lrt -pthread -lstdc++,$(LIBS))) $(LM) $(EXTRA_LDFLAGS)
-
-$(objroot)test/integration/cpp/%$(EXE): $(objroot)test/integration/cpp/%.$(O) $(C_TESTLIB_INTEGRATION_OBJS) $(C_UTIL_INTEGRATION_OBJS) $(objroot)lib/$(LIBJEMALLOC).$(IMPORTLIB)
- @mkdir -p $(@D)
- $(CXX) $(LDTARGET) $(filter %.$(O),$^) $(call RPATH,$(objroot)lib) $(objroot)lib/$(LIBJEMALLOC).$(IMPORTLIB) $(LDFLAGS) $(filter-out -lm,$(LIBS)) -lm $(EXTRA_LDFLAGS)
-
-$(objroot)test/stress/%$(EXE): $(objroot)test/stress/%.$(O) $(C_JET_OBJS) $(C_TESTLIB_STRESS_OBJS) $(objroot)lib/$(LIBJEMALLOC).$(IMPORTLIB)
- @mkdir -p $(@D)
- $(CC) $(TEST_LD_MODE) $(LDTARGET) $(filter %.$(O),$^) $(call RPATH,$(objroot)lib) $(objroot)lib/$(LIBJEMALLOC).$(IMPORTLIB) $(LDFLAGS) $(filter-out -lm,$(LIBS)) $(LM) $(EXTRA_LDFLAGS)
-
-build_lib_shared: $(DSOS)
-build_lib_static: $(STATIC_LIBS)
-ifeq ($(enable_shared), 1)
-build_lib: build_lib_shared
-endif
-ifeq ($(enable_static), 1)
-build_lib: build_lib_static
-endif
-
-install_bin:
- $(INSTALL) -d $(BINDIR)
- @for b in $(BINS); do \
- echo "$(INSTALL) -m 755 $$b $(BINDIR)"; \
- $(INSTALL) -m 755 $$b $(BINDIR); \
-done
-
-install_include:
- $(INSTALL) -d $(INCLUDEDIR)/jemalloc
- @for h in $(C_HDRS); do \
- echo "$(INSTALL) -m 644 $$h $(INCLUDEDIR)/jemalloc"; \
- $(INSTALL) -m 644 $$h $(INCLUDEDIR)/jemalloc; \
-done
-
-install_lib_shared: $(DSOS)
- $(INSTALL) -d $(LIBDIR)
- $(INSTALL) -m 755 $(objroot)lib/$(LIBJEMALLOC).$(SOREV) $(LIBDIR)
-ifneq ($(SOREV),$(SO))
- ln -sf $(LIBJEMALLOC).$(SOREV) $(LIBDIR)/$(LIBJEMALLOC).$(SO)
-endif
-
-install_lib_static: $(STATIC_LIBS)
- $(INSTALL) -d $(LIBDIR)
- @for l in $(STATIC_LIBS); do \
- echo "$(INSTALL) -m 755 $$l $(LIBDIR)"; \
- $(INSTALL) -m 755 $$l $(LIBDIR); \
-done
-
-install_lib_pc: $(PC)
- $(INSTALL) -d $(LIBDIR)/pkgconfig
- @for l in $(PC); do \
- echo "$(INSTALL) -m 644 $$l $(LIBDIR)/pkgconfig"; \
- $(INSTALL) -m 644 $$l $(LIBDIR)/pkgconfig; \
-done
-
-ifeq ($(enable_shared), 1)
-install_lib: install_lib_shared
-endif
-ifeq ($(enable_static), 1)
-install_lib: install_lib_static
-endif
-install_lib: install_lib_pc
-
-install_doc_html:
- $(INSTALL) -d $(DATADIR)/doc/jemalloc$(install_suffix)
- @for d in $(DOCS_HTML); do \
- echo "$(INSTALL) -m 644 $$d $(DATADIR)/doc/jemalloc$(install_suffix)"; \
- $(INSTALL) -m 644 $$d $(DATADIR)/doc/jemalloc$(install_suffix); \
-done
-
-install_doc_man:
- $(INSTALL) -d $(MANDIR)/man3
- @for d in $(DOCS_MAN3); do \
- echo "$(INSTALL) -m 644 $$d $(MANDIR)/man3"; \
- $(INSTALL) -m 644 $$d $(MANDIR)/man3; \
-done
-
-install_doc: build_doc install_doc_html install_doc_man
-
-install: install_bin install_include install_lib
-
-ifeq ($(enable_doc), 1)
-install: install_doc
-endif
-
-tests_unit: $(TESTS_UNIT:$(srcroot)%.c=$(objroot)%$(EXE))
-tests_integration: $(TESTS_INTEGRATION:$(srcroot)%.c=$(objroot)%$(EXE)) $(TESTS_INTEGRATION_CPP:$(srcroot)%.cpp=$(objroot)%$(EXE))
-tests_stress: $(TESTS_STRESS:$(srcroot)%.c=$(objroot)%$(EXE))
-tests: tests_unit tests_integration tests_stress
-
-check_unit_dir:
- @mkdir -p $(objroot)test/unit
-check_integration_dir:
- @mkdir -p $(objroot)test/integration
-stress_dir:
- @mkdir -p $(objroot)test/stress
-check_dir: check_unit_dir check_integration_dir
-
-check_unit: tests_unit check_unit_dir
- $(SHELL) $(objroot)test/test.sh $(TESTS_UNIT:$(srcroot)%.c=$(objroot)%)
-check_integration_prof: tests_integration check_integration_dir
-ifeq ($(enable_prof), 1)
- $(MALLOC_CONF)="prof:true" $(SHELL) $(objroot)test/test.sh $(TESTS_INTEGRATION:$(srcroot)%.c=$(objroot)%) $(TESTS_INTEGRATION_CPP:$(srcroot)%.cpp=$(objroot)%)
- $(MALLOC_CONF)="prof:true,prof_active:false" $(SHELL) $(objroot)test/test.sh $(TESTS_INTEGRATION:$(srcroot)%.c=$(objroot)%) $(TESTS_INTEGRATION_CPP:$(srcroot)%.cpp=$(objroot)%)
-endif
-check_integration_decay: tests_integration check_integration_dir
- $(MALLOC_CONF)="dirty_decay_ms:-1,muzzy_decay_ms:-1" $(SHELL) $(objroot)test/test.sh $(TESTS_INTEGRATION:$(srcroot)%.c=$(objroot)%) $(TESTS_INTEGRATION_CPP:$(srcroot)%.cpp=$(objroot)%)
- $(MALLOC_CONF)="dirty_decay_ms:0,muzzy_decay_ms:0" $(SHELL) $(objroot)test/test.sh $(TESTS_INTEGRATION:$(srcroot)%.c=$(objroot)%) $(TESTS_INTEGRATION_CPP:$(srcroot)%.cpp=$(objroot)%)
-check_integration: tests_integration check_integration_dir
- $(SHELL) $(objroot)test/test.sh $(TESTS_INTEGRATION:$(srcroot)%.c=$(objroot)%) $(TESTS_INTEGRATION_CPP:$(srcroot)%.cpp=$(objroot)%)
-stress: tests_stress stress_dir
- $(SHELL) $(objroot)test/test.sh $(TESTS_STRESS:$(srcroot)%.c=$(objroot)%)
-check: check_unit check_integration check_integration_decay check_integration_prof
-
-clean:
- rm -f $(PRIVATE_NAMESPACE_HDRS)
- rm -f $(PRIVATE_NAMESPACE_GEN_HDRS)
- rm -f $(C_SYM_OBJS)
- rm -f $(C_SYMS)
- rm -f $(C_OBJS)
- rm -f $(CPP_OBJS)
- rm -f $(C_PIC_OBJS)
- rm -f $(CPP_PIC_OBJS)
- rm -f $(C_JET_SYM_OBJS)
- rm -f $(C_JET_SYMS)
- rm -f $(C_JET_OBJS)
- rm -f $(C_TESTLIB_OBJS)
- rm -f $(C_SYM_OBJS:%.$(O)=%.d)
- rm -f $(C_OBJS:%.$(O)=%.d)
- rm -f $(CPP_OBJS:%.$(O)=%.d)
- rm -f $(C_PIC_OBJS:%.$(O)=%.d)
- rm -f $(CPP_PIC_OBJS:%.$(O)=%.d)
- rm -f $(C_JET_SYM_OBJS:%.$(O)=%.d)
- rm -f $(C_JET_OBJS:%.$(O)=%.d)
- rm -f $(C_TESTLIB_OBJS:%.$(O)=%.d)
- rm -f $(TESTS_OBJS:%.$(O)=%$(EXE))
- rm -f $(TESTS_OBJS)
- rm -f $(TESTS_OBJS:%.$(O)=%.d)
- rm -f $(TESTS_OBJS:%.$(O)=%.out)
- rm -f $(TESTS_CPP_OBJS:%.$(O)=%$(EXE))
- rm -f $(TESTS_CPP_OBJS)
- rm -f $(TESTS_CPP_OBJS:%.$(O)=%.d)
- rm -f $(TESTS_CPP_OBJS:%.$(O)=%.out)
- rm -f $(DSOS) $(STATIC_LIBS)
-
-distclean: clean
- rm -f $(objroot)bin/jemalloc-config
- rm -f $(objroot)bin/jemalloc.sh
- rm -f $(objroot)bin/jeprof
- rm -f $(objroot)config.log
- rm -f $(objroot)config.status
- rm -f $(objroot)config.stamp
- rm -f $(cfghdrs_out)
- rm -f $(cfgoutputs_out)
-
-relclean: distclean
- rm -f $(objroot)configure
- rm -f $(objroot)VERSION
- rm -f $(DOCS_HTML)
- rm -f $(DOCS_MAN3)
-
-#===============================================================================
-# Re-configuration rules.
-
-ifeq ($(enable_autogen), 1)
-$(srcroot)configure : $(srcroot)configure.ac
- cd ./$(srcroot) && $(AUTOCONF)
-
-$(objroot)config.status : $(srcroot)configure
- ./$(objroot)config.status --recheck
-
-$(srcroot)config.stamp.in : $(srcroot)configure.ac
- echo stamp > $(srcroot)config.stamp.in
-
-$(objroot)config.stamp : $(cfgoutputs_in) $(cfghdrs_in) $(srcroot)configure
- ./$(objroot)config.status
- @touch $@
-
-# There must be some action in order for make to re-read Makefile when it is
-# out of date.
-$(cfgoutputs_out) $(cfghdrs_out) : $(objroot)config.stamp
- @true
-endif
->>>>>>> main
diff --git a/contrib/jemalloc/TUNING.md b/contrib/jemalloc/TUNING.md
index 500541dd52d0..e96399d7c9b8 100644
--- a/contrib/jemalloc/TUNING.md
+++ b/contrib/jemalloc/TUNING.md
@@ -1,4 +1,3 @@
-<<<<<<< HEAD
This document summarizes the common approaches for performance fine tuning with
jemalloc (as of 5.3.0). The default configuration of jemalloc tends to work
reasonably well in practice, and most applications should not have to tune any
@@ -128,135 +127,3 @@ improve application performance with jemalloc.
access / allocation patterns. Threads with heavy workloads often benefit
from explicit binding, e.g. binding very active threads to dedicated arenas
may reduce contention at the allocator level.
-||||||| dec341af7695
-=======
-This document summarizes the common approaches for performance fine tuning with
-jemalloc (as of 5.1.0). The default configuration of jemalloc tends to work
-reasonably well in practice, and most applications should not have to tune any
-options. However, in order to cover a wide range of applications and avoid
-pathological cases, the default setting is sometimes kept conservative and
-suboptimal, even for many common workloads. When jemalloc is properly tuned for
-a specific application / workload, it is common to improve system level metrics
-by a few percent, or make favorable trade-offs.
-
-
-## Notable runtime options for performance tuning
-
-Runtime options can be set via
-[malloc_conf](http://jemalloc.net/jemalloc.3.html#tuning).
-
-* [background_thread](http://jemalloc.net/jemalloc.3.html#background_thread)
-
- Enabling jemalloc background threads generally improves the tail latency for
- application threads, since unused memory purging is shifted to the dedicated
- background threads. In addition, unintended purging delay caused by
- application inactivity is avoided with background threads.
-
- Suggested: `background_thread:true` when jemalloc managed threads can be
- allowed.
-
-* [metadata_thp](http://jemalloc.net/jemalloc.3.html#opt.metadata_thp)
-
- Allowing jemalloc to utilize transparent huge pages for its internal
- metadata usually reduces TLB misses significantly, especially for programs
- with large memory footprint and frequent allocation / deallocation
- activities. Metadata memory usage may increase due to the use of huge
- pages.
-
- Suggested for allocation intensive programs: `metadata_thp:auto` or
- `metadata_thp:always`, which is expected to improve CPU utilization at a
- small memory cost.
-
-* [dirty_decay_ms](http://jemalloc.net/jemalloc.3.html#opt.dirty_decay_ms) and
- [muzzy_decay_ms](http://jemalloc.net/jemalloc.3.html#opt.muzzy_decay_ms)
-
- Decay time determines how fast jemalloc returns unused pages back to the
- operating system, and therefore provides a fairly straightforward trade-off
- between CPU and memory usage. Shorter decay time purges unused pages faster
- to reduces memory usage (usually at the cost of more CPU cycles spent on
- purging), and vice versa.
-
- Suggested: tune the values based on the desired trade-offs.
-
-* [narenas](http://jemalloc.net/jemalloc.3.html#opt.narenas)
-
- By default jemalloc uses multiple arenas to reduce internal lock contention.
- However high arena count may also increase overall memory fragmentation,
- since arenas manage memory independently. When high degree of parallelism
- is not expected at the allocator level, lower number of arenas often
- improves memory usage.
-
- Suggested: if low parallelism is expected, try lower arena count while
- monitoring CPU and memory usage.
-
-* [percpu_arena](http://jemalloc.net/jemalloc.3.html#opt.percpu_arena)
-
- Enable dynamic thread to arena association based on running CPU. This has
- the potential to improve locality, e.g. when thread to CPU affinity is
- present.
-
- Suggested: try `percpu_arena:percpu` or `percpu_arena:phycpu` if
- thread migration between processors is expected to be infrequent.
-
-Examples:
-
-* High resource consumption application, prioritizing CPU utilization:
-
- `background_thread:true,metadata_thp:auto` combined with relaxed decay time
- (increased `dirty_decay_ms` and / or `muzzy_decay_ms`,
- e.g. `dirty_decay_ms:30000,muzzy_decay_ms:30000`).
-
-* High resource consumption application, prioritizing memory usage:
-
- `background_thread:true` combined with shorter decay time (decreased
- `dirty_decay_ms` and / or `muzzy_decay_ms`,
- e.g. `dirty_decay_ms:5000,muzzy_decay_ms:5000`), and lower arena count
- (e.g. number of CPUs).
-
-* Low resource consumption application:
-
- `narenas:1,lg_tcache_max:13` combined with shorter decay time (decreased
- `dirty_decay_ms` and / or `muzzy_decay_ms`,e.g.
- `dirty_decay_ms:1000,muzzy_decay_ms:0`).
-
-* Extremely conservative -- minimize memory usage at all costs, only suitable when
-allocation activity is very rare:
-
- `narenas:1,tcache:false,dirty_decay_ms:0,muzzy_decay_ms:0`
-
-Note that it is recommended to combine the options with `abort_conf:true` which
-aborts immediately on illegal options.
-
-## Beyond runtime options
-
-In addition to the runtime options, there are a number of programmatic ways to
-improve application performance with jemalloc.
-
-* [Explicit arenas](http://jemalloc.net/jemalloc.3.html#arenas.create)
-
- Manually created arenas can help performance in various ways, e.g. by
- managing locality and contention for specific usages. For example,
- applications can explicitly allocate frequently accessed objects from a
- dedicated arena with
- [mallocx()](http://jemalloc.net/jemalloc.3.html#MALLOCX_ARENA) to improve
- locality. In addition, explicit arenas often benefit from individually
- tuned options, e.g. relaxed [decay
- time](http://jemalloc.net/jemalloc.3.html#arena.i.dirty_decay_ms) if
- frequent reuse is expected.
-
-* [Extent hooks](http://jemalloc.net/jemalloc.3.html#arena.i.extent_hooks)
-
- Extent hooks allow customization for managing underlying memory. One use
- case for performance purpose is to utilize huge pages -- for example,
- [HHVM](https://github.com/facebook/hhvm/blob/master/hphp/util/alloc.cpp)
- uses explicit arenas with customized extent hooks to manage 1GB huge pages
- for frequently accessed data, which reduces TLB misses significantly.
-
-* [Explicit thread-to-arena
- binding](http://jemalloc.net/jemalloc.3.html#thread.arena)
-
- It is common for some threads in an application to have different memory
- access / allocation patterns. Threads with heavy workloads often benefit
- from explicit binding, e.g. binding very active threads to dedicated arenas
- may reduce contention at the allocator level.
->>>>>>> main
diff --git a/contrib/jemalloc/bin/jeprof.in b/contrib/jemalloc/bin/jeprof.in
index dc2c3ea877b8..dbf6252b921e 100644
--- a/contrib/jemalloc/bin/jeprof.in
+++ b/contrib/jemalloc/bin/jeprof.in
@@ -1,4 +1,3 @@
-<<<<<<< HEAD
#! /usr/bin/env perl
# Copyright (c) 1998-2007, Google Inc.
@@ -5722,5631 +5721,3 @@ sub RunUnitTests {
}
exit ($error_count);
}
-||||||| dec341af7695
-=======
-#! /usr/bin/env perl
-
-# Copyright (c) 1998-2007, Google Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# * 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.
-# * Neither the name of Google Inc. 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 COPYRIGHT HOLDERS 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 COPYRIGHT
-# OWNER 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.
-
-# ---
-# Program for printing the profile generated by common/profiler.cc,
-# or by the heap profiler (common/debugallocation.cc)
-#
-# The profile contains a sequence of entries of the form:
-# <count> <stack trace>
-# This program parses the profile, and generates user-readable
-# output.
-#
-# Examples:
-#
-# % tools/jeprof "program" "profile"
-# Enters "interactive" mode
-#
-# % tools/jeprof --text "program" "profile"
-# Generates one line per procedure
-#
-# % tools/jeprof --gv "program" "profile"
-# Generates annotated call-graph and displays via "gv"
-#
-# % tools/jeprof --gv --focus=Mutex "program" "profile"
-# Restrict to code paths that involve an entry that matches "Mutex"
-#
-# % tools/jeprof --gv --focus=Mutex --ignore=string "program" "profile"
-# Restrict to code paths that involve an entry that matches "Mutex"
-# and does not match "string"
-#
-# % tools/jeprof --list=IBF_CheckDocid "program" "profile"
-# Generates disassembly listing of all routines with at least one
-# sample that match the --list=<regexp> pattern. The listing is
-# annotated with the flat and cumulative sample counts at each line.
-#
-# % tools/jeprof --disasm=IBF_CheckDocid "program" "profile"
-# Generates disassembly listing of all routines with at least one
-# sample that match the --disasm=<regexp> pattern. The listing is
-# annotated with the flat and cumulative sample counts at each PC value.
-#
-# TODO: Use color to indicate files?
-
-use strict;
-use warnings;
-use Getopt::Long;
-use Cwd;
-
-my $JEPROF_VERSION = "@jemalloc_version@";
-my $PPROF_VERSION = "2.0";
-
-# These are the object tools we use which can come from a
-# user-specified location using --tools, from the JEPROF_TOOLS
-# environment variable, or from the environment.
-my %obj_tool_map = (
- "objdump" => "objdump",
- "nm" => "nm",
- "addr2line" => "addr2line",
- "c++filt" => "c++filt",
- ## ConfigureObjTools may add architecture-specific entries:
- #"nm_pdb" => "nm-pdb", # for reading windows (PDB-format) executables
- #"addr2line_pdb" => "addr2line-pdb", # ditto
- #"otool" => "otool", # equivalent of objdump on OS X
-);
-# NOTE: these are lists, so you can put in commandline flags if you want.
-my @DOT = ("dot"); # leave non-absolute, since it may be in /usr/local
-my @GV = ("gv");
-my @EVINCE = ("evince"); # could also be xpdf or perhaps acroread
-my @KCACHEGRIND = ("kcachegrind");
-my @PS2PDF = ("ps2pdf");
-# These are used for dynamic profiles
-my @URL_FETCHER = ("curl", "-s", "--fail");
-
-# These are the web pages that servers need to support for dynamic profiles
-my $HEAP_PAGE = "/pprof/heap";
-my $PROFILE_PAGE = "/pprof/profile"; # must support cgi-param "?seconds=#"
-my $PMUPROFILE_PAGE = "/pprof/pmuprofile(?:\\?.*)?"; # must support cgi-param
- # ?seconds=#&event=x&period=n
-my $GROWTH_PAGE = "/pprof/growth";
-my $CONTENTION_PAGE = "/pprof/contention";
-my $WALL_PAGE = "/pprof/wall(?:\\?.*)?"; # accepts options like namefilter
-my $FILTEREDPROFILE_PAGE = "/pprof/filteredprofile(?:\\?.*)?";
-my $CENSUSPROFILE_PAGE = "/pprof/censusprofile(?:\\?.*)?"; # must support cgi-param
- # "?seconds=#",
- # "?tags_regexp=#" and
- # "?type=#".
-my $SYMBOL_PAGE = "/pprof/symbol"; # must support symbol lookup via POST
-my $PROGRAM_NAME_PAGE = "/pprof/cmdline";
-
-# These are the web pages that can be named on the command line.
-# All the alternatives must begin with /.
-my $PROFILES = "($HEAP_PAGE|$PROFILE_PAGE|$PMUPROFILE_PAGE|" .
- "$GROWTH_PAGE|$CONTENTION_PAGE|$WALL_PAGE|" .
- "$FILTEREDPROFILE_PAGE|$CENSUSPROFILE_PAGE)";
-
-# default binary name
-my $UNKNOWN_BINARY = "(unknown)";
-
-# There is a pervasive dependency on the length (in hex characters,
-# i.e., nibbles) of an address, distinguishing between 32-bit and
-# 64-bit profiles. To err on the safe size, default to 64-bit here:
-my $address_length = 16;
-
-my $dev_null = "/dev/null";
-if (! -e $dev_null && $^O =~ /MSWin/) { # $^O is the OS perl was built for
- $dev_null = "nul";
-}
-
-# A list of paths to search for shared object files
-my @prefix_list = ();
-
-# Special routine name that should not have any symbols.
-# Used as separator to parse "addr2line -i" output.
-my $sep_symbol = '_fini';
-my $sep_address = undef;
-
-##### Argument parsing #####
-
-sub usage_string {
- return <<EOF;
-Usage:
-jeprof [options] <program> <profiles>
- <profiles> is a space separated list of profile names.
-jeprof [options] <symbolized-profiles>
- <symbolized-profiles> is a list of profile files where each file contains
- the necessary symbol mappings as well as profile data (likely generated
- with --raw).
-jeprof [options] <profile>
- <profile> is a remote form. Symbols are obtained from host:port$SYMBOL_PAGE
-
- Each name can be:
- /path/to/profile - a path to a profile file
- host:port[/<service>] - a location of a service to get profile from
-
- The /<service> can be $HEAP_PAGE, $PROFILE_PAGE, /pprof/pmuprofile,
- $GROWTH_PAGE, $CONTENTION_PAGE, /pprof/wall,
- $CENSUSPROFILE_PAGE, or /pprof/filteredprofile.
- For instance:
- jeprof http://myserver.com:80$HEAP_PAGE
- If /<service> is omitted, the service defaults to $PROFILE_PAGE (cpu profiling).
-jeprof --symbols <program>
- Maps addresses to symbol names. In this mode, stdin should be a
- list of library mappings, in the same format as is found in the heap-
- and cpu-profile files (this loosely matches that of /proc/self/maps
- on linux), followed by a list of hex addresses to map, one per line.
-
- For more help with querying remote servers, including how to add the
- necessary server-side support code, see this filename (or one like it):
-
- /usr/doc/gperftools-$PPROF_VERSION/pprof_remote_servers.html
-
-Options:
- --cum Sort by cumulative data
- --base=<base> Subtract <base> from <profile> before display
- --interactive Run in interactive mode (interactive "help" gives help) [default]
- --seconds=<n> Length of time for dynamic profiles [default=30 secs]
- --add_lib=<file> Read additional symbols and line info from the given library
- --lib_prefix=<dir> Comma separated list of library path prefixes
-
-Reporting Granularity:
- --addresses Report at address level
- --lines Report at source line level
- --functions Report at function level [default]
- --files Report at source file level
-
-Output type:
- --text Generate text report
- --callgrind Generate callgrind format to stdout
- --gv Generate Postscript and display
- --evince Generate PDF and display
- --web Generate SVG and display
- --list=<regexp> Generate source listing of matching routines
- --disasm=<regexp> Generate disassembly of matching routines
- --symbols Print demangled symbol names found at given addresses
- --dot Generate DOT file to stdout
- --ps Generate Postcript to stdout
- --pdf Generate PDF to stdout
- --svg Generate SVG to stdout
- --gif Generate GIF to stdout
- --raw Generate symbolized jeprof data (useful with remote fetch)
-
-Heap-Profile Options:
- --inuse_space Display in-use (mega)bytes [default]
- --inuse_objects Display in-use objects
- --alloc_space Display allocated (mega)bytes
- --alloc_objects Display allocated objects
- --show_bytes Display space in bytes
- --drop_negative Ignore negative differences
-
-Contention-profile options:
- --total_delay Display total delay at each region [default]
- --contentions Display number of delays at each region
- --mean_delay Display mean delay at each region
-
-Call-graph Options:
- --nodecount=<n> Show at most so many nodes [default=80]
- --nodefraction=<f> Hide nodes below <f>*total [default=.005]
- --edgefraction=<f> Hide edges below <f>*total [default=.001]
- --maxdegree=<n> Max incoming/outgoing edges per node [default=8]
- --focus=<regexp> Focus on backtraces with nodes matching <regexp>
- --thread=<n> Show profile for thread <n>
- --ignore=<regexp> Ignore backtraces with nodes matching <regexp>
- --scale=<n> Set GV scaling [default=0]
- --heapcheck Make nodes with non-0 object counts
- (i.e. direct leak generators) more visible
- --retain=<regexp> Retain only nodes that match <regexp>
- --exclude=<regexp> Exclude all nodes that match <regexp>
-
-Miscellaneous:
- --tools=<prefix or binary:fullpath>[,...] \$PATH for object tool pathnames
- --test Run unit tests
- --help This message
- --version Version information
-
-Environment Variables:
- JEPROF_TMPDIR Profiles directory. Defaults to \$HOME/jeprof
- JEPROF_TOOLS Prefix for object tools pathnames
-
-Examples:
-
-jeprof /bin/ls ls.prof
- Enters "interactive" mode
-jeprof --text /bin/ls ls.prof
- Outputs one line per procedure
-jeprof --web /bin/ls ls.prof
- Displays annotated call-graph in web browser
-jeprof --gv /bin/ls ls.prof
- Displays annotated call-graph via 'gv'
-jeprof --gv --focus=Mutex /bin/ls ls.prof
- Restricts to code paths including a .*Mutex.* entry
-jeprof --gv --focus=Mutex --ignore=string /bin/ls ls.prof
- Code paths including Mutex but not string
-jeprof --list=getdir /bin/ls ls.prof
- (Per-line) annotated source listing for getdir()
-jeprof --disasm=getdir /bin/ls ls.prof
- (Per-PC) annotated disassembly for getdir()
-
-jeprof http://localhost:1234/
- Enters "interactive" mode
-jeprof --text localhost:1234
- Outputs one line per procedure for localhost:1234
-jeprof --raw localhost:1234 > ./local.raw
-jeprof --text ./local.raw
- Fetches a remote profile for later analysis and then
- analyzes it in text mode.
-EOF
-}
-
-sub version_string {
- return <<EOF
-jeprof (part of jemalloc $JEPROF_VERSION)
-based on pprof (part of gperftools $PPROF_VERSION)
-
-Copyright 1998-2007 Google Inc.
-
-This is BSD licensed software; see the source for copying conditions
-and license information.
-There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
-PARTICULAR PURPOSE.
-EOF
-}
-
-sub usage {
- my $msg = shift;
- print STDERR "$msg\n\n";
- print STDERR usage_string();
- print STDERR "\nFATAL ERROR: $msg\n"; # just as a reminder
- exit(1);
-}
-
-sub Init() {
- # Setup tmp-file name and handler to clean it up.
- # We do this in the very beginning so that we can use
- # error() and cleanup() function anytime here after.
- $main::tmpfile_sym = "/tmp/jeprof$$.sym";
- $main::tmpfile_ps = "/tmp/jeprof$$";
- $main::next_tmpfile = 0;
- $SIG{'INT'} = \&sighandler;
-
- # Cache from filename/linenumber to source code
- $main::source_cache = ();
-
- $main::opt_help = 0;
- $main::opt_version = 0;
-
- $main::opt_cum = 0;
- $main::opt_base = '';
- $main::opt_addresses = 0;
- $main::opt_lines = 0;
- $main::opt_functions = 0;
- $main::opt_files = 0;
- $main::opt_lib_prefix = "";
-
- $main::opt_text = 0;
- $main::opt_callgrind = 0;
- $main::opt_list = "";
- $main::opt_disasm = "";
- $main::opt_symbols = 0;
- $main::opt_gv = 0;
- $main::opt_evince = 0;
- $main::opt_web = 0;
- $main::opt_dot = 0;
- $main::opt_ps = 0;
- $main::opt_pdf = 0;
- $main::opt_gif = 0;
- $main::opt_svg = 0;
- $main::opt_raw = 0;
-
- $main::opt_nodecount = 80;
- $main::opt_nodefraction = 0.005;
- $main::opt_edgefraction = 0.001;
- $main::opt_maxdegree = 8;
- $main::opt_focus = '';
- $main::opt_thread = undef;
- $main::opt_ignore = '';
- $main::opt_scale = 0;
- $main::opt_heapcheck = 0;
- $main::opt_retain = '';
- $main::opt_exclude = '';
- $main::opt_seconds = 30;
- $main::opt_lib = "";
-
- $main::opt_inuse_space = 0;
- $main::opt_inuse_objects = 0;
- $main::opt_alloc_space = 0;
- $main::opt_alloc_objects = 0;
- $main::opt_show_bytes = 0;
- $main::opt_drop_negative = 0;
- $main::opt_interactive = 0;
-
- $main::opt_total_delay = 0;
- $main::opt_contentions = 0;
- $main::opt_mean_delay = 0;
-
- $main::opt_tools = "";
- $main::opt_debug = 0;
- $main::opt_test = 0;
-
- # These are undocumented flags used only by unittests.
- $main::opt_test_stride = 0;
-
- # Are we using $SYMBOL_PAGE?
- $main::use_symbol_page = 0;
-
- # Files returned by TempName.
- %main::tempnames = ();
-
- # Type of profile we are dealing with
- # Supported types:
- # cpu
- # heap
- # growth
- # contention
- $main::profile_type = ''; # Empty type means "unknown"
-
- GetOptions("help!" => \$main::opt_help,
- "version!" => \$main::opt_version,
- "cum!" => \$main::opt_cum,
- "base=s" => \$main::opt_base,
- "seconds=i" => \$main::opt_seconds,
- "add_lib=s" => \$main::opt_lib,
- "lib_prefix=s" => \$main::opt_lib_prefix,
- "functions!" => \$main::opt_functions,
- "lines!" => \$main::opt_lines,
- "addresses!" => \$main::opt_addresses,
- "files!" => \$main::opt_files,
- "text!" => \$main::opt_text,
- "callgrind!" => \$main::opt_callgrind,
- "list=s" => \$main::opt_list,
- "disasm=s" => \$main::opt_disasm,
- "symbols!" => \$main::opt_symbols,
- "gv!" => \$main::opt_gv,
- "evince!" => \$main::opt_evince,
- "web!" => \$main::opt_web,
- "dot!" => \$main::opt_dot,
- "ps!" => \$main::opt_ps,
- "pdf!" => \$main::opt_pdf,
- "svg!" => \$main::opt_svg,
- "gif!" => \$main::opt_gif,
- "raw!" => \$main::opt_raw,
- "interactive!" => \$main::opt_interactive,
- "nodecount=i" => \$main::opt_nodecount,
- "nodefraction=f" => \$main::opt_nodefraction,
- "edgefraction=f" => \$main::opt_edgefraction,
- "maxdegree=i" => \$main::opt_maxdegree,
- "focus=s" => \$main::opt_focus,
- "thread=s" => \$main::opt_thread,
- "ignore=s" => \$main::opt_ignore,
- "scale=i" => \$main::opt_scale,
- "heapcheck" => \$main::opt_heapcheck,
- "retain=s" => \$main::opt_retain,
- "exclude=s" => \$main::opt_exclude,
- "inuse_space!" => \$main::opt_inuse_space,
- "inuse_objects!" => \$main::opt_inuse_objects,
- "alloc_space!" => \$main::opt_alloc_space,
- "alloc_objects!" => \$main::opt_alloc_objects,
- "show_bytes!" => \$main::opt_show_bytes,
- "drop_negative!" => \$main::opt_drop_negative,
- "total_delay!" => \$main::opt_total_delay,
- "contentions!" => \$main::opt_contentions,
- "mean_delay!" => \$main::opt_mean_delay,
- "tools=s" => \$main::opt_tools,
- "test!" => \$main::opt_test,
- "debug!" => \$main::opt_debug,
- # Undocumented flags used only by unittests:
- "test_stride=i" => \$main::opt_test_stride,
- ) || usage("Invalid option(s)");
-
- # Deal with the standard --help and --version
- if ($main::opt_help) {
- print usage_string();
- exit(0);
- }
-
- if ($main::opt_version) {
- print version_string();
- exit(0);
- }
-
- # Disassembly/listing/symbols mode requires address-level info
- if ($main::opt_disasm || $main::opt_list || $main::opt_symbols) {
- $main::opt_functions = 0;
- $main::opt_lines = 0;
- $main::opt_addresses = 1;
- $main::opt_files = 0;
- }
-
- # Check heap-profiling flags
- if ($main::opt_inuse_space +
- $main::opt_inuse_objects +
- $main::opt_alloc_space +
- $main::opt_alloc_objects > 1) {
- usage("Specify at most on of --inuse/--alloc options");
- }
-
- # Check output granularities
- my $grains =
- $main::opt_functions +
- $main::opt_lines +
- $main::opt_addresses +
- $main::opt_files +
- 0;
- if ($grains > 1) {
- usage("Only specify one output granularity option");
- }
- if ($grains == 0) {
- $main::opt_functions = 1;
- }
-
- # Check output modes
- my $modes =
- $main::opt_text +
- $main::opt_callgrind +
- ($main::opt_list eq '' ? 0 : 1) +
- ($main::opt_disasm eq '' ? 0 : 1) +
- ($main::opt_symbols == 0 ? 0 : 1) +
- $main::opt_gv +
- $main::opt_evince +
- $main::opt_web +
- $main::opt_dot +
- $main::opt_ps +
- $main::opt_pdf +
- $main::opt_svg +
- $main::opt_gif +
- $main::opt_raw +
- $main::opt_interactive +
- 0;
- if ($modes > 1) {
- usage("Only specify one output mode");
- }
- if ($modes == 0) {
- if (-t STDOUT) { # If STDOUT is a tty, activate interactive mode
- $main::opt_interactive = 1;
- } else {
- $main::opt_text = 1;
- }
- }
-
- if ($main::opt_test) {
- RunUnitTests();
- # Should not return
- exit(1);
- }
-
- # Binary name and profile arguments list
- $main::prog = "";
- @main::pfile_args = ();
-
- # Remote profiling without a binary (using $SYMBOL_PAGE instead)
- if (@ARGV > 0) {
- if (IsProfileURL($ARGV[0])) {
- $main::use_symbol_page = 1;
- } elsif (IsSymbolizedProfileFile($ARGV[0])) {
- $main::use_symbolized_profile = 1;
- $main::prog = $UNKNOWN_BINARY; # will be set later from the profile file
- }
- }
-
- if ($main::use_symbol_page || $main::use_symbolized_profile) {
- # We don't need a binary!
- my %disabled = ('--lines' => $main::opt_lines,
- '--disasm' => $main::opt_disasm);
- for my $option (keys %disabled) {
- usage("$option cannot be used without a binary") if $disabled{$option};
- }
- # Set $main::prog later...
- scalar(@ARGV) || usage("Did not specify profile file");
- } elsif ($main::opt_symbols) {
- # --symbols needs a binary-name (to run nm on, etc) but not profiles
- $main::prog = shift(@ARGV) || usage("Did not specify program");
- } else {
- $main::prog = shift(@ARGV) || usage("Did not specify program");
- scalar(@ARGV) || usage("Did not specify profile file");
- }
-
- # Parse profile file/location arguments
- foreach my $farg (@ARGV) {
- if ($farg =~ m/(.*)\@([0-9]+)(|\/.*)$/ ) {
- my $machine = $1;
- my $num_machines = $2;
- my $path = $3;
- for (my $i = 0; $i < $num_machines; $i++) {
- unshift(@main::pfile_args, "$i.$machine$path");
- }
- } else {
- unshift(@main::pfile_args, $farg);
- }
- }
-
- if ($main::use_symbol_page) {
- unless (IsProfileURL($main::pfile_args[0])) {
- error("The first profile should be a remote form to use $SYMBOL_PAGE\n");
- }
- CheckSymbolPage();
- $main::prog = FetchProgramName();
- } elsif (!$main::use_symbolized_profile) { # may not need objtools!
- ConfigureObjTools($main::prog)
- }
-
- # Break the opt_lib_prefix into the prefix_list array
- @prefix_list = split (',', $main::opt_lib_prefix);
-
- # Remove trailing / from the prefixes, in the list to prevent
- # searching things like /my/path//lib/mylib.so
- foreach (@prefix_list) {
- s|/+$||;
- }
-}
-
-sub FilterAndPrint {
- my ($profile, $symbols, $libs, $thread) = @_;
-
- # Get total data in profile
- my $total = TotalProfile($profile);
-
- # Remove uniniteresting stack items
- $profile = RemoveUninterestingFrames($symbols, $profile);
-
- # Focus?
- if ($main::opt_focus ne '') {
- $profile = FocusProfile($symbols, $profile, $main::opt_focus);
- }
-
- # Ignore?
- if ($main::opt_ignore ne '') {
- $profile = IgnoreProfile($symbols, $profile, $main::opt_ignore);
- }
-
- my $calls = ExtractCalls($symbols, $profile);
-
- # Reduce profiles to required output granularity, and also clean
- # each stack trace so a given entry exists at most once.
- my $reduced = ReduceProfile($symbols, $profile);
-
- # Get derived profiles
- my $flat = FlatProfile($reduced);
- my $cumulative = CumulativeProfile($reduced);
-
- # Print
- if (!$main::opt_interactive) {
- if ($main::opt_disasm) {
- PrintDisassembly($libs, $flat, $cumulative, $main::opt_disasm);
- } elsif ($main::opt_list) {
- PrintListing($total, $libs, $flat, $cumulative, $main::opt_list, 0);
- } elsif ($main::opt_text) {
- # Make sure the output is empty when have nothing to report
- # (only matters when --heapcheck is given but we must be
- # compatible with old branches that did not pass --heapcheck always):
- if ($total != 0) {
- printf("Total%s: %s %s\n",
- (defined($thread) ? " (t$thread)" : ""),
- Unparse($total), Units());
- }
- PrintText($symbols, $flat, $cumulative, -1);
- } elsif ($main::opt_raw) {
- PrintSymbolizedProfile($symbols, $profile, $main::prog);
- } elsif ($main::opt_callgrind) {
- PrintCallgrind($calls);
- } else {
- if (PrintDot($main::prog, $symbols, $profile, $flat, $cumulative, $total)) {
- if ($main::opt_gv) {
- RunGV(TempName($main::next_tmpfile, "ps"), "");
- } elsif ($main::opt_evince) {
- RunEvince(TempName($main::next_tmpfile, "pdf"), "");
- } elsif ($main::opt_web) {
- my $tmp = TempName($main::next_tmpfile, "svg");
- RunWeb($tmp);
- # The command we run might hand the file name off
- # to an already running browser instance and then exit.
- # Normally, we'd remove $tmp on exit (right now),
- # but fork a child to remove $tmp a little later, so that the
- # browser has time to load it first.
- delete $main::tempnames{$tmp};
- if (fork() == 0) {
- sleep 5;
- unlink($tmp);
- exit(0);
- }
- }
- } else {
- cleanup();
- exit(1);
- }
- }
- } else {
- InteractiveMode($profile, $symbols, $libs, $total);
- }
-}
-
-sub Main() {
- Init();
- $main::collected_profile = undef;
- @main::profile_files = ();
- $main::op_time = time();
-
- # Printing symbols is special and requires a lot less info that most.
- if ($main::opt_symbols) {
- PrintSymbols(*STDIN); # Get /proc/maps and symbols output from stdin
- return;
- }
-
- # Fetch all profile data
- FetchDynamicProfiles();
-
- # this will hold symbols that we read from the profile files
- my $symbol_map = {};
-
- # Read one profile, pick the last item on the list
- my $data = ReadProfile($main::prog, pop(@main::profile_files));
- my $profile = $data->{profile};
- my $pcs = $data->{pcs};
- my $libs = $data->{libs}; # Info about main program and shared libraries
- $symbol_map = MergeSymbols($symbol_map, $data->{symbols});
-
- # Add additional profiles, if available.
- if (scalar(@main::profile_files) > 0) {
- foreach my $pname (@main::profile_files) {
- my $data2 = ReadProfile($main::prog, $pname);
- $profile = AddProfile($profile, $data2->{profile});
- $pcs = AddPcs($pcs, $data2->{pcs});
- $symbol_map = MergeSymbols($symbol_map, $data2->{symbols});
- }
- }
-
- # Subtract base from profile, if specified
- if ($main::opt_base ne '') {
- my $base = ReadProfile($main::prog, $main::opt_base);
- $profile = SubtractProfile($profile, $base->{profile});
- $pcs = AddPcs($pcs, $base->{pcs});
- $symbol_map = MergeSymbols($symbol_map, $base->{symbols});
- }
-
- # Collect symbols
- my $symbols;
- if ($main::use_symbolized_profile) {
- $symbols = FetchSymbols($pcs, $symbol_map);
- } elsif ($main::use_symbol_page) {
- $symbols = FetchSymbols($pcs);
- } else {
- # TODO(csilvers): $libs uses the /proc/self/maps data from profile1,
- # which may differ from the data from subsequent profiles, especially
- # if they were run on different machines. Use appropriate libs for
- # each pc somehow.
- $symbols = ExtractSymbols($libs, $pcs);
- }
-
- if (!defined($main::opt_thread)) {
- FilterAndPrint($profile, $symbols, $libs);
- }
- if (defined($data->{threads})) {
- foreach my $thread (sort { $a <=> $b } keys(%{$data->{threads}})) {
- if (defined($main::opt_thread) &&
- ($main::opt_thread eq '*' || $main::opt_thread == $thread)) {
- my $thread_profile = $data->{threads}{$thread};
- FilterAndPrint($thread_profile, $symbols, $libs, $thread);
- }
- }
- }
-
- cleanup();
- exit(0);
-}
-
-##### Entry Point #####
-
-Main();
-
-# Temporary code to detect if we're running on a Goobuntu system.
-# These systems don't have the right stuff installed for the special
-# Readline libraries to work, so as a temporary workaround, we default
-# to using the normal stdio code, rather than the fancier readline-based
-# code
-sub ReadlineMightFail {
- if (-e '/lib/libtermcap.so.2') {
- return 0; # libtermcap exists, so readline should be okay
- } else {
- return 1;
- }
-}
-
-sub RunGV {
- my $fname = shift;
- my $bg = shift; # "" or " &" if we should run in background
- if (!system(ShellEscape(@GV, "--version") . " >$dev_null 2>&1")) {
- # Options using double dash are supported by this gv version.
- # Also, turn on noantialias to better handle bug in gv for
- # postscript files with large dimensions.
- # TODO: Maybe we should not pass the --noantialias flag
- # if the gv version is known to work properly without the flag.
- system(ShellEscape(@GV, "--scale=$main::opt_scale", "--noantialias", $fname)
- . $bg);
- } else {
- # Old gv version - only supports options that use single dash.
- print STDERR ShellEscape(@GV, "-scale", $main::opt_scale) . "\n";
- system(ShellEscape(@GV, "-scale", "$main::opt_scale", $fname) . $bg);
- }
-}
-
-sub RunEvince {
- my $fname = shift;
- my $bg = shift; # "" or " &" if we should run in background
- system(ShellEscape(@EVINCE, $fname) . $bg);
-}
-
-sub RunWeb {
- my $fname = shift;
- print STDERR "Loading web page file:///$fname\n";
-
- if (`uname` =~ /Darwin/) {
- # OS X: open will use standard preference for SVG files.
- system("/usr/bin/open", $fname);
- return;
- }
-
- # Some kind of Unix; try generic symlinks, then specific browsers.
- # (Stop once we find one.)
- # Works best if the browser is already running.
- my @alt = (
- "/etc/alternatives/gnome-www-browser",
- "/etc/alternatives/x-www-browser",
- "google-chrome",
- "firefox",
- );
- foreach my $b (@alt) {
- if (system($b, $fname) == 0) {
- return;
- }
- }
-
- print STDERR "Could not load web browser.\n";
-}
-
-sub RunKcachegrind {
- my $fname = shift;
- my $bg = shift; # "" or " &" if we should run in background
- print STDERR "Starting '@KCACHEGRIND " . $fname . $bg . "'\n";
- system(ShellEscape(@KCACHEGRIND, $fname) . $bg);
-}
-
-
-##### Interactive helper routines #####
-
-sub InteractiveMode {
- $| = 1; # Make output unbuffered for interactive mode
- my ($orig_profile, $symbols, $libs, $total) = @_;
-
- print STDERR "Welcome to jeprof! For help, type 'help'.\n";
-
- # Use ReadLine if it's installed and input comes from a console.
- if ( -t STDIN &&
- !ReadlineMightFail() &&
- defined(eval {require Term::ReadLine}) ) {
- my $term = new Term::ReadLine 'jeprof';
- while ( defined ($_ = $term->readline('(jeprof) '))) {
- $term->addhistory($_) if /\S/;
- if (!InteractiveCommand($orig_profile, $symbols, $libs, $total, $_)) {
- last; # exit when we get an interactive command to quit
- }
- }
- } else { # don't have readline
- while (1) {
- print STDERR "(jeprof) ";
- $_ = <STDIN>;
- last if ! defined $_ ;
- s/\r//g; # turn windows-looking lines into unix-looking lines
-
- # Save some flags that might be reset by InteractiveCommand()
- my $save_opt_lines = $main::opt_lines;
-
- if (!InteractiveCommand($orig_profile, $symbols, $libs, $total, $_)) {
- last; # exit when we get an interactive command to quit
- }
-
- # Restore flags
- $main::opt_lines = $save_opt_lines;
- }
- }
-}
-
-# Takes two args: orig profile, and command to run.
-# Returns 1 if we should keep going, or 0 if we were asked to quit
-sub InteractiveCommand {
- my($orig_profile, $symbols, $libs, $total, $command) = @_;
- $_ = $command; # just to make future m//'s easier
- if (!defined($_)) {
- print STDERR "\n";
- return 0;
- }
- if (m/^\s*quit/) {
- return 0;
- }
- if (m/^\s*help/) {
- InteractiveHelpMessage();
- return 1;
- }
- # Clear all the mode options -- mode is controlled by "$command"
- $main::opt_text = 0;
- $main::opt_callgrind = 0;
- $main::opt_disasm = 0;
- $main::opt_list = 0;
- $main::opt_gv = 0;
- $main::opt_evince = 0;
- $main::opt_cum = 0;
-
- if (m/^\s*(text|top)(\d*)\s*(.*)/) {
- $main::opt_text = 1;
-
- my $line_limit = ($2 ne "") ? int($2) : 10;
-
- my $routine;
- my $ignore;
- ($routine, $ignore) = ParseInteractiveArgs($3);
-
- my $profile = ProcessProfile($total, $orig_profile, $symbols, "", $ignore);
- my $reduced = ReduceProfile($symbols, $profile);
-
- # Get derived profiles
- my $flat = FlatProfile($reduced);
- my $cumulative = CumulativeProfile($reduced);
-
- PrintText($symbols, $flat, $cumulative, $line_limit);
- return 1;
- }
- if (m/^\s*callgrind\s*([^ \n]*)/) {
- $main::opt_callgrind = 1;
-
- # Get derived profiles
- my $calls = ExtractCalls($symbols, $orig_profile);
- my $filename = $1;
- if ( $1 eq '' ) {
- $filename = TempName($main::next_tmpfile, "callgrind");
- }
- PrintCallgrind($calls, $filename);
- if ( $1 eq '' ) {
- RunKcachegrind($filename, " & ");
- $main::next_tmpfile++;
- }
-
- return 1;
- }
- if (m/^\s*(web)?list\s*(.+)/) {
- my $html = (defined($1) && ($1 eq "web"));
- $main::opt_list = 1;
-
- my $routine;
- my $ignore;
- ($routine, $ignore) = ParseInteractiveArgs($2);
-
- my $profile = ProcessProfile($total, $orig_profile, $symbols, "", $ignore);
- my $reduced = ReduceProfile($symbols, $profile);
-
- # Get derived profiles
- my $flat = FlatProfile($reduced);
- my $cumulative = CumulativeProfile($reduced);
-
- PrintListing($total, $libs, $flat, $cumulative, $routine, $html);
- return 1;
- }
- if (m/^\s*disasm\s*(.+)/) {
- $main::opt_disasm = 1;
-
- my $routine;
- my $ignore;
- ($routine, $ignore) = ParseInteractiveArgs($1);
-
- # Process current profile to account for various settings
- my $profile = ProcessProfile($total, $orig_profile, $symbols, "", $ignore);
- my $reduced = ReduceProfile($symbols, $profile);
-
- # Get derived profiles
- my $flat = FlatProfile($reduced);
- my $cumulative = CumulativeProfile($reduced);
-
- PrintDisassembly($libs, $flat, $cumulative, $routine);
- return 1;
- }
- if (m/^\s*(gv|web|evince)\s*(.*)/) {
- $main::opt_gv = 0;
- $main::opt_evince = 0;
- $main::opt_web = 0;
- if ($1 eq "gv") {
- $main::opt_gv = 1;
- } elsif ($1 eq "evince") {
- $main::opt_evince = 1;
- } elsif ($1 eq "web") {
- $main::opt_web = 1;
- }
-
- my $focus;
- my $ignore;
- ($focus, $ignore) = ParseInteractiveArgs($2);
-
- # Process current profile to account for various settings
- my $profile = ProcessProfile($total, $orig_profile, $symbols,
- $focus, $ignore);
- my $reduced = ReduceProfile($symbols, $profile);
-
- # Get derived profiles
- my $flat = FlatProfile($reduced);
- my $cumulative = CumulativeProfile($reduced);
-
- if (PrintDot($main::prog, $symbols, $profile, $flat, $cumulative, $total)) {
- if ($main::opt_gv) {
- RunGV(TempName($main::next_tmpfile, "ps"), " &");
- } elsif ($main::opt_evince) {
- RunEvince(TempName($main::next_tmpfile, "pdf"), " &");
- } elsif ($main::opt_web) {
- RunWeb(TempName($main::next_tmpfile, "svg"));
- }
- $main::next_tmpfile++;
- }
- return 1;
- }
- if (m/^\s*$/) {
- return 1;
- }
- print STDERR "Unknown command: try 'help'.\n";
- return 1;
-}
-
-
-sub ProcessProfile {
- my $total_count = shift;
- my $orig_profile = shift;
- my $symbols = shift;
- my $focus = shift;
- my $ignore = shift;
-
- # Process current profile to account for various settings
- my $profile = $orig_profile;
- printf("Total: %s %s\n", Unparse($total_count), Units());
- if ($focus ne '') {
- $profile = FocusProfile($symbols, $profile, $focus);
- my $focus_count = TotalProfile($profile);
- printf("After focusing on '%s': %s %s of %s (%0.1f%%)\n",
- $focus,
- Unparse($focus_count), Units(),
- Unparse($total_count), ($focus_count*100.0) / $total_count);
- }
- if ($ignore ne '') {
- $profile = IgnoreProfile($symbols, $profile, $ignore);
- my $ignore_count = TotalProfile($profile);
- printf("After ignoring '%s': %s %s of %s (%0.1f%%)\n",
- $ignore,
- Unparse($ignore_count), Units(),
- Unparse($total_count),
- ($ignore_count*100.0) / $total_count);
- }
-
- return $profile;
-}
-
-sub InteractiveHelpMessage {
- print STDERR <<ENDOFHELP;
-Interactive jeprof mode
-
-Commands:
- gv
- gv [focus] [-ignore1] [-ignore2]
- Show graphical hierarchical display of current profile. Without
- any arguments, shows all samples in the profile. With the optional
- "focus" argument, restricts the samples shown to just those where
- the "focus" regular expression matches a routine name on the stack
- trace.
-
- web
- web [focus] [-ignore1] [-ignore2]
- Like GV, but displays profile in your web browser instead of using
- Ghostview. Works best if your web browser is already running.
- To change the browser that gets used:
- On Linux, set the /etc/alternatives/gnome-www-browser symlink.
- On OS X, change the Finder association for SVG files.
-
- list [routine_regexp] [-ignore1] [-ignore2]
- Show source listing of routines whose names match "routine_regexp"
-
- weblist [routine_regexp] [-ignore1] [-ignore2]
- Displays a source listing of routines whose names match "routine_regexp"
- in a web browser. You can click on source lines to view the
- corresponding disassembly.
-
- top [--cum] [-ignore1] [-ignore2]
- top20 [--cum] [-ignore1] [-ignore2]
- top37 [--cum] [-ignore1] [-ignore2]
- Show top lines ordered by flat profile count, or cumulative count
- if --cum is specified. If a number is present after 'top', the
- top K routines will be shown (defaults to showing the top 10)
-
- disasm [routine_regexp] [-ignore1] [-ignore2]
- Show disassembly of routines whose names match "routine_regexp",
- annotated with sample counts.
-
- callgrind
- callgrind [filename]
- Generates callgrind file. If no filename is given, kcachegrind is called.
-
- help - This listing
- quit or ^D - End jeprof
-
-For commands that accept optional -ignore tags, samples where any routine in
-the stack trace matches the regular expression in any of the -ignore
-parameters will be ignored.
-
-Further pprof details are available at this location (or one similar):
-
- /usr/doc/gperftools-$PPROF_VERSION/cpu_profiler.html
- /usr/doc/gperftools-$PPROF_VERSION/heap_profiler.html
-
-ENDOFHELP
-}
-sub ParseInteractiveArgs {
- my $args = shift;
- my $focus = "";
- my $ignore = "";
- my @x = split(/ +/, $args);
- foreach $a (@x) {
- if ($a =~ m/^(--|-)lines$/) {
- $main::opt_lines = 1;
- } elsif ($a =~ m/^(--|-)cum$/) {
- $main::opt_cum = 1;
- } elsif ($a =~ m/^-(.*)/) {
- $ignore .= (($ignore ne "") ? "|" : "" ) . $1;
- } else {
- $focus .= (($focus ne "") ? "|" : "" ) . $a;
- }
- }
- if ($ignore ne "") {
- print STDERR "Ignoring samples in call stacks that match '$ignore'\n";
- }
- return ($focus, $ignore);
-}
-
-##### Output code #####
-
-sub TempName {
- my $fnum = shift;
- my $ext = shift;
- my $file = "$main::tmpfile_ps.$fnum.$ext";
- $main::tempnames{$file} = 1;
- return $file;
-}
-
-# Print profile data in packed binary format (64-bit) to standard out
-sub PrintProfileData {
- my $profile = shift;
-
- # print header (64-bit style)
- # (zero) (header-size) (version) (sample-period) (zero)
- print pack('L*', 0, 0, 3, 0, 0, 0, 1, 0, 0, 0);
-
- foreach my $k (keys(%{$profile})) {
- my $count = $profile->{$k};
- my @addrs = split(/\n/, $k);
- if ($#addrs >= 0) {
- my $depth = $#addrs + 1;
- # int(foo / 2**32) is the only reliable way to get rid of bottom
- # 32 bits on both 32- and 64-bit systems.
- print pack('L*', $count & 0xFFFFFFFF, int($count / 2**32));
- print pack('L*', $depth & 0xFFFFFFFF, int($depth / 2**32));
-
- foreach my $full_addr (@addrs) {
- my $addr = $full_addr;
- $addr =~ s/0x0*//; # strip off leading 0x, zeroes
- if (length($addr) > 16) {
- print STDERR "Invalid address in profile: $full_addr\n";
- next;
- }
- my $low_addr = substr($addr, -8); # get last 8 hex chars
- my $high_addr = substr($addr, -16, 8); # get up to 8 more hex chars
- print pack('L*', hex('0x' . $low_addr), hex('0x' . $high_addr));
- }
- }
- }
-}
-
-# Print symbols and profile data
-sub PrintSymbolizedProfile {
- my $symbols = shift;
- my $profile = shift;
- my $prog = shift;
-
- $SYMBOL_PAGE =~ m,[^/]+$,; # matches everything after the last slash
- my $symbol_marker = $&;
-
- print '--- ', $symbol_marker, "\n";
- if (defined($prog)) {
- print 'binary=', $prog, "\n";
- }
- while (my ($pc, $name) = each(%{$symbols})) {
- my $sep = ' ';
- print '0x', $pc;
- # We have a list of function names, which include the inlined
- # calls. They are separated (and terminated) by --, which is
- # illegal in function names.
- for (my $j = 2; $j <= $#{$name}; $j += 3) {
- print $sep, $name->[$j];
- $sep = '--';
- }
- print "\n";
- }
- print '---', "\n";
-
- my $profile_marker;
- if ($main::profile_type eq 'heap') {
- $HEAP_PAGE =~ m,[^/]+$,; # matches everything after the last slash
- $profile_marker = $&;
- } elsif ($main::profile_type eq 'growth') {
- $GROWTH_PAGE =~ m,[^/]+$,; # matches everything after the last slash
- $profile_marker = $&;
- } elsif ($main::profile_type eq 'contention') {
- $CONTENTION_PAGE =~ m,[^/]+$,; # matches everything after the last slash
- $profile_marker = $&;
- } else { # elsif ($main::profile_type eq 'cpu')
- $PROFILE_PAGE =~ m,[^/]+$,; # matches everything after the last slash
- $profile_marker = $&;
- }
-
- print '--- ', $profile_marker, "\n";
- if (defined($main::collected_profile)) {
- # if used with remote fetch, simply dump the collected profile to output.
- open(SRC, "<$main::collected_profile");
- while (<SRC>) {
- print $_;
- }
- close(SRC);
- } else {
- # --raw/http: For everything to work correctly for non-remote profiles, we
- # would need to extend PrintProfileData() to handle all possible profile
- # types, re-enable the code that is currently disabled in ReadCPUProfile()
- # and FixCallerAddresses(), and remove the remote profile dumping code in
- # the block above.
- die "--raw/http: jeprof can only dump remote profiles for --raw\n";
- # dump a cpu-format profile to standard out
- PrintProfileData($profile);
- }
-}
-
-# Print text output
-sub PrintText {
- my $symbols = shift;
- my $flat = shift;
- my $cumulative = shift;
- my $line_limit = shift;
-
- my $total = TotalProfile($flat);
-
- # Which profile to sort by?
- my $s = $main::opt_cum ? $cumulative : $flat;
-
- my $running_sum = 0;
- my $lines = 0;
- foreach my $k (sort { GetEntry($s, $b) <=> GetEntry($s, $a) || $a cmp $b }
- keys(%{$cumulative})) {
- my $f = GetEntry($flat, $k);
- my $c = GetEntry($cumulative, $k);
- $running_sum += $f;
-
- my $sym = $k;
- if (exists($symbols->{$k})) {
- $sym = $symbols->{$k}->[0] . " " . $symbols->{$k}->[1];
- if ($main::opt_addresses) {
- $sym = $k . " " . $sym;
- }
- }
-
- if ($f != 0 || $c != 0) {
- printf("%8s %6s %6s %8s %6s %s\n",
- Unparse($f),
- Percent($f, $total),
- Percent($running_sum, $total),
- Unparse($c),
- Percent($c, $total),
- $sym);
- }
- $lines++;
- last if ($line_limit >= 0 && $lines >= $line_limit);
- }
-}
-
-# Callgrind format has a compression for repeated function and file
-# names. You show the name the first time, and just use its number
-# subsequently. This can cut down the file to about a third or a
-# quarter of its uncompressed size. $key and $val are the key/value
-# pair that would normally be printed by callgrind; $map is a map from
-# value to number.
-sub CompressedCGName {
- my($key, $val, $map) = @_;
- my $idx = $map->{$val};
- # For very short keys, providing an index hurts rather than helps.
- if (length($val) <= 3) {
- return "$key=$val\n";
- } elsif (defined($idx)) {
- return "$key=($idx)\n";
- } else {
- # scalar(keys $map) gives the number of items in the map.
- $idx = scalar(keys(%{$map})) + 1;
- $map->{$val} = $idx;
- return "$key=($idx) $val\n";
- }
-}
-
-# Print the call graph in a way that's suiteable for callgrind.
-sub PrintCallgrind {
- my $calls = shift;
- my $filename;
- my %filename_to_index_map;
- my %fnname_to_index_map;
-
- if ($main::opt_interactive) {
- $filename = shift;
- print STDERR "Writing callgrind file to '$filename'.\n"
- } else {
- $filename = "&STDOUT";
- }
- open(CG, ">$filename");
- printf CG ("events: Hits\n\n");
- foreach my $call ( map { $_->[0] }
- sort { $a->[1] cmp $b ->[1] ||
- $a->[2] <=> $b->[2] }
- map { /([^:]+):(\d+):([^ ]+)( -> ([^:]+):(\d+):(.+))?/;
- [$_, $1, $2] }
- keys %$calls ) {
- my $count = int($calls->{$call});
- $call =~ /([^:]+):(\d+):([^ ]+)( -> ([^:]+):(\d+):(.+))?/;
- my ( $caller_file, $caller_line, $caller_function,
- $callee_file, $callee_line, $callee_function ) =
- ( $1, $2, $3, $5, $6, $7 );
-
- # TODO(csilvers): for better compression, collect all the
- # caller/callee_files and functions first, before printing
- # anything, and only compress those referenced more than once.
- printf CG CompressedCGName("fl", $caller_file, \%filename_to_index_map);
- printf CG CompressedCGName("fn", $caller_function, \%fnname_to_index_map);
- if (defined $6) {
- printf CG CompressedCGName("cfl", $callee_file, \%filename_to_index_map);
- printf CG CompressedCGName("cfn", $callee_function, \%fnname_to_index_map);
- printf CG ("calls=$count $callee_line\n");
- }
- printf CG ("$caller_line $count\n\n");
- }
-}
-
-# Print disassembly for all all routines that match $main::opt_disasm
-sub PrintDisassembly {
- my $libs = shift;
- my $flat = shift;
- my $cumulative = shift;
- my $disasm_opts = shift;
-
- my $total = TotalProfile($flat);
-
- foreach my $lib (@{$libs}) {
- my $symbol_table = GetProcedureBoundaries($lib->[0], $disasm_opts);
- my $offset = AddressSub($lib->[1], $lib->[3]);
- foreach my $routine (sort ByName keys(%{$symbol_table})) {
- my $start_addr = $symbol_table->{$routine}->[0];
- my $end_addr = $symbol_table->{$routine}->[1];
- # See if there are any samples in this routine
- my $length = hex(AddressSub($end_addr, $start_addr));
- my $addr = AddressAdd($start_addr, $offset);
- for (my $i = 0; $i < $length; $i++) {
- if (defined($cumulative->{$addr})) {
- PrintDisassembledFunction($lib->[0], $offset,
- $routine, $flat, $cumulative,
- $start_addr, $end_addr, $total);
- last;
- }
- $addr = AddressInc($addr);
- }
- }
- }
-}
-
-# Return reference to array of tuples of the form:
-# [start_address, filename, linenumber, instruction, limit_address]
-# E.g.,
-# ["0x806c43d", "/foo/bar.cc", 131, "ret", "0x806c440"]
-sub Disassemble {
- my $prog = shift;
- my $offset = shift;
- my $start_addr = shift;
- my $end_addr = shift;
-
- my $objdump = $obj_tool_map{"objdump"};
- my $cmd = ShellEscape($objdump, "-C", "-d", "-l", "--no-show-raw-insn",
- "--start-address=0x$start_addr",
- "--stop-address=0x$end_addr", $prog);
- open(OBJDUMP, "$cmd |") || error("$cmd: $!\n");
- my @result = ();
- my $filename = "";
- my $linenumber = -1;
- my $last = ["", "", "", ""];
- while (<OBJDUMP>) {
- s/\r//g; # turn windows-looking lines into unix-looking lines
- chop;
- if (m|\s*([^:\s]+):(\d+)\s*$|) {
- # Location line of the form:
- # <filename>:<linenumber>
- $filename = $1;
- $linenumber = $2;
- } elsif (m/^ +([0-9a-f]+):\s*(.*)/) {
- # Disassembly line -- zero-extend address to full length
- my $addr = HexExtend($1);
- my $k = AddressAdd($addr, $offset);
- $last->[4] = $k; # Store ending address for previous instruction
- $last = [$k, $filename, $linenumber, $2, $end_addr];
- push(@result, $last);
- }
- }
- close(OBJDUMP);
- return @result;
-}
-
-# The input file should contain lines of the form /proc/maps-like
-# output (same format as expected from the profiles) or that looks
-# like hex addresses (like "0xDEADBEEF"). We will parse all
-# /proc/maps output, and for all the hex addresses, we will output
-# "short" symbol names, one per line, in the same order as the input.
-sub PrintSymbols {
- my $maps_and_symbols_file = shift;
-
- # ParseLibraries expects pcs to be in a set. Fine by us...
- my @pclist = (); # pcs in sorted order
- my $pcs = {};
- my $map = "";
- foreach my $line (<$maps_and_symbols_file>) {
- $line =~ s/\r//g; # turn windows-looking lines into unix-looking lines
- if ($line =~ /\b(0x[0-9a-f]+)\b/i) {
- push(@pclist, HexExtend($1));
- $pcs->{$pclist[-1]} = 1;
- } else {
- $map .= $line;
- }
- }
-
- my $libs = ParseLibraries($main::prog, $map, $pcs);
- my $symbols = ExtractSymbols($libs, $pcs);
-
- foreach my $pc (@pclist) {
- # ->[0] is the shortname, ->[2] is the full name
- print(($symbols->{$pc}->[0] || "??") . "\n");
- }
-}
-
-
-# For sorting functions by name
-sub ByName {
- return ShortFunctionName($a) cmp ShortFunctionName($b);
-}
-
-# Print source-listing for all all routines that match $list_opts
-sub PrintListing {
- my $total = shift;
- my $libs = shift;
- my $flat = shift;
- my $cumulative = shift;
- my $list_opts = shift;
- my $html = shift;
-
- my $output = \*STDOUT;
- my $fname = "";
-
- if ($html) {
- # Arrange to write the output to a temporary file
- $fname = TempName($main::next_tmpfile, "html");
- $main::next_tmpfile++;
- if (!open(TEMP, ">$fname")) {
- print STDERR "$fname: $!\n";
- return;
- }
- $output = \*TEMP;
- print $output HtmlListingHeader();
- printf $output ("<div class=\"legend\">%s<br>Total: %s %s</div>\n",
- $main::prog, Unparse($total), Units());
- }
-
- my $listed = 0;
- foreach my $lib (@{$libs}) {
- my $symbol_table = GetProcedureBoundaries($lib->[0], $list_opts);
- my $offset = AddressSub($lib->[1], $lib->[3]);
- foreach my $routine (sort ByName keys(%{$symbol_table})) {
- # Print if there are any samples in this routine
- my $start_addr = $symbol_table->{$routine}->[0];
- my $end_addr = $symbol_table->{$routine}->[1];
- my $length = hex(AddressSub($end_addr, $start_addr));
- my $addr = AddressAdd($start_addr, $offset);
- for (my $i = 0; $i < $length; $i++) {
- if (defined($cumulative->{$addr})) {
- $listed += PrintSource(
- $lib->[0], $offset,
- $routine, $flat, $cumulative,
- $start_addr, $end_addr,
- $html,
- $output);
- last;
- }
- $addr = AddressInc($addr);
- }
- }
- }
-
- if ($html) {
- if ($listed > 0) {
- print $output HtmlListingFooter();
- close($output);
- RunWeb($fname);
- } else {
- close($output);
- unlink($fname);
- }
- }
-}
-
-sub HtmlListingHeader {
- return <<'EOF';
-<DOCTYPE html>
-<html>
-<head>
-<title>Pprof listing</title>
-<style type="text/css">
-body {
- font-family: sans-serif;
-}
-h1 {
- font-size: 1.5em;
- margin-bottom: 4px;
-}
-.legend {
- font-size: 1.25em;
-}
-.line {
- color: #aaaaaa;
-}
-.nop {
- color: #aaaaaa;
-}
-.unimportant {
- color: #cccccc;
-}
-.disasmloc {
- color: #000000;
-}
-.deadsrc {
- cursor: pointer;
-}
-.deadsrc:hover {
- background-color: #eeeeee;
-}
-.livesrc {
- color: #0000ff;
- cursor: pointer;
-}
-.livesrc:hover {
- background-color: #eeeeee;
-}
-.asm {
- color: #008800;
- display: none;
-}
-</style>
-<script type="text/javascript">
-function jeprof_toggle_asm(e) {
- var target;
- if (!e) e = window.event;
- if (e.target) target = e.target;
- else if (e.srcElement) target = e.srcElement;
-
- if (target) {
- var asm = target.nextSibling;
- if (asm && asm.className == "asm") {
- asm.style.display = (asm.style.display == "block" ? "" : "block");
- e.preventDefault();
- return false;
- }
- }
-}
-</script>
-</head>
-<body>
-EOF
-}
-
-sub HtmlListingFooter {
- return <<'EOF';
-</body>
-</html>
-EOF
-}
-
-sub HtmlEscape {
- my $text = shift;
- $text =~ s/&/&amp;/g;
- $text =~ s/</&lt;/g;
- $text =~ s/>/&gt;/g;
- return $text;
-}
-
-# Returns the indentation of the line, if it has any non-whitespace
-# characters. Otherwise, returns -1.
-sub Indentation {
- my $line = shift;
- if (m/^(\s*)\S/) {
- return length($1);
- } else {
- return -1;
- }
-}
-
-# If the symbol table contains inlining info, Disassemble() may tag an
-# instruction with a location inside an inlined function. But for
-# source listings, we prefer to use the location in the function we
-# are listing. So use MapToSymbols() to fetch full location
-# information for each instruction and then pick out the first
-# location from a location list (location list contains callers before
-# callees in case of inlining).
-#
-# After this routine has run, each entry in $instructions contains:
-# [0] start address
-# [1] filename for function we are listing
-# [2] line number for function we are listing
-# [3] disassembly
-# [4] limit address
-# [5] most specific filename (may be different from [1] due to inlining)
-# [6] most specific line number (may be different from [2] due to inlining)
-sub GetTopLevelLineNumbers {
- my ($lib, $offset, $instructions) = @_;
- my $pcs = [];
- for (my $i = 0; $i <= $#{$instructions}; $i++) {
- push(@{$pcs}, $instructions->[$i]->[0]);
- }
- my $symbols = {};
- MapToSymbols($lib, $offset, $pcs, $symbols);
- for (my $i = 0; $i <= $#{$instructions}; $i++) {
- my $e = $instructions->[$i];
- push(@{$e}, $e->[1]);
- push(@{$e}, $e->[2]);
- my $addr = $e->[0];
- my $sym = $symbols->{$addr};
- if (defined($sym)) {
- if ($#{$sym} >= 2 && $sym->[1] =~ m/^(.*):(\d+)$/) {
- $e->[1] = $1; # File name
- $e->[2] = $2; # Line number
- }
- }
- }
-}
-
-# Print source-listing for one routine
-sub PrintSource {
- my $prog = shift;
- my $offset = shift;
- my $routine = shift;
- my $flat = shift;
- my $cumulative = shift;
- my $start_addr = shift;
- my $end_addr = shift;
- my $html = shift;
- my $output = shift;
-
- # Disassemble all instructions (just to get line numbers)
- my @instructions = Disassemble($prog, $offset, $start_addr, $end_addr);
- GetTopLevelLineNumbers($prog, $offset, \@instructions);
-
- # Hack 1: assume that the first source file encountered in the
- # disassembly contains the routine
- my $filename = undef;
- for (my $i = 0; $i <= $#instructions; $i++) {
- if ($instructions[$i]->[2] >= 0) {
- $filename = $instructions[$i]->[1];
- last;
- }
- }
- if (!defined($filename)) {
- print STDERR "no filename found in $routine\n";
- return 0;
- }
-
- # Hack 2: assume that the largest line number from $filename is the
- # end of the procedure. This is typically safe since if P1 contains
- # an inlined call to P2, then P2 usually occurs earlier in the
- # source file. If this does not work, we might have to compute a
- # density profile or just print all regions we find.
- my $lastline = 0;
- for (my $i = 0; $i <= $#instructions; $i++) {
- my $f = $instructions[$i]->[1];
- my $l = $instructions[$i]->[2];
- if (($f eq $filename) && ($l > $lastline)) {
- $lastline = $l;
- }
- }
-
- # Hack 3: assume the first source location from "filename" is the start of
- # the source code.
- my $firstline = 1;
- for (my $i = 0; $i <= $#instructions; $i++) {
- if ($instructions[$i]->[1] eq $filename) {
- $firstline = $instructions[$i]->[2];
- last;
- }
- }
-
- # Hack 4: Extend last line forward until its indentation is less than
- # the indentation we saw on $firstline
- my $oldlastline = $lastline;
- {
- if (!open(FILE, "<$filename")) {
- print STDERR "$filename: $!\n";
- return 0;
- }
- my $l = 0;
- my $first_indentation = -1;
- while (<FILE>) {
- s/\r//g; # turn windows-looking lines into unix-looking lines
- $l++;
- my $indent = Indentation($_);
- if ($l >= $firstline) {
- if ($first_indentation < 0 && $indent >= 0) {
- $first_indentation = $indent;
- last if ($first_indentation == 0);
- }
- }
- if ($l >= $lastline && $indent >= 0) {
- if ($indent >= $first_indentation) {
- $lastline = $l+1;
- } else {
- last;
- }
- }
- }
- close(FILE);
- }
-
- # Assign all samples to the range $firstline,$lastline,
- # Hack 4: If an instruction does not occur in the range, its samples
- # are moved to the next instruction that occurs in the range.
- my $samples1 = {}; # Map from line number to flat count
- my $samples2 = {}; # Map from line number to cumulative count
- my $running1 = 0; # Unassigned flat counts
- my $running2 = 0; # Unassigned cumulative counts
- my $total1 = 0; # Total flat counts
- my $total2 = 0; # Total cumulative counts
- my %disasm = (); # Map from line number to disassembly
- my $running_disasm = ""; # Unassigned disassembly
- my $skip_marker = "---\n";
- if ($html) {
- $skip_marker = "";
- for (my $l = $firstline; $l <= $lastline; $l++) {
- $disasm{$l} = "";
- }
- }
- my $last_dis_filename = '';
- my $last_dis_linenum = -1;
- my $last_touched_line = -1; # To detect gaps in disassembly for a line
- foreach my $e (@instructions) {
- # Add up counts for all address that fall inside this instruction
- my $c1 = 0;
- my $c2 = 0;
- for (my $a = $e->[0]; $a lt $e->[4]; $a = AddressInc($a)) {
- $c1 += GetEntry($flat, $a);
- $c2 += GetEntry($cumulative, $a);
- }
-
- if ($html) {
- my $dis = sprintf(" %6s %6s \t\t%8s: %s ",
- HtmlPrintNumber($c1),
- HtmlPrintNumber($c2),
- UnparseAddress($offset, $e->[0]),
- CleanDisassembly($e->[3]));
-
- # Append the most specific source line associated with this instruction
- if (length($dis) < 80) { $dis .= (' ' x (80 - length($dis))) };
- $dis = HtmlEscape($dis);
- my $f = $e->[5];
- my $l = $e->[6];
- if ($f ne $last_dis_filename) {
- $dis .= sprintf("<span class=disasmloc>%s:%d</span>",
- HtmlEscape(CleanFileName($f)), $l);
- } elsif ($l ne $last_dis_linenum) {
- # De-emphasize the unchanged file name portion
- $dis .= sprintf("<span class=unimportant>%s</span>" .
- "<span class=disasmloc>:%d</span>",
- HtmlEscape(CleanFileName($f)), $l);
- } else {
- # De-emphasize the entire location
- $dis .= sprintf("<span class=unimportant>%s:%d</span>",
- HtmlEscape(CleanFileName($f)), $l);
- }
- $last_dis_filename = $f;
- $last_dis_linenum = $l;
- $running_disasm .= $dis;
- $running_disasm .= "\n";
- }
-
- $running1 += $c1;
- $running2 += $c2;
- $total1 += $c1;
- $total2 += $c2;
- my $file = $e->[1];
- my $line = $e->[2];
- if (($file eq $filename) &&
- ($line >= $firstline) &&
- ($line <= $lastline)) {
- # Assign all accumulated samples to this line
- AddEntry($samples1, $line, $running1);
- AddEntry($samples2, $line, $running2);
- $running1 = 0;
- $running2 = 0;
- if ($html) {
- if ($line != $last_touched_line && $disasm{$line} ne '') {
- $disasm{$line} .= "\n";
- }
- $disasm{$line} .= $running_disasm;
- $running_disasm = '';
- $last_touched_line = $line;
- }
- }
- }
-
- # Assign any leftover samples to $lastline
- AddEntry($samples1, $lastline, $running1);
- AddEntry($samples2, $lastline, $running2);
- if ($html) {
- if ($lastline != $last_touched_line && $disasm{$lastline} ne '') {
- $disasm{$lastline} .= "\n";
- }
- $disasm{$lastline} .= $running_disasm;
- }
-
- if ($html) {
- printf $output (
- "<h1>%s</h1>%s\n<pre onClick=\"jeprof_toggle_asm()\">\n" .
- "Total:%6s %6s (flat / cumulative %s)\n",
- HtmlEscape(ShortFunctionName($routine)),
- HtmlEscape(CleanFileName($filename)),
- Unparse($total1),
- Unparse($total2),
- Units());
- } else {
- printf $output (
- "ROUTINE ====================== %s in %s\n" .
- "%6s %6s Total %s (flat / cumulative)\n",
- ShortFunctionName($routine),
- CleanFileName($filename),
- Unparse($total1),
- Unparse($total2),
- Units());
- }
- if (!open(FILE, "<$filename")) {
- print STDERR "$filename: $!\n";
- return 0;
- }
- my $l = 0;
- while (<FILE>) {
- s/\r//g; # turn windows-looking lines into unix-looking lines
- $l++;
- if ($l >= $firstline - 5 &&
- (($l <= $oldlastline + 5) || ($l <= $lastline))) {
- chop;
- my $text = $_;
- if ($l == $firstline) { print $output $skip_marker; }
- my $n1 = GetEntry($samples1, $l);
- my $n2 = GetEntry($samples2, $l);
- if ($html) {
- # Emit a span that has one of the following classes:
- # livesrc -- has samples
- # deadsrc -- has disassembly, but with no samples
- # nop -- has no matching disasembly
- # Also emit an optional span containing disassembly.
- my $dis = $disasm{$l};
- my $asm = "";
- if (defined($dis) && $dis ne '') {
- $asm = "<span class=\"asm\">" . $dis . "</span>";
- }
- my $source_class = (($n1 + $n2 > 0)
- ? "livesrc"
- : (($asm ne "") ? "deadsrc" : "nop"));
- printf $output (
- "<span class=\"line\">%5d</span> " .
- "<span class=\"%s\">%6s %6s %s</span>%s\n",
- $l, $source_class,
- HtmlPrintNumber($n1),
- HtmlPrintNumber($n2),
- HtmlEscape($text),
- $asm);
- } else {
- printf $output(
- "%6s %6s %4d: %s\n",
- UnparseAlt($n1),
- UnparseAlt($n2),
- $l,
- $text);
- }
- if ($l == $lastline) { print $output $skip_marker; }
- };
- }
- close(FILE);
- if ($html) {
- print $output "</pre>\n";
- }
- return 1;
-}
-
-# Return the source line for the specified file/linenumber.
-# Returns undef if not found.
-sub SourceLine {
- my $file = shift;
- my $line = shift;
-
- # Look in cache
- if (!defined($main::source_cache{$file})) {
- if (100 < scalar keys(%main::source_cache)) {
- # Clear the cache when it gets too big
- $main::source_cache = ();
- }
-
- # Read all lines from the file
- if (!open(FILE, "<$file")) {
- print STDERR "$file: $!\n";
- $main::source_cache{$file} = []; # Cache the negative result
- return undef;
- }
- my $lines = [];
- push(@{$lines}, ""); # So we can use 1-based line numbers as indices
- while (<FILE>) {
- push(@{$lines}, $_);
- }
- close(FILE);
-
- # Save the lines in the cache
- $main::source_cache{$file} = $lines;
- }
-
- my $lines = $main::source_cache{$file};
- if (($line < 0) || ($line > $#{$lines})) {
- return undef;
- } else {
- return $lines->[$line];
- }
-}
-
-# Print disassembly for one routine with interspersed source if available
-sub PrintDisassembledFunction {
- my $prog = shift;
- my $offset = shift;
- my $routine = shift;
- my $flat = shift;
- my $cumulative = shift;
- my $start_addr = shift;
- my $end_addr = shift;
- my $total = shift;
-
- # Disassemble all instructions
- my @instructions = Disassemble($prog, $offset, $start_addr, $end_addr);
-
- # Make array of counts per instruction
- my @flat_count = ();
- my @cum_count = ();
- my $flat_total = 0;
- my $cum_total = 0;
- foreach my $e (@instructions) {
- # Add up counts for all address that fall inside this instruction
- my $c1 = 0;
- my $c2 = 0;
- for (my $a = $e->[0]; $a lt $e->[4]; $a = AddressInc($a)) {
- $c1 += GetEntry($flat, $a);
- $c2 += GetEntry($cumulative, $a);
- }
- push(@flat_count, $c1);
- push(@cum_count, $c2);
- $flat_total += $c1;
- $cum_total += $c2;
- }
-
- # Print header with total counts
- printf("ROUTINE ====================== %s\n" .
- "%6s %6s %s (flat, cumulative) %.1f%% of total\n",
- ShortFunctionName($routine),
- Unparse($flat_total),
- Unparse($cum_total),
- Units(),
- ($cum_total * 100.0) / $total);
-
- # Process instructions in order
- my $current_file = "";
- for (my $i = 0; $i <= $#instructions; ) {
- my $e = $instructions[$i];
-
- # Print the new file name whenever we switch files
- if ($e->[1] ne $current_file) {
- $current_file = $e->[1];
- my $fname = $current_file;
- $fname =~ s|^\./||; # Trim leading "./"
-
- # Shorten long file names
- if (length($fname) >= 58) {
- $fname = "..." . substr($fname, -55);
- }
- printf("-------------------- %s\n", $fname);
- }
-
- # TODO: Compute range of lines to print together to deal with
- # small reorderings.
- my $first_line = $e->[2];
- my $last_line = $first_line;
- my %flat_sum = ();
- my %cum_sum = ();
- for (my $l = $first_line; $l <= $last_line; $l++) {
- $flat_sum{$l} = 0;
- $cum_sum{$l} = 0;
- }
-
- # Find run of instructions for this range of source lines
- my $first_inst = $i;
- while (($i <= $#instructions) &&
- ($instructions[$i]->[2] >= $first_line) &&
- ($instructions[$i]->[2] <= $last_line)) {
- $e = $instructions[$i];
- $flat_sum{$e->[2]} += $flat_count[$i];
- $cum_sum{$e->[2]} += $cum_count[$i];
- $i++;
- }
- my $last_inst = $i - 1;
-
- # Print source lines
- for (my $l = $first_line; $l <= $last_line; $l++) {
- my $line = SourceLine($current_file, $l);
- if (!defined($line)) {
- $line = "?\n";
- next;
- } else {
- $line =~ s/^\s+//;
- }
- printf("%6s %6s %5d: %s",
- UnparseAlt($flat_sum{$l}),
- UnparseAlt($cum_sum{$l}),
- $l,
- $line);
- }
-
- # Print disassembly
- for (my $x = $first_inst; $x <= $last_inst; $x++) {
- my $e = $instructions[$x];
- printf("%6s %6s %8s: %6s\n",
- UnparseAlt($flat_count[$x]),
- UnparseAlt($cum_count[$x]),
- UnparseAddress($offset, $e->[0]),
- CleanDisassembly($e->[3]));
- }
- }
-}
-
-# Print DOT graph
-sub PrintDot {
- my $prog = shift;
- my $symbols = shift;
- my $raw = shift;
- my $flat = shift;
- my $cumulative = shift;
- my $overall_total = shift;
-
- # Get total
- my $local_total = TotalProfile($flat);
- my $nodelimit = int($main::opt_nodefraction * $local_total);
- my $edgelimit = int($main::opt_edgefraction * $local_total);
- my $nodecount = $main::opt_nodecount;
-
- # Find nodes to include
- my @list = (sort { abs(GetEntry($cumulative, $b)) <=>
- abs(GetEntry($cumulative, $a))
- || $a cmp $b }
- keys(%{$cumulative}));
- my $last = $nodecount - 1;
- if ($last > $#list) {
- $last = $#list;
- }
- while (($last >= 0) &&
- (abs(GetEntry($cumulative, $list[$last])) <= $nodelimit)) {
- $last--;
- }
- if ($last < 0) {
- print STDERR "No nodes to print\n";
- return 0;
- }
-
- if ($nodelimit > 0 || $edgelimit > 0) {
- printf STDERR ("Dropping nodes with <= %s %s; edges with <= %s abs(%s)\n",
- Unparse($nodelimit), Units(),
- Unparse($edgelimit), Units());
- }
-
- # Open DOT output file
- my $output;
- my $escaped_dot = ShellEscape(@DOT);
- my $escaped_ps2pdf = ShellEscape(@PS2PDF);
- if ($main::opt_gv) {
- my $escaped_outfile = ShellEscape(TempName($main::next_tmpfile, "ps"));
- $output = "| $escaped_dot -Tps2 >$escaped_outfile";
- } elsif ($main::opt_evince) {
- my $escaped_outfile = ShellEscape(TempName($main::next_tmpfile, "pdf"));
- $output = "| $escaped_dot -Tps2 | $escaped_ps2pdf - $escaped_outfile";
- } elsif ($main::opt_ps) {
- $output = "| $escaped_dot -Tps2";
- } elsif ($main::opt_pdf) {
- $output = "| $escaped_dot -Tps2 | $escaped_ps2pdf - -";
- } elsif ($main::opt_web || $main::opt_svg) {
- # We need to post-process the SVG, so write to a temporary file always.
- my $escaped_outfile = ShellEscape(TempName($main::next_tmpfile, "svg"));
- $output = "| $escaped_dot -Tsvg >$escaped_outfile";
- } elsif ($main::opt_gif) {
- $output = "| $escaped_dot -Tgif";
- } else {
- $output = ">&STDOUT";
- }
- open(DOT, $output) || error("$output: $!\n");
-
- # Title
- printf DOT ("digraph \"%s; %s %s\" {\n",
- $prog,
- Unparse($overall_total),
- Units());
- if ($main::opt_pdf) {
- # The output is more printable if we set the page size for dot.
- printf DOT ("size=\"8,11\"\n");
- }
- printf DOT ("node [width=0.375,height=0.25];\n");
-
- # Print legend
- printf DOT ("Legend [shape=box,fontsize=24,shape=plaintext," .
- "label=\"%s\\l%s\\l%s\\l%s\\l%s\\l\"];\n",
- $prog,
- sprintf("Total %s: %s", Units(), Unparse($overall_total)),
- sprintf("Focusing on: %s", Unparse($local_total)),
- sprintf("Dropped nodes with <= %s abs(%s)",
- Unparse($nodelimit), Units()),
- sprintf("Dropped edges with <= %s %s",
- Unparse($edgelimit), Units())
- );
-
- # Print nodes
- my %node = ();
- my $nextnode = 1;
- foreach my $a (@list[0..$last]) {
- # Pick font size
- my $f = GetEntry($flat, $a);
- my $c = GetEntry($cumulative, $a);
-
- my $fs = 8;
- if ($local_total > 0) {
- $fs = 8 + (50.0 * sqrt(abs($f * 1.0 / $local_total)));
- }
-
- $node{$a} = $nextnode++;
- my $sym = $a;
- $sym =~ s/\s+/\\n/g;
- $sym =~ s/::/\\n/g;
-
- # Extra cumulative info to print for non-leaves
- my $extra = "";
- if ($f != $c) {
- $extra = sprintf("\\rof %s (%s)",
- Unparse($c),
- Percent($c, $local_total));
- }
- my $style = "";
- if ($main::opt_heapcheck) {
- if ($f > 0) {
- # make leak-causing nodes more visible (add a background)
- $style = ",style=filled,fillcolor=gray"
- } elsif ($f < 0) {
- # make anti-leak-causing nodes (which almost never occur)
- # stand out as well (triple border)
- $style = ",peripheries=3"
- }
- }
-
- printf DOT ("N%d [label=\"%s\\n%s (%s)%s\\r" .
- "\",shape=box,fontsize=%.1f%s];\n",
- $node{$a},
- $sym,
- Unparse($f),
- Percent($f, $local_total),
- $extra,
- $fs,
- $style,
- );
- }
-
- # Get edges and counts per edge
- my %edge = ();
- my $n;
- my $fullname_to_shortname_map = {};
- FillFullnameToShortnameMap($symbols, $fullname_to_shortname_map);
- foreach my $k (keys(%{$raw})) {
- # TODO: omit low %age edges
- $n = $raw->{$k};
- my @translated = TranslateStack($symbols, $fullname_to_shortname_map, $k);
- for (my $i = 1; $i <= $#translated; $i++) {
- my $src = $translated[$i];
- my $dst = $translated[$i-1];
- #next if ($src eq $dst); # Avoid self-edges?
- if (exists($node{$src}) && exists($node{$dst})) {
- my $edge_label = "$src\001$dst";
- if (!exists($edge{$edge_label})) {
- $edge{$edge_label} = 0;
- }
- $edge{$edge_label} += $n;
- }
- }
- }
-
- # Print edges (process in order of decreasing counts)
- my %indegree = (); # Number of incoming edges added per node so far
- my %outdegree = (); # Number of outgoing edges added per node so far
- foreach my $e (sort { $edge{$b} <=> $edge{$a} } keys(%edge)) {
- my @x = split(/\001/, $e);
- $n = $edge{$e};
-
- # Initialize degree of kept incoming and outgoing edges if necessary
- my $src = $x[0];
- my $dst = $x[1];
- if (!exists($outdegree{$src})) { $outdegree{$src} = 0; }
- if (!exists($indegree{$dst})) { $indegree{$dst} = 0; }
-
- my $keep;
- if ($indegree{$dst} == 0) {
- # Keep edge if needed for reachability
- $keep = 1;
- } elsif (abs($n) <= $edgelimit) {
- # Drop if we are below --edgefraction
- $keep = 0;
- } elsif ($outdegree{$src} >= $main::opt_maxdegree ||
- $indegree{$dst} >= $main::opt_maxdegree) {
- # Keep limited number of in/out edges per node
- $keep = 0;
- } else {
- $keep = 1;
- }
-
- if ($keep) {
- $outdegree{$src}++;
- $indegree{$dst}++;
-
- # Compute line width based on edge count
- my $fraction = abs($local_total ? (3 * ($n / $local_total)) : 0);
- if ($fraction > 1) { $fraction = 1; }
- my $w = $fraction * 2;
- if ($w < 1 && ($main::opt_web || $main::opt_svg)) {
- # SVG output treats line widths < 1 poorly.
- $w = 1;
- }
-
- # Dot sometimes segfaults if given edge weights that are too large, so
- # we cap the weights at a large value
- my $edgeweight = abs($n) ** 0.7;
- if ($edgeweight > 100000) { $edgeweight = 100000; }
- $edgeweight = int($edgeweight);
-
- my $style = sprintf("setlinewidth(%f)", $w);
- if ($x[1] =~ m/\(inline\)/) {
- $style .= ",dashed";
- }
-
- # Use a slightly squashed function of the edge count as the weight
- printf DOT ("N%s -> N%s [label=%s, weight=%d, style=\"%s\"];\n",
- $node{$x[0]},
- $node{$x[1]},
- Unparse($n),
- $edgeweight,
- $style);
- }
- }
-
- print DOT ("}\n");
- close(DOT);
-
- if ($main::opt_web || $main::opt_svg) {
- # Rewrite SVG to be more usable inside web browser.
- RewriteSvg(TempName($main::next_tmpfile, "svg"));
- }
-
- return 1;
-}
-
-sub RewriteSvg {
- my $svgfile = shift;
-
- open(SVG, $svgfile) || die "open temp svg: $!";
- my @svg = <SVG>;
- close(SVG);
- unlink $svgfile;
- my $svg = join('', @svg);
-
- # Dot's SVG output is
- #
- # <svg width="___" height="___"
- # viewBox="___" xmlns=...>
- # <g id="graph0" transform="...">
- # ...
- # </g>
- # </svg>
- #
- # Change it to
- #
- # <svg width="100%" height="100%"
- # xmlns=...>
- # $svg_javascript
- # <g id="viewport" transform="translate(0,0)">
- # <g id="graph0" transform="...">
- # ...
- # </g>
- # </g>
- # </svg>
-
- # Fix width, height; drop viewBox.
- $svg =~ s/(?s)<svg width="[^"]+" height="[^"]+"(.*?)viewBox="[^"]+"/<svg width="100%" height="100%"$1/;
-
- # Insert script, viewport <g> above first <g>
- my $svg_javascript = SvgJavascript();
- my $viewport = "<g id=\"viewport\" transform=\"translate(0,0)\">\n";
- $svg =~ s/<g id="graph\d"/$svg_javascript$viewport$&/;
-
- # Insert final </g> above </svg>.
- $svg =~ s/(.*)(<\/svg>)/$1<\/g>$2/;
- $svg =~ s/<g id="graph\d"(.*?)/<g id="viewport"$1/;
-
- if ($main::opt_svg) {
- # --svg: write to standard output.
- print $svg;
- } else {
- # Write back to temporary file.
- open(SVG, ">$svgfile") || die "open $svgfile: $!";
- print SVG $svg;
- close(SVG);
- }
-}
-
-sub SvgJavascript {
- return <<'EOF';
-<script type="text/ecmascript"><![CDATA[
-// SVGPan
-// http://www.cyberz.org/blog/2009/12/08/svgpan-a-javascript-svg-panzoomdrag-library/
-// Local modification: if(true || ...) below to force panning, never moving.
-
-/**
- * SVGPan library 1.2
- * ====================
- *
- * Given an unique existing element with id "viewport", including the
- * the library into any SVG adds the following capabilities:
- *
- * - Mouse panning
- * - Mouse zooming (using the wheel)
- * - Object dargging
- *
- * Known issues:
- *
- * - Zooming (while panning) on Safari has still some issues
- *
- * Releases:
- *
- * 1.2, Sat Mar 20 08:42:50 GMT 2010, Zeng Xiaohui
- * Fixed a bug with browser mouse handler interaction
- *
- * 1.1, Wed Feb 3 17:39:33 GMT 2010, Zeng Xiaohui
- * Updated the zoom code to support the mouse wheel on Safari/Chrome
- *
- * 1.0, Andrea Leofreddi
- * First release
- *
- * This code is licensed under the following BSD license:
- *
- * Copyright 2009-2010 Andrea Leofreddi <a.leofreddi@itcharm.com>. 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 Andrea Leofreddi ``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 Andrea Leofreddi 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.
- *
- * The views and conclusions contained in the software and documentation are those of the
- * authors and should not be interpreted as representing official policies, either expressed
- * or implied, of Andrea Leofreddi.
- */
-
-var root = document.documentElement;
-
-var state = 'none', stateTarget, stateOrigin, stateTf;
-
-setupHandlers(root);
-
-/**
- * Register handlers
- */
-function setupHandlers(root){
- setAttributes(root, {
- "onmouseup" : "add(evt)",
- "onmousedown" : "handleMouseDown(evt)",
- "onmousemove" : "handleMouseMove(evt)",
- "onmouseup" : "handleMouseUp(evt)",
- //"onmouseout" : "handleMouseUp(evt)", // Decomment this to stop the pan functionality when dragging out of the SVG element
- });
-
- if(navigator.userAgent.toLowerCase().indexOf('webkit') >= 0)
- window.addEventListener('mousewheel', handleMouseWheel, false); // Chrome/Safari
- else
- window.addEventListener('DOMMouseScroll', handleMouseWheel, false); // Others
-
- var g = svgDoc.getElementById("svg");
- g.width = "100%";
- g.height = "100%";
-}
-
-/**
- * Instance an SVGPoint object with given event coordinates.
- */
-function getEventPoint(evt) {
- var p = root.createSVGPoint();
-
- p.x = evt.clientX;
- p.y = evt.clientY;
-
- return p;
-}
-
-/**
- * Sets the current transform matrix of an element.
- */
-function setCTM(element, matrix) {
- var s = "matrix(" + matrix.a + "," + matrix.b + "," + matrix.c + "," + matrix.d + "," + matrix.e + "," + matrix.f + ")";
-
- element.setAttribute("transform", s);
-}
-
-/**
- * Dumps a matrix to a string (useful for debug).
- */
-function dumpMatrix(matrix) {
- var s = "[ " + matrix.a + ", " + matrix.c + ", " + matrix.e + "\n " + matrix.b + ", " + matrix.d + ", " + matrix.f + "\n 0, 0, 1 ]";
-
- return s;
-}
-
-/**
- * Sets attributes of an element.
- */
-function setAttributes(element, attributes){
- for (i in attributes)
- element.setAttributeNS(null, i, attributes[i]);
-}
-
-/**
- * Handle mouse move event.
- */
-function handleMouseWheel(evt) {
- if(evt.preventDefault)
- evt.preventDefault();
-
- evt.returnValue = false;
-
- var svgDoc = evt.target.ownerDocument;
-
- var delta;
-
- if(evt.wheelDelta)
- delta = evt.wheelDelta / 3600; // Chrome/Safari
- else
- delta = evt.detail / -90; // Mozilla
-
- var z = 1 + delta; // Zoom factor: 0.9/1.1
-
- var g = svgDoc.getElementById("viewport");
-
- var p = getEventPoint(evt);
-
- p = p.matrixTransform(g.getCTM().inverse());
-
- // Compute new scale matrix in current mouse position
- var k = root.createSVGMatrix().translate(p.x, p.y).scale(z).translate(-p.x, -p.y);
-
- setCTM(g, g.getCTM().multiply(k));
-
- stateTf = stateTf.multiply(k.inverse());
-}
-
-/**
- * Handle mouse move event.
- */
-function handleMouseMove(evt) {
- if(evt.preventDefault)
- evt.preventDefault();
-
- evt.returnValue = false;
-
- var svgDoc = evt.target.ownerDocument;
-
- var g = svgDoc.getElementById("viewport");
-
- if(state == 'pan') {
- // Pan mode
- var p = getEventPoint(evt).matrixTransform(stateTf);
-
- setCTM(g, stateTf.inverse().translate(p.x - stateOrigin.x, p.y - stateOrigin.y));
- } else if(state == 'move') {
- // Move mode
- var p = getEventPoint(evt).matrixTransform(g.getCTM().inverse());
-
- setCTM(stateTarget, root.createSVGMatrix().translate(p.x - stateOrigin.x, p.y - stateOrigin.y).multiply(g.getCTM().inverse()).multiply(stateTarget.getCTM()));
-
- stateOrigin = p;
- }
-}
-
-/**
- * Handle click event.
- */
-function handleMouseDown(evt) {
- if(evt.preventDefault)
- evt.preventDefault();
-
- evt.returnValue = false;
-
- var svgDoc = evt.target.ownerDocument;
-
- var g = svgDoc.getElementById("viewport");
-
- if(true || evt.target.tagName == "svg") {
- // Pan mode
- state = 'pan';
-
- stateTf = g.getCTM().inverse();
-
- stateOrigin = getEventPoint(evt).matrixTransform(stateTf);
- } else {
- // Move mode
- state = 'move';
-
- stateTarget = evt.target;
-
- stateTf = g.getCTM().inverse();
-
- stateOrigin = getEventPoint(evt).matrixTransform(stateTf);
- }
-}
-
-/**
- * Handle mouse button release event.
- */
-function handleMouseUp(evt) {
- if(evt.preventDefault)
- evt.preventDefault();
-
- evt.returnValue = false;
-
- var svgDoc = evt.target.ownerDocument;
-
- if(state == 'pan' || state == 'move') {
- // Quit pan mode
- state = '';
- }
-}
-
-]]></script>
-EOF
-}
-
-# Provides a map from fullname to shortname for cases where the
-# shortname is ambiguous. The symlist has both the fullname and
-# shortname for all symbols, which is usually fine, but sometimes --
-# such as overloaded functions -- two different fullnames can map to
-# the same shortname. In that case, we use the address of the
-# function to disambiguate the two. This function fills in a map that
-# maps fullnames to modified shortnames in such cases. If a fullname
-# is not present in the map, the 'normal' shortname provided by the
-# symlist is the appropriate one to use.
-sub FillFullnameToShortnameMap {
- my $symbols = shift;
- my $fullname_to_shortname_map = shift;
- my $shortnames_seen_once = {};
- my $shortnames_seen_more_than_once = {};
-
- foreach my $symlist (values(%{$symbols})) {
- # TODO(csilvers): deal with inlined symbols too.
- my $shortname = $symlist->[0];
- my $fullname = $symlist->[2];
- if ($fullname !~ /<[0-9a-fA-F]+>$/) { # fullname doesn't end in an address
- next; # the only collisions we care about are when addresses differ
- }
- if (defined($shortnames_seen_once->{$shortname}) &&
- $shortnames_seen_once->{$shortname} ne $fullname) {
- $shortnames_seen_more_than_once->{$shortname} = 1;
- } else {
- $shortnames_seen_once->{$shortname} = $fullname;
- }
- }
-
- foreach my $symlist (values(%{$symbols})) {
- my $shortname = $symlist->[0];
- my $fullname = $symlist->[2];
- # TODO(csilvers): take in a list of addresses we care about, and only
- # store in the map if $symlist->[1] is in that list. Saves space.
- next if defined($fullname_to_shortname_map->{$fullname});
- if (defined($shortnames_seen_more_than_once->{$shortname})) {
- if ($fullname =~ /<0*([^>]*)>$/) { # fullname has address at end of it
- $fullname_to_shortname_map->{$fullname} = "$shortname\@$1";
- }
- }
- }
-}
-
-# Return a small number that identifies the argument.
-# Multiple calls with the same argument will return the same number.
-# Calls with different arguments will return different numbers.
-sub ShortIdFor {
- my $key = shift;
- my $id = $main::uniqueid{$key};
- if (!defined($id)) {
- $id = keys(%main::uniqueid) + 1;
- $main::uniqueid{$key} = $id;
- }
- return $id;
-}
-
-# Translate a stack of addresses into a stack of symbols
-sub TranslateStack {
- my $symbols = shift;
- my $fullname_to_shortname_map = shift;
- my $k = shift;
-
- my @addrs = split(/\n/, $k);
- my @result = ();
- for (my $i = 0; $i <= $#addrs; $i++) {
- my $a = $addrs[$i];
-
- # Skip large addresses since they sometimes show up as fake entries on RH9
- if (length($a) > 8 && $a gt "7fffffffffffffff") {
- next;
- }
-
- if ($main::opt_disasm || $main::opt_list) {
- # We want just the address for the key
- push(@result, $a);
- next;
- }
-
- my $symlist = $symbols->{$a};
- if (!defined($symlist)) {
- $symlist = [$a, "", $a];
- }
-
- # We can have a sequence of symbols for a particular entry
- # (more than one symbol in the case of inlining). Callers
- # come before callees in symlist, so walk backwards since
- # the translated stack should contain callees before callers.
- for (my $j = $#{$symlist}; $j >= 2; $j -= 3) {
- my $func = $symlist->[$j-2];
- my $fileline = $symlist->[$j-1];
- my $fullfunc = $symlist->[$j];
- if (defined($fullname_to_shortname_map->{$fullfunc})) {
- $func = $fullname_to_shortname_map->{$fullfunc};
- }
- if ($j > 2) {
- $func = "$func (inline)";
- }
-
- # Do not merge nodes corresponding to Callback::Run since that
- # causes confusing cycles in dot display. Instead, we synthesize
- # a unique name for this frame per caller.
- if ($func =~ m/Callback.*::Run$/) {
- my $caller = ($i > 0) ? $addrs[$i-1] : 0;
- $func = "Run#" . ShortIdFor($caller);
- }
-
- if ($main::opt_addresses) {
- push(@result, "$a $func $fileline");
- } elsif ($main::opt_lines) {
- if ($func eq '??' && $fileline eq '??:0') {
- push(@result, "$a");
- } else {
- push(@result, "$func $fileline");
- }
- } elsif ($main::opt_functions) {
- if ($func eq '??') {
- push(@result, "$a");
- } else {
- push(@result, $func);
- }
- } elsif ($main::opt_files) {
- if ($fileline eq '??:0' || $fileline eq '') {
- push(@result, "$a");
- } else {
- my $f = $fileline;
- $f =~ s/:\d+$//;
- push(@result, $f);
- }
- } else {
- push(@result, $a);
- last; # Do not print inlined info
- }
- }
- }
-
- # print join(",", @addrs), " => ", join(",", @result), "\n";
- return @result;
-}
-
-# Generate percent string for a number and a total
-sub Percent {
- my $num = shift;
- my $tot = shift;
- if ($tot != 0) {
- return sprintf("%.1f%%", $num * 100.0 / $tot);
- } else {
- return ($num == 0) ? "nan" : (($num > 0) ? "+inf" : "-inf");
- }
-}
-
-# Generate pretty-printed form of number
-sub Unparse {
- my $num = shift;
- if ($main::profile_type eq 'heap' || $main::profile_type eq 'growth') {
- if ($main::opt_inuse_objects || $main::opt_alloc_objects) {
- return sprintf("%d", $num);
- } else {
- if ($main::opt_show_bytes) {
- return sprintf("%d", $num);
- } else {
- return sprintf("%.1f", $num / 1048576.0);
- }
- }
- } elsif ($main::profile_type eq 'contention' && !$main::opt_contentions) {
- return sprintf("%.3f", $num / 1e9); # Convert nanoseconds to seconds
- } else {
- return sprintf("%d", $num);
- }
-}
-
-# Alternate pretty-printed form: 0 maps to "."
-sub UnparseAlt {
- my $num = shift;
- if ($num == 0) {
- return ".";
- } else {
- return Unparse($num);
- }
-}
-
-# Alternate pretty-printed form: 0 maps to ""
-sub HtmlPrintNumber {
- my $num = shift;
- if ($num == 0) {
- return "";
- } else {
- return Unparse($num);
- }
-}
-
-# Return output units
-sub Units {
- if ($main::profile_type eq 'heap' || $main::profile_type eq 'growth') {
- if ($main::opt_inuse_objects || $main::opt_alloc_objects) {
- return "objects";
- } else {
- if ($main::opt_show_bytes) {
- return "B";
- } else {
- return "MB";
- }
- }
- } elsif ($main::profile_type eq 'contention' && !$main::opt_contentions) {
- return "seconds";
- } else {
- return "samples";
- }
-}
-
-##### Profile manipulation code #####
-
-# Generate flattened profile:
-# If count is charged to stack [a,b,c,d], in generated profile,
-# it will be charged to [a]
-sub FlatProfile {
- my $profile = shift;
- my $result = {};
- foreach my $k (keys(%{$profile})) {
- my $count = $profile->{$k};
- my @addrs = split(/\n/, $k);
- if ($#addrs >= 0) {
- AddEntry($result, $addrs[0], $count);
- }
- }
- return $result;
-}
-
-# Generate cumulative profile:
-# If count is charged to stack [a,b,c,d], in generated profile,
-# it will be charged to [a], [b], [c], [d]
-sub CumulativeProfile {
- my $profile = shift;
- my $result = {};
- foreach my $k (keys(%{$profile})) {
- my $count = $profile->{$k};
- my @addrs = split(/\n/, $k);
- foreach my $a (@addrs) {
- AddEntry($result, $a, $count);
- }
- }
- return $result;
-}
-
-# If the second-youngest PC on the stack is always the same, returns
-# that pc. Otherwise, returns undef.
-sub IsSecondPcAlwaysTheSame {
- my $profile = shift;
-
- my $second_pc = undef;
- foreach my $k (keys(%{$profile})) {
- my @addrs = split(/\n/, $k);
- if ($#addrs < 1) {
- return undef;
- }
- if (not defined $second_pc) {
- $second_pc = $addrs[1];
- } else {
- if ($second_pc ne $addrs[1]) {
- return undef;
- }
- }
- }
- return $second_pc;
-}
-
-sub ExtractSymbolLocation {
- my $symbols = shift;
- my $address = shift;
- # 'addr2line' outputs "??:0" for unknown locations; we do the
- # same to be consistent.
- my $location = "??:0:unknown";
- if (exists $symbols->{$address}) {
- my $file = $symbols->{$address}->[1];
- if ($file eq "?") {
- $file = "??:0"
- }
- $location = $file . ":" . $symbols->{$address}->[0];
- }
- return $location;
-}
-
-# Extracts a graph of calls.
-sub ExtractCalls {
- my $symbols = shift;
- my $profile = shift;
-
- my $calls = {};
- while( my ($stack_trace, $count) = each %$profile ) {
- my @address = split(/\n/, $stack_trace);
- my $destination = ExtractSymbolLocation($symbols, $address[0]);
- AddEntry($calls, $destination, $count);
- for (my $i = 1; $i <= $#address; $i++) {
- my $source = ExtractSymbolLocation($symbols, $address[$i]);
- my $call = "$source -> $destination";
- AddEntry($calls, $call, $count);
- $destination = $source;
- }
- }
-
- return $calls;
-}
-
-sub FilterFrames {
- my $symbols = shift;
- my $profile = shift;
-
- if ($main::opt_retain eq '' && $main::opt_exclude eq '') {
- return $profile;
- }
-
- my $result = {};
- foreach my $k (keys(%{$profile})) {
- my $count = $profile->{$k};
- my @addrs = split(/\n/, $k);
- my @path = ();
- foreach my $a (@addrs) {
- my $sym;
- if (exists($symbols->{$a})) {
- $sym = $symbols->{$a}->[0];
- } else {
- $sym = $a;
- }
- if ($main::opt_retain ne '' && $sym !~ m/$main::opt_retain/) {
- next;
- }
- if ($main::opt_exclude ne '' && $sym =~ m/$main::opt_exclude/) {
- next;
- }
- push(@path, $a);
- }
- if (scalar(@path) > 0) {
- my $reduced_path = join("\n", @path);
- AddEntry($result, $reduced_path, $count);
- }
- }
-
- return $result;
-}
-
-sub RemoveUninterestingFrames {
- my $symbols = shift;
- my $profile = shift;
-
- # List of function names to skip
- my %skip = ();
- my $skip_regexp = 'NOMATCH';
- if ($main::profile_type eq 'heap' || $main::profile_type eq 'growth') {
- foreach my $name ('@JEMALLOC_PREFIX@calloc',
- 'cfree',
- '@JEMALLOC_PREFIX@malloc',
- 'newImpl',
- 'void* newImpl',
- '@JEMALLOC_PREFIX@free',
- '@JEMALLOC_PREFIX@memalign',
- '@JEMALLOC_PREFIX@posix_memalign',
- '@JEMALLOC_PREFIX@aligned_alloc',
- 'pvalloc',
- '@JEMALLOC_PREFIX@valloc',
- '@JEMALLOC_PREFIX@realloc',
- '@JEMALLOC_PREFIX@mallocx',
- '@JEMALLOC_PREFIX@rallocx',
- '@JEMALLOC_PREFIX@xallocx',
- '@JEMALLOC_PREFIX@dallocx',
- '@JEMALLOC_PREFIX@sdallocx',
- '@JEMALLOC_PREFIX@sdallocx_noflags',
- 'tc_calloc',
- 'tc_cfree',
- 'tc_malloc',
- 'tc_free',
- 'tc_memalign',
- 'tc_posix_memalign',
- 'tc_pvalloc',
- 'tc_valloc',
- 'tc_realloc',
- 'tc_new',
- 'tc_delete',
- 'tc_newarray',
- 'tc_deletearray',
- 'tc_new_nothrow',
- 'tc_newarray_nothrow',
- 'do_malloc',
- '::do_malloc', # new name -- got moved to an unnamed ns
- '::do_malloc_or_cpp_alloc',
- 'DoSampledAllocation',
- 'simple_alloc::allocate',
- '__malloc_alloc_template::allocate',
- '__builtin_delete',
- '__builtin_new',
- '__builtin_vec_delete',
- '__builtin_vec_new',
- 'operator new',
- 'operator new[]',
- # The entry to our memory-allocation routines on OS X
- 'malloc_zone_malloc',
- 'malloc_zone_calloc',
- 'malloc_zone_valloc',
- 'malloc_zone_realloc',
- 'malloc_zone_memalign',
- 'malloc_zone_free',
- # These mark the beginning/end of our custom sections
- '__start_google_malloc',
- '__stop_google_malloc',
- '__start_malloc_hook',
- '__stop_malloc_hook') {
- $skip{$name} = 1;
- $skip{"_" . $name} = 1; # Mach (OS X) adds a _ prefix to everything
- }
- # TODO: Remove TCMalloc once everything has been
- # moved into the tcmalloc:: namespace and we have flushed
- # old code out of the system.
- $skip_regexp = "TCMalloc|^tcmalloc::";
- } elsif ($main::profile_type eq 'contention') {
- foreach my $vname ('base::RecordLockProfileData',
- 'base::SubmitMutexProfileData',
- 'base::SubmitSpinLockProfileData',
- 'Mutex::Unlock',
- 'Mutex::UnlockSlow',
- 'Mutex::ReaderUnlock',
- 'MutexLock::~MutexLock',
- 'SpinLock::Unlock',
- 'SpinLock::SlowUnlock',
- 'SpinLockHolder::~SpinLockHolder') {
- $skip{$vname} = 1;
- }
- } elsif ($main::profile_type eq 'cpu') {
- # Drop signal handlers used for CPU profile collection
- # TODO(dpeng): this should not be necessary; it's taken
- # care of by the general 2nd-pc mechanism below.
- foreach my $name ('ProfileData::Add', # historical
- 'ProfileData::prof_handler', # historical
- 'CpuProfiler::prof_handler',
- '__FRAME_END__',
- '__pthread_sighandler',
- '__restore') {
- $skip{$name} = 1;
- }
- } else {
- # Nothing skipped for unknown types
- }
-
- if ($main::profile_type eq 'cpu') {
- # If all the second-youngest program counters are the same,
- # this STRONGLY suggests that it is an artifact of measurement,
- # i.e., stack frames pushed by the CPU profiler signal handler.
- # Hence, we delete them.
- # (The topmost PC is read from the signal structure, not from
- # the stack, so it does not get involved.)
- while (my $second_pc = IsSecondPcAlwaysTheSame($profile)) {
- my $result = {};
- my $func = '';
- if (exists($symbols->{$second_pc})) {
- $second_pc = $symbols->{$second_pc}->[0];
- }
- print STDERR "Removing $second_pc from all stack traces.\n";
- foreach my $k (keys(%{$profile})) {
- my $count = $profile->{$k};
- my @addrs = split(/\n/, $k);
- splice @addrs, 1, 1;
- my $reduced_path = join("\n", @addrs);
- AddEntry($result, $reduced_path, $count);
- }
- $profile = $result;
- }
- }
-
- my $result = {};
- foreach my $k (keys(%{$profile})) {
- my $count = $profile->{$k};
- my @addrs = split(/\n/, $k);
- my @path = ();
- foreach my $a (@addrs) {
- if (exists($symbols->{$a})) {
- my $func = $symbols->{$a}->[0];
- if ($skip{$func} || ($func =~ m/$skip_regexp/)) {
- # Throw away the portion of the backtrace seen so far, under the
- # assumption that previous frames were for functions internal to the
- # allocator.
- @path = ();
- next;
- }
- }
- push(@path, $a);
- }
- my $reduced_path = join("\n", @path);
- AddEntry($result, $reduced_path, $count);
- }
-
- $result = FilterFrames($symbols, $result);
-
- return $result;
-}
-
-# Reduce profile to granularity given by user
-sub ReduceProfile {
- my $symbols = shift;
- my $profile = shift;
- my $result = {};
- my $fullname_to_shortname_map = {};
- FillFullnameToShortnameMap($symbols, $fullname_to_shortname_map);
- foreach my $k (keys(%{$profile})) {
- my $count = $profile->{$k};
- my @translated = TranslateStack($symbols, $fullname_to_shortname_map, $k);
- my @path = ();
- my %seen = ();
- $seen{''} = 1; # So that empty keys are skipped
- foreach my $e (@translated) {
- # To avoid double-counting due to recursion, skip a stack-trace
- # entry if it has already been seen
- if (!$seen{$e}) {
- $seen{$e} = 1;
- push(@path, $e);
- }
- }
- my $reduced_path = join("\n", @path);
- AddEntry($result, $reduced_path, $count);
- }
- return $result;
-}
-
-# Does the specified symbol array match the regexp?
-sub SymbolMatches {
- my $sym = shift;
- my $re = shift;
- if (defined($sym)) {
- for (my $i = 0; $i < $#{$sym}; $i += 3) {
- if ($sym->[$i] =~ m/$re/ || $sym->[$i+1] =~ m/$re/) {
- return 1;
- }
- }
- }
- return 0;
-}
-
-# Focus only on paths involving specified regexps
-sub FocusProfile {
- my $symbols = shift;
- my $profile = shift;
- my $focus = shift;
- my $result = {};
- foreach my $k (keys(%{$profile})) {
- my $count = $profile->{$k};
- my @addrs = split(/\n/, $k);
- foreach my $a (@addrs) {
- # Reply if it matches either the address/shortname/fileline
- if (($a =~ m/$focus/) || SymbolMatches($symbols->{$a}, $focus)) {
- AddEntry($result, $k, $count);
- last;
- }
- }
- }
- return $result;
-}
-
-# Focus only on paths not involving specified regexps
-sub IgnoreProfile {
- my $symbols = shift;
- my $profile = shift;
- my $ignore = shift;
- my $result = {};
- foreach my $k (keys(%{$profile})) {
- my $count = $profile->{$k};
- my @addrs = split(/\n/, $k);
- my $matched = 0;
- foreach my $a (@addrs) {
- # Reply if it matches either the address/shortname/fileline
- if (($a =~ m/$ignore/) || SymbolMatches($symbols->{$a}, $ignore)) {
- $matched = 1;
- last;
- }
- }
- if (!$matched) {
- AddEntry($result, $k, $count);
- }
- }
- return $result;
-}
-
-# Get total count in profile
-sub TotalProfile {
- my $profile = shift;
- my $result = 0;
- foreach my $k (keys(%{$profile})) {
- $result += $profile->{$k};
- }
- return $result;
-}
-
-# Add A to B
-sub AddProfile {
- my $A = shift;
- my $B = shift;
-
- my $R = {};
- # add all keys in A
- foreach my $k (keys(%{$A})) {
- my $v = $A->{$k};
- AddEntry($R, $k, $v);
- }
- # add all keys in B
- foreach my $k (keys(%{$B})) {
- my $v = $B->{$k};
- AddEntry($R, $k, $v);
- }
- return $R;
-}
-
-# Merges symbol maps
-sub MergeSymbols {
- my $A = shift;
- my $B = shift;
-
- my $R = {};
- foreach my $k (keys(%{$A})) {
- $R->{$k} = $A->{$k};
- }
- if (defined($B)) {
- foreach my $k (keys(%{$B})) {
- $R->{$k} = $B->{$k};
- }
- }
- return $R;
-}
-
-
-# Add A to B
-sub AddPcs {
- my $A = shift;
- my $B = shift;
-
- my $R = {};
- # add all keys in A
- foreach my $k (keys(%{$A})) {
- $R->{$k} = 1
- }
- # add all keys in B
- foreach my $k (keys(%{$B})) {
- $R->{$k} = 1
- }
- return $R;
-}
-
-# Subtract B from A
-sub SubtractProfile {
- my $A = shift;
- my $B = shift;
-
- my $R = {};
- foreach my $k (keys(%{$A})) {
- my $v = $A->{$k} - GetEntry($B, $k);
- if ($v < 0 && $main::opt_drop_negative) {
- $v = 0;
- }
- AddEntry($R, $k, $v);
- }
- if (!$main::opt_drop_negative) {
- # Take care of when subtracted profile has more entries
- foreach my $k (keys(%{$B})) {
- if (!exists($A->{$k})) {
- AddEntry($R, $k, 0 - $B->{$k});
- }
- }
- }
- return $R;
-}
-
-# Get entry from profile; zero if not present
-sub GetEntry {
- my $profile = shift;
- my $k = shift;
- if (exists($profile->{$k})) {
- return $profile->{$k};
- } else {
- return 0;
- }
-}
-
-# Add entry to specified profile
-sub AddEntry {
- my $profile = shift;
- my $k = shift;
- my $n = shift;
- if (!exists($profile->{$k})) {
- $profile->{$k} = 0;
- }
- $profile->{$k} += $n;
-}
-
-# Add a stack of entries to specified profile, and add them to the $pcs
-# list.
-sub AddEntries {
- my $profile = shift;
- my $pcs = shift;
- my $stack = shift;
- my $count = shift;
- my @k = ();
-
- foreach my $e (split(/\s+/, $stack)) {
- my $pc = HexExtend($e);
- $pcs->{$pc} = 1;
- push @k, $pc;
- }
- AddEntry($profile, (join "\n", @k), $count);
-}
-
-##### Code to profile a server dynamically #####
-
-sub CheckSymbolPage {
- my $url = SymbolPageURL();
- my $command = ShellEscape(@URL_FETCHER, $url);
- open(SYMBOL, "$command |") or error($command);
- my $line = <SYMBOL>;
- $line =~ s/\r//g; # turn windows-looking lines into unix-looking lines
- close(SYMBOL);
- unless (defined($line)) {
- error("$url doesn't exist\n");
- }
-
- if ($line =~ /^num_symbols:\s+(\d+)$/) {
- if ($1 == 0) {
- error("Stripped binary. No symbols available.\n");
- }
- } else {
- error("Failed to get the number of symbols from $url\n");
- }
-}
-
-sub IsProfileURL {
- my $profile_name = shift;
- if (-f $profile_name) {
- printf STDERR "Using local file $profile_name.\n";
- return 0;
- }
- return 1;
-}
-
-sub ParseProfileURL {
- my $profile_name = shift;
-
- if (!defined($profile_name) || $profile_name eq "") {
- return ();
- }
-
- # Split profile URL - matches all non-empty strings, so no test.
- $profile_name =~ m,^(https?://)?([^/]+)(.*?)(/|$PROFILES)?$,;
-
- my $proto = $1 || "http://";
- my $hostport = $2;
- my $prefix = $3;
- my $profile = $4 || "/";
-
- my $host = $hostport;
- $host =~ s/:.*//;
-
- my $baseurl = "$proto$hostport$prefix";
- return ($host, $baseurl, $profile);
-}
-
-# We fetch symbols from the first profile argument.
-sub SymbolPageURL {
- my ($host, $baseURL, $path) = ParseProfileURL($main::pfile_args[0]);
- return "$baseURL$SYMBOL_PAGE";
-}
-
-sub FetchProgramName() {
- my ($host, $baseURL, $path) = ParseProfileURL($main::pfile_args[0]);
- my $url = "$baseURL$PROGRAM_NAME_PAGE";
- my $command_line = ShellEscape(@URL_FETCHER, $url);
- open(CMDLINE, "$command_line |") or error($command_line);
- my $cmdline = <CMDLINE>;
- $cmdline =~ s/\r//g; # turn windows-looking lines into unix-looking lines
- close(CMDLINE);
- error("Failed to get program name from $url\n") unless defined($cmdline);
- $cmdline =~ s/\x00.+//; # Remove argv[1] and latters.
- $cmdline =~ s!\n!!g; # Remove LFs.
- return $cmdline;
-}
-
-# Gee, curl's -L (--location) option isn't reliable at least
-# with its 7.12.3 version. Curl will forget to post data if
-# there is a redirection. This function is a workaround for
-# curl. Redirection happens on borg hosts.
-sub ResolveRedirectionForCurl {
- my $url = shift;
- my $command_line = ShellEscape(@URL_FETCHER, "--head", $url);
- open(CMDLINE, "$command_line |") or error($command_line);
- while (<CMDLINE>) {
- s/\r//g; # turn windows-looking lines into unix-looking lines
- if (/^Location: (.*)/) {
- $url = $1;
- }
- }
- close(CMDLINE);
- return $url;
-}
-
-# Add a timeout flat to URL_FETCHER. Returns a new list.
-sub AddFetchTimeout {
- my $timeout = shift;
- my @fetcher = @_;
- if (defined($timeout)) {
- if (join(" ", @fetcher) =~ m/\bcurl -s/) {
- push(@fetcher, "--max-time", sprintf("%d", $timeout));
- } elsif (join(" ", @fetcher) =~ m/\brpcget\b/) {
- push(@fetcher, sprintf("--deadline=%d", $timeout));
- }
- }
- return @fetcher;
-}
-
-# Reads a symbol map from the file handle name given as $1, returning
-# the resulting symbol map. Also processes variables relating to symbols.
-# Currently, the only variable processed is 'binary=<value>' which updates
-# $main::prog to have the correct program name.
-sub ReadSymbols {
- my $in = shift;
- my $map = {};
- while (<$in>) {
- s/\r//g; # turn windows-looking lines into unix-looking lines
- # Removes all the leading zeroes from the symbols, see comment below.
- if (m/^0x0*([0-9a-f]+)\s+(.+)/) {
- $map->{$1} = $2;
- } elsif (m/^---/) {
- last;
- } elsif (m/^([a-z][^=]*)=(.*)$/ ) {
- my ($variable, $value) = ($1, $2);
- for ($variable, $value) {
- s/^\s+//;
- s/\s+$//;
- }
- if ($variable eq "binary") {
- if ($main::prog ne $UNKNOWN_BINARY && $main::prog ne $value) {
- printf STDERR ("Warning: Mismatched binary name '%s', using '%s'.\n",
- $main::prog, $value);
- }
- $main::prog = $value;
- } else {
- printf STDERR ("Ignoring unknown variable in symbols list: " .
- "'%s' = '%s'\n", $variable, $value);
- }
- }
- }
- return $map;
-}
-
-sub URLEncode {
- my $str = shift;
- $str =~ s/([^A-Za-z0-9\-_.!~*'()])/ sprintf "%%%02x", ord $1 /eg;
- return $str;
-}
-
-sub AppendSymbolFilterParams {
- my $url = shift;
- my @params = ();
- if ($main::opt_retain ne '') {
- push(@params, sprintf("retain=%s", URLEncode($main::opt_retain)));
- }
- if ($main::opt_exclude ne '') {
- push(@params, sprintf("exclude=%s", URLEncode($main::opt_exclude)));
- }
- if (scalar @params > 0) {
- $url = sprintf("%s?%s", $url, join("&", @params));
- }
- return $url;
-}
-
-# Fetches and processes symbols to prepare them for use in the profile output
-# code. If the optional 'symbol_map' arg is not given, fetches symbols from
-# $SYMBOL_PAGE for all PC values found in profile. Otherwise, the raw symbols
-# are assumed to have already been fetched into 'symbol_map' and are simply
-# extracted and processed.
-sub FetchSymbols {
- my $pcset = shift;
- my $symbol_map = shift;
-
- my %seen = ();
- my @pcs = grep { !$seen{$_}++ } keys(%$pcset); # uniq
-
- if (!defined($symbol_map)) {
- my $post_data = join("+", sort((map {"0x" . "$_"} @pcs)));
-
- open(POSTFILE, ">$main::tmpfile_sym");
- print POSTFILE $post_data;
- close(POSTFILE);
-
- my $url = SymbolPageURL();
-
- my $command_line;
- if (join(" ", @URL_FETCHER) =~ m/\bcurl -s/) {
- $url = ResolveRedirectionForCurl($url);
- $url = AppendSymbolFilterParams($url);
- $command_line = ShellEscape(@URL_FETCHER, "-d", "\@$main::tmpfile_sym",
- $url);
- } else {
- $url = AppendSymbolFilterParams($url);
- $command_line = (ShellEscape(@URL_FETCHER, "--post", $url)
- . " < " . ShellEscape($main::tmpfile_sym));
- }
- # We use c++filt in case $SYMBOL_PAGE gives us mangled symbols.
- my $escaped_cppfilt = ShellEscape($obj_tool_map{"c++filt"});
- open(SYMBOL, "$command_line | $escaped_cppfilt |") or error($command_line);
- $symbol_map = ReadSymbols(*SYMBOL{IO});
- close(SYMBOL);
- }
-
- my $symbols = {};
- foreach my $pc (@pcs) {
- my $fullname;
- # For 64 bits binaries, symbols are extracted with 8 leading zeroes.
- # Then /symbol reads the long symbols in as uint64, and outputs
- # the result with a "0x%08llx" format which get rid of the zeroes.
- # By removing all the leading zeroes in both $pc and the symbols from
- # /symbol, the symbols match and are retrievable from the map.
- my $shortpc = $pc;
- $shortpc =~ s/^0*//;
- # Each line may have a list of names, which includes the function
- # and also other functions it has inlined. They are separated (in
- # PrintSymbolizedProfile), by --, which is illegal in function names.
- my $fullnames;
- if (defined($symbol_map->{$shortpc})) {
- $fullnames = $symbol_map->{$shortpc};
- } else {
- $fullnames = "0x" . $pc; # Just use addresses
- }
- my $sym = [];
- $symbols->{$pc} = $sym;
- foreach my $fullname (split("--", $fullnames)) {
- my $name = ShortFunctionName($fullname);
- push(@{$sym}, $name, "?", $fullname);
- }
- }
- return $symbols;
-}
-
-sub BaseName {
- my $file_name = shift;
- $file_name =~ s!^.*/!!; # Remove directory name
- return $file_name;
-}
-
-sub MakeProfileBaseName {
- my ($binary_name, $profile_name) = @_;
- my ($host, $baseURL, $path) = ParseProfileURL($profile_name);
- my $binary_shortname = BaseName($binary_name);
- return sprintf("%s.%s.%s",
- $binary_shortname, $main::op_time, $host);
-}
-
-sub FetchDynamicProfile {
- my $binary_name = shift;
- my $profile_name = shift;
- my $fetch_name_only = shift;
- my $encourage_patience = shift;
-
- if (!IsProfileURL($profile_name)) {
- return $profile_name;
- } else {
- my ($host, $baseURL, $path) = ParseProfileURL($profile_name);
- if ($path eq "" || $path eq "/") {
- # Missing type specifier defaults to cpu-profile
- $path = $PROFILE_PAGE;
- }
-
- my $profile_file = MakeProfileBaseName($binary_name, $profile_name);
-
- my $url = "$baseURL$path";
- my $fetch_timeout = undef;
- if ($path =~ m/$PROFILE_PAGE|$PMUPROFILE_PAGE/) {
- if ($path =~ m/[?]/) {
- $url .= "&";
- } else {
- $url .= "?";
- }
- $url .= sprintf("seconds=%d", $main::opt_seconds);
- $fetch_timeout = $main::opt_seconds * 1.01 + 60;
- # Set $profile_type for consumption by PrintSymbolizedProfile.
- $main::profile_type = 'cpu';
- } else {
- # For non-CPU profiles, we add a type-extension to
- # the target profile file name.
- my $suffix = $path;
- $suffix =~ s,/,.,g;
- $profile_file .= $suffix;
- # Set $profile_type for consumption by PrintSymbolizedProfile.
- if ($path =~ m/$HEAP_PAGE/) {
- $main::profile_type = 'heap';
- } elsif ($path =~ m/$GROWTH_PAGE/) {
- $main::profile_type = 'growth';
- } elsif ($path =~ m/$CONTENTION_PAGE/) {
- $main::profile_type = 'contention';
- }
- }
-
- my $profile_dir = $ENV{"JEPROF_TMPDIR"} || ($ENV{HOME} . "/jeprof");
- if (! -d $profile_dir) {
- mkdir($profile_dir)
- || die("Unable to create profile directory $profile_dir: $!\n");
- }
- my $tmp_profile = "$profile_dir/.tmp.$profile_file";
- my $real_profile = "$profile_dir/$profile_file";
-
- if ($fetch_name_only > 0) {
- return $real_profile;
- }
-
- my @fetcher = AddFetchTimeout($fetch_timeout, @URL_FETCHER);
- my $cmd = ShellEscape(@fetcher, $url) . " > " . ShellEscape($tmp_profile);
- if ($path =~ m/$PROFILE_PAGE|$PMUPROFILE_PAGE|$CENSUSPROFILE_PAGE/){
- print STDERR "Gathering CPU profile from $url for $main::opt_seconds seconds to\n ${real_profile}\n";
- if ($encourage_patience) {
- print STDERR "Be patient...\n";
- }
- } else {
- print STDERR "Fetching $path profile from $url to\n ${real_profile}\n";
- }
-
- (system($cmd) == 0) || error("Failed to get profile: $cmd: $!\n");
- (system("mv", $tmp_profile, $real_profile) == 0) || error("Unable to rename profile\n");
- print STDERR "Wrote profile to $real_profile\n";
- $main::collected_profile = $real_profile;
- return $main::collected_profile;
- }
-}
-
-# Collect profiles in parallel
-sub FetchDynamicProfiles {
- my $items = scalar(@main::pfile_args);
- my $levels = log($items) / log(2);
-
- if ($items == 1) {
- $main::profile_files[0] = FetchDynamicProfile($main::prog, $main::pfile_args[0], 0, 1);
- } else {
- # math rounding issues
- if ((2 ** $levels) < $items) {
- $levels++;
- }
- my $count = scalar(@main::pfile_args);
- for (my $i = 0; $i < $count; $i++) {
- $main::profile_files[$i] = FetchDynamicProfile($main::prog, $main::pfile_args[$i], 1, 0);
- }
- print STDERR "Fetching $count profiles, Be patient...\n";
- FetchDynamicProfilesRecurse($levels, 0, 0);
- $main::collected_profile = join(" \\\n ", @main::profile_files);
- }
-}
-
-# Recursively fork a process to get enough processes
-# collecting profiles
-sub FetchDynamicProfilesRecurse {
- my $maxlevel = shift;
- my $level = shift;
- my $position = shift;
-
- if (my $pid = fork()) {
- $position = 0 | ($position << 1);
- TryCollectProfile($maxlevel, $level, $position);
- wait;
- } else {
- $position = 1 | ($position << 1);
- TryCollectProfile($maxlevel, $level, $position);
- cleanup();
- exit(0);
- }
-}
-
-# Collect a single profile
-sub TryCollectProfile {
- my $maxlevel = shift;
- my $level = shift;
- my $position = shift;
-
- if ($level >= ($maxlevel - 1)) {
- if ($position < scalar(@main::pfile_args)) {
- FetchDynamicProfile($main::prog, $main::pfile_args[$position], 0, 0);
- }
- } else {
- FetchDynamicProfilesRecurse($maxlevel, $level+1, $position);
- }
-}
-
-##### Parsing code #####
-
-# Provide a small streaming-read module to handle very large
-# cpu-profile files. Stream in chunks along a sliding window.
-# Provides an interface to get one 'slot', correctly handling
-# endian-ness differences. A slot is one 32-bit or 64-bit word
-# (depending on the input profile). We tell endianness and bit-size
-# for the profile by looking at the first 8 bytes: in cpu profiles,
-# the second slot is always 3 (we'll accept anything that's not 0).
-BEGIN {
- package CpuProfileStream;
-
- sub new {
- my ($class, $file, $fname) = @_;
- my $self = { file => $file,
- base => 0,
- stride => 512 * 1024, # must be a multiple of bitsize/8
- slots => [],
- unpack_code => "", # N for big-endian, V for little
- perl_is_64bit => 1, # matters if profile is 64-bit
- };
- bless $self, $class;
- # Let unittests adjust the stride
- if ($main::opt_test_stride > 0) {
- $self->{stride} = $main::opt_test_stride;
- }
- # Read the first two slots to figure out bitsize and endianness.
- my $slots = $self->{slots};
- my $str;
- read($self->{file}, $str, 8);
- # Set the global $address_length based on what we see here.
- # 8 is 32-bit (8 hexadecimal chars); 16 is 64-bit (16 hexadecimal chars).
- $address_length = ($str eq (chr(0)x8)) ? 16 : 8;
- if ($address_length == 8) {
- if (substr($str, 6, 2) eq chr(0)x2) {
- $self->{unpack_code} = 'V'; # Little-endian.
- } elsif (substr($str, 4, 2) eq chr(0)x2) {
- $self->{unpack_code} = 'N'; # Big-endian
- } else {
- ::error("$fname: header size >= 2**16\n");
- }
- @$slots = unpack($self->{unpack_code} . "*", $str);
- } else {
- # If we're a 64-bit profile, check if we're a 64-bit-capable
- # perl. Otherwise, each slot will be represented as a float
- # instead of an int64, losing precision and making all the
- # 64-bit addresses wrong. We won't complain yet, but will
- # later if we ever see a value that doesn't fit in 32 bits.
- my $has_q = 0;
- eval { $has_q = pack("Q", "1") ? 1 : 1; };
- if (!$has_q) {
- $self->{perl_is_64bit} = 0;
- }
- read($self->{file}, $str, 8);
- if (substr($str, 4, 4) eq chr(0)x4) {
- # We'd love to use 'Q', but it's a) not universal, b) not endian-proof.
- $self->{unpack_code} = 'V'; # Little-endian.
- } elsif (substr($str, 0, 4) eq chr(0)x4) {
- $self->{unpack_code} = 'N'; # Big-endian
- } else {
- ::error("$fname: header size >= 2**32\n");
- }
- my @pair = unpack($self->{unpack_code} . "*", $str);
- # Since we know one of the pair is 0, it's fine to just add them.
- @$slots = (0, $pair[0] + $pair[1]);
- }
- return $self;
- }
-
- # Load more data when we access slots->get(X) which is not yet in memory.
- sub overflow {
- my ($self) = @_;
- my $slots = $self->{slots};
- $self->{base} += $#$slots + 1; # skip over data we're replacing
- my $str;
- read($self->{file}, $str, $self->{stride});
- if ($address_length == 8) { # the 32-bit case
- # This is the easy case: unpack provides 32-bit unpacking primitives.
- @$slots = unpack($self->{unpack_code} . "*", $str);
- } else {
- # We need to unpack 32 bits at a time and combine.
- my @b32_values = unpack($self->{unpack_code} . "*", $str);
- my @b64_values = ();
- for (my $i = 0; $i < $#b32_values; $i += 2) {
- # TODO(csilvers): if this is a 32-bit perl, the math below
- # could end up in a too-large int, which perl will promote
- # to a double, losing necessary precision. Deal with that.
- # Right now, we just die.
- my ($lo, $hi) = ($b32_values[$i], $b32_values[$i+1]);
- if ($self->{unpack_code} eq 'N') { # big-endian
- ($lo, $hi) = ($hi, $lo);
- }
- my $value = $lo + $hi * (2**32);
- if (!$self->{perl_is_64bit} && # check value is exactly represented
- (($value % (2**32)) != $lo || int($value / (2**32)) != $hi)) {
- ::error("Need a 64-bit perl to process this 64-bit profile.\n");
- }
- push(@b64_values, $value);
- }
- @$slots = @b64_values;
- }
- }
-
- # Access the i-th long in the file (logically), or -1 at EOF.
- sub get {
- my ($self, $idx) = @_;
- my $slots = $self->{slots};
- while ($#$slots >= 0) {
- if ($idx < $self->{base}) {
- # The only time we expect a reference to $slots[$i - something]
- # after referencing $slots[$i] is reading the very first header.
- # Since $stride > |header|, that shouldn't cause any lookback
- # errors. And everything after the header is sequential.
- print STDERR "Unexpected look-back reading CPU profile";
- return -1; # shrug, don't know what better to return
- } elsif ($idx > $self->{base} + $#$slots) {
- $self->overflow();
- } else {
- return $slots->[$idx - $self->{base}];
- }
- }
- # If we get here, $slots is [], which means we've reached EOF
- return -1; # unique since slots is supposed to hold unsigned numbers
- }
-}
-
-# Reads the top, 'header' section of a profile, and returns the last
-# line of the header, commonly called a 'header line'. The header
-# section of a profile consists of zero or more 'command' lines that
-# are instructions to jeprof, which jeprof executes when reading the
-# header. All 'command' lines start with a %. After the command
-# lines is the 'header line', which is a profile-specific line that
-# indicates what type of profile it is, and perhaps other global
-# information about the profile. For instance, here's a header line
-# for a heap profile:
-# heap profile: 53: 38236 [ 5525: 1284029] @ heapprofile
-# For historical reasons, the CPU profile does not contain a text-
-# readable header line. If the profile looks like a CPU profile,
-# this function returns "". If no header line could be found, this
-# function returns undef.
-#
-# The following commands are recognized:
-# %warn -- emit the rest of this line to stderr, prefixed by 'WARNING:'
-#
-# The input file should be in binmode.
-sub ReadProfileHeader {
- local *PROFILE = shift;
- my $firstchar = "";
- my $line = "";
- read(PROFILE, $firstchar, 1);
- seek(PROFILE, -1, 1); # unread the firstchar
- if ($firstchar !~ /[[:print:]]/) { # is not a text character
- return "";
- }
- while (defined($line = <PROFILE>)) {
- $line =~ s/\r//g; # turn windows-looking lines into unix-looking lines
- if ($line =~ /^%warn\s+(.*)/) { # 'warn' command
- # Note this matches both '%warn blah\n' and '%warn\n'.
- print STDERR "WARNING: $1\n"; # print the rest of the line
- } elsif ($line =~ /^%/) {
- print STDERR "Ignoring unknown command from profile header: $line";
- } else {
- # End of commands, must be the header line.
- return $line;
- }
- }
- return undef; # got to EOF without seeing a header line
-}
-
-sub IsSymbolizedProfileFile {
- my $file_name = shift;
- if (!(-e $file_name) || !(-r $file_name)) {
- return 0;
- }
- # Check if the file contains a symbol-section marker.
- open(TFILE, "<$file_name");
- binmode TFILE;
- my $firstline = ReadProfileHeader(*TFILE);
- close(TFILE);
- if (!$firstline) {
- return 0;
- }
- $SYMBOL_PAGE =~ m,[^/]+$,; # matches everything after the last slash
- my $symbol_marker = $&;
- return $firstline =~ /^--- *$symbol_marker/;
-}
-
-# Parse profile generated by common/profiler.cc and return a reference
-# to a map:
-# $result->{version} Version number of profile file
-# $result->{period} Sampling period (in microseconds)
-# $result->{profile} Profile object
-# $result->{threads} Map of thread IDs to profile objects
-# $result->{map} Memory map info from profile
-# $result->{pcs} Hash of all PC values seen, key is hex address
-sub ReadProfile {
- my $prog = shift;
- my $fname = shift;
- my $result; # return value
-
- $CONTENTION_PAGE =~ m,[^/]+$,; # matches everything after the last slash
- my $contention_marker = $&;
- $GROWTH_PAGE =~ m,[^/]+$,; # matches everything after the last slash
- my $growth_marker = $&;
- $SYMBOL_PAGE =~ m,[^/]+$,; # matches everything after the last slash
- my $symbol_marker = $&;
- $PROFILE_PAGE =~ m,[^/]+$,; # matches everything after the last slash
- my $profile_marker = $&;
- $HEAP_PAGE =~ m,[^/]+$,; # matches everything after the last slash
- my $heap_marker = $&;
-
- # Look at first line to see if it is a heap or a CPU profile.
- # CPU profile may start with no header at all, and just binary data
- # (starting with \0\0\0\0) -- in that case, don't try to read the
- # whole firstline, since it may be gigabytes(!) of data.
- open(PROFILE, "<$fname") || error("$fname: $!\n");
- binmode PROFILE; # New perls do UTF-8 processing
- my $header = ReadProfileHeader(*PROFILE);
- if (!defined($header)) { # means "at EOF"
- error("Profile is empty.\n");
- }
-
- my $symbols;
- if ($header =~ m/^--- *$symbol_marker/o) {
- # Verify that the user asked for a symbolized profile
- if (!$main::use_symbolized_profile) {
- # we have both a binary and symbolized profiles, abort
- error("FATAL ERROR: Symbolized profile\n $fname\ncannot be used with " .
- "a binary arg. Try again without passing\n $prog\n");
- }
- # Read the symbol section of the symbolized profile file.
- $symbols = ReadSymbols(*PROFILE{IO});
- # Read the next line to get the header for the remaining profile.
- $header = ReadProfileHeader(*PROFILE) || "";
- }
-
- if ($header =~ m/^--- *($heap_marker|$growth_marker)/o) {
- # Skip "--- ..." line for profile types that have their own headers.
- $header = ReadProfileHeader(*PROFILE) || "";
- }
-
- $main::profile_type = '';
-
- if ($header =~ m/^heap profile:.*$growth_marker/o) {
- $main::profile_type = 'growth';
- $result = ReadHeapProfile($prog, *PROFILE, $header);
- } elsif ($header =~ m/^heap profile:/) {
- $main::profile_type = 'heap';
- $result = ReadHeapProfile($prog, *PROFILE, $header);
- } elsif ($header =~ m/^heap/) {
- $main::profile_type = 'heap';
- $result = ReadThreadedHeapProfile($prog, $fname, $header);
- } elsif ($header =~ m/^--- *$contention_marker/o) {
- $main::profile_type = 'contention';
- $result = ReadSynchProfile($prog, *PROFILE);
- } elsif ($header =~ m/^--- *Stacks:/) {
- print STDERR
- "Old format contention profile: mistakenly reports " .
- "condition variable signals as lock contentions.\n";
- $main::profile_type = 'contention';
- $result = ReadSynchProfile($prog, *PROFILE);
- } elsif ($header =~ m/^--- *$profile_marker/) {
- # the binary cpu profile data starts immediately after this line
- $main::profile_type = 'cpu';
- $result = ReadCPUProfile($prog, $fname, *PROFILE);
- } else {
- if (defined($symbols)) {
- # a symbolized profile contains a format we don't recognize, bail out
- error("$fname: Cannot recognize profile section after symbols.\n");
- }
- # no ascii header present -- must be a CPU profile
- $main::profile_type = 'cpu';
- $result = ReadCPUProfile($prog, $fname, *PROFILE);
- }
-
- close(PROFILE);
-
- # if we got symbols along with the profile, return those as well
- if (defined($symbols)) {
- $result->{symbols} = $symbols;
- }
-
- return $result;
-}
-
-# Subtract one from caller pc so we map back to call instr.
-# However, don't do this if we're reading a symbolized profile
-# file, in which case the subtract-one was done when the file
-# was written.
-#
-# We apply the same logic to all readers, though ReadCPUProfile uses an
-# independent implementation.
-sub FixCallerAddresses {
- my $stack = shift;
- # --raw/http: Always subtract one from pc's, because PrintSymbolizedProfile()
- # dumps unadjusted profiles.
- {
- $stack =~ /(\s)/;
- my $delimiter = $1;
- my @addrs = split(' ', $stack);
- my @fixedaddrs;
- $#fixedaddrs = $#addrs;
- if ($#addrs >= 0) {
- $fixedaddrs[0] = $addrs[0];
- }
- for (my $i = 1; $i <= $#addrs; $i++) {
- $fixedaddrs[$i] = AddressSub($addrs[$i], "0x1");
- }
- return join $delimiter, @fixedaddrs;
- }
-}
-
-# CPU profile reader
-sub ReadCPUProfile {
- my $prog = shift;
- my $fname = shift; # just used for logging
- local *PROFILE = shift;
- my $version;
- my $period;
- my $i;
- my $profile = {};
- my $pcs = {};
-
- # Parse string into array of slots.
- my $slots = CpuProfileStream->new(*PROFILE, $fname);
-
- # Read header. The current header version is a 5-element structure
- # containing:
- # 0: header count (always 0)
- # 1: header "words" (after this one: 3)
- # 2: format version (0)
- # 3: sampling period (usec)
- # 4: unused padding (always 0)
- if ($slots->get(0) != 0 ) {
- error("$fname: not a profile file, or old format profile file\n");
- }
- $i = 2 + $slots->get(1);
- $version = $slots->get(2);
- $period = $slots->get(3);
- # Do some sanity checking on these header values.
- if ($version > (2**32) || $period > (2**32) || $i > (2**32) || $i < 5) {
- error("$fname: not a profile file, or corrupted profile file\n");
- }
-
- # Parse profile
- while ($slots->get($i) != -1) {
- my $n = $slots->get($i++);
- my $d = $slots->get($i++);
- if ($d > (2**16)) { # TODO(csilvers): what's a reasonable max-stack-depth?
- my $addr = sprintf("0%o", $i * ($address_length == 8 ? 4 : 8));
- print STDERR "At index $i (address $addr):\n";
- error("$fname: stack trace depth >= 2**32\n");
- }
- if ($slots->get($i) == 0) {
- # End of profile data marker
- $i += $d;
- last;
- }
-
- # Make key out of the stack entries
- my @k = ();
- for (my $j = 0; $j < $d; $j++) {
- my $pc = $slots->get($i+$j);
- # Subtract one from caller pc so we map back to call instr.
- $pc--;
- $pc = sprintf("%0*x", $address_length, $pc);
- $pcs->{$pc} = 1;
- push @k, $pc;
- }
-
- AddEntry($profile, (join "\n", @k), $n);
- $i += $d;
- }
-
- # Parse map
- my $map = '';
- seek(PROFILE, $i * 4, 0);
- read(PROFILE, $map, (stat PROFILE)[7]);
-
- my $r = {};
- $r->{version} = $version;
- $r->{period} = $period;
- $r->{profile} = $profile;
- $r->{libs} = ParseLibraries($prog, $map, $pcs);
- $r->{pcs} = $pcs;
-
- return $r;
-}
-
-sub HeapProfileIndex {
- my $index = 1;
- if ($main::opt_inuse_space) {
- $index = 1;
- } elsif ($main::opt_inuse_objects) {
- $index = 0;
- } elsif ($main::opt_alloc_space) {
- $index = 3;
- } elsif ($main::opt_alloc_objects) {
- $index = 2;
- }
- return $index;
-}
-
-sub ReadMappedLibraries {
- my $fh = shift;
- my $map = "";
- # Read the /proc/self/maps data
- while (<$fh>) {
- s/\r//g; # turn windows-looking lines into unix-looking lines
- $map .= $_;
- }
- return $map;
-}
-
-sub ReadMemoryMap {
- my $fh = shift;
- my $map = "";
- # Read /proc/self/maps data as formatted by DumpAddressMap()
- my $buildvar = "";
- while (<PROFILE>) {
- s/\r//g; # turn windows-looking lines into unix-looking lines
- # Parse "build=<dir>" specification if supplied
- if (m/^\s*build=(.*)\n/) {
- $buildvar = $1;
- }
-
- # Expand "$build" variable if available
- $_ =~ s/\$build\b/$buildvar/g;
-
- $map .= $_;
- }
- return $map;
-}
-
-sub AdjustSamples {
- my ($sample_adjustment, $sampling_algorithm, $n1, $s1, $n2, $s2) = @_;
- if ($sample_adjustment) {
- if ($sampling_algorithm == 2) {
- # Remote-heap version 2
- # The sampling frequency is the rate of a Poisson process.
- # This means that the probability of sampling an allocation of
- # size X with sampling rate Y is 1 - exp(-X/Y)
- if ($n1 != 0) {
- my $ratio = (($s1*1.0)/$n1)/($sample_adjustment);
- my $scale_factor = 1/(1 - exp(-$ratio));
- $n1 *= $scale_factor;
- $s1 *= $scale_factor;
- }
- if ($n2 != 0) {
- my $ratio = (($s2*1.0)/$n2)/($sample_adjustment);
- my $scale_factor = 1/(1 - exp(-$ratio));
- $n2 *= $scale_factor;
- $s2 *= $scale_factor;
- }
- } else {
- # Remote-heap version 1
- my $ratio;
- $ratio = (($s1*1.0)/$n1)/($sample_adjustment);
- if ($ratio < 1) {
- $n1 /= $ratio;
- $s1 /= $ratio;
- }
- $ratio = (($s2*1.0)/$n2)/($sample_adjustment);
- if ($ratio < 1) {
- $n2 /= $ratio;
- $s2 /= $ratio;
- }
- }
- }
- return ($n1, $s1, $n2, $s2);
-}
-
-sub ReadHeapProfile {
- my $prog = shift;
- local *PROFILE = shift;
- my $header = shift;
-
- my $index = HeapProfileIndex();
-
- # Find the type of this profile. The header line looks like:
- # heap profile: 1246: 8800744 [ 1246: 8800744] @ <heap-url>/266053
- # There are two pairs <count: size>, the first inuse objects/space, and the
- # second allocated objects/space. This is followed optionally by a profile
- # type, and if that is present, optionally by a sampling frequency.
- # For remote heap profiles (v1):
- # The interpretation of the sampling frequency is that the profiler, for
- # each sample, calculates a uniformly distributed random integer less than
- # the given value, and records the next sample after that many bytes have
- # been allocated. Therefore, the expected sample interval is half of the
- # given frequency. By default, if not specified, the expected sample
- # interval is 128KB. Only remote-heap-page profiles are adjusted for
- # sample size.
- # For remote heap profiles (v2):
- # The sampling frequency is the rate of a Poisson process. This means that
- # the probability of sampling an allocation of size X with sampling rate Y
- # is 1 - exp(-X/Y)
- # For version 2, a typical header line might look like this:
- # heap profile: 1922: 127792360 [ 1922: 127792360] @ <heap-url>_v2/524288
- # the trailing number (524288) is the sampling rate. (Version 1 showed
- # double the 'rate' here)
- my $sampling_algorithm = 0;
- my $sample_adjustment = 0;
- chomp($header);
- my $type = "unknown";
- if ($header =~ m"^heap profile:\s*(\d+):\s+(\d+)\s+\[\s*(\d+):\s+(\d+)\](\s*@\s*([^/]*)(/(\d+))?)?") {
- if (defined($6) && ($6 ne '')) {
- $type = $6;
- my $sample_period = $8;
- # $type is "heapprofile" for profiles generated by the
- # heap-profiler, and either "heap" or "heap_v2" for profiles
- # generated by sampling directly within tcmalloc. It can also
- # be "growth" for heap-growth profiles. The first is typically
- # found for profiles generated locally, and the others for
- # remote profiles.
- if (($type eq "heapprofile") || ($type !~ /heap/) ) {
- # No need to adjust for the sampling rate with heap-profiler-derived data
- $sampling_algorithm = 0;
- } elsif ($type =~ /_v2/) {
- $sampling_algorithm = 2; # version 2 sampling
- if (defined($sample_period) && ($sample_period ne '')) {
- $sample_adjustment = int($sample_period);
- }
- } else {
- $sampling_algorithm = 1; # version 1 sampling
- if (defined($sample_period) && ($sample_period ne '')) {
- $sample_adjustment = int($sample_period)/2;
- }
- }
- } else {
- # We detect whether or not this is a remote-heap profile by checking
- # that the total-allocated stats ($n2,$s2) are exactly the
- # same as the in-use stats ($n1,$s1). It is remotely conceivable
- # that a non-remote-heap profile may pass this check, but it is hard
- # to imagine how that could happen.
- # In this case it's so old it's guaranteed to be remote-heap version 1.
- my ($n1, $s1, $n2, $s2) = ($1, $2, $3, $4);
- if (($n1 == $n2) && ($s1 == $s2)) {
- # This is likely to be a remote-heap based sample profile
- $sampling_algorithm = 1;
- }
- }
- }
-
- if ($sampling_algorithm > 0) {
- # For remote-heap generated profiles, adjust the counts and sizes to
- # account for the sample rate (we sample once every 128KB by default).
- if ($sample_adjustment == 0) {
- # Turn on profile adjustment.
- $sample_adjustment = 128*1024;
- print STDERR "Adjusting heap profiles for 1-in-128KB sampling rate\n";
- } else {
- printf STDERR ("Adjusting heap profiles for 1-in-%d sampling rate\n",
- $sample_adjustment);
- }
- if ($sampling_algorithm > 1) {
- # We don't bother printing anything for the original version (version 1)
- printf STDERR "Heap version $sampling_algorithm\n";
- }
- }
-
- my $profile = {};
- my $pcs = {};
- my $map = "";
-
- while (<PROFILE>) {
- s/\r//g; # turn windows-looking lines into unix-looking lines
- if (/^MAPPED_LIBRARIES:/) {
- $map .= ReadMappedLibraries(*PROFILE);
- last;
- }
-
- if (/^--- Memory map:/) {
- $map .= ReadMemoryMap(*PROFILE);
- last;
- }
-
- # Read entry of the form:
- # <count1>: <bytes1> [<count2>: <bytes2>] @ a1 a2 a3 ... an
- s/^\s*//;
- s/\s*$//;
- if (m/^\s*(\d+):\s+(\d+)\s+\[\s*(\d+):\s+(\d+)\]\s+@\s+(.*)$/) {
- my $stack = $5;
- my ($n1, $s1, $n2, $s2) = ($1, $2, $3, $4);
- my @counts = AdjustSamples($sample_adjustment, $sampling_algorithm,
- $n1, $s1, $n2, $s2);
- AddEntries($profile, $pcs, FixCallerAddresses($stack), $counts[$index]);
- }
- }
-
- my $r = {};
- $r->{version} = "heap";
- $r->{period} = 1;
- $r->{profile} = $profile;
- $r->{libs} = ParseLibraries($prog, $map, $pcs);
- $r->{pcs} = $pcs;
- return $r;
-}
-
-sub ReadThreadedHeapProfile {
- my ($prog, $fname, $header) = @_;
-
- my $index = HeapProfileIndex();
- my $sampling_algorithm = 0;
- my $sample_adjustment = 0;
- chomp($header);
- my $type = "unknown";
- # Assuming a very specific type of header for now.
- if ($header =~ m"^heap_v2/(\d+)") {
- $type = "_v2";
- $sampling_algorithm = 2;
- $sample_adjustment = int($1);
- }
- if ($type ne "_v2" || !defined($sample_adjustment)) {
- die "Threaded heap profiles require v2 sampling with a sample rate\n";
- }
-
- my $profile = {};
- my $thread_profiles = {};
- my $pcs = {};
- my $map = "";
- my $stack = "";
-
- while (<PROFILE>) {
- s/\r//g;
- if (/^MAPPED_LIBRARIES:/) {
- $map .= ReadMappedLibraries(*PROFILE);
- last;
- }
-
- if (/^--- Memory map:/) {
- $map .= ReadMemoryMap(*PROFILE);
- last;
- }
-
- # Read entry of the form:
- # @ a1 a2 ... an
- # t*: <count1>: <bytes1> [<count2>: <bytes2>]
- # t1: <count1>: <bytes1> [<count2>: <bytes2>]
- # ...
- # tn: <count1>: <bytes1> [<count2>: <bytes2>]
- s/^\s*//;
- s/\s*$//;
- if (m/^@\s+(.*)$/) {
- $stack = $1;
- } elsif (m/^\s*(t(\*|\d+)):\s+(\d+):\s+(\d+)\s+\[\s*(\d+):\s+(\d+)\]$/) {
- if ($stack eq "") {
- # Still in the header, so this is just a per-thread summary.
- next;
- }
- my $thread = $2;
- my ($n1, $s1, $n2, $s2) = ($3, $4, $5, $6);
- my @counts = AdjustSamples($sample_adjustment, $sampling_algorithm,
- $n1, $s1, $n2, $s2);
- if ($thread eq "*") {
- AddEntries($profile, $pcs, FixCallerAddresses($stack), $counts[$index]);
- } else {
- if (!exists($thread_profiles->{$thread})) {
- $thread_profiles->{$thread} = {};
- }
- AddEntries($thread_profiles->{$thread}, $pcs,
- FixCallerAddresses($stack), $counts[$index]);
- }
- }
- }
-
- my $r = {};
- $r->{version} = "heap";
- $r->{period} = 1;
- $r->{profile} = $profile;
- $r->{threads} = $thread_profiles;
- $r->{libs} = ParseLibraries($prog, $map, $pcs);
- $r->{pcs} = $pcs;
- return $r;
-}
-
-sub ReadSynchProfile {
- my $prog = shift;
- local *PROFILE = shift;
- my $header = shift;
-
- my $map = '';
- my $profile = {};
- my $pcs = {};
- my $sampling_period = 1;
- my $cyclespernanosec = 2.8; # Default assumption for old binaries
- my $seen_clockrate = 0;
- my $line;
-
- my $index = 0;
- if ($main::opt_total_delay) {
- $index = 0;
- } elsif ($main::opt_contentions) {
- $index = 1;
- } elsif ($main::opt_mean_delay) {
- $index = 2;
- }
-
- while ( $line = <PROFILE> ) {
- $line =~ s/\r//g; # turn windows-looking lines into unix-looking lines
- if ( $line =~ /^\s*(\d+)\s+(\d+) \@\s*(.*?)\s*$/ ) {
- my ($cycles, $count, $stack) = ($1, $2, $3);
-
- # Convert cycles to nanoseconds
- $cycles /= $cyclespernanosec;
-
- # Adjust for sampling done by application
- $cycles *= $sampling_period;
- $count *= $sampling_period;
-
- my @values = ($cycles, $count, $cycles / $count);
- AddEntries($profile, $pcs, FixCallerAddresses($stack), $values[$index]);
-
- } elsif ( $line =~ /^(slow release).*thread \d+ \@\s*(.*?)\s*$/ ||
- $line =~ /^\s*(\d+) \@\s*(.*?)\s*$/ ) {
- my ($cycles, $stack) = ($1, $2);
- if ($cycles !~ /^\d+$/) {
- next;
- }
-
- # Convert cycles to nanoseconds
- $cycles /= $cyclespernanosec;
-
- # Adjust for sampling done by application
- $cycles *= $sampling_period;
-
- AddEntries($profile, $pcs, FixCallerAddresses($stack), $cycles);
-
- } elsif ( $line =~ m/^([a-z][^=]*)=(.*)$/ ) {
- my ($variable, $value) = ($1,$2);
- for ($variable, $value) {
- s/^\s+//;
- s/\s+$//;
- }
- if ($variable eq "cycles/second") {
- $cyclespernanosec = $value / 1e9;
- $seen_clockrate = 1;
- } elsif ($variable eq "sampling period") {
- $sampling_period = $value;
- } elsif ($variable eq "ms since reset") {
- # Currently nothing is done with this value in jeprof
- # So we just silently ignore it for now
- } elsif ($variable eq "discarded samples") {
- # Currently nothing is done with this value in jeprof
- # So we just silently ignore it for now
- } else {
- printf STDERR ("Ignoring unnknown variable in /contention output: " .
- "'%s' = '%s'\n",$variable,$value);
- }
- } else {
- # Memory map entry
- $map .= $line;
- }
- }
-
- if (!$seen_clockrate) {
- printf STDERR ("No cycles/second entry in profile; Guessing %.1f GHz\n",
- $cyclespernanosec);
- }
-
- my $r = {};
- $r->{version} = 0;
- $r->{period} = $sampling_period;
- $r->{profile} = $profile;
- $r->{libs} = ParseLibraries($prog, $map, $pcs);
- $r->{pcs} = $pcs;
- return $r;
-}
-
-# Given a hex value in the form "0x1abcd" or "1abcd", return either
-# "0001abcd" or "000000000001abcd", depending on the current (global)
-# address length.
-sub HexExtend {
- my $addr = shift;
-
- $addr =~ s/^(0x)?0*//;
- my $zeros_needed = $address_length - length($addr);
- if ($zeros_needed < 0) {
- printf STDERR "Warning: address $addr is longer than address length $address_length\n";
- return $addr;
- }
- return ("0" x $zeros_needed) . $addr;
-}
-
-##### Symbol extraction #####
-
-# Aggressively search the lib_prefix values for the given library
-# If all else fails, just return the name of the library unmodified.
-# If the lib_prefix is "/my/path,/other/path" and $file is "/lib/dir/mylib.so"
-# it will search the following locations in this order, until it finds a file:
-# /my/path/lib/dir/mylib.so
-# /other/path/lib/dir/mylib.so
-# /my/path/dir/mylib.so
-# /other/path/dir/mylib.so
-# /my/path/mylib.so
-# /other/path/mylib.so
-# /lib/dir/mylib.so (returned as last resort)
-sub FindLibrary {
- my $file = shift;
- my $suffix = $file;
-
- # Search for the library as described above
- do {
- foreach my $prefix (@prefix_list) {
- my $fullpath = $prefix . $suffix;
- if (-e $fullpath) {
- return $fullpath;
- }
- }
- } while ($suffix =~ s|^/[^/]+/|/|);
- return $file;
-}
-
-# Return path to library with debugging symbols.
-# For libc libraries, the copy in /usr/lib/debug contains debugging symbols
-sub DebuggingLibrary {
- my $file = shift;
- if ($file =~ m|^/|) {
- if (-f "/usr/lib/debug$file") {
- return "/usr/lib/debug$file";
- } elsif (-f "/usr/lib/debug$file.debug") {
- return "/usr/lib/debug$file.debug";
- }
- }
- return undef;
-}
-
-# Parse text section header of a library using objdump
-sub ParseTextSectionHeaderFromObjdump {
- my $lib = shift;
-
- my $size = undef;
- my $vma;
- my $file_offset;
- # Get objdump output from the library file to figure out how to
- # map between mapped addresses and addresses in the library.
- my $cmd = ShellEscape($obj_tool_map{"objdump"}, "-h", $lib);
- open(OBJDUMP, "$cmd |") || error("$cmd: $!\n");
- while (<OBJDUMP>) {
- s/\r//g; # turn windows-looking lines into unix-looking lines
- # Idx Name Size VMA LMA File off Algn
- # 10 .text 00104b2c 420156f0 420156f0 000156f0 2**4
- # For 64-bit objects, VMA and LMA will be 16 hex digits, size and file
- # offset may still be 8. But AddressSub below will still handle that.
- my @x = split;
- if (($#x >= 6) && ($x[1] eq '.text')) {
- $size = $x[2];
- $vma = $x[3];
- $file_offset = $x[5];
- last;
- }
- }
- close(OBJDUMP);
-
- if (!defined($size)) {
- return undef;
- }
-
- my $r = {};
- $r->{size} = $size;
- $r->{vma} = $vma;
- $r->{file_offset} = $file_offset;
-
- return $r;
-}
-
-# Parse text section header of a library using otool (on OS X)
-sub ParseTextSectionHeaderFromOtool {
- my $lib = shift;
-
- my $size = undef;
- my $vma = undef;
- my $file_offset = undef;
- # Get otool output from the library file to figure out how to
- # map between mapped addresses and addresses in the library.
- my $command = ShellEscape($obj_tool_map{"otool"}, "-l", $lib);
- open(OTOOL, "$command |") || error("$command: $!\n");
- my $cmd = "";
- my $sectname = "";
- my $segname = "";
- foreach my $line (<OTOOL>) {
- $line =~ s/\r//g; # turn windows-looking lines into unix-looking lines
- # Load command <#>
- # cmd LC_SEGMENT
- # [...]
- # Section
- # sectname __text
- # segname __TEXT
- # addr 0x000009f8
- # size 0x00018b9e
- # offset 2552
- # align 2^2 (4)
- # We will need to strip off the leading 0x from the hex addresses,
- # and convert the offset into hex.
- if ($line =~ /Load command/) {
- $cmd = "";
- $sectname = "";
- $segname = "";
- } elsif ($line =~ /Section/) {
- $sectname = "";
- $segname = "";
- } elsif ($line =~ /cmd (\w+)/) {
- $cmd = $1;
- } elsif ($line =~ /sectname (\w+)/) {
- $sectname = $1;
- } elsif ($line =~ /segname (\w+)/) {
- $segname = $1;
- } elsif (!(($cmd eq "LC_SEGMENT" || $cmd eq "LC_SEGMENT_64") &&
- $sectname eq "__text" &&
- $segname eq "__TEXT")) {
- next;
- } elsif ($line =~ /\baddr 0x([0-9a-fA-F]+)/) {
- $vma = $1;
- } elsif ($line =~ /\bsize 0x([0-9a-fA-F]+)/) {
- $size = $1;
- } elsif ($line =~ /\boffset ([0-9]+)/) {
- $file_offset = sprintf("%016x", $1);
- }
- if (defined($vma) && defined($size) && defined($file_offset)) {
- last;
- }
- }
- close(OTOOL);
-
- if (!defined($vma) || !defined($size) || !defined($file_offset)) {
- return undef;
- }
-
- my $r = {};
- $r->{size} = $size;
- $r->{vma} = $vma;
- $r->{file_offset} = $file_offset;
-
- return $r;
-}
-
-sub ParseTextSectionHeader {
- # obj_tool_map("otool") is only defined if we're in a Mach-O environment
- if (defined($obj_tool_map{"otool"})) {
- my $r = ParseTextSectionHeaderFromOtool(@_);
- if (defined($r)){
- return $r;
- }
- }
- # If otool doesn't work, or we don't have it, fall back to objdump
- return ParseTextSectionHeaderFromObjdump(@_);
-}
-
-# Split /proc/pid/maps dump into a list of libraries
-sub ParseLibraries {
- return if $main::use_symbol_page; # We don't need libraries info.
- my $prog = Cwd::abs_path(shift);
- my $map = shift;
- my $pcs = shift;
-
- my $result = [];
- my $h = "[a-f0-9]+";
- my $zero_offset = HexExtend("0");
-
- my $buildvar = "";
- foreach my $l (split("\n", $map)) {
- if ($l =~ m/^\s*build=(.*)$/) {
- $buildvar = $1;
- }
-
- my $start;
- my $finish;
- my $offset;
- my $lib;
- if ($l =~ /^($h)-($h)\s+..x.\s+($h)\s+\S+:\S+\s+\d+\s+(\S+\.(so|dll|dylib|bundle)((\.\d+)+\w*(\.\d+){0,3})?)$/i) {
- # Full line from /proc/self/maps. Example:
- # 40000000-40015000 r-xp 00000000 03:01 12845071 /lib/ld-2.3.2.so
- $start = HexExtend($1);
- $finish = HexExtend($2);
- $offset = HexExtend($3);
- $lib = $4;
- $lib =~ s|\\|/|g; # turn windows-style paths into unix-style paths
- } elsif ($l =~ /^\s*($h)-($h):\s*(\S+\.so(\.\d+)*)/) {
- # Cooked line from DumpAddressMap. Example:
- # 40000000-40015000: /lib/ld-2.3.2.so
- $start = HexExtend($1);
- $finish = HexExtend($2);
- $offset = $zero_offset;
- $lib = $3;
- } elsif (($l =~ /^($h)-($h)\s+..x.\s+($h)\s+\S+:\S+\s+\d+\s+(\S+)$/i) && ($4 eq $prog)) {
- # PIEs and address space randomization do not play well with our
- # default assumption that main executable is at lowest
- # addresses. So we're detecting main executable in
- # /proc/self/maps as well.
- $start = HexExtend($1);
- $finish = HexExtend($2);
- $offset = HexExtend($3);
- $lib = $4;
- $lib =~ s|\\|/|g; # turn windows-style paths into unix-style paths
- }
- # FreeBSD 10.0 virtual memory map /proc/curproc/map as defined in
- # function procfs_doprocmap (sys/fs/procfs/procfs_map.c)
- #
- # Example:
- # 0x800600000 0x80061a000 26 0 0xfffff800035a0000 r-x 75 33 0x1004 COW NC vnode /libexec/ld-elf.s
- # o.1 NCH -1
- elsif ($l =~ /^(0x$h)\s(0x$h)\s\d+\s\d+\s0x$h\sr-x\s\d+\s\d+\s0x\d+\s(COW|NCO)\s(NC|NNC)\svnode\s(\S+\.so(\.\d+)*)/) {
- $start = HexExtend($1);
- $finish = HexExtend($2);
- $offset = $zero_offset;
- $lib = FindLibrary($5);
-
- } else {
- next;
- }
-
- # Expand "$build" variable if available
- $lib =~ s/\$build\b/$buildvar/g;
-
- $lib = FindLibrary($lib);
-
- # Check for pre-relocated libraries, which use pre-relocated symbol tables
- # and thus require adjusting the offset that we'll use to translate
- # VM addresses into symbol table addresses.
- # Only do this if we're not going to fetch the symbol table from a
- # debugging copy of the library.
- if (!DebuggingLibrary($lib)) {
- my $text = ParseTextSectionHeader($lib);
- if (defined($text)) {
- my $vma_offset = AddressSub($text->{vma}, $text->{file_offset});
- $offset = AddressAdd($offset, $vma_offset);
- }
- }
-
- if($main::opt_debug) { printf STDERR "$start:$finish ($offset) $lib\n"; }
- push(@{$result}, [$lib, $start, $finish, $offset]);
- }
-
- # Append special entry for additional library (not relocated)
- if ($main::opt_lib ne "") {
- my $text = ParseTextSectionHeader($main::opt_lib);
- if (defined($text)) {
- my $start = $text->{vma};
- my $finish = AddressAdd($start, $text->{size});
-
- push(@{$result}, [$main::opt_lib, $start, $finish, $start]);
- }
- }
-
- # Append special entry for the main program. This covers
- # 0..max_pc_value_seen, so that we assume pc values not found in one
- # of the library ranges will be treated as coming from the main
- # program binary.
- my $min_pc = HexExtend("0");
- my $max_pc = $min_pc; # find the maximal PC value in any sample
- foreach my $pc (keys(%{$pcs})) {
- if (HexExtend($pc) gt $max_pc) { $max_pc = HexExtend($pc); }
- }
- push(@{$result}, [$prog, $min_pc, $max_pc, $zero_offset]);
-
- return $result;
-}
-
-# Add two hex addresses of length $address_length.
-# Run jeprof --test for unit test if this is changed.
-sub AddressAdd {
- my $addr1 = shift;
- my $addr2 = shift;
- my $sum;
-
- if ($address_length == 8) {
- # Perl doesn't cope with wraparound arithmetic, so do it explicitly:
- $sum = (hex($addr1)+hex($addr2)) % (0x10000000 * 16);
- return sprintf("%08x", $sum);
-
- } else {
- # Do the addition in 7-nibble chunks to trivialize carry handling.
-
- if ($main::opt_debug and $main::opt_test) {
- print STDERR "AddressAdd $addr1 + $addr2 = ";
- }
-
- my $a1 = substr($addr1,-7);
- $addr1 = substr($addr1,0,-7);
- my $a2 = substr($addr2,-7);
- $addr2 = substr($addr2,0,-7);
- $sum = hex($a1) + hex($a2);
- my $c = 0;
- if ($sum > 0xfffffff) {
- $c = 1;
- $sum -= 0x10000000;
- }
- my $r = sprintf("%07x", $sum);
-
- $a1 = substr($addr1,-7);
- $addr1 = substr($addr1,0,-7);
- $a2 = substr($addr2,-7);
- $addr2 = substr($addr2,0,-7);
- $sum = hex($a1) + hex($a2) + $c;
- $c = 0;
- if ($sum > 0xfffffff) {
- $c = 1;
- $sum -= 0x10000000;
- }
- $r = sprintf("%07x", $sum) . $r;
-
- $sum = hex($addr1) + hex($addr2) + $c;
- if ($sum > 0xff) { $sum -= 0x100; }
- $r = sprintf("%02x", $sum) . $r;
-
- if ($main::opt_debug and $main::opt_test) { print STDERR "$r\n"; }
-
- return $r;
- }
-}
-
-
-# Subtract two hex addresses of length $address_length.
-# Run jeprof --test for unit test if this is changed.
-sub AddressSub {
- my $addr1 = shift;
- my $addr2 = shift;
- my $diff;
-
- if ($address_length == 8) {
- # Perl doesn't cope with wraparound arithmetic, so do it explicitly:
- $diff = (hex($addr1)-hex($addr2)) % (0x10000000 * 16);
- return sprintf("%08x", $diff);
-
- } else {
- # Do the addition in 7-nibble chunks to trivialize borrow handling.
- # if ($main::opt_debug) { print STDERR "AddressSub $addr1 - $addr2 = "; }
-
- my $a1 = hex(substr($addr1,-7));
- $addr1 = substr($addr1,0,-7);
- my $a2 = hex(substr($addr2,-7));
- $addr2 = substr($addr2,0,-7);
- my $b = 0;
- if ($a2 > $a1) {
- $b = 1;
- $a1 += 0x10000000;
- }
- $diff = $a1 - $a2;
- my $r = sprintf("%07x", $diff);
-
- $a1 = hex(substr($addr1,-7));
- $addr1 = substr($addr1,0,-7);
- $a2 = hex(substr($addr2,-7)) + $b;
- $addr2 = substr($addr2,0,-7);
- $b = 0;
- if ($a2 > $a1) {
- $b = 1;
- $a1 += 0x10000000;
- }
- $diff = $a1 - $a2;
- $r = sprintf("%07x", $diff) . $r;
-
- $a1 = hex($addr1);
- $a2 = hex($addr2) + $b;
- if ($a2 > $a1) { $a1 += 0x100; }
- $diff = $a1 - $a2;
- $r = sprintf("%02x", $diff) . $r;
-
- # if ($main::opt_debug) { print STDERR "$r\n"; }
-
- return $r;
- }
-}
-
-# Increment a hex addresses of length $address_length.
-# Run jeprof --test for unit test if this is changed.
-sub AddressInc {
- my $addr = shift;
- my $sum;
-
- if ($address_length == 8) {
- # Perl doesn't cope with wraparound arithmetic, so do it explicitly:
- $sum = (hex($addr)+1) % (0x10000000 * 16);
- return sprintf("%08x", $sum);
-
- } else {
- # Do the addition in 7-nibble chunks to trivialize carry handling.
- # We are always doing this to step through the addresses in a function,
- # and will almost never overflow the first chunk, so we check for this
- # case and exit early.
-
- # if ($main::opt_debug) { print STDERR "AddressInc $addr1 = "; }
-
- my $a1 = substr($addr,-7);
- $addr = substr($addr,0,-7);
- $sum = hex($a1) + 1;
- my $r = sprintf("%07x", $sum);
- if ($sum <= 0xfffffff) {
- $r = $addr . $r;
- # if ($main::opt_debug) { print STDERR "$r\n"; }
- return HexExtend($r);
- } else {
- $r = "0000000";
- }
-
- $a1 = substr($addr,-7);
- $addr = substr($addr,0,-7);
- $sum = hex($a1) + 1;
- $r = sprintf("%07x", $sum) . $r;
- if ($sum <= 0xfffffff) {
- $r = $addr . $r;
- # if ($main::opt_debug) { print STDERR "$r\n"; }
- return HexExtend($r);
- } else {
- $r = "00000000000000";
- }
-
- $sum = hex($addr) + 1;
- if ($sum > 0xff) { $sum -= 0x100; }
- $r = sprintf("%02x", $sum) . $r;
-
- # if ($main::opt_debug) { print STDERR "$r\n"; }
- return $r;
- }
-}
-
-# Extract symbols for all PC values found in profile
-sub ExtractSymbols {
- my $libs = shift;
- my $pcset = shift;
-
- my $symbols = {};
-
- # Map each PC value to the containing library. To make this faster,
- # we sort libraries by their starting pc value (highest first), and
- # advance through the libraries as we advance the pc. Sometimes the
- # addresses of libraries may overlap with the addresses of the main
- # binary, so to make sure the libraries 'win', we iterate over the
- # libraries in reverse order (which assumes the binary doesn't start
- # in the middle of a library, which seems a fair assumption).
- my @pcs = (sort { $a cmp $b } keys(%{$pcset})); # pcset is 0-extended strings
- foreach my $lib (sort {$b->[1] cmp $a->[1]} @{$libs}) {
- my $libname = $lib->[0];
- my $start = $lib->[1];
- my $finish = $lib->[2];
- my $offset = $lib->[3];
-
- # Use debug library if it exists
- my $debug_libname = DebuggingLibrary($libname);
- if ($debug_libname) {
- $libname = $debug_libname;
- }
-
- # Get list of pcs that belong in this library.
- my $contained = [];
- my ($start_pc_index, $finish_pc_index);
- # Find smallest finish_pc_index such that $finish < $pc[$finish_pc_index].
- for ($finish_pc_index = $#pcs + 1; $finish_pc_index > 0;
- $finish_pc_index--) {
- last if $pcs[$finish_pc_index - 1] le $finish;
- }
- # Find smallest start_pc_index such that $start <= $pc[$start_pc_index].
- for ($start_pc_index = $finish_pc_index; $start_pc_index > 0;
- $start_pc_index--) {
- last if $pcs[$start_pc_index - 1] lt $start;
- }
- # This keeps PC values higher than $pc[$finish_pc_index] in @pcs,
- # in case there are overlaps in libraries and the main binary.
- @{$contained} = splice(@pcs, $start_pc_index,
- $finish_pc_index - $start_pc_index);
- # Map to symbols
- MapToSymbols($libname, AddressSub($start, $offset), $contained, $symbols);
- }
-
- return $symbols;
-}
-
-# Map list of PC values to symbols for a given image
-sub MapToSymbols {
- my $image = shift;
- my $offset = shift;
- my $pclist = shift;
- my $symbols = shift;
-
- my $debug = 0;
-
- # Ignore empty binaries
- if ($#{$pclist} < 0) { return; }
-
- # Figure out the addr2line command to use
- my $addr2line = $obj_tool_map{"addr2line"};
- my $cmd = ShellEscape($addr2line, "-f", "-C", "-e", $image);
- if (exists $obj_tool_map{"addr2line_pdb"}) {
- $addr2line = $obj_tool_map{"addr2line_pdb"};
- $cmd = ShellEscape($addr2line, "--demangle", "-f", "-C", "-e", $image);
- }
-
- # If "addr2line" isn't installed on the system at all, just use
- # nm to get what info we can (function names, but not line numbers).
- if (system(ShellEscape($addr2line, "--help") . " >$dev_null 2>&1") != 0) {
- MapSymbolsWithNM($image, $offset, $pclist, $symbols);
- return;
- }
-
- # "addr2line -i" can produce a variable number of lines per input
- # address, with no separator that allows us to tell when data for
- # the next address starts. So we find the address for a special
- # symbol (_fini) and interleave this address between all real
- # addresses passed to addr2line. The name of this special symbol
- # can then be used as a separator.
- $sep_address = undef; # May be filled in by MapSymbolsWithNM()
- my $nm_symbols = {};
- MapSymbolsWithNM($image, $offset, $pclist, $nm_symbols);
- if (defined($sep_address)) {
- # Only add " -i" to addr2line if the binary supports it.
- # addr2line --help returns 0, but not if it sees an unknown flag first.
- if (system("$cmd -i --help >$dev_null 2>&1") == 0) {
- $cmd .= " -i";
- } else {
- $sep_address = undef; # no need for sep_address if we don't support -i
- }
- }
-
- # Make file with all PC values with intervening 'sep_address' so
- # that we can reliably detect the end of inlined function list
- open(ADDRESSES, ">$main::tmpfile_sym") || error("$main::tmpfile_sym: $!\n");
- if ($debug) { print("---- $image ---\n"); }
- for (my $i = 0; $i <= $#{$pclist}; $i++) {
- # addr2line always reads hex addresses, and does not need '0x' prefix.
- if ($debug) { printf STDERR ("%s\n", $pclist->[$i]); }
- printf ADDRESSES ("%s\n", AddressSub($pclist->[$i], $offset));
- if (defined($sep_address)) {
- printf ADDRESSES ("%s\n", $sep_address);
- }
- }
- close(ADDRESSES);
- if ($debug) {
- print("----\n");
- system("cat", $main::tmpfile_sym);
- print("----\n");
- system("$cmd < " . ShellEscape($main::tmpfile_sym));
- print("----\n");
- }
-
- open(SYMBOLS, "$cmd <" . ShellEscape($main::tmpfile_sym) . " |")
- || error("$cmd: $!\n");
- my $count = 0; # Index in pclist
- while (<SYMBOLS>) {
- # Read fullfunction and filelineinfo from next pair of lines
- s/\r?\n$//g;
- my $fullfunction = $_;
- $_ = <SYMBOLS>;
- s/\r?\n$//g;
- my $filelinenum = $_;
-
- if (defined($sep_address) && $fullfunction eq $sep_symbol) {
- # Terminating marker for data for this address
- $count++;
- next;
- }
-
- $filelinenum =~ s|\\|/|g; # turn windows-style paths into unix-style paths
-
- my $pcstr = $pclist->[$count];
- my $function = ShortFunctionName($fullfunction);
- my $nms = $nm_symbols->{$pcstr};
- if (defined($nms)) {
- if ($fullfunction eq '??') {
- # nm found a symbol for us.
- $function = $nms->[0];
- $fullfunction = $nms->[2];
- } else {
- # MapSymbolsWithNM tags each routine with its starting address,
- # useful in case the image has multiple occurrences of this
- # routine. (It uses a syntax that resembles template paramters,
- # that are automatically stripped out by ShortFunctionName().)
- # addr2line does not provide the same information. So we check
- # if nm disambiguated our symbol, and if so take the annotated
- # (nm) version of the routine-name. TODO(csilvers): this won't
- # catch overloaded, inlined symbols, which nm doesn't see.
- # Better would be to do a check similar to nm's, in this fn.
- if ($nms->[2] =~ m/^\Q$function\E/) { # sanity check it's the right fn
- $function = $nms->[0];
- $fullfunction = $nms->[2];
- }
- }
- }
-
- # Prepend to accumulated symbols for pcstr
- # (so that caller comes before callee)
- my $sym = $symbols->{$pcstr};
- if (!defined($sym)) {
- $sym = [];
- $symbols->{$pcstr} = $sym;
- }
- unshift(@{$sym}, $function, $filelinenum, $fullfunction);
- if ($debug) { printf STDERR ("%s => [%s]\n", $pcstr, join(" ", @{$sym})); }
- if (!defined($sep_address)) {
- # Inlining is off, so this entry ends immediately
- $count++;
- }
- }
- close(SYMBOLS);
-}
-
-# Use nm to map the list of referenced PCs to symbols. Return true iff we
-# are able to read procedure information via nm.
-sub MapSymbolsWithNM {
- my $image = shift;
- my $offset = shift;
- my $pclist = shift;
- my $symbols = shift;
-
- # Get nm output sorted by increasing address
- my $symbol_table = GetProcedureBoundaries($image, ".");
- if (!%{$symbol_table}) {
- return 0;
- }
- # Start addresses are already the right length (8 or 16 hex digits).
- my @names = sort { $symbol_table->{$a}->[0] cmp $symbol_table->{$b}->[0] }
- keys(%{$symbol_table});
-
- if ($#names < 0) {
- # No symbols: just use addresses
- foreach my $pc (@{$pclist}) {
- my $pcstr = "0x" . $pc;
- $symbols->{$pc} = [$pcstr, "?", $pcstr];
- }
- return 0;
- }
-
- # Sort addresses so we can do a join against nm output
- my $index = 0;
- my $fullname = $names[0];
- my $name = ShortFunctionName($fullname);
- foreach my $pc (sort { $a cmp $b } @{$pclist}) {
- # Adjust for mapped offset
- my $mpc = AddressSub($pc, $offset);
- while (($index < $#names) && ($mpc ge $symbol_table->{$fullname}->[1])){
- $index++;
- $fullname = $names[$index];
- $name = ShortFunctionName($fullname);
- }
- if ($mpc lt $symbol_table->{$fullname}->[1]) {
- $symbols->{$pc} = [$name, "?", $fullname];
- } else {
- my $pcstr = "0x" . $pc;
- $symbols->{$pc} = [$pcstr, "?", $pcstr];
- }
- }
- return 1;
-}
-
-sub ShortFunctionName {
- my $function = shift;
- while ($function =~ s/\([^()]*\)(\s*const)?//g) { } # Argument types
- while ($function =~ s/<[^<>]*>//g) { } # Remove template arguments
- $function =~ s/^.*\s+(\w+::)/$1/; # Remove leading type
- return $function;
-}
-
-# Trim overly long symbols found in disassembler output
-sub CleanDisassembly {
- my $d = shift;
- while ($d =~ s/\([^()%]*\)(\s*const)?//g) { } # Argument types, not (%rax)
- while ($d =~ s/(\w+)<[^<>]*>/$1/g) { } # Remove template arguments
- return $d;
-}
-
-# Clean file name for display
-sub CleanFileName {
- my ($f) = @_;
- $f =~ s|^/proc/self/cwd/||;
- $f =~ s|^\./||;
- return $f;
-}
-
-# Make address relative to section and clean up for display
-sub UnparseAddress {
- my ($offset, $address) = @_;
- $address = AddressSub($address, $offset);
- $address =~ s/^0x//;
- $address =~ s/^0*//;
- return $address;
-}
-
-##### Miscellaneous #####
-
-# Find the right versions of the above object tools to use. The
-# argument is the program file being analyzed, and should be an ELF
-# 32-bit or ELF 64-bit executable file. The location of the tools
-# is determined by considering the following options in this order:
-# 1) --tools option, if set
-# 2) JEPROF_TOOLS environment variable, if set
-# 3) the environment
-sub ConfigureObjTools {
- my $prog_file = shift;
-
- # Check for the existence of $prog_file because /usr/bin/file does not
- # predictably return error status in prod.
- (-e $prog_file) || error("$prog_file does not exist.\n");
-
- my $file_type = undef;
- if (-e "/usr/bin/file") {
- # Follow symlinks (at least for systems where "file" supports that).
- my $escaped_prog_file = ShellEscape($prog_file);
- $file_type = `/usr/bin/file -L $escaped_prog_file 2>$dev_null ||
- /usr/bin/file $escaped_prog_file`;
- } elsif ($^O == "MSWin32") {
- $file_type = "MS Windows";
- } else {
- print STDERR "WARNING: Can't determine the file type of $prog_file";
- }
-
- if ($file_type =~ /64-bit/) {
- # Change $address_length to 16 if the program file is ELF 64-bit.
- # We can't detect this from many (most?) heap or lock contention
- # profiles, since the actual addresses referenced are generally in low
- # memory even for 64-bit programs.
- $address_length = 16;
- }
-
- if ($file_type =~ /MS Windows/) {
- # For windows, we provide a version of nm and addr2line as part of
- # the opensource release, which is capable of parsing
- # Windows-style PDB executables. It should live in the path, or
- # in the same directory as jeprof.
- $obj_tool_map{"nm_pdb"} = "nm-pdb";
- $obj_tool_map{"addr2line_pdb"} = "addr2line-pdb";
- }
-
- if ($file_type =~ /Mach-O/) {
- # OS X uses otool to examine Mach-O files, rather than objdump.
- $obj_tool_map{"otool"} = "otool";
- $obj_tool_map{"addr2line"} = "false"; # no addr2line
- $obj_tool_map{"objdump"} = "false"; # no objdump
- }
-
- # Go fill in %obj_tool_map with the pathnames to use:
- foreach my $tool (keys %obj_tool_map) {
- $obj_tool_map{$tool} = ConfigureTool($obj_tool_map{$tool});
- }
-}
-
-# Returns the path of a caller-specified object tool. If --tools or
-# JEPROF_TOOLS are specified, then returns the full path to the tool
-# with that prefix. Otherwise, returns the path unmodified (which
-# means we will look for it on PATH).
-sub ConfigureTool {
- my $tool = shift;
- my $path;
-
- # --tools (or $JEPROF_TOOLS) is a comma separated list, where each
- # item is either a) a pathname prefix, or b) a map of the form
- # <tool>:<path>. First we look for an entry of type (b) for our
- # tool. If one is found, we use it. Otherwise, we consider all the
- # pathname prefixes in turn, until one yields an existing file. If
- # none does, we use a default path.
- my $tools = $main::opt_tools || $ENV{"JEPROF_TOOLS"} || "";
- if ($tools =~ m/(,|^)\Q$tool\E:([^,]*)/) {
- $path = $2;
- # TODO(csilvers): sanity-check that $path exists? Hard if it's relative.
- } elsif ($tools ne '') {
- foreach my $prefix (split(',', $tools)) {
- next if ($prefix =~ /:/); # ignore "tool:fullpath" entries in the list
- if (-x $prefix . $tool) {
- $path = $prefix . $tool;
- last;
- }
- }
- if (!$path) {
- error("No '$tool' found with prefix specified by " .
- "--tools (or \$JEPROF_TOOLS) '$tools'\n");
- }
- } else {
- # ... otherwise use the version that exists in the same directory as
- # jeprof. If there's nothing there, use $PATH.
- $0 =~ m,[^/]*$,; # this is everything after the last slash
- my $dirname = $`; # this is everything up to and including the last slash
- if (-x "$dirname$tool") {
- $path = "$dirname$tool";
- } else {
- $path = $tool;
- }
- }
- if ($main::opt_debug) { print STDERR "Using '$path' for '$tool'.\n"; }
- return $path;
-}
-
-sub ShellEscape {
- my @escaped_words = ();
- foreach my $word (@_) {
- my $escaped_word = $word;
- if ($word =~ m![^a-zA-Z0-9/.,_=-]!) { # check for anything not in whitelist
- $escaped_word =~ s/'/'\\''/;
- $escaped_word = "'$escaped_word'";
- }
- push(@escaped_words, $escaped_word);
- }
- return join(" ", @escaped_words);
-}
-
-sub cleanup {
- unlink($main::tmpfile_sym);
- unlink(keys %main::tempnames);
-
- # We leave any collected profiles in $HOME/jeprof in case the user wants
- # to look at them later. We print a message informing them of this.
- if ((scalar(@main::profile_files) > 0) &&
- defined($main::collected_profile)) {
- if (scalar(@main::profile_files) == 1) {
- print STDERR "Dynamically gathered profile is in $main::collected_profile\n";
- }
- print STDERR "If you want to investigate this profile further, you can do:\n";
- print STDERR "\n";
- print STDERR " jeprof \\\n";
- print STDERR " $main::prog \\\n";
- print STDERR " $main::collected_profile\n";
- print STDERR "\n";
- }
-}
-
-sub sighandler {
- cleanup();
- exit(1);
-}
-
-sub error {
- my $msg = shift;
- print STDERR $msg;
- cleanup();
- exit(1);
-}
-
-
-# Run $nm_command and get all the resulting procedure boundaries whose
-# names match "$regexp" and returns them in a hashtable mapping from
-# procedure name to a two-element vector of [start address, end address]
-sub GetProcedureBoundariesViaNm {
- my $escaped_nm_command = shift; # shell-escaped
- my $regexp = shift;
-
- my $symbol_table = {};
- open(NM, "$escaped_nm_command |") || error("$escaped_nm_command: $!\n");
- my $last_start = "0";
- my $routine = "";
- while (<NM>) {
- s/\r//g; # turn windows-looking lines into unix-looking lines
- if (m/^\s*([0-9a-f]+) (.) (..*)/) {
- my $start_val = $1;
- my $type = $2;
- my $this_routine = $3;
-
- # It's possible for two symbols to share the same address, if
- # one is a zero-length variable (like __start_google_malloc) or
- # one symbol is a weak alias to another (like __libc_malloc).
- # In such cases, we want to ignore all values except for the
- # actual symbol, which in nm-speak has type "T". The logic
- # below does this, though it's a bit tricky: what happens when
- # we have a series of lines with the same address, is the first
- # one gets queued up to be processed. However, it won't
- # *actually* be processed until later, when we read a line with
- # a different address. That means that as long as we're reading
- # lines with the same address, we have a chance to replace that
- # item in the queue, which we do whenever we see a 'T' entry --
- # that is, a line with type 'T'. If we never see a 'T' entry,
- # we'll just go ahead and process the first entry (which never
- # got touched in the queue), and ignore the others.
- if ($start_val eq $last_start && $type =~ /t/i) {
- # We are the 'T' symbol at this address, replace previous symbol.
- $routine = $this_routine;
- next;
- } elsif ($start_val eq $last_start) {
- # We're not the 'T' symbol at this address, so ignore us.
- next;
- }
-
- if ($this_routine eq $sep_symbol) {
- $sep_address = HexExtend($start_val);
- }
-
- # Tag this routine with the starting address in case the image
- # has multiple occurrences of this routine. We use a syntax
- # that resembles template parameters that are automatically
- # stripped out by ShortFunctionName()
- $this_routine .= "<$start_val>";
-
- if (defined($routine) && $routine =~ m/$regexp/) {
- $symbol_table->{$routine} = [HexExtend($last_start),
- HexExtend($start_val)];
- }
- $last_start = $start_val;
- $routine = $this_routine;
- } elsif (m/^Loaded image name: (.+)/) {
- # The win32 nm workalike emits information about the binary it is using.
- if ($main::opt_debug) { print STDERR "Using Image $1\n"; }
- } elsif (m/^PDB file name: (.+)/) {
- # The win32 nm workalike emits information about the pdb it is using.
- if ($main::opt_debug) { print STDERR "Using PDB $1\n"; }
- }
- }
- close(NM);
- # Handle the last line in the nm output. Unfortunately, we don't know
- # how big this last symbol is, because we don't know how big the file
- # is. For now, we just give it a size of 0.
- # TODO(csilvers): do better here.
- if (defined($routine) && $routine =~ m/$regexp/) {
- $symbol_table->{$routine} = [HexExtend($last_start),
- HexExtend($last_start)];
- }
- return $symbol_table;
-}
-
-# Gets the procedure boundaries for all routines in "$image" whose names
-# match "$regexp" and returns them in a hashtable mapping from procedure
-# name to a two-element vector of [start address, end address].
-# Will return an empty map if nm is not installed or not working properly.
-sub GetProcedureBoundaries {
- my $image = shift;
- my $regexp = shift;
-
- # If $image doesn't start with /, then put ./ in front of it. This works
- # around an obnoxious bug in our probing of nm -f behavior.
- # "nm -f $image" is supposed to fail on GNU nm, but if:
- #
- # a. $image starts with [BbSsPp] (for example, bin/foo/bar), AND
- # b. you have a.out in your current directory (a not uncommon occurence)
- #
- # then "nm -f $image" succeeds because -f only looks at the first letter of
- # the argument, which looks valid because it's [BbSsPp], and then since
- # there's no image provided, it looks for a.out and finds it.
- #
- # This regex makes sure that $image starts with . or /, forcing the -f
- # parsing to fail since . and / are not valid formats.
- $image =~ s#^[^/]#./$&#;
-
- # For libc libraries, the copy in /usr/lib/debug contains debugging symbols
- my $debugging = DebuggingLibrary($image);
- if ($debugging) {
- $image = $debugging;
- }
-
- my $nm = $obj_tool_map{"nm"};
- my $cppfilt = $obj_tool_map{"c++filt"};
-
- # nm can fail for two reasons: 1) $image isn't a debug library; 2) nm
- # binary doesn't support --demangle. In addition, for OS X we need
- # to use the -f flag to get 'flat' nm output (otherwise we don't sort
- # properly and get incorrect results). Unfortunately, GNU nm uses -f
- # in an incompatible way. So first we test whether our nm supports
- # --demangle and -f.
- my $demangle_flag = "";
- my $cppfilt_flag = "";
- my $to_devnull = ">$dev_null 2>&1";
- if (system(ShellEscape($nm, "--demangle", $image) . $to_devnull) == 0) {
- # In this mode, we do "nm --demangle <foo>"
- $demangle_flag = "--demangle";
- $cppfilt_flag = "";
- } elsif (system(ShellEscape($cppfilt, $image) . $to_devnull) == 0) {
- # In this mode, we do "nm <foo> | c++filt"
- $cppfilt_flag = " | " . ShellEscape($cppfilt);
- };
- my $flatten_flag = "";
- if (system(ShellEscape($nm, "-f", $image) . $to_devnull) == 0) {
- $flatten_flag = "-f";
- }
-
- # Finally, in the case $imagie isn't a debug library, we try again with
- # -D to at least get *exported* symbols. If we can't use --demangle,
- # we use c++filt instead, if it exists on this system.
- my @nm_commands = (ShellEscape($nm, "-n", $flatten_flag, $demangle_flag,
- $image) . " 2>$dev_null $cppfilt_flag",
- ShellEscape($nm, "-D", "-n", $flatten_flag, $demangle_flag,
- $image) . " 2>$dev_null $cppfilt_flag",
- # 6nm is for Go binaries
- ShellEscape("6nm", "$image") . " 2>$dev_null | sort",
- );
-
- # If the executable is an MS Windows PDB-format executable, we'll
- # have set up obj_tool_map("nm_pdb"). In this case, we actually
- # want to use both unix nm and windows-specific nm_pdb, since
- # PDB-format executables can apparently include dwarf .o files.
- if (exists $obj_tool_map{"nm_pdb"}) {
- push(@nm_commands,
- ShellEscape($obj_tool_map{"nm_pdb"}, "--demangle", $image)
- . " 2>$dev_null");
- }
-
- foreach my $nm_command (@nm_commands) {
- my $symbol_table = GetProcedureBoundariesViaNm($nm_command, $regexp);
- return $symbol_table if (%{$symbol_table});
- }
- my $symbol_table = {};
- return $symbol_table;
-}
-
-
-# The test vectors for AddressAdd/Sub/Inc are 8-16-nibble hex strings.
-# To make them more readable, we add underscores at interesting places.
-# This routine removes the underscores, producing the canonical representation
-# used by jeprof to represent addresses, particularly in the tested routines.
-sub CanonicalHex {
- my $arg = shift;
- return join '', (split '_',$arg);
-}
-
-
-# Unit test for AddressAdd:
-sub AddressAddUnitTest {
- my $test_data_8 = shift;
- my $test_data_16 = shift;
- my $error_count = 0;
- my $fail_count = 0;
- my $pass_count = 0;
- # print STDERR "AddressAddUnitTest: ", 1+$#{$test_data_8}, " tests\n";
-
- # First a few 8-nibble addresses. Note that this implementation uses
- # plain old arithmetic, so a quick sanity check along with verifying what
- # happens to overflow (we want it to wrap):
- $address_length = 8;
- foreach my $row (@{$test_data_8}) {
- if ($main::opt_debug and $main::opt_test) { print STDERR "@{$row}\n"; }
- my $sum = AddressAdd ($row->[0], $row->[1]);
- if ($sum ne $row->[2]) {
- printf STDERR "ERROR: %s != %s + %s = %s\n", $sum,
- $row->[0], $row->[1], $row->[2];
- ++$fail_count;
- } else {
- ++$pass_count;
- }
- }
- printf STDERR "AddressAdd 32-bit tests: %d passes, %d failures\n",
- $pass_count, $fail_count;
- $error_count = $fail_count;
- $fail_count = 0;
- $pass_count = 0;
-
- # Now 16-nibble addresses.
- $address_length = 16;
- foreach my $row (@{$test_data_16}) {
- if ($main::opt_debug and $main::opt_test) { print STDERR "@{$row}\n"; }
- my $sum = AddressAdd (CanonicalHex($row->[0]), CanonicalHex($row->[1]));
- my $expected = join '', (split '_',$row->[2]);
- if ($sum ne CanonicalHex($row->[2])) {
- printf STDERR "ERROR: %s != %s + %s = %s\n", $sum,
- $row->[0], $row->[1], $row->[2];
- ++$fail_count;
- } else {
- ++$pass_count;
- }
- }
- printf STDERR "AddressAdd 64-bit tests: %d passes, %d failures\n",
- $pass_count, $fail_count;
- $error_count += $fail_count;
-
- return $error_count;
-}
-
-
-# Unit test for AddressSub:
-sub AddressSubUnitTest {
- my $test_data_8 = shift;
- my $test_data_16 = shift;
- my $error_count = 0;
- my $fail_count = 0;
- my $pass_count = 0;
- # print STDERR "AddressSubUnitTest: ", 1+$#{$test_data_8}, " tests\n";
-
- # First a few 8-nibble addresses. Note that this implementation uses
- # plain old arithmetic, so a quick sanity check along with verifying what
- # happens to overflow (we want it to wrap):
- $address_length = 8;
- foreach my $row (@{$test_data_8}) {
- if ($main::opt_debug and $main::opt_test) { print STDERR "@{$row}\n"; }
- my $sum = AddressSub ($row->[0], $row->[1]);
- if ($sum ne $row->[3]) {
- printf STDERR "ERROR: %s != %s - %s = %s\n", $sum,
- $row->[0], $row->[1], $row->[3];
- ++$fail_count;
- } else {
- ++$pass_count;
- }
- }
- printf STDERR "AddressSub 32-bit tests: %d passes, %d failures\n",
- $pass_count, $fail_count;
- $error_count = $fail_count;
- $fail_count = 0;
- $pass_count = 0;
-
- # Now 16-nibble addresses.
- $address_length = 16;
- foreach my $row (@{$test_data_16}) {
- if ($main::opt_debug and $main::opt_test) { print STDERR "@{$row}\n"; }
- my $sum = AddressSub (CanonicalHex($row->[0]), CanonicalHex($row->[1]));
- if ($sum ne CanonicalHex($row->[3])) {
- printf STDERR "ERROR: %s != %s - %s = %s\n", $sum,
- $row->[0], $row->[1], $row->[3];
- ++$fail_count;
- } else {
- ++$pass_count;
- }
- }
- printf STDERR "AddressSub 64-bit tests: %d passes, %d failures\n",
- $pass_count, $fail_count;
- $error_count += $fail_count;
-
- return $error_count;
-}
-
-
-# Unit test for AddressInc:
-sub AddressIncUnitTest {
- my $test_data_8 = shift;
- my $test_data_16 = shift;
- my $error_count = 0;
- my $fail_count = 0;
- my $pass_count = 0;
- # print STDERR "AddressIncUnitTest: ", 1+$#{$test_data_8}, " tests\n";
-
- # First a few 8-nibble addresses. Note that this implementation uses
- # plain old arithmetic, so a quick sanity check along with verifying what
- # happens to overflow (we want it to wrap):
- $address_length = 8;
- foreach my $row (@{$test_data_8}) {
- if ($main::opt_debug and $main::opt_test) { print STDERR "@{$row}\n"; }
- my $sum = AddressInc ($row->[0]);
- if ($sum ne $row->[4]) {
- printf STDERR "ERROR: %s != %s + 1 = %s\n", $sum,
- $row->[0], $row->[4];
- ++$fail_count;
- } else {
- ++$pass_count;
- }
- }
- printf STDERR "AddressInc 32-bit tests: %d passes, %d failures\n",
- $pass_count, $fail_count;
- $error_count = $fail_count;
- $fail_count = 0;
- $pass_count = 0;
-
- # Now 16-nibble addresses.
- $address_length = 16;
- foreach my $row (@{$test_data_16}) {
- if ($main::opt_debug and $main::opt_test) { print STDERR "@{$row}\n"; }
- my $sum = AddressInc (CanonicalHex($row->[0]));
- if ($sum ne CanonicalHex($row->[4])) {
- printf STDERR "ERROR: %s != %s + 1 = %s\n", $sum,
- $row->[0], $row->[4];
- ++$fail_count;
- } else {
- ++$pass_count;
- }
- }
- printf STDERR "AddressInc 64-bit tests: %d passes, %d failures\n",
- $pass_count, $fail_count;
- $error_count += $fail_count;
-
- return $error_count;
-}
-
-
-# Driver for unit tests.
-# Currently just the address add/subtract/increment routines for 64-bit.
-sub RunUnitTests {
- my $error_count = 0;
-
- # This is a list of tuples [a, b, a+b, a-b, a+1]
- my $unit_test_data_8 = [
- [qw(aaaaaaaa 50505050 fafafafa 5a5a5a5a aaaaaaab)],
- [qw(50505050 aaaaaaaa fafafafa a5a5a5a6 50505051)],
- [qw(ffffffff aaaaaaaa aaaaaaa9 55555555 00000000)],
- [qw(00000001 ffffffff 00000000 00000002 00000002)],
- [qw(00000001 fffffff0 fffffff1 00000011 00000002)],
- ];
- my $unit_test_data_16 = [
- # The implementation handles data in 7-nibble chunks, so those are the
- # interesting boundaries.
- [qw(aaaaaaaa 50505050
- 00_000000f_afafafa 00_0000005_a5a5a5a 00_000000a_aaaaaab)],
- [qw(50505050 aaaaaaaa
- 00_000000f_afafafa ff_ffffffa_5a5a5a6 00_0000005_0505051)],
- [qw(ffffffff aaaaaaaa
- 00_000001a_aaaaaa9 00_0000005_5555555 00_0000010_0000000)],
- [qw(00000001 ffffffff
- 00_0000010_0000000 ff_ffffff0_0000002 00_0000000_0000002)],
- [qw(00000001 fffffff0
- 00_000000f_ffffff1 ff_ffffff0_0000011 00_0000000_0000002)],
-
- [qw(00_a00000a_aaaaaaa 50505050
- 00_a00000f_afafafa 00_a000005_a5a5a5a 00_a00000a_aaaaaab)],
- [qw(0f_fff0005_0505050 aaaaaaaa
- 0f_fff000f_afafafa 0f_ffefffa_5a5a5a6 0f_fff0005_0505051)],
- [qw(00_000000f_fffffff 01_800000a_aaaaaaa
- 01_800001a_aaaaaa9 fe_8000005_5555555 00_0000010_0000000)],
- [qw(00_0000000_0000001 ff_fffffff_fffffff
- 00_0000000_0000000 00_0000000_0000002 00_0000000_0000002)],
- [qw(00_0000000_0000001 ff_fffffff_ffffff0
- ff_fffffff_ffffff1 00_0000000_0000011 00_0000000_0000002)],
- ];
-
- $error_count += AddressAddUnitTest($unit_test_data_8, $unit_test_data_16);
- $error_count += AddressSubUnitTest($unit_test_data_8, $unit_test_data_16);
- $error_count += AddressIncUnitTest($unit_test_data_8, $unit_test_data_16);
- if ($error_count > 0) {
- print STDERR $error_count, " errors: FAILED\n";
- } else {
- print STDERR "PASS\n";
- }
- exit ($error_count);
-}
->>>>>>> main
diff --git a/contrib/jemalloc/build-aux/config.guess b/contrib/jemalloc/build-aux/config.guess
index e8241c60f184..f7727026b706 100755
--- a/contrib/jemalloc/build-aux/config.guess
+++ b/contrib/jemalloc/build-aux/config.guess
@@ -1,4 +1,3 @@
-<<<<<<< HEAD
#! /bin/sh
# Attempt to guess a canonical system name.
# Copyright 1992-2021 Free Software Foundation, Inc.
@@ -1700,1468 +1699,3 @@ exit 1
# time-stamp-format: "%:y-%02m-%02d"
# time-stamp-end: "'"
# End:
-||||||| dec341af7695
-=======
-#! /bin/sh
-# Attempt to guess a canonical system name.
-# Copyright 1992-2016 Free Software Foundation, Inc.
-
-timestamp='2016-10-02'
-
-# This file is free software; you can redistribute it and/or modify it
-# under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, see <http://www.gnu.org/licenses/>.
-#
-# As a special exception to the GNU General Public License, if you
-# distribute this file as part of a program that contains a
-# configuration script generated by Autoconf, you may include it under
-# the same distribution terms that you use for the rest of that
-# program. This Exception is an additional permission under section 7
-# of the GNU General Public License, version 3 ("GPLv3").
-#
-# Originally written by Per Bothner; maintained since 2000 by Ben Elliston.
-#
-# You can get the latest version of this script from:
-# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess
-#
-# Please send patches to <config-patches@gnu.org>.
-
-
-me=`echo "$0" | sed -e 's,.*/,,'`
-
-usage="\
-Usage: $0 [OPTION]
-
-Output the configuration name of the system \`$me' is run on.
-
-Operation modes:
- -h, --help print this help, then exit
- -t, --time-stamp print date of last modification, then exit
- -v, --version print version number, then exit
-
-Report bugs and patches to <config-patches@gnu.org>."
-
-version="\
-GNU config.guess ($timestamp)
-
-Originally written by Per Bothner.
-Copyright 1992-2016 Free Software Foundation, Inc.
-
-This is free software; see the source for copying conditions. There is NO
-warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
-
-help="
-Try \`$me --help' for more information."
-
-# Parse command line
-while test $# -gt 0 ; do
- case $1 in
- --time-stamp | --time* | -t )
- echo "$timestamp" ; exit ;;
- --version | -v )
- echo "$version" ; exit ;;
- --help | --h* | -h )
- echo "$usage"; exit ;;
- -- ) # Stop option processing
- shift; break ;;
- - ) # Use stdin as input.
- break ;;
- -* )
- echo "$me: invalid option $1$help" >&2
- exit 1 ;;
- * )
- break ;;
- esac
-done
-
-if test $# != 0; then
- echo "$me: too many arguments$help" >&2
- exit 1
-fi
-
-trap 'exit 1' 1 2 15
-
-# CC_FOR_BUILD -- compiler used by this script. Note that the use of a
-# compiler to aid in system detection is discouraged as it requires
-# temporary files to be created and, as you can see below, it is a
-# headache to deal with in a portable fashion.
-
-# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
-# use `HOST_CC' if defined, but it is deprecated.
-
-# Portable tmp directory creation inspired by the Autoconf team.
-
-set_cc_for_build='
-trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ;
-trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ;
-: ${TMPDIR=/tmp} ;
- { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
- { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } ||
- { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } ||
- { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ;
-dummy=$tmp/dummy ;
-tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ;
-case $CC_FOR_BUILD,$HOST_CC,$CC in
- ,,) echo "int x;" > $dummy.c ;
- for c in cc gcc c89 c99 ; do
- if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then
- CC_FOR_BUILD="$c"; break ;
- fi ;
- done ;
- if test x"$CC_FOR_BUILD" = x ; then
- CC_FOR_BUILD=no_compiler_found ;
- fi
- ;;
- ,,*) CC_FOR_BUILD=$CC ;;
- ,*,*) CC_FOR_BUILD=$HOST_CC ;;
-esac ; set_cc_for_build= ;'
-
-# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
-# (ghazi@noc.rutgers.edu 1994-08-24)
-if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
- PATH=$PATH:/.attbin ; export PATH
-fi
-
-UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
-UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
-UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown
-UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
-
-case "${UNAME_SYSTEM}" in
-Linux|GNU|GNU/*)
- # If the system lacks a compiler, then just pick glibc.
- # We could probably try harder.
- LIBC=gnu
-
- eval $set_cc_for_build
- cat <<-EOF > $dummy.c
- #include <features.h>
- #if defined(__UCLIBC__)
- LIBC=uclibc
- #elif defined(__dietlibc__)
- LIBC=dietlibc
- #else
- LIBC=gnu
- #endif
- EOF
- eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC' | sed 's, ,,g'`
- ;;
-esac
-
-# Note: order is significant - the case branches are not exclusive.
-
-case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
- *:NetBSD:*:*)
- # NetBSD (nbsd) targets should (where applicable) match one or
- # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*,
- # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently
- # switched to ELF, *-*-netbsd* would select the old
- # object file format. This provides both forward
- # compatibility and a consistent mechanism for selecting the
- # object file format.
- #
- # Note: NetBSD doesn't particularly care about the vendor
- # portion of the name. We always set it to "unknown".
- sysctl="sysctl -n hw.machine_arch"
- UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \
- /sbin/$sysctl 2>/dev/null || \
- /usr/sbin/$sysctl 2>/dev/null || \
- echo unknown)`
- case "${UNAME_MACHINE_ARCH}" in
- armeb) machine=armeb-unknown ;;
- arm*) machine=arm-unknown ;;
- sh3el) machine=shl-unknown ;;
- sh3eb) machine=sh-unknown ;;
- sh5el) machine=sh5le-unknown ;;
- earmv*)
- arch=`echo ${UNAME_MACHINE_ARCH} | sed -e 's,^e\(armv[0-9]\).*$,\1,'`
- endian=`echo ${UNAME_MACHINE_ARCH} | sed -ne 's,^.*\(eb\)$,\1,p'`
- machine=${arch}${endian}-unknown
- ;;
- *) machine=${UNAME_MACHINE_ARCH}-unknown ;;
- esac
- # The Operating System including object format, if it has switched
- # to ELF recently (or will in the future) and ABI.
- case "${UNAME_MACHINE_ARCH}" in
- earm*)
- os=netbsdelf
- ;;
- arm*|i386|m68k|ns32k|sh3*|sparc|vax)
- eval $set_cc_for_build
- if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
- | grep -q __ELF__
- then
- # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
- # Return netbsd for either. FIX?
- os=netbsd
- else
- os=netbsdelf
- fi
- ;;
- *)
- os=netbsd
- ;;
- esac
- # Determine ABI tags.
- case "${UNAME_MACHINE_ARCH}" in
- earm*)
- expr='s/^earmv[0-9]/-eabi/;s/eb$//'
- abi=`echo ${UNAME_MACHINE_ARCH} | sed -e "$expr"`
- ;;
- esac
- # The OS release
- # Debian GNU/NetBSD machines have a different userland, and
- # thus, need a distinct triplet. However, they do not need
- # kernel version information, so it can be replaced with a
- # suitable tag, in the style of linux-gnu.
- case "${UNAME_VERSION}" in
- Debian*)
- release='-gnu'
- ;;
- *)
- release=`echo ${UNAME_RELEASE} | sed -e 's/[-_].*//' | cut -d. -f1,2`
- ;;
- esac
- # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
- # contains redundant information, the shorter form:
- # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
- echo "${machine}-${os}${release}${abi}"
- exit ;;
- *:Bitrig:*:*)
- UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'`
- echo ${UNAME_MACHINE_ARCH}-unknown-bitrig${UNAME_RELEASE}
- exit ;;
- *:OpenBSD:*:*)
- UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
- echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE}
- exit ;;
- *:LibertyBSD:*:*)
- UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'`
- echo ${UNAME_MACHINE_ARCH}-unknown-libertybsd${UNAME_RELEASE}
- exit ;;
- *:ekkoBSD:*:*)
- echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE}
- exit ;;
- *:SolidBSD:*:*)
- echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE}
- exit ;;
- macppc:MirBSD:*:*)
- echo powerpc-unknown-mirbsd${UNAME_RELEASE}
- exit ;;
- *:MirBSD:*:*)
- echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE}
- exit ;;
- *:Sortix:*:*)
- echo ${UNAME_MACHINE}-unknown-sortix
- exit ;;
- alpha:OSF1:*:*)
- case $UNAME_RELEASE in
- *4.0)
- UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
- ;;
- *5.*)
- UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'`
- ;;
- esac
- # According to Compaq, /usr/sbin/psrinfo has been available on
- # OSF/1 and Tru64 systems produced since 1995. I hope that
- # covers most systems running today. This code pipes the CPU
- # types through head -n 1, so we only detect the type of CPU 0.
- ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1`
- case "$ALPHA_CPU_TYPE" in
- "EV4 (21064)")
- UNAME_MACHINE=alpha ;;
- "EV4.5 (21064)")
- UNAME_MACHINE=alpha ;;
- "LCA4 (21066/21068)")
- UNAME_MACHINE=alpha ;;
- "EV5 (21164)")
- UNAME_MACHINE=alphaev5 ;;
- "EV5.6 (21164A)")
- UNAME_MACHINE=alphaev56 ;;
- "EV5.6 (21164PC)")
- UNAME_MACHINE=alphapca56 ;;
- "EV5.7 (21164PC)")
- UNAME_MACHINE=alphapca57 ;;
- "EV6 (21264)")
- UNAME_MACHINE=alphaev6 ;;
- "EV6.7 (21264A)")
- UNAME_MACHINE=alphaev67 ;;
- "EV6.8CB (21264C)")
- UNAME_MACHINE=alphaev68 ;;
- "EV6.8AL (21264B)")
- UNAME_MACHINE=alphaev68 ;;
- "EV6.8CX (21264D)")
- UNAME_MACHINE=alphaev68 ;;
- "EV6.9A (21264/EV69A)")
- UNAME_MACHINE=alphaev69 ;;
- "EV7 (21364)")
- UNAME_MACHINE=alphaev7 ;;
- "EV7.9 (21364A)")
- UNAME_MACHINE=alphaev79 ;;
- esac
- # A Pn.n version is a patched version.
- # A Vn.n version is a released version.
- # A Tn.n version is a released field test version.
- # A Xn.n version is an unreleased experimental baselevel.
- # 1.2 uses "1.2" for uname -r.
- echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz`
- # Reset EXIT trap before exiting to avoid spurious non-zero exit code.
- exitcode=$?
- trap '' 0
- exit $exitcode ;;
- Alpha\ *:Windows_NT*:*)
- # How do we know it's Interix rather than the generic POSIX subsystem?
- # Should we change UNAME_MACHINE based on the output of uname instead
- # of the specific Alpha model?
- echo alpha-pc-interix
- exit ;;
- 21064:Windows_NT:50:3)
- echo alpha-dec-winnt3.5
- exit ;;
- Amiga*:UNIX_System_V:4.0:*)
- echo m68k-unknown-sysv4
- exit ;;
- *:[Aa]miga[Oo][Ss]:*:*)
- echo ${UNAME_MACHINE}-unknown-amigaos
- exit ;;
- *:[Mm]orph[Oo][Ss]:*:*)
- echo ${UNAME_MACHINE}-unknown-morphos
- exit ;;
- *:OS/390:*:*)
- echo i370-ibm-openedition
- exit ;;
- *:z/VM:*:*)
- echo s390-ibm-zvmoe
- exit ;;
- *:OS400:*:*)
- echo powerpc-ibm-os400
- exit ;;
- arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
- echo arm-acorn-riscix${UNAME_RELEASE}
- exit ;;
- arm*:riscos:*:*|arm*:RISCOS:*:*)
- echo arm-unknown-riscos
- exit ;;
- SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
- echo hppa1.1-hitachi-hiuxmpp
- exit ;;
- Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
- # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
- if test "`(/bin/universe) 2>/dev/null`" = att ; then
- echo pyramid-pyramid-sysv3
- else
- echo pyramid-pyramid-bsd
- fi
- exit ;;
- NILE*:*:*:dcosx)
- echo pyramid-pyramid-svr4
- exit ;;
- DRS?6000:unix:4.0:6*)
- echo sparc-icl-nx6
- exit ;;
- DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*)
- case `/usr/bin/uname -p` in
- sparc) echo sparc-icl-nx7; exit ;;
- esac ;;
- s390x:SunOS:*:*)
- echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
- exit ;;
- sun4H:SunOS:5.*:*)
- echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
- exit ;;
- sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
- echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
- exit ;;
- i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*)
- echo i386-pc-auroraux${UNAME_RELEASE}
- exit ;;
- i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*)
- eval $set_cc_for_build
- SUN_ARCH=i386
- # If there is a compiler, see if it is configured for 64-bit objects.
- # Note that the Sun cc does not turn __LP64__ into 1 like gcc does.
- # This test works for both compilers.
- if [ "$CC_FOR_BUILD" != no_compiler_found ]; then
- if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \
- (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
- grep IS_64BIT_ARCH >/dev/null
- then
- SUN_ARCH=x86_64
- fi
- fi
- echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
- exit ;;
- sun4*:SunOS:6*:*)
- # According to config.sub, this is the proper way to canonicalize
- # SunOS6. Hard to guess exactly what SunOS6 will be like, but
- # it's likely to be more like Solaris than SunOS4.
- echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
- exit ;;
- sun4*:SunOS:*:*)
- case "`/usr/bin/arch -k`" in
- Series*|S4*)
- UNAME_RELEASE=`uname -v`
- ;;
- esac
- # Japanese Language versions have a version number like `4.1.3-JL'.
- echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
- exit ;;
- sun3*:SunOS:*:*)
- echo m68k-sun-sunos${UNAME_RELEASE}
- exit ;;
- sun*:*:4.2BSD:*)
- UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
- test "x${UNAME_RELEASE}" = x && UNAME_RELEASE=3
- case "`/bin/arch`" in
- sun3)
- echo m68k-sun-sunos${UNAME_RELEASE}
- ;;
- sun4)
- echo sparc-sun-sunos${UNAME_RELEASE}
- ;;
- esac
- exit ;;
- aushp:SunOS:*:*)
- echo sparc-auspex-sunos${UNAME_RELEASE}
- exit ;;
- # The situation for MiNT is a little confusing. The machine name
- # can be virtually everything (everything which is not
- # "atarist" or "atariste" at least should have a processor
- # > m68000). The system name ranges from "MiNT" over "FreeMiNT"
- # to the lowercase version "mint" (or "freemint"). Finally
- # the system name "TOS" denotes a system which is actually not
- # MiNT. But MiNT is downward compatible to TOS, so this should
- # be no problem.
- atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
- echo m68k-atari-mint${UNAME_RELEASE}
- exit ;;
- atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
- echo m68k-atari-mint${UNAME_RELEASE}
- exit ;;
- *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
- echo m68k-atari-mint${UNAME_RELEASE}
- exit ;;
- milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
- echo m68k-milan-mint${UNAME_RELEASE}
- exit ;;
- hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
- echo m68k-hades-mint${UNAME_RELEASE}
- exit ;;
- *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
- echo m68k-unknown-mint${UNAME_RELEASE}
- exit ;;
- m68k:machten:*:*)
- echo m68k-apple-machten${UNAME_RELEASE}
- exit ;;
- powerpc:machten:*:*)
- echo powerpc-apple-machten${UNAME_RELEASE}
- exit ;;
- RISC*:Mach:*:*)
- echo mips-dec-mach_bsd4.3
- exit ;;
- RISC*:ULTRIX:*:*)
- echo mips-dec-ultrix${UNAME_RELEASE}
- exit ;;
- VAX*:ULTRIX*:*:*)
- echo vax-dec-ultrix${UNAME_RELEASE}
- exit ;;
- 2020:CLIX:*:* | 2430:CLIX:*:*)
- echo clipper-intergraph-clix${UNAME_RELEASE}
- exit ;;
- mips:*:*:UMIPS | mips:*:*:RISCos)
- eval $set_cc_for_build
- sed 's/^ //' << EOF >$dummy.c
-#ifdef __cplusplus
-#include <stdio.h> /* for printf() prototype */
- int main (int argc, char *argv[]) {
-#else
- int main (argc, argv) int argc; char *argv[]; {
-#endif
- #if defined (host_mips) && defined (MIPSEB)
- #if defined (SYSTYPE_SYSV)
- printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
- #endif
- #if defined (SYSTYPE_SVR4)
- printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
- #endif
- #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
- printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
- #endif
- #endif
- exit (-1);
- }
-EOF
- $CC_FOR_BUILD -o $dummy $dummy.c &&
- dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` &&
- SYSTEM_NAME=`$dummy $dummyarg` &&
- { echo "$SYSTEM_NAME"; exit; }
- echo mips-mips-riscos${UNAME_RELEASE}
- exit ;;
- Motorola:PowerMAX_OS:*:*)
- echo powerpc-motorola-powermax
- exit ;;
- Motorola:*:4.3:PL8-*)
- echo powerpc-harris-powermax
- exit ;;
- Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*)
- echo powerpc-harris-powermax
- exit ;;
- Night_Hawk:Power_UNIX:*:*)
- echo powerpc-harris-powerunix
- exit ;;
- m88k:CX/UX:7*:*)
- echo m88k-harris-cxux7
- exit ;;
- m88k:*:4*:R4*)
- echo m88k-motorola-sysv4
- exit ;;
- m88k:*:3*:R3*)
- echo m88k-motorola-sysv3
- exit ;;
- AViiON:dgux:*:*)
- # DG/UX returns AViiON for all architectures
- UNAME_PROCESSOR=`/usr/bin/uname -p`
- if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]
- then
- if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
- [ ${TARGET_BINARY_INTERFACE}x = x ]
- then
- echo m88k-dg-dgux${UNAME_RELEASE}
- else
- echo m88k-dg-dguxbcs${UNAME_RELEASE}
- fi
- else
- echo i586-dg-dgux${UNAME_RELEASE}
- fi
- exit ;;
- M88*:DolphinOS:*:*) # DolphinOS (SVR3)
- echo m88k-dolphin-sysv3
- exit ;;
- M88*:*:R3*:*)
- # Delta 88k system running SVR3
- echo m88k-motorola-sysv3
- exit ;;
- XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
- echo m88k-tektronix-sysv3
- exit ;;
- Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
- echo m68k-tektronix-bsd
- exit ;;
- *:IRIX*:*:*)
- echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
- exit ;;
- ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
- echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id
- exit ;; # Note that: echo "'`uname -s`'" gives 'AIX '
- i*86:AIX:*:*)
- echo i386-ibm-aix
- exit ;;
- ia64:AIX:*:*)
- if [ -x /usr/bin/oslevel ] ; then
- IBM_REV=`/usr/bin/oslevel`
- else
- IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
- fi
- echo ${UNAME_MACHINE}-ibm-aix${IBM_REV}
- exit ;;
- *:AIX:2:3)
- if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
- eval $set_cc_for_build
- sed 's/^ //' << EOF >$dummy.c
- #include <sys/systemcfg.h>
-
- main()
- {
- if (!__power_pc())
- exit(1);
- puts("powerpc-ibm-aix3.2.5");
- exit(0);
- }
-EOF
- if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy`
- then
- echo "$SYSTEM_NAME"
- else
- echo rs6000-ibm-aix3.2.5
- fi
- elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
- echo rs6000-ibm-aix3.2.4
- else
- echo rs6000-ibm-aix3.2
- fi
- exit ;;
- *:AIX:*:[4567])
- IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
- if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then
- IBM_ARCH=rs6000
- else
- IBM_ARCH=powerpc
- fi
- if [ -x /usr/bin/lslpp ] ; then
- IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc |
- awk -F: '{ print $3 }' | sed s/[0-9]*$/0/`
- else
- IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
- fi
- echo ${IBM_ARCH}-ibm-aix${IBM_REV}
- exit ;;
- *:AIX:*:*)
- echo rs6000-ibm-aix
- exit ;;
- ibmrt:4.4BSD:*|romp-ibm:BSD:*)
- echo romp-ibm-bsd4.4
- exit ;;
- ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and
- echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to
- exit ;; # report: romp-ibm BSD 4.3
- *:BOSX:*:*)
- echo rs6000-bull-bosx
- exit ;;
- DPX/2?00:B.O.S.:*:*)
- echo m68k-bull-sysv3
- exit ;;
- 9000/[34]??:4.3bsd:1.*:*)
- echo m68k-hp-bsd
- exit ;;
- hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
- echo m68k-hp-bsd4.4
- exit ;;
- 9000/[34678]??:HP-UX:*:*)
- HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
- case "${UNAME_MACHINE}" in
- 9000/31? ) HP_ARCH=m68000 ;;
- 9000/[34]?? ) HP_ARCH=m68k ;;
- 9000/[678][0-9][0-9])
- if [ -x /usr/bin/getconf ]; then
- sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
- sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
- case "${sc_cpu_version}" in
- 523) HP_ARCH=hppa1.0 ;; # CPU_PA_RISC1_0
- 528) HP_ARCH=hppa1.1 ;; # CPU_PA_RISC1_1
- 532) # CPU_PA_RISC2_0
- case "${sc_kernel_bits}" in
- 32) HP_ARCH=hppa2.0n ;;
- 64) HP_ARCH=hppa2.0w ;;
- '') HP_ARCH=hppa2.0 ;; # HP-UX 10.20
- esac ;;
- esac
- fi
- if [ "${HP_ARCH}" = "" ]; then
- eval $set_cc_for_build
- sed 's/^ //' << EOF >$dummy.c
-
- #define _HPUX_SOURCE
- #include <stdlib.h>
- #include <unistd.h>
-
- int main ()
- {
- #if defined(_SC_KERNEL_BITS)
- long bits = sysconf(_SC_KERNEL_BITS);
- #endif
- long cpu = sysconf (_SC_CPU_VERSION);
-
- switch (cpu)
- {
- case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
- case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
- case CPU_PA_RISC2_0:
- #if defined(_SC_KERNEL_BITS)
- switch (bits)
- {
- case 64: puts ("hppa2.0w"); break;
- case 32: puts ("hppa2.0n"); break;
- default: puts ("hppa2.0"); break;
- } break;
- #else /* !defined(_SC_KERNEL_BITS) */
- puts ("hppa2.0"); break;
- #endif
- default: puts ("hppa1.0"); break;
- }
- exit (0);
- }
-EOF
- (CCOPTS="" $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`
- test -z "$HP_ARCH" && HP_ARCH=hppa
- fi ;;
- esac
- if [ ${HP_ARCH} = hppa2.0w ]
- then
- eval $set_cc_for_build
-
- # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating
- # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler
- # generating 64-bit code. GNU and HP use different nomenclature:
- #
- # $ CC_FOR_BUILD=cc ./config.guess
- # => hppa2.0w-hp-hpux11.23
- # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess
- # => hppa64-hp-hpux11.23
-
- if echo __LP64__ | (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) |
- grep -q __LP64__
- then
- HP_ARCH=hppa2.0w
- else
- HP_ARCH=hppa64
- fi
- fi
- echo ${HP_ARCH}-hp-hpux${HPUX_REV}
- exit ;;
- ia64:HP-UX:*:*)
- HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
- echo ia64-hp-hpux${HPUX_REV}
- exit ;;
- 3050*:HI-UX:*:*)
- eval $set_cc_for_build
- sed 's/^ //' << EOF >$dummy.c
- #include <unistd.h>
- int
- main ()
- {
- long cpu = sysconf (_SC_CPU_VERSION);
- /* The order matters, because CPU_IS_HP_MC68K erroneously returns
- true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct
- results, however. */
- if (CPU_IS_PA_RISC (cpu))
- {
- switch (cpu)
- {
- case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
- case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
- case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
- default: puts ("hppa-hitachi-hiuxwe2"); break;
- }
- }
- else if (CPU_IS_HP_MC68K (cpu))
- puts ("m68k-hitachi-hiuxwe2");
- else puts ("unknown-hitachi-hiuxwe2");
- exit (0);
- }
-EOF
- $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` &&
- { echo "$SYSTEM_NAME"; exit; }
- echo unknown-hitachi-hiuxwe2
- exit ;;
- 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
- echo hppa1.1-hp-bsd
- exit ;;
- 9000/8??:4.3bsd:*:*)
- echo hppa1.0-hp-bsd
- exit ;;
- *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)
- echo hppa1.0-hp-mpeix
- exit ;;
- hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
- echo hppa1.1-hp-osf
- exit ;;
- hp8??:OSF1:*:*)
- echo hppa1.0-hp-osf
- exit ;;
- i*86:OSF1:*:*)
- if [ -x /usr/sbin/sysversion ] ; then
- echo ${UNAME_MACHINE}-unknown-osf1mk
- else
- echo ${UNAME_MACHINE}-unknown-osf1
- fi
- exit ;;
- parisc*:Lites*:*:*)
- echo hppa1.1-hp-lites
- exit ;;
- C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
- echo c1-convex-bsd
- exit ;;
- C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
- if getsysinfo -f scalar_acc
- then echo c32-convex-bsd
- else echo c2-convex-bsd
- fi
- exit ;;
- C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
- echo c34-convex-bsd
- exit ;;
- C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
- echo c38-convex-bsd
- exit ;;
- C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
- echo c4-convex-bsd
- exit ;;
- CRAY*Y-MP:*:*:*)
- echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
- exit ;;
- CRAY*[A-Z]90:*:*:*)
- echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
- | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
- -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \
- -e 's/\.[^.]*$/.X/'
- exit ;;
- CRAY*TS:*:*:*)
- echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
- exit ;;
- CRAY*T3E:*:*:*)
- echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
- exit ;;
- CRAY*SV1:*:*:*)
- echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
- exit ;;
- *:UNICOS/mp:*:*)
- echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
- exit ;;
- F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
- FUJITSU_PROC=`uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz`
- FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'`
- FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
- echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
- exit ;;
- 5000:UNIX_System_V:4.*:*)
- FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'`
- FUJITSU_REL=`echo ${UNAME_RELEASE} | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/'`
- echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
- exit ;;
- i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
- echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
- exit ;;
- sparc*:BSD/OS:*:*)
- echo sparc-unknown-bsdi${UNAME_RELEASE}
- exit ;;
- *:BSD/OS:*:*)
- echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
- exit ;;
- *:FreeBSD:*:*)
- UNAME_PROCESSOR=`/usr/bin/uname -p`
- case ${UNAME_PROCESSOR} in
- amd64)
- echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
- *)
- echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
- esac
- exit ;;
- i*:CYGWIN*:*)
- echo ${UNAME_MACHINE}-pc-cygwin
- exit ;;
- *:MINGW64*:*)
- echo ${UNAME_MACHINE}-pc-mingw64
- exit ;;
- *:MINGW*:*)
- echo ${UNAME_MACHINE}-pc-mingw32
- exit ;;
- *:MSYS*:*)
- echo ${UNAME_MACHINE}-pc-msys
- exit ;;
- i*:windows32*:*)
- # uname -m includes "-pc" on this system.
- echo ${UNAME_MACHINE}-mingw32
- exit ;;
- i*:PW*:*)
- echo ${UNAME_MACHINE}-pc-pw32
- exit ;;
- *:Interix*:*)
- case ${UNAME_MACHINE} in
- x86)
- echo i586-pc-interix${UNAME_RELEASE}
- exit ;;
- authenticamd | genuineintel | EM64T)
- echo x86_64-unknown-interix${UNAME_RELEASE}
- exit ;;
- IA64)
- echo ia64-unknown-interix${UNAME_RELEASE}
- exit ;;
- esac ;;
- [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*)
- echo i${UNAME_MACHINE}-pc-mks
- exit ;;
- 8664:Windows_NT:*)
- echo x86_64-pc-mks
- exit ;;
- i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
- # How do we know it's Interix rather than the generic POSIX subsystem?
- # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
- # UNAME_MACHINE based on the output of uname instead of i386?
- echo i586-pc-interix
- exit ;;
- i*:UWIN*:*)
- echo ${UNAME_MACHINE}-pc-uwin
- exit ;;
- amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*)
- echo x86_64-unknown-cygwin
- exit ;;
- p*:CYGWIN*:*)
- echo powerpcle-unknown-cygwin
- exit ;;
- prep*:SunOS:5.*:*)
- echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
- exit ;;
- *:GNU:*:*)
- # the GNU system
- echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-${LIBC}`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
- exit ;;
- *:GNU/*:*:*)
- # other systems with GNU libc and userland
- echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC}
- exit ;;
- i*86:Minix:*:*)
- echo ${UNAME_MACHINE}-pc-minix
- exit ;;
- aarch64:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
- exit ;;
- aarch64_be:Linux:*:*)
- UNAME_MACHINE=aarch64_be
- echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
- exit ;;
- alpha:Linux:*:*)
- case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
- EV5) UNAME_MACHINE=alphaev5 ;;
- EV56) UNAME_MACHINE=alphaev56 ;;
- PCA56) UNAME_MACHINE=alphapca56 ;;
- PCA57) UNAME_MACHINE=alphapca56 ;;
- EV6) UNAME_MACHINE=alphaev6 ;;
- EV67) UNAME_MACHINE=alphaev67 ;;
- EV68*) UNAME_MACHINE=alphaev68 ;;
- esac
- objdump --private-headers /bin/sh | grep -q ld.so.1
- if test "$?" = 0 ; then LIBC=gnulibc1 ; fi
- echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
- exit ;;
- arc:Linux:*:* | arceb:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
- exit ;;
- arm*:Linux:*:*)
- eval $set_cc_for_build
- if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \
- | grep -q __ARM_EABI__
- then
- echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
- else
- if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \
- | grep -q __ARM_PCS_VFP
- then
- echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabi
- else
- echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabihf
- fi
- fi
- exit ;;
- avr32*:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
- exit ;;
- cris:Linux:*:*)
- echo ${UNAME_MACHINE}-axis-linux-${LIBC}
- exit ;;
- crisv32:Linux:*:*)
- echo ${UNAME_MACHINE}-axis-linux-${LIBC}
- exit ;;
- e2k:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
- exit ;;
- frv:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
- exit ;;
- hexagon:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
- exit ;;
- i*86:Linux:*:*)
- echo ${UNAME_MACHINE}-pc-linux-${LIBC}
- exit ;;
- ia64:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
- exit ;;
- k1om:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
- exit ;;
- m32r*:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
- exit ;;
- m68*:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
- exit ;;
- mips:Linux:*:* | mips64:Linux:*:*)
- eval $set_cc_for_build
- sed 's/^ //' << EOF >$dummy.c
- #undef CPU
- #undef ${UNAME_MACHINE}
- #undef ${UNAME_MACHINE}el
- #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
- CPU=${UNAME_MACHINE}el
- #else
- #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
- CPU=${UNAME_MACHINE}
- #else
- CPU=
- #endif
- #endif
-EOF
- eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'`
- test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; }
- ;;
- mips64el:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
- exit ;;
- openrisc*:Linux:*:*)
- echo or1k-unknown-linux-${LIBC}
- exit ;;
- or32:Linux:*:* | or1k*:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
- exit ;;
- padre:Linux:*:*)
- echo sparc-unknown-linux-${LIBC}
- exit ;;
- parisc64:Linux:*:* | hppa64:Linux:*:*)
- echo hppa64-unknown-linux-${LIBC}
- exit ;;
- parisc:Linux:*:* | hppa:Linux:*:*)
- # Look for CPU level
- case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
- PA7*) echo hppa1.1-unknown-linux-${LIBC} ;;
- PA8*) echo hppa2.0-unknown-linux-${LIBC} ;;
- *) echo hppa-unknown-linux-${LIBC} ;;
- esac
- exit ;;
- ppc64:Linux:*:*)
- echo powerpc64-unknown-linux-${LIBC}
- exit ;;
- ppc:Linux:*:*)
- echo powerpc-unknown-linux-${LIBC}
- exit ;;
- ppc64le:Linux:*:*)
- echo powerpc64le-unknown-linux-${LIBC}
- exit ;;
- ppcle:Linux:*:*)
- echo powerpcle-unknown-linux-${LIBC}
- exit ;;
- riscv32:Linux:*:* | riscv64:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
- exit ;;
- s390:Linux:*:* | s390x:Linux:*:*)
- echo ${UNAME_MACHINE}-ibm-linux-${LIBC}
- exit ;;
- sh64*:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
- exit ;;
- sh*:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
- exit ;;
- sparc:Linux:*:* | sparc64:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
- exit ;;
- tile*:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
- exit ;;
- vax:Linux:*:*)
- echo ${UNAME_MACHINE}-dec-linux-${LIBC}
- exit ;;
- x86_64:Linux:*:*)
- echo ${UNAME_MACHINE}-pc-linux-${LIBC}
- exit ;;
- xtensa*:Linux:*:*)
- echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
- exit ;;
- i*86:DYNIX/ptx:4*:*)
- # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
- # earlier versions are messed up and put the nodename in both
- # sysname and nodename.
- echo i386-sequent-sysv4
- exit ;;
- i*86:UNIX_SV:4.2MP:2.*)
- # Unixware is an offshoot of SVR4, but it has its own version
- # number series starting with 2...
- # I am not positive that other SVR4 systems won't match this,
- # I just have to hope. -- rms.
- # Use sysv4.2uw... so that sysv4* matches it.
- echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
- exit ;;
- i*86:OS/2:*:*)
- # If we were able to find `uname', then EMX Unix compatibility
- # is probably installed.
- echo ${UNAME_MACHINE}-pc-os2-emx
- exit ;;
- i*86:XTS-300:*:STOP)
- echo ${UNAME_MACHINE}-unknown-stop
- exit ;;
- i*86:atheos:*:*)
- echo ${UNAME_MACHINE}-unknown-atheos
- exit ;;
- i*86:syllable:*:*)
- echo ${UNAME_MACHINE}-pc-syllable
- exit ;;
- i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*)
- echo i386-unknown-lynxos${UNAME_RELEASE}
- exit ;;
- i*86:*DOS:*:*)
- echo ${UNAME_MACHINE}-pc-msdosdjgpp
- exit ;;
- i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*)
- UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'`
- if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
- echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL}
- else
- echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL}
- fi
- exit ;;
- i*86:*:5:[678]*)
- # UnixWare 7.x, OpenUNIX and OpenServer 6.
- case `/bin/uname -X | grep "^Machine"` in
- *486*) UNAME_MACHINE=i486 ;;
- *Pentium) UNAME_MACHINE=i586 ;;
- *Pent*|*Celeron) UNAME_MACHINE=i686 ;;
- esac
- echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}
- exit ;;
- i*86:*:3.2:*)
- if test -f /usr/options/cb.name; then
- UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
- echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
- elif /bin/uname -X 2>/dev/null >/dev/null ; then
- UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')`
- (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486
- (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \
- && UNAME_MACHINE=i586
- (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \
- && UNAME_MACHINE=i686
- (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \
- && UNAME_MACHINE=i686
- echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
- else
- echo ${UNAME_MACHINE}-pc-sysv32
- fi
- exit ;;
- pc:*:*:*)
- # Left here for compatibility:
- # uname -m prints for DJGPP always 'pc', but it prints nothing about
- # the processor, so we play safe by assuming i586.
- # Note: whatever this is, it MUST be the same as what config.sub
- # prints for the "djgpp" host, or else GDB configure will decide that
- # this is a cross-build.
- echo i586-pc-msdosdjgpp
- exit ;;
- Intel:Mach:3*:*)
- echo i386-pc-mach3
- exit ;;
- paragon:*:*:*)
- echo i860-intel-osf1
- exit ;;
- i860:*:4.*:*) # i860-SVR4
- if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
- echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
- else # Add other i860-SVR4 vendors below as they are discovered.
- echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4
- fi
- exit ;;
- mini*:CTIX:SYS*5:*)
- # "miniframe"
- echo m68010-convergent-sysv
- exit ;;
- mc68k:UNIX:SYSTEM5:3.51m)
- echo m68k-convergent-sysv
- exit ;;
- M680?0:D-NIX:5.3:*)
- echo m68k-diab-dnix
- exit ;;
- M68*:*:R3V[5678]*:*)
- test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;;
- 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0)
- OS_REL=''
- test -r /etc/.relid \
- && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
- /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
- && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
- /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
- && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
- 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
- /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
- && { echo i486-ncr-sysv4; exit; } ;;
- NCR*:*:4.2:* | MPRAS*:*:4.2:*)
- OS_REL='.3'
- test -r /etc/.relid \
- && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
- /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
- && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
- /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
- && { echo i586-ncr-sysv4.3${OS_REL}; exit; }
- /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \
- && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
- m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
- echo m68k-unknown-lynxos${UNAME_RELEASE}
- exit ;;
- mc68030:UNIX_System_V:4.*:*)
- echo m68k-atari-sysv4
- exit ;;
- TSUNAMI:LynxOS:2.*:*)
- echo sparc-unknown-lynxos${UNAME_RELEASE}
- exit ;;
- rs6000:LynxOS:2.*:*)
- echo rs6000-unknown-lynxos${UNAME_RELEASE}
- exit ;;
- PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*)
- echo powerpc-unknown-lynxos${UNAME_RELEASE}
- exit ;;
- SM[BE]S:UNIX_SV:*:*)
- echo mips-dde-sysv${UNAME_RELEASE}
- exit ;;
- RM*:ReliantUNIX-*:*:*)
- echo mips-sni-sysv4
- exit ;;
- RM*:SINIX-*:*:*)
- echo mips-sni-sysv4
- exit ;;
- *:SINIX-*:*:*)
- if uname -p 2>/dev/null >/dev/null ; then
- UNAME_MACHINE=`(uname -p) 2>/dev/null`
- echo ${UNAME_MACHINE}-sni-sysv4
- else
- echo ns32k-sni-sysv
- fi
- exit ;;
- PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
- # says <Richard.M.Bartel@ccMail.Census.GOV>
- echo i586-unisys-sysv4
- exit ;;
- *:UNIX_System_V:4*:FTX*)
- # From Gerald Hewes <hewes@openmarket.com>.
- # How about differentiating between stratus architectures? -djm
- echo hppa1.1-stratus-sysv4
- exit ;;
- *:*:*:FTX*)
- # From seanf@swdc.stratus.com.
- echo i860-stratus-sysv4
- exit ;;
- i*86:VOS:*:*)
- # From Paul.Green@stratus.com.
- echo ${UNAME_MACHINE}-stratus-vos
- exit ;;
- *:VOS:*:*)
- # From Paul.Green@stratus.com.
- echo hppa1.1-stratus-vos
- exit ;;
- mc68*:A/UX:*:*)
- echo m68k-apple-aux${UNAME_RELEASE}
- exit ;;
- news*:NEWS-OS:6*:*)
- echo mips-sony-newsos6
- exit ;;
- R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
- if [ -d /usr/nec ]; then
- echo mips-nec-sysv${UNAME_RELEASE}
- else
- echo mips-unknown-sysv${UNAME_RELEASE}
- fi
- exit ;;
- BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only.
- echo powerpc-be-beos
- exit ;;
- BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only.
- echo powerpc-apple-beos
- exit ;;
- BePC:BeOS:*:*) # BeOS running on Intel PC compatible.
- echo i586-pc-beos
- exit ;;
- BePC:Haiku:*:*) # Haiku running on Intel PC compatible.
- echo i586-pc-haiku
- exit ;;
- x86_64:Haiku:*:*)
- echo x86_64-unknown-haiku
- exit ;;
- SX-4:SUPER-UX:*:*)
- echo sx4-nec-superux${UNAME_RELEASE}
- exit ;;
- SX-5:SUPER-UX:*:*)
- echo sx5-nec-superux${UNAME_RELEASE}
- exit ;;
- SX-6:SUPER-UX:*:*)
- echo sx6-nec-superux${UNAME_RELEASE}
- exit ;;
- SX-7:SUPER-UX:*:*)
- echo sx7-nec-superux${UNAME_RELEASE}
- exit ;;
- SX-8:SUPER-UX:*:*)
- echo sx8-nec-superux${UNAME_RELEASE}
- exit ;;
- SX-8R:SUPER-UX:*:*)
- echo sx8r-nec-superux${UNAME_RELEASE}
- exit ;;
- SX-ACE:SUPER-UX:*:*)
- echo sxace-nec-superux${UNAME_RELEASE}
- exit ;;
- Power*:Rhapsody:*:*)
- echo powerpc-apple-rhapsody${UNAME_RELEASE}
- exit ;;
- *:Rhapsody:*:*)
- echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
- exit ;;
- *:Darwin:*:*)
- UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown
- eval $set_cc_for_build
- if test "$UNAME_PROCESSOR" = unknown ; then
- UNAME_PROCESSOR=powerpc
- fi
- if test `echo "$UNAME_RELEASE" | sed -e 's/\..*//'` -le 10 ; then
- if [ "$CC_FOR_BUILD" != no_compiler_found ]; then
- if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
- (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
- grep IS_64BIT_ARCH >/dev/null
- then
- case $UNAME_PROCESSOR in
- i386) UNAME_PROCESSOR=x86_64 ;;
- powerpc) UNAME_PROCESSOR=powerpc64 ;;
- esac
- fi
- fi
- elif test "$UNAME_PROCESSOR" = i386 ; then
- # Avoid executing cc on OS X 10.9, as it ships with a stub
- # that puts up a graphical alert prompting to install
- # developer tools. Any system running Mac OS X 10.7 or
- # later (Darwin 11 and later) is required to have a 64-bit
- # processor. This is not true of the ARM version of Darwin
- # that Apple uses in portable devices.
- UNAME_PROCESSOR=x86_64
- fi
- echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
- exit ;;
- *:procnto*:*:* | *:QNX:[0123456789]*:*)
- UNAME_PROCESSOR=`uname -p`
- if test "$UNAME_PROCESSOR" = x86; then
- UNAME_PROCESSOR=i386
- UNAME_MACHINE=pc
- fi
- echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE}
- exit ;;
- *:QNX:*:4*)
- echo i386-pc-qnx
- exit ;;
- NEO-?:NONSTOP_KERNEL:*:*)
- echo neo-tandem-nsk${UNAME_RELEASE}
- exit ;;
- NSE-*:NONSTOP_KERNEL:*:*)
- echo nse-tandem-nsk${UNAME_RELEASE}
- exit ;;
- NSR-?:NONSTOP_KERNEL:*:*)
- echo nsr-tandem-nsk${UNAME_RELEASE}
- exit ;;
- *:NonStop-UX:*:*)
- echo mips-compaq-nonstopux
- exit ;;
- BS2000:POSIX*:*:*)
- echo bs2000-siemens-sysv
- exit ;;
- DS/*:UNIX_System_V:*:*)
- echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE}
- exit ;;
- *:Plan9:*:*)
- # "uname -m" is not consistent, so use $cputype instead. 386
- # is converted to i386 for consistency with other x86
- # operating systems.
- if test "$cputype" = 386; then
- UNAME_MACHINE=i386
- else
- UNAME_MACHINE="$cputype"
- fi
- echo ${UNAME_MACHINE}-unknown-plan9
- exit ;;
- *:TOPS-10:*:*)
- echo pdp10-unknown-tops10
- exit ;;
- *:TENEX:*:*)
- echo pdp10-unknown-tenex
- exit ;;
- KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
- echo pdp10-dec-tops20
- exit ;;
- XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
- echo pdp10-xkl-tops20
- exit ;;
- *:TOPS-20:*:*)
- echo pdp10-unknown-tops20
- exit ;;
- *:ITS:*:*)
- echo pdp10-unknown-its
- exit ;;
- SEI:*:*:SEIUX)
- echo mips-sei-seiux${UNAME_RELEASE}
- exit ;;
- *:DragonFly:*:*)
- echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
- exit ;;
- *:*VMS:*:*)
- UNAME_MACHINE=`(uname -p) 2>/dev/null`
- case "${UNAME_MACHINE}" in
- A*) echo alpha-dec-vms ; exit ;;
- I*) echo ia64-dec-vms ; exit ;;
- V*) echo vax-dec-vms ; exit ;;
- esac ;;
- *:XENIX:*:SysV)
- echo i386-pc-xenix
- exit ;;
- i*86:skyos:*:*)
- echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE} | sed -e 's/ .*$//'`
- exit ;;
- i*86:rdos:*:*)
- echo ${UNAME_MACHINE}-pc-rdos
- exit ;;
- i*86:AROS:*:*)
- echo ${UNAME_MACHINE}-pc-aros
- exit ;;
- x86_64:VMkernel:*:*)
- echo ${UNAME_MACHINE}-unknown-esx
- exit ;;
- amd64:Isilon\ OneFS:*:*)
- echo x86_64-unknown-onefs
- exit ;;
-esac
-
-cat >&2 <<EOF
-$0: unable to guess system type
-
-This script (version $timestamp), has failed to recognize the
-operating system you are using. If your script is old, overwrite
-config.guess and config.sub with the latest versions from:
-
- http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess
-and
- http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub
-
-If $0 has already been updated, send the following data and any
-information you think might be pertinent to config-patches@gnu.org to
-provide the necessary information to handle your system.
-
-config.guess timestamp = $timestamp
-
-uname -m = `(uname -m) 2>/dev/null || echo unknown`
-uname -r = `(uname -r) 2>/dev/null || echo unknown`
-uname -s = `(uname -s) 2>/dev/null || echo unknown`
-uname -v = `(uname -v) 2>/dev/null || echo unknown`
-
-/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null`
-/bin/uname -X = `(/bin/uname -X) 2>/dev/null`
-
-hostinfo = `(hostinfo) 2>/dev/null`
-/bin/universe = `(/bin/universe) 2>/dev/null`
-/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null`
-/bin/arch = `(/bin/arch) 2>/dev/null`
-/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null`
-/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`
-
-UNAME_MACHINE = ${UNAME_MACHINE}
-UNAME_RELEASE = ${UNAME_RELEASE}
-UNAME_SYSTEM = ${UNAME_SYSTEM}
-UNAME_VERSION = ${UNAME_VERSION}
-EOF
-
-exit 1
-
-# Local variables:
-# eval: (add-hook 'write-file-hooks 'time-stamp)
-# time-stamp-start: "timestamp='"
-# time-stamp-format: "%:y-%02m-%02d"
-# time-stamp-end: "'"
-# End:
->>>>>>> main
diff --git a/contrib/jemalloc/build-aux/config.sub b/contrib/jemalloc/build-aux/config.sub
index 099dab005a9a..b0f8492348d7 100755
--- a/contrib/jemalloc/build-aux/config.sub
+++ b/contrib/jemalloc/build-aux/config.sub
@@ -1,4 +1,3 @@
-<<<<<<< HEAD
#! /bin/sh
# Configuration validation subroutine script.
# Copyright 1992-2021 Free Software Foundation, Inc.
@@ -1854,1831 +1853,3 @@ exit
# time-stamp-format: "%:y-%02m-%02d"
# time-stamp-end: "'"
# End:
-||||||| dec341af7695
-=======
-#! /bin/sh
-# Configuration validation subroutine script.
-# Copyright 1992-2016 Free Software Foundation, Inc.
-
-timestamp='2016-11-04'
-
-# This file is free software; you can redistribute it and/or modify it
-# under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, see <http://www.gnu.org/licenses/>.
-#
-# As a special exception to the GNU General Public License, if you
-# distribute this file as part of a program that contains a
-# configuration script generated by Autoconf, you may include it under
-# the same distribution terms that you use for the rest of that
-# program. This Exception is an additional permission under section 7
-# of the GNU General Public License, version 3 ("GPLv3").
-
-
-# Please send patches to <config-patches@gnu.org>.
-#
-# Configuration subroutine to validate and canonicalize a configuration type.
-# Supply the specified configuration type as an argument.
-# If it is invalid, we print an error message on stderr and exit with code 1.
-# Otherwise, we print the canonical config type on stdout and succeed.
-
-# You can get the latest version of this script from:
-# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub
-
-# This file is supposed to be the same for all GNU packages
-# and recognize all the CPU types, system types and aliases
-# that are meaningful with *any* GNU software.
-# Each package is responsible for reporting which valid configurations
-# it does not support. The user should be able to distinguish
-# a failure to support a valid configuration from a meaningless
-# configuration.
-
-# The goal of this file is to map all the various variations of a given
-# machine specification into a single specification in the form:
-# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
-# or in some cases, the newer four-part form:
-# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
-# It is wrong to echo any other type of specification.
-
-me=`echo "$0" | sed -e 's,.*/,,'`
-
-usage="\
-Usage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS
-
-Canonicalize a configuration name.
-
-Operation modes:
- -h, --help print this help, then exit
- -t, --time-stamp print date of last modification, then exit
- -v, --version print version number, then exit
-
-Report bugs and patches to <config-patches@gnu.org>."
-
-version="\
-GNU config.sub ($timestamp)
-
-Copyright 1992-2016 Free Software Foundation, Inc.
-
-This is free software; see the source for copying conditions. There is NO
-warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
-
-help="
-Try \`$me --help' for more information."
-
-# Parse command line
-while test $# -gt 0 ; do
- case $1 in
- --time-stamp | --time* | -t )
- echo "$timestamp" ; exit ;;
- --version | -v )
- echo "$version" ; exit ;;
- --help | --h* | -h )
- echo "$usage"; exit ;;
- -- ) # Stop option processing
- shift; break ;;
- - ) # Use stdin as input.
- break ;;
- -* )
- echo "$me: invalid option $1$help"
- exit 1 ;;
-
- *local*)
- # First pass through any local machine types.
- echo $1
- exit ;;
-
- * )
- break ;;
- esac
-done
-
-case $# in
- 0) echo "$me: missing argument$help" >&2
- exit 1;;
- 1) ;;
- *) echo "$me: too many arguments$help" >&2
- exit 1;;
-esac
-
-# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
-# Here we must recognize all the valid KERNEL-OS combinations.
-maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
-case $maybe_os in
- nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \
- linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \
- knetbsd*-gnu* | netbsd*-gnu* | netbsd*-eabi* | \
- kopensolaris*-gnu* | cloudabi*-eabi* | \
- storm-chaos* | os2-emx* | rtmk-nova*)
- os=-$maybe_os
- basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
- ;;
- android-linux)
- os=-linux-android
- basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown
- ;;
- *)
- basic_machine=`echo $1 | sed 's/-[^-]*$//'`
- if [ $basic_machine != $1 ]
- then os=`echo $1 | sed 's/.*-/-/'`
- else os=; fi
- ;;
-esac
-
-### Let's recognize common machines as not being operating systems so
-### that things like config.sub decstation-3100 work. We also
-### recognize some manufacturers as not being operating systems, so we
-### can provide default operating systems below.
-case $os in
- -sun*os*)
- # Prevent following clause from handling this invalid input.
- ;;
- -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
- -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
- -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
- -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
- -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
- -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
- -apple | -axis | -knuth | -cray | -microblaze*)
- os=
- basic_machine=$1
- ;;
- -bluegene*)
- os=-cnk
- ;;
- -sim | -cisco | -oki | -wec | -winbond)
- os=
- basic_machine=$1
- ;;
- -scout)
- ;;
- -wrs)
- os=-vxworks
- basic_machine=$1
- ;;
- -chorusos*)
- os=-chorusos
- basic_machine=$1
- ;;
- -chorusrdb)
- os=-chorusrdb
- basic_machine=$1
- ;;
- -hiux*)
- os=-hiuxwe2
- ;;
- -sco6)
- os=-sco5v6
- basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
- ;;
- -sco5)
- os=-sco3.2v5
- basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
- ;;
- -sco4)
- os=-sco3.2v4
- basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
- ;;
- -sco3.2.[4-9]*)
- os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
- basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
- ;;
- -sco3.2v[4-9]*)
- # Don't forget version if it is 3.2v4 or newer.
- basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
- ;;
- -sco5v6*)
- # Don't forget version if it is 3.2v4 or newer.
- basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
- ;;
- -sco*)
- os=-sco3.2v2
- basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
- ;;
- -udk*)
- basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
- ;;
- -isc)
- os=-isc2.2
- basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
- ;;
- -clix*)
- basic_machine=clipper-intergraph
- ;;
- -isc*)
- basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
- ;;
- -lynx*178)
- os=-lynxos178
- ;;
- -lynx*5)
- os=-lynxos5
- ;;
- -lynx*)
- os=-lynxos
- ;;
- -ptx*)
- basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
- ;;
- -windowsnt*)
- os=`echo $os | sed -e 's/windowsnt/winnt/'`
- ;;
- -psos*)
- os=-psos
- ;;
- -mint | -mint[0-9]*)
- basic_machine=m68k-atari
- os=-mint
- ;;
-esac
-
-# Decode aliases for certain CPU-COMPANY combinations.
-case $basic_machine in
- # Recognize the basic CPU types without company name.
- # Some are omitted here because they have special meanings below.
- 1750a | 580 \
- | a29k \
- | aarch64 | aarch64_be \
- | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
- | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
- | am33_2.0 \
- | arc | arceb \
- | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \
- | avr | avr32 \
- | ba \
- | be32 | be64 \
- | bfin \
- | c4x | c8051 | clipper \
- | d10v | d30v | dlx | dsp16xx \
- | e2k | epiphany \
- | fido | fr30 | frv | ft32 \
- | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
- | hexagon \
- | i370 | i860 | i960 | ia64 \
- | ip2k | iq2000 \
- | k1om \
- | le32 | le64 \
- | lm32 \
- | m32c | m32r | m32rle | m68000 | m68k | m88k \
- | maxq | mb | microblaze | microblazeel | mcore | mep | metag \
- | mips | mipsbe | mipseb | mipsel | mipsle \
- | mips16 \
- | mips64 | mips64el \
- | mips64octeon | mips64octeonel \
- | mips64orion | mips64orionel \
- | mips64r5900 | mips64r5900el \
- | mips64vr | mips64vrel \
- | mips64vr4100 | mips64vr4100el \
- | mips64vr4300 | mips64vr4300el \
- | mips64vr5000 | mips64vr5000el \
- | mips64vr5900 | mips64vr5900el \
- | mipsisa32 | mipsisa32el \
- | mipsisa32r2 | mipsisa32r2el \
- | mipsisa32r6 | mipsisa32r6el \
- | mipsisa64 | mipsisa64el \
- | mipsisa64r2 | mipsisa64r2el \
- | mipsisa64r6 | mipsisa64r6el \
- | mipsisa64sb1 | mipsisa64sb1el \
- | mipsisa64sr71k | mipsisa64sr71kel \
- | mipsr5900 | mipsr5900el \
- | mipstx39 | mipstx39el \
- | mn10200 | mn10300 \
- | moxie \
- | mt \
- | msp430 \
- | nds32 | nds32le | nds32be \
- | nios | nios2 | nios2eb | nios2el \
- | ns16k | ns32k \
- | open8 | or1k | or1knd | or32 \
- | pdp10 | pdp11 | pj | pjl \
- | powerpc | powerpc64 | powerpc64le | powerpcle \
- | pru \
- | pyramid \
- | riscv32 | riscv64 \
- | rl78 | rx \
- | score \
- | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[234]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
- | sh64 | sh64le \
- | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \
- | sparcv8 | sparcv9 | sparcv9b | sparcv9v \
- | spu \
- | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \
- | ubicom32 \
- | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \
- | visium \
- | we32k \
- | x86 | xc16x | xstormy16 | xtensa \
- | z8k | z80)
- basic_machine=$basic_machine-unknown
- ;;
- c54x)
- basic_machine=tic54x-unknown
- ;;
- c55x)
- basic_machine=tic55x-unknown
- ;;
- c6x)
- basic_machine=tic6x-unknown
- ;;
- leon|leon[3-9])
- basic_machine=sparc-$basic_machine
- ;;
- m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip)
- basic_machine=$basic_machine-unknown
- os=-none
- ;;
- m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k)
- ;;
- ms1)
- basic_machine=mt-unknown
- ;;
-
- strongarm | thumb | xscale)
- basic_machine=arm-unknown
- ;;
- xgate)
- basic_machine=$basic_machine-unknown
- os=-none
- ;;
- xscaleeb)
- basic_machine=armeb-unknown
- ;;
-
- xscaleel)
- basic_machine=armel-unknown
- ;;
-
- # We use `pc' rather than `unknown'
- # because (1) that's what they normally are, and
- # (2) the word "unknown" tends to confuse beginning users.
- i*86 | x86_64)
- basic_machine=$basic_machine-pc
- ;;
- # Object if more than one company name word.
- *-*-*)
- echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
- exit 1
- ;;
- # Recognize the basic CPU types with company name.
- 580-* \
- | a29k-* \
- | aarch64-* | aarch64_be-* \
- | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
- | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
- | alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \
- | arm-* | armbe-* | armle-* | armeb-* | armv*-* \
- | avr-* | avr32-* \
- | ba-* \
- | be32-* | be64-* \
- | bfin-* | bs2000-* \
- | c[123]* | c30-* | [cjt]90-* | c4x-* \
- | c8051-* | clipper-* | craynv-* | cydra-* \
- | d10v-* | d30v-* | dlx-* \
- | e2k-* | elxsi-* \
- | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \
- | h8300-* | h8500-* \
- | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
- | hexagon-* \
- | i*86-* | i860-* | i960-* | ia64-* \
- | ip2k-* | iq2000-* \
- | k1om-* \
- | le32-* | le64-* \
- | lm32-* \
- | m32c-* | m32r-* | m32rle-* \
- | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
- | m88110-* | m88k-* | maxq-* | mcore-* | metag-* \
- | microblaze-* | microblazeel-* \
- | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
- | mips16-* \
- | mips64-* | mips64el-* \
- | mips64octeon-* | mips64octeonel-* \
- | mips64orion-* | mips64orionel-* \
- | mips64r5900-* | mips64r5900el-* \
- | mips64vr-* | mips64vrel-* \
- | mips64vr4100-* | mips64vr4100el-* \
- | mips64vr4300-* | mips64vr4300el-* \
- | mips64vr5000-* | mips64vr5000el-* \
- | mips64vr5900-* | mips64vr5900el-* \
- | mipsisa32-* | mipsisa32el-* \
- | mipsisa32r2-* | mipsisa32r2el-* \
- | mipsisa32r6-* | mipsisa32r6el-* \
- | mipsisa64-* | mipsisa64el-* \
- | mipsisa64r2-* | mipsisa64r2el-* \
- | mipsisa64r6-* | mipsisa64r6el-* \
- | mipsisa64sb1-* | mipsisa64sb1el-* \
- | mipsisa64sr71k-* | mipsisa64sr71kel-* \
- | mipsr5900-* | mipsr5900el-* \
- | mipstx39-* | mipstx39el-* \
- | mmix-* \
- | mt-* \
- | msp430-* \
- | nds32-* | nds32le-* | nds32be-* \
- | nios-* | nios2-* | nios2eb-* | nios2el-* \
- | none-* | np1-* | ns16k-* | ns32k-* \
- | open8-* \
- | or1k*-* \
- | orion-* \
- | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
- | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \
- | pru-* \
- | pyramid-* \
- | riscv32-* | riscv64-* \
- | rl78-* | romp-* | rs6000-* | rx-* \
- | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
- | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
- | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \
- | sparclite-* \
- | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx*-* \
- | tahoe-* \
- | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
- | tile*-* \
- | tron-* \
- | ubicom32-* \
- | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \
- | vax-* \
- | visium-* \
- | we32k-* \
- | x86-* | x86_64-* | xc16x-* | xps100-* \
- | xstormy16-* | xtensa*-* \
- | ymp-* \
- | z8k-* | z80-*)
- ;;
- # Recognize the basic CPU types without company name, with glob match.
- xtensa*)
- basic_machine=$basic_machine-unknown
- ;;
- # Recognize the various machine names and aliases which stand
- # for a CPU type and a company and sometimes even an OS.
- 386bsd)
- basic_machine=i386-unknown
- os=-bsd
- ;;
- 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
- basic_machine=m68000-att
- ;;
- 3b*)
- basic_machine=we32k-att
- ;;
- a29khif)
- basic_machine=a29k-amd
- os=-udi
- ;;
- abacus)
- basic_machine=abacus-unknown
- ;;
- adobe68k)
- basic_machine=m68010-adobe
- os=-scout
- ;;
- alliant | fx80)
- basic_machine=fx80-alliant
- ;;
- altos | altos3068)
- basic_machine=m68k-altos
- ;;
- am29k)
- basic_machine=a29k-none
- os=-bsd
- ;;
- amd64)
- basic_machine=x86_64-pc
- ;;
- amd64-*)
- basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'`
- ;;
- amdahl)
- basic_machine=580-amdahl
- os=-sysv
- ;;
- amiga | amiga-*)
- basic_machine=m68k-unknown
- ;;
- amigaos | amigados)
- basic_machine=m68k-unknown
- os=-amigaos
- ;;
- amigaunix | amix)
- basic_machine=m68k-unknown
- os=-sysv4
- ;;
- apollo68)
- basic_machine=m68k-apollo
- os=-sysv
- ;;
- apollo68bsd)
- basic_machine=m68k-apollo
- os=-bsd
- ;;
- aros)
- basic_machine=i386-pc
- os=-aros
- ;;
- asmjs)
- basic_machine=asmjs-unknown
- ;;
- aux)
- basic_machine=m68k-apple
- os=-aux
- ;;
- balance)
- basic_machine=ns32k-sequent
- os=-dynix
- ;;
- blackfin)
- basic_machine=bfin-unknown
- os=-linux
- ;;
- blackfin-*)
- basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'`
- os=-linux
- ;;
- bluegene*)
- basic_machine=powerpc-ibm
- os=-cnk
- ;;
- c54x-*)
- basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'`
- ;;
- c55x-*)
- basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'`
- ;;
- c6x-*)
- basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'`
- ;;
- c90)
- basic_machine=c90-cray
- os=-unicos
- ;;
- cegcc)
- basic_machine=arm-unknown
- os=-cegcc
- ;;
- convex-c1)
- basic_machine=c1-convex
- os=-bsd
- ;;
- convex-c2)
- basic_machine=c2-convex
- os=-bsd
- ;;
- convex-c32)
- basic_machine=c32-convex
- os=-bsd
- ;;
- convex-c34)
- basic_machine=c34-convex
- os=-bsd
- ;;
- convex-c38)
- basic_machine=c38-convex
- os=-bsd
- ;;
- cray | j90)
- basic_machine=j90-cray
- os=-unicos
- ;;
- craynv)
- basic_machine=craynv-cray
- os=-unicosmp
- ;;
- cr16 | cr16-*)
- basic_machine=cr16-unknown
- os=-elf
- ;;
- crds | unos)
- basic_machine=m68k-crds
- ;;
- crisv32 | crisv32-* | etraxfs*)
- basic_machine=crisv32-axis
- ;;
- cris | cris-* | etrax*)
- basic_machine=cris-axis
- ;;
- crx)
- basic_machine=crx-unknown
- os=-elf
- ;;
- da30 | da30-*)
- basic_machine=m68k-da30
- ;;
- decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
- basic_machine=mips-dec
- ;;
- decsystem10* | dec10*)
- basic_machine=pdp10-dec
- os=-tops10
- ;;
- decsystem20* | dec20*)
- basic_machine=pdp10-dec
- os=-tops20
- ;;
- delta | 3300 | motorola-3300 | motorola-delta \
- | 3300-motorola | delta-motorola)
- basic_machine=m68k-motorola
- ;;
- delta88)
- basic_machine=m88k-motorola
- os=-sysv3
- ;;
- dicos)
- basic_machine=i686-pc
- os=-dicos
- ;;
- djgpp)
- basic_machine=i586-pc
- os=-msdosdjgpp
- ;;
- dpx20 | dpx20-*)
- basic_machine=rs6000-bull
- os=-bosx
- ;;
- dpx2* | dpx2*-bull)
- basic_machine=m68k-bull
- os=-sysv3
- ;;
- e500v[12])
- basic_machine=powerpc-unknown
- os=$os"spe"
- ;;
- e500v[12]-*)
- basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
- os=$os"spe"
- ;;
- ebmon29k)
- basic_machine=a29k-amd
- os=-ebmon
- ;;
- elxsi)
- basic_machine=elxsi-elxsi
- os=-bsd
- ;;
- encore | umax | mmax)
- basic_machine=ns32k-encore
- ;;
- es1800 | OSE68k | ose68k | ose | OSE)
- basic_machine=m68k-ericsson
- os=-ose
- ;;
- fx2800)
- basic_machine=i860-alliant
- ;;
- genix)
- basic_machine=ns32k-ns
- ;;
- gmicro)
- basic_machine=tron-gmicro
- os=-sysv
- ;;
- go32)
- basic_machine=i386-pc
- os=-go32
- ;;
- h3050r* | hiux*)
- basic_machine=hppa1.1-hitachi
- os=-hiuxwe2
- ;;
- h8300hms)
- basic_machine=h8300-hitachi
- os=-hms
- ;;
- h8300xray)
- basic_machine=h8300-hitachi
- os=-xray
- ;;
- h8500hms)
- basic_machine=h8500-hitachi
- os=-hms
- ;;
- harris)
- basic_machine=m88k-harris
- os=-sysv3
- ;;
- hp300-*)
- basic_machine=m68k-hp
- ;;
- hp300bsd)
- basic_machine=m68k-hp
- os=-bsd
- ;;
- hp300hpux)
- basic_machine=m68k-hp
- os=-hpux
- ;;
- hp3k9[0-9][0-9] | hp9[0-9][0-9])
- basic_machine=hppa1.0-hp
- ;;
- hp9k2[0-9][0-9] | hp9k31[0-9])
- basic_machine=m68000-hp
- ;;
- hp9k3[2-9][0-9])
- basic_machine=m68k-hp
- ;;
- hp9k6[0-9][0-9] | hp6[0-9][0-9])
- basic_machine=hppa1.0-hp
- ;;
- hp9k7[0-79][0-9] | hp7[0-79][0-9])
- basic_machine=hppa1.1-hp
- ;;
- hp9k78[0-9] | hp78[0-9])
- # FIXME: really hppa2.0-hp
- basic_machine=hppa1.1-hp
- ;;
- hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
- # FIXME: really hppa2.0-hp
- basic_machine=hppa1.1-hp
- ;;
- hp9k8[0-9][13679] | hp8[0-9][13679])
- basic_machine=hppa1.1-hp
- ;;
- hp9k8[0-9][0-9] | hp8[0-9][0-9])
- basic_machine=hppa1.0-hp
- ;;
- hppa-next)
- os=-nextstep3
- ;;
- hppaosf)
- basic_machine=hppa1.1-hp
- os=-osf
- ;;
- hppro)
- basic_machine=hppa1.1-hp
- os=-proelf
- ;;
- i370-ibm* | ibm*)
- basic_machine=i370-ibm
- ;;
- i*86v32)
- basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
- os=-sysv32
- ;;
- i*86v4*)
- basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
- os=-sysv4
- ;;
- i*86v)
- basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
- os=-sysv
- ;;
- i*86sol2)
- basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
- os=-solaris2
- ;;
- i386mach)
- basic_machine=i386-mach
- os=-mach
- ;;
- i386-vsta | vsta)
- basic_machine=i386-unknown
- os=-vsta
- ;;
- iris | iris4d)
- basic_machine=mips-sgi
- case $os in
- -irix*)
- ;;
- *)
- os=-irix4
- ;;
- esac
- ;;
- isi68 | isi)
- basic_machine=m68k-isi
- os=-sysv
- ;;
- leon-*|leon[3-9]-*)
- basic_machine=sparc-`echo $basic_machine | sed 's/-.*//'`
- ;;
- m68knommu)
- basic_machine=m68k-unknown
- os=-linux
- ;;
- m68knommu-*)
- basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'`
- os=-linux
- ;;
- m88k-omron*)
- basic_machine=m88k-omron
- ;;
- magnum | m3230)
- basic_machine=mips-mips
- os=-sysv
- ;;
- merlin)
- basic_machine=ns32k-utek
- os=-sysv
- ;;
- microblaze*)
- basic_machine=microblaze-xilinx
- ;;
- mingw64)
- basic_machine=x86_64-pc
- os=-mingw64
- ;;
- mingw32)
- basic_machine=i686-pc
- os=-mingw32
- ;;
- mingw32ce)
- basic_machine=arm-unknown
- os=-mingw32ce
- ;;
- miniframe)
- basic_machine=m68000-convergent
- ;;
- *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)
- basic_machine=m68k-atari
- os=-mint
- ;;
- mips3*-*)
- basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
- ;;
- mips3*)
- basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
- ;;
- monitor)
- basic_machine=m68k-rom68k
- os=-coff
- ;;
- morphos)
- basic_machine=powerpc-unknown
- os=-morphos
- ;;
- moxiebox)
- basic_machine=moxie-unknown
- os=-moxiebox
- ;;
- msdos)
- basic_machine=i386-pc
- os=-msdos
- ;;
- ms1-*)
- basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'`
- ;;
- msys)
- basic_machine=i686-pc
- os=-msys
- ;;
- mvs)
- basic_machine=i370-ibm
- os=-mvs
- ;;
- nacl)
- basic_machine=le32-unknown
- os=-nacl
- ;;
- ncr3000)
- basic_machine=i486-ncr
- os=-sysv4
- ;;
- netbsd386)
- basic_machine=i386-unknown
- os=-netbsd
- ;;
- netwinder)
- basic_machine=armv4l-rebel
- os=-linux
- ;;
- news | news700 | news800 | news900)
- basic_machine=m68k-sony
- os=-newsos
- ;;
- news1000)
- basic_machine=m68030-sony
- os=-newsos
- ;;
- news-3600 | risc-news)
- basic_machine=mips-sony
- os=-newsos
- ;;
- necv70)
- basic_machine=v70-nec
- os=-sysv
- ;;
- next | m*-next )
- basic_machine=m68k-next
- case $os in
- -nextstep* )
- ;;
- -ns2*)
- os=-nextstep2
- ;;
- *)
- os=-nextstep3
- ;;
- esac
- ;;
- nh3000)
- basic_machine=m68k-harris
- os=-cxux
- ;;
- nh[45]000)
- basic_machine=m88k-harris
- os=-cxux
- ;;
- nindy960)
- basic_machine=i960-intel
- os=-nindy
- ;;
- mon960)
- basic_machine=i960-intel
- os=-mon960
- ;;
- nonstopux)
- basic_machine=mips-compaq
- os=-nonstopux
- ;;
- np1)
- basic_machine=np1-gould
- ;;
- neo-tandem)
- basic_machine=neo-tandem
- ;;
- nse-tandem)
- basic_machine=nse-tandem
- ;;
- nsr-tandem)
- basic_machine=nsr-tandem
- ;;
- op50n-* | op60c-*)
- basic_machine=hppa1.1-oki
- os=-proelf
- ;;
- openrisc | openrisc-*)
- basic_machine=or32-unknown
- ;;
- os400)
- basic_machine=powerpc-ibm
- os=-os400
- ;;
- OSE68000 | ose68000)
- basic_machine=m68000-ericsson
- os=-ose
- ;;
- os68k)
- basic_machine=m68k-none
- os=-os68k
- ;;
- pa-hitachi)
- basic_machine=hppa1.1-hitachi
- os=-hiuxwe2
- ;;
- paragon)
- basic_machine=i860-intel
- os=-osf
- ;;
- parisc)
- basic_machine=hppa-unknown
- os=-linux
- ;;
- parisc-*)
- basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'`
- os=-linux
- ;;
- pbd)
- basic_machine=sparc-tti
- ;;
- pbb)
- basic_machine=m68k-tti
- ;;
- pc532 | pc532-*)
- basic_machine=ns32k-pc532
- ;;
- pc98)
- basic_machine=i386-pc
- ;;
- pc98-*)
- basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'`
- ;;
- pentium | p5 | k5 | k6 | nexgen | viac3)
- basic_machine=i586-pc
- ;;
- pentiumpro | p6 | 6x86 | athlon | athlon_*)
- basic_machine=i686-pc
- ;;
- pentiumii | pentium2 | pentiumiii | pentium3)
- basic_machine=i686-pc
- ;;
- pentium4)
- basic_machine=i786-pc
- ;;
- pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
- basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
- ;;
- pentiumpro-* | p6-* | 6x86-* | athlon-*)
- basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
- ;;
- pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
- basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
- ;;
- pentium4-*)
- basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'`
- ;;
- pn)
- basic_machine=pn-gould
- ;;
- power) basic_machine=power-ibm
- ;;
- ppc | ppcbe) basic_machine=powerpc-unknown
- ;;
- ppc-* | ppcbe-*)
- basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
- ;;
- ppcle | powerpclittle)
- basic_machine=powerpcle-unknown
- ;;
- ppcle-* | powerpclittle-*)
- basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
- ;;
- ppc64) basic_machine=powerpc64-unknown
- ;;
- ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
- ;;
- ppc64le | powerpc64little)
- basic_machine=powerpc64le-unknown
- ;;
- ppc64le-* | powerpc64little-*)
- basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'`
- ;;
- ps2)
- basic_machine=i386-ibm
- ;;
- pw32)
- basic_machine=i586-unknown
- os=-pw32
- ;;
- rdos | rdos64)
- basic_machine=x86_64-pc
- os=-rdos
- ;;
- rdos32)
- basic_machine=i386-pc
- os=-rdos
- ;;
- rom68k)
- basic_machine=m68k-rom68k
- os=-coff
- ;;
- rm[46]00)
- basic_machine=mips-siemens
- ;;
- rtpc | rtpc-*)
- basic_machine=romp-ibm
- ;;
- s390 | s390-*)
- basic_machine=s390-ibm
- ;;
- s390x | s390x-*)
- basic_machine=s390x-ibm
- ;;
- sa29200)
- basic_machine=a29k-amd
- os=-udi
- ;;
- sb1)
- basic_machine=mipsisa64sb1-unknown
- ;;
- sb1el)
- basic_machine=mipsisa64sb1el-unknown
- ;;
- sde)
- basic_machine=mipsisa32-sde
- os=-elf
- ;;
- sei)
- basic_machine=mips-sei
- os=-seiux
- ;;
- sequent)
- basic_machine=i386-sequent
- ;;
- sh)
- basic_machine=sh-hitachi
- os=-hms
- ;;
- sh5el)
- basic_machine=sh5le-unknown
- ;;
- sh64)
- basic_machine=sh64-unknown
- ;;
- sparclite-wrs | simso-wrs)
- basic_machine=sparclite-wrs
- os=-vxworks
- ;;
- sps7)
- basic_machine=m68k-bull
- os=-sysv2
- ;;
- spur)
- basic_machine=spur-unknown
- ;;
- st2000)
- basic_machine=m68k-tandem
- ;;
- stratus)
- basic_machine=i860-stratus
- os=-sysv4
- ;;
- strongarm-* | thumb-*)
- basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'`
- ;;
- sun2)
- basic_machine=m68000-sun
- ;;
- sun2os3)
- basic_machine=m68000-sun
- os=-sunos3
- ;;
- sun2os4)
- basic_machine=m68000-sun
- os=-sunos4
- ;;
- sun3os3)
- basic_machine=m68k-sun
- os=-sunos3
- ;;
- sun3os4)
- basic_machine=m68k-sun
- os=-sunos4
- ;;
- sun4os3)
- basic_machine=sparc-sun
- os=-sunos3
- ;;
- sun4os4)
- basic_machine=sparc-sun
- os=-sunos4
- ;;
- sun4sol2)
- basic_machine=sparc-sun
- os=-solaris2
- ;;
- sun3 | sun3-*)
- basic_machine=m68k-sun
- ;;
- sun4)
- basic_machine=sparc-sun
- ;;
- sun386 | sun386i | roadrunner)
- basic_machine=i386-sun
- ;;
- sv1)
- basic_machine=sv1-cray
- os=-unicos
- ;;
- symmetry)
- basic_machine=i386-sequent
- os=-dynix
- ;;
- t3e)
- basic_machine=alphaev5-cray
- os=-unicos
- ;;
- t90)
- basic_machine=t90-cray
- os=-unicos
- ;;
- tile*)
- basic_machine=$basic_machine-unknown
- os=-linux-gnu
- ;;
- tx39)
- basic_machine=mipstx39-unknown
- ;;
- tx39el)
- basic_machine=mipstx39el-unknown
- ;;
- toad1)
- basic_machine=pdp10-xkl
- os=-tops20
- ;;
- tower | tower-32)
- basic_machine=m68k-ncr
- ;;
- tpf)
- basic_machine=s390x-ibm
- os=-tpf
- ;;
- udi29k)
- basic_machine=a29k-amd
- os=-udi
- ;;
- ultra3)
- basic_machine=a29k-nyu
- os=-sym1
- ;;
- v810 | necv810)
- basic_machine=v810-nec
- os=-none
- ;;
- vaxv)
- basic_machine=vax-dec
- os=-sysv
- ;;
- vms)
- basic_machine=vax-dec
- os=-vms
- ;;
- vpp*|vx|vx-*)
- basic_machine=f301-fujitsu
- ;;
- vxworks960)
- basic_machine=i960-wrs
- os=-vxworks
- ;;
- vxworks68)
- basic_machine=m68k-wrs
- os=-vxworks
- ;;
- vxworks29k)
- basic_machine=a29k-wrs
- os=-vxworks
- ;;
- w65*)
- basic_machine=w65-wdc
- os=-none
- ;;
- w89k-*)
- basic_machine=hppa1.1-winbond
- os=-proelf
- ;;
- xbox)
- basic_machine=i686-pc
- os=-mingw32
- ;;
- xps | xps100)
- basic_machine=xps100-honeywell
- ;;
- xscale-* | xscalee[bl]-*)
- basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'`
- ;;
- ymp)
- basic_machine=ymp-cray
- os=-unicos
- ;;
- z8k-*-coff)
- basic_machine=z8k-unknown
- os=-sim
- ;;
- z80-*-coff)
- basic_machine=z80-unknown
- os=-sim
- ;;
- none)
- basic_machine=none-none
- os=-none
- ;;
-
-# Here we handle the default manufacturer of certain CPU types. It is in
-# some cases the only manufacturer, in others, it is the most popular.
- w89k)
- basic_machine=hppa1.1-winbond
- ;;
- op50n)
- basic_machine=hppa1.1-oki
- ;;
- op60c)
- basic_machine=hppa1.1-oki
- ;;
- romp)
- basic_machine=romp-ibm
- ;;
- mmix)
- basic_machine=mmix-knuth
- ;;
- rs6000)
- basic_machine=rs6000-ibm
- ;;
- vax)
- basic_machine=vax-dec
- ;;
- pdp10)
- # there are many clones, so DEC is not a safe bet
- basic_machine=pdp10-unknown
- ;;
- pdp11)
- basic_machine=pdp11-dec
- ;;
- we32k)
- basic_machine=we32k-att
- ;;
- sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele)
- basic_machine=sh-unknown
- ;;
- sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v)
- basic_machine=sparc-sun
- ;;
- cydra)
- basic_machine=cydra-cydrome
- ;;
- orion)
- basic_machine=orion-highlevel
- ;;
- orion105)
- basic_machine=clipper-highlevel
- ;;
- mac | mpw | mac-mpw)
- basic_machine=m68k-apple
- ;;
- pmac | pmac-mpw)
- basic_machine=powerpc-apple
- ;;
- *-unknown)
- # Make sure to match an already-canonicalized machine name.
- ;;
- *)
- echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
- exit 1
- ;;
-esac
-
-# Here we canonicalize certain aliases for manufacturers.
-case $basic_machine in
- *-digital*)
- basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
- ;;
- *-commodore*)
- basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
- ;;
- *)
- ;;
-esac
-
-# Decode manufacturer-specific aliases for certain operating systems.
-
-if [ x"$os" != x"" ]
-then
-case $os in
- # First match some system type aliases
- # that might get confused with valid system types.
- # -solaris* is a basic system type, with this one exception.
- -auroraux)
- os=-auroraux
- ;;
- -solaris1 | -solaris1.*)
- os=`echo $os | sed -e 's|solaris1|sunos4|'`
- ;;
- -solaris)
- os=-solaris2
- ;;
- -svr4*)
- os=-sysv4
- ;;
- -unixware*)
- os=-sysv4.2uw
- ;;
- -gnu/linux*)
- os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
- ;;
- # First accept the basic system types.
- # The portable systems comes first.
- # Each alternative MUST END IN A *, to match a version number.
- # -sysv* is not here because it comes later, after sysvr4.
- -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
- | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\
- | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \
- | -sym* | -kopensolaris* | -plan9* \
- | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
- | -aos* | -aros* | -cloudabi* | -sortix* \
- | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
- | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
- | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \
- | -bitrig* | -openbsd* | -solidbsd* | -libertybsd* \
- | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \
- | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
- | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
- | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
- | -chorusos* | -chorusrdb* | -cegcc* \
- | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
- | -midipix* | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \
- | -linux-newlib* | -linux-musl* | -linux-uclibc* \
- | -uxpv* | -beos* | -mpeix* | -udk* | -moxiebox* \
- | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
- | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
- | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
- | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
- | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
- | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
- | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* \
- | -onefs* | -tirtos* | -phoenix* | -fuchsia*)
- # Remember, each alternative MUST END IN *, to match a version number.
- ;;
- -qnx*)
- case $basic_machine in
- x86-* | i*86-*)
- ;;
- *)
- os=-nto$os
- ;;
- esac
- ;;
- -nto-qnx*)
- ;;
- -nto*)
- os=`echo $os | sed -e 's|nto|nto-qnx|'`
- ;;
- -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
- | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \
- | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
- ;;
- -mac*)
- os=`echo $os | sed -e 's|mac|macos|'`
- ;;
- -linux-dietlibc)
- os=-linux-dietlibc
- ;;
- -linux*)
- os=`echo $os | sed -e 's|linux|linux-gnu|'`
- ;;
- -sunos5*)
- os=`echo $os | sed -e 's|sunos5|solaris2|'`
- ;;
- -sunos6*)
- os=`echo $os | sed -e 's|sunos6|solaris3|'`
- ;;
- -opened*)
- os=-openedition
- ;;
- -os400*)
- os=-os400
- ;;
- -wince*)
- os=-wince
- ;;
- -osfrose*)
- os=-osfrose
- ;;
- -osf*)
- os=-osf
- ;;
- -utek*)
- os=-bsd
- ;;
- -dynix*)
- os=-bsd
- ;;
- -acis*)
- os=-aos
- ;;
- -atheos*)
- os=-atheos
- ;;
- -syllable*)
- os=-syllable
- ;;
- -386bsd)
- os=-bsd
- ;;
- -ctix* | -uts*)
- os=-sysv
- ;;
- -nova*)
- os=-rtmk-nova
- ;;
- -ns2 )
- os=-nextstep2
- ;;
- -nsk*)
- os=-nsk
- ;;
- # Preserve the version number of sinix5.
- -sinix5.*)
- os=`echo $os | sed -e 's|sinix|sysv|'`
- ;;
- -sinix*)
- os=-sysv4
- ;;
- -tpf*)
- os=-tpf
- ;;
- -triton*)
- os=-sysv3
- ;;
- -oss*)
- os=-sysv3
- ;;
- -svr4)
- os=-sysv4
- ;;
- -svr3)
- os=-sysv3
- ;;
- -sysvr4)
- os=-sysv4
- ;;
- # This must come after -sysvr4.
- -sysv*)
- ;;
- -ose*)
- os=-ose
- ;;
- -es1800*)
- os=-ose
- ;;
- -xenix)
- os=-xenix
- ;;
- -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
- os=-mint
- ;;
- -aros*)
- os=-aros
- ;;
- -zvmoe)
- os=-zvmoe
- ;;
- -dicos*)
- os=-dicos
- ;;
- -nacl*)
- ;;
- -ios)
- ;;
- -none)
- ;;
- *)
- # Get rid of the `-' at the beginning of $os.
- os=`echo $os | sed 's/[^-]*-//'`
- echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
- exit 1
- ;;
-esac
-else
-
-# Here we handle the default operating systems that come with various machines.
-# The value should be what the vendor currently ships out the door with their
-# machine or put another way, the most popular os provided with the machine.
-
-# Note that if you're going to try to match "-MANUFACTURER" here (say,
-# "-sun"), then you have to tell the case statement up towards the top
-# that MANUFACTURER isn't an operating system. Otherwise, code above
-# will signal an error saying that MANUFACTURER isn't an operating
-# system, and we'll never get to this point.
-
-case $basic_machine in
- score-*)
- os=-elf
- ;;
- spu-*)
- os=-elf
- ;;
- *-acorn)
- os=-riscix1.2
- ;;
- arm*-rebel)
- os=-linux
- ;;
- arm*-semi)
- os=-aout
- ;;
- c4x-* | tic4x-*)
- os=-coff
- ;;
- c8051-*)
- os=-elf
- ;;
- hexagon-*)
- os=-elf
- ;;
- tic54x-*)
- os=-coff
- ;;
- tic55x-*)
- os=-coff
- ;;
- tic6x-*)
- os=-coff
- ;;
- # This must come before the *-dec entry.
- pdp10-*)
- os=-tops20
- ;;
- pdp11-*)
- os=-none
- ;;
- *-dec | vax-*)
- os=-ultrix4.2
- ;;
- m68*-apollo)
- os=-domain
- ;;
- i386-sun)
- os=-sunos4.0.2
- ;;
- m68000-sun)
- os=-sunos3
- ;;
- m68*-cisco)
- os=-aout
- ;;
- mep-*)
- os=-elf
- ;;
- mips*-cisco)
- os=-elf
- ;;
- mips*-*)
- os=-elf
- ;;
- or32-*)
- os=-coff
- ;;
- *-tti) # must be before sparc entry or we get the wrong os.
- os=-sysv3
- ;;
- sparc-* | *-sun)
- os=-sunos4.1.1
- ;;
- *-be)
- os=-beos
- ;;
- *-haiku)
- os=-haiku
- ;;
- *-ibm)
- os=-aix
- ;;
- *-knuth)
- os=-mmixware
- ;;
- *-wec)
- os=-proelf
- ;;
- *-winbond)
- os=-proelf
- ;;
- *-oki)
- os=-proelf
- ;;
- *-hp)
- os=-hpux
- ;;
- *-hitachi)
- os=-hiux
- ;;
- i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
- os=-sysv
- ;;
- *-cbm)
- os=-amigaos
- ;;
- *-dg)
- os=-dgux
- ;;
- *-dolphin)
- os=-sysv3
- ;;
- m68k-ccur)
- os=-rtu
- ;;
- m88k-omron*)
- os=-luna
- ;;
- *-next )
- os=-nextstep
- ;;
- *-sequent)
- os=-ptx
- ;;
- *-crds)
- os=-unos
- ;;
- *-ns)
- os=-genix
- ;;
- i370-*)
- os=-mvs
- ;;
- *-next)
- os=-nextstep3
- ;;
- *-gould)
- os=-sysv
- ;;
- *-highlevel)
- os=-bsd
- ;;
- *-encore)
- os=-bsd
- ;;
- *-sgi)
- os=-irix
- ;;
- *-siemens)
- os=-sysv4
- ;;
- *-masscomp)
- os=-rtu
- ;;
- f30[01]-fujitsu | f700-fujitsu)
- os=-uxpv
- ;;
- *-rom68k)
- os=-coff
- ;;
- *-*bug)
- os=-coff
- ;;
- *-apple)
- os=-macos
- ;;
- *-atari*)
- os=-mint
- ;;
- *)
- os=-none
- ;;
-esac
-fi
-
-# Here we handle the case where we know the os, and the CPU type, but not the
-# manufacturer. We pick the logical manufacturer.
-vendor=unknown
-case $basic_machine in
- *-unknown)
- case $os in
- -riscix*)
- vendor=acorn
- ;;
- -sunos*)
- vendor=sun
- ;;
- -cnk*|-aix*)
- vendor=ibm
- ;;
- -beos*)
- vendor=be
- ;;
- -hpux*)
- vendor=hp
- ;;
- -mpeix*)
- vendor=hp
- ;;
- -hiux*)
- vendor=hitachi
- ;;
- -unos*)
- vendor=crds
- ;;
- -dgux*)
- vendor=dg
- ;;
- -luna*)
- vendor=omron
- ;;
- -genix*)
- vendor=ns
- ;;
- -mvs* | -opened*)
- vendor=ibm
- ;;
- -os400*)
- vendor=ibm
- ;;
- -ptx*)
- vendor=sequent
- ;;
- -tpf*)
- vendor=ibm
- ;;
- -vxsim* | -vxworks* | -windiss*)
- vendor=wrs
- ;;
- -aux*)
- vendor=apple
- ;;
- -hms*)
- vendor=hitachi
- ;;
- -mpw* | -macos*)
- vendor=apple
- ;;
- -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
- vendor=atari
- ;;
- -vos*)
- vendor=stratus
- ;;
- esac
- basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
- ;;
-esac
-
-echo $basic_machine$os
-exit
-
-# Local variables:
-# eval: (add-hook 'write-file-hooks 'time-stamp)
-# time-stamp-start: "timestamp='"
-# time-stamp-format: "%:y-%02m-%02d"
-# time-stamp-end: "'"
-# End:
->>>>>>> main
diff --git a/contrib/jemalloc/configure.ac b/contrib/jemalloc/configure.ac
index f7285a6154b9..f6d25f3345ee 100644
--- a/contrib/jemalloc/configure.ac
+++ b/contrib/jemalloc/configure.ac
@@ -1,4 +1,3 @@
-<<<<<<< HEAD
dnl Process this file with autoconf to produce a configure script.
AC_PREREQ(2.68)
AC_INIT([Makefile.in])
@@ -2668,2412 +2667,3 @@ AC_MSG_RESULT([lazy_lock : ${enable_lazy_lock}])
AC_MSG_RESULT([cache-oblivious : ${enable_cache_oblivious}])
AC_MSG_RESULT([cxx : ${enable_cxx}])
AC_MSG_RESULT([===============================================================================])
-||||||| dec341af7695
-=======
-dnl Process this file with autoconf to produce a configure script.
-AC_PREREQ(2.68)
-AC_INIT([Makefile.in])
-
-AC_CONFIG_AUX_DIR([build-aux])
-
-dnl ============================================================================
-dnl Custom macro definitions.
-
-dnl JE_CONCAT_VVV(r, a, b)
-dnl
-dnl Set $r to the concatenation of $a and $b, with a space separating them iff
-dnl both $a and $b are non-empty.
-AC_DEFUN([JE_CONCAT_VVV],
-if test "x[$]{$2}" = "x" -o "x[$]{$3}" = "x" ; then
- $1="[$]{$2}[$]{$3}"
-else
- $1="[$]{$2} [$]{$3}"
-fi
-)
-
-dnl JE_APPEND_VS(a, b)
-dnl
-dnl Set $a to the concatenation of $a and b, with a space separating them iff
-dnl both $a and b are non-empty.
-AC_DEFUN([JE_APPEND_VS],
- T_APPEND_V=$2
- JE_CONCAT_VVV($1, $1, T_APPEND_V)
-)
-
-CONFIGURE_CFLAGS=
-SPECIFIED_CFLAGS="${CFLAGS}"
-dnl JE_CFLAGS_ADD(cflag)
-dnl
-dnl CFLAGS is the concatenation of CONFIGURE_CFLAGS and SPECIFIED_CFLAGS
-dnl (ignoring EXTRA_CFLAGS, which does not impact configure tests. This macro
-dnl appends to CONFIGURE_CFLAGS and regenerates CFLAGS.
-AC_DEFUN([JE_CFLAGS_ADD],
-[
-AC_MSG_CHECKING([whether compiler supports $1])
-T_CONFIGURE_CFLAGS="${CONFIGURE_CFLAGS}"
-JE_APPEND_VS(CONFIGURE_CFLAGS, $1)
-JE_CONCAT_VVV(CFLAGS, CONFIGURE_CFLAGS, SPECIFIED_CFLAGS)
-AC_COMPILE_IFELSE([AC_LANG_PROGRAM(
-[[
-]], [[
- return 0;
-]])],
- [je_cv_cflags_added=$1]
- AC_MSG_RESULT([yes]),
- [je_cv_cflags_added=]
- AC_MSG_RESULT([no])
- [CONFIGURE_CFLAGS="${T_CONFIGURE_CFLAGS}"]
-)
-JE_CONCAT_VVV(CFLAGS, CONFIGURE_CFLAGS, SPECIFIED_CFLAGS)
-])
-
-dnl JE_CFLAGS_SAVE()
-dnl JE_CFLAGS_RESTORE()
-dnl
-dnl Save/restore CFLAGS. Nesting is not supported.
-AC_DEFUN([JE_CFLAGS_SAVE],
-SAVED_CONFIGURE_CFLAGS="${CONFIGURE_CFLAGS}"
-)
-AC_DEFUN([JE_CFLAGS_RESTORE],
-CONFIGURE_CFLAGS="${SAVED_CONFIGURE_CFLAGS}"
-JE_CONCAT_VVV(CFLAGS, CONFIGURE_CFLAGS, SPECIFIED_CFLAGS)
-)
-
-CONFIGURE_CXXFLAGS=
-SPECIFIED_CXXFLAGS="${CXXFLAGS}"
-dnl JE_CXXFLAGS_ADD(cxxflag)
-AC_DEFUN([JE_CXXFLAGS_ADD],
-[
-AC_MSG_CHECKING([whether compiler supports $1])
-T_CONFIGURE_CXXFLAGS="${CONFIGURE_CXXFLAGS}"
-JE_APPEND_VS(CONFIGURE_CXXFLAGS, $1)
-JE_CONCAT_VVV(CXXFLAGS, CONFIGURE_CXXFLAGS, SPECIFIED_CXXFLAGS)
-AC_LANG_PUSH([C++])
-AC_COMPILE_IFELSE([AC_LANG_PROGRAM(
-[[
-]], [[
- return 0;
-]])],
- [je_cv_cxxflags_added=$1]
- AC_MSG_RESULT([yes]),
- [je_cv_cxxflags_added=]
- AC_MSG_RESULT([no])
- [CONFIGURE_CXXFLAGS="${T_CONFIGURE_CXXFLAGS}"]
-)
-AC_LANG_POP([C++])
-JE_CONCAT_VVV(CXXFLAGS, CONFIGURE_CXXFLAGS, SPECIFIED_CXXFLAGS)
-])
-
-dnl JE_COMPILABLE(label, hcode, mcode, rvar)
-dnl
-dnl Use AC_LINK_IFELSE() rather than AC_COMPILE_IFELSE() so that linker errors
-dnl cause failure.
-AC_DEFUN([JE_COMPILABLE],
-[
-AC_CACHE_CHECK([whether $1 is compilable],
- [$4],
- [AC_LINK_IFELSE([AC_LANG_PROGRAM([$2],
- [$3])],
- [$4=yes],
- [$4=no])])
-])
-
-dnl ============================================================================
-
-CONFIG=`echo ${ac_configure_args} | sed -e 's#'"'"'\([^ ]*\)'"'"'#\1#g'`
-AC_SUBST([CONFIG])
-
-dnl Library revision.
-rev=2
-AC_SUBST([rev])
-
-srcroot=$srcdir
-if test "x${srcroot}" = "x." ; then
- srcroot=""
-else
- srcroot="${srcroot}/"
-fi
-AC_SUBST([srcroot])
-abs_srcroot="`cd \"${srcdir}\"; pwd`/"
-AC_SUBST([abs_srcroot])
-
-objroot=""
-AC_SUBST([objroot])
-abs_objroot="`pwd`/"
-AC_SUBST([abs_objroot])
-
-dnl Munge install path variables.
-if test "x$prefix" = "xNONE" ; then
- prefix="/usr/local"
-fi
-if test "x$exec_prefix" = "xNONE" ; then
- exec_prefix=$prefix
-fi
-PREFIX=$prefix
-AC_SUBST([PREFIX])
-BINDIR=`eval echo $bindir`
-BINDIR=`eval echo $BINDIR`
-AC_SUBST([BINDIR])
-INCLUDEDIR=`eval echo $includedir`
-INCLUDEDIR=`eval echo $INCLUDEDIR`
-AC_SUBST([INCLUDEDIR])
-LIBDIR=`eval echo $libdir`
-LIBDIR=`eval echo $LIBDIR`
-AC_SUBST([LIBDIR])
-DATADIR=`eval echo $datadir`
-DATADIR=`eval echo $DATADIR`
-AC_SUBST([DATADIR])
-MANDIR=`eval echo $mandir`
-MANDIR=`eval echo $MANDIR`
-AC_SUBST([MANDIR])
-
-dnl Support for building documentation.
-AC_PATH_PROG([XSLTPROC], [xsltproc], [false], [$PATH])
-if test -d "/usr/share/xml/docbook/stylesheet/docbook-xsl" ; then
- DEFAULT_XSLROOT="/usr/share/xml/docbook/stylesheet/docbook-xsl"
-elif test -d "/usr/share/sgml/docbook/xsl-stylesheets" ; then
- DEFAULT_XSLROOT="/usr/share/sgml/docbook/xsl-stylesheets"
-else
- dnl Documentation building will fail if this default gets used.
- DEFAULT_XSLROOT=""
-fi
-AC_ARG_WITH([xslroot],
- [AS_HELP_STRING([--with-xslroot=<path>], [XSL stylesheet root path])], [
-if test "x$with_xslroot" = "xno" ; then
- XSLROOT="${DEFAULT_XSLROOT}"
-else
- XSLROOT="${with_xslroot}"
-fi
-],
- XSLROOT="${DEFAULT_XSLROOT}"
-)
-if test "x$XSLTPROC" = "xfalse" ; then
- XSLROOT=""
-fi
-AC_SUBST([XSLROOT])
-
-dnl If CFLAGS isn't defined, set CFLAGS to something reasonable. Otherwise,
-dnl just prevent autoconf from molesting CFLAGS.
-CFLAGS=$CFLAGS
-AC_PROG_CC
-
-if test "x$GCC" != "xyes" ; then
- AC_CACHE_CHECK([whether compiler is MSVC],
- [je_cv_msvc],
- [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([],
- [
-#ifndef _MSC_VER
- int fail[-1];
-#endif
-])],
- [je_cv_msvc=yes],
- [je_cv_msvc=no])])
-fi
-
-dnl check if a cray prgenv wrapper compiler is being used
-je_cv_cray_prgenv_wrapper=""
-if test "x${PE_ENV}" != "x" ; then
- case "${CC}" in
- CC|cc)
- je_cv_cray_prgenv_wrapper="yes"
- ;;
- *)
- ;;
- esac
-fi
-
-AC_CACHE_CHECK([whether compiler is cray],
- [je_cv_cray],
- [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([],
- [
-#ifndef _CRAYC
- int fail[-1];
-#endif
-])],
- [je_cv_cray=yes],
- [je_cv_cray=no])])
-
-if test "x${je_cv_cray}" = "xyes" ; then
- AC_CACHE_CHECK([whether cray compiler version is 8.4],
- [je_cv_cray_84],
- [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([],
- [
-#if !(_RELEASE_MAJOR == 8 && _RELEASE_MINOR == 4)
- int fail[-1];
-#endif
-])],
- [je_cv_cray_84=yes],
- [je_cv_cray_84=no])])
-fi
-
-if test "x$GCC" = "xyes" ; then
- JE_CFLAGS_ADD([-std=gnu11])
- if test "x$je_cv_cflags_added" = "x-std=gnu11" ; then
- AC_DEFINE_UNQUOTED([JEMALLOC_HAS_RESTRICT])
- else
- JE_CFLAGS_ADD([-std=gnu99])
- if test "x$je_cv_cflags_added" = "x-std=gnu99" ; then
- AC_DEFINE_UNQUOTED([JEMALLOC_HAS_RESTRICT])
- fi
- fi
- JE_CFLAGS_ADD([-Wall])
- JE_CFLAGS_ADD([-Wextra])
- JE_CFLAGS_ADD([-Wshorten-64-to-32])
- JE_CFLAGS_ADD([-Wsign-compare])
- JE_CFLAGS_ADD([-Wundef])
- JE_CFLAGS_ADD([-Wno-format-zero-length])
- JE_CFLAGS_ADD([-pipe])
- JE_CFLAGS_ADD([-g3])
-elif test "x$je_cv_msvc" = "xyes" ; then
- CC="$CC -nologo"
- JE_CFLAGS_ADD([-Zi])
- JE_CFLAGS_ADD([-MT])
- JE_CFLAGS_ADD([-W3])
- JE_CFLAGS_ADD([-FS])
- JE_APPEND_VS(CPPFLAGS, -I${srcdir}/include/msvc_compat)
-fi
-if test "x$je_cv_cray" = "xyes" ; then
- dnl cray compiler 8.4 has an inlining bug
- if test "x$je_cv_cray_84" = "xyes" ; then
- JE_CFLAGS_ADD([-hipa2])
- JE_CFLAGS_ADD([-hnognu])
- fi
- dnl ignore unreachable code warning
- JE_CFLAGS_ADD([-hnomessage=128])
- dnl ignore redefinition of "malloc", "free", etc warning
- JE_CFLAGS_ADD([-hnomessage=1357])
-fi
-AC_SUBST([CONFIGURE_CFLAGS])
-AC_SUBST([SPECIFIED_CFLAGS])
-AC_SUBST([EXTRA_CFLAGS])
-AC_PROG_CPP
-
-AC_ARG_ENABLE([cxx],
- [AS_HELP_STRING([--disable-cxx], [Disable C++ integration])],
-if test "x$enable_cxx" = "xno" ; then
- enable_cxx="0"
-else
- enable_cxx="1"
-fi
-,
-enable_cxx="1"
-)
-if test "x$enable_cxx" = "x1" ; then
- dnl Require at least c++14, which is the first version to support sized
- dnl deallocation. C++ support is not compiled otherwise.
- m4_include([m4/ax_cxx_compile_stdcxx.m4])
- AX_CXX_COMPILE_STDCXX([14], [noext], [optional])
- if test "x${HAVE_CXX14}" = "x1" ; then
- JE_CXXFLAGS_ADD([-Wall])
- JE_CXXFLAGS_ADD([-Wextra])
- JE_CXXFLAGS_ADD([-g3])
-
- SAVED_LIBS="${LIBS}"
- JE_APPEND_VS(LIBS, -lstdc++)
- JE_COMPILABLE([libstdc++ linkage], [
-#include <stdlib.h>
-], [[
- int *arr = (int *)malloc(sizeof(int) * 42);
- if (arr == NULL)
- return 1;
-]], [je_cv_libstdcxx])
- if test "x${je_cv_libstdcxx}" = "xno" ; then
- LIBS="${SAVED_LIBS}"
- fi
- else
- enable_cxx="0"
- fi
-fi
-AC_SUBST([enable_cxx])
-AC_SUBST([CONFIGURE_CXXFLAGS])
-AC_SUBST([SPECIFIED_CXXFLAGS])
-AC_SUBST([EXTRA_CXXFLAGS])
-
-AC_C_BIGENDIAN([ac_cv_big_endian=1], [ac_cv_big_endian=0])
-if test "x${ac_cv_big_endian}" = "x1" ; then
- AC_DEFINE_UNQUOTED([JEMALLOC_BIG_ENDIAN], [ ])
-fi
-
-if test "x${je_cv_msvc}" = "xyes" -a "x${ac_cv_header_inttypes_h}" = "xno"; then
- JE_APPEND_VS(CPPFLAGS, -I${srcdir}/include/msvc_compat/C99)
-fi
-
-if test "x${je_cv_msvc}" = "xyes" ; then
- LG_SIZEOF_PTR=LG_SIZEOF_PTR_WIN
- AC_MSG_RESULT([Using a predefined value for sizeof(void *): 4 for 32-bit, 8 for 64-bit])
-else
- AC_CHECK_SIZEOF([void *])
- if test "x${ac_cv_sizeof_void_p}" = "x8" ; then
- LG_SIZEOF_PTR=3
- elif test "x${ac_cv_sizeof_void_p}" = "x4" ; then
- LG_SIZEOF_PTR=2
- else
- AC_MSG_ERROR([Unsupported pointer size: ${ac_cv_sizeof_void_p}])
- fi
-fi
-AC_DEFINE_UNQUOTED([LG_SIZEOF_PTR], [$LG_SIZEOF_PTR])
-
-AC_CHECK_SIZEOF([int])
-if test "x${ac_cv_sizeof_int}" = "x8" ; then
- LG_SIZEOF_INT=3
-elif test "x${ac_cv_sizeof_int}" = "x4" ; then
- LG_SIZEOF_INT=2
-else
- AC_MSG_ERROR([Unsupported int size: ${ac_cv_sizeof_int}])
-fi
-AC_DEFINE_UNQUOTED([LG_SIZEOF_INT], [$LG_SIZEOF_INT])
-
-AC_CHECK_SIZEOF([long])
-if test "x${ac_cv_sizeof_long}" = "x8" ; then
- LG_SIZEOF_LONG=3
-elif test "x${ac_cv_sizeof_long}" = "x4" ; then
- LG_SIZEOF_LONG=2
-else
- AC_MSG_ERROR([Unsupported long size: ${ac_cv_sizeof_long}])
-fi
-AC_DEFINE_UNQUOTED([LG_SIZEOF_LONG], [$LG_SIZEOF_LONG])
-
-AC_CHECK_SIZEOF([long long])
-if test "x${ac_cv_sizeof_long_long}" = "x8" ; then
- LG_SIZEOF_LONG_LONG=3
-elif test "x${ac_cv_sizeof_long_long}" = "x4" ; then
- LG_SIZEOF_LONG_LONG=2
-else
- AC_MSG_ERROR([Unsupported long long size: ${ac_cv_sizeof_long_long}])
-fi
-AC_DEFINE_UNQUOTED([LG_SIZEOF_LONG_LONG], [$LG_SIZEOF_LONG_LONG])
-
-AC_CHECK_SIZEOF([intmax_t])
-if test "x${ac_cv_sizeof_intmax_t}" = "x16" ; then
- LG_SIZEOF_INTMAX_T=4
-elif test "x${ac_cv_sizeof_intmax_t}" = "x8" ; then
- LG_SIZEOF_INTMAX_T=3
-elif test "x${ac_cv_sizeof_intmax_t}" = "x4" ; then
- LG_SIZEOF_INTMAX_T=2
-else
- AC_MSG_ERROR([Unsupported intmax_t size: ${ac_cv_sizeof_intmax_t}])
-fi
-AC_DEFINE_UNQUOTED([LG_SIZEOF_INTMAX_T], [$LG_SIZEOF_INTMAX_T])
-
-AC_CANONICAL_HOST
-dnl CPU-specific settings.
-CPU_SPINWAIT=""
-case "${host_cpu}" in
- i686|x86_64)
- HAVE_CPU_SPINWAIT=1
- if test "x${je_cv_msvc}" = "xyes" ; then
- AC_CACHE_VAL([je_cv_pause_msvc],
- [JE_COMPILABLE([pause instruction MSVC], [],
- [[_mm_pause(); return 0;]],
- [je_cv_pause_msvc])])
- if test "x${je_cv_pause_msvc}" = "xyes" ; then
- CPU_SPINWAIT='_mm_pause()'
- fi
- else
- AC_CACHE_VAL([je_cv_pause],
- [JE_COMPILABLE([pause instruction], [],
- [[__asm__ volatile("pause"); return 0;]],
- [je_cv_pause])])
- if test "x${je_cv_pause}" = "xyes" ; then
- CPU_SPINWAIT='__asm__ volatile("pause")'
- fi
- fi
- ;;
- *)
- HAVE_CPU_SPINWAIT=0
- ;;
-esac
-AC_DEFINE_UNQUOTED([HAVE_CPU_SPINWAIT], [$HAVE_CPU_SPINWAIT])
-AC_DEFINE_UNQUOTED([CPU_SPINWAIT], [$CPU_SPINWAIT])
-
-AC_ARG_WITH([lg_vaddr],
- [AS_HELP_STRING([--with-lg-vaddr=<lg-vaddr>], [Number of significant virtual address bits])],
- [LG_VADDR="$with_lg_vaddr"], [LG_VADDR="detect"])
-
-case "${host_cpu}" in
- aarch64)
- if test "x$LG_VADDR" = "xdetect"; then
- AC_MSG_CHECKING([number of significant virtual address bits])
- if test "x${LG_SIZEOF_PTR}" = "x2" ; then
- #aarch64 ILP32
- LG_VADDR=32
- else
- #aarch64 LP64
- LG_VADDR=48
- fi
- AC_MSG_RESULT([$LG_VADDR])
- fi
- ;;
- x86_64)
- if test "x$LG_VADDR" = "xdetect"; then
- AC_CACHE_CHECK([number of significant virtual address bits],
- [je_cv_lg_vaddr],
- AC_RUN_IFELSE([AC_LANG_PROGRAM(
-[[
-#include <stdio.h>
-#ifdef _WIN32
-#include <limits.h>
-#include <intrin.h>
-typedef unsigned __int32 uint32_t;
-#else
-#include <stdint.h>
-#endif
-]], [[
- uint32_t r[[4]];
- uint32_t eax_in = 0x80000008U;
-#ifdef _WIN32
- __cpuid((int *)r, (int)eax_in);
-#else
- asm volatile ("cpuid"
- : "=a" (r[[0]]), "=b" (r[[1]]), "=c" (r[[2]]), "=d" (r[[3]])
- : "a" (eax_in), "c" (0)
- );
-#endif
- uint32_t eax_out = r[[0]];
- uint32_t vaddr = ((eax_out & 0x0000ff00U) >> 8);
- FILE *f = fopen("conftest.out", "w");
- if (f == NULL) {
- return 1;
- }
- if (vaddr > (sizeof(void *) << 3)) {
- vaddr = sizeof(void *) << 3;
- }
- fprintf(f, "%u", vaddr);
- fclose(f);
- return 0;
-]])],
- [je_cv_lg_vaddr=`cat conftest.out`],
- [je_cv_lg_vaddr=error],
- [je_cv_lg_vaddr=57]))
- if test "x${je_cv_lg_vaddr}" != "x" ; then
- LG_VADDR="${je_cv_lg_vaddr}"
- fi
- if test "x${LG_VADDR}" != "xerror" ; then
- AC_DEFINE_UNQUOTED([LG_VADDR], [$LG_VADDR])
- else
- AC_MSG_ERROR([cannot determine number of significant virtual address bits])
- fi
- fi
- ;;
- *)
- if test "x$LG_VADDR" = "xdetect"; then
- AC_MSG_CHECKING([number of significant virtual address bits])
- if test "x${LG_SIZEOF_PTR}" = "x3" ; then
- LG_VADDR=64
- elif test "x${LG_SIZEOF_PTR}" = "x2" ; then
- LG_VADDR=32
- elif test "x${LG_SIZEOF_PTR}" = "xLG_SIZEOF_PTR_WIN" ; then
- LG_VADDR="(1U << (LG_SIZEOF_PTR_WIN+3))"
- else
- AC_MSG_ERROR([Unsupported lg(pointer size): ${LG_SIZEOF_PTR}])
- fi
- AC_MSG_RESULT([$LG_VADDR])
- fi
- ;;
-esac
-AC_DEFINE_UNQUOTED([LG_VADDR], [$LG_VADDR])
-
-LD_PRELOAD_VAR="LD_PRELOAD"
-so="so"
-importlib="${so}"
-o="$ac_objext"
-a="a"
-exe="$ac_exeext"
-libprefix="lib"
-link_whole_archive="0"
-DSO_LDFLAGS='-shared -Wl,-soname,$(@F)'
-RPATH='-Wl,-rpath,$(1)'
-SOREV="${so}.${rev}"
-PIC_CFLAGS='-fPIC -DPIC'
-CTARGET='-o $@'
-LDTARGET='-o $@'
-TEST_LD_MODE=
-EXTRA_LDFLAGS=
-ARFLAGS='crus'
-AROUT=' $@'
-CC_MM=1
-
-if test "x$je_cv_cray_prgenv_wrapper" = "xyes" ; then
- TEST_LD_MODE='-dynamic'
-fi
-
-if test "x${je_cv_cray}" = "xyes" ; then
- CC_MM=
-fi
-
-AN_MAKEVAR([AR], [AC_PROG_AR])
-AN_PROGRAM([ar], [AC_PROG_AR])
-AC_DEFUN([AC_PROG_AR], [AC_CHECK_TOOL(AR, ar, :)])
-AC_PROG_AR
-
-AN_MAKEVAR([NM], [AC_PROG_NM])
-AN_PROGRAM([nm], [AC_PROG_NM])
-AC_DEFUN([AC_PROG_NM], [AC_CHECK_TOOL(NM, nm, :)])
-AC_PROG_NM
-
-AC_PROG_AWK
-
-dnl ============================================================================
-dnl jemalloc version.
-dnl
-
-AC_ARG_WITH([version],
- [AS_HELP_STRING([--with-version=<major>.<minor>.<bugfix>-<nrev>-g<gid>],
- [Version string])],
- [
- echo "${with_version}" | grep ['^[0-9]\+\.[0-9]\+\.[0-9]\+-[0-9]\+-g[0-9a-f]\+$'] 2>&1 1>/dev/null
- if test $? -eq 0 ; then
- echo "$with_version" > "${objroot}VERSION"
- else
- echo "${with_version}" | grep ['^VERSION$'] 2>&1 1>/dev/null
- if test $? -ne 0 ; then
- AC_MSG_ERROR([${with_version} does not match <major>.<minor>.<bugfix>-<nrev>-g<gid> or VERSION])
- fi
- fi
- ], [
- dnl Set VERSION if source directory is inside a git repository.
- if test "x`test ! \"${srcroot}\" && cd \"${srcroot}\"; git rev-parse --is-inside-work-tree 2>/dev/null`" = "xtrue" ; then
- dnl Pattern globs aren't powerful enough to match both single- and
- dnl double-digit version numbers, so iterate over patterns to support up
- dnl to version 99.99.99 without any accidental matches.
- for pattern in ['[0-9].[0-9].[0-9]' '[0-9].[0-9].[0-9][0-9]' \
- '[0-9].[0-9][0-9].[0-9]' '[0-9].[0-9][0-9].[0-9][0-9]' \
- '[0-9][0-9].[0-9].[0-9]' '[0-9][0-9].[0-9].[0-9][0-9]' \
- '[0-9][0-9].[0-9][0-9].[0-9]' \
- '[0-9][0-9].[0-9][0-9].[0-9][0-9]']; do
- (test ! "${srcroot}" && cd "${srcroot}"; git describe --long --abbrev=40 --match="${pattern}") > "${objroot}VERSION.tmp" 2>/dev/null
- if test $? -eq 0 ; then
- mv "${objroot}VERSION.tmp" "${objroot}VERSION"
- break
- fi
- done
- fi
- rm -f "${objroot}VERSION.tmp"
- ])
-
-if test ! -e "${objroot}VERSION" ; then
- if test ! -e "${srcroot}VERSION" ; then
- AC_MSG_RESULT(
- [Missing VERSION file, and unable to generate it; creating bogus VERSION])
- echo "0.0.0-0-g0000000000000000000000000000000000000000" > "${objroot}VERSION"
- else
- cp ${srcroot}VERSION ${objroot}VERSION
- fi
-fi
-jemalloc_version=`cat "${objroot}VERSION"`
-jemalloc_version_major=`echo ${jemalloc_version} | tr ".g-" " " | awk '{print [$]1}'`
-jemalloc_version_minor=`echo ${jemalloc_version} | tr ".g-" " " | awk '{print [$]2}'`
-jemalloc_version_bugfix=`echo ${jemalloc_version} | tr ".g-" " " | awk '{print [$]3}'`
-jemalloc_version_nrev=`echo ${jemalloc_version} | tr ".g-" " " | awk '{print [$]4}'`
-jemalloc_version_gid=`echo ${jemalloc_version} | tr ".g-" " " | awk '{print [$]5}'`
-AC_SUBST([jemalloc_version])
-AC_SUBST([jemalloc_version_major])
-AC_SUBST([jemalloc_version_minor])
-AC_SUBST([jemalloc_version_bugfix])
-AC_SUBST([jemalloc_version_nrev])
-AC_SUBST([jemalloc_version_gid])
-
-dnl Platform-specific settings. abi and RPATH can probably be determined
-dnl programmatically, but doing so is error-prone, which makes it generally
-dnl not worth the trouble.
-dnl
-dnl Define cpp macros in CPPFLAGS, rather than doing AC_DEFINE(macro), since the
-dnl definitions need to be seen before any headers are included, which is a pain
-dnl to make happen otherwise.
-default_retain="0"
-maps_coalesce="1"
-DUMP_SYMS="${NM} -a"
-SYM_PREFIX=""
-case "${host}" in
- *-*-darwin* | *-*-ios*)
- abi="macho"
- RPATH=""
- LD_PRELOAD_VAR="DYLD_INSERT_LIBRARIES"
- so="dylib"
- importlib="${so}"
- force_tls="0"
- DSO_LDFLAGS='-shared -Wl,-install_name,$(LIBDIR)/$(@F)'
- SOREV="${rev}.${so}"
- sbrk_deprecated="1"
- SYM_PREFIX="_"
- ;;
- *-*-freebsd*)
- abi="elf"
- AC_DEFINE([JEMALLOC_SYSCTL_VM_OVERCOMMIT], [ ])
- force_lazy_lock="1"
- ;;
- *-*-dragonfly*)
- abi="elf"
- ;;
- *-*-openbsd*)
- abi="elf"
- force_tls="0"
- ;;
- *-*-bitrig*)
- abi="elf"
- ;;
- *-*-linux-android)
- dnl syscall(2) and secure_getenv(3) are exposed by _GNU_SOURCE.
- JE_APPEND_VS(CPPFLAGS, -D_GNU_SOURCE)
- abi="elf"
- AC_DEFINE([JEMALLOC_PURGE_MADVISE_DONTNEED_ZEROS], [ ])
- AC_DEFINE([JEMALLOC_HAS_ALLOCA_H])
- AC_DEFINE([JEMALLOC_PROC_SYS_VM_OVERCOMMIT_MEMORY], [ ])
- AC_DEFINE([JEMALLOC_THREADED_INIT], [ ])
- AC_DEFINE([JEMALLOC_C11_ATOMICS])
- force_tls="0"
- if test "${LG_SIZEOF_PTR}" = "3"; then
- default_retain="1"
- fi
- ;;
- *-*-linux*)
- dnl syscall(2) and secure_getenv(3) are exposed by _GNU_SOURCE.
- JE_APPEND_VS(CPPFLAGS, -D_GNU_SOURCE)
- abi="elf"
- AC_DEFINE([JEMALLOC_PURGE_MADVISE_DONTNEED_ZEROS], [ ])
- AC_DEFINE([JEMALLOC_HAS_ALLOCA_H])
- AC_DEFINE([JEMALLOC_PROC_SYS_VM_OVERCOMMIT_MEMORY], [ ])
- AC_DEFINE([JEMALLOC_THREADED_INIT], [ ])
- AC_DEFINE([JEMALLOC_USE_CXX_THROW], [ ])
- if test "${LG_SIZEOF_PTR}" = "3"; then
- default_retain="1"
- fi
- ;;
- *-*-kfreebsd*)
- dnl syscall(2) and secure_getenv(3) are exposed by _GNU_SOURCE.
- JE_APPEND_VS(CPPFLAGS, -D_GNU_SOURCE)
- abi="elf"
- AC_DEFINE([JEMALLOC_HAS_ALLOCA_H])
- AC_DEFINE([JEMALLOC_SYSCTL_VM_OVERCOMMIT], [ ])
- AC_DEFINE([JEMALLOC_THREADED_INIT], [ ])
- AC_DEFINE([JEMALLOC_USE_CXX_THROW], [ ])
- ;;
- *-*-netbsd*)
- AC_MSG_CHECKING([ABI])
- AC_COMPILE_IFELSE([AC_LANG_PROGRAM(
-[[#ifdef __ELF__
-/* ELF */
-#else
-#error aout
-#endif
-]])],
- [abi="elf"],
- [abi="aout"])
- AC_MSG_RESULT([$abi])
- ;;
- *-*-solaris2*)
- abi="elf"
- RPATH='-Wl,-R,$(1)'
- dnl Solaris needs this for sigwait().
- JE_APPEND_VS(CPPFLAGS, -D_POSIX_PTHREAD_SEMANTICS)
- JE_APPEND_VS(LIBS, -lposix4 -lsocket -lnsl)
- ;;
- *-ibm-aix*)
- if test "${LG_SIZEOF_PTR}" = "3"; then
- dnl 64bit AIX
- LD_PRELOAD_VAR="LDR_PRELOAD64"
- else
- dnl 32bit AIX
- LD_PRELOAD_VAR="LDR_PRELOAD"
- fi
- abi="xcoff"
- ;;
- *-*-mingw* | *-*-cygwin*)
- abi="pecoff"
- force_tls="0"
- maps_coalesce="0"
- RPATH=""
- so="dll"
- if test "x$je_cv_msvc" = "xyes" ; then
- importlib="lib"
- DSO_LDFLAGS="-LD"
- EXTRA_LDFLAGS="-link -DEBUG"
- CTARGET='-Fo$@'
- LDTARGET='-Fe$@'
- AR='lib'
- ARFLAGS='-nologo -out:'
- AROUT='$@'
- CC_MM=
- else
- importlib="${so}"
- DSO_LDFLAGS="-shared"
- link_whole_archive="1"
- fi
- case "${host}" in
- *-*-cygwin*)
- DUMP_SYMS="dumpbin /SYMBOLS"
- ;;
- *)
- ;;
- esac
- a="lib"
- libprefix=""
- SOREV="${so}"
- PIC_CFLAGS=""
- if test "${LG_SIZEOF_PTR}" = "3"; then
- default_retain="1"
- fi
- ;;
- *)
- AC_MSG_RESULT([Unsupported operating system: ${host}])
- abi="elf"
- ;;
-esac
-
-JEMALLOC_USABLE_SIZE_CONST=const
-AC_CHECK_HEADERS([malloc.h], [
- AC_MSG_CHECKING([whether malloc_usable_size definition can use const argument])
- AC_COMPILE_IFELSE([AC_LANG_PROGRAM(
- [#include <malloc.h>
- #include <stddef.h>
- size_t malloc_usable_size(const void *ptr);
- ],
- [])],[
- AC_MSG_RESULT([yes])
- ],[
- JEMALLOC_USABLE_SIZE_CONST=
- AC_MSG_RESULT([no])
- ])
-])
-AC_DEFINE_UNQUOTED([JEMALLOC_USABLE_SIZE_CONST], [$JEMALLOC_USABLE_SIZE_CONST])
-AC_SUBST([abi])
-AC_SUBST([RPATH])
-AC_SUBST([LD_PRELOAD_VAR])
-AC_SUBST([so])
-AC_SUBST([importlib])
-AC_SUBST([o])
-AC_SUBST([a])
-AC_SUBST([exe])
-AC_SUBST([libprefix])
-AC_SUBST([link_whole_archive])
-AC_SUBST([DSO_LDFLAGS])
-AC_SUBST([EXTRA_LDFLAGS])
-AC_SUBST([SOREV])
-AC_SUBST([PIC_CFLAGS])
-AC_SUBST([CTARGET])
-AC_SUBST([LDTARGET])
-AC_SUBST([TEST_LD_MODE])
-AC_SUBST([MKLIB])
-AC_SUBST([ARFLAGS])
-AC_SUBST([AROUT])
-AC_SUBST([DUMP_SYMS])
-AC_SUBST([CC_MM])
-
-dnl Determine whether libm must be linked to use e.g. log(3).
-AC_SEARCH_LIBS([log], [m], , [AC_MSG_ERROR([Missing math functions])])
-if test "x$ac_cv_search_log" != "xnone required" ; then
- LM="$ac_cv_search_log"
-else
- LM=
-fi
-AC_SUBST(LM)
-
-JE_COMPILABLE([__attribute__ syntax],
- [static __attribute__((unused)) void foo(void){}],
- [],
- [je_cv_attribute])
-if test "x${je_cv_attribute}" = "xyes" ; then
- AC_DEFINE([JEMALLOC_HAVE_ATTR], [ ])
- if test "x${GCC}" = "xyes" -a "x${abi}" = "xelf"; then
- JE_CFLAGS_ADD([-fvisibility=hidden])
- JE_CXXFLAGS_ADD([-fvisibility=hidden])
- fi
-fi
-dnl Check for tls_model attribute support (clang 3.0 still lacks support).
-JE_CFLAGS_SAVE()
-JE_CFLAGS_ADD([-Werror])
-JE_CFLAGS_ADD([-herror_on_warning])
-JE_COMPILABLE([tls_model attribute], [],
- [static __thread int
- __attribute__((tls_model("initial-exec"), unused)) foo;
- foo = 0;],
- [je_cv_tls_model])
-JE_CFLAGS_RESTORE()
-dnl (Setting of JEMALLOC_TLS_MODEL is done later, after we've checked for
-dnl --disable-initial-exec-tls)
-
-dnl Check for alloc_size attribute support.
-JE_CFLAGS_SAVE()
-JE_CFLAGS_ADD([-Werror])
-JE_CFLAGS_ADD([-herror_on_warning])
-JE_COMPILABLE([alloc_size attribute], [#include <stdlib.h>],
- [void *foo(size_t size) __attribute__((alloc_size(1)));],
- [je_cv_alloc_size])
-JE_CFLAGS_RESTORE()
-if test "x${je_cv_alloc_size}" = "xyes" ; then
- AC_DEFINE([JEMALLOC_HAVE_ATTR_ALLOC_SIZE], [ ])
-fi
-dnl Check for format(gnu_printf, ...) attribute support.
-JE_CFLAGS_SAVE()
-JE_CFLAGS_ADD([-Werror])
-JE_CFLAGS_ADD([-herror_on_warning])
-JE_COMPILABLE([format(gnu_printf, ...) attribute], [#include <stdlib.h>],
- [void *foo(const char *format, ...) __attribute__((format(gnu_printf, 1, 2)));],
- [je_cv_format_gnu_printf])
-JE_CFLAGS_RESTORE()
-if test "x${je_cv_format_gnu_printf}" = "xyes" ; then
- AC_DEFINE([JEMALLOC_HAVE_ATTR_FORMAT_GNU_PRINTF], [ ])
-fi
-dnl Check for format(printf, ...) attribute support.
-JE_CFLAGS_SAVE()
-JE_CFLAGS_ADD([-Werror])
-JE_CFLAGS_ADD([-herror_on_warning])
-JE_COMPILABLE([format(printf, ...) attribute], [#include <stdlib.h>],
- [void *foo(const char *format, ...) __attribute__((format(printf, 1, 2)));],
- [je_cv_format_printf])
-JE_CFLAGS_RESTORE()
-if test "x${je_cv_format_printf}" = "xyes" ; then
- AC_DEFINE([JEMALLOC_HAVE_ATTR_FORMAT_PRINTF], [ ])
-fi
-
-dnl Check for format_arg(...) attribute support.
-JE_CFLAGS_SAVE()
-JE_CFLAGS_ADD([-Werror])
-JE_CFLAGS_ADD([-herror_on_warning])
-JE_COMPILABLE([format(printf, ...) attribute], [#include <stdlib.h>],
- [const char * __attribute__((__format_arg__(1))) foo(const char *format);],
- [je_cv_format_arg])
-JE_CFLAGS_RESTORE()
-if test "x${je_cv_format_arg}" = "xyes" ; then
- AC_DEFINE([JEMALLOC_HAVE_ATTR_FORMAT_ARG], [ ])
-fi
-
-dnl Support optional additions to rpath.
-AC_ARG_WITH([rpath],
- [AS_HELP_STRING([--with-rpath=<rpath>], [Colon-separated rpath (ELF systems only)])],
-if test "x$with_rpath" = "xno" ; then
- RPATH_EXTRA=
-else
- RPATH_EXTRA="`echo $with_rpath | tr \":\" \" \"`"
-fi,
- RPATH_EXTRA=
-)
-AC_SUBST([RPATH_EXTRA])
-
-dnl Disable rules that do automatic regeneration of configure output by default.
-AC_ARG_ENABLE([autogen],
- [AS_HELP_STRING([--enable-autogen], [Automatically regenerate configure output])],
-if test "x$enable_autogen" = "xno" ; then
- enable_autogen="0"
-else
- enable_autogen="1"
-fi
-,
-enable_autogen="0"
-)
-AC_SUBST([enable_autogen])
-
-AC_PROG_INSTALL
-AC_PROG_RANLIB
-AC_PATH_PROG([LD], [ld], [false], [$PATH])
-AC_PATH_PROG([AUTOCONF], [autoconf], [false], [$PATH])
-
-dnl Enable documentation
-AC_ARG_ENABLE([doc],
- [AS_HELP_STRING([--enable-documentation], [Build documentation])],
-if test "x$enable_doc" = "xno" ; then
- enable_doc="0"
-else
- enable_doc="1"
-fi
-,
-enable_doc="1"
-)
-AC_SUBST([enable_doc])
-
-dnl Enable shared libs
-AC_ARG_ENABLE([shared],
- [AS_HELP_STRING([--enable-shared], [Build shared libaries])],
-if test "x$enable_shared" = "xno" ; then
- enable_shared="0"
-else
- enable_shared="1"
-fi
-,
-enable_shared="1"
-)
-AC_SUBST([enable_shared])
-
-dnl Enable static libs
-AC_ARG_ENABLE([static],
- [AS_HELP_STRING([--enable-static], [Build static libaries])],
-if test "x$enable_static" = "xno" ; then
- enable_static="0"
-else
- enable_static="1"
-fi
-,
-enable_static="1"
-)
-AC_SUBST([enable_static])
-
-if test "$enable_shared$enable_static" = "00" ; then
- AC_MSG_ERROR([Please enable one of shared or static builds])
-fi
-
-dnl Perform no name mangling by default.
-AC_ARG_WITH([mangling],
- [AS_HELP_STRING([--with-mangling=<map>], [Mangle symbols in <map>])],
- [mangling_map="$with_mangling"], [mangling_map=""])
-
-dnl Do not prefix public APIs by default.
-AC_ARG_WITH([jemalloc_prefix],
- [AS_HELP_STRING([--with-jemalloc-prefix=<prefix>], [Prefix to prepend to all public APIs])],
- [JEMALLOC_PREFIX="$with_jemalloc_prefix"],
- [if test "x$abi" != "xmacho" -a "x$abi" != "xpecoff"; then
- JEMALLOC_PREFIX=""
-else
- JEMALLOC_PREFIX="je_"
-fi]
-)
-if test "x$JEMALLOC_PREFIX" = "x" ; then
- AC_DEFINE([JEMALLOC_IS_MALLOC])
-else
- JEMALLOC_CPREFIX=`echo ${JEMALLOC_PREFIX} | tr "a-z" "A-Z"`
- AC_DEFINE_UNQUOTED([JEMALLOC_PREFIX], ["$JEMALLOC_PREFIX"])
- AC_DEFINE_UNQUOTED([JEMALLOC_CPREFIX], ["$JEMALLOC_CPREFIX"])
-fi
-AC_SUBST([JEMALLOC_PREFIX])
-AC_SUBST([JEMALLOC_CPREFIX])
-
-AC_ARG_WITH([export],
- [AS_HELP_STRING([--without-export], [disable exporting jemalloc public APIs])],
- [if test "x$with_export" = "xno"; then
- AC_DEFINE([JEMALLOC_EXPORT],[])
-fi]
-)
-
-public_syms="aligned_alloc calloc dallocx free mallctl mallctlbymib mallctlnametomib malloc malloc_conf malloc_message malloc_stats_print malloc_usable_size mallocx smallocx_${jemalloc_version_gid} nallocx posix_memalign rallocx realloc sallocx sdallocx xallocx"
-dnl Check for additional platform-specific public API functions.
-AC_CHECK_FUNC([memalign],
- [AC_DEFINE([JEMALLOC_OVERRIDE_MEMALIGN], [ ])
- public_syms="${public_syms} memalign"])
-AC_CHECK_FUNC([valloc],
- [AC_DEFINE([JEMALLOC_OVERRIDE_VALLOC], [ ])
- public_syms="${public_syms} valloc"])
-
-dnl Check for allocator-related functions that should be wrapped.
-wrap_syms=
-if test "x${JEMALLOC_PREFIX}" = "x" ; then
- AC_CHECK_FUNC([__libc_calloc],
- [AC_DEFINE([JEMALLOC_OVERRIDE___LIBC_CALLOC], [ ])
- wrap_syms="${wrap_syms} __libc_calloc"])
- AC_CHECK_FUNC([__libc_free],
- [AC_DEFINE([JEMALLOC_OVERRIDE___LIBC_FREE], [ ])
- wrap_syms="${wrap_syms} __libc_free"])
- AC_CHECK_FUNC([__libc_malloc],
- [AC_DEFINE([JEMALLOC_OVERRIDE___LIBC_MALLOC], [ ])
- wrap_syms="${wrap_syms} __libc_malloc"])
- AC_CHECK_FUNC([__libc_memalign],
- [AC_DEFINE([JEMALLOC_OVERRIDE___LIBC_MEMALIGN], [ ])
- wrap_syms="${wrap_syms} __libc_memalign"])
- AC_CHECK_FUNC([__libc_realloc],
- [AC_DEFINE([JEMALLOC_OVERRIDE___LIBC_REALLOC], [ ])
- wrap_syms="${wrap_syms} __libc_realloc"])
- AC_CHECK_FUNC([__libc_valloc],
- [AC_DEFINE([JEMALLOC_OVERRIDE___LIBC_VALLOC], [ ])
- wrap_syms="${wrap_syms} __libc_valloc"])
- AC_CHECK_FUNC([__posix_memalign],
- [AC_DEFINE([JEMALLOC_OVERRIDE___POSIX_MEMALIGN], [ ])
- wrap_syms="${wrap_syms} __posix_memalign"])
-fi
-
-case "${host}" in
- *-*-mingw* | *-*-cygwin*)
- wrap_syms="${wrap_syms} tls_callback"
- ;;
- *)
- ;;
-esac
-
-dnl Mangle library-private APIs.
-AC_ARG_WITH([private_namespace],
- [AS_HELP_STRING([--with-private-namespace=<prefix>], [Prefix to prepend to all library-private APIs])],
- [JEMALLOC_PRIVATE_NAMESPACE="${with_private_namespace}je_"],
- [JEMALLOC_PRIVATE_NAMESPACE="je_"]
-)
-AC_DEFINE_UNQUOTED([JEMALLOC_PRIVATE_NAMESPACE], [$JEMALLOC_PRIVATE_NAMESPACE])
-private_namespace="$JEMALLOC_PRIVATE_NAMESPACE"
-AC_SUBST([private_namespace])
-
-dnl Do not add suffix to installed files by default.
-AC_ARG_WITH([install_suffix],
- [AS_HELP_STRING([--with-install-suffix=<suffix>], [Suffix to append to all installed files])],
- [INSTALL_SUFFIX="$with_install_suffix"],
- [INSTALL_SUFFIX=]
-)
-install_suffix="$INSTALL_SUFFIX"
-AC_SUBST([install_suffix])
-
-dnl Specify default malloc_conf.
-AC_ARG_WITH([malloc_conf],
- [AS_HELP_STRING([--with-malloc-conf=<malloc_conf>], [config.malloc_conf options string])],
- [JEMALLOC_CONFIG_MALLOC_CONF="$with_malloc_conf"],
- [JEMALLOC_CONFIG_MALLOC_CONF=""]
-)
-config_malloc_conf="$JEMALLOC_CONFIG_MALLOC_CONF"
-AC_DEFINE_UNQUOTED([JEMALLOC_CONFIG_MALLOC_CONF], ["$config_malloc_conf"])
-
-dnl Substitute @je_@ in jemalloc_protos.h.in, primarily to make generation of
-dnl jemalloc_protos_jet.h easy.
-je_="je_"
-AC_SUBST([je_])
-
-cfgoutputs_in="Makefile.in"
-cfgoutputs_in="${cfgoutputs_in} jemalloc.pc.in"
-cfgoutputs_in="${cfgoutputs_in} doc/html.xsl.in"
-cfgoutputs_in="${cfgoutputs_in} doc/manpages.xsl.in"
-cfgoutputs_in="${cfgoutputs_in} doc/jemalloc.xml.in"
-cfgoutputs_in="${cfgoutputs_in} include/jemalloc/jemalloc_macros.h.in"
-cfgoutputs_in="${cfgoutputs_in} include/jemalloc/jemalloc_protos.h.in"
-cfgoutputs_in="${cfgoutputs_in} include/jemalloc/jemalloc_typedefs.h.in"
-cfgoutputs_in="${cfgoutputs_in} include/jemalloc/internal/jemalloc_preamble.h.in"
-cfgoutputs_in="${cfgoutputs_in} test/test.sh.in"
-cfgoutputs_in="${cfgoutputs_in} test/include/test/jemalloc_test.h.in"
-
-cfgoutputs_out="Makefile"
-cfgoutputs_out="${cfgoutputs_out} jemalloc.pc"
-cfgoutputs_out="${cfgoutputs_out} doc/html.xsl"
-cfgoutputs_out="${cfgoutputs_out} doc/manpages.xsl"
-cfgoutputs_out="${cfgoutputs_out} doc/jemalloc.xml"
-cfgoutputs_out="${cfgoutputs_out} include/jemalloc/jemalloc_macros.h"
-cfgoutputs_out="${cfgoutputs_out} include/jemalloc/jemalloc_protos.h"
-cfgoutputs_out="${cfgoutputs_out} include/jemalloc/jemalloc_typedefs.h"
-cfgoutputs_out="${cfgoutputs_out} include/jemalloc/internal/jemalloc_preamble.h"
-cfgoutputs_out="${cfgoutputs_out} test/test.sh"
-cfgoutputs_out="${cfgoutputs_out} test/include/test/jemalloc_test.h"
-
-cfgoutputs_tup="Makefile"
-cfgoutputs_tup="${cfgoutputs_tup} jemalloc.pc:jemalloc.pc.in"
-cfgoutputs_tup="${cfgoutputs_tup} doc/html.xsl:doc/html.xsl.in"
-cfgoutputs_tup="${cfgoutputs_tup} doc/manpages.xsl:doc/manpages.xsl.in"
-cfgoutputs_tup="${cfgoutputs_tup} doc/jemalloc.xml:doc/jemalloc.xml.in"
-cfgoutputs_tup="${cfgoutputs_tup} include/jemalloc/jemalloc_macros.h:include/jemalloc/jemalloc_macros.h.in"
-cfgoutputs_tup="${cfgoutputs_tup} include/jemalloc/jemalloc_protos.h:include/jemalloc/jemalloc_protos.h.in"
-cfgoutputs_tup="${cfgoutputs_tup} include/jemalloc/jemalloc_typedefs.h:include/jemalloc/jemalloc_typedefs.h.in"
-cfgoutputs_tup="${cfgoutputs_tup} include/jemalloc/internal/jemalloc_preamble.h"
-cfgoutputs_tup="${cfgoutputs_tup} test/test.sh:test/test.sh.in"
-cfgoutputs_tup="${cfgoutputs_tup} test/include/test/jemalloc_test.h:test/include/test/jemalloc_test.h.in"
-
-cfghdrs_in="include/jemalloc/jemalloc_defs.h.in"
-cfghdrs_in="${cfghdrs_in} include/jemalloc/internal/jemalloc_internal_defs.h.in"
-cfghdrs_in="${cfghdrs_in} include/jemalloc/internal/private_symbols.sh"
-cfghdrs_in="${cfghdrs_in} include/jemalloc/internal/private_namespace.sh"
-cfghdrs_in="${cfghdrs_in} include/jemalloc/internal/public_namespace.sh"
-cfghdrs_in="${cfghdrs_in} include/jemalloc/internal/public_unnamespace.sh"
-cfghdrs_in="${cfghdrs_in} include/jemalloc/jemalloc_rename.sh"
-cfghdrs_in="${cfghdrs_in} include/jemalloc/jemalloc_mangle.sh"
-cfghdrs_in="${cfghdrs_in} include/jemalloc/jemalloc.sh"
-cfghdrs_in="${cfghdrs_in} test/include/test/jemalloc_test_defs.h.in"
-
-cfghdrs_out="include/jemalloc/jemalloc_defs.h"
-cfghdrs_out="${cfghdrs_out} include/jemalloc/jemalloc${install_suffix}.h"
-cfghdrs_out="${cfghdrs_out} include/jemalloc/internal/private_symbols.awk"
-cfghdrs_out="${cfghdrs_out} include/jemalloc/internal/private_symbols_jet.awk"
-cfghdrs_out="${cfghdrs_out} include/jemalloc/internal/public_symbols.txt"
-cfghdrs_out="${cfghdrs_out} include/jemalloc/internal/public_namespace.h"
-cfghdrs_out="${cfghdrs_out} include/jemalloc/internal/public_unnamespace.h"
-cfghdrs_out="${cfghdrs_out} include/jemalloc/jemalloc_protos_jet.h"
-cfghdrs_out="${cfghdrs_out} include/jemalloc/jemalloc_rename.h"
-cfghdrs_out="${cfghdrs_out} include/jemalloc/jemalloc_mangle.h"
-cfghdrs_out="${cfghdrs_out} include/jemalloc/jemalloc_mangle_jet.h"
-cfghdrs_out="${cfghdrs_out} include/jemalloc/internal/jemalloc_internal_defs.h"
-cfghdrs_out="${cfghdrs_out} test/include/test/jemalloc_test_defs.h"
-
-cfghdrs_tup="include/jemalloc/jemalloc_defs.h:include/jemalloc/jemalloc_defs.h.in"
-cfghdrs_tup="${cfghdrs_tup} include/jemalloc/internal/jemalloc_internal_defs.h:include/jemalloc/internal/jemalloc_internal_defs.h.in"
-cfghdrs_tup="${cfghdrs_tup} test/include/test/jemalloc_test_defs.h:test/include/test/jemalloc_test_defs.h.in"
-
-dnl ============================================================================
-dnl jemalloc build options.
-dnl
-
-dnl Do not compile with debugging by default.
-AC_ARG_ENABLE([debug],
- [AS_HELP_STRING([--enable-debug],
- [Build debugging code])],
-[if test "x$enable_debug" = "xno" ; then
- enable_debug="0"
-else
- enable_debug="1"
-fi
-],
-[enable_debug="0"]
-)
-if test "x$enable_debug" = "x1" ; then
- AC_DEFINE([JEMALLOC_DEBUG], [ ])
-fi
-if test "x$enable_debug" = "x1" ; then
- AC_DEFINE([JEMALLOC_DEBUG], [ ])
-fi
-AC_SUBST([enable_debug])
-
-dnl Only optimize if not debugging.
-if test "x$enable_debug" = "x0" ; then
- if test "x$GCC" = "xyes" ; then
- JE_CFLAGS_ADD([-O3])
- JE_CXXFLAGS_ADD([-O3])
- JE_CFLAGS_ADD([-funroll-loops])
- elif test "x$je_cv_msvc" = "xyes" ; then
- JE_CFLAGS_ADD([-O2])
- JE_CXXFLAGS_ADD([-O2])
- else
- JE_CFLAGS_ADD([-O])
- JE_CXXFLAGS_ADD([-O])
- fi
-fi
-
-dnl Enable statistics calculation by default.
-AC_ARG_ENABLE([stats],
- [AS_HELP_STRING([--disable-stats],
- [Disable statistics calculation/reporting])],
-[if test "x$enable_stats" = "xno" ; then
- enable_stats="0"
-else
- enable_stats="1"
-fi
-],
-[enable_stats="1"]
-)
-if test "x$enable_stats" = "x1" ; then
- AC_DEFINE([JEMALLOC_STATS], [ ])
-fi
-AC_SUBST([enable_stats])
-
-dnl Do not enable smallocx by default.
-AC_ARG_ENABLE([experimental_smallocx],
- [AS_HELP_STRING([--enable-experimental-smallocx], [Enable experimental smallocx API])],
-[if test "x$enable_experimental_smallocx" = "xno" ; then
-enable_experimental_smallocx="0"
-else
-enable_experimental_smallocx="1"
-fi
-],
-[enable_experimental_smallocx="0"]
-)
-if test "x$enable_experimental_smallocx" = "x1" ; then
- AC_DEFINE([JEMALLOC_EXPERIMENTAL_SMALLOCX_API])
-fi
-AC_SUBST([enable_experimental_smallocx])
-
-dnl Do not enable profiling by default.
-AC_ARG_ENABLE([prof],
- [AS_HELP_STRING([--enable-prof], [Enable allocation profiling])],
-[if test "x$enable_prof" = "xno" ; then
- enable_prof="0"
-else
- enable_prof="1"
-fi
-],
-[enable_prof="0"]
-)
-if test "x$enable_prof" = "x1" ; then
- backtrace_method=""
-else
- backtrace_method="N/A"
-fi
-
-AC_ARG_ENABLE([prof-libunwind],
- [AS_HELP_STRING([--enable-prof-libunwind], [Use libunwind for backtracing])],
-[if test "x$enable_prof_libunwind" = "xno" ; then
- enable_prof_libunwind="0"
-else
- enable_prof_libunwind="1"
-fi
-],
-[enable_prof_libunwind="0"]
-)
-AC_ARG_WITH([static_libunwind],
- [AS_HELP_STRING([--with-static-libunwind=<libunwind.a>],
- [Path to static libunwind library; use rather than dynamically linking])],
-if test "x$with_static_libunwind" = "xno" ; then
- LUNWIND="-lunwind"
-else
- if test ! -f "$with_static_libunwind" ; then
- AC_MSG_ERROR([Static libunwind not found: $with_static_libunwind])
- fi
- LUNWIND="$with_static_libunwind"
-fi,
- LUNWIND="-lunwind"
-)
-if test "x$backtrace_method" = "x" -a "x$enable_prof_libunwind" = "x1" ; then
- AC_CHECK_HEADERS([libunwind.h], , [enable_prof_libunwind="0"])
- if test "x$LUNWIND" = "x-lunwind" ; then
- AC_CHECK_LIB([unwind], [unw_backtrace], [JE_APPEND_VS(LIBS, $LUNWIND)],
- [enable_prof_libunwind="0"])
- else
- JE_APPEND_VS(LIBS, $LUNWIND)
- fi
- if test "x${enable_prof_libunwind}" = "x1" ; then
- backtrace_method="libunwind"
- AC_DEFINE([JEMALLOC_PROF_LIBUNWIND], [ ])
- fi
-fi
-
-AC_ARG_ENABLE([prof-libgcc],
- [AS_HELP_STRING([--disable-prof-libgcc],
- [Do not use libgcc for backtracing])],
-[if test "x$enable_prof_libgcc" = "xno" ; then
- enable_prof_libgcc="0"
-else
- enable_prof_libgcc="1"
-fi
-],
-[enable_prof_libgcc="1"]
-)
-if test "x$backtrace_method" = "x" -a "x$enable_prof_libgcc" = "x1" \
- -a "x$GCC" = "xyes" ; then
- AC_CHECK_HEADERS([unwind.h], , [enable_prof_libgcc="0"])
- if test "x${enable_prof_libgcc}" = "x1" ; then
- AC_CHECK_LIB([gcc], [_Unwind_Backtrace], [JE_APPEND_VS(LIBS, -lgcc)], [enable_prof_libgcc="0"])
- fi
- if test "x${enable_prof_libgcc}" = "x1" ; then
- backtrace_method="libgcc"
- AC_DEFINE([JEMALLOC_PROF_LIBGCC], [ ])
- fi
-else
- enable_prof_libgcc="0"
-fi
-
-AC_ARG_ENABLE([prof-gcc],
- [AS_HELP_STRING([--disable-prof-gcc],
- [Do not use gcc intrinsics for backtracing])],
-[if test "x$enable_prof_gcc" = "xno" ; then
- enable_prof_gcc="0"
-else
- enable_prof_gcc="1"
-fi
-],
-[enable_prof_gcc="1"]
-)
-if test "x$backtrace_method" = "x" -a "x$enable_prof_gcc" = "x1" \
- -a "x$GCC" = "xyes" ; then
- JE_CFLAGS_ADD([-fno-omit-frame-pointer])
- backtrace_method="gcc intrinsics"
- AC_DEFINE([JEMALLOC_PROF_GCC], [ ])
-else
- enable_prof_gcc="0"
-fi
-
-if test "x$backtrace_method" = "x" ; then
- backtrace_method="none (disabling profiling)"
- enable_prof="0"
-fi
-AC_MSG_CHECKING([configured backtracing method])
-AC_MSG_RESULT([$backtrace_method])
-if test "x$enable_prof" = "x1" ; then
- dnl Heap profiling uses the log(3) function.
- JE_APPEND_VS(LIBS, $LM)
-
- AC_DEFINE([JEMALLOC_PROF], [ ])
-fi
-AC_SUBST([enable_prof])
-
-dnl Indicate whether adjacent virtual memory mappings automatically coalesce
-dnl (and fragment on demand).
-if test "x${maps_coalesce}" = "x1" ; then
- AC_DEFINE([JEMALLOC_MAPS_COALESCE], [ ])
-fi
-
-dnl Indicate whether to retain memory (rather than using munmap()) by default.
-if test "x$default_retain" = "x1" ; then
- AC_DEFINE([JEMALLOC_RETAIN], [ ])
-fi
-
-dnl Enable allocation from DSS if supported by the OS.
-have_dss="1"
-dnl Check whether the BSD/SUSv1 sbrk() exists. If not, disable DSS support.
-AC_CHECK_FUNC([sbrk], [have_sbrk="1"], [have_sbrk="0"])
-if test "x$have_sbrk" = "x1" ; then
- if test "x$sbrk_deprecated" = "x1" ; then
- AC_MSG_RESULT([Disabling dss allocation because sbrk is deprecated])
- have_dss="0"
- fi
-else
- have_dss="0"
-fi
-
-if test "x$have_dss" = "x1" ; then
- AC_DEFINE([JEMALLOC_DSS], [ ])
-fi
-
-dnl Support the junk/zero filling option by default.
-AC_ARG_ENABLE([fill],
- [AS_HELP_STRING([--disable-fill], [Disable support for junk/zero filling])],
-[if test "x$enable_fill" = "xno" ; then
- enable_fill="0"
-else
- enable_fill="1"
-fi
-],
-[enable_fill="1"]
-)
-if test "x$enable_fill" = "x1" ; then
- AC_DEFINE([JEMALLOC_FILL], [ ])
-fi
-AC_SUBST([enable_fill])
-
-dnl Disable utrace(2)-based tracing by default.
-AC_ARG_ENABLE([utrace],
- [AS_HELP_STRING([--enable-utrace], [Enable utrace(2)-based tracing])],
-[if test "x$enable_utrace" = "xno" ; then
- enable_utrace="0"
-else
- enable_utrace="1"
-fi
-],
-[enable_utrace="0"]
-)
-JE_COMPILABLE([utrace(2)], [
-#include <sys/types.h>
-#include <sys/param.h>
-#include <sys/time.h>
-#include <sys/uio.h>
-#include <sys/ktrace.h>
-], [
- utrace((void *)0, 0);
-], [je_cv_utrace])
-if test "x${je_cv_utrace}" = "xno" ; then
- enable_utrace="0"
-fi
-if test "x$enable_utrace" = "x1" ; then
- AC_DEFINE([JEMALLOC_UTRACE], [ ])
-fi
-AC_SUBST([enable_utrace])
-
-dnl Do not support the xmalloc option by default.
-AC_ARG_ENABLE([xmalloc],
- [AS_HELP_STRING([--enable-xmalloc], [Support xmalloc option])],
-[if test "x$enable_xmalloc" = "xno" ; then
- enable_xmalloc="0"
-else
- enable_xmalloc="1"
-fi
-],
-[enable_xmalloc="0"]
-)
-if test "x$enable_xmalloc" = "x1" ; then
- AC_DEFINE([JEMALLOC_XMALLOC], [ ])
-fi
-AC_SUBST([enable_xmalloc])
-
-dnl Support cache-oblivious allocation alignment by default.
-AC_ARG_ENABLE([cache-oblivious],
- [AS_HELP_STRING([--disable-cache-oblivious],
- [Disable support for cache-oblivious allocation alignment])],
-[if test "x$enable_cache_oblivious" = "xno" ; then
- enable_cache_oblivious="0"
-else
- enable_cache_oblivious="1"
-fi
-],
-[enable_cache_oblivious="1"]
-)
-if test "x$enable_cache_oblivious" = "x1" ; then
- AC_DEFINE([JEMALLOC_CACHE_OBLIVIOUS], [ ])
-fi
-AC_SUBST([enable_cache_oblivious])
-
-dnl Do not log by default.
-AC_ARG_ENABLE([log],
- [AS_HELP_STRING([--enable-log], [Support debug logging])],
-[if test "x$enable_log" = "xno" ; then
- enable_log="0"
-else
- enable_log="1"
-fi
-],
-[enable_log="0"]
-)
-if test "x$enable_log" = "x1" ; then
- AC_DEFINE([JEMALLOC_LOG], [ ])
-fi
-AC_SUBST([enable_log])
-
-dnl Do not use readlinkat by default
-AC_ARG_ENABLE([readlinkat],
- [AS_HELP_STRING([--enable-readlinkat], [Use readlinkat over readlink])],
-[if test "x$enable_readlinkat" = "xno" ; then
- enable_readlinkat="0"
-else
- enable_readlinkat="1"
-fi
-],
-[enable_readlinkat="0"]
-)
-if test "x$enable_readlinkat" = "x1" ; then
- AC_DEFINE([JEMALLOC_READLINKAT], [ ])
-fi
-AC_SUBST([enable_readlinkat])
-
-dnl Avoid extra safety checks by default
-AC_ARG_ENABLE([opt-safety-checks],
- [AS_HELP_STRING([--enable-opt-safety-checks],
- [Perform certain low-overhead checks, even in opt mode])],
-[if test "x$enable_opt_safety_checks" = "xno" ; then
- enable_opt_safety_checks="0"
-else
- enable_opt_safety_checks="1"
-fi
-],
-[enable_opt_safety_checks="0"]
-)
-if test "x$enable_opt_safety_checks" = "x1" ; then
- AC_DEFINE([JEMALLOC_OPT_SAFETY_CHECKS], [ ])
-fi
-AC_SUBST([enable_opt_safety_checks])
-
-JE_COMPILABLE([a program using __builtin_unreachable], [
-void foo (void) {
- __builtin_unreachable();
-}
-], [
- {
- foo();
- }
-], [je_cv_gcc_builtin_unreachable])
-if test "x${je_cv_gcc_builtin_unreachable}" = "xyes" ; then
- AC_DEFINE([JEMALLOC_INTERNAL_UNREACHABLE], [__builtin_unreachable])
-else
- AC_DEFINE([JEMALLOC_INTERNAL_UNREACHABLE], [abort])
-fi
-
-dnl ============================================================================
-dnl Check for __builtin_ffsl(), then ffsl(3), and fail if neither are found.
-dnl One of those two functions should (theoretically) exist on all platforms
-dnl that jemalloc currently has a chance of functioning on without modification.
-dnl We additionally assume ffs[ll]() or __builtin_ffs[ll]() are defined if
-dnl ffsl() or __builtin_ffsl() are defined, respectively.
-JE_COMPILABLE([a program using __builtin_ffsl], [
-#include <stdio.h>
-#include <strings.h>
-#include <string.h>
-], [
- {
- int rv = __builtin_ffsl(0x08);
- printf("%d\n", rv);
- }
-], [je_cv_gcc_builtin_ffsl])
-if test "x${je_cv_gcc_builtin_ffsl}" = "xyes" ; then
- AC_DEFINE([JEMALLOC_INTERNAL_FFSLL], [__builtin_ffsll])
- AC_DEFINE([JEMALLOC_INTERNAL_FFSL], [__builtin_ffsl])
- AC_DEFINE([JEMALLOC_INTERNAL_FFS], [__builtin_ffs])
-else
- JE_COMPILABLE([a program using ffsl], [
- #include <stdio.h>
- #include <strings.h>
- #include <string.h>
- ], [
- {
- int rv = ffsl(0x08);
- printf("%d\n", rv);
- }
- ], [je_cv_function_ffsl])
- if test "x${je_cv_function_ffsl}" = "xyes" ; then
- AC_DEFINE([JEMALLOC_INTERNAL_FFSLL], [ffsll])
- AC_DEFINE([JEMALLOC_INTERNAL_FFSL], [ffsl])
- AC_DEFINE([JEMALLOC_INTERNAL_FFS], [ffs])
- else
- AC_MSG_ERROR([Cannot build without ffsl(3) or __builtin_ffsl()])
- fi
-fi
-
-JE_COMPILABLE([a program using __builtin_popcountl], [
-#include <stdio.h>
-#include <strings.h>
-#include <string.h>
-], [
- {
- int rv = __builtin_popcountl(0x08);
- printf("%d\n", rv);
- }
-], [je_cv_gcc_builtin_popcountl])
-if test "x${je_cv_gcc_builtin_popcountl}" = "xyes" ; then
- AC_DEFINE([JEMALLOC_INTERNAL_POPCOUNT], [__builtin_popcount])
- AC_DEFINE([JEMALLOC_INTERNAL_POPCOUNTL], [__builtin_popcountl])
-fi
-
-AC_ARG_WITH([lg_quantum],
- [AS_HELP_STRING([--with-lg-quantum=<lg-quantum>],
- [Base 2 log of minimum allocation alignment])],
- [LG_QUANTA="$with_lg_quantum"],
- [LG_QUANTA="3 4"])
-if test "x$with_lg_quantum" != "x" ; then
- AC_DEFINE_UNQUOTED([LG_QUANTUM], [$with_lg_quantum])
-fi
-
-AC_ARG_WITH([lg_page],
- [AS_HELP_STRING([--with-lg-page=<lg-page>], [Base 2 log of system page size])],
- [LG_PAGE="$with_lg_page"], [LG_PAGE="detect"])
-if test "x$LG_PAGE" = "xdetect"; then
- AC_CACHE_CHECK([LG_PAGE],
- [je_cv_lg_page],
- AC_RUN_IFELSE([AC_LANG_PROGRAM(
-[[
-#include <strings.h>
-#ifdef _WIN32
-#include <windows.h>
-#else
-#include <unistd.h>
-#endif
-#include <stdio.h>
-]],
-[[
- int result;
- FILE *f;
-
-#ifdef _WIN32
- SYSTEM_INFO si;
- GetSystemInfo(&si);
- result = si.dwPageSize;
-#else
- result = sysconf(_SC_PAGESIZE);
-#endif
- if (result == -1) {
- return 1;
- }
- result = JEMALLOC_INTERNAL_FFSL(result) - 1;
-
- f = fopen("conftest.out", "w");
- if (f == NULL) {
- return 1;
- }
- fprintf(f, "%d", result);
- fclose(f);
-
- return 0;
-]])],
- [je_cv_lg_page=`cat conftest.out`],
- [je_cv_lg_page=undefined],
- [je_cv_lg_page=12]))
-fi
-if test "x${je_cv_lg_page}" != "x" ; then
- LG_PAGE="${je_cv_lg_page}"
-fi
-if test "x${LG_PAGE}" != "xundefined" ; then
- AC_DEFINE_UNQUOTED([LG_PAGE], [$LG_PAGE])
-else
- AC_MSG_ERROR([cannot determine value for LG_PAGE])
-fi
-
-AC_ARG_WITH([lg_hugepage],
- [AS_HELP_STRING([--with-lg-hugepage=<lg-hugepage>],
- [Base 2 log of system huge page size])],
- [je_cv_lg_hugepage="${with_lg_hugepage}"],
- [je_cv_lg_hugepage=""])
-if test "x${je_cv_lg_hugepage}" = "x" ; then
- dnl Look in /proc/meminfo (Linux-specific) for information on the default huge
- dnl page size, if any. The relevant line looks like:
- dnl
- dnl Hugepagesize: 2048 kB
- if test -e "/proc/meminfo" ; then
- hpsk=[`cat /proc/meminfo 2>/dev/null | \
- grep -e '^Hugepagesize:[[:space:]]\+[0-9]\+[[:space:]]kB$' | \
- awk '{print $2}'`]
- if test "x${hpsk}" != "x" ; then
- je_cv_lg_hugepage=10
- while test "${hpsk}" -gt 1 ; do
- hpsk="$((hpsk / 2))"
- je_cv_lg_hugepage="$((je_cv_lg_hugepage + 1))"
- done
- fi
- fi
-
- dnl Set default if unable to automatically configure.
- if test "x${je_cv_lg_hugepage}" = "x" ; then
- je_cv_lg_hugepage=21
- fi
-fi
-if test "x${LG_PAGE}" != "xundefined" -a \
- "${je_cv_lg_hugepage}" -lt "${LG_PAGE}" ; then
- AC_MSG_ERROR([Huge page size (2^${je_cv_lg_hugepage}) must be at least page size (2^${LG_PAGE})])
-fi
-AC_DEFINE_UNQUOTED([LG_HUGEPAGE], [${je_cv_lg_hugepage}])
-
-dnl ============================================================================
-dnl Enable libdl by default.
-AC_ARG_ENABLE([libdl],
- [AS_HELP_STRING([--disable-libdl],
- [Do not use libdl])],
-[if test "x$enable_libdl" = "xno" ; then
- enable_libdl="0"
-else
- enable_libdl="1"
-fi
-],
-[enable_libdl="1"]
-)
-AC_SUBST([libdl])
-
-dnl ============================================================================
-dnl Configure pthreads.
-
-if test "x$abi" != "xpecoff" ; then
- AC_DEFINE([JEMALLOC_HAVE_PTHREAD], [ ])
- AC_CHECK_HEADERS([pthread.h], , [AC_MSG_ERROR([pthread.h is missing])])
- dnl Some systems may embed pthreads functionality in libc; check for libpthread
- dnl first, but try libc too before failing.
- AC_CHECK_LIB([pthread], [pthread_create], [JE_APPEND_VS(LIBS, -pthread)],
- [AC_SEARCH_LIBS([pthread_create], , ,
- AC_MSG_ERROR([libpthread is missing]))])
- wrap_syms="${wrap_syms} pthread_create"
- have_pthread="1"
-
-dnl Check if we have dlsym support.
- if test "x$enable_libdl" = "x1" ; then
- have_dlsym="1"
- AC_CHECK_HEADERS([dlfcn.h],
- AC_CHECK_FUNC([dlsym], [],
- [AC_CHECK_LIB([dl], [dlsym], [LIBS="$LIBS -ldl"], [have_dlsym="0"])]),
- [have_dlsym="0"])
- if test "x$have_dlsym" = "x1" ; then
- AC_DEFINE([JEMALLOC_HAVE_DLSYM], [ ])
- fi
- else
- have_dlsym="0"
- fi
-
- JE_COMPILABLE([pthread_atfork(3)], [
-#include <pthread.h>
-], [
- pthread_atfork((void *)0, (void *)0, (void *)0);
-], [je_cv_pthread_atfork])
- if test "x${je_cv_pthread_atfork}" = "xyes" ; then
- AC_DEFINE([JEMALLOC_HAVE_PTHREAD_ATFORK], [ ])
- fi
- dnl Check if pthread_setname_np is available with the expected API.
- JE_COMPILABLE([pthread_setname_np(3)], [
-#include <pthread.h>
-], [
- pthread_setname_np(pthread_self(), "setname_test");
-], [je_cv_pthread_setname_np])
- if test "x${je_cv_pthread_setname_np}" = "xyes" ; then
- AC_DEFINE([JEMALLOC_HAVE_PTHREAD_SETNAME_NP], [ ])
- fi
-fi
-
-JE_APPEND_VS(CPPFLAGS, -D_REENTRANT)
-
-dnl Check whether clock_gettime(2) is in libc or librt.
-AC_SEARCH_LIBS([clock_gettime], [rt])
-
-dnl Cray wrapper compiler often adds `-lrt` when using `-static`. Check with
-dnl `-dynamic` as well in case a user tries to dynamically link in jemalloc
-if test "x$je_cv_cray_prgenv_wrapper" = "xyes" ; then
- if test "$ac_cv_search_clock_gettime" != "-lrt"; then
- JE_CFLAGS_SAVE()
-
- unset ac_cv_search_clock_gettime
- JE_CFLAGS_ADD([-dynamic])
- AC_SEARCH_LIBS([clock_gettime], [rt])
-
- JE_CFLAGS_RESTORE()
- fi
-fi
-
-dnl check for CLOCK_MONOTONIC_COARSE (Linux-specific).
-JE_COMPILABLE([clock_gettime(CLOCK_MONOTONIC_COARSE, ...)], [
-#include <time.h>
-], [
- struct timespec ts;
-
- clock_gettime(CLOCK_MONOTONIC_COARSE, &ts);
-], [je_cv_clock_monotonic_coarse])
-if test "x${je_cv_clock_monotonic_coarse}" = "xyes" ; then
- AC_DEFINE([JEMALLOC_HAVE_CLOCK_MONOTONIC_COARSE])
-fi
-
-dnl check for CLOCK_MONOTONIC.
-JE_COMPILABLE([clock_gettime(CLOCK_MONOTONIC, ...)], [
-#include <unistd.h>
-#include <time.h>
-], [
- struct timespec ts;
-
- clock_gettime(CLOCK_MONOTONIC, &ts);
-#if !defined(_POSIX_MONOTONIC_CLOCK) || _POSIX_MONOTONIC_CLOCK < 0
-# error _POSIX_MONOTONIC_CLOCK missing/invalid
-#endif
-], [je_cv_clock_monotonic])
-if test "x${je_cv_clock_monotonic}" = "xyes" ; then
- AC_DEFINE([JEMALLOC_HAVE_CLOCK_MONOTONIC])
-fi
-
-dnl Check for mach_absolute_time().
-JE_COMPILABLE([mach_absolute_time()], [
-#include <mach/mach_time.h>
-], [
- mach_absolute_time();
-], [je_cv_mach_absolute_time])
-if test "x${je_cv_mach_absolute_time}" = "xyes" ; then
- AC_DEFINE([JEMALLOC_HAVE_MACH_ABSOLUTE_TIME])
-fi
-
-dnl Use syscall(2) (if available) by default.
-AC_ARG_ENABLE([syscall],
- [AS_HELP_STRING([--disable-syscall], [Disable use of syscall(2)])],
-[if test "x$enable_syscall" = "xno" ; then
- enable_syscall="0"
-else
- enable_syscall="1"
-fi
-],
-[enable_syscall="1"]
-)
-if test "x$enable_syscall" = "x1" ; then
- dnl Check if syscall(2) is usable. Treat warnings as errors, so that e.g. OS
- dnl X 10.12's deprecation warning prevents use.
- JE_CFLAGS_SAVE()
- JE_CFLAGS_ADD([-Werror])
- JE_COMPILABLE([syscall(2)], [
-#include <sys/syscall.h>
-#include <unistd.h>
-], [
- syscall(SYS_write, 2, "hello", 5);
-],
- [je_cv_syscall])
- JE_CFLAGS_RESTORE()
- if test "x$je_cv_syscall" = "xyes" ; then
- AC_DEFINE([JEMALLOC_USE_SYSCALL], [ ])
- fi
-fi
-
-dnl Check if the GNU-specific secure_getenv function exists.
-AC_CHECK_FUNC([secure_getenv],
- [have_secure_getenv="1"],
- [have_secure_getenv="0"]
- )
-if test "x$have_secure_getenv" = "x1" ; then
- AC_DEFINE([JEMALLOC_HAVE_SECURE_GETENV], [ ])
-fi
-
-dnl Check if the GNU-specific sched_getcpu function exists.
-AC_CHECK_FUNC([sched_getcpu],
- [have_sched_getcpu="1"],
- [have_sched_getcpu="0"]
- )
-if test "x$have_sched_getcpu" = "x1" ; then
- AC_DEFINE([JEMALLOC_HAVE_SCHED_GETCPU], [ ])
-fi
-
-dnl Check if the GNU-specific sched_setaffinity function exists.
-AC_CHECK_FUNC([sched_setaffinity],
- [have_sched_setaffinity="1"],
- [have_sched_setaffinity="0"]
- )
-if test "x$have_sched_setaffinity" = "x1" ; then
- AC_DEFINE([JEMALLOC_HAVE_SCHED_SETAFFINITY], [ ])
-fi
-
-dnl Check if the Solaris/BSD issetugid function exists.
-AC_CHECK_FUNC([issetugid],
- [have_issetugid="1"],
- [have_issetugid="0"]
- )
-if test "x$have_issetugid" = "x1" ; then
- AC_DEFINE([JEMALLOC_HAVE_ISSETUGID], [ ])
-fi
-
-dnl Check whether the BSD-specific _malloc_thread_cleanup() exists. If so, use
-dnl it rather than pthreads TSD cleanup functions to support cleanup during
-dnl thread exit, in order to avoid pthreads library recursion during
-dnl bootstrapping.
-AC_CHECK_FUNC([_malloc_thread_cleanup],
- [have__malloc_thread_cleanup="1"],
- [have__malloc_thread_cleanup="0"]
- )
-if test "x$have__malloc_thread_cleanup" = "x1" ; then
- AC_DEFINE([JEMALLOC_MALLOC_THREAD_CLEANUP], [ ])
- wrap_syms="${wrap_syms} _malloc_thread_cleanup"
- force_tls="1"
-fi
-
-dnl Check whether the BSD-specific _pthread_mutex_init_calloc_cb() exists. If
-dnl so, mutex initialization causes allocation, and we need to implement this
-dnl callback function in order to prevent recursive allocation.
-AC_CHECK_FUNC([_pthread_mutex_init_calloc_cb],
- [have__pthread_mutex_init_calloc_cb="1"],
- [have__pthread_mutex_init_calloc_cb="0"]
- )
-if test "x$have__pthread_mutex_init_calloc_cb" = "x1" ; then
- AC_DEFINE([JEMALLOC_MUTEX_INIT_CB])
- wrap_syms="${wrap_syms} _malloc_prefork _malloc_postfork"
-fi
-
-dnl Disable lazy locking by default.
-AC_ARG_ENABLE([lazy_lock],
- [AS_HELP_STRING([--enable-lazy-lock],
- [Enable lazy locking (only lock when multi-threaded)])],
-[if test "x$enable_lazy_lock" = "xno" ; then
- enable_lazy_lock="0"
-else
- enable_lazy_lock="1"
-fi
-],
-[enable_lazy_lock=""]
-)
-if test "x${enable_lazy_lock}" = "x" ; then
- if test "x${force_lazy_lock}" = "x1" ; then
- AC_MSG_RESULT([Forcing lazy-lock to avoid allocator/threading bootstrap issues])
- enable_lazy_lock="1"
- else
- enable_lazy_lock="0"
- fi
-fi
-if test "x${enable_lazy_lock}" = "x1" -a "x${abi}" = "xpecoff" ; then
- AC_MSG_RESULT([Forcing no lazy-lock because thread creation monitoring is unimplemented])
- enable_lazy_lock="0"
-fi
-if test "x$enable_lazy_lock" = "x1" ; then
- if test "x$have_dlsym" = "x1" ; then
- AC_DEFINE([JEMALLOC_LAZY_LOCK], [ ])
- else
- AC_MSG_ERROR([Missing dlsym support: lazy-lock cannot be enabled.])
- fi
-fi
-AC_SUBST([enable_lazy_lock])
-
-dnl Automatically configure TLS.
-if test "x${force_tls}" = "x1" ; then
- enable_tls="1"
-elif test "x${force_tls}" = "x0" ; then
- enable_tls="0"
-else
- enable_tls="1"
-fi
-if test "x${enable_tls}" = "x1" ; then
-AC_MSG_CHECKING([for TLS])
-AC_COMPILE_IFELSE([AC_LANG_PROGRAM(
-[[
- __thread int x;
-]], [[
- x = 42;
-
- return 0;
-]])],
- AC_MSG_RESULT([yes]),
- AC_MSG_RESULT([no])
- enable_tls="0")
-else
- enable_tls="0"
-fi
-AC_SUBST([enable_tls])
-if test "x${enable_tls}" = "x1" ; then
- AC_DEFINE_UNQUOTED([JEMALLOC_TLS], [ ])
-fi
-
-dnl ============================================================================
-dnl Check for C11 atomics.
-
-JE_COMPILABLE([C11 atomics], [
-#include <stdint.h>
-#if (__STDC_VERSION__ >= 201112L) && !defined(__STDC_NO_ATOMICS__)
-#include <stdatomic.h>
-#else
-#error Atomics not available
-#endif
-], [
- uint64_t *p = (uint64_t *)0;
- uint64_t x = 1;
- volatile atomic_uint_least64_t *a = (volatile atomic_uint_least64_t *)p;
- uint64_t r = atomic_fetch_add(a, x) + x;
- return r == 0;
-], [je_cv_c11_atomics])
-if test "x${je_cv_c11_atomics}" = "xyes" ; then
- AC_DEFINE([JEMALLOC_C11_ATOMICS])
-fi
-
-dnl ============================================================================
-dnl Check for GCC-style __atomic atomics.
-
-JE_COMPILABLE([GCC __atomic atomics], [
-], [
- int x = 0;
- int val = 1;
- int y = __atomic_fetch_add(&x, val, __ATOMIC_RELAXED);
- int after_add = x;
- return after_add == 1;
-], [je_cv_gcc_atomic_atomics])
-if test "x${je_cv_gcc_atomic_atomics}" = "xyes" ; then
- AC_DEFINE([JEMALLOC_GCC_ATOMIC_ATOMICS])
-
- dnl check for 8-bit atomic support
- JE_COMPILABLE([GCC 8-bit __atomic atomics], [
- ], [
- unsigned char x = 0;
- int val = 1;
- int y = __atomic_fetch_add(&x, val, __ATOMIC_RELAXED);
- int after_add = (int)x;
- return after_add == 1;
- ], [je_cv_gcc_u8_atomic_atomics])
- if test "x${je_cv_gcc_u8_atomic_atomics}" = "xyes" ; then
- AC_DEFINE([JEMALLOC_GCC_U8_ATOMIC_ATOMICS])
- fi
-fi
-
-dnl ============================================================================
-dnl Check for GCC-style __sync atomics.
-
-JE_COMPILABLE([GCC __sync atomics], [
-], [
- int x = 0;
- int before_add = __sync_fetch_and_add(&x, 1);
- int after_add = x;
- return (before_add == 0) && (after_add == 1);
-], [je_cv_gcc_sync_atomics])
-if test "x${je_cv_gcc_sync_atomics}" = "xyes" ; then
- AC_DEFINE([JEMALLOC_GCC_SYNC_ATOMICS])
-
- dnl check for 8-bit atomic support
- JE_COMPILABLE([GCC 8-bit __sync atomics], [
- ], [
- unsigned char x = 0;
- int before_add = __sync_fetch_and_add(&x, 1);
- int after_add = (int)x;
- return (before_add == 0) && (after_add == 1);
- ], [je_cv_gcc_u8_sync_atomics])
- if test "x${je_cv_gcc_u8_sync_atomics}" = "xyes" ; then
- AC_DEFINE([JEMALLOC_GCC_U8_SYNC_ATOMICS])
- fi
-fi
-
-dnl ============================================================================
-dnl Check for atomic(3) operations as provided on Darwin.
-dnl We need this not for the atomic operations (which are provided above), but
-dnl rather for the OS_unfair_lock type it exposes.
-
-JE_COMPILABLE([Darwin OSAtomic*()], [
-#include <libkern/OSAtomic.h>
-#include <inttypes.h>
-], [
- {
- int32_t x32 = 0;
- volatile int32_t *x32p = &x32;
- OSAtomicAdd32(1, x32p);
- }
- {
- int64_t x64 = 0;
- volatile int64_t *x64p = &x64;
- OSAtomicAdd64(1, x64p);
- }
-], [je_cv_osatomic])
-if test "x${je_cv_osatomic}" = "xyes" ; then
- AC_DEFINE([JEMALLOC_OSATOMIC], [ ])
-fi
-
-dnl ============================================================================
-dnl Check for madvise(2).
-
-JE_COMPILABLE([madvise(2)], [
-#include <sys/mman.h>
-], [
- madvise((void *)0, 0, 0);
-], [je_cv_madvise])
-if test "x${je_cv_madvise}" = "xyes" ; then
- AC_DEFINE([JEMALLOC_HAVE_MADVISE], [ ])
-
- dnl Check for madvise(..., MADV_FREE).
- JE_COMPILABLE([madvise(..., MADV_FREE)], [
-#include <sys/mman.h>
-], [
- madvise((void *)0, 0, MADV_FREE);
-], [je_cv_madv_free])
- if test "x${je_cv_madv_free}" = "xyes" ; then
- AC_DEFINE([JEMALLOC_PURGE_MADVISE_FREE], [ ])
- elif test "x${je_cv_madvise}" = "xyes" ; then
- case "${host_cpu}" in i686|x86_64)
- case "${host}" in *-*-linux*)
- AC_DEFINE([JEMALLOC_PURGE_MADVISE_FREE], [ ])
- AC_DEFINE([JEMALLOC_DEFINE_MADVISE_FREE], [ ])
- ;;
- esac
- ;;
- esac
- fi
-
- dnl Check for madvise(..., MADV_DONTNEED).
- JE_COMPILABLE([madvise(..., MADV_DONTNEED)], [
-#include <sys/mman.h>
-], [
- madvise((void *)0, 0, MADV_DONTNEED);
-], [je_cv_madv_dontneed])
- if test "x${je_cv_madv_dontneed}" = "xyes" ; then
- AC_DEFINE([JEMALLOC_PURGE_MADVISE_DONTNEED], [ ])
- fi
-
- dnl Check for madvise(..., MADV_DO[NT]DUMP).
- JE_COMPILABLE([madvise(..., MADV_DO[[NT]]DUMP)], [
-#include <sys/mman.h>
-], [
- madvise((void *)0, 0, MADV_DONTDUMP);
- madvise((void *)0, 0, MADV_DODUMP);
-], [je_cv_madv_dontdump])
- if test "x${je_cv_madv_dontdump}" = "xyes" ; then
- AC_DEFINE([JEMALLOC_MADVISE_DONTDUMP], [ ])
- fi
-
- dnl Check for madvise(..., MADV_[NO]HUGEPAGE).
- JE_COMPILABLE([madvise(..., MADV_[[NO]]HUGEPAGE)], [
-#include <sys/mman.h>
-], [
- madvise((void *)0, 0, MADV_HUGEPAGE);
- madvise((void *)0, 0, MADV_NOHUGEPAGE);
-], [je_cv_thp])
-case "${host_cpu}" in
- arm*)
- ;;
- *)
- if test "x${je_cv_thp}" = "xyes" ; then
- AC_DEFINE([JEMALLOC_HAVE_MADVISE_HUGE], [ ])
- fi
- ;;
-esac
-fi
-
-dnl ============================================================================
-dnl Check for __builtin_clz() and __builtin_clzl().
-
-AC_CACHE_CHECK([for __builtin_clz],
- [je_cv_builtin_clz],
- [AC_LINK_IFELSE([AC_LANG_PROGRAM([],
- [
- {
- unsigned x = 0;
- int y = __builtin_clz(x);
- }
- {
- unsigned long x = 0;
- int y = __builtin_clzl(x);
- }
- ])],
- [je_cv_builtin_clz=yes],
- [je_cv_builtin_clz=no])])
-
-if test "x${je_cv_builtin_clz}" = "xyes" ; then
- AC_DEFINE([JEMALLOC_HAVE_BUILTIN_CLZ], [ ])
-fi
-
-dnl ============================================================================
-dnl Check for os_unfair_lock operations as provided on Darwin.
-
-JE_COMPILABLE([Darwin os_unfair_lock_*()], [
-#include <os/lock.h>
-#include <AvailabilityMacros.h>
-], [
- #if MAC_OS_X_VERSION_MIN_REQUIRED < 101200
- #error "os_unfair_lock is not supported"
- #else
- os_unfair_lock lock = OS_UNFAIR_LOCK_INIT;
- os_unfair_lock_lock(&lock);
- os_unfair_lock_unlock(&lock);
- #endif
-], [je_cv_os_unfair_lock])
-if test "x${je_cv_os_unfair_lock}" = "xyes" ; then
- AC_DEFINE([JEMALLOC_OS_UNFAIR_LOCK], [ ])
-fi
-
-dnl ============================================================================
-dnl Darwin-related configuration.
-
-AC_ARG_ENABLE([zone-allocator],
- [AS_HELP_STRING([--disable-zone-allocator],
- [Disable zone allocator for Darwin])],
-[if test "x$enable_zone_allocator" = "xno" ; then
- enable_zone_allocator="0"
-else
- enable_zone_allocator="1"
-fi
-],
-[if test "x${abi}" = "xmacho"; then
- enable_zone_allocator="1"
-fi
-]
-)
-AC_SUBST([enable_zone_allocator])
-
-if test "x${enable_zone_allocator}" = "x1" ; then
- if test "x${abi}" != "xmacho"; then
- AC_MSG_ERROR([--enable-zone-allocator is only supported on Darwin])
- fi
- AC_DEFINE([JEMALLOC_ZONE], [ ])
-fi
-
-dnl ============================================================================
-dnl Use initial-exec TLS by default.
-AC_ARG_ENABLE([initial-exec-tls],
- [AS_HELP_STRING([--disable-initial-exec-tls],
- [Disable the initial-exec tls model])],
-[if test "x$enable_initial_exec_tls" = "xno" ; then
- enable_initial_exec_tls="0"
-else
- enable_initial_exec_tls="1"
-fi
-],
-[enable_initial_exec_tls="1"]
-)
-AC_SUBST([enable_initial_exec_tls])
-
-if test "x${je_cv_tls_model}" = "xyes" -a \
- "x${enable_initial_exec_tls}" = "x1" ; then
- AC_DEFINE([JEMALLOC_TLS_MODEL],
- [__attribute__((tls_model("initial-exec")))])
-else
- AC_DEFINE([JEMALLOC_TLS_MODEL], [ ])
-fi
-
-dnl ============================================================================
-dnl Enable background threads if possible.
-
-if test "x${have_pthread}" = "x1" -a "x${je_cv_os_unfair_lock}" != "xyes" ; then
- AC_DEFINE([JEMALLOC_BACKGROUND_THREAD])
-fi
-
-dnl ============================================================================
-dnl Check for glibc malloc hooks
-
-JE_COMPILABLE([glibc malloc hook], [
-#include <stddef.h>
-
-extern void (* __free_hook)(void *ptr);
-extern void *(* __malloc_hook)(size_t size);
-extern void *(* __realloc_hook)(void *ptr, size_t size);
-], [
- void *ptr = 0L;
- if (__malloc_hook) ptr = __malloc_hook(1);
- if (__realloc_hook) ptr = __realloc_hook(ptr, 2);
- if (__free_hook && ptr) __free_hook(ptr);
-], [je_cv_glibc_malloc_hook])
-if test "x${je_cv_glibc_malloc_hook}" = "xyes" ; then
- if test "x${JEMALLOC_PREFIX}" = "x" ; then
- AC_DEFINE([JEMALLOC_GLIBC_MALLOC_HOOK], [ ])
- wrap_syms="${wrap_syms} __free_hook __malloc_hook __realloc_hook"
- fi
-fi
-
-JE_COMPILABLE([glibc memalign hook], [
-#include <stddef.h>
-
-extern void *(* __memalign_hook)(size_t alignment, size_t size);
-], [
- void *ptr = 0L;
- if (__memalign_hook) ptr = __memalign_hook(16, 7);
-], [je_cv_glibc_memalign_hook])
-if test "x${je_cv_glibc_memalign_hook}" = "xyes" ; then
- if test "x${JEMALLOC_PREFIX}" = "x" ; then
- AC_DEFINE([JEMALLOC_GLIBC_MEMALIGN_HOOK], [ ])
- wrap_syms="${wrap_syms} __memalign_hook"
- fi
-fi
-
-JE_COMPILABLE([pthreads adaptive mutexes], [
-#include <pthread.h>
-], [
- pthread_mutexattr_t attr;
- pthread_mutexattr_init(&attr);
- pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ADAPTIVE_NP);
- pthread_mutexattr_destroy(&attr);
-], [je_cv_pthread_mutex_adaptive_np])
-if test "x${je_cv_pthread_mutex_adaptive_np}" = "xyes" ; then
- AC_DEFINE([JEMALLOC_HAVE_PTHREAD_MUTEX_ADAPTIVE_NP], [ ])
-fi
-
-JE_CFLAGS_SAVE()
-JE_CFLAGS_ADD([-D_GNU_SOURCE])
-JE_CFLAGS_ADD([-Werror])
-JE_CFLAGS_ADD([-herror_on_warning])
-JE_COMPILABLE([strerror_r returns char with gnu source], [
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-], [
- char *buffer = (char *) malloc(100);
- char *error = strerror_r(EINVAL, buffer, 100);
- printf("%s\n", error);
-], [je_cv_strerror_r_returns_char_with_gnu_source])
-JE_CFLAGS_RESTORE()
-if test "x${je_cv_strerror_r_returns_char_with_gnu_source}" = "xyes" ; then
- AC_DEFINE([JEMALLOC_STRERROR_R_RETURNS_CHAR_WITH_GNU_SOURCE], [ ])
-fi
-
-dnl ============================================================================
-dnl Check for typedefs, structures, and compiler characteristics.
-AC_HEADER_STDBOOL
-
-dnl ============================================================================
-dnl Define commands that generate output files.
-
-AC_CONFIG_COMMANDS([include/jemalloc/internal/public_symbols.txt], [
- f="${objroot}include/jemalloc/internal/public_symbols.txt"
- mkdir -p "${objroot}include/jemalloc/internal"
- cp /dev/null "${f}"
- for nm in `echo ${mangling_map} |tr ',' ' '` ; do
- n=`echo ${nm} |tr ':' ' ' |awk '{print $[]1}'`
- m=`echo ${nm} |tr ':' ' ' |awk '{print $[]2}'`
- echo "${n}:${m}" >> "${f}"
- dnl Remove name from public_syms so that it isn't redefined later.
- public_syms=`for sym in ${public_syms}; do echo "${sym}"; done |grep -v "^${n}\$" |tr '\n' ' '`
- done
- for sym in ${public_syms} ; do
- n="${sym}"
- m="${JEMALLOC_PREFIX}${sym}"
- echo "${n}:${m}" >> "${f}"
- done
-], [
- srcdir="${srcdir}"
- objroot="${objroot}"
- mangling_map="${mangling_map}"
- public_syms="${public_syms}"
- JEMALLOC_PREFIX="${JEMALLOC_PREFIX}"
-])
-AC_CONFIG_COMMANDS([include/jemalloc/internal/private_symbols.awk], [
- f="${objroot}include/jemalloc/internal/private_symbols.awk"
- mkdir -p "${objroot}include/jemalloc/internal"
- export_syms=`for sym in ${public_syms}; do echo "${JEMALLOC_PREFIX}${sym}"; done; for sym in ${wrap_syms}; do echo "${sym}"; done;`
- "${srcdir}/include/jemalloc/internal/private_symbols.sh" "${SYM_PREFIX}" ${export_syms} > "${objroot}include/jemalloc/internal/private_symbols.awk"
-], [
- srcdir="${srcdir}"
- objroot="${objroot}"
- public_syms="${public_syms}"
- wrap_syms="${wrap_syms}"
- SYM_PREFIX="${SYM_PREFIX}"
- JEMALLOC_PREFIX="${JEMALLOC_PREFIX}"
-])
-AC_CONFIG_COMMANDS([include/jemalloc/internal/private_symbols_jet.awk], [
- f="${objroot}include/jemalloc/internal/private_symbols_jet.awk"
- mkdir -p "${objroot}include/jemalloc/internal"
- export_syms=`for sym in ${public_syms}; do echo "jet_${sym}"; done; for sym in ${wrap_syms}; do echo "${sym}"; done;`
- "${srcdir}/include/jemalloc/internal/private_symbols.sh" "${SYM_PREFIX}" ${export_syms} > "${objroot}include/jemalloc/internal/private_symbols_jet.awk"
-], [
- srcdir="${srcdir}"
- objroot="${objroot}"
- public_syms="${public_syms}"
- wrap_syms="${wrap_syms}"
- SYM_PREFIX="${SYM_PREFIX}"
-])
-AC_CONFIG_COMMANDS([include/jemalloc/internal/public_namespace.h], [
- mkdir -p "${objroot}include/jemalloc/internal"
- "${srcdir}/include/jemalloc/internal/public_namespace.sh" "${objroot}include/jemalloc/internal/public_symbols.txt" > "${objroot}include/jemalloc/internal/public_namespace.h"
-], [
- srcdir="${srcdir}"
- objroot="${objroot}"
-])
-AC_CONFIG_COMMANDS([include/jemalloc/internal/public_unnamespace.h], [
- mkdir -p "${objroot}include/jemalloc/internal"
- "${srcdir}/include/jemalloc/internal/public_unnamespace.sh" "${objroot}include/jemalloc/internal/public_symbols.txt" > "${objroot}include/jemalloc/internal/public_unnamespace.h"
-], [
- srcdir="${srcdir}"
- objroot="${objroot}"
-])
-AC_CONFIG_COMMANDS([include/jemalloc/jemalloc_protos_jet.h], [
- mkdir -p "${objroot}include/jemalloc"
- cat "${srcdir}/include/jemalloc/jemalloc_protos.h.in" | sed -e 's/@je_@/jet_/g' > "${objroot}include/jemalloc/jemalloc_protos_jet.h"
-], [
- srcdir="${srcdir}"
- objroot="${objroot}"
-])
-AC_CONFIG_COMMANDS([include/jemalloc/jemalloc_rename.h], [
- mkdir -p "${objroot}include/jemalloc"
- "${srcdir}/include/jemalloc/jemalloc_rename.sh" "${objroot}include/jemalloc/internal/public_symbols.txt" > "${objroot}include/jemalloc/jemalloc_rename.h"
-], [
- srcdir="${srcdir}"
- objroot="${objroot}"
-])
-AC_CONFIG_COMMANDS([include/jemalloc/jemalloc_mangle.h], [
- mkdir -p "${objroot}include/jemalloc"
- "${srcdir}/include/jemalloc/jemalloc_mangle.sh" "${objroot}include/jemalloc/internal/public_symbols.txt" je_ > "${objroot}include/jemalloc/jemalloc_mangle.h"
-], [
- srcdir="${srcdir}"
- objroot="${objroot}"
-])
-AC_CONFIG_COMMANDS([include/jemalloc/jemalloc_mangle_jet.h], [
- mkdir -p "${objroot}include/jemalloc"
- "${srcdir}/include/jemalloc/jemalloc_mangle.sh" "${objroot}include/jemalloc/internal/public_symbols.txt" jet_ > "${objroot}include/jemalloc/jemalloc_mangle_jet.h"
-], [
- srcdir="${srcdir}"
- objroot="${objroot}"
-])
-AC_CONFIG_COMMANDS([include/jemalloc/jemalloc.h], [
- mkdir -p "${objroot}include/jemalloc"
- "${srcdir}/include/jemalloc/jemalloc.sh" "${objroot}" > "${objroot}include/jemalloc/jemalloc${install_suffix}.h"
-], [
- srcdir="${srcdir}"
- objroot="${objroot}"
- install_suffix="${install_suffix}"
-])
-
-dnl Process .in files.
-AC_SUBST([cfghdrs_in])
-AC_SUBST([cfghdrs_out])
-AC_CONFIG_HEADERS([$cfghdrs_tup])
-
-dnl ============================================================================
-dnl Generate outputs.
-
-AC_CONFIG_FILES([$cfgoutputs_tup config.stamp bin/jemalloc-config bin/jemalloc.sh bin/jeprof])
-AC_SUBST([cfgoutputs_in])
-AC_SUBST([cfgoutputs_out])
-AC_OUTPUT
-
-dnl ============================================================================
-dnl Print out the results of configuration.
-AC_MSG_RESULT([===============================================================================])
-AC_MSG_RESULT([jemalloc version : ${jemalloc_version}])
-AC_MSG_RESULT([library revision : ${rev}])
-AC_MSG_RESULT([])
-AC_MSG_RESULT([CONFIG : ${CONFIG}])
-AC_MSG_RESULT([CC : ${CC}])
-AC_MSG_RESULT([CONFIGURE_CFLAGS : ${CONFIGURE_CFLAGS}])
-AC_MSG_RESULT([SPECIFIED_CFLAGS : ${SPECIFIED_CFLAGS}])
-AC_MSG_RESULT([EXTRA_CFLAGS : ${EXTRA_CFLAGS}])
-AC_MSG_RESULT([CPPFLAGS : ${CPPFLAGS}])
-AC_MSG_RESULT([CXX : ${CXX}])
-AC_MSG_RESULT([CONFIGURE_CXXFLAGS : ${CONFIGURE_CXXFLAGS}])
-AC_MSG_RESULT([SPECIFIED_CXXFLAGS : ${SPECIFIED_CXXFLAGS}])
-AC_MSG_RESULT([EXTRA_CXXFLAGS : ${EXTRA_CXXFLAGS}])
-AC_MSG_RESULT([LDFLAGS : ${LDFLAGS}])
-AC_MSG_RESULT([EXTRA_LDFLAGS : ${EXTRA_LDFLAGS}])
-AC_MSG_RESULT([DSO_LDFLAGS : ${DSO_LDFLAGS}])
-AC_MSG_RESULT([LIBS : ${LIBS}])
-AC_MSG_RESULT([RPATH_EXTRA : ${RPATH_EXTRA}])
-AC_MSG_RESULT([])
-AC_MSG_RESULT([XSLTPROC : ${XSLTPROC}])
-AC_MSG_RESULT([XSLROOT : ${XSLROOT}])
-AC_MSG_RESULT([])
-AC_MSG_RESULT([PREFIX : ${PREFIX}])
-AC_MSG_RESULT([BINDIR : ${BINDIR}])
-AC_MSG_RESULT([DATADIR : ${DATADIR}])
-AC_MSG_RESULT([INCLUDEDIR : ${INCLUDEDIR}])
-AC_MSG_RESULT([LIBDIR : ${LIBDIR}])
-AC_MSG_RESULT([MANDIR : ${MANDIR}])
-AC_MSG_RESULT([])
-AC_MSG_RESULT([srcroot : ${srcroot}])
-AC_MSG_RESULT([abs_srcroot : ${abs_srcroot}])
-AC_MSG_RESULT([objroot : ${objroot}])
-AC_MSG_RESULT([abs_objroot : ${abs_objroot}])
-AC_MSG_RESULT([])
-AC_MSG_RESULT([JEMALLOC_PREFIX : ${JEMALLOC_PREFIX}])
-AC_MSG_RESULT([JEMALLOC_PRIVATE_NAMESPACE])
-AC_MSG_RESULT([ : ${JEMALLOC_PRIVATE_NAMESPACE}])
-AC_MSG_RESULT([install_suffix : ${install_suffix}])
-AC_MSG_RESULT([malloc_conf : ${config_malloc_conf}])
-AC_MSG_RESULT([documentation : ${enable_doc}])
-AC_MSG_RESULT([shared libs : ${enable_shared}])
-AC_MSG_RESULT([static libs : ${enable_static}])
-AC_MSG_RESULT([autogen : ${enable_autogen}])
-AC_MSG_RESULT([debug : ${enable_debug}])
-AC_MSG_RESULT([stats : ${enable_stats}])
-AC_MSG_RESULT([experimetal_smallocx : ${enable_experimental_smallocx}])
-AC_MSG_RESULT([prof : ${enable_prof}])
-AC_MSG_RESULT([prof-libunwind : ${enable_prof_libunwind}])
-AC_MSG_RESULT([prof-libgcc : ${enable_prof_libgcc}])
-AC_MSG_RESULT([prof-gcc : ${enable_prof_gcc}])
-AC_MSG_RESULT([fill : ${enable_fill}])
-AC_MSG_RESULT([utrace : ${enable_utrace}])
-AC_MSG_RESULT([xmalloc : ${enable_xmalloc}])
-AC_MSG_RESULT([log : ${enable_log}])
-AC_MSG_RESULT([lazy_lock : ${enable_lazy_lock}])
-AC_MSG_RESULT([cache-oblivious : ${enable_cache_oblivious}])
-AC_MSG_RESULT([cxx : ${enable_cxx}])
-AC_MSG_RESULT([===============================================================================])
->>>>>>> main
diff --git a/contrib/jemalloc/doc/jemalloc.xml.in b/contrib/jemalloc/doc/jemalloc.xml.in
index e2b15de21961..4f5d27996816 100644
--- a/contrib/jemalloc/doc/jemalloc.xml.in
+++ b/contrib/jemalloc/doc/jemalloc.xml.in
@@ -1,4 +1,3 @@
-<<<<<<< HEAD
<?xml version='1.0' encoding='UTF-8'?>
<?xml-stylesheet type="text/xsl"
href="http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl"?>
@@ -3787,3544 +3786,3 @@ malloc_conf = "narenas:1";]]></programlisting></para>
11.0.</para>
</refsect1>
</refentry>
-||||||| dec341af7695
-=======
-<?xml version='1.0' encoding='UTF-8'?>
-<?xml-stylesheet type="text/xsl"
- href="http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl"?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN"
- "http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd" [
-]>
-
-<refentry>
- <refentryinfo>
- <title>User Manual</title>
- <productname>jemalloc</productname>
- <releaseinfo role="version">@jemalloc_version@</releaseinfo>
- <authorgroup>
- <author>
- <firstname>Jason</firstname>
- <surname>Evans</surname>
- <personblurb>Author</personblurb>
- </author>
- </authorgroup>
- </refentryinfo>
- <refmeta>
- <refentrytitle>JEMALLOC</refentrytitle>
- <manvolnum>3</manvolnum>
- </refmeta>
- <refnamediv>
- <refdescriptor>jemalloc</refdescriptor>
- <refname>jemalloc</refname>
- <!-- Each refname causes a man page file to be created. Only if this were
- the system malloc(3) implementation would these files be appropriate.
- <refname>malloc</refname>
- <refname>calloc</refname>
- <refname>posix_memalign</refname>
- <refname>aligned_alloc</refname>
- <refname>realloc</refname>
- <refname>free</refname>
- <refname>mallocx</refname>
- <refname>rallocx</refname>
- <refname>xallocx</refname>
- <refname>sallocx</refname>
- <refname>dallocx</refname>
- <refname>sdallocx</refname>
- <refname>nallocx</refname>
- <refname>mallctl</refname>
- <refname>mallctlnametomib</refname>
- <refname>mallctlbymib</refname>
- <refname>malloc_stats_print</refname>
- <refname>malloc_usable_size</refname>
- -->
- <refpurpose>general purpose memory allocation functions</refpurpose>
- </refnamediv>
- <refsect1 id="library">
- <title>LIBRARY</title>
- <para>This manual describes jemalloc @jemalloc_version@. More information
- can be found at the <ulink
- url="http://jemalloc.net/">jemalloc website</ulink>.</para>
-
- <para>The following configuration options are enabled in libc's built-in
- jemalloc: <option>--enable-fill</option>,
- <option>--enable-lazy-lock</option>, <option>--enable-stats</option>,
- <option>--enable-utrace</option>, <option>--enable-xmalloc</option>, and
- <option>--with-malloc-conf=abort_conf:false</option>.
- Additionally, <option>--enable-debug</option> is enabled in development
- versions of FreeBSD (controlled by the
- <constant>MK_MALLOC_PRODUCTION</constant> make variable).</para>
-
- </refsect1>
- <refsynopsisdiv>
- <title>SYNOPSIS</title>
- <funcsynopsis>
- <funcsynopsisinfo>#include &lt;<filename class="headerfile">stdlib.h</filename>&gt;
-#include &lt;<filename class="headerfile">malloc_np.h</filename>&gt;</funcsynopsisinfo>
- <refsect2>
- <title>Standard API</title>
- <funcprototype>
- <funcdef>void *<function>malloc</function></funcdef>
- <paramdef>size_t <parameter>size</parameter></paramdef>
- </funcprototype>
- <funcprototype>
- <funcdef>void *<function>calloc</function></funcdef>
- <paramdef>size_t <parameter>number</parameter></paramdef>
- <paramdef>size_t <parameter>size</parameter></paramdef>
- </funcprototype>
- <funcprototype>
- <funcdef>int <function>posix_memalign</function></funcdef>
- <paramdef>void **<parameter>ptr</parameter></paramdef>
- <paramdef>size_t <parameter>alignment</parameter></paramdef>
- <paramdef>size_t <parameter>size</parameter></paramdef>
- </funcprototype>
- <funcprototype>
- <funcdef>void *<function>aligned_alloc</function></funcdef>
- <paramdef>size_t <parameter>alignment</parameter></paramdef>
- <paramdef>size_t <parameter>size</parameter></paramdef>
- </funcprototype>
- <funcprototype>
- <funcdef>void *<function>realloc</function></funcdef>
- <paramdef>void *<parameter>ptr</parameter></paramdef>
- <paramdef>size_t <parameter>size</parameter></paramdef>
- </funcprototype>
- <funcprototype>
- <funcdef>void <function>free</function></funcdef>
- <paramdef>void *<parameter>ptr</parameter></paramdef>
- </funcprototype>
- </refsect2>
- <refsect2>
- <title>Non-standard API</title>
- <funcprototype>
- <funcdef>void *<function>mallocx</function></funcdef>
- <paramdef>size_t <parameter>size</parameter></paramdef>
- <paramdef>int <parameter>flags</parameter></paramdef>
- </funcprototype>
- <funcprototype>
- <funcdef>void *<function>rallocx</function></funcdef>
- <paramdef>void *<parameter>ptr</parameter></paramdef>
- <paramdef>size_t <parameter>size</parameter></paramdef>
- <paramdef>int <parameter>flags</parameter></paramdef>
- </funcprototype>
- <funcprototype>
- <funcdef>size_t <function>xallocx</function></funcdef>
- <paramdef>void *<parameter>ptr</parameter></paramdef>
- <paramdef>size_t <parameter>size</parameter></paramdef>
- <paramdef>size_t <parameter>extra</parameter></paramdef>
- <paramdef>int <parameter>flags</parameter></paramdef>
- </funcprototype>
- <funcprototype>
- <funcdef>size_t <function>sallocx</function></funcdef>
- <paramdef>void *<parameter>ptr</parameter></paramdef>
- <paramdef>int <parameter>flags</parameter></paramdef>
- </funcprototype>
- <funcprototype>
- <funcdef>void <function>dallocx</function></funcdef>
- <paramdef>void *<parameter>ptr</parameter></paramdef>
- <paramdef>int <parameter>flags</parameter></paramdef>
- </funcprototype>
- <funcprototype>
- <funcdef>void <function>sdallocx</function></funcdef>
- <paramdef>void *<parameter>ptr</parameter></paramdef>
- <paramdef>size_t <parameter>size</parameter></paramdef>
- <paramdef>int <parameter>flags</parameter></paramdef>
- </funcprototype>
- <funcprototype>
- <funcdef>size_t <function>nallocx</function></funcdef>
- <paramdef>size_t <parameter>size</parameter></paramdef>
- <paramdef>int <parameter>flags</parameter></paramdef>
- </funcprototype>
- <funcprototype>
- <funcdef>int <function>mallctl</function></funcdef>
- <paramdef>const char *<parameter>name</parameter></paramdef>
- <paramdef>void *<parameter>oldp</parameter></paramdef>
- <paramdef>size_t *<parameter>oldlenp</parameter></paramdef>
- <paramdef>void *<parameter>newp</parameter></paramdef>
- <paramdef>size_t <parameter>newlen</parameter></paramdef>
- </funcprototype>
- <funcprototype>
- <funcdef>int <function>mallctlnametomib</function></funcdef>
- <paramdef>const char *<parameter>name</parameter></paramdef>
- <paramdef>size_t *<parameter>mibp</parameter></paramdef>
- <paramdef>size_t *<parameter>miblenp</parameter></paramdef>
- </funcprototype>
- <funcprototype>
- <funcdef>int <function>mallctlbymib</function></funcdef>
- <paramdef>const size_t *<parameter>mib</parameter></paramdef>
- <paramdef>size_t <parameter>miblen</parameter></paramdef>
- <paramdef>void *<parameter>oldp</parameter></paramdef>
- <paramdef>size_t *<parameter>oldlenp</parameter></paramdef>
- <paramdef>void *<parameter>newp</parameter></paramdef>
- <paramdef>size_t <parameter>newlen</parameter></paramdef>
- </funcprototype>
- <funcprototype>
- <funcdef>void <function>malloc_stats_print</function></funcdef>
- <paramdef>void <parameter>(*write_cb)</parameter>
- <funcparams>void *, const char *</funcparams>
- </paramdef>
- <paramdef>void *<parameter>cbopaque</parameter></paramdef>
- <paramdef>const char *<parameter>opts</parameter></paramdef>
- </funcprototype>
- <funcprototype>
- <funcdef>size_t <function>malloc_usable_size</function></funcdef>
- <paramdef>const void *<parameter>ptr</parameter></paramdef>
- </funcprototype>
- <funcprototype>
- <funcdef>void <function>(*malloc_message)</function></funcdef>
- <paramdef>void *<parameter>cbopaque</parameter></paramdef>
- <paramdef>const char *<parameter>s</parameter></paramdef>
- </funcprototype>
- <para><type>const char *</type><varname>malloc_conf</varname>;</para>
- </refsect2>
- </funcsynopsis>
- </refsynopsisdiv>
- <refsect1 id="description">
- <title>DESCRIPTION</title>
- <refsect2>
- <title>Standard API</title>
-
- <para>The <function>malloc()</function> function allocates
- <parameter>size</parameter> bytes of uninitialized memory. The allocated
- space is suitably aligned (after possible pointer coercion) for storage
- of any type of object.</para>
-
- <para>The <function>calloc()</function> function allocates
- space for <parameter>number</parameter> objects, each
- <parameter>size</parameter> bytes in length. The result is identical to
- calling <function>malloc()</function> with an argument of
- <parameter>number</parameter> * <parameter>size</parameter>, with the
- exception that the allocated memory is explicitly initialized to zero
- bytes.</para>
-
- <para>The <function>posix_memalign()</function> function
- allocates <parameter>size</parameter> bytes of memory such that the
- allocation's base address is a multiple of
- <parameter>alignment</parameter>, and returns the allocation in the value
- pointed to by <parameter>ptr</parameter>. The requested
- <parameter>alignment</parameter> must be a power of 2 at least as large as
- <code language="C">sizeof(<type>void *</type>)</code>.</para>
-
- <para>The <function>aligned_alloc()</function> function
- allocates <parameter>size</parameter> bytes of memory such that the
- allocation's base address is a multiple of
- <parameter>alignment</parameter>. The requested
- <parameter>alignment</parameter> must be a power of 2. Behavior is
- undefined if <parameter>size</parameter> is not an integral multiple of
- <parameter>alignment</parameter>.</para>
-
- <para>The <function>realloc()</function> function changes the
- size of the previously allocated memory referenced by
- <parameter>ptr</parameter> to <parameter>size</parameter> bytes. The
- contents of the memory are unchanged up to the lesser of the new and old
- sizes. If the new size is larger, the contents of the newly allocated
- portion of the memory are undefined. Upon success, the memory referenced
- by <parameter>ptr</parameter> is freed and a pointer to the newly
- allocated memory is returned. Note that
- <function>realloc()</function> may move the memory allocation,
- resulting in a different return value than <parameter>ptr</parameter>.
- If <parameter>ptr</parameter> is <constant>NULL</constant>, the
- <function>realloc()</function> function behaves identically to
- <function>malloc()</function> for the specified size.</para>
-
- <para>The <function>free()</function> function causes the
- allocated memory referenced by <parameter>ptr</parameter> to be made
- available for future allocations. If <parameter>ptr</parameter> is
- <constant>NULL</constant>, no action occurs.</para>
- </refsect2>
- <refsect2>
- <title>Non-standard API</title>
- <para>The <function>mallocx()</function>,
- <function>rallocx()</function>,
- <function>xallocx()</function>,
- <function>sallocx()</function>,
- <function>dallocx()</function>,
- <function>sdallocx()</function>, and
- <function>nallocx()</function> functions all have a
- <parameter>flags</parameter> argument that can be used to specify
- options. The functions only check the options that are contextually
- relevant. Use bitwise or (<code language="C">|</code>) operations to
- specify one or more of the following:
- <variablelist>
- <varlistentry id="MALLOCX_LG_ALIGN">
- <term><constant>MALLOCX_LG_ALIGN(<parameter>la</parameter>)
- </constant></term>
-
- <listitem><para>Align the memory allocation to start at an address
- that is a multiple of <code language="C">(1 &lt;&lt;
- <parameter>la</parameter>)</code>. This macro does not validate
- that <parameter>la</parameter> is within the valid
- range.</para></listitem>
- </varlistentry>
- <varlistentry id="MALLOCX_ALIGN">
- <term><constant>MALLOCX_ALIGN(<parameter>a</parameter>)
- </constant></term>
-
- <listitem><para>Align the memory allocation to start at an address
- that is a multiple of <parameter>a</parameter>, where
- <parameter>a</parameter> is a power of two. This macro does not
- validate that <parameter>a</parameter> is a power of 2.
- </para></listitem>
- </varlistentry>
- <varlistentry id="MALLOCX_ZERO">
- <term><constant>MALLOCX_ZERO</constant></term>
-
- <listitem><para>Initialize newly allocated memory to contain zero
- bytes. In the growing reallocation case, the real size prior to
- reallocation defines the boundary between untouched bytes and those
- that are initialized to contain zero bytes. If this macro is
- absent, newly allocated memory is uninitialized.</para></listitem>
- </varlistentry>
- <varlistentry id="MALLOCX_TCACHE">
- <term><constant>MALLOCX_TCACHE(<parameter>tc</parameter>)
- </constant></term>
-
- <listitem><para>Use the thread-specific cache (tcache) specified by
- the identifier <parameter>tc</parameter>, which must have been
- acquired via the <link
- linkend="tcache.create"><mallctl>tcache.create</mallctl></link>
- mallctl. This macro does not validate that
- <parameter>tc</parameter> specifies a valid
- identifier.</para></listitem>
- </varlistentry>
- <varlistentry id="MALLOC_TCACHE_NONE">
- <term><constant>MALLOCX_TCACHE_NONE</constant></term>
-
- <listitem><para>Do not use a thread-specific cache (tcache). Unless
- <constant>MALLOCX_TCACHE(<parameter>tc</parameter>)</constant> or
- <constant>MALLOCX_TCACHE_NONE</constant> is specified, an
- automatically managed tcache will be used under many circumstances.
- This macro cannot be used in the same <parameter>flags</parameter>
- argument as
- <constant>MALLOCX_TCACHE(<parameter>tc</parameter>)</constant>.</para></listitem>
- </varlistentry>
- <varlistentry id="MALLOCX_ARENA">
- <term><constant>MALLOCX_ARENA(<parameter>a</parameter>)
- </constant></term>
-
- <listitem><para>Use the arena specified by the index
- <parameter>a</parameter>. This macro has no effect for regions that
- were allocated via an arena other than the one specified. This
- macro does not validate that <parameter>a</parameter> specifies an
- arena index in the valid range.</para></listitem>
- </varlistentry>
- </variablelist>
- </para>
-
- <para>The <function>mallocx()</function> function allocates at
- least <parameter>size</parameter> bytes of memory, and returns a pointer
- to the base address of the allocation. Behavior is undefined if
- <parameter>size</parameter> is <constant>0</constant>.</para>
-
- <para>The <function>rallocx()</function> function resizes the
- allocation at <parameter>ptr</parameter> to be at least
- <parameter>size</parameter> bytes, and returns a pointer to the base
- address of the resulting allocation, which may or may not have moved from
- its original location. Behavior is undefined if
- <parameter>size</parameter> is <constant>0</constant>.</para>
-
- <para>The <function>xallocx()</function> function resizes the
- allocation at <parameter>ptr</parameter> in place to be at least
- <parameter>size</parameter> bytes, and returns the real size of the
- allocation. If <parameter>extra</parameter> is non-zero, an attempt is
- made to resize the allocation to be at least <code
- language="C">(<parameter>size</parameter> +
- <parameter>extra</parameter>)</code> bytes, though inability to allocate
- the extra byte(s) will not by itself result in failure to resize.
- Behavior is undefined if <parameter>size</parameter> is
- <constant>0</constant>, or if <code
- language="C">(<parameter>size</parameter> + <parameter>extra</parameter>
- &gt; <constant>SIZE_T_MAX</constant>)</code>.</para>
-
- <para>The <function>sallocx()</function> function returns the
- real size of the allocation at <parameter>ptr</parameter>.</para>
-
- <para>The <function>dallocx()</function> function causes the
- memory referenced by <parameter>ptr</parameter> to be made available for
- future allocations.</para>
-
- <para>The <function>sdallocx()</function> function is an
- extension of <function>dallocx()</function> with a
- <parameter>size</parameter> parameter to allow the caller to pass in the
- allocation size as an optimization. The minimum valid input size is the
- original requested size of the allocation, and the maximum valid input
- size is the corresponding value returned by
- <function>nallocx()</function> or
- <function>sallocx()</function>.</para>
-
- <para>The <function>nallocx()</function> function allocates no
- memory, but it performs the same size computation as the
- <function>mallocx()</function> function, and returns the real
- size of the allocation that would result from the equivalent
- <function>mallocx()</function> function call, or
- <constant>0</constant> if the inputs exceed the maximum supported size
- class and/or alignment. Behavior is undefined if
- <parameter>size</parameter> is <constant>0</constant>.</para>
-
- <para>The <function>mallctl()</function> function provides a
- general interface for introspecting the memory allocator, as well as
- setting modifiable parameters and triggering actions. The
- period-separated <parameter>name</parameter> argument specifies a
- location in a tree-structured namespace; see the <xref
- linkend="mallctl_namespace" xrefstyle="template:%t"/> section for
- documentation on the tree contents. To read a value, pass a pointer via
- <parameter>oldp</parameter> to adequate space to contain the value, and a
- pointer to its length via <parameter>oldlenp</parameter>; otherwise pass
- <constant>NULL</constant> and <constant>NULL</constant>. Similarly, to
- write a value, pass a pointer to the value via
- <parameter>newp</parameter>, and its length via
- <parameter>newlen</parameter>; otherwise pass <constant>NULL</constant>
- and <constant>0</constant>.</para>
-
- <para>The <function>mallctlnametomib()</function> function
- provides a way to avoid repeated name lookups for applications that
- repeatedly query the same portion of the namespace, by translating a name
- to a <quote>Management Information Base</quote> (MIB) that can be passed
- repeatedly to <function>mallctlbymib()</function>. Upon
- successful return from <function>mallctlnametomib()</function>,
- <parameter>mibp</parameter> contains an array of
- <parameter>*miblenp</parameter> integers, where
- <parameter>*miblenp</parameter> is the lesser of the number of components
- in <parameter>name</parameter> and the input value of
- <parameter>*miblenp</parameter>. Thus it is possible to pass a
- <parameter>*miblenp</parameter> that is smaller than the number of
- period-separated name components, which results in a partial MIB that can
- be used as the basis for constructing a complete MIB. For name
- components that are integers (e.g. the 2 in
- <link
- linkend="arenas.bin.i.size"><mallctl>arenas.bin.2.size</mallctl></link>),
- the corresponding MIB component will always be that integer. Therefore,
- it is legitimate to construct code like the following: <programlisting
- language="C"><![CDATA[
-unsigned nbins, i;
-size_t mib[4];
-size_t len, miblen;
-
-len = sizeof(nbins);
-mallctl("arenas.nbins", &nbins, &len, NULL, 0);
-
-miblen = 4;
-mallctlnametomib("arenas.bin.0.size", mib, &miblen);
-for (i = 0; i < nbins; i++) {
- size_t bin_size;
-
- mib[2] = i;
- len = sizeof(bin_size);
- mallctlbymib(mib, miblen, (void *)&bin_size, &len, NULL, 0);
- /* Do something with bin_size... */
-}]]></programlisting></para>
-
- <varlistentry id="malloc_stats_print_opts">
- </varlistentry>
- <para>The <function>malloc_stats_print()</function> function writes
- summary statistics via the <parameter>write_cb</parameter> callback
- function pointer and <parameter>cbopaque</parameter> data passed to
- <parameter>write_cb</parameter>, or <function>malloc_message()</function>
- if <parameter>write_cb</parameter> is <constant>NULL</constant>. The
- statistics are presented in human-readable form unless <quote>J</quote> is
- specified as a character within the <parameter>opts</parameter> string, in
- which case the statistics are presented in <ulink
- url="http://www.json.org/">JSON format</ulink>. This function can be
- called repeatedly. General information that never changes during
- execution can be omitted by specifying <quote>g</quote> as a character
- within the <parameter>opts</parameter> string. Note that
- <function>malloc_stats_print()</function> uses the
- <function>mallctl*()</function> functions internally, so inconsistent
- statistics can be reported if multiple threads use these functions
- simultaneously. If <option>--enable-stats</option> is specified during
- configuration, <quote>m</quote>, <quote>d</quote>, and <quote>a</quote>
- can be specified to omit merged arena, destroyed merged arena, and per
- arena statistics, respectively; <quote>b</quote> and <quote>l</quote> can
- be specified to omit per size class statistics for bins and large objects,
- respectively; <quote>x</quote> can be specified to omit all mutex
- statistics; <quote>e</quote> can be used to omit extent statistics.
- Unrecognized characters are silently ignored. Note that thread caching
- may prevent some statistics from being completely up to date, since extra
- locking would be required to merge counters that track thread cache
- operations.</para>
-
- <para>The <function>malloc_usable_size()</function> function
- returns the usable size of the allocation pointed to by
- <parameter>ptr</parameter>. The return value may be larger than the size
- that was requested during allocation. The
- <function>malloc_usable_size()</function> function is not a
- mechanism for in-place <function>realloc()</function>; rather
- it is provided solely as a tool for introspection purposes. Any
- discrepancy between the requested allocation size and the size reported
- by <function>malloc_usable_size()</function> should not be
- depended on, since such behavior is entirely implementation-dependent.
- </para>
- </refsect2>
- </refsect1>
- <refsect1 id="tuning">
- <title>TUNING</title>
- <para>Once, when the first call is made to one of the memory allocation
- routines, the allocator initializes its internals based in part on various
- options that can be specified at compile- or run-time.</para>
-
- <para>The string specified via <option>--with-malloc-conf</option>, the
- string pointed to by the global variable <varname>malloc_conf</varname>, the
- <quote>name</quote> of the file referenced by the symbolic link named
- <filename class="symlink">/etc/malloc.conf</filename>, and the value of the
- environment variable <envar>MALLOC_CONF</envar>, will be interpreted, in
- that order, from left to right as options. Note that
- <varname>malloc_conf</varname> may be read before
- <function>main()</function> is entered, so the declaration of
- <varname>malloc_conf</varname> should specify an initializer that contains
- the final value to be read by jemalloc. <option>--with-malloc-conf</option>
- and <varname>malloc_conf</varname> are compile-time mechanisms, whereas
- <filename class="symlink">/etc/malloc.conf</filename> and
- <envar>MALLOC_CONF</envar> can be safely set any time prior to program
- invocation.</para>
-
- <para>An options string is a comma-separated list of option:value pairs.
- There is one key corresponding to each <link
- linkend="opt.abort"><mallctl>opt.*</mallctl></link> mallctl (see the <xref
- linkend="mallctl_namespace" xrefstyle="template:%t"/> section for options
- documentation). For example, <literal>abort:true,narenas:1</literal> sets
- the <link linkend="opt.abort"><mallctl>opt.abort</mallctl></link> and <link
- linkend="opt.narenas"><mallctl>opt.narenas</mallctl></link> options. Some
- options have boolean values (true/false), others have integer values (base
- 8, 10, or 16, depending on prefix), and yet others have raw string
- values.</para>
- </refsect1>
- <refsect1 id="implementation_notes">
- <title>IMPLEMENTATION NOTES</title>
- <para>Traditionally, allocators have used
- <citerefentry><refentrytitle>sbrk</refentrytitle>
- <manvolnum>2</manvolnum></citerefentry> to obtain memory, which is
- suboptimal for several reasons, including race conditions, increased
- fragmentation, and artificial limitations on maximum usable memory. If
- <citerefentry><refentrytitle>sbrk</refentrytitle>
- <manvolnum>2</manvolnum></citerefentry> is supported by the operating
- system, this allocator uses both
- <citerefentry><refentrytitle>mmap</refentrytitle>
- <manvolnum>2</manvolnum></citerefentry> and
- <citerefentry><refentrytitle>sbrk</refentrytitle>
- <manvolnum>2</manvolnum></citerefentry>, in that order of preference;
- otherwise only <citerefentry><refentrytitle>mmap</refentrytitle>
- <manvolnum>2</manvolnum></citerefentry> is used.</para>
-
- <para>This allocator uses multiple arenas in order to reduce lock
- contention for threaded programs on multi-processor systems. This works
- well with regard to threading scalability, but incurs some costs. There is
- a small fixed per-arena overhead, and additionally, arenas manage memory
- completely independently of each other, which means a small fixed increase
- in overall memory fragmentation. These overheads are not generally an
- issue, given the number of arenas normally used. Note that using
- substantially more arenas than the default is not likely to improve
- performance, mainly due to reduced cache performance. However, it may make
- sense to reduce the number of arenas if an application does not make much
- use of the allocation functions.</para>
-
- <para>In addition to multiple arenas, this allocator supports
- thread-specific caching, in order to make it possible to completely avoid
- synchronization for most allocation requests. Such caching allows very fast
- allocation in the common case, but it increases memory usage and
- fragmentation, since a bounded number of objects can remain allocated in
- each thread cache.</para>
-
- <para>Memory is conceptually broken into extents. Extents are always
- aligned to multiples of the page size. This alignment makes it possible to
- find metadata for user objects quickly. User objects are broken into two
- categories according to size: small and large. Contiguous small objects
- comprise a slab, which resides within a single extent, whereas large objects
- each have their own extents backing them.</para>
-
- <para>Small objects are managed in groups by slabs. Each slab maintains
- a bitmap to track which regions are in use. Allocation requests that are no
- more than half the quantum (8 or 16, depending on architecture) are rounded
- up to the nearest power of two that is at least <code
- language="C">sizeof(<type>double</type>)</code>. All other object size
- classes are multiples of the quantum, spaced such that there are four size
- classes for each doubling in size, which limits internal fragmentation to
- approximately 20% for all but the smallest size classes. Small size classes
- are smaller than four times the page size, and large size classes extend
- from four times the page size up to the largest size class that does not
- exceed <constant>PTRDIFF_MAX</constant>.</para>
-
- <para>Allocations are packed tightly together, which can be an issue for
- multi-threaded applications. If you need to assure that allocations do not
- suffer from cacheline sharing, round your allocation requests up to the
- nearest multiple of the cacheline size, or specify cacheline alignment when
- allocating.</para>
-
- <para>The <function>realloc()</function>,
- <function>rallocx()</function>, and
- <function>xallocx()</function> functions may resize allocations
- without moving them under limited circumstances. Unlike the
- <function>*allocx()</function> API, the standard API does not
- officially round up the usable size of an allocation to the nearest size
- class, so technically it is necessary to call
- <function>realloc()</function> to grow e.g. a 9-byte allocation to
- 16 bytes, or shrink a 16-byte allocation to 9 bytes. Growth and shrinkage
- trivially succeeds in place as long as the pre-size and post-size both round
- up to the same size class. No other API guarantees are made regarding
- in-place resizing, but the current implementation also tries to resize large
- allocations in place, as long as the pre-size and post-size are both large.
- For shrinkage to succeed, the extent allocator must support splitting (see
- <link
- linkend="arena.i.extent_hooks"><mallctl>arena.&lt;i&gt;.extent_hooks</mallctl></link>).
- Growth only succeeds if the trailing memory is currently available, and the
- extent allocator supports merging.</para>
-
- <para>Assuming 4 KiB pages and a 16-byte quantum on a 64-bit system, the
- size classes in each category are as shown in <xref linkend="size_classes"
- xrefstyle="template:Table %n"/>.</para>
-
- <table xml:id="size_classes" frame="all">
- <title>Size classes</title>
- <tgroup cols="3" colsep="1" rowsep="1">
- <colspec colname="c1" align="left"/>
- <colspec colname="c2" align="right"/>
- <colspec colname="c3" align="left"/>
- <thead>
- <row>
- <entry>Category</entry>
- <entry>Spacing</entry>
- <entry>Size</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry morerows="8">Small</entry>
- <entry>lg</entry>
- <entry>[8]</entry>
- </row>
- <row>
- <entry>16</entry>
- <entry>[16, 32, 48, 64, 80, 96, 112, 128]</entry>
- </row>
- <row>
- <entry>32</entry>
- <entry>[160, 192, 224, 256]</entry>
- </row>
- <row>
- <entry>64</entry>
- <entry>[320, 384, 448, 512]</entry>
- </row>
- <row>
- <entry>128</entry>
- <entry>[640, 768, 896, 1024]</entry>
- </row>
- <row>
- <entry>256</entry>
- <entry>[1280, 1536, 1792, 2048]</entry>
- </row>
- <row>
- <entry>512</entry>
- <entry>[2560, 3072, 3584, 4096]</entry>
- </row>
- <row>
- <entry>1 KiB</entry>
- <entry>[5 KiB, 6 KiB, 7 KiB, 8 KiB]</entry>
- </row>
- <row>
- <entry>2 KiB</entry>
- <entry>[10 KiB, 12 KiB, 14 KiB]</entry>
- </row>
- <row>
- <entry morerows="15">Large</entry>
- <entry>2 KiB</entry>
- <entry>[16 KiB]</entry>
- </row>
- <row>
- <entry>4 KiB</entry>
- <entry>[20 KiB, 24 KiB, 28 KiB, 32 KiB]</entry>
- </row>
- <row>
- <entry>8 KiB</entry>
- <entry>[40 KiB, 48 KiB, 54 KiB, 64 KiB]</entry>
- </row>
- <row>
- <entry>16 KiB</entry>
- <entry>[80 KiB, 96 KiB, 112 KiB, 128 KiB]</entry>
- </row>
- <row>
- <entry>32 KiB</entry>
- <entry>[160 KiB, 192 KiB, 224 KiB, 256 KiB]</entry>
- </row>
- <row>
- <entry>64 KiB</entry>
- <entry>[320 KiB, 384 KiB, 448 KiB, 512 KiB]</entry>
- </row>
- <row>
- <entry>128 KiB</entry>
- <entry>[640 KiB, 768 KiB, 896 KiB, 1 MiB]</entry>
- </row>
- <row>
- <entry>256 KiB</entry>
- <entry>[1280 KiB, 1536 KiB, 1792 KiB, 2 MiB]</entry>
- </row>
- <row>
- <entry>512 KiB</entry>
- <entry>[2560 KiB, 3 MiB, 3584 KiB, 4 MiB]</entry>
- </row>
- <row>
- <entry>1 MiB</entry>
- <entry>[5 MiB, 6 MiB, 7 MiB, 8 MiB]</entry>
- </row>
- <row>
- <entry>2 MiB</entry>
- <entry>[10 MiB, 12 MiB, 14 MiB, 16 MiB]</entry>
- </row>
- <row>
- <entry>4 MiB</entry>
- <entry>[20 MiB, 24 MiB, 28 MiB, 32 MiB]</entry>
- </row>
- <row>
- <entry>8 MiB</entry>
- <entry>[40 MiB, 48 MiB, 56 MiB, 64 MiB]</entry>
- </row>
- <row>
- <entry>...</entry>
- <entry>...</entry>
- </row>
- <row>
- <entry>512 PiB</entry>
- <entry>[2560 PiB, 3 EiB, 3584 PiB, 4 EiB]</entry>
- </row>
- <row>
- <entry>1 EiB</entry>
- <entry>[5 EiB, 6 EiB, 7 EiB]</entry>
- </row>
- </tbody>
- </tgroup>
- </table>
- </refsect1>
- <refsect1 id="mallctl_namespace">
- <title>MALLCTL NAMESPACE</title>
- <para>The following names are defined in the namespace accessible via the
- <function>mallctl*()</function> functions. Value types are specified in
- parentheses, their readable/writable statuses are encoded as
- <literal>rw</literal>, <literal>r-</literal>, <literal>-w</literal>, or
- <literal>--</literal>, and required build configuration flags follow, if
- any. A name element encoded as <literal>&lt;i&gt;</literal> or
- <literal>&lt;j&gt;</literal> indicates an integer component, where the
- integer varies from 0 to some upper value that must be determined via
- introspection. In the case of <mallctl>stats.arenas.&lt;i&gt;.*</mallctl>
- and <mallctl>arena.&lt;i&gt;.{initialized,purge,decay,dss}</mallctl>,
- <literal>&lt;i&gt;</literal> equal to
- <constant>MALLCTL_ARENAS_ALL</constant> can be used to operate on all arenas
- or access the summation of statistics from all arenas; similarly
- <literal>&lt;i&gt;</literal> equal to
- <constant>MALLCTL_ARENAS_DESTROYED</constant> can be used to access the
- summation of statistics from all destroyed arenas. These constants can be
- utilized either via <function>mallctlnametomib()</function> followed by
- <function>mallctlbymib()</function>, or via code such as the following:
- <programlisting language="C"><![CDATA[
-#define STRINGIFY_HELPER(x) #x
-#define STRINGIFY(x) STRINGIFY_HELPER(x)
-
-mallctl("arena." STRINGIFY(MALLCTL_ARENAS_ALL) ".decay",
- NULL, NULL, NULL, 0);]]></programlisting>
- Take special note of the <link
- linkend="epoch"><mallctl>epoch</mallctl></link> mallctl, which controls
- refreshing of cached dynamic statistics.</para>
-
- <variablelist>
- <varlistentry id="version">
- <term>
- <mallctl>version</mallctl>
- (<type>const char *</type>)
- <literal>r-</literal>
- </term>
- <listitem><para>Return the jemalloc version string.</para></listitem>
- </varlistentry>
-
- <varlistentry id="epoch">
- <term>
- <mallctl>epoch</mallctl>
- (<type>uint64_t</type>)
- <literal>rw</literal>
- </term>
- <listitem><para>If a value is passed in, refresh the data from which
- the <function>mallctl*()</function> functions report values,
- and increment the epoch. Return the current epoch. This is useful for
- detecting whether another thread caused a refresh.</para></listitem>
- </varlistentry>
-
- <varlistentry id="background_thread">
- <term>
- <mallctl>background_thread</mallctl>
- (<type>bool</type>)
- <literal>rw</literal>
- </term>
- <listitem><para>Enable/disable internal background worker threads. When
- set to true, background threads are created on demand (the number of
- background threads will be no more than the number of CPUs or active
- arenas). Threads run periodically, and handle <link
- linkend="arena.i.decay">purging</link> asynchronously. When switching
- off, background threads are terminated synchronously. Note that after
- <citerefentry><refentrytitle>fork</refentrytitle><manvolnum>2</manvolnum></citerefentry>
- function, the state in the child process will be disabled regardless
- the state in parent process. See <link
- linkend="stats.background_thread.num_threads"><mallctl>stats.background_thread</mallctl></link>
- for related stats. <link
- linkend="opt.background_thread"><mallctl>opt.background_thread</mallctl></link>
- can be used to set the default option. This option is only available on
- selected pthread-based platforms.</para></listitem>
- </varlistentry>
-
- <varlistentry id="max_background_threads">
- <term>
- <mallctl>max_background_threads</mallctl>
- (<type>size_t</type>)
- <literal>rw</literal>
- </term>
- <listitem><para>Maximum number of background worker threads that will
- be created. This value is capped at <link
- linkend="opt.max_background_threads"><mallctl>opt.max_background_threads</mallctl></link> at
- startup.</para></listitem>
- </varlistentry>
-
- <varlistentry id="config.cache_oblivious">
- <term>
- <mallctl>config.cache_oblivious</mallctl>
- (<type>bool</type>)
- <literal>r-</literal>
- </term>
- <listitem><para><option>--enable-cache-oblivious</option> was specified
- during build configuration.</para></listitem>
- </varlistentry>
-
- <varlistentry id="config.debug">
- <term>
- <mallctl>config.debug</mallctl>
- (<type>bool</type>)
- <literal>r-</literal>
- </term>
- <listitem><para><option>--enable-debug</option> was specified during
- build configuration.</para></listitem>
- </varlistentry>
-
- <varlistentry id="config.fill">
- <term>
- <mallctl>config.fill</mallctl>
- (<type>bool</type>)
- <literal>r-</literal>
- </term>
- <listitem><para><option>--enable-fill</option> was specified during
- build configuration.</para></listitem>
- </varlistentry>
-
- <varlistentry id="config.lazy_lock">
- <term>
- <mallctl>config.lazy_lock</mallctl>
- (<type>bool</type>)
- <literal>r-</literal>
- </term>
- <listitem><para><option>--enable-lazy-lock</option> was specified
- during build configuration.</para></listitem>
- </varlistentry>
-
- <varlistentry id="config.malloc_conf">
- <term>
- <mallctl>config.malloc_conf</mallctl>
- (<type>const char *</type>)
- <literal>r-</literal>
- </term>
- <listitem><para>Embedded configure-time-specified run-time options
- string, empty unless <option>--with-malloc-conf</option> was specified
- during build configuration.</para></listitem>
- </varlistentry>
-
- <varlistentry id="config.prof">
- <term>
- <mallctl>config.prof</mallctl>
- (<type>bool</type>)
- <literal>r-</literal>
- </term>
- <listitem><para><option>--enable-prof</option> was specified during
- build configuration.</para></listitem>
- </varlistentry>
-
- <varlistentry id="config.prof_libgcc">
- <term>
- <mallctl>config.prof_libgcc</mallctl>
- (<type>bool</type>)
- <literal>r-</literal>
- </term>
- <listitem><para><option>--disable-prof-libgcc</option> was not
- specified during build configuration.</para></listitem>
- </varlistentry>
-
- <varlistentry id="config.prof_libunwind">
- <term>
- <mallctl>config.prof_libunwind</mallctl>
- (<type>bool</type>)
- <literal>r-</literal>
- </term>
- <listitem><para><option>--enable-prof-libunwind</option> was specified
- during build configuration.</para></listitem>
- </varlistentry>
-
- <varlistentry id="config.stats">
- <term>
- <mallctl>config.stats</mallctl>
- (<type>bool</type>)
- <literal>r-</literal>
- </term>
- <listitem><para><option>--enable-stats</option> was specified during
- build configuration.</para></listitem>
- </varlistentry>
-
-
- <varlistentry id="config.utrace">
- <term>
- <mallctl>config.utrace</mallctl>
- (<type>bool</type>)
- <literal>r-</literal>
- </term>
- <listitem><para><option>--enable-utrace</option> was specified during
- build configuration.</para></listitem>
- </varlistentry>
-
- <varlistentry id="config.xmalloc">
- <term>
- <mallctl>config.xmalloc</mallctl>
- (<type>bool</type>)
- <literal>r-</literal>
- </term>
- <listitem><para><option>--enable-xmalloc</option> was specified during
- build configuration.</para></listitem>
- </varlistentry>
-
- <varlistentry id="opt.abort">
- <term>
- <mallctl>opt.abort</mallctl>
- (<type>bool</type>)
- <literal>r-</literal>
- </term>
- <listitem><para>Abort-on-warning enabled/disabled. If true, most
- warnings are fatal. Note that runtime option warnings are not included
- (see <link
- linkend="opt.abort_conf"><mallctl>opt.abort_conf</mallctl></link> for
- that). The process will call
- <citerefentry><refentrytitle>abort</refentrytitle>
- <manvolnum>3</manvolnum></citerefentry> in these cases. This option is
- disabled by default unless <option>--enable-debug</option> is
- specified during configuration, in which case it is enabled by default.
- </para></listitem>
- </varlistentry>
-
- <varlistentry id="opt.confirm_conf">
- <term>
- <mallctl>opt.confirm_conf</mallctl>
- (<type>bool</type>)
- <literal>r-</literal>
- </term>
- <listitem><para>Confirm-runtime-options-when-program-starts
- enabled/disabled. If true, the string specified via
- <option>--with-malloc-conf</option>, the string pointed to by the
- global variable <varname>malloc_conf</varname>, the <quote>name</quote>
- of the file referenced by the symbolic link named
- <filename class="symlink">/etc/malloc.conf</filename>, and the value of
- the environment variable <envar>MALLOC_CONF</envar>, will be printed in
- order. Then, each option being set will be individually printed. This
- option is disabled by default.</para></listitem>
- </varlistentry>
-
- <varlistentry id="opt.abort_conf">
- <term>
- <mallctl>opt.abort_conf</mallctl>
- (<type>bool</type>)
- <literal>r-</literal>
- </term>
- <listitem><para>Abort-on-invalid-configuration enabled/disabled. If
- true, invalid runtime options are fatal. The process will call
- <citerefentry><refentrytitle>abort</refentrytitle>
- <manvolnum>3</manvolnum></citerefentry> in these cases. This option is
- disabled by default unless <option>--enable-debug</option> is
- specified during configuration, in which case it is enabled by default.
- </para></listitem>
- </varlistentry>
-
- <varlistentry id="opt.metadata_thp">
- <term>
- <mallctl>opt.metadata_thp</mallctl>
- (<type>const char *</type>)
- <literal>r-</literal>
- </term>
- <listitem><para>Controls whether to allow jemalloc to use transparent
- huge page (THP) for internal metadata (see <link
- linkend="stats.metadata">stats.metadata</link>). <quote>always</quote>
- allows such usage. <quote>auto</quote> uses no THP initially, but may
- begin to do so when metadata usage reaches certain level. The default
- is <quote>disabled</quote>.</para></listitem>
- </varlistentry>
-
- <varlistentry id="opt.retain">
- <term>
- <mallctl>opt.retain</mallctl>
- (<type>bool</type>)
- <literal>r-</literal>
- </term>
- <listitem><para>If true, retain unused virtual memory for later reuse
- rather than discarding it by calling
- <citerefentry><refentrytitle>munmap</refentrytitle>
- <manvolnum>2</manvolnum></citerefentry> or equivalent (see <link
- linkend="stats.retained">stats.retained</link> for related details).
- It also makes jemalloc use <citerefentry>
- <refentrytitle>mmap</refentrytitle><manvolnum>2</manvolnum>
- </citerefentry> or equivalent in a more greedy way, mapping larger
- chunks in one go. This option is disabled by default unless discarding
- virtual memory is known to trigger platform-specific performance
- problems, namely 1) for [64-bit] Linux, which has a quirk in its virtual
- memory allocation algorithm that causes semi-permanent VM map holes
- under normal jemalloc operation; and 2) for [64-bit] Windows, which
- disallows split / merged regions with
- <parameter><constant>MEM_RELEASE</constant></parameter>. Although the
- same issues may present on 32-bit platforms as well, retaining virtual
- memory for 32-bit Linux and Windows is disabled by default due to the
- practical possibility of address space exhaustion. </para></listitem>
- </varlistentry>
-
- <varlistentry id="opt.dss">
- <term>
- <mallctl>opt.dss</mallctl>
- (<type>const char *</type>)
- <literal>r-</literal>
- </term>
- <listitem><para>dss (<citerefentry><refentrytitle>sbrk</refentrytitle>
- <manvolnum>2</manvolnum></citerefentry>) allocation precedence as
- related to <citerefentry><refentrytitle>mmap</refentrytitle>
- <manvolnum>2</manvolnum></citerefentry> allocation. The following
- settings are supported if
- <citerefentry><refentrytitle>sbrk</refentrytitle>
- <manvolnum>2</manvolnum></citerefentry> is supported by the operating
- system: <quote>disabled</quote>, <quote>primary</quote>, and
- <quote>secondary</quote>; otherwise only <quote>disabled</quote> is
- supported. The default is <quote>secondary</quote> if
- <citerefentry><refentrytitle>sbrk</refentrytitle>
- <manvolnum>2</manvolnum></citerefentry> is supported by the operating
- system; <quote>disabled</quote> otherwise.
- </para></listitem>
- </varlistentry>
-
- <varlistentry id="opt.narenas">
- <term>
- <mallctl>opt.narenas</mallctl>
- (<type>unsigned</type>)
- <literal>r-</literal>
- </term>
- <listitem><para>Maximum number of arenas to use for automatic
- multiplexing of threads and arenas. The default is four times the
- number of CPUs, or one if there is a single CPU.</para></listitem>
- </varlistentry>
-
- <varlistentry id="opt.oversize_threshold">
- <term>
- <mallctl>opt.oversize_threshold</mallctl>
- (<type>size_t</type>)
- <literal>r-</literal>
- </term>
- <listitem><para>The threshold in bytes of which requests are considered
- oversize. Allocation requests with greater sizes are fulfilled from a
- dedicated arena (automatically managed, however not within
- <literal>narenas</literal>), in order to reduce fragmentation by not
- mixing huge allocations with small ones. In addition, the decay API
- guarantees on the extents greater than the specified threshold may be
- overridden. Note that requests with arena index specified via
- <constant>MALLOCX_ARENA</constant>, or threads associated with explicit
- arenas will not be considered. The default threshold is 8MiB. Values
- not within large size classes disables this feature.</para></listitem>
- </varlistentry>
-
- <varlistentry id="opt.percpu_arena">
- <term>
- <mallctl>opt.percpu_arena</mallctl>
- (<type>const char *</type>)
- <literal>r-</literal>
- </term>
- <listitem><para>Per CPU arena mode. Use the <quote>percpu</quote>
- setting to enable this feature, which uses number of CPUs to determine
- number of arenas, and bind threads to arenas dynamically based on the
- CPU the thread runs on currently. <quote>phycpu</quote> setting uses
- one arena per physical CPU, which means the two hyper threads on the
- same CPU share one arena. Note that no runtime checking regarding the
- availability of hyper threading is done at the moment. When set to
- <quote>disabled</quote>, narenas and thread to arena association will
- not be impacted by this option. The default is <quote>disabled</quote>.
- </para></listitem>
- </varlistentry>
-
- <varlistentry id="opt.background_thread">
- <term>
- <mallctl>opt.background_thread</mallctl>
- (<type>bool</type>)
- <literal>r-</literal>
- </term>
- <listitem><para>Internal background worker threads enabled/disabled.
- Because of potential circular dependencies, enabling background thread
- using this option may cause crash or deadlock during initialization. For
- a reliable way to use this feature, see <link
- linkend="background_thread">background_thread</link> for dynamic control
- options and details. This option is disabled by
- default.</para></listitem>
- </varlistentry>
-
- <varlistentry id="opt.max_background_threads">
- <term>
- <mallctl>opt.max_background_threads</mallctl>
- (<type>size_t</type>)
- <literal>r-</literal>
- </term>
- <listitem><para>Maximum number of background threads that will be created
- if <link linkend="background_thread">background_thread</link> is set.
- Defaults to number of cpus.</para></listitem>
- </varlistentry>
-
- <varlistentry id="opt.dirty_decay_ms">
- <term>
- <mallctl>opt.dirty_decay_ms</mallctl>
- (<type>ssize_t</type>)
- <literal>r-</literal>
- </term>
- <listitem><para>Approximate time in milliseconds from the creation of a
- set of unused dirty pages until an equivalent set of unused dirty pages
- is purged (i.e. converted to muzzy via e.g.
- <function>madvise(<parameter>...</parameter><parameter><constant>MADV_FREE</constant></parameter>)</function>
- if supported by the operating system, or converted to clean otherwise)
- and/or reused. Dirty pages are defined as previously having been
- potentially written to by the application, and therefore consuming
- physical memory, yet having no current use. The pages are incrementally
- purged according to a sigmoidal decay curve that starts and ends with
- zero purge rate. A decay time of 0 causes all unused dirty pages to be
- purged immediately upon creation. A decay time of -1 disables purging.
- The default decay time is 10 seconds. See <link
- linkend="arenas.dirty_decay_ms"><mallctl>arenas.dirty_decay_ms</mallctl></link>
- and <link
- linkend="arena.i.dirty_decay_ms"><mallctl>arena.&lt;i&gt;.dirty_decay_ms</mallctl></link>
- for related dynamic control options. See <link
- linkend="opt.muzzy_decay_ms"><mallctl>opt.muzzy_decay_ms</mallctl></link>
- for a description of muzzy pages.for a description of muzzy pages. Note
- that when the <link
- linkend="opt.oversize_threshold"><mallctl>oversize_threshold</mallctl></link>
- feature is enabled, the arenas reserved for oversize requests may have
- its own default decay settings.</para></listitem>
- </varlistentry>
-
- <varlistentry id="opt.muzzy_decay_ms">
- <term>
- <mallctl>opt.muzzy_decay_ms</mallctl>
- (<type>ssize_t</type>)
- <literal>r-</literal>
- </term>
- <listitem><para>Approximate time in milliseconds from the creation of a
- set of unused muzzy pages until an equivalent set of unused muzzy pages
- is purged (i.e. converted to clean) and/or reused. Muzzy pages are
- defined as previously having been unused dirty pages that were
- subsequently purged in a manner that left them subject to the
- reclamation whims of the operating system (e.g.
- <function>madvise(<parameter>...</parameter><parameter><constant>MADV_FREE</constant></parameter>)</function>),
- and therefore in an indeterminate state. The pages are incrementally
- purged according to a sigmoidal decay curve that starts and ends with
- zero purge rate. A decay time of 0 causes all unused muzzy pages to be
- purged immediately upon creation. A decay time of -1 disables purging.
- The default decay time is 10 seconds. See <link
- linkend="arenas.muzzy_decay_ms"><mallctl>arenas.muzzy_decay_ms</mallctl></link>
- and <link
- linkend="arena.i.muzzy_decay_ms"><mallctl>arena.&lt;i&gt;.muzzy_decay_ms</mallctl></link>
- for related dynamic control options.</para></listitem>
- </varlistentry>
-
- <varlistentry id="opt.lg_extent_max_active_fit">
- <term>
- <mallctl>opt.lg_extent_max_active_fit</mallctl>
- (<type>size_t</type>)
- <literal>r-</literal>
- </term>
- <listitem><para>When reusing dirty extents, this determines the (log
- base 2 of the) maximum ratio between the size of the active extent
- selected (to split off from) and the size of the requested allocation.
- This prevents the splitting of large active extents for smaller
- allocations, which can reduce fragmentation over the long run
- (especially for non-active extents). Lower value may reduce
- fragmentation, at the cost of extra active extents. The default value
- is 6, which gives a maximum ratio of 64 (2^6).</para></listitem>
- </varlistentry>
-
- <varlistentry id="opt.stats_print">
- <term>
- <mallctl>opt.stats_print</mallctl>
- (<type>bool</type>)
- <literal>r-</literal>
- </term>
- <listitem><para>Enable/disable statistics printing at exit. If
- enabled, the <function>malloc_stats_print()</function>
- function is called at program exit via an
- <citerefentry><refentrytitle>atexit</refentrytitle>
- <manvolnum>3</manvolnum></citerefentry> function. <link
- linkend="opt.stats_print_opts"><mallctl>opt.stats_print_opts</mallctl></link>
- can be combined to specify output options. If
- <option>--enable-stats</option> is specified during configuration, this
- has the potential to cause deadlock for a multi-threaded process that
- exits while one or more threads are executing in the memory allocation
- functions. Furthermore, <function>atexit()</function> may
- allocate memory during application initialization and then deadlock
- internally when jemalloc in turn calls
- <function>atexit()</function>, so this option is not
- universally usable (though the application can register its own
- <function>atexit()</function> function with equivalent
- functionality). Therefore, this option should only be used with care;
- it is primarily intended as a performance tuning aid during application
- development. This option is disabled by default.</para></listitem>
- </varlistentry>
-
- <varlistentry id="opt.stats_print_opts">
- <term>
- <mallctl>opt.stats_print_opts</mallctl>
- (<type>const char *</type>)
- <literal>r-</literal>
- </term>
- <listitem><para>Options (the <parameter>opts</parameter> string) to pass
- to the <function>malloc_stats_print()</function> at exit (enabled
- through <link
- linkend="opt.stats_print"><mallctl>opt.stats_print</mallctl></link>). See
- available options in <link
- linkend="malloc_stats_print_opts"><function>malloc_stats_print()</function></link>.
- Has no effect unless <link
- linkend="opt.stats_print"><mallctl>opt.stats_print</mallctl></link> is
- enabled. The default is <quote></quote>.</para></listitem>
- </varlistentry>
-
- <varlistentry id="opt.junk">
- <term>
- <mallctl>opt.junk</mallctl>
- (<type>const char *</type>)
- <literal>r-</literal>
- [<option>--enable-fill</option>]
- </term>
- <listitem><para>Junk filling. If set to <quote>alloc</quote>, each byte
- of uninitialized allocated memory will be initialized to
- <literal>0xa5</literal>. If set to <quote>free</quote>, all deallocated
- memory will be initialized to <literal>0x5a</literal>. If set to
- <quote>true</quote>, both allocated and deallocated memory will be
- initialized, and if set to <quote>false</quote>, junk filling be
- disabled entirely. This is intended for debugging and will impact
- performance negatively. This option is <quote>false</quote> by default
- unless <option>--enable-debug</option> is specified during
- configuration, in which case it is <quote>true</quote> by
- default.</para></listitem>
- </varlistentry>
-
- <varlistentry id="opt.zero">
- <term>
- <mallctl>opt.zero</mallctl>
- (<type>bool</type>)
- <literal>r-</literal>
- [<option>--enable-fill</option>]
- </term>
- <listitem><para>Zero filling enabled/disabled. If enabled, each byte
- of uninitialized allocated memory will be initialized to 0. Note that
- this initialization only happens once for each byte, so
- <function>realloc()</function> and
- <function>rallocx()</function> calls do not zero memory that
- was previously allocated. This is intended for debugging and will
- impact performance negatively. This option is disabled by default.
- </para></listitem>
- </varlistentry>
-
- <varlistentry id="opt.utrace">
- <term>
- <mallctl>opt.utrace</mallctl>
- (<type>bool</type>)
- <literal>r-</literal>
- [<option>--enable-utrace</option>]
- </term>
- <listitem><para>Allocation tracing based on
- <citerefentry><refentrytitle>utrace</refentrytitle>
- <manvolnum>2</manvolnum></citerefentry> enabled/disabled. This option
- is disabled by default.</para></listitem>
- </varlistentry>
-
- <varlistentry id="opt.xmalloc">
- <term>
- <mallctl>opt.xmalloc</mallctl>
- (<type>bool</type>)
- <literal>r-</literal>
- [<option>--enable-xmalloc</option>]
- </term>
- <listitem><para>Abort-on-out-of-memory enabled/disabled. If enabled,
- rather than returning failure for any allocation function, display a
- diagnostic message on <constant>STDERR_FILENO</constant> and cause the
- program to drop core (using
- <citerefentry><refentrytitle>abort</refentrytitle>
- <manvolnum>3</manvolnum></citerefentry>). If an application is
- designed to depend on this behavior, set the option at compile time by
- including the following in the source code:
- <programlisting language="C"><![CDATA[
-malloc_conf = "xmalloc:true";]]></programlisting>
- This option is disabled by default.</para></listitem>
- </varlistentry>
-
- <varlistentry id="opt.tcache">
- <term>
- <mallctl>opt.tcache</mallctl>
- (<type>bool</type>)
- <literal>r-</literal>
- </term>
- <listitem><para>Thread-specific caching (tcache) enabled/disabled. When
- there are multiple threads, each thread uses a tcache for objects up to
- a certain size. Thread-specific caching allows many allocations to be
- satisfied without performing any thread synchronization, at the cost of
- increased memory use. See the <link
- linkend="opt.lg_tcache_max"><mallctl>opt.lg_tcache_max</mallctl></link>
- option for related tuning information. This option is enabled by
- default.</para></listitem>
- </varlistentry>
-
- <varlistentry id="opt.lg_tcache_max">
- <term>
- <mallctl>opt.lg_tcache_max</mallctl>
- (<type>size_t</type>)
- <literal>r-</literal>
- </term>
- <listitem><para>Maximum size class (log base 2) to cache in the
- thread-specific cache (tcache). At a minimum, all small size classes
- are cached, and at a maximum all large size classes are cached. The
- default maximum is 32 KiB (2^15).</para></listitem>
- </varlistentry>
-
- <varlistentry id="opt.thp">
- <term>
- <mallctl>opt.thp</mallctl>
- (<type>const char *</type>)
- <literal>r-</literal>
- </term>
- <listitem><para>Transparent hugepage (THP) mode. Settings "always",
- "never" and "default" are available if THP is supported by the operating
- system. The "always" setting enables transparent hugepage for all user
- memory mappings with
- <parameter><constant>MADV_HUGEPAGE</constant></parameter>; "never"
- ensures no transparent hugepage with
- <parameter><constant>MADV_NOHUGEPAGE</constant></parameter>; the default
- setting "default" makes no changes. Note that: this option does not
- affect THP for jemalloc internal metadata (see <link
- linkend="opt.metadata_thp"><mallctl>opt.metadata_thp</mallctl></link>);
- in addition, for arenas with customized <link
- linkend="arena.i.extent_hooks"><mallctl>extent_hooks</mallctl></link>,
- this option is bypassed as it is implemented as part of the default
- extent hooks.</para></listitem>
- </varlistentry>
-
- <varlistentry id="opt.prof">
- <term>
- <mallctl>opt.prof</mallctl>
- (<type>bool</type>)
- <literal>r-</literal>
- [<option>--enable-prof</option>]
- </term>
- <listitem><para>Memory profiling enabled/disabled. If enabled, profile
- memory allocation activity. See the <link
- linkend="opt.prof_active"><mallctl>opt.prof_active</mallctl></link>
- option for on-the-fly activation/deactivation. See the <link
- linkend="opt.lg_prof_sample"><mallctl>opt.lg_prof_sample</mallctl></link>
- option for probabilistic sampling control. See the <link
- linkend="opt.prof_accum"><mallctl>opt.prof_accum</mallctl></link>
- option for control of cumulative sample reporting. See the <link
- linkend="opt.lg_prof_interval"><mallctl>opt.lg_prof_interval</mallctl></link>
- option for information on interval-triggered profile dumping, the <link
- linkend="opt.prof_gdump"><mallctl>opt.prof_gdump</mallctl></link>
- option for information on high-water-triggered profile dumping, and the
- <link linkend="opt.prof_final"><mallctl>opt.prof_final</mallctl></link>
- option for final profile dumping. Profile output is compatible with
- the <command>jeprof</command> command, which is based on the
- <command>pprof</command> that is developed as part of the <ulink
- url="http://code.google.com/p/gperftools/">gperftools
- package</ulink>. See <link linkend="heap_profile_format">HEAP PROFILE
- FORMAT</link> for heap profile format documentation.</para></listitem>
- </varlistentry>
-
- <varlistentry id="opt.prof_prefix">
- <term>
- <mallctl>opt.prof_prefix</mallctl>
- (<type>const char *</type>)
- <literal>r-</literal>
- [<option>--enable-prof</option>]
- </term>
- <listitem><para>Filename prefix for profile dumps. If the prefix is
- set to the empty string, no automatic dumps will occur; this is
- primarily useful for disabling the automatic final heap dump (which
- also disables leak reporting, if enabled). The default prefix is
- <filename>jeprof</filename>.</para></listitem>
- </varlistentry>
-
- <varlistentry id="opt.prof_active">
- <term>
- <mallctl>opt.prof_active</mallctl>
- (<type>bool</type>)
- <literal>r-</literal>
- [<option>--enable-prof</option>]
- </term>
- <listitem><para>Profiling activated/deactivated. This is a secondary
- control mechanism that makes it possible to start the application with
- profiling enabled (see the <link
- linkend="opt.prof"><mallctl>opt.prof</mallctl></link> option) but
- inactive, then toggle profiling at any time during program execution
- with the <link
- linkend="prof.active"><mallctl>prof.active</mallctl></link> mallctl.
- This option is enabled by default.</para></listitem>
- </varlistentry>
-
- <varlistentry id="opt.prof_thread_active_init">
- <term>
- <mallctl>opt.prof_thread_active_init</mallctl>
- (<type>bool</type>)
- <literal>r-</literal>
- [<option>--enable-prof</option>]
- </term>
- <listitem><para>Initial setting for <link
- linkend="thread.prof.active"><mallctl>thread.prof.active</mallctl></link>
- in newly created threads. The initial setting for newly created threads
- can also be changed during execution via the <link
- linkend="prof.thread_active_init"><mallctl>prof.thread_active_init</mallctl></link>
- mallctl. This option is enabled by default.</para></listitem>
- </varlistentry>
-
- <varlistentry id="opt.lg_prof_sample">
- <term>
- <mallctl>opt.lg_prof_sample</mallctl>
- (<type>size_t</type>)
- <literal>r-</literal>
- [<option>--enable-prof</option>]
- </term>
- <listitem><para>Average interval (log base 2) between allocation
- samples, as measured in bytes of allocation activity. Increasing the
- sampling interval decreases profile fidelity, but also decreases the
- computational overhead. The default sample interval is 512 KiB (2^19
- B).</para></listitem>
- </varlistentry>
-
- <varlistentry id="opt.prof_accum">
- <term>
- <mallctl>opt.prof_accum</mallctl>
- (<type>bool</type>)
- <literal>r-</literal>
- [<option>--enable-prof</option>]
- </term>
- <listitem><para>Reporting of cumulative object/byte counts in profile
- dumps enabled/disabled. If this option is enabled, every unique
- backtrace must be stored for the duration of execution. Depending on
- the application, this can impose a large memory overhead, and the
- cumulative counts are not always of interest. This option is disabled
- by default.</para></listitem>
- </varlistentry>
-
- <varlistentry id="opt.lg_prof_interval">
- <term>
- <mallctl>opt.lg_prof_interval</mallctl>
- (<type>ssize_t</type>)
- <literal>r-</literal>
- [<option>--enable-prof</option>]
- </term>
- <listitem><para>Average interval (log base 2) between memory profile
- dumps, as measured in bytes of allocation activity. The actual
- interval between dumps may be sporadic because decentralized allocation
- counters are used to avoid synchronization bottlenecks. Profiles are
- dumped to files named according to the pattern
- <filename>&lt;prefix&gt;.&lt;pid&gt;.&lt;seq&gt;.i&lt;iseq&gt;.heap</filename>,
- where <literal>&lt;prefix&gt;</literal> is controlled by the
- <link
- linkend="opt.prof_prefix"><mallctl>opt.prof_prefix</mallctl></link>
- option. By default, interval-triggered profile dumping is disabled
- (encoded as -1).
- </para></listitem>
- </varlistentry>
-
- <varlistentry id="opt.prof_gdump">
- <term>
- <mallctl>opt.prof_gdump</mallctl>
- (<type>bool</type>)
- <literal>r-</literal>
- [<option>--enable-prof</option>]
- </term>
- <listitem><para>Set the initial state of <link
- linkend="prof.gdump"><mallctl>prof.gdump</mallctl></link>, which when
- enabled triggers a memory profile dump every time the total virtual
- memory exceeds the previous maximum. This option is disabled by
- default.</para></listitem>
- </varlistentry>
-
- <varlistentry id="opt.prof_final">
- <term>
- <mallctl>opt.prof_final</mallctl>
- (<type>bool</type>)
- <literal>r-</literal>
- [<option>--enable-prof</option>]
- </term>
- <listitem><para>Use an
- <citerefentry><refentrytitle>atexit</refentrytitle>
- <manvolnum>3</manvolnum></citerefentry> function to dump final memory
- usage to a file named according to the pattern
- <filename>&lt;prefix&gt;.&lt;pid&gt;.&lt;seq&gt;.f.heap</filename>,
- where <literal>&lt;prefix&gt;</literal> is controlled by the <link
- linkend="opt.prof_prefix"><mallctl>opt.prof_prefix</mallctl></link>
- option. Note that <function>atexit()</function> may allocate
- memory during application initialization and then deadlock internally
- when jemalloc in turn calls <function>atexit()</function>, so
- this option is not universally usable (though the application can
- register its own <function>atexit()</function> function with
- equivalent functionality). This option is disabled by
- default.</para></listitem>
- </varlistentry>
-
- <varlistentry id="opt.prof_leak">
- <term>
- <mallctl>opt.prof_leak</mallctl>
- (<type>bool</type>)
- <literal>r-</literal>
- [<option>--enable-prof</option>]
- </term>
- <listitem><para>Leak reporting enabled/disabled. If enabled, use an
- <citerefentry><refentrytitle>atexit</refentrytitle>
- <manvolnum>3</manvolnum></citerefentry> function to report memory leaks
- detected by allocation sampling. See the
- <link linkend="opt.prof"><mallctl>opt.prof</mallctl></link> option for
- information on analyzing heap profile output. This option is disabled
- by default.</para></listitem>
- </varlistentry>
-
- <varlistentry id="thread.arena">
- <term>
- <mallctl>thread.arena</mallctl>
- (<type>unsigned</type>)
- <literal>rw</literal>
- </term>
- <listitem><para>Get or set the arena associated with the calling
- thread. If the specified arena was not initialized beforehand (see the
- <link
- linkend="arena.i.initialized"><mallctl>arena.i.initialized</mallctl></link>
- mallctl), it will be automatically initialized as a side effect of
- calling this interface.</para></listitem>
- </varlistentry>
-
- <varlistentry id="thread.allocated">
- <term>
- <mallctl>thread.allocated</mallctl>
- (<type>uint64_t</type>)
- <literal>r-</literal>
- [<option>--enable-stats</option>]
- </term>
- <listitem><para>Get the total number of bytes ever allocated by the
- calling thread. This counter has the potential to wrap around; it is
- up to the application to appropriately interpret the counter in such
- cases.</para></listitem>
- </varlistentry>
-
- <varlistentry id="thread.allocatedp">
- <term>
- <mallctl>thread.allocatedp</mallctl>
- (<type>uint64_t *</type>)
- <literal>r-</literal>
- [<option>--enable-stats</option>]
- </term>
- <listitem><para>Get a pointer to the the value that is returned by the
- <link
- linkend="thread.allocated"><mallctl>thread.allocated</mallctl></link>
- mallctl. This is useful for avoiding the overhead of repeated
- <function>mallctl*()</function> calls.</para></listitem>
- </varlistentry>
-
- <varlistentry id="thread.deallocated">
- <term>
- <mallctl>thread.deallocated</mallctl>
- (<type>uint64_t</type>)
- <literal>r-</literal>
- [<option>--enable-stats</option>]
- </term>
- <listitem><para>Get the total number of bytes ever deallocated by the
- calling thread. This counter has the potential to wrap around; it is
- up to the application to appropriately interpret the counter in such
- cases.</para></listitem>
- </varlistentry>
-
- <varlistentry id="thread.deallocatedp">
- <term>
- <mallctl>thread.deallocatedp</mallctl>
- (<type>uint64_t *</type>)
- <literal>r-</literal>
- [<option>--enable-stats</option>]
- </term>
- <listitem><para>Get a pointer to the the value that is returned by the
- <link
- linkend="thread.deallocated"><mallctl>thread.deallocated</mallctl></link>
- mallctl. This is useful for avoiding the overhead of repeated
- <function>mallctl*()</function> calls.</para></listitem>
- </varlistentry>
-
- <varlistentry id="thread.tcache.enabled">
- <term>
- <mallctl>thread.tcache.enabled</mallctl>
- (<type>bool</type>)
- <literal>rw</literal>
- </term>
- <listitem><para>Enable/disable calling thread's tcache. The tcache is
- implicitly flushed as a side effect of becoming
- disabled (see <link
- linkend="thread.tcache.flush"><mallctl>thread.tcache.flush</mallctl></link>).
- </para></listitem>
- </varlistentry>
-
- <varlistentry id="thread.tcache.flush">
- <term>
- <mallctl>thread.tcache.flush</mallctl>
- (<type>void</type>)
- <literal>--</literal>
- </term>
- <listitem><para>Flush calling thread's thread-specific cache (tcache).
- This interface releases all cached objects and internal data structures
- associated with the calling thread's tcache. Ordinarily, this interface
- need not be called, since automatic periodic incremental garbage
- collection occurs, and the thread cache is automatically discarded when
- a thread exits. However, garbage collection is triggered by allocation
- activity, so it is possible for a thread that stops
- allocating/deallocating to retain its cache indefinitely, in which case
- the developer may find manual flushing useful.</para></listitem>
- </varlistentry>
-
- <varlistentry id="thread.prof.name">
- <term>
- <mallctl>thread.prof.name</mallctl>
- (<type>const char *</type>)
- <literal>r-</literal> or
- <literal>-w</literal>
- [<option>--enable-prof</option>]
- </term>
- <listitem><para>Get/set the descriptive name associated with the calling
- thread in memory profile dumps. An internal copy of the name string is
- created, so the input string need not be maintained after this interface
- completes execution. The output string of this interface should be
- copied for non-ephemeral uses, because multiple implementation details
- can cause asynchronous string deallocation. Furthermore, each
- invocation of this interface can only read or write; simultaneous
- read/write is not supported due to string lifetime limitations. The
- name string must be nil-terminated and comprised only of characters in
- the sets recognized
- by <citerefentry><refentrytitle>isgraph</refentrytitle>
- <manvolnum>3</manvolnum></citerefentry> and
- <citerefentry><refentrytitle>isblank</refentrytitle>
- <manvolnum>3</manvolnum></citerefentry>.</para></listitem>
- </varlistentry>
-
- <varlistentry id="thread.prof.active">
- <term>
- <mallctl>thread.prof.active</mallctl>
- (<type>bool</type>)
- <literal>rw</literal>
- [<option>--enable-prof</option>]
- </term>
- <listitem><para>Control whether sampling is currently active for the
- calling thread. This is an activation mechanism in addition to <link
- linkend="prof.active"><mallctl>prof.active</mallctl></link>; both must
- be active for the calling thread to sample. This flag is enabled by
- default.</para></listitem>
- </varlistentry>
-
- <varlistentry id="tcache.create">
- <term>
- <mallctl>tcache.create</mallctl>
- (<type>unsigned</type>)
- <literal>r-</literal>
- </term>
- <listitem><para>Create an explicit thread-specific cache (tcache) and
- return an identifier that can be passed to the <link
- linkend="MALLOCX_TCACHE"><constant>MALLOCX_TCACHE(<parameter>tc</parameter>)</constant></link>
- macro to explicitly use the specified cache rather than the
- automatically managed one that is used by default. Each explicit cache
- can be used by only one thread at a time; the application must assure
- that this constraint holds.
- </para></listitem>
- </varlistentry>
-
- <varlistentry id="tcache.flush">
- <term>
- <mallctl>tcache.flush</mallctl>
- (<type>unsigned</type>)
- <literal>-w</literal>
- </term>
- <listitem><para>Flush the specified thread-specific cache (tcache). The
- same considerations apply to this interface as to <link
- linkend="thread.tcache.flush"><mallctl>thread.tcache.flush</mallctl></link>,
- except that the tcache will never be automatically discarded.
- </para></listitem>
- </varlistentry>
-
- <varlistentry id="tcache.destroy">
- <term>
- <mallctl>tcache.destroy</mallctl>
- (<type>unsigned</type>)
- <literal>-w</literal>
- </term>
- <listitem><para>Flush the specified thread-specific cache (tcache) and
- make the identifier available for use during a future tcache creation.
- </para></listitem>
- </varlistentry>
-
- <varlistentry id="arena.i.initialized">
- <term>
- <mallctl>arena.&lt;i&gt;.initialized</mallctl>
- (<type>bool</type>)
- <literal>r-</literal>
- </term>
- <listitem><para>Get whether the specified arena's statistics are
- initialized (i.e. the arena was initialized prior to the current epoch).
- This interface can also be nominally used to query whether the merged
- statistics corresponding to <constant>MALLCTL_ARENAS_ALL</constant> are
- initialized (always true).</para></listitem>
- </varlistentry>
-
- <varlistentry id="arena.i.decay">
- <term>
- <mallctl>arena.&lt;i&gt;.decay</mallctl>
- (<type>void</type>)
- <literal>--</literal>
- </term>
- <listitem><para>Trigger decay-based purging of unused dirty/muzzy pages
- for arena &lt;i&gt;, or for all arenas if &lt;i&gt; equals
- <constant>MALLCTL_ARENAS_ALL</constant>. The proportion of unused
- dirty/muzzy pages to be purged depends on the current time; see <link
- linkend="opt.dirty_decay_ms"><mallctl>opt.dirty_decay_ms</mallctl></link>
- and <link
- linkend="opt.muzzy_decay_ms"><mallctl>opt.muzy_decay_ms</mallctl></link>
- for details.</para></listitem>
- </varlistentry>
-
- <varlistentry id="arena.i.purge">
- <term>
- <mallctl>arena.&lt;i&gt;.purge</mallctl>
- (<type>void</type>)
- <literal>--</literal>
- </term>
- <listitem><para>Purge all unused dirty pages for arena &lt;i&gt;, or for
- all arenas if &lt;i&gt; equals <constant>MALLCTL_ARENAS_ALL</constant>.
- </para></listitem>
- </varlistentry>
-
- <varlistentry id="arena.i.reset">
- <term>
- <mallctl>arena.&lt;i&gt;.reset</mallctl>
- (<type>void</type>)
- <literal>--</literal>
- </term>
- <listitem><para>Discard all of the arena's extant allocations. This
- interface can only be used with arenas explicitly created via <link
- linkend="arenas.create"><mallctl>arenas.create</mallctl></link>. None
- of the arena's discarded/cached allocations may accessed afterward. As
- part of this requirement, all thread caches which were used to
- allocate/deallocate in conjunction with the arena must be flushed
- beforehand.</para></listitem>
- </varlistentry>
-
- <varlistentry id="arena.i.destroy">
- <term>
- <mallctl>arena.&lt;i&gt;.destroy</mallctl>
- (<type>void</type>)
- <literal>--</literal>
- </term>
- <listitem><para>Destroy the arena. Discard all of the arena's extant
- allocations using the same mechanism as for <link
- linkend="arena.i.reset"><mallctl>arena.&lt;i&gt;.reset</mallctl></link>
- (with all the same constraints and side effects), merge the arena stats
- into those accessible at arena index
- <constant>MALLCTL_ARENAS_DESTROYED</constant>, and then completely
- discard all metadata associated with the arena. Future calls to <link
- linkend="arenas.create"><mallctl>arenas.create</mallctl></link> may
- recycle the arena index. Destruction will fail if any threads are
- currently associated with the arena as a result of calls to <link
- linkend="thread.arena"><mallctl>thread.arena</mallctl></link>.</para></listitem>
- </varlistentry>
-
- <varlistentry id="arena.i.dss">
- <term>
- <mallctl>arena.&lt;i&gt;.dss</mallctl>
- (<type>const char *</type>)
- <literal>rw</literal>
- </term>
- <listitem><para>Set the precedence of dss allocation as related to mmap
- allocation for arena &lt;i&gt;, or for all arenas if &lt;i&gt; equals
- <constant>MALLCTL_ARENAS_ALL</constant>. See <link
- linkend="opt.dss"><mallctl>opt.dss</mallctl></link> for supported
- settings.</para></listitem>
- </varlistentry>
-
- <varlistentry id="arena.i.dirty_decay_ms">
- <term>
- <mallctl>arena.&lt;i&gt;.dirty_decay_ms</mallctl>
- (<type>ssize_t</type>)
- <literal>rw</literal>
- </term>
- <listitem><para>Current per-arena approximate time in milliseconds from
- the creation of a set of unused dirty pages until an equivalent set of
- unused dirty pages is purged and/or reused. Each time this interface is
- set, all currently unused dirty pages are considered to have fully
- decayed, which causes immediate purging of all unused dirty pages unless
- the decay time is set to -1 (i.e. purging disabled). See <link
- linkend="opt.dirty_decay_ms"><mallctl>opt.dirty_decay_ms</mallctl></link>
- for additional information.</para></listitem>
- </varlistentry>
-
- <varlistentry id="arena.i.muzzy_decay_ms">
- <term>
- <mallctl>arena.&lt;i&gt;.muzzy_decay_ms</mallctl>
- (<type>ssize_t</type>)
- <literal>rw</literal>
- </term>
- <listitem><para>Current per-arena approximate time in milliseconds from
- the creation of a set of unused muzzy pages until an equivalent set of
- unused muzzy pages is purged and/or reused. Each time this interface is
- set, all currently unused muzzy pages are considered to have fully
- decayed, which causes immediate purging of all unused muzzy pages unless
- the decay time is set to -1 (i.e. purging disabled). See <link
- linkend="opt.muzzy_decay_ms"><mallctl>opt.muzzy_decay_ms</mallctl></link>
- for additional information.</para></listitem>
- </varlistentry>
-
- <varlistentry id="arena.i.retain_grow_limit">
- <term>
- <mallctl>arena.&lt;i&gt;.retain_grow_limit</mallctl>
- (<type>size_t</type>)
- <literal>rw</literal>
- </term>
- <listitem><para>Maximum size to grow retained region (only relevant when
- <link linkend="opt.retain"><mallctl>opt.retain</mallctl></link> is
- enabled). This controls the maximum increment to expand virtual memory,
- or allocation through <link
- linkend="arena.i.extent_hooks"><mallctl>arena.&lt;i&gt;extent_hooks</mallctl></link>.
- In particular, if customized extent hooks reserve physical memory
- (e.g. 1G huge pages), this is useful to control the allocation hook's
- input size. The default is no limit.</para></listitem>
- </varlistentry>
-
- <varlistentry id="arena.i.extent_hooks">
- <term>
- <mallctl>arena.&lt;i&gt;.extent_hooks</mallctl>
- (<type>extent_hooks_t *</type>)
- <literal>rw</literal>
- </term>
- <listitem><para>Get or set the extent management hook functions for
- arena &lt;i&gt;. The functions must be capable of operating on all
- extant extents associated with arena &lt;i&gt;, usually by passing
- unknown extents to the replaced functions. In practice, it is feasible
- to control allocation for arenas explicitly created via <link
- linkend="arenas.create"><mallctl>arenas.create</mallctl></link> such
- that all extents originate from an application-supplied extent allocator
- (by specifying the custom extent hook functions during arena creation).
- However, the API guarantees for the automatically created arenas may be
- relaxed -- hooks set there may be called in a "best effort" fashion; in
- addition there may be extents created prior to the application having an
- opportunity to take over extent allocation.</para>
-
- <programlisting language="C"><![CDATA[
-typedef extent_hooks_s extent_hooks_t;
-struct extent_hooks_s {
- extent_alloc_t *alloc;
- extent_dalloc_t *dalloc;
- extent_destroy_t *destroy;
- extent_commit_t *commit;
- extent_decommit_t *decommit;
- extent_purge_t *purge_lazy;
- extent_purge_t *purge_forced;
- extent_split_t *split;
- extent_merge_t *merge;
-};]]></programlisting>
- <para>The <type>extent_hooks_t</type> structure comprises function
- pointers which are described individually below. jemalloc uses these
- functions to manage extent lifetime, which starts off with allocation of
- mapped committed memory, in the simplest case followed by deallocation.
- However, there are performance and platform reasons to retain extents
- for later reuse. Cleanup attempts cascade from deallocation to decommit
- to forced purging to lazy purging, which gives the extent management
- functions opportunities to reject the most permanent cleanup operations
- in favor of less permanent (and often less costly) operations. All
- operations except allocation can be universally opted out of by setting
- the hook pointers to <constant>NULL</constant>, or selectively opted out
- of by returning failure. Note that once the extent hook is set, the
- structure is accessed directly by the associated arenas, so it must
- remain valid for the entire lifetime of the arenas.</para>
-
- <funcsynopsis><funcprototype>
- <funcdef>typedef void *<function>(extent_alloc_t)</function></funcdef>
- <paramdef>extent_hooks_t *<parameter>extent_hooks</parameter></paramdef>
- <paramdef>void *<parameter>new_addr</parameter></paramdef>
- <paramdef>size_t <parameter>size</parameter></paramdef>
- <paramdef>size_t <parameter>alignment</parameter></paramdef>
- <paramdef>bool *<parameter>zero</parameter></paramdef>
- <paramdef>bool *<parameter>commit</parameter></paramdef>
- <paramdef>unsigned <parameter>arena_ind</parameter></paramdef>
- </funcprototype></funcsynopsis>
- <literallayout></literallayout>
- <para>An extent allocation function conforms to the
- <type>extent_alloc_t</type> type and upon success returns a pointer to
- <parameter>size</parameter> bytes of mapped memory on behalf of arena
- <parameter>arena_ind</parameter> such that the extent's base address is
- a multiple of <parameter>alignment</parameter>, as well as setting
- <parameter>*zero</parameter> to indicate whether the extent is zeroed
- and <parameter>*commit</parameter> to indicate whether the extent is
- committed. Upon error the function returns <constant>NULL</constant>
- and leaves <parameter>*zero</parameter> and
- <parameter>*commit</parameter> unmodified. The
- <parameter>size</parameter> parameter is always a multiple of the page
- size. The <parameter>alignment</parameter> parameter is always a power
- of two at least as large as the page size. Zeroing is mandatory if
- <parameter>*zero</parameter> is true upon function entry. Committing is
- mandatory if <parameter>*commit</parameter> is true upon function entry.
- If <parameter>new_addr</parameter> is not <constant>NULL</constant>, the
- returned pointer must be <parameter>new_addr</parameter> on success or
- <constant>NULL</constant> on error. Committed memory may be committed
- in absolute terms as on a system that does not overcommit, or in
- implicit terms as on a system that overcommits and satisfies physical
- memory needs on demand via soft page faults. Note that replacing the
- default extent allocation function makes the arena's <link
- linkend="arena.i.dss"><mallctl>arena.&lt;i&gt;.dss</mallctl></link>
- setting irrelevant.</para>
-
- <funcsynopsis><funcprototype>
- <funcdef>typedef bool <function>(extent_dalloc_t)</function></funcdef>
- <paramdef>extent_hooks_t *<parameter>extent_hooks</parameter></paramdef>
- <paramdef>void *<parameter>addr</parameter></paramdef>
- <paramdef>size_t <parameter>size</parameter></paramdef>
- <paramdef>bool <parameter>committed</parameter></paramdef>
- <paramdef>unsigned <parameter>arena_ind</parameter></paramdef>
- </funcprototype></funcsynopsis>
- <literallayout></literallayout>
- <para>
- An extent deallocation function conforms to the
- <type>extent_dalloc_t</type> type and deallocates an extent at given
- <parameter>addr</parameter> and <parameter>size</parameter> with
- <parameter>committed</parameter>/decommited memory as indicated, on
- behalf of arena <parameter>arena_ind</parameter>, returning false upon
- success. If the function returns true, this indicates opt-out from
- deallocation; the virtual memory mapping associated with the extent
- remains mapped, in the same commit state, and available for future use,
- in which case it will be automatically retained for later reuse.</para>
-
- <funcsynopsis><funcprototype>
- <funcdef>typedef void <function>(extent_destroy_t)</function></funcdef>
- <paramdef>extent_hooks_t *<parameter>extent_hooks</parameter></paramdef>
- <paramdef>void *<parameter>addr</parameter></paramdef>
- <paramdef>size_t <parameter>size</parameter></paramdef>
- <paramdef>bool <parameter>committed</parameter></paramdef>
- <paramdef>unsigned <parameter>arena_ind</parameter></paramdef>
- </funcprototype></funcsynopsis>
- <literallayout></literallayout>
- <para>
- An extent destruction function conforms to the
- <type>extent_destroy_t</type> type and unconditionally destroys an
- extent at given <parameter>addr</parameter> and
- <parameter>size</parameter> with
- <parameter>committed</parameter>/decommited memory as indicated, on
- behalf of arena <parameter>arena_ind</parameter>. This function may be
- called to destroy retained extents during arena destruction (see <link
- linkend="arena.i.destroy"><mallctl>arena.&lt;i&gt;.destroy</mallctl></link>).</para>
-
- <funcsynopsis><funcprototype>
- <funcdef>typedef bool <function>(extent_commit_t)</function></funcdef>
- <paramdef>extent_hooks_t *<parameter>extent_hooks</parameter></paramdef>
- <paramdef>void *<parameter>addr</parameter></paramdef>
- <paramdef>size_t <parameter>size</parameter></paramdef>
- <paramdef>size_t <parameter>offset</parameter></paramdef>
- <paramdef>size_t <parameter>length</parameter></paramdef>
- <paramdef>unsigned <parameter>arena_ind</parameter></paramdef>
- </funcprototype></funcsynopsis>
- <literallayout></literallayout>
- <para>An extent commit function conforms to the
- <type>extent_commit_t</type> type and commits zeroed physical memory to
- back pages within an extent at given <parameter>addr</parameter> and
- <parameter>size</parameter> at <parameter>offset</parameter> bytes,
- extending for <parameter>length</parameter> on behalf of arena
- <parameter>arena_ind</parameter>, returning false upon success.
- Committed memory may be committed in absolute terms as on a system that
- does not overcommit, or in implicit terms as on a system that
- overcommits and satisfies physical memory needs on demand via soft page
- faults. If the function returns true, this indicates insufficient
- physical memory to satisfy the request.</para>
-
- <funcsynopsis><funcprototype>
- <funcdef>typedef bool <function>(extent_decommit_t)</function></funcdef>
- <paramdef>extent_hooks_t *<parameter>extent_hooks</parameter></paramdef>
- <paramdef>void *<parameter>addr</parameter></paramdef>
- <paramdef>size_t <parameter>size</parameter></paramdef>
- <paramdef>size_t <parameter>offset</parameter></paramdef>
- <paramdef>size_t <parameter>length</parameter></paramdef>
- <paramdef>unsigned <parameter>arena_ind</parameter></paramdef>
- </funcprototype></funcsynopsis>
- <literallayout></literallayout>
- <para>An extent decommit function conforms to the
- <type>extent_decommit_t</type> type and decommits any physical memory
- that is backing pages within an extent at given
- <parameter>addr</parameter> and <parameter>size</parameter> at
- <parameter>offset</parameter> bytes, extending for
- <parameter>length</parameter> on behalf of arena
- <parameter>arena_ind</parameter>, returning false upon success, in which
- case the pages will be committed via the extent commit function before
- being reused. If the function returns true, this indicates opt-out from
- decommit; the memory remains committed and available for future use, in
- which case it will be automatically retained for later reuse.</para>
-
- <funcsynopsis><funcprototype>
- <funcdef>typedef bool <function>(extent_purge_t)</function></funcdef>
- <paramdef>extent_hooks_t *<parameter>extent_hooks</parameter></paramdef>
- <paramdef>void *<parameter>addr</parameter></paramdef>
- <paramdef>size_t <parameter>size</parameter></paramdef>
- <paramdef>size_t <parameter>offset</parameter></paramdef>
- <paramdef>size_t <parameter>length</parameter></paramdef>
- <paramdef>unsigned <parameter>arena_ind</parameter></paramdef>
- </funcprototype></funcsynopsis>
- <literallayout></literallayout>
- <para>An extent purge function conforms to the
- <type>extent_purge_t</type> type and discards physical pages
- within the virtual memory mapping associated with an extent at given
- <parameter>addr</parameter> and <parameter>size</parameter> at
- <parameter>offset</parameter> bytes, extending for
- <parameter>length</parameter> on behalf of arena
- <parameter>arena_ind</parameter>. A lazy extent purge function (e.g.
- implemented via
- <function>madvise(<parameter>...</parameter><parameter><constant>MADV_FREE</constant></parameter>)</function>)
- can delay purging indefinitely and leave the pages within the purged
- virtual memory range in an indeterminite state, whereas a forced extent
- purge function immediately purges, and the pages within the virtual
- memory range will be zero-filled the next time they are accessed. If
- the function returns true, this indicates failure to purge.</para>
-
- <funcsynopsis><funcprototype>
- <funcdef>typedef bool <function>(extent_split_t)</function></funcdef>
- <paramdef>extent_hooks_t *<parameter>extent_hooks</parameter></paramdef>
- <paramdef>void *<parameter>addr</parameter></paramdef>
- <paramdef>size_t <parameter>size</parameter></paramdef>
- <paramdef>size_t <parameter>size_a</parameter></paramdef>
- <paramdef>size_t <parameter>size_b</parameter></paramdef>
- <paramdef>bool <parameter>committed</parameter></paramdef>
- <paramdef>unsigned <parameter>arena_ind</parameter></paramdef>
- </funcprototype></funcsynopsis>
- <literallayout></literallayout>
- <para>An extent split function conforms to the
- <type>extent_split_t</type> type and optionally splits an extent at
- given <parameter>addr</parameter> and <parameter>size</parameter> into
- two adjacent extents, the first of <parameter>size_a</parameter> bytes,
- and the second of <parameter>size_b</parameter> bytes, operating on
- <parameter>committed</parameter>/decommitted memory as indicated, on
- behalf of arena <parameter>arena_ind</parameter>, returning false upon
- success. If the function returns true, this indicates that the extent
- remains unsplit and therefore should continue to be operated on as a
- whole.</para>
-
- <funcsynopsis><funcprototype>
- <funcdef>typedef bool <function>(extent_merge_t)</function></funcdef>
- <paramdef>extent_hooks_t *<parameter>extent_hooks</parameter></paramdef>
- <paramdef>void *<parameter>addr_a</parameter></paramdef>
- <paramdef>size_t <parameter>size_a</parameter></paramdef>
- <paramdef>void *<parameter>addr_b</parameter></paramdef>
- <paramdef>size_t <parameter>size_b</parameter></paramdef>
- <paramdef>bool <parameter>committed</parameter></paramdef>
- <paramdef>unsigned <parameter>arena_ind</parameter></paramdef>
- </funcprototype></funcsynopsis>
- <literallayout></literallayout>
- <para>An extent merge function conforms to the
- <type>extent_merge_t</type> type and optionally merges adjacent extents,
- at given <parameter>addr_a</parameter> and <parameter>size_a</parameter>
- with given <parameter>addr_b</parameter> and
- <parameter>size_b</parameter> into one contiguous extent, operating on
- <parameter>committed</parameter>/decommitted memory as indicated, on
- behalf of arena <parameter>arena_ind</parameter>, returning false upon
- success. If the function returns true, this indicates that the extents
- remain distinct mappings and therefore should continue to be operated on
- independently.</para>
- </listitem>
- </varlistentry>
-
- <varlistentry id="arenas.narenas">
- <term>
- <mallctl>arenas.narenas</mallctl>
- (<type>unsigned</type>)
- <literal>r-</literal>
- </term>
- <listitem><para>Current limit on number of arenas.</para></listitem>
- </varlistentry>
-
- <varlistentry id="arenas.dirty_decay_ms">
- <term>
- <mallctl>arenas.dirty_decay_ms</mallctl>
- (<type>ssize_t</type>)
- <literal>rw</literal>
- </term>
- <listitem><para>Current default per-arena approximate time in
- milliseconds from the creation of a set of unused dirty pages until an
- equivalent set of unused dirty pages is purged and/or reused, used to
- initialize <link
- linkend="arena.i.dirty_decay_ms"><mallctl>arena.&lt;i&gt;.dirty_decay_ms</mallctl></link>
- during arena creation. See <link
- linkend="opt.dirty_decay_ms"><mallctl>opt.dirty_decay_ms</mallctl></link>
- for additional information.</para></listitem>
- </varlistentry>
-
- <varlistentry id="arenas.muzzy_decay_ms">
- <term>
- <mallctl>arenas.muzzy_decay_ms</mallctl>
- (<type>ssize_t</type>)
- <literal>rw</literal>
- </term>
- <listitem><para>Current default per-arena approximate time in
- milliseconds from the creation of a set of unused muzzy pages until an
- equivalent set of unused muzzy pages is purged and/or reused, used to
- initialize <link
- linkend="arena.i.muzzy_decay_ms"><mallctl>arena.&lt;i&gt;.muzzy_decay_ms</mallctl></link>
- during arena creation. See <link
- linkend="opt.muzzy_decay_ms"><mallctl>opt.muzzy_decay_ms</mallctl></link>
- for additional information.</para></listitem>
- </varlistentry>
-
- <varlistentry id="arenas.quantum">
- <term>
- <mallctl>arenas.quantum</mallctl>
- (<type>size_t</type>)
- <literal>r-</literal>
- </term>
- <listitem><para>Quantum size.</para></listitem>
- </varlistentry>
-
- <varlistentry id="arenas.page">
- <term>
- <mallctl>arenas.page</mallctl>
- (<type>size_t</type>)
- <literal>r-</literal>
- </term>
- <listitem><para>Page size.</para></listitem>
- </varlistentry>
-
- <varlistentry id="arenas.tcache_max">
- <term>
- <mallctl>arenas.tcache_max</mallctl>
- (<type>size_t</type>)
- <literal>r-</literal>
- </term>
- <listitem><para>Maximum thread-cached size class.</para></listitem>
- </varlistentry>
-
- <varlistentry id="arenas.nbins">
- <term>
- <mallctl>arenas.nbins</mallctl>
- (<type>unsigned</type>)
- <literal>r-</literal>
- </term>
- <listitem><para>Number of bin size classes.</para></listitem>
- </varlistentry>
-
- <varlistentry id="arenas.nhbins">
- <term>
- <mallctl>arenas.nhbins</mallctl>
- (<type>unsigned</type>)
- <literal>r-</literal>
- </term>
- <listitem><para>Total number of thread cache bin size
- classes.</para></listitem>
- </varlistentry>
-
- <varlistentry id="arenas.bin.i.size">
- <term>
- <mallctl>arenas.bin.&lt;i&gt;.size</mallctl>
- (<type>size_t</type>)
- <literal>r-</literal>
- </term>
- <listitem><para>Maximum size supported by size class.</para></listitem>
- </varlistentry>
-
- <varlistentry id="arenas.bin.i.nregs">
- <term>
- <mallctl>arenas.bin.&lt;i&gt;.nregs</mallctl>
- (<type>uint32_t</type>)
- <literal>r-</literal>
- </term>
- <listitem><para>Number of regions per slab.</para></listitem>
- </varlistentry>
-
- <varlistentry id="arenas.bin.i.slab_size">
- <term>
- <mallctl>arenas.bin.&lt;i&gt;.slab_size</mallctl>
- (<type>size_t</type>)
- <literal>r-</literal>
- </term>
- <listitem><para>Number of bytes per slab.</para></listitem>
- </varlistentry>
-
- <varlistentry id="arenas.nlextents">
- <term>
- <mallctl>arenas.nlextents</mallctl>
- (<type>unsigned</type>)
- <literal>r-</literal>
- </term>
- <listitem><para>Total number of large size classes.</para></listitem>
- </varlistentry>
-
- <varlistentry id="arenas.lextent.i.size">
- <term>
- <mallctl>arenas.lextent.&lt;i&gt;.size</mallctl>
- (<type>size_t</type>)
- <literal>r-</literal>
- </term>
- <listitem><para>Maximum size supported by this large size
- class.</para></listitem>
- </varlistentry>
-
- <varlistentry id="arenas.create">
- <term>
- <mallctl>arenas.create</mallctl>
- (<type>unsigned</type>, <type>extent_hooks_t *</type>)
- <literal>rw</literal>
- </term>
- <listitem><para>Explicitly create a new arena outside the range of
- automatically managed arenas, with optionally specified extent hooks,
- and return the new arena index.</para></listitem>
- </varlistentry>
-
- <varlistentry id="arenas.lookup">
- <term>
- <mallctl>arenas.lookup</mallctl>
- (<type>unsigned</type>, <type>void*</type>)
- <literal>rw</literal>
- </term>
- <listitem><para>Index of the arena to which an allocation belongs to.</para></listitem>
- </varlistentry>
-
- <varlistentry id="prof.thread_active_init">
- <term>
- <mallctl>prof.thread_active_init</mallctl>
- (<type>bool</type>)
- <literal>rw</literal>
- [<option>--enable-prof</option>]
- </term>
- <listitem><para>Control the initial setting for <link
- linkend="thread.prof.active"><mallctl>thread.prof.active</mallctl></link>
- in newly created threads. See the <link
- linkend="opt.prof_thread_active_init"><mallctl>opt.prof_thread_active_init</mallctl></link>
- option for additional information.</para></listitem>
- </varlistentry>
-
- <varlistentry id="prof.active">
- <term>
- <mallctl>prof.active</mallctl>
- (<type>bool</type>)
- <literal>rw</literal>
- [<option>--enable-prof</option>]
- </term>
- <listitem><para>Control whether sampling is currently active. See the
- <link
- linkend="opt.prof_active"><mallctl>opt.prof_active</mallctl></link>
- option for additional information, as well as the interrelated <link
- linkend="thread.prof.active"><mallctl>thread.prof.active</mallctl></link>
- mallctl.</para></listitem>
- </varlistentry>
-
- <varlistentry id="prof.dump">
- <term>
- <mallctl>prof.dump</mallctl>
- (<type>const char *</type>)
- <literal>-w</literal>
- [<option>--enable-prof</option>]
- </term>
- <listitem><para>Dump a memory profile to the specified file, or if NULL
- is specified, to a file according to the pattern
- <filename>&lt;prefix&gt;.&lt;pid&gt;.&lt;seq&gt;.m&lt;mseq&gt;.heap</filename>,
- where <literal>&lt;prefix&gt;</literal> is controlled by the
- <link
- linkend="opt.prof_prefix"><mallctl>opt.prof_prefix</mallctl></link>
- option.</para></listitem>
- </varlistentry>
-
- <varlistentry id="prof.gdump">
- <term>
- <mallctl>prof.gdump</mallctl>
- (<type>bool</type>)
- <literal>rw</literal>
- [<option>--enable-prof</option>]
- </term>
- <listitem><para>When enabled, trigger a memory profile dump every time
- the total virtual memory exceeds the previous maximum. Profiles are
- dumped to files named according to the pattern
- <filename>&lt;prefix&gt;.&lt;pid&gt;.&lt;seq&gt;.u&lt;useq&gt;.heap</filename>,
- where <literal>&lt;prefix&gt;</literal> is controlled by the <link
- linkend="opt.prof_prefix"><mallctl>opt.prof_prefix</mallctl></link>
- option.</para></listitem>
- </varlistentry>
-
- <varlistentry id="prof.reset">
- <term>
- <mallctl>prof.reset</mallctl>
- (<type>size_t</type>)
- <literal>-w</literal>
- [<option>--enable-prof</option>]
- </term>
- <listitem><para>Reset all memory profile statistics, and optionally
- update the sample rate (see <link
- linkend="opt.lg_prof_sample"><mallctl>opt.lg_prof_sample</mallctl></link>
- and <link
- linkend="prof.lg_sample"><mallctl>prof.lg_sample</mallctl></link>).
- </para></listitem>
- </varlistentry>
-
- <varlistentry id="prof.lg_sample">
- <term>
- <mallctl>prof.lg_sample</mallctl>
- (<type>size_t</type>)
- <literal>r-</literal>
- [<option>--enable-prof</option>]
- </term>
- <listitem><para>Get the current sample rate (see <link
- linkend="opt.lg_prof_sample"><mallctl>opt.lg_prof_sample</mallctl></link>).
- </para></listitem>
- </varlistentry>
-
- <varlistentry id="prof.interval">
- <term>
- <mallctl>prof.interval</mallctl>
- (<type>uint64_t</type>)
- <literal>r-</literal>
- [<option>--enable-prof</option>]
- </term>
- <listitem><para>Average number of bytes allocated between
- interval-based profile dumps. See the
- <link
- linkend="opt.lg_prof_interval"><mallctl>opt.lg_prof_interval</mallctl></link>
- option for additional information.</para></listitem>
- </varlistentry>
-
- <varlistentry id="stats.allocated">
- <term>
- <mallctl>stats.allocated</mallctl>
- (<type>size_t</type>)
- <literal>r-</literal>
- [<option>--enable-stats</option>]
- </term>
- <listitem><para>Total number of bytes allocated by the
- application.</para></listitem>
- </varlistentry>
-
- <varlistentry id="stats.active">
- <term>
- <mallctl>stats.active</mallctl>
- (<type>size_t</type>)
- <literal>r-</literal>
- [<option>--enable-stats</option>]
- </term>
- <listitem><para>Total number of bytes in active pages allocated by the
- application. This is a multiple of the page size, and greater than or
- equal to <link
- linkend="stats.allocated"><mallctl>stats.allocated</mallctl></link>.
- This does not include <link linkend="stats.arenas.i.pdirty">
- <mallctl>stats.arenas.&lt;i&gt;.pdirty</mallctl></link>,
- <link linkend="stats.arenas.i.pmuzzy">
- <mallctl>stats.arenas.&lt;i&gt;.pmuzzy</mallctl></link>, nor pages
- entirely devoted to allocator metadata.</para></listitem>
- </varlistentry>
-
- <varlistentry id="stats.metadata">
- <term>
- <mallctl>stats.metadata</mallctl>
- (<type>size_t</type>)
- <literal>r-</literal>
- [<option>--enable-stats</option>]
- </term>
- <listitem><para>Total number of bytes dedicated to metadata, which
- comprise base allocations used for bootstrap-sensitive allocator
- metadata structures (see <link
- linkend="stats.arenas.i.base"><mallctl>stats.arenas.&lt;i&gt;.base</mallctl></link>)
- and internal allocations (see <link
- linkend="stats.arenas.i.internal"><mallctl>stats.arenas.&lt;i&gt;.internal</mallctl></link>).
- Transparent huge page (enabled with <link
- linkend="opt.metadata_thp">opt.metadata_thp</link>) usage is not
- considered.</para></listitem>
- </varlistentry>
-
- <varlistentry id="stats.metadata_thp">
- <term>
- <mallctl>stats.metadata_thp</mallctl>
- (<type>size_t</type>)
- <literal>r-</literal>
- [<option>--enable-stats</option>]
- </term>
- <listitem><para>Number of transparent huge pages (THP) used for
- metadata. See <link
- linkend="stats.metadata"><mallctl>stats.metadata</mallctl></link> and
- <link linkend="opt.metadata_thp">opt.metadata_thp</link>) for
- details.</para></listitem>
- </varlistentry>
-
- <varlistentry id="stats.resident">
- <term>
- <mallctl>stats.resident</mallctl>
- (<type>size_t</type>)
- <literal>r-</literal>
- [<option>--enable-stats</option>]
- </term>
- <listitem><para>Maximum number of bytes in physically resident data
- pages mapped by the allocator, comprising all pages dedicated to
- allocator metadata, pages backing active allocations, and unused dirty
- pages. This is a maximum rather than precise because pages may not
- actually be physically resident if they correspond to demand-zeroed
- virtual memory that has not yet been touched. This is a multiple of the
- page size, and is larger than <link
- linkend="stats.active"><mallctl>stats.active</mallctl></link>.</para></listitem>
- </varlistentry>
-
- <varlistentry id="stats.mapped">
- <term>
- <mallctl>stats.mapped</mallctl>
- (<type>size_t</type>)
- <literal>r-</literal>
- [<option>--enable-stats</option>]
- </term>
- <listitem><para>Total number of bytes in active extents mapped by the
- allocator. This is larger than <link
- linkend="stats.active"><mallctl>stats.active</mallctl></link>. This
- does not include inactive extents, even those that contain unused dirty
- pages, which means that there is no strict ordering between this and
- <link
- linkend="stats.resident"><mallctl>stats.resident</mallctl></link>.</para></listitem>
- </varlistentry>
-
- <varlistentry id="stats.retained">
- <term>
- <mallctl>stats.retained</mallctl>
- (<type>size_t</type>)
- <literal>r-</literal>
- [<option>--enable-stats</option>]
- </term>
- <listitem><para>Total number of bytes in virtual memory mappings that
- were retained rather than being returned to the operating system via
- e.g. <citerefentry><refentrytitle>munmap</refentrytitle>
- <manvolnum>2</manvolnum></citerefentry> or similar. Retained virtual
- memory is typically untouched, decommitted, or purged, so it has no
- strongly associated physical memory (see <link
- linkend="arena.i.extent_hooks">extent hooks</link> for details).
- Retained memory is excluded from mapped memory statistics, e.g. <link
- linkend="stats.mapped"><mallctl>stats.mapped</mallctl></link>.
- </para></listitem>
- </varlistentry>
-
- <varlistentry id="stats.background_thread.num_threads">
- <term>
- <mallctl>stats.background_thread.num_threads</mallctl>
- (<type>size_t</type>)
- <literal>r-</literal>
- [<option>--enable-stats</option>]
- </term>
- <listitem><para> Number of <link linkend="background_thread">background
- threads</link> running currently.</para></listitem>
- </varlistentry>
-
- <varlistentry id="stats.background_thread.num_runs">
- <term>
- <mallctl>stats.background_thread.num_runs</mallctl>
- (<type>uint64_t</type>)
- <literal>r-</literal>
- [<option>--enable-stats</option>]
- </term>
- <listitem><para> Total number of runs from all <link
- linkend="background_thread">background threads</link>.</para></listitem>
- </varlistentry>
-
- <varlistentry id="stats.background_thread.run_interval">
- <term>
- <mallctl>stats.background_thread.run_interval</mallctl>
- (<type>uint64_t</type>)
- <literal>r-</literal>
- [<option>--enable-stats</option>]
- </term>
- <listitem><para> Average run interval in nanoseconds of <link
- linkend="background_thread">background threads</link>.</para></listitem>
- </varlistentry>
-
- <varlistentry id="stats.mutexes.ctl">
- <term>
- <mallctl>stats.mutexes.ctl.{counter};</mallctl>
- (<type>counter specific type</type>)
- <literal>r-</literal>
- [<option>--enable-stats</option>]
- </term>
- <listitem><para>Statistics on <varname>ctl</varname> mutex (global
- scope; mallctl related). <mallctl>{counter}</mallctl> is one of the
- counters below:</para>
- <varlistentry id="mutex_counters">
- <listitem><para><varname>num_ops</varname> (<type>uint64_t</type>):
- Total number of lock acquisition operations on this mutex.</para>
-
- <para><varname>num_spin_acq</varname> (<type>uint64_t</type>): Number
- of times the mutex was spin-acquired. When the mutex is currently
- locked and cannot be acquired immediately, a short period of
- spin-retry within jemalloc will be performed. Acquired through spin
- generally means the contention was lightweight and not causing context
- switches.</para>
-
- <para><varname>num_wait</varname> (<type>uint64_t</type>): Number of
- times the mutex was wait-acquired, which means the mutex contention
- was not solved by spin-retry, and blocking operation was likely
- involved in order to acquire the mutex. This event generally implies
- higher cost / longer delay, and should be investigated if it happens
- often.</para>
-
- <para><varname>max_wait_time</varname> (<type>uint64_t</type>):
- Maximum length of time in nanoseconds spent on a single wait-acquired
- lock operation. Note that to avoid profiling overhead on the common
- path, this does not consider spin-acquired cases.</para>
-
- <para><varname>total_wait_time</varname> (<type>uint64_t</type>):
- Cumulative time in nanoseconds spent on wait-acquired lock operations.
- Similarly, spin-acquired cases are not considered.</para>
-
- <para><varname>max_num_thds</varname> (<type>uint32_t</type>): Maximum
- number of threads waiting on this mutex simultaneously. Similarly,
- spin-acquired cases are not considered.</para>
-
- <para><varname>num_owner_switch</varname> (<type>uint64_t</type>):
- Number of times the current mutex owner is different from the previous
- one. This event does not generally imply an issue; rather it is an
- indicator of how often the protected data are accessed by different
- threads.
- </para>
- </listitem>
- </varlistentry>
- </listitem>
- </varlistentry>
-
- <varlistentry id="stats.mutexes.background_thread">
- <term>
- <mallctl>stats.mutexes.background_thread.{counter}</mallctl>
- (<type>counter specific type</type>) <literal>r-</literal>
- [<option>--enable-stats</option>]
- </term>
- <listitem><para>Statistics on <varname>background_thread</varname> mutex
- (global scope; <link
- linkend="background_thread"><mallctl>background_thread</mallctl></link>
- related). <mallctl>{counter}</mallctl> is one of the counters in <link
- linkend="mutex_counters">mutex profiling
- counters</link>.</para></listitem>
- </varlistentry>
-
- <varlistentry id="stats.mutexes.prof">
- <term>
- <mallctl>stats.mutexes.prof.{counter}</mallctl>
- (<type>counter specific type</type>) <literal>r-</literal>
- [<option>--enable-stats</option>]
- </term>
- <listitem><para>Statistics on <varname>prof</varname> mutex (global
- scope; profiling related). <mallctl>{counter}</mallctl> is one of the
- counters in <link linkend="mutex_counters">mutex profiling
- counters</link>.</para></listitem>
- </varlistentry>
-
- <varlistentry id="stats.mutexes.reset">
- <term>
- <mallctl>stats.mutexes.reset</mallctl>
- (<type>void</type>) <literal>--</literal>
- [<option>--enable-stats</option>]
- </term>
- <listitem><para>Reset all mutex profile statistics, including global
- mutexes, arena mutexes and bin mutexes.</para></listitem>
- </varlistentry>
-
- <varlistentry id="stats.arenas.i.dss">
- <term>
- <mallctl>stats.arenas.&lt;i&gt;.dss</mallctl>
- (<type>const char *</type>)
- <literal>r-</literal>
- </term>
- <listitem><para>dss (<citerefentry><refentrytitle>sbrk</refentrytitle>
- <manvolnum>2</manvolnum></citerefentry>) allocation precedence as
- related to <citerefentry><refentrytitle>mmap</refentrytitle>
- <manvolnum>2</manvolnum></citerefentry> allocation. See <link
- linkend="opt.dss"><mallctl>opt.dss</mallctl></link> for details.
- </para></listitem>
- </varlistentry>
-
- <varlistentry id="stats.arenas.i.dirty_decay_ms">
- <term>
- <mallctl>stats.arenas.&lt;i&gt;.dirty_decay_ms</mallctl>
- (<type>ssize_t</type>)
- <literal>r-</literal>
- </term>
- <listitem><para>Approximate time in milliseconds from the creation of a
- set of unused dirty pages until an equivalent set of unused dirty pages
- is purged and/or reused. See <link
- linkend="opt.dirty_decay_ms"><mallctl>opt.dirty_decay_ms</mallctl></link>
- for details.</para></listitem>
- </varlistentry>
-
- <varlistentry id="stats.arenas.i.muzzy_decay_ms">
- <term>
- <mallctl>stats.arenas.&lt;i&gt;.muzzy_decay_ms</mallctl>
- (<type>ssize_t</type>)
- <literal>r-</literal>
- </term>
- <listitem><para>Approximate time in milliseconds from the creation of a
- set of unused muzzy pages until an equivalent set of unused muzzy pages
- is purged and/or reused. See <link
- linkend="opt.muzzy_decay_ms"><mallctl>opt.muzzy_decay_ms</mallctl></link>
- for details.</para></listitem>
- </varlistentry>
-
- <varlistentry id="stats.arenas.i.nthreads">
- <term>
- <mallctl>stats.arenas.&lt;i&gt;.nthreads</mallctl>
- (<type>unsigned</type>)
- <literal>r-</literal>
- </term>
- <listitem><para>Number of threads currently assigned to
- arena.</para></listitem>
- </varlistentry>
-
- <varlistentry id="stats.arenas.i.uptime">
- <term>
- <mallctl>stats.arenas.&lt;i&gt;.uptime</mallctl>
- (<type>uint64_t</type>)
- <literal>r-</literal>
- </term>
- <listitem><para>Time elapsed (in nanoseconds) since the arena was
- created. If &lt;i&gt; equals <constant>0</constant> or
- <constant>MALLCTL_ARENAS_ALL</constant>, this is the uptime since malloc
- initialization.</para></listitem>
- </varlistentry>
-
- <varlistentry id="stats.arenas.i.pactive">
- <term>
- <mallctl>stats.arenas.&lt;i&gt;.pactive</mallctl>
- (<type>size_t</type>)
- <literal>r-</literal>
- </term>
- <listitem><para>Number of pages in active extents.</para></listitem>
- </varlistentry>
-
- <varlistentry id="stats.arenas.i.pdirty">
- <term>
- <mallctl>stats.arenas.&lt;i&gt;.pdirty</mallctl>
- (<type>size_t</type>)
- <literal>r-</literal>
- </term>
- <listitem><para>Number of pages within unused extents that are
- potentially dirty, and for which <function>madvise()</function> or
- similar has not been called. See <link
- linkend="opt.dirty_decay_ms"><mallctl>opt.dirty_decay_ms</mallctl></link>
- for a description of dirty pages.</para></listitem>
- </varlistentry>
-
- <varlistentry id="stats.arenas.i.pmuzzy">
- <term>
- <mallctl>stats.arenas.&lt;i&gt;.pmuzzy</mallctl>
- (<type>size_t</type>)
- <literal>r-</literal>
- </term>
- <listitem><para>Number of pages within unused extents that are muzzy.
- See <link
- linkend="opt.muzzy_decay_ms"><mallctl>opt.muzzy_decay_ms</mallctl></link>
- for a description of muzzy pages.</para></listitem>
- </varlistentry>
-
- <varlistentry id="stats.arenas.i.mapped">
- <term>
- <mallctl>stats.arenas.&lt;i&gt;.mapped</mallctl>
- (<type>size_t</type>)
- <literal>r-</literal>
- [<option>--enable-stats</option>]
- </term>
- <listitem><para>Number of mapped bytes.</para></listitem>
- </varlistentry>
-
- <varlistentry id="stats.arenas.i.retained">
- <term>
- <mallctl>stats.arenas.&lt;i&gt;.retained</mallctl>
- (<type>size_t</type>)
- <literal>r-</literal>
- [<option>--enable-stats</option>]
- </term>
- <listitem><para>Number of retained bytes. See <link
- linkend="stats.retained"><mallctl>stats.retained</mallctl></link> for
- details.</para></listitem>
- </varlistentry>
-
- <varlistentry id="stats.arenas.i.extent_avail">
- <term>
- <mallctl>stats.arenas.&lt;i&gt;.extent_avail</mallctl>
- (<type>size_t</type>)
- <literal>r-</literal>
- [<option>--enable-stats</option>]
- </term>
- <listitem><para>Number of allocated (but unused) extent structs in this
- arena.</para></listitem>
- </varlistentry>
-
- <varlistentry id="stats.arenas.i.base">
- <term>
- <mallctl>stats.arenas.&lt;i&gt;.base</mallctl>
- (<type>size_t</type>)
- <literal>r-</literal>
- [<option>--enable-stats</option>]
- </term>
- <listitem><para>
- Number of bytes dedicated to bootstrap-sensitive allocator metadata
- structures.</para></listitem>
- </varlistentry>
-
- <varlistentry id="stats.arenas.i.internal">
- <term>
- <mallctl>stats.arenas.&lt;i&gt;.internal</mallctl>
- (<type>size_t</type>)
- <literal>r-</literal>
- [<option>--enable-stats</option>]
- </term>
- <listitem><para>Number of bytes dedicated to internal allocations.
- Internal allocations differ from application-originated allocations in
- that they are for internal use, and that they are omitted from heap
- profiles.</para></listitem>
- </varlistentry>
-
- <varlistentry id="stats.arenas.i.metadata_thp">
- <term>
- <mallctl>stats.arenas.&lt;i&gt;.metadata_thp</mallctl>
- (<type>size_t</type>)
- <literal>r-</literal>
- [<option>--enable-stats</option>]
- </term>
- <listitem><para>Number of transparent huge pages (THP) used for
- metadata. See <link linkend="opt.metadata_thp">opt.metadata_thp</link>
- for details.</para></listitem>
- </varlistentry>
-
- <varlistentry id="stats.arenas.i.resident">
- <term>
- <mallctl>stats.arenas.&lt;i&gt;.resident</mallctl>
- (<type>size_t</type>)
- <literal>r-</literal>
- [<option>--enable-stats</option>]
- </term>
- <listitem><para>Maximum number of bytes in physically resident data
- pages mapped by the arena, comprising all pages dedicated to allocator
- metadata, pages backing active allocations, and unused dirty pages.
- This is a maximum rather than precise because pages may not actually be
- physically resident if they correspond to demand-zeroed virtual memory
- that has not yet been touched. This is a multiple of the page
- size.</para></listitem>
- </varlistentry>
-
- <varlistentry id="stats.arenas.i.dirty_npurge">
- <term>
- <mallctl>stats.arenas.&lt;i&gt;.dirty_npurge</mallctl>
- (<type>uint64_t</type>)
- <literal>r-</literal>
- [<option>--enable-stats</option>]
- </term>
- <listitem><para>Number of dirty page purge sweeps performed.
- </para></listitem>
- </varlistentry>
-
- <varlistentry id="stats.arenas.i.dirty_nmadvise">
- <term>
- <mallctl>stats.arenas.&lt;i&gt;.dirty_nmadvise</mallctl>
- (<type>uint64_t</type>)
- <literal>r-</literal>
- [<option>--enable-stats</option>]
- </term>
- <listitem><para>Number of <function>madvise()</function> or similar
- calls made to purge dirty pages.</para></listitem>
- </varlistentry>
-
- <varlistentry id="stats.arenas.i.dirty_purged">
- <term>
- <mallctl>stats.arenas.&lt;i&gt;.dirty_purged</mallctl>
- (<type>uint64_t</type>)
- <literal>r-</literal>
- [<option>--enable-stats</option>]
- </term>
- <listitem><para>Number of dirty pages purged.</para></listitem>
- </varlistentry>
-
- <varlistentry id="stats.arenas.i.muzzy_npurge">
- <term>
- <mallctl>stats.arenas.&lt;i&gt;.muzzy_npurge</mallctl>
- (<type>uint64_t</type>)
- <literal>r-</literal>
- [<option>--enable-stats</option>]
- </term>
- <listitem><para>Number of muzzy page purge sweeps performed.
- </para></listitem>
- </varlistentry>
-
- <varlistentry id="stats.arenas.i.muzzy_nmadvise">
- <term>
- <mallctl>stats.arenas.&lt;i&gt;.muzzy_nmadvise</mallctl>
- (<type>uint64_t</type>)
- <literal>r-</literal>
- [<option>--enable-stats</option>]
- </term>
- <listitem><para>Number of <function>madvise()</function> or similar
- calls made to purge muzzy pages.</para></listitem>
- </varlistentry>
-
- <varlistentry id="stats.arenas.i.muzzy_purged">
- <term>
- <mallctl>stats.arenas.&lt;i&gt;.muzzy_purged</mallctl>
- (<type>uint64_t</type>)
- <literal>r-</literal>
- [<option>--enable-stats</option>]
- </term>
- <listitem><para>Number of muzzy pages purged.</para></listitem>
- </varlistentry>
-
- <varlistentry id="stats.arenas.i.small.allocated">
- <term>
- <mallctl>stats.arenas.&lt;i&gt;.small.allocated</mallctl>
- (<type>size_t</type>)
- <literal>r-</literal>
- [<option>--enable-stats</option>]
- </term>
- <listitem><para>Number of bytes currently allocated by small objects.
- </para></listitem>
- </varlistentry>
-
- <varlistentry id="stats.arenas.i.small.nmalloc">
- <term>
- <mallctl>stats.arenas.&lt;i&gt;.small.nmalloc</mallctl>
- (<type>uint64_t</type>)
- <literal>r-</literal>
- [<option>--enable-stats</option>]
- </term>
- <listitem><para>Cumulative number of times a small allocation was
- requested from the arena's bins, whether to fill the relevant tcache if
- <link linkend="opt.tcache"><mallctl>opt.tcache</mallctl></link> is
- enabled, or to directly satisfy an allocation request
- otherwise.</para></listitem>
- </varlistentry>
-
- <varlistentry id="stats.arenas.i.small.ndalloc">
- <term>
- <mallctl>stats.arenas.&lt;i&gt;.small.ndalloc</mallctl>
- (<type>uint64_t</type>)
- <literal>r-</literal>
- [<option>--enable-stats</option>]
- </term>
- <listitem><para>Cumulative number of times a small allocation was
- returned to the arena's bins, whether to flush the relevant tcache if
- <link linkend="opt.tcache"><mallctl>opt.tcache</mallctl></link> is
- enabled, or to directly deallocate an allocation
- otherwise.</para></listitem>
- </varlistentry>
-
- <varlistentry id="stats.arenas.i.small.nrequests">
- <term>
- <mallctl>stats.arenas.&lt;i&gt;.small.nrequests</mallctl>
- (<type>uint64_t</type>)
- <literal>r-</literal>
- [<option>--enable-stats</option>]
- </term>
- <listitem><para>Cumulative number of allocation requests satisfied by
- all bin size classes.</para></listitem>
- </varlistentry>
-
- <varlistentry id="stats.arenas.i.small.nfills">
- <term>
- <mallctl>stats.arenas.&lt;i&gt;.small.nfills</mallctl>
- (<type>uint64_t</type>)
- <literal>r-</literal>
- [<option>--enable-stats</option>]
- </term>
- <listitem><para>Cumulative number of tcache fills by all small size
- classes.</para></listitem>
- </varlistentry>
-
- <varlistentry id="stats.arenas.i.small.nflushes">
- <term>
- <mallctl>stats.arenas.&lt;i&gt;.small.nflushes</mallctl>
- (<type>uint64_t</type>)
- <literal>r-</literal>
- [<option>--enable-stats</option>]
- </term>
- <listitem><para>Cumulative number of tcache flushes by all small size
- classes.</para></listitem>
- </varlistentry>
-
- <varlistentry id="stats.arenas.i.large.allocated">
- <term>
- <mallctl>stats.arenas.&lt;i&gt;.large.allocated</mallctl>
- (<type>size_t</type>)
- <literal>r-</literal>
- [<option>--enable-stats</option>]
- </term>
- <listitem><para>Number of bytes currently allocated by large objects.
- </para></listitem>
- </varlistentry>
-
- <varlistentry id="stats.arenas.i.large.nmalloc">
- <term>
- <mallctl>stats.arenas.&lt;i&gt;.large.nmalloc</mallctl>
- (<type>uint64_t</type>)
- <literal>r-</literal>
- [<option>--enable-stats</option>]
- </term>
- <listitem><para>Cumulative number of times a large extent was allocated
- from the arena, whether to fill the relevant tcache if <link
- linkend="opt.tcache"><mallctl>opt.tcache</mallctl></link> is enabled and
- the size class is within the range being cached, or to directly satisfy
- an allocation request otherwise.</para></listitem>
- </varlistentry>
-
- <varlistentry id="stats.arenas.i.large.ndalloc">
- <term>
- <mallctl>stats.arenas.&lt;i&gt;.large.ndalloc</mallctl>
- (<type>uint64_t</type>)
- <literal>r-</literal>
- [<option>--enable-stats</option>]
- </term>
- <listitem><para>Cumulative number of times a large extent was returned
- to the arena, whether to flush the relevant tcache if <link
- linkend="opt.tcache"><mallctl>opt.tcache</mallctl></link> is enabled and
- the size class is within the range being cached, or to directly
- deallocate an allocation otherwise.</para></listitem>
- </varlistentry>
-
- <varlistentry id="stats.arenas.i.large.nrequests">
- <term>
- <mallctl>stats.arenas.&lt;i&gt;.large.nrequests</mallctl>
- (<type>uint64_t</type>)
- <literal>r-</literal>
- [<option>--enable-stats</option>]
- </term>
- <listitem><para>Cumulative number of allocation requests satisfied by
- all large size classes.</para></listitem>
- </varlistentry>
-
- <varlistentry id="stats.arenas.i.large.nfills">
- <term>
- <mallctl>stats.arenas.&lt;i&gt;.large.nfills</mallctl>
- (<type>uint64_t</type>)
- <literal>r-</literal>
- [<option>--enable-stats</option>]
- </term>
- <listitem><para>Cumulative number of tcache fills by all large size
- classes.</para></listitem>
- </varlistentry>
-
- <varlistentry id="stats.arenas.i.large.nflushes">
- <term>
- <mallctl>stats.arenas.&lt;i&gt;.large.nflushes</mallctl>
- (<type>uint64_t</type>)
- <literal>r-</literal>
- [<option>--enable-stats</option>]
- </term>
- <listitem><para>Cumulative number of tcache flushes by all large size
- classes.</para></listitem>
- </varlistentry>
-
- <varlistentry id="stats.arenas.i.bins.j.nmalloc">
- <term>
- <mallctl>stats.arenas.&lt;i&gt;.bins.&lt;j&gt;.nmalloc</mallctl>
- (<type>uint64_t</type>)
- <literal>r-</literal>
- [<option>--enable-stats</option>]
- </term>
- <listitem><para>Cumulative number of times a bin region of the
- corresponding size class was allocated from the arena, whether to fill
- the relevant tcache if <link
- linkend="opt.tcache"><mallctl>opt.tcache</mallctl></link> is enabled, or
- to directly satisfy an allocation request otherwise.</para></listitem>
- </varlistentry>
-
- <varlistentry id="stats.arenas.i.bins.j.ndalloc">
- <term>
- <mallctl>stats.arenas.&lt;i&gt;.bins.&lt;j&gt;.ndalloc</mallctl>
- (<type>uint64_t</type>)
- <literal>r-</literal>
- [<option>--enable-stats</option>]
- </term>
- <listitem><para>Cumulative number of times a bin region of the
- corresponding size class was returned to the arena, whether to flush the
- relevant tcache if <link
- linkend="opt.tcache"><mallctl>opt.tcache</mallctl></link> is enabled, or
- to directly deallocate an allocation otherwise.</para></listitem>
- </varlistentry>
-
- <varlistentry id="stats.arenas.i.bins.j.nrequests">
- <term>
- <mallctl>stats.arenas.&lt;i&gt;.bins.&lt;j&gt;.nrequests</mallctl>
- (<type>uint64_t</type>)
- <literal>r-</literal>
- [<option>--enable-stats</option>]
- </term>
- <listitem><para>Cumulative number of allocation requests satisfied by
- bin regions of the corresponding size class.</para></listitem>
- </varlistentry>
-
- <varlistentry id="stats.arenas.i.bins.j.curregs">
- <term>
- <mallctl>stats.arenas.&lt;i&gt;.bins.&lt;j&gt;.curregs</mallctl>
- (<type>size_t</type>)
- <literal>r-</literal>
- [<option>--enable-stats</option>]
- </term>
- <listitem><para>Current number of regions for this size
- class.</para></listitem>
- </varlistentry>
-
- <varlistentry id="stats.arenas.i.bins.j.nfills">
- <term>
- <mallctl>stats.arenas.&lt;i&gt;.bins.&lt;j&gt;.nfills</mallctl>
- (<type>uint64_t</type>)
- <literal>r-</literal>
- </term>
- <listitem><para>Cumulative number of tcache fills.</para></listitem>
- </varlistentry>
-
- <varlistentry id="stats.arenas.i.bins.j.nflushes">
- <term>
- <mallctl>stats.arenas.&lt;i&gt;.bins.&lt;j&gt;.nflushes</mallctl>
- (<type>uint64_t</type>)
- <literal>r-</literal>
- </term>
- <listitem><para>Cumulative number of tcache flushes.</para></listitem>
- </varlistentry>
-
- <varlistentry id="stats.arenas.i.bins.j.nslabs">
- <term>
- <mallctl>stats.arenas.&lt;i&gt;.bins.&lt;j&gt;.nslabs</mallctl>
- (<type>uint64_t</type>)
- <literal>r-</literal>
- [<option>--enable-stats</option>]
- </term>
- <listitem><para>Cumulative number of slabs created.</para></listitem>
- </varlistentry>
-
- <varlistentry id="stats.arenas.i.bins.j.nreslabs">
- <term>
- <mallctl>stats.arenas.&lt;i&gt;.bins.&lt;j&gt;.nreslabs</mallctl>
- (<type>uint64_t</type>)
- <literal>r-</literal>
- [<option>--enable-stats</option>]
- </term>
- <listitem><para>Cumulative number of times the current slab from which
- to allocate changed.</para></listitem>
- </varlistentry>
-
- <varlistentry id="stats.arenas.i.bins.j.curslabs">
- <term>
- <mallctl>stats.arenas.&lt;i&gt;.bins.&lt;j&gt;.curslabs</mallctl>
- (<type>size_t</type>)
- <literal>r-</literal>
- [<option>--enable-stats</option>]
- </term>
- <listitem><para>Current number of slabs.</para></listitem>
- </varlistentry>
-
-
- <varlistentry id="stats.arenas.i.bins.j.nonfull_slabs">
- <term>
- <mallctl>stats.arenas.&lt;i&gt;.bins.&lt;j&gt;.nonfull_slabs</mallctl>
- (<type>size_t</type>)
- <literal>r-</literal>
- [<option>--enable-stats</option>]
- </term>
- <listitem><para>Current number of nonfull slabs.</para></listitem>
- </varlistentry>
-
- <varlistentry id="stats.arenas.i.bins.mutex">
- <term>
- <mallctl>stats.arenas.&lt;i&gt;.bins.&lt;j&gt;.mutex.{counter}</mallctl>
- (<type>counter specific type</type>) <literal>r-</literal>
- [<option>--enable-stats</option>]
- </term>
- <listitem><para>Statistics on
- <varname>arena.&lt;i&gt;.bins.&lt;j&gt;</varname> mutex (arena bin
- scope; bin operation related). <mallctl>{counter}</mallctl> is one of
- the counters in <link linkend="mutex_counters">mutex profiling
- counters</link>.</para></listitem>
- </varlistentry>
-
- <varlistentry id="stats.arenas.i.extents.n">
- <term>
- <mallctl>stats.arenas.&lt;i&gt;.extents.&lt;j&gt;.n{extent_type}</mallctl>
- (<type>size_t</type>)
- <literal>r-</literal>
- [<option>--enable-stats</option>]
- </term>
- <listitem><para> Number of extents of the given type in this arena in
- the bucket corresponding to page size index &lt;j&gt;. The extent type
- is one of dirty, muzzy, or retained.</para></listitem>
- </varlistentry>
-
- <varlistentry id="stats.arenas.i.extents.bytes">
- <term>
- <mallctl>stats.arenas.&lt;i&gt;.extents.&lt;j&gt;.{extent_type}_bytes</mallctl>
- (<type>size_t</type>)
- <literal>r-</literal>
- [<option>--enable-stats</option>]
- </term>
- <listitem><para> Sum of the bytes managed by extents of the given type
- in this arena in the bucket corresponding to page size index &lt;j&gt;.
- The extent type is one of dirty, muzzy, or retained.</para></listitem>
- </varlistentry>
-
- <varlistentry id="stats.arenas.i.lextents.j.nmalloc">
- <term>
- <mallctl>stats.arenas.&lt;i&gt;.lextents.&lt;j&gt;.nmalloc</mallctl>
- (<type>uint64_t</type>)
- <literal>r-</literal>
- [<option>--enable-stats</option>]
- </term>
- <listitem><para>Cumulative number of times a large extent of the
- corresponding size class was allocated from the arena, whether to fill
- the relevant tcache if <link
- linkend="opt.tcache"><mallctl>opt.tcache</mallctl></link> is enabled and
- the size class is within the range being cached, or to directly satisfy
- an allocation request otherwise.</para></listitem>
- </varlistentry>
-
- <varlistentry id="stats.arenas.i.lextents.j.ndalloc">
- <term>
- <mallctl>stats.arenas.&lt;i&gt;.lextents.&lt;j&gt;.ndalloc</mallctl>
- (<type>uint64_t</type>)
- <literal>r-</literal>
- [<option>--enable-stats</option>]
- </term>
- <listitem><para>Cumulative number of times a large extent of the
- corresponding size class was returned to the arena, whether to flush the
- relevant tcache if <link
- linkend="opt.tcache"><mallctl>opt.tcache</mallctl></link> is enabled and
- the size class is within the range being cached, or to directly
- deallocate an allocation otherwise.</para></listitem>
- </varlistentry>
-
- <varlistentry id="stats.arenas.i.lextents.j.nrequests">
- <term>
- <mallctl>stats.arenas.&lt;i&gt;.lextents.&lt;j&gt;.nrequests</mallctl>
- (<type>uint64_t</type>)
- <literal>r-</literal>
- [<option>--enable-stats</option>]
- </term>
- <listitem><para>Cumulative number of allocation requests satisfied by
- large extents of the corresponding size class.</para></listitem>
- </varlistentry>
-
- <varlistentry id="stats.arenas.i.lextents.j.curlextents">
- <term>
- <mallctl>stats.arenas.&lt;i&gt;.lextents.&lt;j&gt;.curlextents</mallctl>
- (<type>size_t</type>)
- <literal>r-</literal>
- [<option>--enable-stats</option>]
- </term>
- <listitem><para>Current number of large allocations for this size class.
- </para></listitem>
- </varlistentry>
-
- <varlistentry id="stats.arenas.i.mutexes.large">
- <term>
- <mallctl>stats.arenas.&lt;i&gt;.mutexes.large.{counter}</mallctl>
- (<type>counter specific type</type>) <literal>r-</literal>
- [<option>--enable-stats</option>]
- </term>
- <listitem><para>Statistics on <varname>arena.&lt;i&gt;.large</varname>
- mutex (arena scope; large allocation related).
- <mallctl>{counter}</mallctl> is one of the counters in <link
- linkend="mutex_counters">mutex profiling
- counters</link>.</para></listitem>
- </varlistentry>
-
- <varlistentry id="stats.arenas.i.mutexes.extent_avail">
- <term>
- <mallctl>stats.arenas.&lt;i&gt;.mutexes.extent_avail.{counter}</mallctl>
- (<type>counter specific type</type>) <literal>r-</literal>
- [<option>--enable-stats</option>]
- </term>
- <listitem><para>Statistics on <varname>arena.&lt;i&gt;.extent_avail
- </varname> mutex (arena scope; extent avail related).
- <mallctl>{counter}</mallctl> is one of the counters in <link
- linkend="mutex_counters">mutex profiling
- counters</link>.</para></listitem>
- </varlistentry>
-
- <varlistentry id="stats.arenas.i.mutexes.extents_dirty">
- <term>
- <mallctl>stats.arenas.&lt;i&gt;.mutexes.extents_dirty.{counter}</mallctl>
- (<type>counter specific type</type>) <literal>r-</literal>
- [<option>--enable-stats</option>]
- </term>
- <listitem><para>Statistics on <varname>arena.&lt;i&gt;.extents_dirty
- </varname> mutex (arena scope; dirty extents related).
- <mallctl>{counter}</mallctl> is one of the counters in <link
- linkend="mutex_counters">mutex profiling
- counters</link>.</para></listitem>
- </varlistentry>
-
- <varlistentry id="stats.arenas.i.mutexes.extents_muzzy">
- <term>
- <mallctl>stats.arenas.&lt;i&gt;.mutexes.extents_muzzy.{counter}</mallctl>
- (<type>counter specific type</type>) <literal>r-</literal>
- [<option>--enable-stats</option>]
- </term>
- <listitem><para>Statistics on <varname>arena.&lt;i&gt;.extents_muzzy
- </varname> mutex (arena scope; muzzy extents related).
- <mallctl>{counter}</mallctl> is one of the counters in <link
- linkend="mutex_counters">mutex profiling
- counters</link>.</para></listitem>
- </varlistentry>
-
- <varlistentry id="stats.arenas.i.mutexes.extents_retained">
- <term>
- <mallctl>stats.arenas.&lt;i&gt;.mutexes.extents_retained.{counter}</mallctl>
- (<type>counter specific type</type>) <literal>r-</literal>
- [<option>--enable-stats</option>]
- </term>
- <listitem><para>Statistics on <varname>arena.&lt;i&gt;.extents_retained
- </varname> mutex (arena scope; retained extents related).
- <mallctl>{counter}</mallctl> is one of the counters in <link
- linkend="mutex_counters">mutex profiling
- counters</link>.</para></listitem>
- </varlistentry>
-
- <varlistentry id="stats.arenas.i.mutexes.decay_dirty">
- <term>
- <mallctl>stats.arenas.&lt;i&gt;.mutexes.decay_dirty.{counter}</mallctl>
- (<type>counter specific type</type>) <literal>r-</literal>
- [<option>--enable-stats</option>]
- </term>
- <listitem><para>Statistics on <varname>arena.&lt;i&gt;.decay_dirty
- </varname> mutex (arena scope; decay for dirty pages related).
- <mallctl>{counter}</mallctl> is one of the counters in <link
- linkend="mutex_counters">mutex profiling
- counters</link>.</para></listitem>
- </varlistentry>
-
- <varlistentry id="stats.arenas.i.mutexes.decay_muzzy">
- <term>
- <mallctl>stats.arenas.&lt;i&gt;.mutexes.decay_muzzy.{counter}</mallctl>
- (<type>counter specific type</type>) <literal>r-</literal>
- [<option>--enable-stats</option>]
- </term>
- <listitem><para>Statistics on <varname>arena.&lt;i&gt;.decay_muzzy
- </varname> mutex (arena scope; decay for muzzy pages related).
- <mallctl>{counter}</mallctl> is one of the counters in <link
- linkend="mutex_counters">mutex profiling
- counters</link>.</para></listitem>
- </varlistentry>
-
- <varlistentry id="stats.arenas.i.mutexes.base">
- <term>
- <mallctl>stats.arenas.&lt;i&gt;.mutexes.base.{counter}</mallctl>
- (<type>counter specific type</type>) <literal>r-</literal>
- [<option>--enable-stats</option>]
- </term>
- <listitem><para>Statistics on <varname>arena.&lt;i&gt;.base</varname>
- mutex (arena scope; base allocator related).
- <mallctl>{counter}</mallctl> is one of the counters in <link
- linkend="mutex_counters">mutex profiling
- counters</link>.</para></listitem>
- </varlistentry>
-
- <varlistentry id="stats.arenas.i.mutexes.tcache_list">
- <term>
- <mallctl>stats.arenas.&lt;i&gt;.mutexes.tcache_list.{counter}</mallctl>
- (<type>counter specific type</type>) <literal>r-</literal>
- [<option>--enable-stats</option>]
- </term>
- <listitem><para>Statistics on
- <varname>arena.&lt;i&gt;.tcache_list</varname> mutex (arena scope;
- tcache to arena association related). This mutex is expected to be
- accessed less often. <mallctl>{counter}</mallctl> is one of the
- counters in <link linkend="mutex_counters">mutex profiling
- counters</link>.</para></listitem>
- </varlistentry>
-
- </variablelist>
- </refsect1>
- <refsect1 id="heap_profile_format">
- <title>HEAP PROFILE FORMAT</title>
- <para>Although the heap profiling functionality was originally designed to
- be compatible with the
- <command>pprof</command> command that is developed as part of the <ulink
- url="http://code.google.com/p/gperftools/">gperftools
- package</ulink>, the addition of per thread heap profiling functionality
- required a different heap profile format. The <command>jeprof</command>
- command is derived from <command>pprof</command>, with enhancements to
- support the heap profile format described here.</para>
-
- <para>In the following hypothetical heap profile, <constant>[...]</constant>
- indicates elision for the sake of compactness. <programlisting><![CDATA[
-heap_v2/524288
- t*: 28106: 56637512 [0: 0]
- [...]
- t3: 352: 16777344 [0: 0]
- [...]
- t99: 17754: 29341640 [0: 0]
- [...]
-@ 0x5f86da8 0x5f5a1dc [...] 0x29e4d4e 0xa200316 0xabb2988 [...]
- t*: 13: 6688 [0: 0]
- t3: 12: 6496 [0: ]
- t99: 1: 192 [0: 0]
-[...]
-
-MAPPED_LIBRARIES:
-[...]]]></programlisting> The following matches the above heap profile, but most
-tokens are replaced with <constant>&lt;description&gt;</constant> to indicate
-descriptions of the corresponding fields. <programlisting><![CDATA[
-<heap_profile_format_version>/<mean_sample_interval>
- <aggregate>: <curobjs>: <curbytes> [<cumobjs>: <cumbytes>]
- [...]
- <thread_3_aggregate>: <curobjs>: <curbytes>[<cumobjs>: <cumbytes>]
- [...]
- <thread_99_aggregate>: <curobjs>: <curbytes>[<cumobjs>: <cumbytes>]
- [...]
-@ <top_frame> <frame> [...] <frame> <frame> <frame> [...]
- <backtrace_aggregate>: <curobjs>: <curbytes> [<cumobjs>: <cumbytes>]
- <backtrace_thread_3>: <curobjs>: <curbytes> [<cumobjs>: <cumbytes>]
- <backtrace_thread_99>: <curobjs>: <curbytes> [<cumobjs>: <cumbytes>]
-[...]
-
-MAPPED_LIBRARIES:
-</proc/<pid>/maps>]]></programlisting></para>
- </refsect1>
-
- <refsect1 id="debugging_malloc_problems">
- <title>DEBUGGING MALLOC PROBLEMS</title>
- <para>When debugging, it is a good idea to configure/build jemalloc with
- the <option>--enable-debug</option> and <option>--enable-fill</option>
- options, and recompile the program with suitable options and symbols for
- debugger support. When so configured, jemalloc incorporates a wide variety
- of run-time assertions that catch application errors such as double-free,
- write-after-free, etc.</para>
-
- <para>Programs often accidentally depend on <quote>uninitialized</quote>
- memory actually being filled with zero bytes. Junk filling
- (see the <link linkend="opt.junk"><mallctl>opt.junk</mallctl></link>
- option) tends to expose such bugs in the form of obviously incorrect
- results and/or coredumps. Conversely, zero
- filling (see the <link
- linkend="opt.zero"><mallctl>opt.zero</mallctl></link> option) eliminates
- the symptoms of such bugs. Between these two options, it is usually
- possible to quickly detect, diagnose, and eliminate such bugs.</para>
-
- <para>This implementation does not provide much detail about the problems
- it detects, because the performance impact for storing such information
- would be prohibitive.</para>
- </refsect1>
- <refsect1 id="diagnostic_messages">
- <title>DIAGNOSTIC MESSAGES</title>
- <para>If any of the memory allocation/deallocation functions detect an
- error or warning condition, a message will be printed to file descriptor
- <constant>STDERR_FILENO</constant>. Errors will result in the process
- dumping core. If the <link
- linkend="opt.abort"><mallctl>opt.abort</mallctl></link> option is set, most
- warnings are treated as errors.</para>
-
- <para>The <varname>malloc_message</varname> variable allows the programmer
- to override the function which emits the text strings forming the errors
- and warnings if for some reason the <constant>STDERR_FILENO</constant> file
- descriptor is not suitable for this.
- <function>malloc_message()</function> takes the
- <parameter>cbopaque</parameter> pointer argument that is
- <constant>NULL</constant> unless overridden by the arguments in a call to
- <function>malloc_stats_print()</function>, followed by a string
- pointer. Please note that doing anything which tries to allocate memory in
- this function is likely to result in a crash or deadlock.</para>
-
- <para>All messages are prefixed by
- <quote><computeroutput>&lt;jemalloc&gt;: </computeroutput></quote>.</para>
- </refsect1>
- <refsect1 id="return_values">
- <title>RETURN VALUES</title>
- <refsect2>
- <title>Standard API</title>
- <para>The <function>malloc()</function> and
- <function>calloc()</function> functions return a pointer to the
- allocated memory if successful; otherwise a <constant>NULL</constant>
- pointer is returned and <varname>errno</varname> is set to
- <errorname>ENOMEM</errorname>.</para>
-
- <para>The <function>posix_memalign()</function> function
- returns the value 0 if successful; otherwise it returns an error value.
- The <function>posix_memalign()</function> function will fail
- if:
- <variablelist>
- <varlistentry>
- <term><errorname>EINVAL</errorname></term>
-
- <listitem><para>The <parameter>alignment</parameter> parameter is
- not a power of 2 at least as large as
- <code language="C">sizeof(<type>void *</type>)</code>.
- </para></listitem>
- </varlistentry>
- <varlistentry>
- <term><errorname>ENOMEM</errorname></term>
-
- <listitem><para>Memory allocation error.</para></listitem>
- </varlistentry>
- </variablelist>
- </para>
-
- <para>The <function>aligned_alloc()</function> function returns
- a pointer to the allocated memory if successful; otherwise a
- <constant>NULL</constant> pointer is returned and
- <varname>errno</varname> is set. The
- <function>aligned_alloc()</function> function will fail if:
- <variablelist>
- <varlistentry>
- <term><errorname>EINVAL</errorname></term>
-
- <listitem><para>The <parameter>alignment</parameter> parameter is
- not a power of 2.
- </para></listitem>
- </varlistentry>
- <varlistentry>
- <term><errorname>ENOMEM</errorname></term>
-
- <listitem><para>Memory allocation error.</para></listitem>
- </varlistentry>
- </variablelist>
- </para>
-
- <para>The <function>realloc()</function> function returns a
- pointer, possibly identical to <parameter>ptr</parameter>, to the
- allocated memory if successful; otherwise a <constant>NULL</constant>
- pointer is returned, and <varname>errno</varname> is set to
- <errorname>ENOMEM</errorname> if the error was the result of an
- allocation failure. The <function>realloc()</function>
- function always leaves the original buffer intact when an error occurs.
- </para>
-
- <para>The <function>free()</function> function returns no
- value.</para>
- </refsect2>
- <refsect2>
- <title>Non-standard API</title>
- <para>The <function>mallocx()</function> and
- <function>rallocx()</function> functions return a pointer to
- the allocated memory if successful; otherwise a <constant>NULL</constant>
- pointer is returned to indicate insufficient contiguous memory was
- available to service the allocation request. </para>
-
- <para>The <function>xallocx()</function> function returns the
- real size of the resulting resized allocation pointed to by
- <parameter>ptr</parameter>, which is a value less than
- <parameter>size</parameter> if the allocation could not be adequately
- grown in place. </para>
-
- <para>The <function>sallocx()</function> function returns the
- real size of the allocation pointed to by <parameter>ptr</parameter>.
- </para>
-
- <para>The <function>nallocx()</function> returns the real size
- that would result from a successful equivalent
- <function>mallocx()</function> function call, or zero if
- insufficient memory is available to perform the size computation. </para>
-
- <para>The <function>mallctl()</function>,
- <function>mallctlnametomib()</function>, and
- <function>mallctlbymib()</function> functions return 0 on
- success; otherwise they return an error value. The functions will fail
- if:
- <variablelist>
- <varlistentry>
- <term><errorname>EINVAL</errorname></term>
-
- <listitem><para><parameter>newp</parameter> is not
- <constant>NULL</constant>, and <parameter>newlen</parameter> is too
- large or too small. Alternatively, <parameter>*oldlenp</parameter>
- is too large or too small; in this case as much data as possible
- are read despite the error.</para></listitem>
- </varlistentry>
- <varlistentry>
- <term><errorname>ENOENT</errorname></term>
-
- <listitem><para><parameter>name</parameter> or
- <parameter>mib</parameter> specifies an unknown/invalid
- value.</para></listitem>
- </varlistentry>
- <varlistentry>
- <term><errorname>EPERM</errorname></term>
-
- <listitem><para>Attempt to read or write void value, or attempt to
- write read-only value.</para></listitem>
- </varlistentry>
- <varlistentry>
- <term><errorname>EAGAIN</errorname></term>
-
- <listitem><para>A memory allocation failure
- occurred.</para></listitem>
- </varlistentry>
- <varlistentry>
- <term><errorname>EFAULT</errorname></term>
-
- <listitem><para>An interface with side effects failed in some way
- not directly related to <function>mallctl*()</function>
- read/write processing.</para></listitem>
- </varlistentry>
- </variablelist>
- </para>
-
- <para>The <function>malloc_usable_size()</function> function
- returns the usable size of the allocation pointed to by
- <parameter>ptr</parameter>. </para>
- </refsect2>
- </refsect1>
- <refsect1 id="environment">
- <title>ENVIRONMENT</title>
- <para>The following environment variable affects the execution of the
- allocation functions:
- <variablelist>
- <varlistentry>
- <term><envar>MALLOC_CONF</envar></term>
-
- <listitem><para>If the environment variable
- <envar>MALLOC_CONF</envar> is set, the characters it contains
- will be interpreted as options.</para></listitem>
- </varlistentry>
- </variablelist>
- </para>
- </refsect1>
- <refsect1 id="examples">
- <title>EXAMPLES</title>
- <para>To dump core whenever a problem occurs:
- <screen>ln -s 'abort:true' /etc/malloc.conf</screen>
- </para>
- <para>To specify in the source that only one arena should be automatically
- created:
- <programlisting language="C"><![CDATA[
-malloc_conf = "narenas:1";]]></programlisting></para>
- </refsect1>
- <refsect1 id="see_also">
- <title>SEE ALSO</title>
- <para><citerefentry><refentrytitle>madvise</refentrytitle>
- <manvolnum>2</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>mmap</refentrytitle>
- <manvolnum>2</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>sbrk</refentrytitle>
- <manvolnum>2</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>utrace</refentrytitle>
- <manvolnum>2</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>alloca</refentrytitle>
- <manvolnum>3</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>atexit</refentrytitle>
- <manvolnum>3</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>getpagesize</refentrytitle>
- <manvolnum>3</manvolnum></citerefentry></para>
- </refsect1>
- <refsect1 id="standards">
- <title>STANDARDS</title>
- <para>The <function>malloc()</function>,
- <function>calloc()</function>,
- <function>realloc()</function>, and
- <function>free()</function> functions conform to ISO/IEC
- 9899:1990 (<quote>ISO C90</quote>).</para>
-
- <para>The <function>posix_memalign()</function> function conforms
- to IEEE Std 1003.1-2001 (<quote>POSIX.1</quote>).</para>
- </refsect1>
- <refsect1 id="history">
- <title>HISTORY</title>
- <para>The <function>malloc_usable_size()</function> and
- <function>posix_memalign()</function> functions first appeared in FreeBSD
- 7.0.</para>
-
- <para>The <function>aligned_alloc()</function>,
- <function>malloc_stats_print()</function>, and
- <function>mallctl*()</function> functions first appeared in FreeBSD
- 10.0.</para>
-
- <para>The <function>*allocx()</function> functions first appeared in FreeBSD
- 11.0.</para>
- </refsect1>
-</refentry>
->>>>>>> main
diff --git a/contrib/jemalloc/include/jemalloc/internal/jemalloc_internal_defs.h.in b/contrib/jemalloc/include/jemalloc/internal/jemalloc_internal_defs.h.in
index 52b31878a464..3588072f178c 100644
--- a/contrib/jemalloc/include/jemalloc/internal/jemalloc_internal_defs.h.in
+++ b/contrib/jemalloc/include/jemalloc/internal/jemalloc_internal_defs.h.in
@@ -1,4 +1,3 @@
-<<<<<<< HEAD
#ifndef JEMALLOC_INTERNAL_DEFS_H_
#define JEMALLOC_INTERNAL_DEFS_H_
/*
@@ -426,372 +425,3 @@
#undef JEMALLOC_ZERO_REALLOC_DEFAULT_FREE
#endif /* JEMALLOC_INTERNAL_DEFS_H_ */
-||||||| dec341af7695
-=======
-#ifndef JEMALLOC_INTERNAL_DEFS_H_
-#define JEMALLOC_INTERNAL_DEFS_H_
-/*
- * If JEMALLOC_PREFIX is defined via --with-jemalloc-prefix, it will cause all
- * public APIs to be prefixed. This makes it possible, with some care, to use
- * multiple allocators simultaneously.
- */
-#undef JEMALLOC_PREFIX
-#undef JEMALLOC_CPREFIX
-
-/*
- * Define overrides for non-standard allocator-related functions if they are
- * present on the system.
- */
-#undef JEMALLOC_OVERRIDE___LIBC_CALLOC
-#undef JEMALLOC_OVERRIDE___LIBC_FREE
-#undef JEMALLOC_OVERRIDE___LIBC_MALLOC
-#undef JEMALLOC_OVERRIDE___LIBC_MEMALIGN
-#undef JEMALLOC_OVERRIDE___LIBC_REALLOC
-#undef JEMALLOC_OVERRIDE___LIBC_VALLOC
-#undef JEMALLOC_OVERRIDE___POSIX_MEMALIGN
-
-/*
- * JEMALLOC_PRIVATE_NAMESPACE is used as a prefix for all library-private APIs.
- * For shared libraries, symbol visibility mechanisms prevent these symbols
- * from being exported, but for static libraries, naming collisions are a real
- * possibility.
- */
-#undef JEMALLOC_PRIVATE_NAMESPACE
-
-/*
- * Hyper-threaded CPUs may need a special instruction inside spin loops in
- * order to yield to another virtual CPU.
- */
-#undef CPU_SPINWAIT
-/* 1 if CPU_SPINWAIT is defined, 0 otherwise. */
-#undef HAVE_CPU_SPINWAIT
-
-/*
- * Number of significant bits in virtual addresses. This may be less than the
- * total number of bits in a pointer, e.g. on x64, for which the uppermost 16
- * bits are the same as bit 47.
- */
-#undef LG_VADDR
-
-/* Defined if C11 atomics are available. */
-#undef JEMALLOC_C11_ATOMICS
-
-/* Defined if GCC __atomic atomics are available. */
-#undef JEMALLOC_GCC_ATOMIC_ATOMICS
-/* and the 8-bit variant support. */
-#undef JEMALLOC_GCC_U8_ATOMIC_ATOMICS
-
-/* Defined if GCC __sync atomics are available. */
-#undef JEMALLOC_GCC_SYNC_ATOMICS
-/* and the 8-bit variant support. */
-#undef JEMALLOC_GCC_U8_SYNC_ATOMICS
-
-/*
- * Defined if __builtin_clz() and __builtin_clzl() are available.
- */
-#undef JEMALLOC_HAVE_BUILTIN_CLZ
-
-/*
- * Defined if os_unfair_lock_*() functions are available, as provided by Darwin.
- */
-#undef JEMALLOC_OS_UNFAIR_LOCK
-
-/* Defined if syscall(2) is usable. */
-#undef JEMALLOC_USE_SYSCALL
-
-/*
- * Defined if secure_getenv(3) is available.
- */
-#undef JEMALLOC_HAVE_SECURE_GETENV
-
-/*
- * Defined if issetugid(2) is available.
- */
-#undef JEMALLOC_HAVE_ISSETUGID
-
-/* Defined if pthread_atfork(3) is available. */
-#undef JEMALLOC_HAVE_PTHREAD_ATFORK
-
-/* Defined if pthread_setname_np(3) is available. */
-#undef JEMALLOC_HAVE_PTHREAD_SETNAME_NP
-
-/*
- * Defined if clock_gettime(CLOCK_MONOTONIC_COARSE, ...) is available.
- */
-#undef JEMALLOC_HAVE_CLOCK_MONOTONIC_COARSE
-
-/*
- * Defined if clock_gettime(CLOCK_MONOTONIC, ...) is available.
- */
-#undef JEMALLOC_HAVE_CLOCK_MONOTONIC
-
-/*
- * Defined if mach_absolute_time() is available.
- */
-#undef JEMALLOC_HAVE_MACH_ABSOLUTE_TIME
-
-/*
- * Defined if _malloc_thread_cleanup() exists. At least in the case of
- * FreeBSD, pthread_key_create() allocates, which if used during malloc
- * bootstrapping will cause recursion into the pthreads library. Therefore, if
- * _malloc_thread_cleanup() exists, use it as the basis for thread cleanup in
- * malloc_tsd.
- */
-#undef JEMALLOC_MALLOC_THREAD_CLEANUP
-
-/*
- * Defined if threaded initialization is known to be safe on this platform.
- * Among other things, it must be possible to initialize a mutex without
- * triggering allocation in order for threaded allocation to be safe.
- */
-#undef JEMALLOC_THREADED_INIT
-
-/*
- * Defined if the pthreads implementation defines
- * _pthread_mutex_init_calloc_cb(), in which case the function is used in order
- * to avoid recursive allocation during mutex initialization.
- */
-#undef JEMALLOC_MUTEX_INIT_CB
-
-/* Non-empty if the tls_model attribute is supported. */
-#undef JEMALLOC_TLS_MODEL
-
-/*
- * JEMALLOC_DEBUG enables assertions and other sanity checks, and disables
- * inline functions.
- */
-#undef JEMALLOC_DEBUG
-
-/* JEMALLOC_STATS enables statistics calculation. */
-#undef JEMALLOC_STATS
-
-/* JEMALLOC_EXPERIMENTAL_SMALLOCX_API enables experimental smallocx API. */
-#undef JEMALLOC_EXPERIMENTAL_SMALLOCX_API
-
-/* JEMALLOC_PROF enables allocation profiling. */
-#undef JEMALLOC_PROF
-
-/* Use libunwind for profile backtracing if defined. */
-#undef JEMALLOC_PROF_LIBUNWIND
-
-/* Use libgcc for profile backtracing if defined. */
-#undef JEMALLOC_PROF_LIBGCC
-
-/* Use gcc intrinsics for profile backtracing if defined. */
-#undef JEMALLOC_PROF_GCC
-
-/*
- * JEMALLOC_DSS enables use of sbrk(2) to allocate extents from the data storage
- * segment (DSS).
- */
-#undef JEMALLOC_DSS
-
-/* Support memory filling (junk/zero). */
-#undef JEMALLOC_FILL
-
-/* Support utrace(2)-based tracing. */
-#undef JEMALLOC_UTRACE
-
-/* Support optional abort() on OOM. */
-#undef JEMALLOC_XMALLOC
-
-/* Support lazy locking (avoid locking unless a second thread is launched). */
-#undef JEMALLOC_LAZY_LOCK
-
-/*
- * Minimum allocation alignment is 2^LG_QUANTUM bytes (ignoring tiny size
- * classes).
- */
-#undef LG_QUANTUM
-
-/* One page is 2^LG_PAGE bytes. */
-#undef LG_PAGE
-
-/*
- * One huge page is 2^LG_HUGEPAGE bytes. Note that this is defined even if the
- * system does not explicitly support huge pages; system calls that require
- * explicit huge page support are separately configured.
- */
-#undef LG_HUGEPAGE
-
-/*
- * If defined, adjacent virtual memory mappings with identical attributes
- * automatically coalesce, and they fragment when changes are made to subranges.
- * This is the normal order of things for mmap()/munmap(), but on Windows
- * VirtualAlloc()/VirtualFree() operations must be precisely matched, i.e.
- * mappings do *not* coalesce/fragment.
- */
-#undef JEMALLOC_MAPS_COALESCE
-
-/*
- * If defined, retain memory for later reuse by default rather than using e.g.
- * munmap() to unmap freed extents. This is enabled on 64-bit Linux because
- * common sequences of mmap()/munmap() calls will cause virtual memory map
- * holes.
- */
-#undef JEMALLOC_RETAIN
-
-/* TLS is used to map arenas and magazine caches to threads. */
-#undef JEMALLOC_TLS
-
-/*
- * Used to mark unreachable code to quiet "end of non-void" compiler warnings.
- * Don't use this directly; instead use unreachable() from util.h
- */
-#undef JEMALLOC_INTERNAL_UNREACHABLE
-
-/*
- * ffs*() functions to use for bitmapping. Don't use these directly; instead,
- * use ffs_*() from util.h.
- */
-#undef JEMALLOC_INTERNAL_FFSLL
-#undef JEMALLOC_INTERNAL_FFSL
-#undef JEMALLOC_INTERNAL_FFS
-
-/*
- * popcount*() functions to use for bitmapping.
- */
-#undef JEMALLOC_INTERNAL_POPCOUNTL
-#undef JEMALLOC_INTERNAL_POPCOUNT
-
-/*
- * If defined, explicitly attempt to more uniformly distribute large allocation
- * pointer alignments across all cache indices.
- */
-#undef JEMALLOC_CACHE_OBLIVIOUS
-
-/*
- * If defined, enable logging facilities. We make this a configure option to
- * avoid taking extra branches everywhere.
- */
-#undef JEMALLOC_LOG
-
-/*
- * If defined, use readlinkat() (instead of readlink()) to follow
- * /etc/malloc_conf.
- */
-#undef JEMALLOC_READLINKAT
-
-/*
- * Darwin (OS X) uses zones to work around Mach-O symbol override shortcomings.
- */
-#undef JEMALLOC_ZONE
-
-/*
- * Methods for determining whether the OS overcommits.
- * JEMALLOC_PROC_SYS_VM_OVERCOMMIT_MEMORY: Linux's
- * /proc/sys/vm.overcommit_memory file.
- * JEMALLOC_SYSCTL_VM_OVERCOMMIT: FreeBSD's vm.overcommit sysctl.
- */
-#undef JEMALLOC_SYSCTL_VM_OVERCOMMIT
-#undef JEMALLOC_PROC_SYS_VM_OVERCOMMIT_MEMORY
-
-/* Defined if madvise(2) is available. */
-#undef JEMALLOC_HAVE_MADVISE
-
-/*
- * Defined if transparent huge pages are supported via the MADV_[NO]HUGEPAGE
- * arguments to madvise(2).
- */
-#undef JEMALLOC_HAVE_MADVISE_HUGE
-
-/*
- * Methods for purging unused pages differ between operating systems.
- *
- * madvise(..., MADV_FREE) : This marks pages as being unused, such that they
- * will be discarded rather than swapped out.
- * madvise(..., MADV_DONTNEED) : If JEMALLOC_PURGE_MADVISE_DONTNEED_ZEROS is
- * defined, this immediately discards pages,
- * such that new pages will be demand-zeroed if
- * the address region is later touched;
- * otherwise this behaves similarly to
- * MADV_FREE, though typically with higher
- * system overhead.
- */
-#undef JEMALLOC_PURGE_MADVISE_FREE
-#undef JEMALLOC_PURGE_MADVISE_DONTNEED
-#undef JEMALLOC_PURGE_MADVISE_DONTNEED_ZEROS
-
-/* Defined if madvise(2) is available but MADV_FREE is not (x86 Linux only). */
-#undef JEMALLOC_DEFINE_MADVISE_FREE
-
-/*
- * Defined if MADV_DO[NT]DUMP is supported as an argument to madvise.
- */
-#undef JEMALLOC_MADVISE_DONTDUMP
-
-/*
- * Defined if transparent huge pages (THPs) are supported via the
- * MADV_[NO]HUGEPAGE arguments to madvise(2), and THP support is enabled.
- */
-#undef JEMALLOC_THP
-
-/* Define if operating system has alloca.h header. */
-#undef JEMALLOC_HAS_ALLOCA_H
-
-/* C99 restrict keyword supported. */
-#undef JEMALLOC_HAS_RESTRICT
-
-/* For use by hash code. */
-#undef JEMALLOC_BIG_ENDIAN
-
-/* sizeof(int) == 2^LG_SIZEOF_INT. */
-#undef LG_SIZEOF_INT
-
-/* sizeof(long) == 2^LG_SIZEOF_LONG. */
-#undef LG_SIZEOF_LONG
-
-/* sizeof(long long) == 2^LG_SIZEOF_LONG_LONG. */
-#undef LG_SIZEOF_LONG_LONG
-
-/* sizeof(intmax_t) == 2^LG_SIZEOF_INTMAX_T. */
-#undef LG_SIZEOF_INTMAX_T
-
-/* glibc malloc hooks (__malloc_hook, __realloc_hook, __free_hook). */
-#undef JEMALLOC_GLIBC_MALLOC_HOOK
-
-/* glibc memalign hook. */
-#undef JEMALLOC_GLIBC_MEMALIGN_HOOK
-
-/* pthread support */
-#undef JEMALLOC_HAVE_PTHREAD
-
-/* dlsym() support */
-#undef JEMALLOC_HAVE_DLSYM
-
-/* Adaptive mutex support in pthreads. */
-#undef JEMALLOC_HAVE_PTHREAD_MUTEX_ADAPTIVE_NP
-
-/* GNU specific sched_getcpu support */
-#undef JEMALLOC_HAVE_SCHED_GETCPU
-
-/* GNU specific sched_setaffinity support */
-#undef JEMALLOC_HAVE_SCHED_SETAFFINITY
-
-/*
- * If defined, all the features necessary for background threads are present.
- */
-#undef JEMALLOC_BACKGROUND_THREAD
-
-/*
- * If defined, jemalloc symbols are not exported (doesn't work when
- * JEMALLOC_PREFIX is not defined).
- */
-#undef JEMALLOC_EXPORT
-
-/* config.malloc_conf options string. */
-#undef JEMALLOC_CONFIG_MALLOC_CONF
-
-/* If defined, jemalloc takes the malloc/free/etc. symbol names. */
-#undef JEMALLOC_IS_MALLOC
-
-/*
- * Defined if strerror_r returns char * if _GNU_SOURCE is defined.
- */
-#undef JEMALLOC_STRERROR_R_RETURNS_CHAR_WITH_GNU_SOURCE
-
-/* Performs additional safety checks when defined. */
-#undef JEMALLOC_OPT_SAFETY_CHECKS
-
-#endif /* JEMALLOC_INTERNAL_DEFS_H_ */
->>>>>>> main
diff --git a/contrib/jemalloc/include/jemalloc/internal/jemalloc_preamble.h.in b/contrib/jemalloc/include/jemalloc/internal/jemalloc_preamble.h.in
index c4fb2d0793bf..e4932f1e8c18 100644
--- a/contrib/jemalloc/include/jemalloc/internal/jemalloc_preamble.h.in
+++ b/contrib/jemalloc/include/jemalloc/internal/jemalloc_preamble.h.in
@@ -1,4 +1,3 @@
-<<<<<<< HEAD
#ifndef JEMALLOC_PREAMBLE_H
#define JEMALLOC_PREAMBLE_H
@@ -261,218 +260,3 @@ static const bool have_memcntl =
;
#endif /* JEMALLOC_PREAMBLE_H */
-||||||| dec341af7695
-=======
-#ifndef JEMALLOC_PREAMBLE_H
-#define JEMALLOC_PREAMBLE_H
-
-#include "jemalloc_internal_defs.h"
-#include "jemalloc/internal/jemalloc_internal_decls.h"
-
-#ifdef JEMALLOC_UTRACE
-#include <sys/ktrace.h>
-#endif
-
-#ifndef JEMALLOC_PRIVATE_NAMESPACE
-#include "un-namespace.h"
-#include "libc_private.h"
-#endif
-
-#define JEMALLOC_NO_DEMANGLE
-#ifdef JEMALLOC_JET
-# undef JEMALLOC_IS_MALLOC
-# define JEMALLOC_N(n) jet_##n
-# include "jemalloc/internal/public_namespace.h"
-# define JEMALLOC_NO_RENAME
-# include "../jemalloc@install_suffix@.h"
-# undef JEMALLOC_NO_RENAME
-#else
-# define JEMALLOC_N(n) @private_namespace@##n
-# include "../jemalloc@install_suffix@.h"
-#endif
-
-#if defined(JEMALLOC_OSATOMIC)
-#include <libkern/OSAtomic.h>
-#endif
-
-#ifdef JEMALLOC_ZONE
-#include <mach/mach_error.h>
-#include <mach/mach_init.h>
-#include <mach/vm_map.h>
-#endif
-
-#include "jemalloc/internal/jemalloc_internal_macros.h"
-
-/*
- * Note that the ordering matters here; the hook itself is name-mangled. We
- * want the inclusion of hooks to happen early, so that we hook as much as
- * possible.
- */
-#ifndef JEMALLOC_NO_PRIVATE_NAMESPACE
-# ifndef JEMALLOC_JET
-# include "jemalloc/internal/private_namespace.h"
-# else
-# include "jemalloc/internal/private_namespace_jet.h"
-# endif
-#endif
-#include "jemalloc/internal/test_hooks.h"
-
-#ifdef JEMALLOC_DEFINE_MADVISE_FREE
-# define JEMALLOC_MADV_FREE 8
-#endif
-
-static const bool config_debug =
-#ifdef JEMALLOC_DEBUG
- true
-#else
- false
-#endif
- ;
-static const bool have_dss =
-#ifdef JEMALLOC_DSS
- true
-#else
- false
-#endif
- ;
-static const bool have_madvise_huge =
-#ifdef JEMALLOC_HAVE_MADVISE_HUGE
- true
-#else
- false
-#endif
- ;
-static const bool config_fill =
-#ifdef JEMALLOC_FILL
- true
-#else
- false
-#endif
- ;
-static const bool config_lazy_lock = true;
-static const char * const config_malloc_conf = JEMALLOC_CONFIG_MALLOC_CONF;
-static const bool config_prof =
-#ifdef JEMALLOC_PROF
- true
-#else
- false
-#endif
- ;
-static const bool config_prof_libgcc =
-#ifdef JEMALLOC_PROF_LIBGCC
- true
-#else
- false
-#endif
- ;
-static const bool config_prof_libunwind =
-#ifdef JEMALLOC_PROF_LIBUNWIND
- true
-#else
- false
-#endif
- ;
-static const bool maps_coalesce =
-#ifdef JEMALLOC_MAPS_COALESCE
- true
-#else
- false
-#endif
- ;
-static const bool config_stats =
-#ifdef JEMALLOC_STATS
- true
-#else
- false
-#endif
- ;
-static const bool config_tls =
-#ifdef JEMALLOC_TLS
- true
-#else
- false
-#endif
- ;
-static const bool config_utrace =
-#ifdef JEMALLOC_UTRACE
- true
-#else
- false
-#endif
- ;
-static const bool config_xmalloc =
-#ifdef JEMALLOC_XMALLOC
- true
-#else
- false
-#endif
- ;
-static const bool config_cache_oblivious =
-#ifdef JEMALLOC_CACHE_OBLIVIOUS
- true
-#else
- false
-#endif
- ;
-/*
- * Undocumented, for jemalloc development use only at the moment. See the note
- * in jemalloc/internal/log.h.
- */
-static const bool config_log =
-#ifdef JEMALLOC_LOG
- true
-#else
- false
-#endif
- ;
-/*
- * Are extra safety checks enabled; things like checking the size of sized
- * deallocations, double-frees, etc.
- */
-static const bool config_opt_safety_checks =
-#ifdef JEMALLOC_OPT_SAFETY_CHECKS
- true
-#elif defined(JEMALLOC_DEBUG)
- /*
- * This lets us only guard safety checks by one flag instead of two; fast
- * checks can guard solely by config_opt_safety_checks and run in debug mode
- * too.
- */
- true
-#else
- false
-#endif
- ;
-
-#if defined(_WIN32) || defined(JEMALLOC_HAVE_SCHED_GETCPU)
-/* Currently percpu_arena depends on sched_getcpu. */
-#define JEMALLOC_PERCPU_ARENA
-#endif
-static const bool have_percpu_arena =
-#ifdef JEMALLOC_PERCPU_ARENA
- true
-#else
- false
-#endif
- ;
-/*
- * Undocumented, and not recommended; the application should take full
- * responsibility for tracking provenance.
- */
-static const bool force_ivsalloc =
-#ifdef JEMALLOC_FORCE_IVSALLOC
- true
-#else
- false
-#endif
- ;
-static const bool have_background_thread =
-#ifdef JEMALLOC_BACKGROUND_THREAD
- true
-#else
- false
-#endif
- ;
-
-#endif /* JEMALLOC_PREAMBLE_H */
->>>>>>> main
diff --git a/contrib/jemalloc/include/jemalloc/internal/tsd_win.h b/contrib/jemalloc/include/jemalloc/internal/tsd_win.h
index 46be2434b5a5..a91dac88e06a 100644
--- a/contrib/jemalloc/include/jemalloc/internal/tsd_win.h
+++ b/contrib/jemalloc/include/jemalloc/internal/tsd_win.h
@@ -1,4 +1,3 @@
-<<<<<<< HEAD
#ifdef JEMALLOC_INTERNAL_TSD_WIN_H
#error This file should be included only once, by tsd.h.
#endif
@@ -138,145 +137,3 @@ tsd_set(tsd_t *val) {
}
wrapper->initialized = true;
}
-||||||| dec341af7695
-=======
-#ifdef JEMALLOC_INTERNAL_TSD_WIN_H
-#error This file should be included only once, by tsd.h.
-#endif
-#define JEMALLOC_INTERNAL_TSD_WIN_H
-
-typedef struct {
- bool initialized;
- tsd_t val;
-} tsd_wrapper_t;
-
-extern DWORD tsd_tsd;
-extern tsd_wrapper_t tsd_boot_wrapper;
-extern bool tsd_booted;
-
-/* Initialization/cleanup. */
-JEMALLOC_ALWAYS_INLINE bool
-tsd_cleanup_wrapper(void) {
- DWORD error = GetLastError();
- tsd_wrapper_t *wrapper = (tsd_wrapper_t *)TlsGetValue(tsd_tsd);
- SetLastError(error);
-
- if (wrapper == NULL) {
- return false;
- }
-
- if (wrapper->initialized) {
- wrapper->initialized = false;
- tsd_cleanup(&wrapper->val);
- if (wrapper->initialized) {
- /* Trigger another cleanup round. */
- return true;
- }
- }
- malloc_tsd_dalloc(wrapper);
- return false;
-}
-
-JEMALLOC_ALWAYS_INLINE void
-tsd_wrapper_set(tsd_wrapper_t *wrapper) {
- if (!TlsSetValue(tsd_tsd, (void *)wrapper)) {
- malloc_write("<jemalloc>: Error setting TSD\n");
- abort();
- }
-}
-
-JEMALLOC_ALWAYS_INLINE tsd_wrapper_t *
-tsd_wrapper_get(bool init) {
- DWORD error = GetLastError();
- tsd_wrapper_t *wrapper = (tsd_wrapper_t *) TlsGetValue(tsd_tsd);
- SetLastError(error);
-
- if (init && unlikely(wrapper == NULL)) {
- wrapper = (tsd_wrapper_t *)
- malloc_tsd_malloc(sizeof(tsd_wrapper_t));
- if (wrapper == NULL) {
- malloc_write("<jemalloc>: Error allocating TSD\n");
- abort();
- } else {
- wrapper->initialized = false;
- /* MSVC is finicky about aggregate initialization. */
- tsd_t tsd_initializer = TSD_INITIALIZER;
- wrapper->val = tsd_initializer;
- }
- tsd_wrapper_set(wrapper);
- }
- return wrapper;
-}
-
-JEMALLOC_ALWAYS_INLINE bool
-tsd_boot0(void) {
- tsd_tsd = TlsAlloc();
- if (tsd_tsd == TLS_OUT_OF_INDEXES) {
- return true;
- }
- malloc_tsd_cleanup_register(&tsd_cleanup_wrapper);
- tsd_wrapper_set(&tsd_boot_wrapper);
- tsd_booted = true;
- return false;
-}
-
-JEMALLOC_ALWAYS_INLINE void
-tsd_boot1(void) {
- tsd_wrapper_t *wrapper;
- wrapper = (tsd_wrapper_t *)
- malloc_tsd_malloc(sizeof(tsd_wrapper_t));
- if (wrapper == NULL) {
- malloc_write("<jemalloc>: Error allocating TSD\n");
- abort();
- }
- tsd_boot_wrapper.initialized = false;
- tsd_cleanup(&tsd_boot_wrapper.val);
- wrapper->initialized = false;
- tsd_t initializer = TSD_INITIALIZER;
- wrapper->val = initializer;
- tsd_wrapper_set(wrapper);
-}
-JEMALLOC_ALWAYS_INLINE bool
-tsd_boot(void) {
- if (tsd_boot0()) {
- return true;
- }
- tsd_boot1();
- return false;
-}
-
-JEMALLOC_ALWAYS_INLINE bool
-tsd_booted_get(void) {
- return tsd_booted;
-}
-
-JEMALLOC_ALWAYS_INLINE bool
-tsd_get_allocates(void) {
- return true;
-}
-
-/* Get/set. */
-JEMALLOC_ALWAYS_INLINE tsd_t *
-tsd_get(bool init) {
- tsd_wrapper_t *wrapper;
-
- assert(tsd_booted);
- wrapper = tsd_wrapper_get(init);
- if (tsd_get_allocates() && !init && wrapper == NULL) {
- return NULL;
- }
- return &wrapper->val;
-}
-
-JEMALLOC_ALWAYS_INLINE void
-tsd_set(tsd_t *val) {
- tsd_wrapper_t *wrapper;
-
- assert(tsd_booted);
- wrapper = tsd_wrapper_get(true);
- if (likely(&wrapper->val != val)) {
- wrapper->val = *(val);
- }
- wrapper->initialized = true;
-}
->>>>>>> main
diff --git a/contrib/jemalloc/include/jemalloc/jemalloc_defs.h.in b/contrib/jemalloc/include/jemalloc/jemalloc_defs.h.in
index 19c990dcdbdf..cbe2fca6ba53 100644
--- a/contrib/jemalloc/include/jemalloc/jemalloc_defs.h.in
+++ b/contrib/jemalloc/include/jemalloc/jemalloc_defs.h.in
@@ -1,4 +1,3 @@
-<<<<<<< HEAD
/* Defined if __attribute__((...)) syntax is supported. */
#undef JEMALLOC_HAVE_ATTR
@@ -53,54 +52,3 @@
/* sizeof(void *) == 2^LG_SIZEOF_PTR. */
#undef LG_SIZEOF_PTR
-||||||| dec341af7695
-=======
-/* Defined if __attribute__((...)) syntax is supported. */
-#undef JEMALLOC_HAVE_ATTR
-
-/* Defined if alloc_size attribute is supported. */
-#undef JEMALLOC_HAVE_ATTR_ALLOC_SIZE
-
-/* Defined if format_arg(...) attribute is supported. */
-#undef JEMALLOC_HAVE_ATTR_FORMAT_ARG
-
-/* Defined if format(gnu_printf, ...) attribute is supported. */
-#undef JEMALLOC_HAVE_ATTR_FORMAT_GNU_PRINTF
-
-/* Defined if format(printf, ...) attribute is supported. */
-#undef JEMALLOC_HAVE_ATTR_FORMAT_PRINTF
-
-/*
- * Define overrides for non-standard allocator-related functions if they are
- * present on the system.
- */
-#undef JEMALLOC_OVERRIDE_MEMALIGN
-#undef JEMALLOC_OVERRIDE_VALLOC
-
-/*
- * At least Linux omits the "const" in:
- *
- * size_t malloc_usable_size(const void *ptr);
- *
- * Match the operating system's prototype.
- */
-#undef JEMALLOC_USABLE_SIZE_CONST
-
-/*
- * If defined, specify throw() for the public function prototypes when compiling
- * with C++. The only justification for this is to match the prototypes that
- * glibc defines.
- */
-#undef JEMALLOC_USE_CXX_THROW
-
-#ifdef _MSC_VER
-# ifdef _WIN64
-# define LG_SIZEOF_PTR_WIN 3
-# else
-# define LG_SIZEOF_PTR_WIN 2
-# endif
-#endif
-
-/* sizeof(void *) == 2^LG_SIZEOF_PTR. */
-#undef LG_SIZEOF_PTR
->>>>>>> main
diff --git a/contrib/jemalloc/include/jemalloc/jemalloc_macros.h.in b/contrib/jemalloc/include/jemalloc/jemalloc_macros.h.in
index dc57f521f580..ebb3137e6f7e 100644
--- a/contrib/jemalloc/include/jemalloc/jemalloc_macros.h.in
+++ b/contrib/jemalloc/include/jemalloc/jemalloc_macros.h.in
@@ -1,4 +1,3 @@
-<<<<<<< HEAD
#include <stdlib.h>
#include <stdbool.h>
#include <stdint.h>
@@ -148,135 +147,3 @@
#else
# define JEMALLOC_SYS_NOTHROW JEMALLOC_NOTHROW
#endif
-||||||| dec341af7695
-=======
-#include <stdlib.h>
-#include <stdbool.h>
-#include <stdint.h>
-#include <limits.h>
-#include <strings.h>
-
-#define JEMALLOC_VERSION "@jemalloc_version@"
-#define JEMALLOC_VERSION_MAJOR @jemalloc_version_major@
-#define JEMALLOC_VERSION_MINOR @jemalloc_version_minor@
-#define JEMALLOC_VERSION_BUGFIX @jemalloc_version_bugfix@
-#define JEMALLOC_VERSION_NREV @jemalloc_version_nrev@
-#define JEMALLOC_VERSION_GID "@jemalloc_version_gid@"
-#define JEMALLOC_VERSION_GID_IDENT @jemalloc_version_gid@
-
-#define MALLOCX_LG_ALIGN(la) ((int)(la))
-#if LG_SIZEOF_PTR == 2
-# define MALLOCX_ALIGN(a) ((int)(ffs((int)(a))-1))
-#else
-# define MALLOCX_ALIGN(a) \
- ((int)(((size_t)(a) < (size_t)INT_MAX) ? ffs((int)(a))-1 : \
- ffs((int)(((size_t)(a))>>32))+31))
-#endif
-#define MALLOCX_ZERO ((int)0x40)
-/*
- * Bias tcache index bits so that 0 encodes "automatic tcache management", and 1
- * encodes MALLOCX_TCACHE_NONE.
- */
-#define MALLOCX_TCACHE(tc) ((int)(((tc)+2) << 8))
-#define MALLOCX_TCACHE_NONE MALLOCX_TCACHE(-1)
-/*
- * Bias arena index bits so that 0 encodes "use an automatically chosen arena".
- */
-#define MALLOCX_ARENA(a) ((((int)(a))+1) << 20)
-
-/*
- * Use as arena index in "arena.<i>.{purge,decay,dss}" and
- * "stats.arenas.<i>.*" mallctl interfaces to select all arenas. This
- * definition is intentionally specified in raw decimal format to support
- * cpp-based string concatenation, e.g.
- *
- * #define STRINGIFY_HELPER(x) #x
- * #define STRINGIFY(x) STRINGIFY_HELPER(x)
- *
- * mallctl("arena." STRINGIFY(MALLCTL_ARENAS_ALL) ".purge", NULL, NULL, NULL,
- * 0);
- */
-#define MALLCTL_ARENAS_ALL 4096
-/*
- * Use as arena index in "stats.arenas.<i>.*" mallctl interfaces to select
- * destroyed arenas.
- */
-#define MALLCTL_ARENAS_DESTROYED 4097
-
-#if defined(__cplusplus) && defined(JEMALLOC_USE_CXX_THROW)
-# define JEMALLOC_CXX_THROW throw()
-#else
-# define JEMALLOC_CXX_THROW
-#endif
-
-#if defined(_MSC_VER)
-# define JEMALLOC_ATTR(s)
-# define JEMALLOC_ALIGNED(s) __declspec(align(s))
-# define JEMALLOC_ALLOC_SIZE(s)
-# define JEMALLOC_ALLOC_SIZE2(s1, s2)
-# ifndef JEMALLOC_EXPORT
-# ifdef DLLEXPORT
-# define JEMALLOC_EXPORT __declspec(dllexport)
-# else
-# define JEMALLOC_EXPORT __declspec(dllimport)
-# endif
-# endif
-# define JEMALLOC_FORMAT_ARG(i)
-# define JEMALLOC_FORMAT_PRINTF(s, i)
-# define JEMALLOC_NOINLINE __declspec(noinline)
-# ifdef __cplusplus
-# define JEMALLOC_NOTHROW __declspec(nothrow)
-# else
-# define JEMALLOC_NOTHROW
-# endif
-# define JEMALLOC_SECTION(s) __declspec(allocate(s))
-# define JEMALLOC_RESTRICT_RETURN __declspec(restrict)
-# if _MSC_VER >= 1900 && !defined(__EDG__)
-# define JEMALLOC_ALLOCATOR __declspec(allocator)
-# else
-# define JEMALLOC_ALLOCATOR
-# endif
-#elif defined(JEMALLOC_HAVE_ATTR)
-# define JEMALLOC_ATTR(s) __attribute__((s))
-# define JEMALLOC_ALIGNED(s) JEMALLOC_ATTR(aligned(s))
-# ifdef JEMALLOC_HAVE_ATTR_ALLOC_SIZE
-# define JEMALLOC_ALLOC_SIZE(s) JEMALLOC_ATTR(alloc_size(s))
-# define JEMALLOC_ALLOC_SIZE2(s1, s2) JEMALLOC_ATTR(alloc_size(s1, s2))
-# else
-# define JEMALLOC_ALLOC_SIZE(s)
-# define JEMALLOC_ALLOC_SIZE2(s1, s2)
-# endif
-# ifndef JEMALLOC_EXPORT
-# define JEMALLOC_EXPORT JEMALLOC_ATTR(visibility("default"))
-# endif
-# ifdef JEMALLOC_HAVE_ATTR_FORMAT_ARG
-# define JEMALLOC_FORMAT_ARG(i) JEMALLOC_ATTR(__format_arg__(3))
-# else
-# define JEMALLOC_FORMAT_ARG(i)
-# endif
-# ifdef JEMALLOC_HAVE_ATTR_FORMAT_GNU_PRINTF
-# define JEMALLOC_FORMAT_PRINTF(s, i) JEMALLOC_ATTR(format(gnu_printf, s, i))
-# elif defined(JEMALLOC_HAVE_ATTR_FORMAT_PRINTF)
-# define JEMALLOC_FORMAT_PRINTF(s, i) JEMALLOC_ATTR(format(printf, s, i))
-# else
-# define JEMALLOC_FORMAT_PRINTF(s, i)
-# endif
-# define JEMALLOC_NOINLINE JEMALLOC_ATTR(noinline)
-# define JEMALLOC_NOTHROW JEMALLOC_ATTR(nothrow)
-# define JEMALLOC_SECTION(s) JEMALLOC_ATTR(section(s))
-# define JEMALLOC_RESTRICT_RETURN
-# define JEMALLOC_ALLOCATOR
-#else
-# define JEMALLOC_ATTR(s)
-# define JEMALLOC_ALIGNED(s)
-# define JEMALLOC_ALLOC_SIZE(s)
-# define JEMALLOC_ALLOC_SIZE2(s1, s2)
-# define JEMALLOC_EXPORT
-# define JEMALLOC_FORMAT_PRINTF(s, i)
-# define JEMALLOC_NOINLINE
-# define JEMALLOC_NOTHROW
-# define JEMALLOC_SECTION(s)
-# define JEMALLOC_RESTRICT_RETURN
-# define JEMALLOC_ALLOCATOR
-#endif
->>>>>>> main
diff --git a/contrib/jemalloc/include/jemalloc/jemalloc_protos.h.in b/contrib/jemalloc/include/jemalloc/jemalloc_protos.h.in
index 116ef116b4e1..356221cc8d52 100644
--- a/contrib/jemalloc/include/jemalloc/jemalloc_protos.h.in
+++ b/contrib/jemalloc/include/jemalloc/jemalloc_protos.h.in
@@ -1,4 +1,3 @@
-<<<<<<< HEAD
/*
* The @je_@ prefix on the following public symbol declarations is an artifact
* of namespace management, and should be omitted in application code unless
@@ -70,72 +69,3 @@ JEMALLOC_EXPORT JEMALLOC_ALLOCATOR JEMALLOC_RESTRICT_RETURN
void JEMALLOC_SYS_NOTHROW *@je_@valloc(size_t size) JEMALLOC_CXX_THROW
JEMALLOC_ATTR(malloc);
#endif
-||||||| dec341af7695
-=======
-/*
- * The @je_@ prefix on the following public symbol declarations is an artifact
- * of namespace management, and should be omitted in application code unless
- * JEMALLOC_NO_DEMANGLE is defined (see jemalloc_mangle@install_suffix@.h).
- */
-extern JEMALLOC_EXPORT const char *@je_@malloc_conf;
-extern JEMALLOC_EXPORT void (*@je_@malloc_message)(void *cbopaque,
- const char *s);
-
-JEMALLOC_EXPORT JEMALLOC_ALLOCATOR JEMALLOC_RESTRICT_RETURN
- void JEMALLOC_NOTHROW *@je_@malloc(size_t size)
- JEMALLOC_CXX_THROW JEMALLOC_ATTR(malloc) JEMALLOC_ALLOC_SIZE(1);
-JEMALLOC_EXPORT JEMALLOC_ALLOCATOR JEMALLOC_RESTRICT_RETURN
- void JEMALLOC_NOTHROW *@je_@calloc(size_t num, size_t size)
- JEMALLOC_CXX_THROW JEMALLOC_ATTR(malloc) JEMALLOC_ALLOC_SIZE2(1, 2);
-JEMALLOC_EXPORT int JEMALLOC_NOTHROW @je_@posix_memalign(void **memptr,
- size_t alignment, size_t size) JEMALLOC_CXX_THROW JEMALLOC_ATTR(nonnull(1));
-JEMALLOC_EXPORT JEMALLOC_ALLOCATOR JEMALLOC_RESTRICT_RETURN
- void JEMALLOC_NOTHROW *@je_@aligned_alloc(size_t alignment,
- size_t size) JEMALLOC_CXX_THROW JEMALLOC_ATTR(malloc)
- JEMALLOC_ALLOC_SIZE(2);
-JEMALLOC_EXPORT JEMALLOC_ALLOCATOR JEMALLOC_RESTRICT_RETURN
- void JEMALLOC_NOTHROW *@je_@realloc(void *ptr, size_t size)
- JEMALLOC_CXX_THROW JEMALLOC_ALLOC_SIZE(2);
-JEMALLOC_EXPORT void JEMALLOC_NOTHROW @je_@free(void *ptr)
- JEMALLOC_CXX_THROW;
-
-JEMALLOC_EXPORT JEMALLOC_ALLOCATOR JEMALLOC_RESTRICT_RETURN
- void JEMALLOC_NOTHROW *@je_@mallocx(size_t size, int flags)
- JEMALLOC_ATTR(malloc) JEMALLOC_ALLOC_SIZE(1);
-JEMALLOC_EXPORT JEMALLOC_ALLOCATOR JEMALLOC_RESTRICT_RETURN
- void JEMALLOC_NOTHROW *@je_@rallocx(void *ptr, size_t size,
- int flags) JEMALLOC_ALLOC_SIZE(2);
-JEMALLOC_EXPORT size_t JEMALLOC_NOTHROW @je_@xallocx(void *ptr, size_t size,
- size_t extra, int flags);
-JEMALLOC_EXPORT size_t JEMALLOC_NOTHROW @je_@sallocx(const void *ptr,
- int flags) JEMALLOC_ATTR(pure);
-JEMALLOC_EXPORT void JEMALLOC_NOTHROW @je_@dallocx(void *ptr, int flags);
-JEMALLOC_EXPORT void JEMALLOC_NOTHROW @je_@sdallocx(void *ptr, size_t size,
- int flags);
-JEMALLOC_EXPORT size_t JEMALLOC_NOTHROW @je_@nallocx(size_t size, int flags)
- JEMALLOC_ATTR(pure);
-
-JEMALLOC_EXPORT int JEMALLOC_NOTHROW @je_@mallctl(const char *name,
- void *oldp, size_t *oldlenp, void *newp, size_t newlen);
-JEMALLOC_EXPORT int JEMALLOC_NOTHROW @je_@mallctlnametomib(const char *name,
- size_t *mibp, size_t *miblenp);
-JEMALLOC_EXPORT int JEMALLOC_NOTHROW @je_@mallctlbymib(const size_t *mib,
- size_t miblen, void *oldp, size_t *oldlenp, void *newp, size_t newlen);
-JEMALLOC_EXPORT void JEMALLOC_NOTHROW @je_@malloc_stats_print(
- void (*write_cb)(void *, const char *), void *@je_@cbopaque,
- const char *opts);
-JEMALLOC_EXPORT size_t JEMALLOC_NOTHROW @je_@malloc_usable_size(
- JEMALLOC_USABLE_SIZE_CONST void *ptr) JEMALLOC_CXX_THROW;
-
-#ifdef JEMALLOC_OVERRIDE_MEMALIGN
-JEMALLOC_EXPORT JEMALLOC_ALLOCATOR JEMALLOC_RESTRICT_RETURN
- void JEMALLOC_NOTHROW *@je_@memalign(size_t alignment, size_t size)
- JEMALLOC_CXX_THROW JEMALLOC_ATTR(malloc);
-#endif
-
-#ifdef JEMALLOC_OVERRIDE_VALLOC
-JEMALLOC_EXPORT JEMALLOC_ALLOCATOR JEMALLOC_RESTRICT_RETURN
- void JEMALLOC_NOTHROW *@je_@valloc(size_t size) JEMALLOC_CXX_THROW
- JEMALLOC_ATTR(malloc);
-#endif
->>>>>>> main
diff --git a/contrib/jemalloc/m4/ax_cxx_compile_stdcxx.m4 b/contrib/jemalloc/m4/ax_cxx_compile_stdcxx.m4
index 72784472d275..43087b2e6889 100644
--- a/contrib/jemalloc/m4/ax_cxx_compile_stdcxx.m4
+++ b/contrib/jemalloc/m4/ax_cxx_compile_stdcxx.m4
@@ -1,4 +1,3 @@
-<<<<<<< HEAD
# ===========================================================================
# https://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx.html
# ===========================================================================
@@ -950,568 +949,3 @@ namespace cxx17
#endif // __cplusplus < 201703L
]])
-||||||| dec341af7695
-=======
-# ===========================================================================
-# http://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx.html
-# ===========================================================================
-#
-# SYNOPSIS
-#
-# AX_CXX_COMPILE_STDCXX(VERSION, [ext|noext], [mandatory|optional])
-#
-# DESCRIPTION
-#
-# Check for baseline language coverage in the compiler for the specified
-# version of the C++ standard. If necessary, add switches to CXX and
-# CXXCPP to enable support. VERSION may be '11' (for the C++11 standard)
-# or '14' (for the C++14 standard).
-#
-# The second argument, if specified, indicates whether you insist on an
-# extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g.
-# -std=c++11). If neither is specified, you get whatever works, with
-# preference for an extended mode.
-#
-# The third argument, if specified 'mandatory' or if left unspecified,
-# indicates that baseline support for the specified C++ standard is
-# required and that the macro should error out if no mode with that
-# support is found. If specified 'optional', then configuration proceeds
-# regardless, after defining HAVE_CXX${VERSION} if and only if a
-# supporting mode is found.
-#
-# LICENSE
-#
-# Copyright (c) 2008 Benjamin Kosnik <bkoz@redhat.com>
-# Copyright (c) 2012 Zack Weinberg <zackw@panix.com>
-# Copyright (c) 2013 Roy Stogner <roystgnr@ices.utexas.edu>
-# Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov <sokolov@google.com>
-# Copyright (c) 2015 Paul Norman <penorman@mac.com>
-# Copyright (c) 2015 Moritz Klammler <moritz@klammler.eu>
-#
-# Copying and distribution of this file, with or without modification, are
-# permitted in any medium without royalty provided the copyright notice
-# and this notice are preserved. This file is offered as-is, without any
-# warranty.
-
-#serial 4
-
-dnl This macro is based on the code from the AX_CXX_COMPILE_STDCXX_11 macro
-dnl (serial version number 13).
-
-AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl
- m4_if([$1], [11], [],
- [$1], [14], [],
- [$1], [17], [m4_fatal([support for C++17 not yet implemented in AX_CXX_COMPILE_STDCXX])],
- [m4_fatal([invalid first argument `$1' to AX_CXX_COMPILE_STDCXX])])dnl
- m4_if([$2], [], [],
- [$2], [ext], [],
- [$2], [noext], [],
- [m4_fatal([invalid second argument `$2' to AX_CXX_COMPILE_STDCXX])])dnl
- m4_if([$3], [], [ax_cxx_compile_cxx$1_required=true],
- [$3], [mandatory], [ax_cxx_compile_cxx$1_required=true],
- [$3], [optional], [ax_cxx_compile_cxx$1_required=false],
- [m4_fatal([invalid third argument `$3' to AX_CXX_COMPILE_STDCXX])])
- AC_LANG_PUSH([C++])dnl
- ac_success=no
- AC_CACHE_CHECK(whether $CXX supports C++$1 features by default,
- ax_cv_cxx_compile_cxx$1,
- [AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
- [ax_cv_cxx_compile_cxx$1=yes],
- [ax_cv_cxx_compile_cxx$1=no])])
- if test x$ax_cv_cxx_compile_cxx$1 = xyes; then
- ac_success=yes
- fi
-
- m4_if([$2], [noext], [], [dnl
- if test x$ac_success = xno; then
- for switch in -std=gnu++$1 -std=gnu++0x; do
- cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch])
- AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch,
- $cachevar,
- [ac_save_CXX="$CXX"
- CXX="$CXX $switch"
- AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
- [eval $cachevar=yes],
- [eval $cachevar=no])
- CXX="$ac_save_CXX"])
- if eval test x\$$cachevar = xyes; then
- CXX="$CXX $switch"
- if test -n "$CXXCPP" ; then
- CXXCPP="$CXXCPP $switch"
- fi
- ac_success=yes
- break
- fi
- done
- fi])
-
- m4_if([$2], [ext], [], [dnl
- if test x$ac_success = xno; then
- dnl HP's aCC needs +std=c++11 according to:
- dnl http://h21007.www2.hp.com/portal/download/files/unprot/aCxx/PDF_Release_Notes/769149-001.pdf
- dnl Cray's crayCC needs "-h std=c++11"
- for switch in -std=c++$1 -std=c++0x +std=c++$1 "-h std=c++$1"; do
- cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch])
- AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch,
- $cachevar,
- [ac_save_CXX="$CXX"
- CXX="$CXX $switch"
- AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
- [eval $cachevar=yes],
- [eval $cachevar=no])
- CXX="$ac_save_CXX"])
- if eval test x\$$cachevar = xyes; then
- CXX="$CXX $switch"
- if test -n "$CXXCPP" ; then
- CXXCPP="$CXXCPP $switch"
- fi
- ac_success=yes
- break
- fi
- done
- fi])
- AC_LANG_POP([C++])
- if test x$ax_cxx_compile_cxx$1_required = xtrue; then
- if test x$ac_success = xno; then
- AC_MSG_ERROR([*** A compiler with support for C++$1 language features is required.])
- fi
- fi
- if test x$ac_success = xno; then
- HAVE_CXX$1=0
- AC_MSG_NOTICE([No compiler with C++$1 support was found])
- else
- HAVE_CXX$1=1
- AC_DEFINE(HAVE_CXX$1,1,
- [define if the compiler supports basic C++$1 syntax])
- fi
- AC_SUBST(HAVE_CXX$1)
-])
-
-
-dnl Test body for checking C++11 support
-
-m4_define([_AX_CXX_COMPILE_STDCXX_testbody_11],
- _AX_CXX_COMPILE_STDCXX_testbody_new_in_11
-)
-
-
-dnl Test body for checking C++14 support
-
-m4_define([_AX_CXX_COMPILE_STDCXX_testbody_14],
- _AX_CXX_COMPILE_STDCXX_testbody_new_in_11
- _AX_CXX_COMPILE_STDCXX_testbody_new_in_14
-)
-
-
-dnl Tests for new features in C++11
-
-m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_11], [[
-
-// If the compiler admits that it is not ready for C++11, why torture it?
-// Hopefully, this will speed up the test.
-
-#ifndef __cplusplus
-
-#error "This is not a C++ compiler"
-
-#elif __cplusplus < 201103L
-
-#error "This is not a C++11 compiler"
-
-#else
-
-namespace cxx11
-{
-
- namespace test_static_assert
- {
-
- template <typename T>
- struct check
- {
- static_assert(sizeof(int) <= sizeof(T), "not big enough");
- };
-
- }
-
- namespace test_final_override
- {
-
- struct Base
- {
- virtual void f() {}
- };
-
- struct Derived : public Base
- {
- virtual void f() override {}
- };
-
- }
-
- namespace test_double_right_angle_brackets
- {
-
- template < typename T >
- struct check {};
-
- typedef check<void> single_type;
- typedef check<check<void>> double_type;
- typedef check<check<check<void>>> triple_type;
- typedef check<check<check<check<void>>>> quadruple_type;
-
- }
-
- namespace test_decltype
- {
-
- int
- f()
- {
- int a = 1;
- decltype(a) b = 2;
- return a + b;
- }
-
- }
-
- namespace test_type_deduction
- {
-
- template < typename T1, typename T2 >
- struct is_same
- {
- static const bool value = false;
- };
-
- template < typename T >
- struct is_same<T, T>
- {
- static const bool value = true;
- };
-
- template < typename T1, typename T2 >
- auto
- add(T1 a1, T2 a2) -> decltype(a1 + a2)
- {
- return a1 + a2;
- }
-
- int
- test(const int c, volatile int v)
- {
- static_assert(is_same<int, decltype(0)>::value == true, "");
- static_assert(is_same<int, decltype(c)>::value == false, "");
- static_assert(is_same<int, decltype(v)>::value == false, "");
- auto ac = c;
- auto av = v;
- auto sumi = ac + av + 'x';
- auto sumf = ac + av + 1.0;
- static_assert(is_same<int, decltype(ac)>::value == true, "");
- static_assert(is_same<int, decltype(av)>::value == true, "");
- static_assert(is_same<int, decltype(sumi)>::value == true, "");
- static_assert(is_same<int, decltype(sumf)>::value == false, "");
- static_assert(is_same<int, decltype(add(c, v))>::value == true, "");
- return (sumf > 0.0) ? sumi : add(c, v);
- }
-
- }
-
- namespace test_noexcept
- {
-
- int f() { return 0; }
- int g() noexcept { return 0; }
-
- static_assert(noexcept(f()) == false, "");
- static_assert(noexcept(g()) == true, "");
-
- }
-
- namespace test_constexpr
- {
-
- template < typename CharT >
- unsigned long constexpr
- strlen_c_r(const CharT *const s, const unsigned long acc) noexcept
- {
- return *s ? strlen_c_r(s + 1, acc + 1) : acc;
- }
-
- template < typename CharT >
- unsigned long constexpr
- strlen_c(const CharT *const s) noexcept
- {
- return strlen_c_r(s, 0UL);
- }
-
- static_assert(strlen_c("") == 0UL, "");
- static_assert(strlen_c("1") == 1UL, "");
- static_assert(strlen_c("example") == 7UL, "");
- static_assert(strlen_c("another\0example") == 7UL, "");
-
- }
-
- namespace test_rvalue_references
- {
-
- template < int N >
- struct answer
- {
- static constexpr int value = N;
- };
-
- answer<1> f(int&) { return answer<1>(); }
- answer<2> f(const int&) { return answer<2>(); }
- answer<3> f(int&&) { return answer<3>(); }
-
- void
- test()
- {
- int i = 0;
- const int c = 0;
- static_assert(decltype(f(i))::value == 1, "");
- static_assert(decltype(f(c))::value == 2, "");
- static_assert(decltype(f(0))::value == 3, "");
- }
-
- }
-
- namespace test_uniform_initialization
- {
-
- struct test
- {
- static const int zero {};
- static const int one {1};
- };
-
- static_assert(test::zero == 0, "");
- static_assert(test::one == 1, "");
-
- }
-
- namespace test_lambdas
- {
-
- void
- test1()
- {
- auto lambda1 = [](){};
- auto lambda2 = lambda1;
- lambda1();
- lambda2();
- }
-
- int
- test2()
- {
- auto a = [](int i, int j){ return i + j; }(1, 2);
- auto b = []() -> int { return '0'; }();
- auto c = [=](){ return a + b; }();
- auto d = [&](){ return c; }();
- auto e = [a, &b](int x) mutable {
- const auto identity = [](int y){ return y; };
- for (auto i = 0; i < a; ++i)
- a += b--;
- return x + identity(a + b);
- }(0);
- return a + b + c + d + e;
- }
-
- int
- test3()
- {
- const auto nullary = [](){ return 0; };
- const auto unary = [](int x){ return x; };
- using nullary_t = decltype(nullary);
- using unary_t = decltype(unary);
- const auto higher1st = [](nullary_t f){ return f(); };
- const auto higher2nd = [unary](nullary_t f1){
- return [unary, f1](unary_t f2){ return f2(unary(f1())); };
- };
- return higher1st(nullary) + higher2nd(nullary)(unary);
- }
-
- }
-
- namespace test_variadic_templates
- {
-
- template <int...>
- struct sum;
-
- template <int N0, int... N1toN>
- struct sum<N0, N1toN...>
- {
- static constexpr auto value = N0 + sum<N1toN...>::value;
- };
-
- template <>
- struct sum<>
- {
- static constexpr auto value = 0;
- };
-
- static_assert(sum<>::value == 0, "");
- static_assert(sum<1>::value == 1, "");
- static_assert(sum<23>::value == 23, "");
- static_assert(sum<1, 2>::value == 3, "");
- static_assert(sum<5, 5, 11>::value == 21, "");
- static_assert(sum<2, 3, 5, 7, 11, 13>::value == 41, "");
-
- }
-
- // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae
- // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function
- // because of this.
- namespace test_template_alias_sfinae
- {
-
- struct foo {};
-
- template<typename T>
- using member = typename T::member_type;
-
- template<typename T>
- void func(...) {}
-
- template<typename T>
- void func(member<T>*) {}
-
- void test();
-
- void test() { func<foo>(0); }
-
- }
-
-} // namespace cxx11
-
-#endif // __cplusplus >= 201103L
-
-]])
-
-
-dnl Tests for new features in C++14
-
-m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_14], [[
-
-// If the compiler admits that it is not ready for C++14, why torture it?
-// Hopefully, this will speed up the test.
-
-#ifndef __cplusplus
-
-#error "This is not a C++ compiler"
-
-#elif __cplusplus < 201402L
-
-#error "This is not a C++14 compiler"
-
-#else
-
-namespace cxx14
-{
-
- namespace test_polymorphic_lambdas
- {
-
- int
- test()
- {
- const auto lambda = [](auto&&... args){
- const auto istiny = [](auto x){
- return (sizeof(x) == 1UL) ? 1 : 0;
- };
- const int aretiny[] = { istiny(args)... };
- return aretiny[0];
- };
- return lambda(1, 1L, 1.0f, '1');
- }
-
- }
-
- namespace test_binary_literals
- {
-
- constexpr auto ivii = 0b0000000000101010;
- static_assert(ivii == 42, "wrong value");
-
- }
-
- namespace test_generalized_constexpr
- {
-
- template < typename CharT >
- constexpr unsigned long
- strlen_c(const CharT *const s) noexcept
- {
- auto length = 0UL;
- for (auto p = s; *p; ++p)
- ++length;
- return length;
- }
-
- static_assert(strlen_c("") == 0UL, "");
- static_assert(strlen_c("x") == 1UL, "");
- static_assert(strlen_c("test") == 4UL, "");
- static_assert(strlen_c("another\0test") == 7UL, "");
-
- }
-
- namespace test_lambda_init_capture
- {
-
- int
- test()
- {
- auto x = 0;
- const auto lambda1 = [a = x](int b){ return a + b; };
- const auto lambda2 = [a = lambda1(x)](){ return a; };
- return lambda2();
- }
-
- }
-
- namespace test_digit_seperators
- {
-
- constexpr auto ten_million = 100'000'000;
- static_assert(ten_million == 100000000, "");
-
- }
-
- namespace test_return_type_deduction
- {
-
- auto f(int& x) { return x; }
- decltype(auto) g(int& x) { return x; }
-
- template < typename T1, typename T2 >
- struct is_same
- {
- static constexpr auto value = false;
- };
-
- template < typename T >
- struct is_same<T, T>
- {
- static constexpr auto value = true;
- };
-
- int
- test()
- {
- auto x = 0;
- static_assert(is_same<int, decltype(f(x))>::value, "");
- static_assert(is_same<int&, decltype(g(x))>::value, "");
- return x;
- }
-
- }
-
-} // namespace cxx14
-
-#endif // __cplusplus >= 201402L
-
-]])
->>>>>>> main
diff --git a/contrib/jemalloc/scripts/gen_run_tests.py b/contrib/jemalloc/scripts/gen_run_tests.py
index 698d3bce4bbf..7c3075f9f6a6 100755
--- a/contrib/jemalloc/scripts/gen_run_tests.py
+++ b/contrib/jemalloc/scripts/gen_run_tests.py
@@ -1,4 +1,3 @@
-<<<<<<< HEAD
#!/usr/bin/env python3
import sys
@@ -129,132 +128,3 @@ chmod 755 run_test_%(ind)d.sh""" % {'ind': ind, 'config_line': config_line,
print('for i in `seq 0 %(last_ind)d` ; do echo run_test_${i}.sh ; done | xargs'
' -P %(nparallel)d -n 1 sh' % {'last_ind': ind-1, 'nparallel': nparallel})
-||||||| dec341af7695
-=======
-#!/usr/bin/env python
-
-import sys
-from itertools import combinations
-from os import uname
-from multiprocessing import cpu_count
-from subprocess import call
-
-# Later, we want to test extended vaddr support. Apparently, the "real" way of
-# checking this is flaky on OS X.
-bits_64 = sys.maxsize > 2**32
-
-nparallel = cpu_count() * 2
-
-uname = uname()[0]
-
-if "BSD" in uname:
- make_cmd = 'gmake'
-else:
- make_cmd = 'make'
-
-def powerset(items):
- result = []
- for i in xrange(len(items) + 1):
- result += combinations(items, i)
- return result
-
-possible_compilers = []
-for cc, cxx in (['gcc', 'g++'], ['clang', 'clang++']):
- try:
- cmd_ret = call([cc, "-v"])
- if cmd_ret == 0:
- possible_compilers.append((cc, cxx))
- except:
- pass
-possible_compiler_opts = [
- '-m32',
-]
-possible_config_opts = [
- '--enable-debug',
- '--enable-prof',
- '--disable-stats',
- '--enable-opt-safety-checks',
-]
-if bits_64:
- possible_config_opts.append('--with-lg-vaddr=56')
-
-possible_malloc_conf_opts = [
- 'tcache:false',
- 'dss:primary',
- 'percpu_arena:percpu',
- 'background_thread:true',
-]
-
-print 'set -e'
-print 'if [ -f Makefile ] ; then %(make_cmd)s relclean ; fi' % {'make_cmd': make_cmd}
-print 'autoconf'
-print 'rm -rf run_tests.out'
-print 'mkdir run_tests.out'
-print 'cd run_tests.out'
-
-ind = 0
-for cc, cxx in possible_compilers:
- for compiler_opts in powerset(possible_compiler_opts):
- for config_opts in powerset(possible_config_opts):
- for malloc_conf_opts in powerset(possible_malloc_conf_opts):
- if cc is 'clang' \
- and '-m32' in possible_compiler_opts \
- and '--enable-prof' in config_opts:
- continue
- config_line = (
- 'EXTRA_CFLAGS=-Werror EXTRA_CXXFLAGS=-Werror '
- + 'CC="{} {}" '.format(cc, " ".join(compiler_opts))
- + 'CXX="{} {}" '.format(cxx, " ".join(compiler_opts))
- + '../../configure '
- + " ".join(config_opts) + (' --with-malloc-conf=' +
- ",".join(malloc_conf_opts) if len(malloc_conf_opts) > 0
- else '')
- )
-
- # We don't want to test large vaddr spaces in 32-bit mode.
- if ('-m32' in compiler_opts and '--with-lg-vaddr=56' in
- config_opts):
- continue
-
- # Per CPU arenas are only supported on Linux.
- linux_supported = ('percpu_arena:percpu' in malloc_conf_opts \
- or 'background_thread:true' in malloc_conf_opts)
- # Heap profiling and dss are not supported on OS X.
- darwin_unsupported = ('--enable-prof' in config_opts or \
- 'dss:primary' in malloc_conf_opts)
- if (uname == 'Linux' and linux_supported) \
- or (not linux_supported and (uname != 'Darwin' or \
- not darwin_unsupported)):
- print """cat <<EOF > run_test_%(ind)d.sh
-#!/bin/sh
-
-set -e
-
-abort() {
- echo "==> Error" >> run_test.log
- echo "Error; see run_tests.out/run_test_%(ind)d.out/run_test.log"
- exit 255 # Special exit code tells xargs to terminate.
-}
-
-# Environment variables are not supported.
-run_cmd() {
- echo "==> \$@" >> run_test.log
- \$@ >> run_test.log 2>&1 || abort
-}
-
-echo "=> run_test_%(ind)d: %(config_line)s"
-mkdir run_test_%(ind)d.out
-cd run_test_%(ind)d.out
-
-echo "==> %(config_line)s" >> run_test.log
-%(config_line)s >> run_test.log 2>&1 || abort
-
-run_cmd %(make_cmd)s all tests
-run_cmd %(make_cmd)s check
-run_cmd %(make_cmd)s distclean
-EOF
-chmod 755 run_test_%(ind)d.sh""" % {'ind': ind, 'config_line': config_line, 'make_cmd': make_cmd}
- ind += 1
-
-print 'for i in `seq 0 %(last_ind)d` ; do echo run_test_${i}.sh ; done | xargs -P %(nparallel)d -n 1 sh' % {'last_ind': ind-1, 'nparallel': nparallel}
->>>>>>> main
diff --git a/contrib/jemalloc/scripts/gen_travis.py b/contrib/jemalloc/scripts/gen_travis.py
index c306744e6a65..4366a066eeab 100755
--- a/contrib/jemalloc/scripts/gen_travis.py
+++ b/contrib/jemalloc/scripts/gen_travis.py
@@ -1,4 +1,3 @@
-<<<<<<< HEAD
#!/usr/bin/env python3
from itertools import combinations, chain
@@ -326,155 +325,3 @@ def main():
if __name__ == '__main__':
main()
-||||||| dec341af7695
-=======
-#!/usr/bin/env python
-
-from itertools import combinations
-
-travis_template = """\
-language: generic
-dist: precise
-
-matrix:
- include:
-%s
-
-before_script:
- - autoconf
- - scripts/gen_travis.py > travis_script && diff .travis.yml travis_script
- - ./configure ${COMPILER_FLAGS:+ \
- CC="$CC $COMPILER_FLAGS" \
- CXX="$CXX $COMPILER_FLAGS" } \
- $CONFIGURE_FLAGS
- - make -j3
- - make -j3 tests
-
-script:
- - make check
-"""
-
-# The 'default' configuration is gcc, on linux, with no compiler or configure
-# flags. We also test with clang, -m32, --enable-debug, --enable-prof,
-# --disable-stats, and --with-malloc-conf=tcache:false. To avoid abusing
-# travis though, we don't test all 2**7 = 128 possible combinations of these;
-# instead, we only test combinations of up to 2 'unusual' settings, under the
-# hope that bugs involving interactions of such settings are rare.
-# Things at once, for C(7, 0) + C(7, 1) + C(7, 2) = 29
-MAX_UNUSUAL_OPTIONS = 2
-
-os_default = 'linux'
-os_unusual = 'osx'
-
-compilers_default = 'CC=gcc CXX=g++'
-compilers_unusual = 'CC=clang CXX=clang++'
-
-compiler_flag_unusuals = ['-m32']
-
-configure_flag_unusuals = [
- '--enable-debug',
- '--enable-prof',
- '--disable-stats',
- '--disable-libdl',
- '--enable-opt-safety-checks',
-]
-
-malloc_conf_unusuals = [
- 'tcache:false',
- 'dss:primary',
- 'percpu_arena:percpu',
- 'background_thread:true',
-]
-
-all_unusuals = (
- [os_unusual] + [compilers_unusual] + compiler_flag_unusuals
- + configure_flag_unusuals + malloc_conf_unusuals
-)
-
-unusual_combinations_to_test = []
-for i in xrange(MAX_UNUSUAL_OPTIONS + 1):
- unusual_combinations_to_test += combinations(all_unusuals, i)
-
-gcc_multilib_set = False
-# Formats a job from a combination of flags
-def format_job(combination):
- global gcc_multilib_set
-
- os = os_unusual if os_unusual in combination else os_default
- compilers = compilers_unusual if compilers_unusual in combination else compilers_default
-
- compiler_flags = [x for x in combination if x in compiler_flag_unusuals]
- configure_flags = [x for x in combination if x in configure_flag_unusuals]
- malloc_conf = [x for x in combination if x in malloc_conf_unusuals]
-
- # Filter out unsupported configurations on OS X.
- if os == 'osx' and ('dss:primary' in malloc_conf or \
- 'percpu_arena:percpu' in malloc_conf or 'background_thread:true' \
- in malloc_conf):
- return ""
- if len(malloc_conf) > 0:
- configure_flags.append('--with-malloc-conf=' + ",".join(malloc_conf))
-
- # Filter out an unsupported configuration - heap profiling on OS X.
- if os == 'osx' and '--enable-prof' in configure_flags:
- return ""
-
- # We get some spurious errors when -Warray-bounds is enabled.
- env_string = ('{} COMPILER_FLAGS="{}" CONFIGURE_FLAGS="{}" '
- 'EXTRA_CFLAGS="-Werror -Wno-array-bounds"').format(
- compilers, " ".join(compiler_flags), " ".join(configure_flags))
-
- job = ""
- job += ' - os: %s\n' % os
- job += ' env: %s\n' % env_string
- if '-m32' in combination and os == 'linux':
- job += ' addons:'
- if gcc_multilib_set:
- job += ' *gcc_multilib\n'
- else:
- job += ' &gcc_multilib\n'
- job += ' apt:\n'
- job += ' packages:\n'
- job += ' - gcc-multilib\n'
- gcc_multilib_set = True
- return job
-
-include_rows = ""
-for combination in unusual_combinations_to_test:
- include_rows += format_job(combination)
-
-# Development build
-include_rows += '''\
- # Development build
- - os: linux
- env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug --disable-cache-oblivious --enable-stats --enable-log --enable-prof" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
-'''
-
-# Enable-expermental-smallocx
-include_rows += '''\
- # --enable-expermental-smallocx:
- - os: linux
- env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="--enable-debug --enable-experimental-smallocx --enable-stats --enable-prof" EXTRA_CFLAGS="-Werror -Wno-array-bounds"
-'''
-
-# Valgrind build bots
-include_rows += '''
- # Valgrind
- - os: linux
- env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="" EXTRA_CFLAGS="-Werror -Wno-array-bounds" JEMALLOC_TEST_PREFIX="valgrind"
- addons:
- apt:
- packages:
- - valgrind
-'''
-
-# To enable valgrind on macosx add:
-#
-# - os: osx
-# env: CC=gcc CXX=g++ COMPILER_FLAGS="" CONFIGURE_FLAGS="" EXTRA_CFLAGS="-Werror -Wno-array-bounds" JEMALLOC_TEST_PREFIX="valgrind"
-# install: brew install valgrind
-#
-# It currently fails due to: https://github.com/jemalloc/jemalloc/issues/1274
-
-print travis_template % include_rows
->>>>>>> main
diff --git a/contrib/jemalloc/src/jemalloc_cpp.cpp b/contrib/jemalloc/src/jemalloc_cpp.cpp
index d606686e0c97..451655f1b5a5 100644
--- a/contrib/jemalloc/src/jemalloc_cpp.cpp
+++ b/contrib/jemalloc/src/jemalloc_cpp.cpp
@@ -1,4 +1,3 @@
-<<<<<<< HEAD
#include <mutex>
#include <new>
@@ -253,147 +252,3 @@ operator delete[](void* ptr, std::size_t size, std::align_val_t alignment) noexc
}
#endif // __cpp_aligned_new
-||||||| dec341af7695
-=======
-#include <mutex>
-#include <new>
-
-#define JEMALLOC_CPP_CPP_
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include "jemalloc/internal/jemalloc_preamble.h"
-#include "jemalloc/internal/jemalloc_internal_includes.h"
-
-#ifdef __cplusplus
-}
-#endif
-
-// All operators in this file are exported.
-
-// Possibly alias hidden versions of malloc and sdallocx to avoid an extra plt
-// thunk?
-//
-// extern __typeof (sdallocx) sdallocx_int
-// __attribute ((alias ("sdallocx"),
-// visibility ("hidden")));
-//
-// ... but it needs to work with jemalloc namespaces.
-
-void *operator new(std::size_t size);
-void *operator new[](std::size_t size);
-void *operator new(std::size_t size, const std::nothrow_t &) noexcept;
-void *operator new[](std::size_t size, const std::nothrow_t &) noexcept;
-void operator delete(void *ptr) noexcept;
-void operator delete[](void *ptr) noexcept;
-void operator delete(void *ptr, const std::nothrow_t &) noexcept;
-void operator delete[](void *ptr, const std::nothrow_t &) noexcept;
-
-#if __cpp_sized_deallocation >= 201309
-/* C++14's sized-delete operators. */
-void operator delete(void *ptr, std::size_t size) noexcept;
-void operator delete[](void *ptr, std::size_t size) noexcept;
-#endif
-
-JEMALLOC_NOINLINE
-static void *
-handleOOM(std::size_t size, bool nothrow) {
- void *ptr = nullptr;
-
- while (ptr == nullptr) {
- std::new_handler handler;
- // GCC-4.8 and clang 4.0 do not have std::get_new_handler.
- {
- static std::mutex mtx;
- std::lock_guard<std::mutex> lock(mtx);
-
- handler = std::set_new_handler(nullptr);
- std::set_new_handler(handler);
- }
- if (handler == nullptr)
- break;
-
- try {
- handler();
- } catch (const std::bad_alloc &) {
- break;
- }
-
- ptr = je_malloc(size);
- }
-
- if (ptr == nullptr && !nothrow)
- std::__throw_bad_alloc();
- return ptr;
-}
-
-template <bool IsNoExcept>
-JEMALLOC_ALWAYS_INLINE
-void *
-newImpl(std::size_t size) noexcept(IsNoExcept) {
- void *ptr = je_malloc(size);
- if (likely(ptr != nullptr))
- return ptr;
-
- return handleOOM(size, IsNoExcept);
-}
-
-void *
-operator new(std::size_t size) {
- return newImpl<false>(size);
-}
-
-void *
-operator new[](std::size_t size) {
- return newImpl<false>(size);
-}
-
-void *
-operator new(std::size_t size, const std::nothrow_t &) noexcept {
- return newImpl<true>(size);
-}
-
-void *
-operator new[](std::size_t size, const std::nothrow_t &) noexcept {
- return newImpl<true>(size);
-}
-
-void
-operator delete(void *ptr) noexcept {
- je_free(ptr);
-}
-
-void
-operator delete[](void *ptr) noexcept {
- je_free(ptr);
-}
-
-void
-operator delete(void *ptr, const std::nothrow_t &) noexcept {
- je_free(ptr);
-}
-
-void operator delete[](void *ptr, const std::nothrow_t &) noexcept {
- je_free(ptr);
-}
-
-#if __cpp_sized_deallocation >= 201309
-
-void
-operator delete(void *ptr, std::size_t size) noexcept {
- if (unlikely(ptr == nullptr)) {
- return;
- }
- je_sdallocx_noflags(ptr, size);
-}
-
-void operator delete[](void *ptr, std::size_t size) noexcept {
- if (unlikely(ptr == nullptr)) {
- return;
- }
- je_sdallocx_noflags(ptr, size);
-}
-
-#endif // __cpp_sized_deallocation
->>>>>>> main
diff --git a/contrib/tzcode/localtime.c b/contrib/tzcode/localtime.c
index a80d422f2955..15afeeecb6d0 100644
--- a/contrib/tzcode/localtime.c
+++ b/contrib/tzcode/localtime.c
@@ -615,6 +615,7 @@ tzloadbody(char const *name, struct state *sp, char tzloadflags,
name = TZDEFAULT;
if (! name)
return EINVAL;
+ tzloadflags &= ~TZLOAD_FROMENV;
}
if (name[0] == ':')
@@ -670,11 +671,13 @@ tzloadbody(char const *name, struct state *sp, char tzloadflags,
fid = _open(name, (O_RDONLY | O_BINARY | O_CLOEXEC | O_CLOFORK
| O_IGNORE_CTTY | O_NOCTTY));
#else /* __FreeBSD__ */
+ if ((tzloadflags & TZLOAD_FROMENV) && strcmp(name, TZDEFAULT) == 0)
+ tzloadflags &= ~TZLOAD_FROMENV;
relname = name;
if (strncmp(relname, TZDIR "/", strlen(TZDIR) + 1) == 0)
relname += strlen(TZDIR) + 1;
dd = _open(TZDIR, O_DIRECTORY | O_RDONLY);
- if (issetugid() && (tzloadflags & TZLOAD_FROMENV)) {
+ if ((tzloadflags & TZLOAD_FROMENV) && issetugid()) {
if (dd < 0)
return errno;
if (fstatat(dd, name, &sb, AT_RESOLVE_BENEATH) < 0) {
@@ -1624,14 +1627,13 @@ zoneinit(struct state *sp, char const *name, char tzloadflags)
static void
tzset_unlocked(void)
{
+ char const *name = getenv("TZ");
#ifdef __FreeBSD__
- tzset_unlocked_name(getenv("TZ"));
+ tzset_unlocked_name(name);
}
static void
tzset_unlocked_name(char const *name)
{
-#else
- char const *name = getenv("TZ");
#endif
struct state *sp = lclptr;
int lcl = name ? strlen(name) < sizeof lcl_TZname : -1;
diff --git a/kerberos5/lib/Makefile.inc b/kerberos5/lib/Makefile.inc
index 7c74af1e9742..a7d76580f56e 100644
--- a/kerberos5/lib/Makefile.inc
+++ b/kerberos5/lib/Makefile.inc
@@ -1,3 +1,5 @@
+PACKAGE= kerberos
+LIB_PACKAGE=
SHLIB_MAJOR?= 11
.include "../Makefile.inc"
diff --git a/kerberos5/lib/libasn1/Makefile b/kerberos5/lib/libasn1/Makefile
index 0398ed185481..e30aa20b3c21 100644
--- a/kerberos5/lib/libasn1/Makefile
+++ b/kerberos5/lib/libasn1/Makefile
@@ -1,5 +1,3 @@
-PACKAGE= kerberos-lib
-
LIB= asn1
LDFLAGS+= -Wl,--no-undefined
INCS= asn1_err.h asn1-common.h heim_asn1.h der.h der-protos.h der-private.h
diff --git a/kerberos5/lib/libgssapi_krb5/Makefile b/kerberos5/lib/libgssapi_krb5/Makefile
index 6f74f6516c4e..2e7767ec9309 100644
--- a/kerberos5/lib/libgssapi_krb5/Makefile
+++ b/kerberos5/lib/libgssapi_krb5/Makefile
@@ -1,5 +1,3 @@
-PACKAGE= kerberos-lib
-
LIB= gssapi_krb5
LDFLAGS+= -Wl,-Bsymbolic -Wl,--no-undefined
LIBADD= gssapi krb5 crypto roken asn1 com_err
diff --git a/kerberos5/lib/libgssapi_ntlm/Makefile b/kerberos5/lib/libgssapi_ntlm/Makefile
index 51da17339620..e4721d73403b 100644
--- a/kerberos5/lib/libgssapi_ntlm/Makefile
+++ b/kerberos5/lib/libgssapi_ntlm/Makefile
@@ -1,5 +1,3 @@
-PACKAGE= kerberos-lib
-
LIB= gssapi_ntlm
LDFLAGS+= -Wl,-Bsymbolic -Wl,--no-undefined
LIBADD= crypto gssapi krb5 heimntlm roken
diff --git a/kerberos5/lib/libgssapi_spnego/Makefile b/kerberos5/lib/libgssapi_spnego/Makefile
index 2cf73285cd37..371e7a2fc423 100644
--- a/kerberos5/lib/libgssapi_spnego/Makefile
+++ b/kerberos5/lib/libgssapi_spnego/Makefile
@@ -1,5 +1,3 @@
-PACKAGE= kerberos-lib
-
LIB= gssapi_spnego
LDFLAGS+= -Wl,-Bsymbolic -Wl,--no-undefined
LIBADD= gssapi heimbase asn1 roken
diff --git a/kerberos5/lib/libhdb/Makefile b/kerberos5/lib/libhdb/Makefile
index 04e3a4739ef9..bcc3f75206bc 100644
--- a/kerberos5/lib/libhdb/Makefile
+++ b/kerberos5/lib/libhdb/Makefile
@@ -1,5 +1,3 @@
-PACKAGE= kerberos-lib
-
LIB= hdb
LDFLAGS+= -Wl,--no-undefined ${LDAPLDFLAGS}
VERSION_MAP= ${KRB5DIR}/lib/hdb/version-script.map
diff --git a/kerberos5/lib/libheimbase/Makefile b/kerberos5/lib/libheimbase/Makefile
index 9870fe1d6204..e5c391e32d24 100644
--- a/kerberos5/lib/libheimbase/Makefile
+++ b/kerberos5/lib/libheimbase/Makefile
@@ -1,5 +1,3 @@
-PACKAGE= kerberos-lib
-
LIB= heimbase
LDFLAGS+= -Wl,--no-undefined
LIBADD= pthread
diff --git a/kerberos5/lib/libheimipcc/Makefile b/kerberos5/lib/libheimipcc/Makefile
index 8eb2b2b3756a..848518da303d 100644
--- a/kerberos5/lib/libheimipcc/Makefile
+++ b/kerberos5/lib/libheimipcc/Makefile
@@ -1,5 +1,3 @@
-PACKAGE= kerberos-lib
-
LIB= heimipcc
PRIVATELIB=
LIBADD= heimbase roken pthread
diff --git a/kerberos5/lib/libheimipcs/Makefile b/kerberos5/lib/libheimipcs/Makefile
index e689ac06a601..68cdf97c9f60 100644
--- a/kerberos5/lib/libheimipcs/Makefile
+++ b/kerberos5/lib/libheimipcs/Makefile
@@ -1,5 +1,3 @@
-PACKAGE= kerberos-lib
-
LIB= heimipcs
PRIVATELIB=
LIBADD= heimbase roken pthread
diff --git a/kerberos5/lib/libheimntlm/Makefile b/kerberos5/lib/libheimntlm/Makefile
index cc32e4c5e509..1b5002479ffd 100644
--- a/kerberos5/lib/libheimntlm/Makefile
+++ b/kerberos5/lib/libheimntlm/Makefile
@@ -1,5 +1,3 @@
-PACKAGE= kerberos-lib
-
LIB= heimntlm
LDFLAGS+= -Wl,--no-undefined
LIBADD= crypto com_err krb5 roken
diff --git a/kerberos5/lib/libhx509/Makefile b/kerberos5/lib/libhx509/Makefile
index 7713b4897170..eedc8765ec42 100644
--- a/kerberos5/lib/libhx509/Makefile
+++ b/kerberos5/lib/libhx509/Makefile
@@ -1,5 +1,3 @@
-PACKAGE= kerberos-lib
-
LIB= hx509
LDFLAGS+= -Wl,--no-undefined
VERSION_MAP= ${KRB5DIR}/lib/hx509/version-script.map
diff --git a/kerberos5/lib/libkadm5clnt/Makefile b/kerberos5/lib/libkadm5clnt/Makefile
index 182d60c9843c..b6a5b70171b2 100644
--- a/kerberos5/lib/libkadm5clnt/Makefile
+++ b/kerberos5/lib/libkadm5clnt/Makefile
@@ -1,5 +1,3 @@
-PACKAGE= kerberos-lib
-
LIB= kadm5clnt
LDFLAGS+= -Wl,--no-undefined
LIBADD= com_err krb5 roken
diff --git a/kerberos5/lib/libkadm5srv/Makefile b/kerberos5/lib/libkadm5srv/Makefile
index 05006288220c..92734b439f8b 100644
--- a/kerberos5/lib/libkadm5srv/Makefile
+++ b/kerberos5/lib/libkadm5srv/Makefile
@@ -1,5 +1,3 @@
-PACKAGE= kerberos-lib
-
LIB= kadm5srv
LDFLAGS+= -Wl,--no-undefined
LIBADD= com_err hdb krb5 roken
diff --git a/kerberos5/lib/libkafs5/Makefile b/kerberos5/lib/libkafs5/Makefile
index 91e06d5d777a..6f52b8a8ac98 100644
--- a/kerberos5/lib/libkafs5/Makefile
+++ b/kerberos5/lib/libkafs5/Makefile
@@ -1,5 +1,3 @@
-PACKAGE= kerberos-lib
-
LIB= kafs5
LDFLAGS+= -Wl,--no-undefined
LIBADD= asn1 krb5 roken
diff --git a/kerberos5/lib/libkdc/Makefile b/kerberos5/lib/libkdc/Makefile
index 72bd7d183a29..d6a1e90654ae 100644
--- a/kerberos5/lib/libkdc/Makefile
+++ b/kerberos5/lib/libkdc/Makefile
@@ -1,5 +1,3 @@
-PACKAGE= kerberos-lib
-
LIB= kdc
LDFLAGS+= -Wl,--no-undefined
VERSION_MAP= ${KRB5DIR}/kdc/version-script.map
diff --git a/kerberos5/lib/libkrb5/Makefile b/kerberos5/lib/libkrb5/Makefile
index d377446cd437..4ea5bfc2f86f 100644
--- a/kerberos5/lib/libkrb5/Makefile
+++ b/kerberos5/lib/libkrb5/Makefile
@@ -1,5 +1,3 @@
-PACKAGE= kerberos-lib
-
LIB= krb5
LDFLAGS+= -Wl,--no-undefined
VERSION_MAP= ${KRB5DIR}/lib/krb5/version-script.map
diff --git a/kerberos5/lib/libroken/Makefile b/kerberos5/lib/libroken/Makefile
index 2299beed67a1..08733ac80774 100644
--- a/kerberos5/lib/libroken/Makefile
+++ b/kerberos5/lib/libroken/Makefile
@@ -1,5 +1,3 @@
-PACKAGE= kerberos-lib
-
LIB= roken
LIBADD= crypt
VERSION_MAP= ${KRB5DIR}/lib/roken/version-script.map
diff --git a/kerberos5/lib/libsl/Makefile b/kerberos5/lib/libsl/Makefile
index 159e16089294..c104bb6d64b6 100644
--- a/kerberos5/lib/libsl/Makefile
+++ b/kerberos5/lib/libsl/Makefile
@@ -1,5 +1,3 @@
-PACKAGE= kerberos-lib
-
LIB= sl
INTERNALLIB=
SRCS= sl.c
diff --git a/kerberos5/lib/libvers/Makefile b/kerberos5/lib/libvers/Makefile
index d7fe0a001659..514b8abe6a32 100644
--- a/kerberos5/lib/libvers/Makefile
+++ b/kerberos5/lib/libvers/Makefile
@@ -1,5 +1,3 @@
-PACKAGE= kerberos-lib
-
LIB= vers
INTERNALLIB=
SRCS= print_version.c roken.h
diff --git a/kerberos5/lib/libwind/Makefile b/kerberos5/lib/libwind/Makefile
index b57d62dc830f..0bf1f7a9613c 100644
--- a/kerberos5/lib/libwind/Makefile
+++ b/kerberos5/lib/libwind/Makefile
@@ -1,5 +1,3 @@
-PACKAGE= kerberos-lib
-
LIB= wind
LDFLAGS+= -Wl,--no-undefined
VERSION_MAP= ${KRB5DIR}/lib/wind/version-script.map
diff --git a/lib/clang/freebsd_cc_version.h b/lib/clang/freebsd_cc_version.h
index 277744ae8624..b493dc96db5e 100644
--- a/lib/clang/freebsd_cc_version.h
+++ b/lib/clang/freebsd_cc_version.h
@@ -1 +1 @@
-#define FREEBSD_CC_VERSION 1500000
+#define FREEBSD_CC_VERSION 1600000
diff --git a/lib/clang/include/lld/Common/Version.inc b/lib/clang/include/lld/Common/Version.inc
index 0643da4abbf4..0def3da7469c 100644
--- a/lib/clang/include/lld/Common/Version.inc
+++ b/lib/clang/include/lld/Common/Version.inc
@@ -1,4 +1,4 @@
// Local identifier in __FreeBSD_version style
-#define LLD_FREEBSD_VERSION 1500001
+#define LLD_FREEBSD_VERSION 1600000
#define LLD_VERSION_STRING "19.1.7 (FreeBSD llvmorg-19.1.7-0-gcd708029e0b2-" __XSTRING(LLD_FREEBSD_VERSION) ")"
diff --git a/lib/libc/tests/stdtime/detect_tz_changes_test.c b/lib/libc/tests/stdtime/detect_tz_changes_test.c
index ad8c4818669d..6648d8498cc5 100644
--- a/lib/libc/tests/stdtime/detect_tz_changes_test.c
+++ b/lib/libc/tests/stdtime/detect_tz_changes_test.c
@@ -70,7 +70,7 @@ change_tz(const char *tzn)
ATF_REQUIRE((zfd = open(zfn, O_DIRECTORY | O_SEARCH)) >= 0);
ATF_REQUIRE((sfd = openat(zfd, tzn, O_RDONLY)) >= 0);
- ATF_REQUIRE((dfd = open(tfn, O_CREAT | O_TRUNC | O_WRONLY)) >= 0);
+ ATF_REQUIRE((dfd = open(tfn, O_CREAT | O_TRUNC | O_WRONLY, 0644)) >= 0);
do {
clen = copy_file_range(sfd, NULL, dfd, NULL, SSIZE_MAX, 0);
ATF_REQUIRE_MSG(clen != -1, "failed to copy %s/%s: %m",
@@ -83,6 +83,19 @@ change_tz(const char *tzn)
debug("time zone %s installed", tzn);
}
+static void
+test_tz(const char *expect)
+{
+ char buf[128];
+ struct tm *tm;
+ size_t len;
+
+ ATF_REQUIRE((tm = localtime(&then)) != NULL);
+ len = strftime(buf, sizeof(buf), "%z (%Z)", tm);
+ ATF_REQUIRE(len > 0);
+ ATF_CHECK_STREQ(expect, buf);
+}
+
ATF_TC(thin_jail);
ATF_TC_HEAD(thin_jail, tc)
{
@@ -92,9 +105,6 @@ ATF_TC_HEAD(thin_jail, tc)
ATF_TC_BODY(thin_jail, tc)
{
const struct tzcase *tzcase = tzcases;
- char buf[128];
- struct tm *tm;
- size_t len;
/* prepare chroot */
ATF_REQUIRE_EQ(0, mkdir("root", 0755));
@@ -105,10 +115,7 @@ ATF_TC_BODY(thin_jail, tc)
ATF_REQUIRE_EQ(0, chdir("/"));
/* check timezone */
unsetenv("TZ");
- ATF_REQUIRE((tm = localtime(&then)) != NULL);
- len = strftime(buf, sizeof(buf), "%z (%Z)", tm);
- ATF_REQUIRE(len > 0);
- ATF_CHECK_STREQ(tzcase->expect, buf);
+ test_tz(tzcase->expect);
}
#ifdef DETECT_TZ_CHANGES
@@ -309,15 +316,8 @@ ATF_TC_BODY(detect_tz_changes, tc)
static void
test_tz_env(const char *tzval, const char *expect)
{
- char buf[128];
- struct tm *tm;
- size_t len;
-
setenv("TZ", tzval, 1);
- ATF_REQUIRE((tm = localtime(&then)) != NULL);
- len = strftime(buf, sizeof(buf), "%z (%Z)", tm);
- ATF_REQUIRE(len > 0);
- ATF_CHECK_STREQ(expect, buf);
+ test_tz(expect);
}
ATF_TC(tz_env);
@@ -333,6 +333,31 @@ ATF_TC_BODY(tz_env, tc)
test_tz_env(tzcase->tzfn, tzcase->expect);
}
+ATF_TC(setugid);
+ATF_TC_HEAD(setugid, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Test setugid process");
+ atf_tc_set_md_var(tc, "require.user", "root");
+}
+ATF_TC_BODY(setugid, tc)
+{
+ const struct tzcase *tzcase = tzcases;
+
+ /* prepare chroot */
+ ATF_REQUIRE_EQ(0, mkdir("root", 0755));
+ ATF_REQUIRE_EQ(0, mkdir("root/etc", 0755));
+ change_tz(tzcase->tzfn);
+ /* enter chroot */
+ ATF_REQUIRE_EQ(0, chroot("root"));
+ ATF_REQUIRE_EQ(0, chdir("/"));
+ /* become setugid */
+ ATF_REQUIRE_EQ(0, seteuid(UID_NOBODY));
+ ATF_REQUIRE(issetugid());
+ /* check timezone */
+ unsetenv("TZ");
+ test_tz(tzcases->expect);
+}
+
ATF_TC(tz_env_setugid);
ATF_TC_HEAD(tz_env_setugid, tc)
{
@@ -342,7 +367,7 @@ ATF_TC_HEAD(tz_env_setugid, tc)
}
ATF_TC_BODY(tz_env_setugid, tc)
{
- const struct tzcase *tzcase;
+ const struct tzcase *tzcase = tzcases;
ATF_REQUIRE_EQ(0, seteuid(UID_NOBODY));
ATF_REQUIRE(issetugid());
@@ -359,6 +384,7 @@ ATF_TP_ADD_TCS(tp)
ATF_TP_ADD_TC(tp, detect_tz_changes);
#endif /* DETECT_TZ_CHANGES */
ATF_TP_ADD_TC(tp, tz_env);
+ ATF_TP_ADD_TC(tp, setugid);
ATF_TP_ADD_TC(tp, tz_env_setugid);
return (atf_no_error());
}
diff --git a/lib/libcom_err/Makefile b/lib/libcom_err/Makefile
index f070fd534469..dab4794fcded 100644
--- a/lib/libcom_err/Makefile
+++ b/lib/libcom_err/Makefile
@@ -1,4 +1,5 @@
-PACKAGE= kerberos-lib
+PACKAGE= kerberos
+LIB_PACKAGE=
LIB= com_err
SRCS= com_err.c error.c
diff --git a/lib/libgpio/Makefile b/lib/libgpio/Makefile
index 42f822e97ba0..271595339792 100644
--- a/lib/libgpio/Makefile
+++ b/lib/libgpio/Makefile
@@ -27,6 +27,8 @@ MLINKS= gpio.3 gpio_open.3 \
gpio.3 gpio_pin_pulldown.3 \
gpio.3 gpio_pin_invin.3 \
gpio.3 gpio_pin_invout.3 \
- gpio.3 gpio_pin_pulsate.3
+ gpio.3 gpio_pin_pulsate.3 \
+ gpio.3 gpio_configure_events.3 \
+ gpio.3 gpio_fileno.3
.include <bsd.lib.mk>
diff --git a/lib/libgpio/gpio.3 b/lib/libgpio/gpio.3
index ed2860776c3c..cb413b838bd0 100644
--- a/lib/libgpio/gpio.3
+++ b/lib/libgpio/gpio.3
@@ -23,7 +23,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd July 1, 2015
+.Dd September 3, 2025
.Dt GPIO 3
.Os
.Sh NAME
@@ -79,6 +79,10 @@
.Fn gpio_pin_invout "gpio_handle_t handle" "gpio_pin_t pin"
.Ft int
.Fn gpio_pin_pulsate "gpio_handle_t handle" "gpio_pin_t pin"
+.Ft int
+.Fn gpio_configure_events "gpio_handle_t handle" "uint32_t report_type" "uint32_t fifo_size"
+.Ft int
+.Fn gpio_fileno "gpio_handle_t handle"
.Sh DESCRIPTION
The
.Nm libgpio
@@ -125,7 +129,7 @@ The pin number should also be passed in through the
variable.
All other structure members will be ignored by this function.
The list of flags can be found in
-.Pa /usr/include/sys/gpio.h .
+.In sys/gpio.h .
.Pp
The get or set the state of a GPIO pin, the functions
.Fn gpio_pin_get
@@ -156,6 +160,66 @@ and
.Fn gpio_pin_pulsate
are wrappers around
.Fn gpio_pin_set_flags .
+.Pp
+The function
+.Fn gpio_configure_events
+configures the interrupt report type and FIFO size for buffered
+gpio interrupts.
+The report type is specified by one of the following values:
+.Bl -tag -width indent
+.It Dv GPIO_EVENT_REPORT_DETAIL
+Events are reported using
+.Ft struct gpio_event_detail .
+.It Dv GPIO_EVENT_REPORT_SUMMARY
+Events are reported using
+.Ft struct gpio_event_summary .
+.El
+.Pp
+By default, the report type is
+.Dv GPIO_EVENT_REPORT_DETAIL ,
+with a default FIFO size of 2 * number of pins belonging to the
+.Ft gpio_device_t
+instance.
+The FIFO argument is only meaningful when
+.Fa report_type
+is
+.Dv GPIO_EVENT_REPORT_DETAIL .
+The structures associated with each report type are defined in
+.In sys/gpio.h .
+This setting is tracked on a per device instance basis.
+The FIFO size cannot be reduced below the default value,
+nor can it be decreased after it has been increased.
+If any pin on the device has already been configured for interrupts,
+.Fn gpio_configure_events
+fails and returns -1.
+On success 0 is returned.
+.Pp
+The function
+.Fn gpio_fileno
+returns the file descriptor associated with the
+.Ft gpio_handle_t
+instance.
+.Pp
+File operations have the following semantics:
+.Bl -tag -width "read (2)"
+.It Xr read 2
+Read one or more gpio interrupts that have occured
+since the last successful
+.Xr read 2 .
+The results are placed into the output buffer
+of the type previously established via
+.Fn gpio_configure_events .
+If there are no pending interrupts,
+.Xr read 2
+blocks until an interrupt occurs, unless
+.Dv O_NONBLOCK
+is set.
+.It Xr poll 2
+When receiving notification via
+.Xr poll 2
+or similar interfaces, the file descriptor becomes readable when
+one or more gpio interrupts are pending.
+.El
.Sh EXAMPLES
The following example shows how to configure pin 16 as output and then
drive it high:
diff --git a/lib/libgpio/gpio.c b/lib/libgpio/gpio.c
index e37ac1cdf8e8..c789bb34cacd 100644
--- a/lib/libgpio/gpio.c
+++ b/lib/libgpio/gpio.c
@@ -274,3 +274,23 @@ gpio_pin_pulsate(gpio_handle_t handle, gpio_pin_t pin)
{
return (gpio_pin_set_flag(handle, pin, GPIO_PIN_PULSATE));
}
+
+int
+gpio_configure_events(gpio_handle_t handle, uint32_t report_type,
+ uint32_t fifo_size)
+{
+ struct gpio_event_config gpevent_config;
+
+ gpevent_config.gp_report_type = report_type;
+ gpevent_config.gp_fifo_size = fifo_size;
+ if (ioctl(handle, GPIOCONFIGEVENTS, &gpevent_config) < 0)
+ return (-1);
+
+ return (0);
+}
+
+int
+gpio_fileno(gpio_handle_t handle)
+{
+ return (handle);
+}
diff --git a/lib/libgpio/libgpio.h b/lib/libgpio/libgpio.h
index 35651ecd8cca..abffc7b1b6ab 100644
--- a/lib/libgpio/libgpio.h
+++ b/lib/libgpio/libgpio.h
@@ -102,6 +102,19 @@ int gpio_pin_pulldown(gpio_handle_t, gpio_pin_t);
int gpio_pin_invin(gpio_handle_t, gpio_pin_t);
int gpio_pin_invout(gpio_handle_t, gpio_pin_t);
int gpio_pin_pulsate(gpio_handle_t, gpio_pin_t);
+/*
+ * GPIO event reporting configuration
+ *
+ * Set the event reporting type, the default being GPIO_EVENT_REPORT_DETAIL,
+ * and fifo size of 2 * number of pins belonging to the gpioc device instance.
+ * FIFO size can only be changed when report_type is GPIO_EVENT_REPORT_DETAIL.
+ */
+int gpio_configure_events(gpio_handle_t, uint32_t, uint32_t);
+/*
+ * Retrieve the file descriptor associated with gpio_handle_t, which can
+ * be used for gpio interrupts.
+ */
+int gpio_fileno(gpio_handle_t);
__END_DECLS
diff --git a/lib/libifconfig/Makefile b/lib/libifconfig/Makefile
index fb7c659e068c..02629eb88f25 100644
--- a/lib/libifconfig/Makefile
+++ b/lib/libifconfig/Makefile
@@ -17,6 +17,7 @@ SRCS= libifconfig.c \
libifconfig_internal.c \
libifconfig_lagg.c \
libifconfig_media.c \
+ libifconfig_nl.c \
libifconfig_sfp.c
GEN= libifconfig_sfp_tables.h \
diff --git a/lib/libifconfig/libifconfig.h b/lib/libifconfig/libifconfig.h
index a5ce7b375830..817f52bd094e 100644
--- a/lib/libifconfig/libifconfig.h
+++ b/lib/libifconfig/libifconfig.h
@@ -35,6 +35,8 @@
#include <netinet/ip_carp.h>
#include <netinet6/in6_var.h>
+#include <stdbool.h>
+
#define ND6_IFF_DEFAULTIF 0x8000
typedef enum {
@@ -381,3 +383,12 @@ int ifconfig_set_vlantag(ifconfig_handle_t *h, const char *name,
* length of *lenp * IFNAMSIZ bytes.
*/
int ifconfig_list_cloners(ifconfig_handle_t *h, char **bufp, size_t *lenp);
+
+/** Brings the interface up/down
+ * @param h An open ifconfig state object
+ * @param ifname The interface name
+ * @param up true to bring the interface up, false to bring it down
+ * @return 0 on success, nonzero on failure.
+ * On failure, the error info on the handle is set.
+ */
+int ifconfig_set_up(ifconfig_handle_t *h, const char *ifname, bool up);
diff --git a/lib/libifconfig/libifconfig_nl.c b/lib/libifconfig/libifconfig_nl.c
new file mode 100644
index 000000000000..7d9decabe26f
--- /dev/null
+++ b/lib/libifconfig/libifconfig_nl.c
@@ -0,0 +1,72 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2025, Muhammad Saheed <saheed@FreeBSD.org>
+ */
+
+#include <netlink/netlink.h>
+#include <netlink/netlink_snl.h>
+#include <netlink/route/common.h>
+#include <netlink/route/interface.h>
+
+#include "libifconfig.h"
+#include "libifconfig_internal.h"
+
+static int ifconfig_modify_flags(ifconfig_handle_t *h, const char *ifname,
+ int ifi_flags, int ifi_change);
+
+static int
+ifconfig_modify_flags(ifconfig_handle_t *h, const char *ifname, int ifi_flags,
+ int ifi_change)
+{
+ int ret = 0;
+ struct snl_state ss;
+ struct snl_writer nw;
+ struct nlmsghdr *hdr;
+ struct ifinfomsg *ifi;
+ struct snl_errmsg_data e = { 0 };
+
+ if (!snl_init(&ss, NETLINK_ROUTE)) {
+ ifconfig_error(h, NETLINK, ENOTSUP);
+ return (-1);
+ }
+
+ snl_init_writer(&ss, &nw);
+ hdr = snl_create_msg_request(&nw, NL_RTM_NEWLINK);
+ ifi = snl_reserve_msg_object(&nw, struct ifinfomsg);
+ snl_add_msg_attr_string(&nw, IFLA_IFNAME, ifname);
+
+ ifi->ifi_flags = ifi_flags;
+ ifi->ifi_change = ifi_change;
+
+ hdr = snl_finalize_msg(&nw);
+ if (hdr == NULL) {
+ ifconfig_error(h, NETLINK, ENOMEM);
+ ret = -1;
+ goto out;
+ }
+
+ if (!snl_send_message(&ss, hdr)) {
+ ifconfig_error(h, NETLINK, EIO);
+ ret = -1;
+ goto out;
+ }
+
+ if (!snl_read_reply_code(&ss, hdr->nlmsg_seq, &e)) {
+ ifconfig_error(h, NETLINK, e.error);
+ ret = -1;
+ goto out;
+ }
+
+out:
+ snl_free(&ss);
+ return (ret);
+}
+
+int
+ifconfig_set_up(ifconfig_handle_t *h, const char *ifname, bool up)
+{
+ int flag = up ? IFF_UP : ~IFF_UP;
+
+ return (ifconfig_modify_flags(h, ifname, flag, IFF_UP));
+}
diff --git a/lib/libjail/jail.c b/lib/libjail/jail.c
index 30282e67866c..931391055919 100644
--- a/lib/libjail/jail.c
+++ b/lib/libjail/jail.c
@@ -75,8 +75,9 @@ int
jail_setv(int flags, ...)
{
va_list ap, tap;
- struct jailparam *jp;
- const char *name, *value;
+ struct jailparam *jp, *jp_desc;
+ const char *name;
+ char *value, *desc_value;
int njp, jid;
/* Create the parameter list and import the parameters. */
@@ -86,15 +87,24 @@ jail_setv(int flags, ...)
(void)va_arg(tap, char *);
va_end(tap);
jp = alloca(njp * sizeof(struct jailparam));
- for (njp = 0; (name = va_arg(ap, char *)) != NULL;) {
+ jp_desc = NULL;
+ desc_value = NULL;
+ for (njp = 0; (name = va_arg(ap, char *)) != NULL; njp++) {
value = va_arg(ap, char *);
if (jailparam_init(jp + njp, name) < 0)
goto error;
- if (jailparam_import(jp + njp++, value) < 0)
+ if (jailparam_import(jp + njp, value) < 0)
goto error;
+ if (!strcmp(name, "desc")
+ && (flags & (JAIL_GET_DESC | JAIL_OWN_DESC))) {
+ jp_desc = jp + njp;
+ desc_value = value;
+ }
}
va_end(ap);
jid = jailparam_set(jp, njp, flags);
+ if (jid > 0 && jp_desc != NULL)
+ sprintf(desc_value, "%d", *(int *)jp_desc->jp_value);
jailparam_free(jp, njp);
return (jid);
@@ -112,9 +122,10 @@ int
jail_getv(int flags, ...)
{
va_list ap, tap;
- struct jailparam *jp, *jp_lastjid, *jp_jid, *jp_name, *jp_key;
+ struct jailparam *jp, *jp_desc, *jp_lastjid, *jp_jid, *jp_name, *jp_key;
char *valarg, *value;
- const char *name, *key_value, *lastjid_value, *jid_value, *name_value;
+ const char *name, *key_value, *desc_value, *lastjid_value, *jid_value;
+ const char *name_value;
int njp, i, jid;
/* Create the parameter list and find the key. */
@@ -126,15 +137,19 @@ jail_getv(int flags, ...)
jp = alloca(njp * sizeof(struct jailparam));
va_copy(tap, ap);
- jp_lastjid = jp_jid = jp_name = NULL;
- lastjid_value = jid_value = name_value = NULL;
+ jp_desc = jp_lastjid = jp_jid = jp_name = NULL;
+ desc_value = lastjid_value = jid_value = name_value = NULL;
for (njp = 0; (name = va_arg(tap, char *)) != NULL; njp++) {
value = va_arg(tap, char *);
if (jailparam_init(jp + njp, name) < 0) {
va_end(tap);
goto error;
}
- if (!strcmp(jp[njp].jp_name, "lastjid")) {
+ if (!strcmp(jp[njp].jp_name, "desc")
+ && (flags & (JAIL_USE_DESC | JAIL_AT_DESC))) {
+ jp_desc = jp + njp;
+ desc_value = value;
+ } else if (!strcmp(jp[njp].jp_name, "lastjid")) {
jp_lastjid = jp + njp;
lastjid_value = value;
} else if (!strcmp(jp[njp].jp_name, "jid")) {
@@ -147,7 +162,10 @@ jail_getv(int flags, ...)
}
va_end(tap);
/* Import the key parameter. */
- if (jp_lastjid != NULL) {
+ if (jp_desc != NULL && (flags & JAIL_USE_DESC)) {
+ jp_key = jp_desc;
+ key_value = desc_value;
+ } else if (jp_lastjid != NULL) {
jp_key = jp_lastjid;
key_value = lastjid_value;
} else if (jp_jid != NULL && strtol(jid_value, NULL, 10) != 0) {
@@ -163,6 +181,9 @@ jail_getv(int flags, ...)
}
if (jailparam_import(jp_key, key_value) < 0)
goto error;
+ if (jp_desc != NULL && jp_desc != jp_key
+ && jailparam_import(jp_desc, desc_value) < 0)
+ goto error;
/* Get the jail and export the parameters. */
jid = jailparam_get(jp, njp, flags);
if (jid < 0)
@@ -571,7 +592,7 @@ int
jailparam_get(struct jailparam *jp, unsigned njp, int flags)
{
struct iovec *jiov;
- struct jailparam *jp_lastjid, *jp_jid, *jp_name, *jp_key;
+ struct jailparam *jp_desc, *jp_lastjid, *jp_jid, *jp_name, *jp_key;
int i, ai, ki, jid, arrays, sanity;
unsigned j;
@@ -580,10 +601,13 @@ jailparam_get(struct jailparam *jp, unsigned njp, int flags)
* Find the key and any array parameters.
*/
jiov = alloca(sizeof(struct iovec) * 2 * (njp + 1));
- jp_lastjid = jp_jid = jp_name = NULL;
+ jp_desc = jp_lastjid = jp_jid = jp_name = NULL;
arrays = 0;
for (ai = j = 0; j < njp; j++) {
- if (!strcmp(jp[j].jp_name, "lastjid"))
+ if (!strcmp(jp[j].jp_name, "desc")
+ && (flags & (JAIL_USE_DESC | JAIL_AT_DESC)))
+ jp_desc = jp + j;
+ else if (!strcmp(jp[j].jp_name, "lastjid"))
jp_lastjid = jp + j;
else if (!strcmp(jp[j].jp_name, "jid"))
jp_jid = jp + j;
@@ -599,7 +623,9 @@ jailparam_get(struct jailparam *jp, unsigned njp, int flags)
ai++;
}
}
- jp_key = jp_lastjid ? jp_lastjid :
+ jp_key = jp_desc && jp_desc->jp_valuelen == sizeof(int) &&
+ jp_desc->jp_value && (flags & JAIL_USE_DESC) ? jp_desc :
+ jp_lastjid ? jp_lastjid :
jp_jid && jp_jid->jp_valuelen == sizeof(int) &&
jp_jid->jp_value && *(int *)jp_jid->jp_value ? jp_jid : jp_name;
if (jp_key == NULL || jp_key->jp_value == NULL) {
@@ -622,6 +648,14 @@ jailparam_get(struct jailparam *jp, unsigned njp, int flags)
jiov[ki].iov_len = JAIL_ERRMSGLEN;
ki++;
jail_errmsg[0] = 0;
+ if (jp_desc != NULL && jp_desc != jp_key) {
+ jiov[ki].iov_base = jp_desc->jp_name;
+ jiov[ki].iov_len = strlen(jp_desc->jp_name) + 1;
+ ki++;
+ jiov[ki].iov_base = jp_desc->jp_value;
+ jiov[ki].iov_len = jp_desc->jp_valuelen;
+ ki++;
+ }
if (arrays && jail_get(jiov, ki, flags) < 0) {
if (!jail_errmsg[0])
snprintf(jail_errmsg, sizeof(jail_errmsg),
@@ -649,7 +683,7 @@ jailparam_get(struct jailparam *jp, unsigned njp, int flags)
jiov[ai].iov_base = jp[j].jp_value;
memset(jiov[ai].iov_base, 0, jiov[ai].iov_len);
ai++;
- } else if (jp + j != jp_key) {
+ } else if (jp + j != jp_key && jp + j != jp_desc) {
jiov[i].iov_base = jp[j].jp_name;
jiov[i].iov_len = strlen(jp[j].jp_name) + 1;
i++;
diff --git a/lib/libpfctl/libpfctl.c b/lib/libpfctl/libpfctl.c
index 0037f31df04b..190ee46baf21 100644
--- a/lib/libpfctl/libpfctl.c
+++ b/lib/libpfctl/libpfctl.c
@@ -1284,8 +1284,8 @@ snl_add_msg_attr_pf_rule(struct snl_writer *nw, uint32_t type, const struct pfct
snl_add_msg_attr_u8(nw, PF_RT_KEEP_STATE, r->keep_state);
snl_add_msg_attr_u8(nw, PF_RT_AF, r->af);
snl_add_msg_attr_u8(nw, PF_RT_PROTO, r->proto);
- snl_add_msg_attr_u8(nw, PF_RT_TYPE, r->type);
- snl_add_msg_attr_u8(nw, PF_RT_CODE, r->code);
+ snl_add_msg_attr_u16(nw, PF_RT_TYPE_2, r->type);
+ snl_add_msg_attr_u16(nw, PF_RT_CODE_2, r->code);
snl_add_msg_attr_u8(nw, PF_RT_FLAGS, r->flags);
snl_add_msg_attr_u8(nw, PF_RT_FLAGSET, r->flagset);
snl_add_msg_attr_u8(nw, PF_RT_MIN_TTL, r->min_ttl);
@@ -1694,6 +1694,8 @@ static struct snl_attr_parser ap_getrule[] = {
{ .type = PF_RT_SRC_NODES_ROUTE, .off = _OUT(r.src_nodes_type[PF_SN_ROUTE]), .cb = snl_attr_get_uint64 },
{ .type = PF_RT_PKTRATE, .off = _OUT(r.pktrate), .arg = &pfctl_threshold_parser, .cb = snl_attr_get_nested },
{ .type = PF_RT_MAX_PKT_SIZE, .off =_OUT(r.max_pkt_size), .cb = snl_attr_get_uint16 },
+ { .type = PF_RT_TYPE_2, .off = _OUT(r.type), .cb = snl_attr_get_uint16 },
+ { .type = PF_RT_CODE_2, .off = _OUT(r.code), .cb = snl_attr_get_uint16 },
};
#undef _OUT
SNL_DECLARE_PARSER(getrule_parser, struct genlmsghdr, snl_f_p_empty, ap_getrule);
diff --git a/lib/libpfctl/libpfctl.h b/lib/libpfctl/libpfctl.h
index f6c8f6a2ccdb..da16d5179ec0 100644
--- a/lib/libpfctl/libpfctl.h
+++ b/lib/libpfctl/libpfctl.h
@@ -261,8 +261,8 @@ struct pfctl_rule {
uint8_t keep_state;
sa_family_t af;
uint8_t proto;
- uint8_t type;
- uint8_t code;
+ uint16_t type;
+ uint16_t code;
uint8_t flags;
uint8_t flagset;
uint8_t min_ttl;
diff --git a/lib/libsys/Symbol.sys.map b/lib/libsys/Symbol.sys.map
index 1a297f9df581..e3fd8ac10621 100644
--- a/lib/libsys/Symbol.sys.map
+++ b/lib/libsys/Symbol.sys.map
@@ -382,6 +382,8 @@ FBSD_1.8 {
getrlimitusage;
inotify_add_watch_at;
inotify_rm_watch;
+ jail_attach_jd;
+ jail_remove_jd;
kcmp;
setcred;
setgroups;
diff --git a/lib/libsys/_libsys.h b/lib/libsys/_libsys.h
index 34eebc1aa67a..6bd768708a78 100644
--- a/lib/libsys/_libsys.h
+++ b/lib/libsys/_libsys.h
@@ -468,6 +468,8 @@ typedef int (__sys_inotify_add_watch_at_t)(int, int, const char *, uint32_t);
typedef int (__sys_inotify_rm_watch_t)(int, int);
typedef int (__sys_getgroups_t)(int, gid_t *);
typedef int (__sys_setgroups_t)(int, const gid_t *);
+typedef int (__sys_jail_attach_jd_t)(int);
+typedef int (__sys_jail_remove_jd_t)(int);
_Noreturn void __sys__exit(int rval);
int __sys_fork(void);
@@ -872,6 +874,8 @@ int __sys_inotify_add_watch_at(int fd, int dfd, const char * path, uint32_t mask
int __sys_inotify_rm_watch(int fd, int wd);
int __sys_getgroups(int gidsetsize, gid_t * gidset);
int __sys_setgroups(int gidsetsize, const gid_t * gidset);
+int __sys_jail_attach_jd(int fd);
+int __sys_jail_remove_jd(int fd);
__END_DECLS
#endif /* __LIBSYS_H_ */
diff --git a/lib/libsys/jail.2 b/lib/libsys/jail.2
index 8f8b9925c712..a0f47cc61cb3 100644
--- a/lib/libsys/jail.2
+++ b/lib/libsys/jail.2
@@ -23,7 +23,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd November 29, 2023
+.Dd September 4, 2025
.Dt JAIL 2
.Os
.Sh NAME
@@ -31,7 +31,9 @@
.Nm jail_get ,
.Nm jail_set ,
.Nm jail_remove ,
-.Nm jail_attach
+.Nm jail_attach ,
+.Nm jail_remove_jd ,
+.Nm jail_attach_jd
.Nd create and manage system jails
.Sh LIBRARY
.Lb libc
@@ -44,6 +46,10 @@
.Fn jail_attach "int jid"
.Ft int
.Fn jail_remove "int jid"
+.Ft int
+.Fn jail_attach_jd "int fd"
+.Ft int
+.Fn jail_remove_jd "int fd"
.In sys/uio.h
.Ft int
.Fn jail_get "struct iovec *iov" "u_int niov" "int flags"
@@ -188,6 +194,29 @@ system call.
This is deprecated in
.Fn jail_set
and has no effect.
+.It Dv JAIL_USE_DESC
+Identify the jail by a descriptor in the
+.Va desc
+parameter.
+.It Dv JAIL_AT_DESC
+Operate in the context of the jail described by the
+.Va desc
+parameter, instead of the current jail.
+Only one of
+.Dv JAIL_USE_DESC
+or
+.Dv JAIL_AT_DESC
+may be specified.
+.It Dv JAIL_GET_DESC
+Return a new jail descriptor for the jail in the
+.Va desc
+parameter.
+.It Dv JAIL_OWN_DESC
+Return an
+.Dq owning
+jail descriptor in the
+.Va desc
+parameter.
.El
.Pp
The
@@ -221,6 +250,9 @@ arguments consists of one or more following flags:
.Bl -tag -width indent
.It Dv JAIL_DYING
Allow getting a jail that is in the process of being removed.
+.It Dv JAIL_USE_DESC , Dv JAIL_AT_DESC , Dv JAIL_GET_DESC , Dv JAIL_OWN_DESC
+These have the same meaning as they do in
+.Fn jail_set .
.El
.Pp
The
@@ -238,6 +270,101 @@ system call removes the jail identified by
.Fa jid .
It will kill all processes belonging to the jail, and remove any children
of that jail.
+.Pp
+The
+.Fn jail_attach_fd
+and
+.Fn jail_remove_fd
+system calls work the same as
+.Fn jail_attach
+and
+.Fn jail_remove ,
+except that they operate on the jail identified by jail descriptor
+.Fa fd .
+.Ss Jail Descriptors
+In addition to the jail ID,
+jails can be referred to using a jail descriptor,
+a type of file descriptor tied to a particular jail.
+Jail descriptors are created by calling
+.Fn jail_set
+or
+.Fn jail_get
+with the special parameter
+.Va desc ,
+and either the
+.Dv JAIL_GET_DESC
+or
+.Dv JAIL_OWN_DESC
+flags set.
+The difference between the two flags is that descriptors created with
+.Dv JAIL_OWN_DESC
+.Po
+called
+.Dq owning
+descriptors
+.Pc
+will automatically remove the jail when the descriptor is closed.
+.Pp
+Jail descriptors can be passed back to
+.Fn jail_set
+or
+.Fm jail_get
+with the
+.Va desc
+parameter,
+and either the
+.Dv JAIL_USE_DESC
+or
+.Dv JAIL_AT_DESC
+flags set.
+With
+.Dv JAIL_USE_DESC ,
+the descriptor identifies the jail to operate on,
+instead of the
+.Va jid
+or
+.Va name
+parameter.
+With
+.Dv JAIL_AT_DESC ,
+the descriptor is used in place of the current jail,
+allowing accessing or creating jails that are children of the
+descriptor jail.
+.Pp
+The system calls
+.Fn jail_attach_jd
+and
+.Fn jail_aremove_jd
+work the same as
+.Fn jail_attach
+and
+.Fn jail_remove ,
+except that they operate on the jail referred to by the passed descriptor.
+.Pp
+Jail operations via descriptors can be done by processes that do not
+normally have permission to see or affect the jail,
+as long as they are allowed by the file permissions of the jail
+descriptor itself.
+These permissions can be changed by the descriptor owner via
+.Xr fchmod 2
+and
+.Xr fchown 2 .
+.Fn jail_get
+requires read permission,
+.Fn jail_set
+and
+.Fn jail_remove
+require write permission,
+and
+.Fn jail_attach
+requires execute permission.
+Also, use of a descriptor with the
+.Dv JAIL_AT_DESC
+flag requires execute permission.
+An owning descriptor is identified by the
+.Em sticky bit ,
+which may also be changed via
+.Xr fchmod 2 .
.Sh RETURN VALUES
If successful,
.Fn jail ,
@@ -249,7 +376,7 @@ They return \-1 on failure, and set
.Va errno
to indicate the error.
.Pp
-.Rv -std jail_attach jail_remove
+.Rv -std jail_attach jail_remove jail_attach_jd jail_remove_jd
.Sh ERRORS
The
.Fn jail
@@ -275,12 +402,44 @@ The
system call
will fail if:
.Bl -tag -width Er
+.It Bq Er EBADF
+The
+.Va desc
+parameter does not refer to a valid jail descriptor,
+and either the
+.Dv JAIL_USE_DESC
+or
+.Dv JAIL_AT_DESC
+flag was set.
+.It Bq Er EACCES
+Write permission is denied on the jail descriptor in the
+.Va desc
+parameter,
+and the
+.Dv JAIL_USE_DESC
+flag was set.
+.It Bq Er EACCES
+Execute permission is denied on the jail descriptor in the
+.Va desc
+parameter,
+and either the
+.Dv JAIL_AT_DESC
+or
+.Dv JAIL_ATTACH
+flag was set.
.It Bq Er EPERM
This process is not allowed to create a jail, either because it is not
the super-user, or because it would exceed the jail's
.Va children.max
limit.
.It Bq Er EPERM
+The jail descriptor in the
+.Va desc
+parameter was created by a user other than the super-user,
+and the
+.Dv JAIL_USE_DESC
+flag was set.
+.It Bq Er EPERM
A jail parameter was set to a less restrictive value then the current
environment.
.It Bq Er EFAULT
@@ -298,8 +457,12 @@ flag is not set.
.It Bq Er ENOENT
The jail referred to by a
.Va jid
-is not accessible by the process, because the process is in a different
-jail.
+parameter is not accessible by the process, because the process is in a
+different jail.
+.It Bq Er ENOENT
+The jail referred to by a
+.Va desc
+parameter has been removed.
.It Bq Er EEXIST
The jail referred to by a
.Va jid
@@ -326,6 +489,24 @@ flags is not set.
A supplied string parameter is longer than allowed.
.It Bq Er EAGAIN
There are no jail IDs left.
+.It Bq Er EMFILE
+A jail descriptor could not be created for the
+.Va desc
+parameter with either the
+.Dv JAIL_GET_DESC
+or
+.Dv JAIL_OWN_DESC
+flag set,
+because the process has already reached its limit for open file descriptors.
+.It Bq Er ENFILE
+A jail descriptor could not be created for the
+.Va desc
+parameter with either the
+.Dv JAIL_GET_DESC
+or
+.Dv JAIL_OWN_DESC
+flag set,
+because the system file table is full.
.El
.Pp
The
@@ -333,6 +514,29 @@ The
system call
will fail if:
.Bl -tag -width Er
+.It Bq Er EBADF
+The
+.Va desc
+parameter does not refer to a valid jail descriptor,
+and either the
+.Dv JAIL_USE_DESC
+or
+.Dv JAIL_AT_DESC
+flag was set.
+.It Bq Er EACCES
+Read permission is denied on the jail descriptor in the
+.Va desc
+parameter,
+and the
+.Dv JAIL_USE_DESC
+flag was set.
+.It Bq Er EACCES
+Execute permission is denied on the jail descriptor in the
+.Va desc
+parameter,
+and the
+.Dv JAIL_AT_DESC
+flag was set.
.It Bq Er EFAULT
.Fa Iov ,
or one of the addresses contained within it,
@@ -352,10 +556,33 @@ jail.
The
.Va lastjid
parameter is greater than the highest current jail ID.
+.It Bq Er ENOENT
+The jail referred to by a
+.Va desc
+parameter has been removed
+.Pq even if the Dv JAIL_CREATE flag has been set .
.It Bq Er EINVAL
A supplied parameter is the wrong size.
.It Bq Er EINVAL
A supplied parameter name does not match any known parameters.
+.It Bq Er EMFILE
+A jail descriptor could not be created for the
+.Va desc
+parameter with either the
+.Dv JAIL_GET_DESC
+or
+.Dv JAIL_OWN_DESC
+flag set,
+because the process has already reached its limit for open file descriptors.
+.It Bq Er ENFILE
+A jail descriptor could not be created for the
+.Va desc
+parameter with either the
+.Dv JAIL_GET_DESC
+or
+.Dv JAIL_OWN_DESC
+flag set,
+because the system file table is full.
.El
.Pp
The
@@ -373,11 +600,39 @@ The jail specified by
does not exist.
.El
.Pp
+The
+.Fn jail_attach_jd
+and
+.Fn jail_remove_jd
+system calls
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EBADF
+The
+.Fa fd
+argument is not a valid jail descriptor.
+.It Bq Er EACCES
+Permission is denied on the jail descriptor
+.Po
+execute permission for
+.Fn jail_attach_fd ,
+or write permission for
+.Fn jail_remove_fd
+.Pc .
+.It Bq Er EPERM
+The jail descriptor was created by a user other than the super-user.
+.It Bq Er EINVAL
+The jail specified by
+.Fa jid
+has been removed.
+.El
+.Pp
Further
.Fn jail ,
.Fn jail_set ,
+.Fn jail_attach ,
and
-.Fn jail_attach
+.Fn jail_attach_jd
call
.Xr chroot 2
internally, so they can fail for all the same reasons.
diff --git a/lib/libsys/kqueue.2 b/lib/libsys/kqueue.2
index d6e949baa24c..e413f7d4fbca 100644
--- a/lib/libsys/kqueue.2
+++ b/lib/libsys/kqueue.2
@@ -22,7 +22,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd March 26, 2023
+.Dd September 4, 2025
.Dt KQUEUE 2
.Os
.Sh NAME
@@ -593,6 +593,62 @@ returns the number of times the signal has occurred since the last call to
This filter automatically sets the
.Dv EV_CLEAR
flag internally.
+.It Dv EVFILT_JAIL
+Takes the jail ID to monitor as the identifier and the events to watch for
+in
+.Va fflags ,
+and returns when the jail performs one or more of the requested events.
+If a process can normally see a jail, it can attach an event to it.
+An identifier of zero will watch the process's own jail.
+The events to monitor are:
+.Bl -tag -width "Dv NOTE_JAIL_ATTACH"
+.It Dv NOTE_JAIL_SET
+The jail has been changed via
+.Xr jail_set 2 .
+.It Dv NOTE_JAIL_ATTACH
+A process has attached to the jail via
+.Xr jail_attach 2
+or a similar call.
+The process ID will be stored in
+.Va data .
+If more than one process has attached since the last call to
+.Fn kevent ,
+.Va data
+will contain the most recently attached process ID,
+with
+.Dv NOTE_JAIL_ATTACH_MULTI
+set in
+.Va fflags .
+.It Dv NOTE_JAIL_REMOVE
+The jail has been removed.
+.It Dv NOTE_JAIL_CHILD
+A child of the watched jail has been created.
+.It Dv NOTE_TRACK
+Follow child jails created under this jail.
+Register a new kevent to monitor the child jail using the same
+.Va fflags
+as the original event.
+The child jail will signal an event with
+.Dv NOTE_CHILD
+set in
+.Va fflags
+and the parent JID in
+.Va data .
+.Pp
+If registering a new kevent fails
+.Pq usually due to resource limitations ,
+it will signal an event with
+.Dv NOTE_TRACKERR
+set in
+.Va fflags ,
+and the child jail will not signal a
+.Dv NOTE_CHILD
+event.
+.El
+.Pp
+On return,
+.Va fflags
+contains the events which triggered the filter.
.It Dv EVFILT_TIMER
Establishes an arbitrary timer identified by
.Va ident .
diff --git a/lib/libsys/syscalls.map b/lib/libsys/syscalls.map
index 4cf80a2ffc69..b5400b9849b3 100644
--- a/lib/libsys/syscalls.map
+++ b/lib/libsys/syscalls.map
@@ -813,4 +813,8 @@ FBSDprivate_1.0 {
__sys_getgroups;
_setgroups;
__sys_setgroups;
+ _jail_attach_jd;
+ __sys_jail_attach_jd;
+ _jail_remove_jd;
+ __sys_jail_remove_jd;
};
diff --git a/libexec/rc/rc.conf b/libexec/rc/rc.conf
index bfa46bd343a6..0ef3012892dd 100644
--- a/libexec/rc/rc.conf
+++ b/libexec/rc/rc.conf
@@ -586,15 +586,19 @@ font8x14="NO" # font 8x14 from /usr/share/{syscons,vt}/fonts/* (or NO).
font8x8="NO" # font 8x8 from /usr/share/{syscons,vt}/fonts/* (or NO).
blanktime="300" # blank time (in seconds) or "NO" to turn it off.
saver="NO" # screen saver: Uses /boot/kernel/${saver}_saver.ko
-moused_nondefault_enable="YES" # Treat non-default mice as enabled unless
+moused_nondefault_enable="NO" # Treat non-default mice as enabled unless
# specifically overridden in rc.conf(5).
moused_enable="NO" # Run the mouse daemon.
moused_type="auto" # See man page for rc.conf(5) for available settings.
-moused_port="/dev/psm0" # Set to your mouse port.
+moused_port="auto" # Set to your mouse port.
moused_flags="" # Any additional flags to moused.
mousechar_start="NO" # if 0xd0-0xd3 default range is occupied in your
# language code table, specify alternative range
# start like mousechar_start=3, see vidcontrol(1)
+msconvd_enable="NO" # Run the mouse protocol conversion daemon.
+msconvd_type="auto" # See rc.conf(5) man page for available moused_type-s.
+msconvd_ports="" # List of msconvd ports.
+msconvd_flags="" # Any additional flags to msconvd.
allscreens_flags="" # Set this vidcontrol mode for all virtual screens
allscreens_kbdflags="" # Set this kbdcontrol mode for all virtual screens
diff --git a/libexec/rc/rc.d/Makefile b/libexec/rc/rc.d/Makefile
index 7c1f50b027a9..e5ee34e62185 100644
--- a/libexec/rc/rc.d/Makefile
+++ b/libexec/rc/rc.d/Makefile
@@ -273,6 +273,7 @@ JAILPACKAGE= jail
.if ${MK_LEGACY_CONSOLE} != "no"
CONFGROUPS+= CONSOLE
CONSOLE+= moused
+CONSOLE+= msconvd
CONSOLE+= syscons
CONSOLEPACKAGE= console-tools
.endif
diff --git a/libexec/rc/rc.d/bluetooth b/libexec/rc/rc.d/bluetooth
index 22bd5078034d..193fd969967f 100755
--- a/libexec/rc/rc.d/bluetooth
+++ b/libexec/rc/rc.d/bluetooth
@@ -127,8 +127,17 @@ bluetooth_setup_stack()
> /dev/null 2>&1 || return 1
# Initilalize HCI node
- ${hccontrol} -n ${dev}hci reset \
- > /dev/null 2>&1 || return 1
+ for loop in 1 2 3
+ do
+ ${hccontrol} -n ${dev}hci reset \
+ > /dev/null 2>&1 && break
+ if [ ${loop} -eq 3 ]
+ then
+ warn Reset failed three times, giving up.
+ return 1
+ fi
+ warn Reset failed, retrying.
+ done
${hccontrol} -n ${dev}hci read_bd_addr \
> /dev/null 2>&1 || return 1
diff --git a/libexec/rc/rc.d/moused b/libexec/rc/rc.d/moused
index 6f1b95af0f0a..aaf0dd0890a8 100755
--- a/libexec/rc/rc.d/moused
+++ b/libexec/rc/rc.d/moused
@@ -70,6 +70,7 @@ moused_start()
esac
for ttyv in /dev/ttyv* ; do
+ [ "$ttyv" = '/dev/ttyv*' ] && break
vidcontrol < ${ttyv} ${mousechar_arg} -m on
done
}
diff --git a/libexec/rc/rc.d/msconvd b/libexec/rc/rc.d/msconvd
new file mode 100755
index 000000000000..c2a96bf2eb68
--- /dev/null
+++ b/libexec/rc/rc.d/msconvd
@@ -0,0 +1,61 @@
+#!/bin/sh
+#
+#
+
+# PROVIDE: msconvd
+# REQUIRE: DAEMON FILESYSTEMS
+# KEYWORD: nojail shutdown
+
+. /etc/rc.subr
+
+name="msconvd"
+desc="Mouse protocol conversion daemon"
+command="/usr/sbin/${name}"
+start_cmd="msconvd_start"
+pidprefix="/var/run/msconvd"
+load_rc_config $name
+
+: ${msconvd_enable="NO"}
+: ${msconvd_type="auto"}
+
+# doesn't make sense to run in a svcj: nojail keyword
+# XXX: How does msconvd communiacte with the kernel?
+# XXX: Does the kernel prevent this communcation in jails?
+msconvd_svcj="NO"
+
+# Set the pid file and variable name. The second argument, if it exists, is
+# expected to be the mouse device.
+#
+if [ -n "$2" ]; then
+ eval msconvd_$2_enable=\${msconvd_$2_enable-${msconvd_enable}}
+ rcvar="msconvd_$2_enable"
+ pidfile="${pidprefix}.$2.pid"
+else
+ for ms in ${msconvd_ports}; do
+ /etc/rc.d/msconvd $1 ${ms}
+ done
+ exit 0
+fi
+
+msconvd_start()
+{
+ local ms myflags myport mytype
+
+ # Set the mouse device and get any related variables. If
+ # a msconvd device has been specified on the commandline, then
+ # rc.conf(5) variables defined for that device take precedence
+ # over the generic msconvd_* variables. The only exception is
+ # the msconvd_port variable, which if not defined sets it to
+ # the passed in device name.
+ #
+ ms=$1
+ eval myflags=\${msconvd_${ms}_flags-$msconvd_flags}
+ eval myport=\${msconvd_${ms}_port-/dev/${ms}}
+ eval mytype=\${msconvd_${ms}_type-$msconvd_type}
+
+ startmsg -n "Starting ${ms} ${name}"
+ ${command} ${myflags} -p ${myport} -t ${mytype} -I ${pidfile}
+ startmsg '.'
+}
+
+run_rc_command $*
diff --git a/libexec/rc/rc.d/serial b/libexec/rc/rc.d/serial
index ea60c8aa77da..f8ddc7ff30d4 100755
--- a/libexec/rc/rc.d/serial
+++ b/libexec/rc/rc.d/serial
@@ -45,7 +45,7 @@ default() {
# Reset everything changed by the other functions to initial defaults.
dc=$1; shift # device name character
- drainwait=`sysctl -n kern.drainwait`
+ drainwait=`sysctl -n kern.tty_drainwait`
for i in $*
do
@@ -84,7 +84,7 @@ modem() {
for i in $*
do
# may depend on modem
- comcontrol /dev/tty${dc}${i} dtrwait 100 drainwait 180
+ comcontrol /dev/tty${dc}${i} drainwait 180
# Lock crtscts on.
# Speed reasonable for V42bis.
stty < /dev/tty${dc}${i}.init crtscts 115200
@@ -156,12 +156,3 @@ terminal() {
# modem u 1
# terminal u 0
# 3wire u 0
-
-# Initialize all ports on a Cyclades-8yo.
-# modem c 00 01 02 03 04 05 06 07
-
-# Initialize all ports on a Cyclades-16ye.
-# modem c 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f
-
-# Initialize all ports on a Digiboard 8.
-# modem D 00 01 02 03 04 05 06 07
diff --git a/libexec/rc/rc.d/syscons b/libexec/rc/rc.d/syscons
index 325628a83d8c..b01b648ace6e 100755
--- a/libexec/rc/rc.d/syscons
+++ b/libexec/rc/rc.d/syscons
@@ -238,6 +238,7 @@ syscons_configure_keyboard()
sc_init
echo -n ' allscreens_kbd'
for ttyv in /dev/ttyv*; do
+ [ "$ttyv" = '/dev/ttyv*' ] && break
kbdcontrol ${allscreens_kbdflags} < ${ttyv} > ${ttyv} 2>&1
done
fi
@@ -382,6 +383,7 @@ syscons_start()
sc_init
echo -n ' allscreens'
for ttyv in /dev/ttyv*; do
+ [ "$ttyv" = '/dev/ttyv*' ] && break
vidcontrol ${allscreens_flags} < ${ttyv} > ${ttyv} 2>&1
done
fi
diff --git a/release/tools/azure.conf b/release/tools/azure.conf
index 519ab13fe432..a633e6e508d4 100644
--- a/release/tools/azure.conf
+++ b/release/tools/azure.conf
@@ -27,7 +27,8 @@ vm_extra_pre_umount() {
# them from the image allows it to boot faster.
chroot ${DESTDIR} ${EMULATOR} env ASSUME_ALWAYS_YES=yes \
/usr/sbin/pkg delete -f -y pkg
- rm -r ${DESTDIR}/var/db/pkg/repos/FreeBSD
+ rm -r ${DESTDIR}/var/db/pkg/repos/FreeBSD-ports
+ rm -r ${DESTDIR}/var/db/pkg/repos/FreeBSD-ports-kmods
chroot ${DESTDIR} ${EMULATOR} pw usermod root -h -
diff --git a/release/tools/ec2.conf b/release/tools/ec2.conf
index ef7a603efea9..31f40962b19d 100644
--- a/release/tools/ec2.conf
+++ b/release/tools/ec2.conf
@@ -27,7 +27,8 @@ ec2_common() {
chroot ${DESTDIR} ${EMULATOR} env ASSUME_ALWAYS_YES=yes \
/usr/sbin/pkg delete -f -y pkg
umount ${DESTDIR}/dev
- rm -r ${DESTDIR}/var/db/pkg/repos/FreeBSD
+ rm -r ${DESTDIR}/var/db/pkg/repos/FreeBSD-ports
+ rm -r ${DESTDIR}/var/db/pkg/repos/FreeBSD-ports-kmods
# Turn off IPv6 Duplicate Address Detection; the EC2 networking
# configuration makes it unnecessary.
diff --git a/release/tools/vagrant.conf b/release/tools/vagrant.conf
index c212af7d012e..506174d0ea16 100644
--- a/release/tools/vagrant.conf
+++ b/release/tools/vagrant.conf
@@ -20,7 +20,8 @@ vagrant_common () {
# them from the image allows it to boot faster.
env ASSUME_ALWAYS_YES=yes pkg -c ${DESTDIR} clean -y -a
env ASSUME_ALWAYS_YES=yes pkg -c ${DESTDIR} delete -f -y pkg
- rm -r ${DESTDIR}/var/db/pkg/repos/FreeBSD
+ rm -r ${DESTDIR}/var/db/pkg/repos/FreeBSD-ports
+ rm -r ${DESTDIR}/var/db/pkg/repos/FreeBSD-ports-kmods
# Vagrant instances use DHCP to get their network configuration.
echo 'ifconfig_DEFAULT="SYNCDHCP"' >> ${DESTDIR}/etc/rc.conf
diff --git a/sbin/comcontrol/comcontrol.8 b/sbin/comcontrol/comcontrol.8
index bee0fdab102b..f51a1f011167 100644
--- a/sbin/comcontrol/comcontrol.8
+++ b/sbin/comcontrol/comcontrol.8
@@ -1,13 +1,17 @@
-.Dd May 15, 1994
+.Dd August 31, 2025
.Dt COMCONTROL 8
.Os
.Sh NAME
.Nm comcontrol
.Nd control a special tty device
+.Sh DEPRECATION NOTICE
+The
+.Nm
+utility is deprecated and will be removed in
+.Fx 16.0 .
.Sh SYNOPSIS
.Nm
.Ar special_device
-.Op dtrwait Ar number
.Op drainwait Ar number
.Sh DESCRIPTION
The
@@ -22,13 +26,6 @@ Only the superuser can change the settings.
.Pp
The following options are available:
.Bl -tag -width indent
-.It Cm dtrwait Ar number
-Set the time to wait after dropping DTR
-to the given number.
-The units are hundredths of a second.
-The default is 300 hundredths, i.e., 3 seconds.
-This option needed mainly to set proper recover time after
-modem reset.
.It Cm drainwait Ar number
Set the time to wait for output drain
to the given number.
@@ -57,7 +54,6 @@ dialout devices
Originally part of cgd's com package patches, version 0.2.1, to
.Bx 386 0.1 .
Once controlled bidirectional capabilities.
-Little is left to control now
-that these capabilities are standard.
+Little is left to control now that these capabilities are standard.
.Sh AUTHORS
.An Christopher G. Demetriou
diff --git a/sbin/comcontrol/comcontrol.c b/sbin/comcontrol/comcontrol.c
index 7a03b3a569cf..d6d24e8acab8 100644
--- a/sbin/comcontrol/comcontrol.c
+++ b/sbin/comcontrol/comcontrol.c
@@ -46,7 +46,7 @@ static void
usage(void)
{
fprintf(stderr,
- "usage: comcontrol <filename> [dtrwait <n>] [drainwait <n>]\n");
+ "usage: comcontrol <filename> [drainwait <n>]\n");
exit(1);
}
@@ -55,8 +55,8 @@ main(int argc, char *argv[])
{
int fd;
int res = 0;
- int print_dtrwait = 1, print_drainwait = 1;
- int dtrwait = -1, drainwait = -1;
+ int print_drainwait = 1;
+ int drainwait = -1;
if (argc < 2)
usage();
@@ -71,13 +71,6 @@ main(int argc, char *argv[])
}
}
if (argc == 2) {
- if (ioctl(fd, TIOCMGDTRWAIT, &dtrwait) < 0) {
- print_dtrwait = 0;
- if (errno != ENOTTY) {
- res = 1;
- warn("TIOCMGDTRWAIT");
- }
- }
if (ioctl(fd, TIOCGDRAINWAIT, &drainwait) < 0) {
print_drainwait = 0;
if (errno != ENOTTY) {
@@ -85,21 +78,12 @@ main(int argc, char *argv[])
warn("TIOCGDRAINWAIT");
}
}
- if (print_dtrwait)
- printf("dtrwait %d ", dtrwait);
if (print_drainwait)
printf("drainwait %d ", drainwait);
printf("\n");
} else {
while (argv[2] != NULL) {
- if (!strcmp(argv[2],"dtrwait")) {
- if (dtrwait >= 0)
- usage();
- if (argv[3] == NULL || !isdigit(argv[3][0]))
- usage();
- dtrwait = atoi(argv[3]);
- argv += 2;
- } else if (!strcmp(argv[2],"drainwait")) {
+ if (!strcmp(argv[2],"drainwait")) {
if (drainwait >= 0)
usage();
if (argv[3] == NULL || !isdigit(argv[3][0]))
@@ -109,12 +93,6 @@ main(int argc, char *argv[])
} else
usage();
}
- if (dtrwait >= 0) {
- if (ioctl(fd, TIOCMSDTRWAIT, &dtrwait) < 0) {
- res = 1;
- warn("TIOCMSDTRWAIT");
- }
- }
if (drainwait >= 0) {
if (ioctl(fd, TIOCSDRAINWAIT, &drainwait) < 0) {
res = 1;
diff --git a/sbin/pfctl/parse.y b/sbin/pfctl/parse.y
index 00c36b218055..dce5800df27a 100644
--- a/sbin/pfctl/parse.y
+++ b/sbin/pfctl/parse.y
@@ -166,8 +166,8 @@ struct node_gid {
};
struct node_icmp {
- u_int8_t code;
- u_int8_t type;
+ uint16_t code;
+ uint16_t type;
u_int8_t proto;
struct node_icmp *next;
struct node_icmp *tail;
@@ -238,6 +238,7 @@ static struct pool_opts {
#define POM_TYPE 0x01
#define POM_STICKYADDRESS 0x02
#define POM_ENDPI 0x04
+#define POM_IPV6NH 0x08
u_int8_t opts;
int type;
int staticport;
@@ -543,7 +544,7 @@ int parseport(char *, struct range *r, int);
%token MAXSRCCONN MAXSRCCONNRATE OVERLOAD FLUSH SLOPPY PFLOW ALLOW_RELATED
%token TAGGED TAG IFBOUND FLOATING STATEPOLICY STATEDEFAULTS ROUTE SETTOS
%token DIVERTTO DIVERTREPLY BRIDGE_TO RECEIVEDON NE LE GE AFTO NATTO RDRTO
-%token BINATTO MAXPKTRATE MAXPKTSIZE
+%token BINATTO MAXPKTRATE MAXPKTSIZE IPV6NH
%token <v.string> STRING
%token <v.number> NUMBER
%token <v.i> PORTBINARY
@@ -2648,13 +2649,16 @@ pfrule : action dir logquick interface route af proto fromto
YYERROR;
}
r.rt = $5.rt;
- decide_address_family($5.redirspec->host, &r.af);
- if (!(r.rule_flag & PFRULE_AFTO))
- remove_invalid_hosts(&($5.redirspec->host), &r.af);
- if ($5.redirspec->host == NULL) {
- yyerror("no routing address with "
- "matching address family found.");
- YYERROR;
+
+ if (!($5.redirspec->pool_opts.opts & PF_POOL_IPV6NH)) {
+ decide_address_family($5.redirspec->host, &r.af);
+ if (!(r.rule_flag & PFRULE_AFTO))
+ remove_invalid_hosts(&($5.redirspec->host), &r.af);
+ if ($5.redirspec->host == NULL) {
+ yyerror("no routing address with "
+ "matching address family found.");
+ YYERROR;
+ }
}
}
#ifdef __FreeBSD__
@@ -2978,7 +2982,8 @@ filter_opt : USER uids {
filter_opts.nat = $4;
filter_opts.nat->af = $2;
- if ($4->af && $4->af != $2) {
+ remove_invalid_hosts(&($4->host), &(filter_opts.nat->af));
+ if ($4->host == NULL) {
yyerror("af-to addresses must be in the "
"target address family");
YYERROR;
@@ -2998,8 +3003,9 @@ filter_opt : USER uids {
filter_opts.nat->af = $2;
filter_opts.rdr = $6;
filter_opts.rdr->af = $2;
- if (($4->af && $4->host->af != $2) ||
- ($6->af && $6->host->af != $2)) {
+ remove_invalid_hosts(&($4->host), &(filter_opts.nat->af));
+ remove_invalid_hosts(&($6->host), &(filter_opts.rdr->af));
+ if ($4->host == NULL || $6->host == NULL) {
yyerror("af-to addresses must be in the "
"target address family");
YYERROR;
@@ -4674,6 +4680,14 @@ pool_opt : BITMASK {
pool_opts.marker |= POM_ENDPI;
pool_opts.opts |= PF_POOL_ENDPI;
}
+ | IPV6NH {
+ if (pool_opts.marker & POM_IPV6NH) {
+ yyerror("prefer-ipv6-nexthop cannot be redefined");
+ YYERROR;
+ }
+ pool_opts.marker |= POM_IPV6NH;
+ pool_opts.opts |= PF_POOL_IPV6NH;
+ }
| MAPEPORTSET number '/' number '/' number {
if (pool_opts.mape.offset) {
yyerror("map-e-portset cannot be redefined");
@@ -4813,6 +4827,12 @@ natrule : nataction interface af proto fromto tag tagged rtable
"address'");
YYERROR;
}
+ if ($9->pool_opts.opts & PF_POOL_IPV6NH) {
+ yyerror("The prefer-ipv6-nexthop option "
+ "can't be used for nat/rdr/binat pools"
+ );
+ YYERROR;
+ }
if (!r.af && ! $9->host->ifindex)
r.af = $9->host->af;
@@ -5074,13 +5094,6 @@ route_host : STRING {
route_host_list : route_host optnl { $$ = $1; }
| route_host_list comma route_host optnl {
- if ($1->af == 0)
- $1->af = $3->af;
- if ($1->af != $3->af) {
- yyerror("all pool addresses must be in the "
- "same address family");
- YYERROR;
- }
$1->tail->next = $3;
$1->tail = $3->tail;
$$ = $1;
@@ -6678,6 +6691,7 @@ lookup(char *s)
{ "pass", PASS},
{ "pflow", PFLOW},
{ "port", PORT},
+ { "prefer-ipv6-nexthop", IPV6NH},
{ "prio", PRIO},
{ "priority", PRIORITY},
{ "priq", PRIQ},
diff --git a/sbin/pfctl/pfctl_parser.c b/sbin/pfctl/pfctl_parser.c
index 18b78a150c28..ce58e0636022 100644
--- a/sbin/pfctl/pfctl_parser.c
+++ b/sbin/pfctl/pfctl_parser.c
@@ -242,7 +242,7 @@ copy_satopfaddr(struct pf_addr *pfa, struct sockaddr *sa)
const struct icmptypeent *
geticmptypebynumber(u_int8_t type, sa_family_t af)
{
- unsigned int i;
+ size_t i;
if (af != AF_INET6) {
for (i=0; i < nitems(icmp_type); i++) {
@@ -261,7 +261,7 @@ geticmptypebynumber(u_int8_t type, sa_family_t af)
const struct icmptypeent *
geticmptypebyname(char *w, sa_family_t af)
{
- unsigned int i;
+ size_t i;
if (af != AF_INET6) {
for (i=0; i < nitems(icmp_type); i++) {
@@ -280,7 +280,7 @@ geticmptypebyname(char *w, sa_family_t af)
const struct icmpcodeent *
geticmpcodebynumber(u_int8_t type, u_int8_t code, sa_family_t af)
{
- unsigned int i;
+ size_t i;
if (af != AF_INET6) {
for (i=0; i < nitems(icmp_code); i++) {
@@ -301,7 +301,7 @@ geticmpcodebynumber(u_int8_t type, u_int8_t code, sa_family_t af)
const struct icmpcodeent *
geticmpcodebyname(u_long type, char *w, sa_family_t af)
{
- unsigned int i;
+ size_t i;
if (af != AF_INET6) {
for (i=0; i < nitems(icmp_code); i++) {
@@ -508,6 +508,8 @@ print_pool(struct pfctl_pool *pool, u_int16_t p1, u_int16_t p2, int id)
if (pool->mape.offset > 0)
printf(" map-e-portset %u/%u/%u",
pool->mape.offset, pool->mape.psidlen, pool->mape.psid);
+ if (pool->opts & PF_POOL_IPV6NH)
+ printf(" prefer-ipv6-nexthop");
}
void
@@ -1438,7 +1440,7 @@ ifa_add_groups_to_map(char *ifa_name)
ENTRY item;
ENTRY *ret_item;
int *answer;
-
+
item.key = ifg->ifgrq_group;
if (hsearch_r(item, FIND, &ret_item, &isgroup_map) == 0) {
struct ifgroupreq ifgr2;
@@ -1580,7 +1582,7 @@ is_a_group(char *name)
{
ENTRY item;
ENTRY *ret_item;
-
+
item.key = name;
if (hsearch_r(item, FIND, &ret_item, &isgroup_map) == 0)
return (0);
diff --git a/sbin/pfctl/tests/files/pf1073.in b/sbin/pfctl/tests/files/pf1073.in
new file mode 100644
index 000000000000..477995893ac3
--- /dev/null
+++ b/sbin/pfctl/tests/files/pf1073.in
@@ -0,0 +1 @@
+pass in on vtnet0 route-to ( vtnet1 2001:db8::1 ) prefer-ipv6-nexthop inet
diff --git a/sbin/pfctl/tests/files/pf1073.ok b/sbin/pfctl/tests/files/pf1073.ok
new file mode 100644
index 000000000000..f34867508c75
--- /dev/null
+++ b/sbin/pfctl/tests/files/pf1073.ok
@@ -0,0 +1 @@
+pass in on vtnet0 route-to (vtnet1 2001:db8::1) prefer-ipv6-nexthop inet all flags S/SA keep state
diff --git a/sbin/pfctl/tests/files/pf1074.fail b/sbin/pfctl/tests/files/pf1074.fail
new file mode 100644
index 000000000000..afe8ee3c458f
--- /dev/null
+++ b/sbin/pfctl/tests/files/pf1074.fail
@@ -0,0 +1 @@
+no routing address with matching address family found.
diff --git a/sbin/pfctl/tests/files/pf1074.in b/sbin/pfctl/tests/files/pf1074.in
new file mode 100644
index 000000000000..5d285bc5d6e8
--- /dev/null
+++ b/sbin/pfctl/tests/files/pf1074.in
@@ -0,0 +1 @@
+pass in on vtnet0 route-to ( vtnet1 2001:db8::1 ) inet
diff --git a/sbin/pfctl/tests/pfctl_test_list.inc b/sbin/pfctl/tests/pfctl_test_list.inc
index 3a68cc06ec74..8bfccddf50e5 100644
--- a/sbin/pfctl/tests/pfctl_test_list.inc
+++ b/sbin/pfctl/tests/pfctl_test_list.inc
@@ -181,3 +181,5 @@ PFCTL_TEST(1069, "max-pkt-size")
PFCTL_TEST_FAIL(1070, "include line number")
PFCTL_TEST(1071, "mask length on (lo0)")
PFCTL_TEST_FAIL(1072, "Invalid port range")
+PFCTL_TEST(1073, "Filter AF different than route-to AF, with prefer-ipv6-nexthop")
+PFCTL_TEST_FAIL(1074, "Filter AF different than route-to AF, without prefer-ipv6-nexthop")
diff --git a/sbin/recoverdisk/recoverdisk.1 b/sbin/recoverdisk/recoverdisk.1
index 9f1deb4c0c23..90849755ea0c 100644
--- a/sbin/recoverdisk/recoverdisk.1
+++ b/sbin/recoverdisk/recoverdisk.1
@@ -31,6 +31,7 @@
.Sh SYNOPSIS
.Nm
.Op Fl b Ar bigsize
+.Op Fl i Ar interval
.Op Fl r Ar readlist
.Op Fl s Ar interval
.Op Fl u Ar pattern
@@ -109,6 +110,11 @@ reports for character and block devices or
if
.Ar source
is a regular file.
+.It Fl i Ar pause
+.Xr sleep 3
+this long between reads. This reduces the load on the
+.Ar source
+device and the system in general.
.It Fl p Ar pause
.Xr sleep 3
this long whenever a read fails. This makes the
diff --git a/sbin/recoverdisk/recoverdisk.c b/sbin/recoverdisk/recoverdisk.c
index f13a1f211863..5971f78738ac 100644
--- a/sbin/recoverdisk/recoverdisk.c
+++ b/sbin/recoverdisk/recoverdisk.c
@@ -28,6 +28,11 @@
#include <time.h>
#include <unistd.h>
+/*
+ * This is a compromise between speed and wasted effort
+ */
+#define COMPROMISE_SIZE (128<<10)
+
struct lump {
uint64_t start;
uint64_t len;
@@ -51,6 +56,7 @@ static uint64_t medium_read;
static uint64_t small_read;
static uint64_t total_size;
static uint64_t done_size;
+static uint64_t wasted_size;
static char *input;
static char *write_worklist_file = NULL;
static char *read_worklist_file = NULL;
@@ -61,6 +67,7 @@ static FILE *log_file = NULL;
static char *work_buf;
static char *pattern_buf;
static double error_pause;
+static double interval;
static unsigned nlumps;
static double n_reads, n_good_reads;
@@ -418,7 +425,8 @@ fill_buf(char *buf, int64_t len, const char *pattern)
static void
usage(void)
{
- fprintf(stderr, "usage: recoverdisk [-b big_read] [-r readlist] "
+ fprintf(stderr, "usage: recoverdisk "
+ "[-b big_read] [-i interval ] [-r readlist] "
"[-s interval] [-w writelist] source [destination]\n");
/* XXX update */
exit(1);
@@ -486,6 +494,7 @@ attempt_one_lump(time_t t_now)
fflush(log_file);
}
} else {
+ wasted_size += sz;
printf("%14ju %7ju read error %d: (%s)",
(uintmax_t)lp->start,
(uintmax_t)sz, error, strerror(error));
@@ -557,8 +566,6 @@ determine_read_sizes(void)
u_int sectorsize;
off_t stripesize;
- determine_total_size();
-
#ifdef DIOCGSECTORSIZE
if (small_read == 0) {
error = ioctl(read_fd, DIOCGSECTORSIZE, &sectorsize);
@@ -572,8 +579,8 @@ determine_read_sizes(void)
#endif
if (small_read == 0) {
- printf("Assuming 512 for small_read\n");
small_read = 512;
+ printf("# Defaulting small_read to %ju\n", (uintmax_t)small_read);
}
if (medium_read && (medium_read % small_read)) {
@@ -593,13 +600,13 @@ determine_read_sizes(void)
#ifdef DIOCGSTRIPESIZE
if (medium_read == 0) {
error = ioctl(read_fd, DIOCGSTRIPESIZE, &stripesize);
- if (error < 0 || stripesize < 0) {
+ if (error < 0 || stripesize <= 0) {
// nope
} else if ((uint64_t)stripesize < small_read) {
// nope
} else if (stripesize % small_read) {
// nope
- } else if (0 < stripesize && stripesize < (128<<10)) {
+ } else if (stripesize <= COMPROMISE_SIZE) {
medium_read = stripesize;
printf("# Got medium_read from DIOCGSTRIPESIZE: %ju\n",
(uintmax_t)medium_read
@@ -607,6 +614,7 @@ determine_read_sizes(void)
}
}
#endif
+
#if defined(DIOCGFWSECTORS) && defined(DIOCGFWHEADS)
if (medium_read == 0) {
u_int fwsectors = 0, fwheads = 0;
@@ -616,10 +624,16 @@ determine_read_sizes(void)
error = ioctl(read_fd, DIOCGFWHEADS, &fwheads);
if (error)
fwheads = 0;
- if (fwsectors && fwheads) {
+ if (fwsectors * fwheads * small_read <= COMPROMISE_SIZE) {
medium_read = fwsectors * fwheads * small_read;
printf(
- "# Got medium_read from DIOCGFW{SECTORS,HEADS}: %ju\n",
+ "# Got medium_read from DIOCGFW{SECTORS*HEADS}: %ju\n",
+ (uintmax_t)medium_read
+ );
+ } else if (fwsectors * small_read <= COMPROMISE_SIZE) {
+ medium_read = fwsectors * small_read;
+ printf(
+ "# Got medium_read from DIOCGFWSECTORS: %ju\n",
(uintmax_t)medium_read
);
}
@@ -627,10 +641,11 @@ determine_read_sizes(void)
#endif
if (big_read == 0 && medium_read != 0) {
- if (medium_read > (64<<10)) {
+ if (medium_read * 2 > COMPROMISE_SIZE) {
big_read = medium_read;
+ medium_read = 0;
} else {
- big_read = 128 << 10;
+ big_read = COMPROMISE_SIZE;
big_read -= big_read % medium_read;
}
printf("# Got big_read from medium_read: %ju\n",
@@ -639,12 +654,16 @@ determine_read_sizes(void)
}
if (big_read == 0) {
- big_read = 128 << 10;
+ big_read = COMPROMISE_SIZE;
+ big_read -= big_read % small_read;
printf("# Defaulting big_read to %ju\n",
(uintmax_t)big_read
);
}
+ if (medium_read >= big_read)
+ medium_read = 0;
+
if (medium_read == 0) {
/*
* We do not want to go directly to single sectors, but
@@ -662,12 +681,20 @@ determine_read_sizes(void)
(uintmax_t)medium_read
);
}
- fprintf(stderr,
- "# Bigsize = %ju, medium_read = %ju, small_read = %ju\n",
+ printf("# Bigsize = %ju, medium_read = %ju, small_read = %ju\n",
(uintmax_t)big_read, (uintmax_t)medium_read, (uintmax_t)small_read);
-}
+ assert(0 < small_read);
+
+ assert(0 < medium_read);
+ assert(medium_read >= small_read);
+ assert(medium_read <= big_read);
+ assert(medium_read % small_read == 0);
+ assert(0 < big_read);
+ assert(big_read >= medium_read);
+ assert(big_read % small_read == 0);
+}
/**********************************************************************/
@@ -687,15 +714,14 @@ monitor_read_sizes(uint64_t failed_size)
);
big_read = medium_read;
medium_read = small_read;
+ wasted_size = 0;
return;
}
- if (failed_size > small_read) {
- if (n_reads < n_good_reads + 100)
- return;
+ if (big_read > small_read && wasted_size / small_read > 200) {
fprintf(
stderr,
- "Too many failures."
+ "Too much wasted effort."
" (%.0f bad of %.0f)"
" Shifting to small_reads.\n",
n_reads - n_good_reads, n_reads
@@ -719,11 +745,14 @@ main(int argc, char * const argv[])
setbuf(stdout, NULL);
setbuf(stderr, NULL);
- while ((ch = getopt(argc, argv, "b:l:p:m:r:w:s:t:u:v")) != -1) {
+ while ((ch = getopt(argc, argv, "b:i:l:p:m:r:w:s:t:u:v")) != -1) {
switch (ch) {
case 'b':
big_read = strtoul(optarg, NULL, 0);
break;
+ case 'i':
+ interval = strtod(optarg, NULL);
+ break;
case 'l':
log_file = fopen(optarg, "a");
if (log_file == NULL) {
@@ -774,6 +803,8 @@ main(int argc, char * const argv[])
if (read_fd < 0)
err(1, "Cannot open read descriptor %s", argv[0]);
+ determine_total_size();
+
determine_read_sizes();
work_buf = malloc(big_read);
@@ -816,6 +847,9 @@ main(int argc, char * const argv[])
t_save = t_first;
unsaved = 0;
while (!aborting) {
+ if (interval > 0) {
+ usleep((unsigned long)(1e6 * interval));
+ }
t_now = time(NULL);
sz = attempt_one_lump(t_now);
error = errno;
diff --git a/sbin/veriexec/veriexec.8 b/sbin/veriexec/veriexec.8
index 8e99f1d61faf..8352dd8e5e49 100644
--- a/sbin/veriexec/veriexec.8
+++ b/sbin/veriexec/veriexec.8
@@ -195,7 +195,7 @@ and be strict about enforcing certificate validity:
.Ed
.Nm
-will look for a detatched signature that it recognizes, such as
+will look for a detached signature that it recognizes, such as
.Pa manifest.asc
(OpenPGP) or
.Pa manifest.*sig
diff --git a/secure/lib/libcrypto/Makefile b/secure/lib/libcrypto/Makefile
index f8f8d291ee9e..75ebb6e65327 100644
--- a/secure/lib/libcrypto/Makefile
+++ b/secure/lib/libcrypto/Makefile
@@ -649,10 +649,11 @@ _cmd1=/%%NO_ASM%%/d
.else
_cmd1=s/%%NO_ASM%%//
.endif
-.if ${MK_OPENSSL_KTLS} != "no"
+.if ${MK_OPENSSL_KTLS} != "no" && !defined(BOOTSTRAPPING)
_cmd2=/%%NO_KTLS%%/d
.else
_cmd2=s/%%NO_KTLS%%//
+CFLAGS+= -DOPENSSL_NO_KTLS
.endif
buildinf.h: Makefile
diff --git a/secure/lib/libcrypto/modules/legacy/Makefile b/secure/lib/libcrypto/modules/legacy/Makefile
index c16919ddcd94..db05f212f62a 100644
--- a/secure/lib/libcrypto/modules/legacy/Makefile
+++ b/secure/lib/libcrypto/modules/legacy/Makefile
@@ -1,7 +1,7 @@
SHLIB_NAME?= legacy.so
LIBADD= crypto
-SRCS+= legacyprov.c prov_running.c
+SRCS+= legacyprov.c prov_running.c params_idx.c
# ciphers
SRCS+= ciphercommon.c ciphercommon_hw.c ciphercommon_block.c \
@@ -21,11 +21,12 @@ SRCS+= digestcommon.c
SRCS+= md4_prov.c wp_prov.c ripemd_prov.c
# kdfs
-SRCS+= pbkdf1.c
+SRCS+= pbkdf1.c pvkkdf.c
.include <bsd.lib.mk>
-.PATH: ${LCRYPTO_SRC}/providers/implementations/ciphers \
+.PATH: ${LCRYPTO_SRC}/crypto \
+ ${LCRYPTO_SRC}/providers/implementations/ciphers \
${LCRYPTO_SRC}/providers/implementations/digests \
${LCRYPTO_SRC}/providers/implementations/kdfs \
${LCRYPTO_SRC}/ssl
diff --git a/secure/lib/libssl/Makefile b/secure/lib/libssl/Makefile
index acb63549c1c8..b0ca31644279 100644
--- a/secure/lib/libssl/Makefile
+++ b/secure/lib/libssl/Makefile
@@ -70,7 +70,7 @@ SRSC+= tls_pad.c
SRCS+= poll_immediate.c
SRCS+= rio_notifier.c poll_builder.c
-.if ${MK_OPENSSL_KTLS} == "no"
+.if ${MK_OPENSSL_KTLS} == "no" || defined(BOOTSTRAPPING)
CFLAGS+=-DOPENSSL_NO_KTLS
.else
SRCS+= ktls_meth.c
diff --git a/share/man/man4/Makefile b/share/man/man4/Makefile
index 519b113b0a2e..1d708cfda019 100644
--- a/share/man/man4/Makefile
+++ b/share/man/man4/Makefile
@@ -8,6 +8,9 @@ MANPACKAGE= kernel
# the doc repository); otherwise the automatically generated hardware
# notes will not include your driver.
+# If you enable a driver for a different architecture, please remember
+# to update the arch specifier in the document title of the manual.
+
MAN= aac.4 \
aacraid.4 \
acpi.4 \
diff --git a/share/man/man4/dtrace_lockstat.4 b/share/man/man4/dtrace_lockstat.4
index e308ca6c22ce..448de91a375f 100644
--- a/share/man/man4/dtrace_lockstat.4
+++ b/share/man/man4/dtrace_lockstat.4
@@ -22,12 +22,12 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd August 20, 2019
+.Dd September 3, 2025
.Dt DTRACE_LOCKSTAT 4
.Os
.Sh NAME
.Nm dtrace_lockstat
-.Nd a DTrace provider for tracing CPU scheduling events
+.Nd a DTrace provider for tracing kernel locking events
.Sh SYNOPSIS
.Fn lockstat:::adaptive-acquire "struct mtx *"
.Fn lockstat:::adaptive-release "struct mtx *"
diff --git a/share/man/man4/epair.4 b/share/man/man4/epair.4
index 342b15b5612a..b406c423361b 100644
--- a/share/man/man4/epair.4
+++ b/share/man/man4/epair.4
@@ -25,7 +25,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd August 12, 2025
+.Dd September 4, 2025
.Dt EPAIR 4
.Os
.Sh NAME
@@ -108,6 +108,29 @@ As with any other Ethernet interface,
can have a
.Xr vlan 4
configured on top of it.
+.Pp
+The
+.Nm
+has RXCSUM and RXCSUM6 enabled because it may receive a packet where the
+checksum has already been validated by a physical interface.
+The
+.Nm
+supports TXCSUM and TXCSUM6 for TCP and UDP, but only by forwarding the order
+to compute the checksum.
+Thus, when using an
+.Nm
+interface, a TCP or UDP sender can offload checksum computation
+to a physical interface.
+Note that, in case the packet does not leave the host, the checksum is
+unnecessary and will be ignored if offloaded.
+Such packets contain an incorrect checksum, since it is not computed yet.
+TXCSUM and TXCSUM6 are synchronized between the
+.Nm
+interface pair (i.e., enabling/disabling the capability on one end
+enables/disables it on the other end).
+In case one end is in a bridge and the bridge disabled TXCSUM or TXCSUM6,
+this avoids a sender to send packets with checksum offloading into the
+bridge by using the other end.
.Sh SEE ALSO
.Xr ioctl 2 ,
.Xr altq 4 ,
diff --git a/share/man/man4/pci.4 b/share/man/man4/pci.4
index 91fbb557f644..b99747969035 100644
--- a/share/man/man4/pci.4
+++ b/share/man/man4/pci.4
@@ -22,7 +22,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd April 2, 2025
+.Dd August 31, 2025
.Dt PCI 4
.Os
.Sh NAME
@@ -235,6 +235,17 @@ revision ID.
Driver name.
.It pd_unit
Driver unit number.
+.It pd_numa_domain
+Driver NUMA domain.
+.It pc_reported_len
+Length of the valid portion of the encompassing
+.Vt pci_conf
+structure.
+This should always be equivalent to the offset of the
+.Va pc_spare
+member.
+.It pc_spare
+Reserved for future use.
.El
.It offset
The offset is passed in by the user to tell the kernel where it should
diff --git a/share/man/man4/syncache.4 b/share/man/man4/syncache.4
index e92502fd15ff..f83e9b083e45 100644
--- a/share/man/man4/syncache.4
+++ b/share/man/man4/syncache.4
@@ -10,7 +10,7 @@
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\"
-.Dd April 12, 2021
+.Dd August 30, 2025
.Dt SYNCACHE 4
.Os
.Sh NAME
@@ -39,6 +39,8 @@ MIBs for controlling TCP SYN caching
.Nm sysctl Cm net.inet.tcp.syncache.count
.It
.Nm sysctl Cm net.inet.tcp.syncache.see_other
+.It
+.Nm sysctl Cm net.inet.tcp.syncache.rst_on_sock_fail
.El
.Sh DESCRIPTION
The
@@ -107,6 +109,18 @@ and run only with
set
.Va net.inet.tcp.syncookies_only
to 1.
+To use
+.Nm syncookies
+to handle bucket overflows in the
+.Nm syncache
+set
+.Va net.inet.tcp.syncookies
+to 1.
+The default value for
+.Va net.inet.tcp.syncookies_only
+is 0 and the default value for
+.Va net.inet.tcp.syncookies
+is 1.
.Pp
The
.Nm
@@ -169,6 +183,9 @@ However, extra
.Xr ucred 9
referencing is required on every incoming SYN packet processed.
The default is off.
+.It Va rst_on_sock_fail
+Send a TCP RST segment if the socket allocation fails.
+The default is on.
.El
.Pp
Statistics on the performance of the
@@ -206,8 +223,16 @@ Entries dropped due to ICMP unreachable messages.
Failures to allocate new
.Nm
entry.
+.It Li "cookies sent"
+SYN cookies sent in SYN ACK segments.
.It Li "cookies received"
-Connections created from segment containing ACK.
+ACK segments with valid syncookies which resulted in TCP connection
+establishment.
+.It Li "spurious cookies rejected"
+Received ACKs, for which the syncache lookup failed and also no syncookie was
+recently sent.
+.It Li "failed cookies rejected"
+Received ACKs for which the syncookie validation failed.
.El
.Sh SEE ALSO
.Xr netstat 1 ,
diff --git a/share/man/man4/tcp.4 b/share/man/man4/tcp.4
index fcfda42908d8..3c9f4ff83f3d 100644
--- a/share/man/man4/tcp.4
+++ b/share/man/man4/tcp.4
@@ -31,7 +31,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd June 27, 2025
+.Dd September 5, 2025
.Dt TCP 4
.Os
.Sh NAME
@@ -940,9 +940,6 @@ maximum segment size.
This helps throughput in general, but
particularly affects short transfers and high-bandwidth large
propagation-delay connections.
-.It Va rfc6675_pipe
-Deprecated and superseded by
-.Va sack.revised
.It Va sack.enable
Enable support for RFC 2018, TCP Selective Acknowledgment option,
which allows the receiver to inform the sender about all successfully
@@ -974,6 +971,11 @@ recovery, the trailing segment is immediately resent, rather than waiting
for a Retransmission timeout.
Finally, SACK loss recovery is also engaged, once two segments plus one byte are
SACKed - even if no traditional duplicate ACKs were observed.
+.Va sack.revised
+is deprecated and will be removed in
+.Fx 16 .
+.Va sack.enable
+will always follow RFC6675.
.It Va sendbuf_auto
Enable automatic send buffer sizing.
.It Va sendbuf_auto_lowat
diff --git a/share/man/man4/umb.4 b/share/man/man4/umb.4
index 311a50faf8e7..37c86b3074f5 100644
--- a/share/man/man4/umb.4
+++ b/share/man/man4/umb.4
@@ -17,14 +17,13 @@
.\"
.\" $NetBSD: umb.4,v 1.4 2019/08/30 09:22:17 wiz Exp $
.\"
-.Dd August 4, 2025
+.Dd September 3, 2025
.Dt UMB 4
.Os
.Sh NAME
.Nm umb
.Nd USB Mobile Broadband Interface Model (MBIM) cellular modem driver
.Sh SYNOPSIS
-.Cd "device netmap"
.Cd "device usb"
.Cd "device umb"
.Pp
diff --git a/share/man/man4/vtnet.4 b/share/man/man4/vtnet.4
index b6f10ddd87cb..67a835050422 100644
--- a/share/man/man4/vtnet.4
+++ b/share/man/man4/vtnet.4
@@ -22,7 +22,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd August 21, 2025
+.Dd September 4, 2025
.Dt VTNET 4
.Os
.Sh NAME
@@ -127,7 +127,6 @@ This option applies to all interfaces.
The default value is 0.
.El
.Sh TRANSMIT QUEUE STATISTICS
-.Bl -tag -width "xxxxxx"
For each transmit queue of each interface the following read-only statistics
are provided:
.Bl -tag -width "xxxxxx"
@@ -154,7 +153,14 @@ The number of times the receive interrupt handler was rescheduled.
.It Va dev.vtnet. Ns Ar X Ns Va .rxq Ns Ar Y Ns Va .host_lro
The number of times TCP large receive offload was performed.
.It Va dev.vtnet. Ns Ar X Ns Va .rxq Ns Ar Y Ns Va .csum_failed
-Currently not used.
+The number of times a packet with a request for receive or transmit checksum
+offloading was received and this request failed.
+The different reasons for the failure are counted by
+.Va dev.vtnet. Ns Ar X Ns Va .rx_csum_inaccessible_ipproto ,
+.Va dev.vtnet. Ns Ar X Ns Va .rx_csum_bad_ipproto ,
+.Va dev.vtnet. Ns Ar X Ns Va .rx_csum_bad_ethtype ,
+and
+.Va dev.vtnet. Ns Ar X Ns Va .rx_csum_bad_offset .
.It Va dev.vtnet. Ns Ar X Ns Va .rxq Ns Ar Y Ns Va .csum
The number of times receive checksum offloading for UDP or TCP was performed.
.It Va dev.vtnet. Ns Ar X Ns Va .rxq Ns Ar Y Ns Va .ierrors
@@ -214,18 +220,21 @@ over all receive queues of the interface.
The sum of
.Va dev.vtnet. Ns Ar X Ns Va .rxq Ns Ar Y Ns Va .csum_failed
over all receive queues of the interface.
-.It Va dev.vtnet. Ns Ar X Ns Va .rx_csum_bad_proto
-Currently unused.
+.It Va dev.vtnet. Ns Ar X Ns Va .rx_csum_inaccessible_ipproto
+The number of times a packet with a request for receive or transmit checksum
+offloading was received where the IP protocol was not accessible.
.It Va dev.vtnet. Ns Ar X Ns Va .rx_csum_bad_offset
-Currently unused.
-.It Va dev.vtnet. Ns Ar X Ns Va .rx_csum_bad_ipproto
-Currently unused.
-.It Va dev.vtnet. Ns Ar X Ns Va .rx_csum_bad_ethtype
The number of times fixing the checksum required by
.Va hw.vtnet.fixup_needs_csum
or
.Va hw.vtnet. Ns Ar X Ns Va .fixup_needs_csum
-was attempted for a packet with an EtherType other than IPv4 or IPv6.
+was attempted for a packet where the csum is not located in the first mbuf.
+.It Va dev.vtnet. Ns Ar X Ns Va .rx_csum_bad_ipproto
+The number of times a packet with a request for receive or transmit checksum
+offloading was received where the IP protocol was neither TCP nor UDP.
+.It Va dev.vtnet. Ns Ar X Ns Va .rx_csum_bad_ethtype
+The number of times a packet with a request for receive or transmit checksum
+offloading was received where the EtherType was neither IPv4 nor IPv6.
.It Va dev.vtnet. Ns Ar X Ns Va .rx_mergeable_failed
The number of times receiving a mergable buffer failed.
.It Va dev.vtnet. Ns Ar X Ns Va .rx_enq_replacement_failed
diff --git a/share/man/man5/pf.conf.5 b/share/man/man5/pf.conf.5
index a9ae823257a4..bdd8a843d72a 100644
--- a/share/man/man5/pf.conf.5
+++ b/share/man/man5/pf.conf.5
@@ -2470,7 +2470,13 @@ NAT address and port.
This feature implements "full-cone" NAT behavior.
.El
.Pp
-Additionally, the
+Additionally, options
+.Ar sticky-address
+and
+.Ar prefer-ipv6-nexthop
+can be specified to influence how IP addresses selected from pools.
+.Pp
+The
.Ar sticky-address
option can be specified to help ensure that multiple connections from the
same source are mapped to the same redirection address.
@@ -2486,6 +2492,14 @@ beyond the lifetime of the states, increase the global options with
See
.Sx STATEFUL TRACKING OPTIONS
for more ways to control the source tracking.
+.Pp
+The
+.Ar prefer-ipv6-nexthop
+option allows for IPv6 addresses to be used as the nexthop
+for IPv4 packets routed with the
+.Ar route-to
+rule option. If a table is used with IPv4 and IPv6 addresses, first the IPv6 addresses
+will be used in round-robin fashion, then IPv4 addresses.
.Sh STATE MODULATION
Much of the security derived from TCP is attributable to how well the
initial sequence numbers (ISNs) are chosen.
@@ -3580,7 +3594,7 @@ limit-item = ( "states" | "frags" | "src-nodes" ) number
pooltype = ( "bitmask" | "random" |
"source-hash" [ ( hex-key | string-key ) ] |
- "round-robin" ) [ sticky-address ]
+ "round-robin" ) [ sticky-address | prefer-ipv6-nexthop ]
subqueue = string | "{" queue-list "}"
queue-list = string [ [ "," ] string ]
diff --git a/share/man/man7/arch.7 b/share/man/man7/arch.7
index fe4e8055a8b1..b29fedbfd4ec 100644
--- a/share/man/man7/arch.7
+++ b/share/man/man7/arch.7
@@ -163,7 +163,10 @@ will support execution of
.Dv armv7
binaries if the CPU implements
.Dv AArch32
-execution state, however older arm binaries are not supported by
+execution state.
+Binaries targeting
+.Dv armv6
+and earlier are no longer supported by
.Fx .
.Pp
On all supported architectures:
diff --git a/share/sendmail/Makefile b/share/sendmail/Makefile
index b6b4d2ec726c..db868b7b33b9 100644
--- a/share/sendmail/Makefile
+++ b/share/sendmail/Makefile
@@ -6,8 +6,8 @@ FILESGROUPS+= SM
SENDMAIL_DIR= ${SRCTOP}/contrib/sendmail
CFDIR= cf
CFPACKAGE= sendmail
-CFDIRS!= (cd ${SENDMAIL_DIR}; find -L ${CFDIR} \( \( -name CVS -o -name .svn \) -prune \) -o -type d -print)
-CFFILES!= (cd ${SENDMAIL_DIR}; find -L ${CFDIR} \( \( -name CVS -o -name .svn \) -prune \) -o -type f -print)
+CFDIRS!= (cd ${SENDMAIL_DIR}; find -s -L ${CFDIR} \( \( -name CVS -o -name .svn \) -prune \) -o -type d -print)
+CFFILES!= (cd ${SENDMAIL_DIR}; find -s -L ${CFDIR} \( \( -name CVS -o -name .svn \) -prune \) -o -type f -print)
SMFILES= ${CFFILES}
SMFILESDIR= ${DDIR}
diff --git a/share/vt/fonts/gallant.hex b/share/vt/fonts/gallant.hex
index 5f45c3d116f4..57a63150954e 100644
--- a/share/vt/fonts/gallant.hex
+++ b/share/vt/fonts/gallant.hex
@@ -225,8 +225,8 @@
00ff:0000000000001980198000000000f0f0602030403040188018800d000d000600060004000c00080078007000
0100:1f801f800000060006000b000b0009001180118010803fc020c0204040604060e0f000000000000000000000
0101:0000000000000fc00fc0000000000f8018c010c003c01cc030c030c030c039c01ee000000000000000000000
-0102:1b001b000e00060006000b000b0009001180118010803fc020c0204040604060e0f000000000000000000000
-0103:000000000d800d800700000000000f8018c010c003c01cc030c030c030c039c01ee000000000000000000000
+0102:198019800f00060006000b000b0009001180118010803fc020c0204040604060e0f000000000000000000000
+0103:000000000cc00cc00780000000000f8018c010c003c01cc030c030c030c039c01ee000000000000000000000
0104:000000000000060006000b000b0009001180118010803fc020c0204040604060e0f000c00180030001e00000
0105:00000000000000000000000000000f8018c010c003c01cc030c030c030c039c01ee000c00180030001e00000
0106:030006000c000fc01060202020006000600060006000600060002000302018400f8000000000000000000000
@@ -243,8 +243,8 @@
0111:00000000006000e0006007f000600f6031e020e0606060606060606070e039601e7000000000000000000000
0112:1f801f8000007fc0304030403000300030803f803080300030003000302030207fe000000000000000000000
0113:0000000000001f801f80000000000f0030c0606060607fe060006000300018600f8000000000000000000000
-0114:0d800d8007007fc0304030403000300030803f803080300030003000302030207fe000000000000000000000
-0115:000000000d800d800700000000000f0030c0606060607fe060006000300018600f8000000000000000000000
+0114:0cc00cc007807fc0304030403000300030803f803080300030003000302030207fe000000000000000000000
+0115:000000000cc00cc00780000000000f0030c0606060607fe060006000300018600f8000000000000000000000
0116:0600060000007fc0304030403000300030803f803080300030003000302030207fe000000000000000000000
0117:00000000000000000600060000000f0030c0606060607fe060006000300018600f8000000000000000000000
0118:0000000000007fc0304030403000300030803f803080300030003000302030207fe000c00180030001e00000
@@ -253,8 +253,8 @@
011b:0000000018c00d800700020000000f0030c0606060607fe060006000300018600f8000000000000000000000
011c:07000d8000000fc0106020202000600060006000600061f060602060306018600f8000000000000000000000
011d:00000000020007000d8018c000001f2031e060c060c060c031803f0060007fc03fe02060402040207fc03f80
-011e:0d800d8007000fc0106020202000600060006000600061f060602060306018600f8000000000000000000000
-011f:000000001b001b000e00000000001f2031e060c060c060c031803f0060007fc03fe02060402040207fc03f80
+011e:0cc00cc007800fc0106020202000600060006000600061f060602060306018600f8000000000000000000000
+011f:00000000198019800f00000000001f2031e060c060c060c031803f0060007fc03fe02060402040207fc03f80
0120:0300030000000fc0106020202000600060006000600061f060602060306018600f8000000000000000000000
0121:00000000000000000600060000001f2031e060c060c060c031803f0060007fc03fe02060402040207fc03f80
0122:0000000000000fc0106020202000600060006000600061f060602060306018600f800600030001800f000000
@@ -268,7 +268,7 @@
012a:1f801f8000001f800600060006000600060006000600060006000600060006001f8000000000000000000000
012b:0000000000001f801f80000000001e00060006000600060006000600060006001f8000000000000000000000
012c:198019800f001f800600060006000600060006000600060006000600060006001f8000000000000000000000
-012d:000000001b001b000e00000000001e00060006000600060006000600060006001f8000000000000000000000
+012d:00000000198019800f00000000001e00060006000600060006000600060006001f8000000000000000000000
012e:0000000000001f800600060006000600060006000600060006000600060006001f8006000c0018000f000000
012f:00000000000006000600000000001e00060006000600060006000600060006001f8006000c0018000f000000
0130:0600060000001f800600060006000600060006000600060006000600060006001f8000000000000000000000
@@ -301,8 +301,8 @@
014b:0000000000000000000000000000278079c030c030c030c030c030c030c030c078c000c000c0008007000600
014c:1f801f8000000f0011c020c020606060606060606060606060602040304018800f0000000000000000000000
014d:0000000000001f801f80000000000f8011c020e06060606060606060704038801f0000000000000000000000
-014e:0d800d8007000f0011c020c020606060606060606060606060602040304018800f0000000000000000000000
-014f:0000000000000d800d80070000000f8011c020e06060606060606060704038801f0000000000000000000000
+014e:0cc00cc007800f0011c020c020606060606060606060606060602040304018800f0000000000000000000000
+014f:0000000000000cc00cc0078000000f8011c020e06060606060606060704038801f0000000000000000000000
0150:036006c00d800f0011c020c020606060606060606060606060602040304018800f0000000000000000000000
0151:00000000000006c00d801b0000000f8011c020e06060606060606060704038801f0000000000000000000000
0152:0000000000001fe0262046204600c600c610c7f0c610c600c6004600661036101ff000000000000000000000
@@ -331,8 +331,8 @@
0169:0000000000000e401fc01380000079e030c030c030c030c030c030c030c039c01e6000000000000000000000
016a:1f801f800000f070602060206020602060206020602060206020602070403fc01f8000000000000000000000
016b:0000000000001f801f800000000079e030c030c030c030c030c030c030c039c01e6000000000000000000000
-016c:0d800d800700f070602060206020602060206020602060206020602070403fc01f8000000000000000000000
-016d:0000000000000d800d800700000079e030c030c030c030c030c030c030c039c01e6000000000000000000000
+016c:0cc00cc00780f070602060206020602060206020602060206020602070403fc01f8000000000000000000000
+016d:0000000000000cc00cc00780000079e030c030c030c030c030c030c030c039c01e6000000000000000000000
016e:07000d800d80f770602060206020602060206020602060206020602070403fc01f8000000000000000000000
016f:0000000007000d800d800700000079e030c030c030c030c030c030c030c039c01e6000000000000000000000
0170:06c00d801b00f070602060206020602060206020602060206020602070403fc01f8000000000000000000000
@@ -351,18 +351,1399 @@
017d:18c00d8007003fe020c000c00180018003000300060006000c000c00180018203fe000000000000000000000
017e:0000000018c00d800700020000007fe060e041c0038007000e001c00382070607fe000000000000000000000
017f:00000000038004c004c00c000c000c000c003c000c000c000c000c000c000c001e0000000000000000000000
+0180:0000000020006000fe006000600067806fc070e06060606060606060706078c04f8000000000000000000000
+0181:0000000000007f80d840d8601860186018c01fc01860183018301830183018603fc000000000000000000000
+0182:000000000000ffc0604060406000600060007f8060c0606060606060606060c0ff8000000000000000000000
+0183:000000007fc0600060006000600067806fc070e06060606060606060706078c04f8000000000000000000000
+0184:00000000100030007000f000b000338037c038e03060306030603060306030c03f8000000000000000000000
+0185:0000000000000000100030007000f000b000338037c038e030603060306030c03f8000000000000000000000
+0186:0000000000000f0011c020c000600060006000600060006000600040304018800f0000000000000000000000
+0187:0000003000600f4011c020c020006000600060006000600060006000304038800f0000000000000000000000
+0188:00000000000000000030006000401fc031c020c06000600060006000704030c01f8000000000000000000000
+0189:000000000000ff0061c060c0606060606060fc60606060606060606060406180fe0000000000000000000000
+018a:0000000000007f80d8e0d86018301830183018301830183018301830182018c03f0000000000000000000000
+018b:0000000000007fe040c040c000c000c000c03fc060c0c0c0c0c0c0c0c0c060c03fe000000000000000000000
+018c:000000003fe000600060006000601e603f6070e0606060606060606060e031e01f2000000000000000000000
+018d:0000000000000f8011c020e0606060606060704038801f000e000700038000c01f8000000000000000000000
+018e:0000000000003fe020c020c000c000c010c01fc010c000c000c000c040c040c07fe000000000000000000000
+018f:0000000000000f0011c020c0206000600060006000607fe060602040304018800f0000000000000000000000
+0190:000000001f803fc070206060600030001c001f80300060006000602020601fc00f8000000000000000000000
+0191:0000000000003fe0182018201800180018401fc0184018001800180018001800d800d0006000000000000000
+0192:00000000038004c004c00c000c000c000c001f800c000c000c000c000c000c006c0068001000000000000000
+0193:0000006000b01fb0218040804000c000c000c000c000c3e0c0c040c060c030c01f0000000000000000000000
+0194:000000000000f07060206020604030403080188019000d000e0006000e0013001300218021801f0000000000
+0195:0000000020006000e000600060006e3073306330633063306330633063306330f1e000000000000000000000
+0196:0000000000001e000600060006000600060006000600060006000600060006001f8000000000000000000000
+0197:0000000000001f80060006000600060006003fc00600060006000600060006001f8000000000000000000000
+0198:000000000000f0606190633066006c00780078007c006e006700638061c060e0f07000000000000000000000
+0199:180024006c00600060006000600061c0630066007c0078007c006e0067006380f1e000000000000000000000
+019a:000000001e00060006000600060006003fc006000600060006000600060006001f8000000000000000000000
+019b:0000000000001c001c000e3006c007000e003b00cb0011801180118020c020c071e000000000000000000000
+019c:00000000ef7066606660666066606660666066606660666066606660666077603bb000000000000000000000
+019d:0000000000006070302038203c202c20262022202320232021a020e020e020602030e000c000000000000000
+019e:0000000000000000000000000000278079c030c030c030c030c030c030c030c078c000c000c000c000c001e0
+019f:0000000000000f0011c020c02060606061606d606b60686060602040304018800f0000000000000000000000
+01a0:0000000000001e3023b041a040c0c0c0c0c0c0c0c0c0c0c0c0c04080608031001e0000000000000000000000
+01a1:00000000000000000000000000001f3023b041e0c0c0c0c0c0c0c0c0e08071003e0000000000000000000000
+01a2:0000000000001c102730437043b0c1b0c1b0c1b0c1b0c1b0c1b041b0633032301c3000300030003000300070
+01a3:000000000000000000000000000000001c102730437041b0c1b0c1b041b063303c3000300030003000300070
+01a4:0000000000007fc09860d830d830183018601bc01800180018001800180018003c0000000000000000000000
+01a5:000000000000000018002c0060006f8071c060e06060606060606060604070807f006000600060006000f000
+01a6:00000000f80060007f00618060c060c060807f00700078006c00660063006180e0c000600030000000000000
+01a7:0000000000007f8060c04060406000e003c007801e00380070006020602030601fe000000000000000000000
+01a8:00000000000000000000000000003f8030c020c001c007801e003800304030c01fc000000000000000000000
+01a9:0000000000007fe060203020180018000c0007000700040008001000202040207fe000000000000000000000
+01aa:000000003800640064003e00060006000600060006000600060006000600060006000660026001c000000000
+01ab:0000000000000000040004000c007fc00c000c000c000c000c000c000c200e6007a0002000c0038000000000
+01ac:0000000000003fe04620660066000600060006000600060006000600060006001f8000000000000000000000
+01ad:0000000001c002c004c004000c007fc00c000c000c000c000c000c000c200e60078000000000000000000000
+01ae:0000000000007fe046200600060006000600060006000600060006000600060006c002c001c0000000000000
+01af:006000d00010f070602060206020602060206020602060206020602070403fc01f8000000000000000000000
+01b0:0000000000000000006000d0001079e030c030c030c030c030c030c030c039c01e6000000000000000000000
+01b1:00000000000079e049200900118020c0204060606060606060606040304038800f0000000000000000000000
+01b2:000000000000f06060d060d06010601060106020602060206040604070803f001e0000000000000000000000
+01b3:000000000000f1e06090313031301a001a001a000c000c000c000c000c000c001e0000000000000000000000
+01b4:0000000000000000000000000000e1e0c05060b060b0310031001a001a000c000c00080018001000f000e000
+01b5:0000000000003fe020c000c00180018003001fe0060006000c000c00180018203fe000000000000000000000
+01b6:00000000000000000000000000007fe060e041c003803fe00e001c00382070607fe000000000000000000000
+01b7:0000000000003fe020c000c0018001800300030007c00fc000e000600060406060403f801f00000000000000
+01b8:0000000000007fc030403000180018000c000c003e003f00700060006000602020601fc00f80000000000000
+01b9:000000000000000000000000000000007fc0304018000c0006003f0070006000604020c01f800f0000000000
+01ba:00000000000000000000000000007fc04180030006000c0018003f8001c000c007803c007000604038c00f80
+01bb:000000001f003f8061c040c000c000c000c001801fe006000c00180030207fe07fe000000000000000000000
+01bc:000000007fc07fc02000200020003f8031c000e00060006000604060606030c01f8000000000000000000000
+01bd:000000000000000000007f807f80200020003f8031c000e000602060306018c00f8000000000000000000000
+01be:00000000000000000000080008001800ff8018001c000f0003c000e0106018601fc000000000000000000000
+01bf:0000000000000000000000000000ef8071c060e060606060606060606040608061006600780060006000f000
+01c0:0000000006000600060006000600060006000600060006000600060006000600060000000000000000000000
+01c1:0000000019801980198019801980198019801980198019801980198019801980198000000000000000000000
+01c2:00000000060006000600060006003fc0060006003fc006000600060006000600060000000000000000000000
+01c3:0000000006000600060006000600060006000600060006000600000000000600060000000000000000000000
+01c4:0c3006600180f3f0da10cc10c620c620c620c640c640c640c680c680c480d910e1f000000000000000000000
+01c5:000000000630f360d9c0cc00c400c5f0c510c420c420c440c440c480c480d910e1f000000000000000000000
+01c6:0c30066001800c001c000c000c006df0dd108c208c208c408c408c808c80dd107bf000000000000000000000
+01c7:000000000000f1f0606060606060606060606060606060606060606061606160ff6000600060004003800300
+01c8:000000000000f03060306000600060f060306030603060306030603060b060b0ffb008300c300e2007c00380
+01c9:000000000000786018601800180019e0186018601860186018601860186018607e60106018601c400f800700
+01ca:000000000000e3f0c130e130e130b130b130993099308d308d30873087308330c7b000300030002001c00180
+01cb:000000000000e330c130e100e100b170b130993099308d308d30873087308330c7b008300c300e2007c00380
+01cc:00000000000000300030000000004f70f3b061b061b061b061b061b061b061b0f3f008300c300e2007c00380
+01cd:18c00d800700060006000b000b0009001180118010803fc020c0204040604060e0f000000000000000000000
+01ce:0000000018c00d800700000000000f8018c010c003c01cc030c030c030c039c01ee000000000000000000000
+01cf:18c00d8007001f800600060006000600060006000600060006000600060006001f8000000000000000000000
+01d0:0000000031801b000e00000000001e00060006000600060006000600060006001f8000000000000000000000
+01d1:31801b000e000f0011c020c020606060606060606060606060602040304018800f0000000000000000000000
+01d2:0000000031801b000e00000000000f8011c020e06060606060606060704038801f0000000000000000000000
+01d3:18c00d800700f070602060206020602060206020602060206020602070403fc01f8000000000000000000000
+01d4:0000000018c00d8007000000000079e030c030c030c030c030c030c030c039c01e6000000000000000000000
+01d5:7fe030c030c00000f07060206020602060206020602060206020602070403fc01f8000000000000000000000
+01d6:00007fe0000030c030c00000000079e030c030c030c030c030c030c030c039c01e6000000000000000000000
+01d7:030066606c600000f07060206020602060206020602060206020602070403fc01f8000000000000000000000
+01d8:00000180030036c030c00000000079e030c030c030c030c030c030c030c039c01e6000000000000000000000
+01d9:18c00d80676060600000f0706020602060206020602060206020602070403fc01f8000000000000000000000
+01da:000018c00d80070060606060000079e030c030c030c030c030c030c030c039c01e6000000000000000000000
+01db:0c000600636060600000f0706020602060206020602060206020602070403fc01f8000000000000000000000
+01dc:00000c000600030060606060000079e030c030c030c030c030c030c030c039c01e6000000000000000000000
+01dd:00000000000000000000000000001f00618000c0006000607fe06060606030c00f0000000000000000000000
+01de:7fe000006060666006000b000b0009001180118010803fc020c0204040604060e0f000000000000000000000
+01df:00007fe0000019801980000000000f8018c010c003c01cc030c030c030c039c01ee000000000000000000000
+01e0:7fe000000f000f0006000b000b0009001180118010803fc020c0204040604060e0f000000000000000000000
+01e1:7fe0000006000f000f00060000000f8018c010c003c01cc030c030c030c039c01ee000000000000000000000
+01e2:7fe0000000000fe00e20162016001600164027c026403e002600460046104610e7f000000000000000000000
+01e3:00000000000000007fe0000000001f80364026600e603fe066006600660067603fc000000000000000000000
+01e4:0000000000000fc010602020200060006000600061f06060606027f0306018600f8000000000000000000000
+01e5:00000000000000000000000000001f2031e060c060c060c031803f0060007fc03fe02060fff040207fc03f80
+01e6:18c00d8007000fc0106020202000600060006000600061f060602060306018600f8000000000000000000000
+01e7:0000000018c00d800700000000001f2031e060c060c060c031803f0060007fc03fe02060402040207fc03f80
+01e8:18c00d800700f0e06180630066006c00780078007c006e006700638061c060e0f07000000000000000000000
+01e9:18c00d806700e00060006000600061c0630066007c0078007c006e0067006380f1e000000000000000000000
+01ea:0000000000000f0011c020c020606060606060606060606060602040304018800f0006000c0018000f000000
+01eb:00000000000000000000000000000f8011c020e06060606060606060704038801f0006000c0018000f000000
+01ec:7fe0000000000f0011c020c020606060606060606060606060602040304018800f0006000c0018000f000000
+01ed:00000000000000007fe0000000000f8011c020e06060606060606060704038801f0006000c0018000f000000
+01ee:18c00d8007003fe020c000c0018001800300030007c00fc000e000600060406060403f801f00000000000000
+01ef:00000000000031801b000e00000000007fc04180030006000c001f8001c000c040c060803f001e0000000000
+01f0:000000000c6006c003800000000007800180018001800180018001800180018001804180618071003e001c00
+01f1:000000000000f3f0da10cc10c620c620c620c640c640c640c680c680c480d910e1f000000000000000000000
+01f2:000000000000f000d800cc00c400c5f0c510c420c420c440c440c480c480d910e1f000000000000000000000
+01f3:0000000000000c001c000c000c006df0dd108c208c208c408c408c808c80dd107bf000000000000000000000
+01f4:03800f001c000fc0106020202000600060006000600061f060602060306018600f8000000000000000000000
+01f5:0000000003800f001c00000000001f2031e060c060c060c031803f0060007fc03fe02060402040207fc03f80
+01f6:000000000000ef00c600c600c600c600c670fe30c630c630c630c630c630c630efe000000000000000000000
+01f7:000000000000ef8071c060e06060606060606060606060c060c061006100660078006000600060006000f000
+01f8:38001e000700c07060207020782058204c2046204720432041a040e040e04060e03000000000000000000000
+01f9:0000000038001e00070000000000278079c030c030c030c030c030c030c030c079e000000000000000000000
+01fa:06001800660009000900060006000b000900118011803fc020c0204040604060e0f000000000000000000000
+01fb:03800f001c0009000900060000000f8018c010c003c01cc030c030c030c039c01ee000000000000000000000
+01fc:03800f001c000fe00e20162016001600164027c026403e002600460046104610e7f000000000000000000000
+01fd:0000000003800f001c00000000001f80364026600e603fe066006600660067603fc000000000000000000000
+01fe:03800f001c600fc011c021c021e06360636066606c606c6078603840304038806f0000000000000000000000
+01ff:0000000003800f001c00000000000fe011c021e06360666066606c60784038807f0000000000000000000000
+0200:e38079e01c70060006000b000b0009001180118010803fc020c0204040604060e0f000000000000000000000
+0201:00000000e38079e01c70000000000f8018c010c003c01cc030c030c030c039c01ee000000000000000000000
+0202:0f0019801980060006000b000b0009001180118010803fc020c0204040604060e0f000000000000000000000
+0203:000000000f0019801980000000000f8018c010c003c01cc030c030c030c039c01ee000000000000000000000
+0204:e38079e01c707fc0304030403000300030803f803080300030003000302030207fe000000000000000000000
+0205:00000000e38079e01c70000000000f0030c0606060607fe060006000300018600f8000000000000000000000
+0206:0f001980198000007fc0304030403000300030803f80308030003000302030207fe000000000000000000000
+0207:000000000f0019801980000000000f0030c0606060607fe060006000300018600f8000000000000000000000
+0208:e38079e01c7000001f80060006000600060006000600060006000600060006001f8000000000000000000000
+0209:00000000e38079e01c70000000001e00060006000600060006000600060006001f8000000000000000000000
+020a:0f001980198000001f80060006000600060006000600060006000600060006001f8000000000000000000000
+020b:000000000f0019801980000000001e00060006000600060006000600060006001f8000000000000000000000
+020c:e38079e01c700f0011c020c020606060606060606060606060602040304018800f0000000000000000000000
+020d:00000000e38079e01c70000000000f8011c020e06060606060606060704038801f0000000000000000000000
+020e:0f001980198000000f0011c020c02060606060606060606060602040304018800f0000000000000000000000
+020f:000000000f0019801980000000000f8011c020e06060606060606060704038801f0000000000000000000000
+0210:e38079e01c70ff00618060c060c060c060807f007c006e006700638061c060e0f07000000000000000000000
+0211:00000000e38079e01c7000000000738034c038c0300030003000300030003000780000000000000000000000
+0212:0f00198019800000ff00618060c060c060807f007c006e006700638061c060e0f07000000000000000000000
+0213:000000000f001980198000000000738034c038c0300030003000300030003000780000000000000000000000
+0214:e38079e01c700000f07060206020602060206020602060206020602070403fc01f8000000000000000000000
+0215:00000000e38079e01c700000000079e030c030c030c030c030c030c030c039c01e6000000000000000000000
+0216:0f00198019800000f07060206020602060206020602060206020602070403fc01f8000000000000000000000
+0217:000000000f00198019800000000079e030c030c030c030c030c030c030c039c01e6000000000000000000000
+0218:0000000000001fe030606020602070003c001e00078001c000e04060406060c07f8000000f000f0003001e00
+0219:00000000000000000000000000001fc030c0304038001e00078001c020c030c03f8000000f000f0003001e00
+021a:0000000000007fe04620060006000600060006000600060006000600060006001f8000000f000f0003001e00
+021b:0000000000000000040004000c007fc00c000c000c000c000c000c000c200e40078000000f000f0003001e00
+021c:0000000020003f8020c000600060006001c007003e00018000600060006000e001c007003c00000000000000
+021d:000000000000000020003f8020c00060006001c007003e0001800060006000e001c007003c00000000000000
+021e:31801b000e00f0f0606060606060606060607fe0606060606060606060606060f0f000000000000000000000
+021f:18c00d8017003000700030003000378039c030c030c030c030c030c030c030c079e000000000000000000000
+0220:000000000000278079c030c030c030c030c030c030c030c030c030c030c030c078c000c000c000c000c001e0
+0221:00000000018003800180018001801d8067804380c180c180c180c1e0e390759039e002000400000000000000
+0222:000000000900118030c030c030c018800d0006000b00118030c030c030c018800f0000000000000000000000
+0223:00000000000000000900118030c030c018800d0006000b00118030c030c018800f0000000000000000000000
+0224:0000000000003fe020c000c00180018003000300060006000c000c00180018003fc00060006001c000000000
+0225:00000000000000000000000000007fe060e041c0038007000e001c00380070007fc00060006001c000000000
+0226:06000f0006000000060006000b000b000900118010803fc020c0204040604060e0f000000000000000000000
+0227:0000000006000f000f00060000000f8018c010c003c01cc030c030c030c039c01ee000000000000000000000
+0228:0000000000007fc0304030403000300030803f803080300030003000302030207fe002000300018009800700
+0229:00000000000000000000000000000f0030c0606060607fe060006000300018600f8002000300018009800700
+022a:7fe00000606060600f0011c020c02060606060606060606060602040304018800f0000000000000000000000
+022b:000000003fc0000030c030c000000f8011c020e06060606060606060704038801f0000000000000000000000
+022c:7fe000003c6063c00f0011c020c02060606060606060606060602040304018800f0000000000000000000000
+022d:00003fc000000cc01f80330000000f8011c020e06060606060606060704038801f0000000000000000000000
+022e:06000f00060000000f0011c020c02060606060606060606060602040304018800f0000000000000000000000
+022f:0000000006000f000600000000000f8011c020e06060606060606060704038801f0000000000000000000000
+0230:3fc000000f000f0000000f0011c020c0206060606060606060602040304018800f0000000000000000000000
+0231:3fc0000006000f000600000000000f8011c020e06060606060606060704038801f0000000000000000000000
+0232:3fc000000000f07060203040188018800d0006000600060006000600060006000f0000000000000000000000
+0233:00000000000000003fc000000000f0f0602030403040188018800d000d000600060004000c00080078007000
+0234:000000001e00060006000600060006000600060006000600060006c0076006401f8004000800000000000000
+0235:0000000000000000000000000000278079c030c030c030c030c030e030d030d079e001000200000000000000
+0236:0000000000000000040004000c007fc00c000c000c000c000c000cc00d600e40078008001000000000000000
+0237:000000000000000000000000000003c000c000c000c000c000c000c000c000c000c020c030c038801f000e00
+0238:0000000006000e0006000600060036c07fe04f20c630c630c630c630ef7079e030c000000000000000000000
+0239:000000000000000000000000000030c079e0ef70c630c630c630c6304f207fe036c006000600060006000f00
+023a:0000000000100620064006800f000b001580198010803fc060c0a04040604060e0f000000000000000000000
+023b:0000004000400fc010e020a02080610061006100620062006200240034201c400f8008000800000000000000
+023c:00000000000000000000004000801f8031c021c06200620064006400784038c01f8010002000000000000000
+023d:0000000000003c0018001800180018001800ff001800180018001800181018103ff000000000000000000000
+023e:0000002000207fe046400680068007000700060006000e000e001600160026003f8040004000000000000000
+023f:00000000000000000000000000001fc030c0304038001e00078001c020c030c03f8018000c00066003c00000
+0240:00000000000000000000000000007fe060e041c0038007000e001c0038007000700018000c00066003c00000
+0241:000000001e007180604060600060006000c001800f000c000c000c000c000c001e0000000000000000000000
+0242:0000000000000000000000001e00718060c000c000c001800e00080008001c00000000000000000000000000
+0243:000000000000ff00608060c060c060c061807f8060c06060fc606060606060c0ff8000000000000000000000
+0244:000000000000f0706020602060206020fff06020602060206020602070403fc01f8000000000000000000000
+0245:00000000000002000200020007000700070009800980098010c010c010c02060707000000000000000000000
+0246:0000008000807fc0314031403100320032803f803480340034003800382038207fe010001000000000000000
+0247:00000000000000000080008001000f0032c0626064607fe068006800300018602f8020000000000000000000
+0248:0000000000001f8006000600060006000600060006003fc00600060006000600060006000600040038003000
+0249:000000000000018001800000000007800180018001800ff0018001800180018001804180618071003e001c00
+024a:000000001cc0278043804180c180c180c180c180c180c180c180e18073803f8001800180018001b000b00060
+024b:00000000000000000000000000001cc027804380c180c180c180c180e18073803f800180018001b000b00060
+024c:000000000000ff00618060c060c060c06080ff007c006e006700638061c060e0f07000000000000000000000
+024d:000000000000000000000000000039c01a601c601800ff0018001800180018003c0000000000000000000000
+024e:000000000000f07060203040fff018800d0006000600060006000600060006000f0000000000000000000000
+024f:0000000000000000000000000000f0f0602030403040fff018800d000d000600060004000c00080078007000
+0250:0000000000000000000000000000778039c030c030c030c033803c00308031801f0000000000000000000000
+0251:00000000000000000000000000003f2063a0c1c0c1c0c180c180c180c3c0e4c0786000000000000000000000
+0252:0000000000000000000000000000c3c064e0786030603060306070607060b8c09f8000000000000000000000
+0253:000000001e00230063006000600067806fc070e06060606060606060706078c04f8000000000000000000000
+0254:00000000000000000000000000003f00618041c000c000c000c000c0608071803f0000000000000000000000
+0255:00000000000000000000000000001f8031c020c06000600060006380744038c05f8000000000000000000000
+0256:0000000000c001c000c000c000c01ec063c041c0c0c0c0c0c0c0c0c0e1c072c03cc000d00050007000000000
+0257:00000000007000d000d000d000c01ec063c041c0c0c0c0c0c0c0c0c0e1c072c03ce000000000000000000000
+0258:00000000000000000000000000000f0030c0606060607fe00060006000c061801f0000000000000000000000
+0259:00000000000000000000000000001f00618000c0006000607fe06060606030c00f0000000000000000000000
+025a:00000000000000000000000000003c00c690035003200d803180c180c18063001c0000000000000000000000
+025b:00000000000000000000000000000f801fc0206060003f003f00600060203fc01f0000000000000000000000
+025c:00000000000000000000000000001f003f80604000600fc00fc0006040603fc00f8000000000000000000000
+025d:00000000000000000000000000003e107f50c0b000d01f801f8000c080c07f801f0000000000000000000000
+025e:00000000000000000000000000001f003f806040c060cfc0cfc0c06040603fc00f8000000000000000000000
+025f:0000000007800300030003000300030003001f800300030003000300320032001c0000000000000000000000
+0260:000000000000000000e0013001301f8031c060c060c060c060c060c061c033c01ec00040204030c01f800f00
+0261:00000000000000000000000000001f8031c060c060c060c060c060c061c033c01ec00040204030c01f800f00
+0262:00000000000000000000000000000fc0106020206000600061f06060306018600f8000000000000000000000
+0263:000000000000000000000000000070e0304030401880188019000d000e0006000e0013001300218021801f00
+0264:0000000000000000000000000000000000007060d8b0989099100d000e0006000e0013001300218021801f00
+0265:0000000079e030c030c030c030c030c030c030c039c01ec000c000c000e000c0008000000000000000000000
+0266:000000001e003300330030003000378039c030c030c030c030c030c030c030c079e000000000000000000000
+0267:0000000010003000700030003000378039c030c030c030c030c030c030c030c078c000c00380070000000000
+0268:00000000000006000600000000001e000600060006003fc006000600060006001f8000000000000000000000
+0269:00000000000000000000000000001e00060006000600060006000600060006001f8000000000000000000000
+026a:00000000000000000000000000001f80060006000600060006000600060006001f8000000000000000000000
+026b:000000001e00060006000600060006001e6067800600060006000600060006001f8000000000000000000000
+026c:000000001e00060006000600060006003e0066003fc0060006000600060006001f8000000000000000000000
+026d:000000001e0006000600060006000600060006000600060006000600060006000660066003c0018000000000
+026e:00000000f00030003000300030003ff0306030c0318033003600338030e03070fc700070186019c00f800000
+026f:0000000000000000000000000000ef70666066606660666066606660666077603bb000000000000000000000
+0270:0000000000000000000000000000ef70666066606660666066606660666076e03b6000600060006000300000
+0271:0000000000000000000000000000ddc06ee06660666066606660666066606660ef6000600660066003c00000
+0272:000000000000000000000000000013c03ce0186018601860186018601860186018f0d800d800700000000000
+0273:00000000000000000000000000004f00f3806180618061806180618061806180f18001b001b000e000000000
+0274:0000000000000000000000000000c0e06040704058404c404640434041c040c0e06000000000000000000000
+0275:00000000000000000000000000000f8011c020e060607fe07fe06060704038801f0000000000000000000000
+0276:00000000000000000000000000001de023304200c210c3f0c210c200e20073303de000000000000000000000
+0277:000000000000000000000f003fc06060c030c630c630c630c630c63066207fc0198000000000000000000000
+0278:0000000000000000060006000f8017c026e0666066606660666076403e801f00060006000000000000000000
+0279:000000000000000000000000000003c00180018001800180018001806380658039c000000000000000000000
+027a:000000000000000003c00180018001800180018001800180018001806380658039c000000000000000000000
+027b:00000000000000000000000000000780030003000300030003000300c700cb0073000330033001e000000000
+027c:0000000000000000000000000000738034c038c0300030003000300030003000300030003000780000000000
+027d:0000000000000000000000000000738034c038c0300030003000300030003000300031801b800e0000000000
+027e:000000000000000000000000038004c004c00c000c000c000c000c000c000c001e0000000000000000000000
+027f:0000000000000000000000001c00320032000300030003000300030003000300030003000300078000000000
+0280:00000000000000000000000000007f8030c0306030403f803e003700338031c078e000000000000000000000
+0281:000000000000000000000000000078e031c0338037003e003f803040306030c07f8000000000000000000000
+0282:00000000000000000000000000001fc030c0304038001e00078001c020c030c03f801000100013000e000000
+0283:0000000001c00260066006000600060006000600060006000600060006000600060006000600640064003800
+0284:0000000001c00260066006000600060006000600060006000600060006003fc0060006000600640064003800
+0285:00000000380064006400060006000600060006000600060006000600060006000600060006000660026001c0
+0286:0000000001c0026006600600060006000600060006000600060006000600060006003fc06660646064003800
+0287:00000000000000001e00270043000300030003000300030003003fe003000200020000000000000000000000
+0288:0000000000000000040004000c007fc00c000c000c000c000c000c000c000c000cc004c00380000000000000
+0289:000000000000000000000000000079e030c030c030c0fff030c030c030c039c01e6000000000000000000000
+028a:000000000000000000000000000079e009001880304060606060206020c011c00f0000000000000000000000
+028b:000000000000000000000000000078c031c03060306030603060306030e039c01f0000000000000000000000
+028c:0000000000000000000000000000060006000b000b001180118020c020c04060e0f000000000000000000000
+028d:00000000000000000000000000001980198019802dc02dc02ec0466046604660eff000000000000000000000
+028e:0000000000e001e0010003000200060006000b000b001180118020c020c04060f0f000000000000000000000
+028f:0000000000000000000000000000f0706020304018800d0006000600060006000f0000000000000000000000
+0290:00000000000000000000000000007fe060e041c0038007000e001c00380070407f80019000f0006000000000
+0291:00000000000000000000000000007fe060e041c0038007000e001c00386070907fe002000400000000000000
+0292:000000000000000000000000000000007fc04180030006000c001f8001c000c040c060803f001e0000000000
+0293:000000000000000000000000000000007fc04180030006000c001f8001c038c044c062803f001e8000400000
+0294:000000001e007180604060600060006000c001800f000c000c000c000c000c001e0000000000000000000000
+0295:00000000078018e02060606060006000300018000f0003000300030003000300078000000000000000000000
+0296:000000001e000c000c000c000c000c000f00018000c0006000606060604071801e0000000000000000000000
+0297:0000000000000000000000000fc0106020202000600060006000600060006000600060002000302018400f80
+0298:0000000000000f0011c020c020606060666066606060606060602040304018800f0000000000000000000000
+0299:0000000000000000000000000000ff00608060c061807f8060c06060606060c0ff8000000000000000000000
+029a:00000000000000000000000000001f003f8040c0c0607e607e60c060c0407f803e0000000000000000000000
+029b:00000000000000000000007000900fc0106020206000600061f06060306018600f8000000000000000000000
+029c:0000000000000000000000000000f1e060c060c060c07fc060c060c060c060c0f1e000000000000000000000
+029d:00000000000003000300000000000f000300030003000300030003000300030007c01b00230022001c000000
+029e:00000000f1e038c01cc00ec007c003c007c00cc018c070c000c000c000c000e000c000000000000000000000
+029f:00000000000000000000000000007800300030003000300030003000300030407fc000000000000000000000
+02a0:00000000000000000030005000501e4023c041c0c0c0c0c0c0c0c0c0e0c071c03fc000c000c000c000c001e0
+02a1:000000001e007180604060600060006000c001800f000c007f800c000c000c001e0000000000000000000000
+02a2:00000000078018e02060606060006000300018000f0003001fe0030003000300078000000000000000000000
+02a3:0000000000000c001c000c000c006df0dd108c208c208c408c408c808c80dd107bf000000000000000000000
+02a4:0000000000000c001c000c000c006df0dd108c208c208c408c408cc08c60dc307a1000100c20064001800000
+02a5:0000000000000c001c000c000c006df0dd108c208c208c408c408c808ce0dd907bf001000200000000000000
+02a6:0000000000000000200020006000fff0663066106700638060e06070623066303fe000000000000000000000
+02a7:0000000000e00130233023006300ff00630063006300630063006300630073003f0003000300320032001c00
+02a8:0000000000000000200020006000f9e0633062106600660066006660629063b03de001000200000000000000
+02a9:000000001800260026006000600060006000fbc0666066606660666066606660f760006000600c600cc00780
+02aa:0000000000000000e0006000600063f0663066106700638060e06070643066303fe000000000000000000000
+02ab:0000000000000000e0006000600067f066306430607060e061c06380671066303ff000000000000000000000
+02ac:00000000ff706620662037403b40198019800000ff706620662037403b401980198000000000000000000000
+02ad:0000000000000000000000007fe07fe060606060000000007fe07fe060606060000000000000000000000000
+02ae:00006000a1e0b0c0b0c030c030c030c030c030c039c01ec000c000c000e000c0008000000000000000000000
+02af:00006000a1e0b0c0b0c030c030c030c030c030c039c01ec000c000c000d00050005000600000000000000000
+02b0:000000001000300070003000378039c030c030c030c030c079e0000000000000000000000000000000000000
+02b1:00000f001380300030003000378039c030c030c030c030c079e0000000000000000000000000000000000000
+02b2:000000c000c0000003c000c000c000c000c000c000c010c018800f0000000000000000000000000000000000
+02b3:0000000033801cc0180018001800180018003c00000000000000000000000000000000000000000000000000
+02b4:0000000003c00180018001800180018033801cc0000000000000000000000000000000000000000000000000
+02b5:0000000007800300030003000300030067003b00030001600080000000000000000000000000000000000000
+02b6:0000000078e031c0338037003e003f803040306030c07f800000000000000000000000000000000000000000
+02b7:00000000eff0466046602ec02dc02dc019801980198000000000000000000000000000000000000000000000
+02b8:0000000078f0302018400c800d000500060006000c0038003000000000000000000000000000000000000000
+02b9:0000000003000300060006000c000c0000000000000000000000000000000000000000000000000000000000
+02ba:000000000c600c6018c018c03180318000000000000000000000000000000000000000000000000000000000
+02bb:000000000100030006000c000c000f000f000600000000000000000000000000000000000000000000000000
+02bc:0000000006000f000f000300030006000c000800000000000000000000000000000000000000000000000000
+02bd:0000000006000f000f000c000c00060003000100000000000000000000000000000000000000000000000000
+02be:000000000e0003800180018003800e0000000000000000000000000000000000000000000000000000000000
+02bf:0000000007001c00180018001c00070000000000000000000000000000000000000000000000000000000000
+02c0:000000001e00718060c000c001800e0008000800080000000000000000000000000000000000000000000000
+02c1:00000000078018e0306030001800070001000100010000000000000000000000000000000000000000000000
+02c2:0000000000e003800e0038000e00038000e00000000000000000000000000000000000000000000000000000
+02c3:0000000070001c00070001c007001c0070000000000000000000000000000000000000000000000000000000
+02c4:0000000006000f00198030c06060000000000000000000000000000000000000000000000000000000000000
+02c5:00000000606030c019800f000600000000000000000000000000000000000000000000000000000000000000
+02c6:0000000006001f8030c000000000000000000000000000000000000000000000000000000000000000000000
+02c7:0000000030c01980060000000000000000000000000000000000000000000000000000000000000000000000
+02c8:0000000006000600060006000600060000000000000000000000000000000000000000000000000000000000
+02c9:000000003fc03fc0000000000000000000000000000000000000000000000000000000000000000000000000
+02ca:03800f001c000000000000000000000000000000000000000000000000000000000000000000000000000000
+02cb:1c000f0003800000000000000000000000000000000000000000000000000000000000000000000000000000
+02cc:0000000000000000000000000000000000000000000000000000000000000000000006000600060006000600
+02cd:00000000000000000000000000000000000000000000000000000000000000000000000000003fc03fc00000
+02ce:1c000f0003800000000000000000000000000000000000000000000000000000000000000000000000000000
+02cf:03800f001c000000000000000000000000000000000000000000000000000000000000000000000000000000
+02d0:00000000000000000000000000001f800f000600000000000000000006000f001f8000000000000000000000
+02d1:00000000000000000000000000001f800f000600000000000000000000000000000000000000000000000000
+02d2:000000000000000000000000000000000e0003800180018003800e0000000000000000000000000000000000
+02d3:0000000000000000000000000000000007001c00180018001c00070000000000000000000000000000000000
+02d4:0000000000000000000000000000000006000600060006001f801f8000000000000000000000000000000000
+02d5:000000000000000000000000000000001f801f80060006000600060000000000000000000000000000000000
+02d6:00000000000000000000000000000000060006001f801f800600060000000000000000000000000000000000
+02d7:00000000000000000000000000000000000000001f801f800000000000000000000000000000000000000000
+02d8:198019800f000000000000000000000000000000000000000000000000000000000000000000000000000000
+02d9:06000f0006000000000000000000000000000000000000000000000000000000000000000000000000000000
+02da:0f00198019800f00000000000000000000000000000000000000000000000000000000000000000000000000
+02db:000000000000000000000000000000000000000000000000000000000000000000000600030001800f000000
+02dc:1c6036c063800000000000000000000000000000000000000000000000000000000000000000000000000000
+02dd:1c7079e0e3800000000000000000000000000000000000000000000000000000000000000000000000000000
+02de:0000000000000000000000000000000000001c0036c003800100000000000000000000000000000000000000
+02df:30c019800f0006000f00198030c0000000000000000000000000000000000000000000000000000000000000
+02e0:0000000070e03040188019000d000e0006000e00130021801f00000000000000000000000000000000000000
+02e1:00001e000600060006000600060006000600060006001f800000000000000000000000000000000000000000
+02e2:000000001fc030c038001e00078001c030c03f80000000000000000000000000000000000000000000000000
+02e3:0000000079c0308019000e000700098010c039e0000000000000000000000000000000000000000000000000
+02e4:00000000070018c018c018000e00020002000000000000000000000000000000000000000000000000000000
+02e5:00000000000000003f8001800180018001800180018001800180018001800180018000000000000000000000
+02e6:00000000000000000180018001803f8001800180018001800180018001800180018000000000000000000000
+02e7:00000000000000000180018001800180018001803f8001800180018001800180018000000000000000000000
+02e8:00000000000000000180018001800180018001800180018001803f8001800180018000000000000000000000
+02e9:00000000000000000180018001800180018001800180018001800180018001803f8000000000000000000000
+02ea:00000000000000000000000000000000000000003000300030003000300030003f8000000000000000000000
+02eb:00000000000000000000000000000000000000003000300030003f8030003000300000000000000000000000
+02ec:0000000000000000000000000000000000000000000000000000000000000000000060c031801b000e000400
+02ed:00007fe000007fe0000000000000000000000000000000000000000000000000000000000000000000000000
+02ee:0000000030c079e079e01860186030c061804100000000000000000000000000000000000000000000000000
+02ef:00000000000000000000000000000000000000000000000000000000000000000000606030c019800f000600
+02f0:0000000000000000000000000000000000000000000000000000000000000000000006000f00198030c06060
+02f1:00000000000000000000000000000000000000000000000000000000000000e003800e0038000e00038000e0
+02f2:00000000000000000000000000000000000000000000000000000000000070001c00070001c007001c007000
+02f3:0000000000000000000000000000000000000000000000000000000000000000000000000f00198019800f00
+02f4:000000000000000000000000000000001c000f00038000000000000000000000000000000000000000000000
+02f5:00000000000000000000000000000000e38079e01c7000000000000000000000000000000000000000000000
+02f6:000000000000000000000000000000001c7079e0e38000000000000000000000000000000000000000000000
+02f7:00000000000000000000000000000000000000000000000000000000000000000000000000001c6036c06380
+02f8:000000000c001e001e000c00000000000c001e001e000c000000000000000000000000000000000000000000
+02f9:000000003f803f80300030003000300030000000000000000000000000000000000000000000000000000000
+02fa:000000001fc01fc000c000c000c000c000c00000000000000000000000000000000000000000000000000000
+02fb:0000000000000000000000000000000000000000300030003000300030003f803f8000000000000000000000
+02fc:000000000000000000000000000000000000000000c000c000c000c000c01fc01fc000000000000000000000
+02fd:0000000000000000000000000000000000000000606060606060606060607fe07fe000000000000000000000
+02fe:0000000000000000000000000000000000000000600060006000600060007fe07fe000000000000000000000
+02ff:00000000000000000000000000000000000000000000000000000000000000000000100030007fe030001000
0300:0c00060003000000000000000000000000000000000000000000000000000000000000000000000000000000
0301:030006000c000000000000000000000000000000000000000000000000000000000000000000000000000000
0302:04000e001b003180000000000000000000000000000000000000000000000000000000000000000000000000
0303:1c803f8027000000000000000000000000000000000000000000000000000000000000000000000000000000
0304:00001f801f800000000000000000000000000000000000000000000000000000000000000000000000000000
-0306:1b001b000e000000000000000000000000000000000000000000000000000000000000000000000000000000
+0305:00007fe07fe00000000000000000000000000000000000000000000000000000000000000000000000000000
+0306:198019800f000000000000000000000000000000000000000000000000000000000000000000000000000000
+0307:0600060000000000000000000000000000000000000000000000000000000000000000000000000000000000
0308:1980198000000000000000000000000000000000000000000000000000000000000000000000000000000000
+0309:0e00130003000600000000000000000000000000000000000000000000000000000000000000000000000000
030a:0e001b001b000e00000000000000000000000000000000000000000000000000000000000000000000000000
+030b:1c7079e0e3800000000000000000000000000000000000000000000000000000000000000000000000000000
030c:31801b000e000400000000000000000000000000000000000000000000000000000000000000000000000000
+030d:0600060006000600000000000000000000000000000000000000000000000000000000000000000000000000
+030e:1980198019801980000000000000000000000000000000000000000000000000000000000000000000000000
+030f:e38079e01c700000000000000000000000000000000000000000000000000000000000000000000000000000
+0310:666030c01f800000000000000000000000000000000000000000000000000000000000000000000000000000
+0311:0f00198019800000000000000000000000000000000000000000000000000000000000000000000000000000
+0312:07000c000f000f00000000000000000000000000000000000000000000000000000000000000000000000000
+0313:0f000f0003000e00000000000000000000000000000000000000000000000000000000000000000000000000
+0314:0f000f000c000700000000000000000000000000000000000000000000000000000000000000000000000000
+0315:01e001e0006001c0000000000000000000000000000000000000000000000000000000000000000000000000
+0316:00000000000000000000000000000000000000000000000000000000000000000000000000001c000f000380
+0317:000000000000000000000000000000000000000000000000000000000000000000000000000003800f001c00
+0318:00000000000000000000000000000000000000000000000000000000000000000000008000800f8000800080
+0319:00000000000000000000000000000000000000000000000000000000000000000000100010001f0010001000
+031a:00f0001000100010000000000000000000000000000000000000000000000000000000000000000000000000
+031b:00000000000000f000f0003000e0000000000000000000000000000000000000000000000000000000000000
+031c:0000000000000000000000000000000000000000000000000000000000000000000007001c0018001c000700
+031d:0000000000000000000000000000000000000000000000000000000000000000000004000400040004001f00
+031e:000000000000000000000000000000000000000000000000000000000000000000001f000400040004000400
+031f:00000000000000000000000000000000000000000000000000000000000000000000040004001f0004000400
+0320:00000000000000000000000000000000000000000000000000000000000000000000000000001f0000000000
+0321:0000000000000000000000000000000000000000000000000000000000000000000000800080008001001e00
+0322:00000000000000000000000000000000000000000000000000000000000000000000020002000200010000f0
+0323:0000000000000000000000000000000000000000000000000000000000000000000000000000060006000000
+0324:0000000000000000000000000000000000000000000000000000000000000000000000000000198019800000
+0325:0000000000000000000000000000000000000000000000000000000000000000000000000600090009000600
+0326:0000000000000000000000000000000000000000000000000000000000000000000000000f000f0003000e00
0327:000000000000000000000000000000000000000000000000000000000000000000000600030001800f000000
0328:0000000000000000000000000000000000000000000000000000000000000000000006000c0018000f000000
+0329:0000000000000000000000000000000000000000000000000000000000000000000006000600060006000000
+032a:0000000000000000000000000000000000000000000000000000000000000000000000007fe0402040200000
+032b:000000000000000000000000000000000000000000000000000000000000000000000000462046207fe00000
+032c:00000000000000000000000000000000000000000000000000000000000000000000000018c00d8007000000
+032d:00000000000000000000000000000000000000000000000000000000000000000000000004000e001b003180
+032e:000000000000000000000000000000000000000000000000000000000000000000000000198019800f000000
+032f:0000000000000000000000000000000000000000000000000000000000000000000000000f00198019800000
+0330:0000000000000000000000000000000000000000000000000000000000000000000000000e401fc013800000
+0331:00000000000000000000000000000000000000000000000000000000000000000000000000001f801f800000
0332:00000000000000000000000000000000000000000000000000000000000000000000000000000000fff0fff0
+0333:00000000000000000000000000000000000000000000000000000000000000000000fff0fff00000fff0fff0
+0334:0000000000000000000000000000000000001c203e6036c067c0438000000000000000000000000000000000
+0335:00000000000000000000000000000000000000001f801f800000000000000000000000000000000000000000
+0336:00000000000000000000000000000000000000007fe07fe00000000000000000000000000000000000000000
+0337:0000000000000000000000000000000001800180060006001800180000000000000000000000000000000000
+0338:0000000000000000000000000060006001800180060006001800180060006000000000000000000000000000
+0339:0000000000000000000000000000000000000000000000000000000000000000000000000600010001000600
+033a:000000000000000000000000000000000000000000000000000000000000000000000000000080208020ffe0
+033b:0000000000000000000000000000000000000000000000000000000000000000000000000000ffe08020ffe0
+033c:00000000000000000000000000000000000000000000000000000000000000000000000071c08a2004000400
+033d:19800f0006000f00198000000000000000000000000000000000000000000000000000000000000000000000
+033e:0300060003000600000000000000000000000000000000000000000000000000000000000000000000000000
+033f:fff00000fff00000000000000000000000000000000000000000000000000000000000000000000000000000
+0340:0c00060003000000000000000000000000000000000000000000000000000000000000000000000000000000
+0341:030006000c000000000000000000000000000000000000000000000000000000000000000000000000000000
+0342:1c40238000000000000000000000000000000000000000000000000000000000000000000000000000000000
+0343:0e00010001000600000000000000000000000000000000000000000000000000000000000000000000000000
+0344:03800f00dc60c060000000000000000000000000000000000000000000000000000000000000000000000000
+0345:0000000000000000000000000000000000000000000000000000000000000000000000000600060007000000
+0346:7fe0402040200000000000000000000000000000000000000000000000000000000000000000000000000000
+0347:0000000000000000000000000000000000000000000000000000000000000000000000003fc000003fc00000
+0348:0000000000000000000000000000000000000000000000000000000000000000000000001980198019801980
+0349:0000000000000000000000000000000000000000000000000000000000000000000000000f00010001000100
+034a:1d20366066c04b80000000000000000000000000000000000000000000000000000000000000000000000000
+034b:060000203e606780400006000000000000000000000000000000000000000000000000000000000000000000
+034c:1e60678000001e60678000000000000000000000000000000000000000000000000000000000000000000000
+034d:0000000000000000000000000000000000000000000000000000000000000000000020406060fff060602040
+034e:0000000000000000000000000000000000000000000000000000000000000000000006000f001f8006000600
+034f:0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+0350:1c00070001c007001c0000000000000000000000000000000000000000000000000000000000000000000000
+0351:0600080008000600000000000000000000000000000000000000000000000000000000000000000000000000
+0352:1f80606046200000000000000000000000000000000000000000000000000000000000000000000000000000
+0353:0000000000000000000000000000000000000000000000000000000000000000000060601980060019806060
+0354:0000000000000000000000000000000000000000000000000000000000000000000003800e0038000e000380
+0355:000000000000000000000000000000000000000000000000000000000000000000001c00070001c007001c00
+0356:00000000000000000000000000000000000000000000000000000000000000000000c0c031e00de03330c330
+0357:0c00020002000c00000000000000000000000000000000000000000000000000000000000000000000000000
+0358:0070007000700000000000000000000000000000000000000000000000000000000000000000000000000000
+0359:00000000000000000000000000000000000000000000000000000000000000000000090006001f8006000900
+035a:0000000000000000000000000000000000000000000000000000000000000000000071c08a2084208a2071c0
+035b:18003fe07fc00180000000000000000000000000000000000000000000000000000000000000000000000000
+035c:0000000000000000000000000000000000000000000000000000000000000000000020102010102008400780
+035d:2010201010200840078000000000000000000000000000000000000000000000000000000000000000000000
+035e:1ff01ff000000000000000000000000000000000000000000000000000000000000000000000000000000000
+035f:000000000000000000000000000000000000000000000000000000000000000000000000000000001ff01ff0
+0360:1e10333021e00000000000000000000000000000000000000000000000000000000000000000000000000000
+0361:0780084010202010201000000000000000000000000000000000000000000000000000000000000000000000
+0362:00000000000000000000000000000000000000000000000000000000000000000000004000603ff000600040
+0363:0f0000800f8010800f8000000000000000000000000000000000000000000000000000000000000000000000
+0364:0f0010801f0010000f0000000000000000000000000000000000000000000000000000000000000000000000
+0365:0200000002000200020000000000000000000000000000000000000000000000000000000000000000000000
+0366:0f001080108010800f0000000000000000000000000000000000000000000000000000000000000000000000
+0367:10801080108010800f0000000000000000000000000000000000000000000000000000000000000000000000
+0368:0f001000100010000f0000000000000000000000000000000000000000000000000000000000000000000000
+0369:0080008007800880078000000000000000000000000000000000000000000000000000000000000000000000
+036a:080008000f000880088000000000000000000000000000000000000000000000000000000000000000000000
+036b:5dc0664044404440444000000000000000000000000000000000000000000000000000000000000000000000
+036c:0b800c0008000800080000000000000000000000000000000000000000000000000000000000000000000000
+036d:04001f0004000400070000000000000000000000000000000000000000000000000000000000000000000000
+036e:1080108009000900060000000000000000000000000000000000000000000000000000000000000000000000
+036f:11000a0004000a00110000000000000000000000000000000000000000000000000000000000000000000000
+0370:0000000000007800300030003000300030003fc0300030003000300030003000780000000000000000000000
+0371:000000000000000000000000000078003000300030003fc03000300030003000780000000000000000000000
+0372:000000000000fff0c630c630c6300600060006000600060006000600060006001f8000000000000000000000
+0373:000000000000000000003fe04620462006000600060006000600060006000600060000000000000000000000
+0374:00000000000007000e000c000800000000000000000000000000000000000000000000000000000000000000
+0375:00000000000000000000000000000000000000000000000000000100030007000e0000000000000000000000
+0376:000000000000f0f0606060e06160616062606260646064606860686070606060f0f000000000000000000000
+0377:0000000000000000000000000000f0f0606060e0616062606460686070606060f0f000000000000000000000
+037a:0000000000000000000000000000000000000000000000000000000000000000000000000600060007000000
+037b:00000000000000000000000000000f8011c020e00060006000600060004038801f0000000000000000000000
+037c:00000000000000000000000000001f00388070406000670067006000200011c00f8000000000000000000000
+037d:00000000000000000000000000000f8011c020e000600e600e600060004038801f0000000000000000000000
+037e:000000000000000000000000000000000c001e001e000c00000000000c001e001e00060006000c0018001000
+037f:0000000000001f80060006000600060006000600060006000600060006000600060006000600040038003000
+0384:03800f001c000000000000000000000000000000000000000000000000000000000000000000000000000000
+0385:03800f00dc60c060000000000000000000000000000000000000000000000000000000000000000000000000
+0386:0000000000004600c600cb008b0009001180118010803fc020c0204040604060e0f000000000000000000000
+0387:0000000000000000000000000000000006000f000f0006000000000000000000000000000000000000000000
+0388:0000000000005fe0d820d8209800180018401fc01840180018001800181018103ff000000000000000000000
+0389:000000000000f8f0b060b060b060306030603fe030603060306030603060306078f000000000000000000000
+038a:0000000000004fc0c300c30083000300030003000300030003000300030003000fc000000000000000000000
+038c:0000000000004780c8e0d0609030303030303030303030303030102018200c40078000000000000000000000
+038e:0000000000007c70d820d8208c400c4006800300030003000300030003000300078000000000000000000000
+038f:0000000000004780c8e0d06090303030303030303030102018200c40048024903cf000000000000000000000
+0390:0000000003800f00dc60c06000001e00060006000600060006000600060006001f8000000000000000000000
+0391:000000000000060006000b000b0009001180118010803fc020c0204040604060e0f000000000000000000000
+0392:000000000000ff00608060c060c060c061807f8060c0606060606060606060c0ff8000000000000000000000
+0393:0000000000007fc0304030403000300030003000300030003000300030003000780000000000000000000000
+0394:00000000000006000e000b000b0011801180118020c020c020c04060406040607fe000000000000000000000
+0395:0000000000007fc0304030403000300030803f803080300030003000302030207fe000000000000000000000
+0396:0000000000003fe020c000c00180018003000300060006000c000c00180018203fe000000000000000000000
+0397:000000000000f0f0606060606060606060607fe0606060606060606060606060f0f000000000000000000000
+0398:0000000000000f8011c020e06060606060606f606060606060606060704038801f0000000000000000000000
+0399:0000000000001f800600060006000600060006000600060006000600060006001f8000000000000000000000
+039a:000000000000f0e06180630066006c00780078007c006e006700638061c060e0f07000000000000000000000
+039b:000000000000060006000b000b000b0011801180118020c020c020c040604060e0f000000000000000000000
+039c:000000000000e07060e070e070e070e05960596059604d604e604e6044604460e4f000000000000000000000
+039d:000000000000c07060207020782058204c2046204720432041a040e040e04060e03000000000000000000000
+039e:0000000000007fe0402000000000000000003fc03fc0000000000000000040207fe000000000000000000000
+039f:0000000000000f0011c020c020606060606060606060606060602040304018800f0000000000000000000000
+03a0:000000000000ffe0606060606060606060606060606060606060606060606060606000000000000000000000
+03a1:0000000000007f8030c030603060306030c03780300030003000300030003000780000000000000000000000
+03a3:0000000000007fe060203020180018000c0007000700040008001000202040207fe000000000000000000000
+03a4:0000000000007fe04620060006000600060006000600060006000600060006001f8000000000000000000000
+03a5:000000000000f07060203040188018800d0006000600060006000600060006000f0000000000000000000000
+03a6:000000000600060006000f8017c026e066606660666066606660666076403e801f0006000600060000000000
+03a7:000000000000f07060203040388018800d00060006000b00118011c020c04060e0f000000000000000000000
+03a8:000000000000ef70666066606660666076403f800f00060006000600060006000f0000000000000000000000
+03a9:0000000000000f0011c020c0206060606060606060602040304018800900492079e000000000000000000000
+03aa:30c030c000001f800600060006000600060006000600060006000600060006001f8000000000000000000000
+03ab:30c030c00000f07060203040188018800d0006000600060006000600060006000f0000000000000000000000
+03ac:00000000020006000600040000001f9031d060e060e060c060c060c061e072603c3000000000000000000000
+03ad:00000000020006000600040000000f801fc0206060003f003f00600060203fc01f0000000000000000000000
+03ae:0000000002000600060004000000278079c030c030c030c030c030c030c030c078c000c000c000c000c001e0
+03af:00000000020006000600040000001e00060006000600060006000600060006001f8000000000000000000000
+03b0:000000000200666066600400000079e030c030c030c030c030c030c030c038800f0000000000000000000000
+03b1:00000000000000000000000000001f9031d060e060e060c060c060c061e072603c3000000000000000000000
+03b2:000000000f00198030c030c030c030c031003e00330031c030e030e030603860378030003000300030007800
+03b3:000000000000000000000000000070e0b04030401880188019000d000e0006000e0013001300218021801f00
+03b4:0000000000001f8030001c000e0007000f8011c020e0606060606060704038801f0000000000000000000000
+03b5:00000000000000000000000000000f801fc0206060003f003f00600060203fc01f0000000000000000000000
+03b6:00000000000000007fe000c003000c00180030007000600060006000700030001e00078000c0006000c00380
+03b7:0000000000000000000000000000278079c030c030c030c030c030c030c030c078c000c000c000c000c001e0
+03b8:00000000000000000f8011c020e06060606060607fe0606060606060704038801f0000000000000000000000
+03b9:00000000000000000000000000001e00060006000600060006000600060006001f8000000000000000000000
+03ba:0000000000000000000000000000f1c0630066007c0078007c006e0067006380f1e000000000000000000000
+03bb:0000000000001c001c000e00060006000b000b000b0011801180118020c020c071e000000000000000000000
+03bc:000000000000000000000000000079e030c030c030c030c030c030c030c039c03e6030003000300030007800
+03bd:0000000000000000000000000000f070602030203040184018800c800d000600060000000000000000000000
+03be:00000000000000007fe018003000600038000e0003c0060018006000700038001e00078000c0006000c00380
+03bf:00000000000000000000000000000f8011c020e06060606060606060704038801f0000000000000000000000
+03c0:0000000000000000000000000000fff030c030c030c030c030c030c030c030e0787000000000000000000000
+03c1:00000000000000000000000000000f8011c020e0606060606060606070407880670060006000600060006000
+03c2:00000000000000000000000000000f8011c020e0600060006000600078003f000f80018000c0018007000000
+03c3:00000000000000000000000000000ff011c020606060606060606060704038801f0000000000000000000000
+03c4:00000000000000000000000000007fe00600060006000600060006000600030001e000000000000000000000
+03c5:000000000000000000000000000079e030c030c030c030c030c030c030c038800f0000000000000000000000
+03c6:0000000000000000000000000000098013c026e0666066606660666076403e801f0006000600060006000600
+03c7:00000000000000000000000000006020702018401c800c800700070007000700098009c010c0207020300000
+03c8:0000000000000000000000000000e670666066606660666066606660666076403f800f000600060006000f00
+03c9:00000000000000000000000000006060c030c630c630c630c630c63066207fc0198000000000000000000000
+03ca:00000000000030c030c0000000001e00060006000600060006000600060006001f8000000000000000000000
+03cb:00000000000030c030c00000000079e030c030c030c030c030c030c030c038800f0000000000000000000000
+03cc:00000000020006000600040000000f8011c020e06060606060606060704038801f0000000000000000000000
+03cd:000000000200060006000400000079e030c030c030c030c030c030c030c038800f0000000000000000000000
+03ce:00000000020006000600040000006060c030c630c630c630c630c63066207fc0198000000000000000000000
+03cf:000000000000f0e06180630066006c00780078007c006e006700638061c060e0f07000c001800b0006000200
+03d0:000003800c4010202040ff8020004f8051c060e06060606060606060704038801f0000000000000000000000
+03d1:000000001e0023004180618060c030c00ff000606060b060b060306038401c800f0000000000000000000000
+03d2:0000000000006030d050d8901880188018800d000d00060006000600060006000f0000000000000000000000
+03d3:0180030006006030d050d8901880188018800d000d00060006000600060006000f0000000000000000000000
+03d4:1980198000006030d050d8901880188018800d000d00060006000600060006000f0000000000000000000000
+03d5:000000000600060006000f8017c026e066606660666066606660666076403e801f0006000600060000000000
+03d6:0000000000000000000000703fc0e0604030c630c630c630c630c63066207fc0198000000000000000000000
+03d7:00000000000000000000000000006040b0e0b1c03380378026802c8078c070e06060004001801e0000000000
+03d8:0000000000000f0011c020c020606060606060606060204030401880060006003fc000000000000000000000
+03d9:00000000000000000000000000000f8011c020e06060606060606060704038801f0006000600060000000000
+03da:0000000000000f0011c020c020606000600060006000200030001800060006003fc000000000000000000000
+03db:00000000000000000000002000e00fc010002000600060006000600078003f000f80018000c0018007000000
+03dc:0000000000007fc0304030403000300030803f80308030003000300030003000780000000000000000000000
+03dd:0000000000000000000000401f80300030003000300030003f80300030003000300030003000300000000000
+03de:0000000000003c00180018001800300030003fc000c000c000c001800180018003c000000000000000000000
+03df:00000000000000002000500058001800186031e0364078c060c00180018001a000a000400000000000000000
+03e0:0000000000000f0011c020c02060006001e00660186001e00660004000400080070000000000000000000000
+03e1:0000000000000f0001c000c00060006001e00660186001e00660004000400080010000000000000000000000
+03e2:00000000000036c066606660c630c630c630c630c630c630c630c630c63066207fc001800600180000000000
+03e3:00000000000000000000000036c066606660c630c630c630c630c630c63066207fc001800600180000000000
+03e4:00000000000008e010602060606060606060606060606060706038e01f6000600060006000600060006000f0
+03e5:000000000000000000000000000008e0106020606060606060606060706038e01f60006000600060006000f0
+03e6:000000000000e00060006000600067806fc070e06060606060606060606060c070c0018003003e0000000000
+03e7:000000000000000000000000e0006000600067806fc070e060606060606060c070c0018003003e0000000000
+03e8:000000001f8031c060e020e001c0038007001c0038003000700070007000700070003020306018c00f800000
+03e9:0000000000000000000000001f8031c060e021c0038007001c0038003000700070003020306018c00f800000
+03ea:000018400c800d00070007000b0009801180118010c020c020c0406040604060fff000000000000000000000
+03eb:0000000000000000000018400c800d0007000b000980118010c020c040604060fff000000000000000000000
+03ec:00000000000001e00e0018003000270058807040606060606060606020e011c00f8000000000000000000000
+03ed:0000000000000000000001e00e00180030002700588070406060606020e011c00f8000000000000000000000
+03ee:000000000f000600060006007fe07fe0462046200600060006000600060006000600060006000f0000000000
+03ef:000000000000000000000f00060006007fe07fe0462046200600060006000600060006000f00000000000000
+03f0:00000000000000000000000000006040b0e0b1c03380338026802c8078a070e0606000000000000000000000
+03f1:00000000000000000000000000000f8011c020e06060606060606060704058802700300018000e0001c00000
+03f2:00000000000000000000000000001f8030c020406000600060006000700030c01f8000000000000000000000
+03f3:00000000000000c000c00000000003c000c000c000c000c000c000c000c000c000c020c030c038801f000e00
+03f4:0000000000000f8011c020e06060606060607fe06060606060606060704038801f0000000000000000000000
+03f5:00000000000000000000000000001f803f80600060007f007f00600060003f801f0000000000000000000000
+03f6:00000000000000000000000000003f003f8000c000c01fc01fc000c000c03f803e0000000000000000000000
+03f7:0000000000007800300030003f8030c0306030603060306030c0378030003000780000000000000000000000
+03f8:00000000000000000000000000007800300030003f8030c0306030603060306038c037803000300030007800
+03f9:0000000000000fc01060202020006000600060006000600060002000302018400f8000000000000000000000
+03fa:000000000000e070606070e079604e6044604060406040604060406040604060e0f000000000000000000000
+03fb:00000000000000000000000000000000c0e0c0c0e1c0f2c09cc088c080c080c080d08050803080008000c000
+03fc:00000000000000000000000000000f8011c020e0606060606060606070407880670060006000ff0060006000
+03fd:0000000000003f00608040400040006000600060006000600060004040c021801f0000000000000000000000
+03fe:0000000000000fc01060202020006000600063006300600060002000302018400f8000000000000000000000
+03ff:0000000000003f00608040400040006000600c600c6000600060004040c021801f0000000000000000000000
+0400:1c000f0003807fc0304030403000300030803f803080300030003000302030207fe000000000000000000000
+0401:1980198000007fc0304030403000300030803f803080300030003000302030207fe000000000000000000000
+0402:000000000000ffc08c400c000c000c000ce00f300c300c300c300c300c300db03ee000000000000000000000
+0403:0180030006007fc0304030403000300030003000300030003000300030003000780000000000000000000000
+0404:0000000000000fc0106020202000600061007f006100600060002000302018400f8000000000000000000000
+0405:0000000000001fe030606020602070003c001e00078001c000e04060406060c07f8000000000000000000000
+0406:0000000000001f800600060006000600060006000600060006000600060006001f8000000000000000000000
+0407:1980198000001f800600060006000600060006000600060006000600060006001f8000000000000000000000
+0408:0000000000001f80060006000600060006000600060006000600060006000600060006000600040038003000
+0409:000000000000ffc02300230023002300230023e02330233023302330a330a330c7e000000000000000000000
+040a:000000000000f780630063006300630063007fe0633063306330633063306330f7e000000000000000000000
+040b:000000000000ffc08c400c000c000c000ce00f300e300c300c300c300c300c301e7000000000000000000000
+040c:018003000600f0e06180630066006c00780078007c006e006700638061c060e0f07000000000000000000000
+040d:38001e000700f0f060606060606060e061606260646068607060606060606060f0f000000000000000000000
+040e:606030c00f00f070602030403040188018800d000d000600060004000c000800780070000000000000000000
+040f:000000000000f0f0606060606060606060606060606060606060606060606060fff00f000600000000000000
+0410:000000000000060006000b000b0009001180118010803fc020c0204040604060e0f000000000000000000000
+0411:000000000000ffc0604060406000600060007f8060c0606060606060606060c0ff8000000000000000000000
+0412:000000000000ff00608060c060c060c061807f8060c0606060606060606060c0ff8000000000000000000000
+0413:0000000000007fc0304030403000300030003000300030003000300030003000780000000000000000000000
+0414:0000000000007ff020c020c020c020c020c020c020c020c040c040c040c040c0fff0c030c030801000000000
+0415:0000000000007fc0304030403000300030803f803080300030003000302030207fe000000000000000000000
+0416:000000000000ef30c6106620664036801f000e0007000ec016c0266046608630cf7000000000000000000000
+0417:000000004f807fc060e04060006000e007c00fc000e000600060406060403f801f0000000000000000000000
+0418:000000000000f0f060606060606060e061606260646068607060606060606060f0f000000000000000000000
+0419:606030c00f00f0f060606060606060e061606260646068607060606060606060f0f000000000000000000000
+041a:000000000000f0e06180630066006c00780078007c006e006700638061c060e0f07000000000000000000000
+041b:0000000000003fe010c010c010c010c010c010c020c020c020c0a0c0e0c0e0c0c1e000000000000000000000
+041c:000000000000e07060e070e070e070e05960596059604d604e604e6044604460e4f000000000000000000000
+041d:000000000000f0f0606060606060606060607fe0606060606060606060606060f0f000000000000000000000
+041e:0000000000000f0011c020c020606060606060606060606060602040304018800f0000000000000000000000
+041f:000000000000fff0606060606060606060606060606060606060606060606060f0f000000000000000000000
+0420:0000000000007f8030c030603060306030c03780300030003000300030003000780000000000000000000000
+0421:0000000000000fc01060202020006000600060006000600060002000302018400f8000000000000000000000
+0422:0000000000007fe04620060006000600060006000600060006000600060006001f8000000000000000000000
+0423:000000000000f070602030403040188018800d000d000600060004000c000800780070000000000000000000
+0424:0000000000001f8006000f8017c026e0666066606660666076403e801f0006001f8000000000000000000000
+0425:000000000000f07060203040388018800d00060006000b00118011c020c04060e0f000000000000000000000
+0426:000000000000f1e060c060c060c060c060c060c060c060c060c060c060c060c0fff000300030001000000000
+0427:00000000000079e030c030c030c030c030c030c039c01ec000c000c000c000c001e000000000000000000000
+0428:000000000000f6f0666066606660666066606660666066606660666066606660fff000000000000000000000
+0429:000000000000f6f0666066606660666066606660666066606660666066606660fff000300030001000000000
+042a:000000000000fc00980098001800180018001f801fc018e018601860186018c01f8000000000000000000000
+042b:000000000000e0f0c060c060c060c060fc60fe60c760c360c360c360c360c660fcf000000000000000000000
+042c:000000000000780030003000300030003f003f8031c030c030c030c030c031807f0000000000000000000000
+042d:0000000000003f00608040400040006008600fe0086000600060004040c021801f0000000000000000000000
+042e:000000000000e180c2e0c460c430cc30cc30fc30cc30cc30cc30c420c620c340e18000000000000000000000
+042f:0000000000000ff0186030603060306010600fe003e007600e601c6038607060e0f000000000000000000000
+0430:00000000000000000000000000000f8018c010c003c01cc030c030c030c039c01ee000000000000000000000
+0431:0000000000000fc01f80200020004f8051c060e06060606060606060704038801f0000000000000000000000
+0432:0000000000000000000000000000ff00608060c061807f8060c06060606060c0ff8000000000000000000000
+0433:00000000000000000000000000007fc030403000300030003000300030003000780000000000000000000000
+0434:00000000000000000000000000003ff0118011801180118011802180218021807ff060606060402000000000
+0435:00000000000000000000000000000f0030c0606060607fe060006000300018600f8000000000000000000000
+0436:0000000000000000000000000000ef30c610662066403f801fc0266046608630cf7000000000000000000000
+0437:0000000000000000000000004f807fc06060006007c00fc00060406060403f801f0000000000000000000000
+0438:0000000000000000000000000000f0f0606060e0616062606460686070606060f0f000000000000000000000
+0439:00000000606030c00f0000000000f0f0606060e0616062606460686070606060f0f000000000000000000000
+043a:0000000000000000000000000000f1c0630066007c0078007c006e0067006380f1e000000000000000000000
+043b:00000000000000000000000000001fe008c008c008c010c010c010c050c070c061e000000000000000000000
+043c:0000000000000000000000000000e07060e070e0596059604d604e6046604460e4f000000000000000000000
+043d:0000000000000000000000000000f1e060c060c060c07fc060c060c060c060c0f1e000000000000000000000
+043e:00000000000000000000000000000f8011c020e06060606060606060704038801f0000000000000000000000
+043f:00000000000000000000000000007fe030c030c030c030c030c030c030c030c079e000000000000000000000
+0440:0000000000000000000000000000ef8071c060e06060606060606060604070807f006000600060006000f000
+0441:00000000000000000000000000001f8031c020c06000600060006000704030c01f8000000000000000000000
+0442:00000000000000000000000000007fe0462006000600060006000600060006001f8000000000000000000000
+0443:0000000000000000000000000000f0f0602030403040188018800d000d000600060004000c00080078007000
+0444:0000000000000f0006000600060036c07fe0ef70c630c630c630c6304f207fe036c006000600060006000f00
+0445:0000000000000000000000000000f8f0704038801d000e0007000b8011c020e0f1f000000000000000000000
+0446:000000000000000000000000000079e030c030c030c030c030c030c030c030c07ff000300030001000000000
+0447:000000000000000000000000000079e030c030c030c039c01ec000c000c000c001e000000000000000000000
+0448:0000000000000000000000000000f6f066606660666066606660666066606660fff000000000000000000000
+0449:0000000000000000000000000000f6f066606660666066606660666066606660fff000300030001000000000
+044a:0000000000000000000000000000fc00980098001f801fc018e01860186018c01f8000000000000000000000
+044b:0000000000000000000000000000e0f0c060c060fc60fe60c760c360c360c660fcf000000000000000000000
+044c:00000000000000000000000000007800300030003f003f8031c030c030c031807f0000000000000000000000
+044d:00000000000000000000000000003f006080404008600fe00860006040c021801f0000000000000000000000
+044e:0000000000000000000000000000f18062e0646064307c306c30642066206340f18000000000000000000000
+044f:00000000000000000000000000001fe030c060c020c01fc007c00ec01cc038c071e000000000000000000000
+0450:0000000000001c000f00038000000f0030c0606060607fe060006000300018600f8000000000000000000000
+0451:00000000000019801980000000000f0030c0606060607fe060006000300018600f8000000000000000000000
+0452:000000001000300070003000fe003000378039c030c030c030c030c030c030c078c000c030c038801f000e00
+0453:00000000030006000c00000000007fc030403000300030003000300030003000780000000000000000000000
+0454:00000000000000000000000000000fc01060202061007f0061006000302018400f8000000000000000000000
+0455:00000000000000000000000000001fc030c0304038001e00078001c020c030c03f8000000000000000000000
+0456:00000000000006000600000000001e00060006000600060006000600060006001f8000000000000000000000
+0457:00000000000019801980000000001e00060006000600060006000600060006001f8000000000000000000000
+0458:00000000000000c000c00000000003c000c000c000c000c000c000c000c000c000c020c030c038801f000e00
+0459:00000000000000000000000000003f8013001300130023e023302330a330e330c7e000000000000000000000
+045a:0000000000000000000000000000f7806300630063007fe06330633063306330f7e000000000000000000000
+045b:000000001000300070003000fe003000378039c030c030c030c030c030c030c079e000000000000000000000
+045c:00000000030006000c0000000000f1c0630066007c0078007c006e0067006380f1e000000000000000000000
+045d:000000001c000f00038000000000f0f0606060e0616062606460686070606060f0f000000000000000000000
+045e:00000000606030c00f0000000000f0f0602030403040188018800d000d000600060004000c00080078007000
+045f:000000000000000000000000000079e030c030c030c030c030c030c030c030c07fe00f000600000000000000
+0460:000000000000fef066206620662076207740334037403bc03b80198019801980198000000000000000000000
+0461:0000000000000000000000000000ff7066206620662037403b403b4019801980198000000000000000000000
+0462:000000000000fc0098001800ff80180018001f801fc018e018601860186018c01f8000000000000000000000
+0463:000000000000000000000000fc001800ff8018001f801fc018e01860186018c01f8000000000000000000000
+0464:000000000000e3c0446048204800580059007f0059005800580048004c204640e38000000000000000000000
+0465:0000000000000000000000000000e3c04460482059007f00590048004c204640e38000000000000000000000
+0466:000000000000060006000b000b0009001180118010803fc024c0244044604460e4f000000000000000000000
+0467:0000000000000000000000000000060006000b000900118010803fc024c04460e4f000000000000000000000
+0468:000000000000e60046004b004b0049005180518050807fc064c0644044604460e4f000000000000000000000
+0469:0000000000000000000000000000e60046004b004900518050807fc064c04460e4f000000000000000000000
+046a:000000000000fff060203040188018800d003fc04660c630c630c630c630c630ef7000000000000000000000
+046b:00000000000000000000000000007fe0304018800d003fc04660c630c630c630ef7000000000000000000000
+046c:000000000000fff0b02098408c8086808700ffe0b330b330b330b330b330b330f77000000000000000000000
+046d:0000000000000000000000000000fff0b02098408c808700ffe0b330b330b330f77000000000000000000000
+046e:19800f00060000000f801fc020e04060006000e007c00fc000e00060006000803f00600060003c001f000000
+046f:000019800f000600000000000f801fc020e0406000e007c00fc000e0006000803f00600060003c001f000000
+0470:000000000000ef70666066606660666076403f800f00060006000600060006000f0000000000000000000000
+0471:0000000000000000000000000000e670666066606660666066606660666076403f800f000600060006000f00
+0472:0000000000000f0011c020c02060606060607c6063e0606060602040304018800f0000000000000000000000
+0473:00000000000000000000000000000f0011c020c060607c6063e02040304018800f0000000000000000000000
+0474:000000000000f020607030d0309030801900190019000e000e000e0004000400040000000000000000000000
+0475:0000000000000000000000000000f020607030d03080190019000e000e000400040000000000000000000000
+0476:e38079e01c70f020607030d0309030801900190019000e000e000e0004000400040000000000000000000000
+0477:00000000e38079e01c7000000000f020607030d03080190019000e000e000400040000000000000000000000
+0478:0000000000003000380048004c00cf30ce10ce10cd20cd20cd2049c068c038c010800080018001000f000e00
+0479:00000000000000000000000000003000380048004c00cf30ce10cd20cd2049c068c038c0108001800f000e00
+047a:000000000e001f802ee040604030c030c030c030c030c030c0304020602037401f8007000000000000000000
+047b:0000000000000000000000000e001f802ee040604030c030c0304020602037401f8007000000000000000000
+047c:0c00338040e00e006160c130c630c030c030c030c030c030c630c630c63066207fc019800000000000000000
+047d:0000000000000c00338040e00e006160c130c630c030c030c630c63066207fc0198000000000000000000000
+047e:7fc044400000fef066206620662076207740334037403bc03b80198019801980198000000000000000000000
+047f:0000000000007fc0444000000000fef0662066207740334037403bc019801980198000000000000000000000
+0480:0000000000000fc01060202020006000600060006000600060002000306018e00fe0006000600060006000f0
+0481:00000000000000000000000000000f8010c02040200060006000200030c019c00fc000c000c000c000c001e0
+0482:00000000000000000000000000000000000000000180018003003b00070006e0ec001c001b80180030003000
+0483:00603fc060000000000000000000000000000000000000000000000000000000000000000000000000000000
+0484:03c0066006600000000000000000000000000000000000000000000000000000000000000000000000000000
+0485:0f000c0007000000000000000000000000000000000000000000000000000000000000000000000000000000
+0486:0f0003000e000000000000000000000000000000000000000000000000000000000000000000000000000000
+0487:3c006780c0e00000000000000000000000000000000000000000000000000000000000000000000000000000
+0488:04000a0000000000204050a000000000000000004020a0500000000000000000204050a00000000004000a00
+0489:08000e000000000040e0702000000000000000008070e010000000000000000040e07020000000000e000200
+048a:606030c00f00f0f060606060606060e061606260646068607060606060606060f0f00030006000c001800000
+048b:00000000606030c00f0000000000f0f0606060e0616062606460686070606060f0f00030006000c001800000
+048c:00000000000030003000fe00300030003f003f8031c030c030c030c030c031807f0000000000000000000000
+048d:00000000000000000000000030003000fe0030003f003f8031c030c030c031807f0000000000000000000000
+048e:0000000000007f8030c030603060366033c03f8030c030603000300030003000780000000000000000000000
+048f:0000000000000000000000000000ef8071c060e06060606060606060664073807f8060c0606060006000f000
+0490:0000004000407fc0300030003000300030003000300030003000300030003000780000000000000000000000
+0491:00000000000000000000004000407fc030003000300030003000300030003000780000000000000000000000
+0492:0000000000003fe018201820180018007f0018001800180018001800180018003c0000000000000000000000
+0493:00000000000000000000000000003fe0182018007f00180018001800180018003c0000000000000000000000
+0494:0000000000007fc030403040300030003000378038c038c030c030c030c030c078c000c008c00cc00f800700
+0495:00000000000000000000000000007fc0304030003000378038c038c030c030c078c000c008c00cc007800000
+0496:000000000000ef30c6106620664036801f000e0007800ec016c0266046608630cf7000300030003000000000
+0497:0000000000000000000000000000ef30c610662066403f801fc0266046608630cf7000300030000000000000
+0498:000000004f807fc060e04060006000e007c00fc000e000600060406060403f801f0004000700010006000000
+0499:0000000000000000000000004f807fc06060006007c00fc00060406060403f801f0004000700010006000000
+049a:000000000000f0e06180630066006c00780078007c006e006700638061c060e0f07000300030003000000000
+049b:0000000000000000000000000000f1c0630066007c0078007c006e0067006380f1f000300030000000000000
+049c:000000000000f07060c069806b006e007c0078007c006e006f006b8069c060e0f07000000000000000000000
+049d:0000000000000000000000000000f0e061806b006e0078006e006f006b8061c0f0f000000000000000000000
+049e:000000000000f07060c0fd80630066007c0078007c006e006700638061c060e0f07000000000000000000000
+049f:0000000000000000f0006000fc0061c0630066007c0078007c006e0067006380f1e000000000000000000000
+04a0:000000000000f870b0c0b180330036003c003c003e003700338031c030e03070783000000000000000000000
+04a1:0000000000000000000000000000f8e0b180b3003e003c003e003700338031c078f000000000000000000000
+04a2:000000000000f0f0606060606060606060607fe0606060606060606060606060f0f000300030003000000000
+04a3:0000000000000000000000000000f0f06060606060607fe06060606060606060f0f000300030000000000000
+04a4:000000000000f3f0619061906180618061807f80618061806180618061806180f3c000000000000000000000
+04a5:0000000000000000000000000000f3f06190618061807f806180618061806180f3c000000000000000000000
+04a6:000000000000ff8063006300630063006300636063b063306330633063306330f7b000300230033003e001c0
+04a7:0000000000000000000000000000ff80630063006300636063b0633063306330f7b000300230033001e00000
+04a8:0000000000000e001000218022c064606c606c606c606c606c602640314019800e6000000000000000000000
+04a9:00000000000000000000000000000e001000218022c064606c602640314019800e6000000000000000000000
+04aa:0000000000000fc01060202020006000600060006000600060002000302018400f8004000700010006000000
+04ab:00000000000000000000000000001f8031c020c06000600060006000704030c01f8004000700010006000000
+04ac:0000000000007fe04620060006000600060006000600060006000600060006001f8004000700010006000000
+04ad:00000000000000000000000000007fe0462006000600060006000600060006001f8004000700010006000000
+04ae:000000000000f07060203040188018800d0006000600060006000600060006000f0000000000000000000000
+04af:0000000000000000000000000000000078e030403040188018800d000d000600060006000600060006000f00
+04b0:000000000000f07060203040188018800d0006003fc0060006000600060006000f0000000000000000000000
+04b1:0000000000000000000000000000000078e030403040188018800d000d0006003fc006000600060006000f00
+04b2:000000000000f07060203040388018800d00060006000b00118011c020c04060e0f000300030003000000000
+04b3:0000000000000000000000000000f8f0704038801d000e0007000b8011c020e0f1f000300030003000000000
+04b4:000000000000ff709960186018601860186018601860186018601860186018603ff000300030003000000000
+04b5:0000000000000000000000000000ff70996018601860186018601860186018603ff000300030000000000000
+04b6:00000000000079e030c030c030c030c030c030c039c01ec000c000c000c000c001e000300030003000000000
+04b7:000000000000000000000000000079e030c030c030c030c039c01ec000c000c001e000300030003000000000
+04b8:00000000000079e030c030c030c034c034c034c03dc01ec004c004c004c000c001e000300030003000000000
+04b9:000000000000000000000000000079e030c030c034c034c03dc01ec004c004c001e000300030003000000000
+04ba:00000000000078003000300030003000378039c030c030c030c030c030c030c079e000000000000000000000
+04bb:0000000000000000000000000000780030003000378039c030c030c030c030c079e000000000000000000000
+04bc:0000000000000f0011c0a0c0a060ffe0600060006000600060002000304018800f0000000000000000000000
+04bd:0000000000000000000000000000070018c0b060b060ffe03000300018000c60078000000000000000000000
+04be:0000000000000f0011c0a0c0a060ffe0600060006000600060002000304018800f0006000600060000000000
+04bf:0000000000000000000000000000070018c0b060b060ffe03000300018000c60078003000300030000000000
+04c0:0000000000001f800600060006000600060006000600060006000600060006001f8000000000000000000000
+04c1:606030c00f00ef30c6106620664036801f000e0007000ec016c0266046608630cf7000000000000000000000
+04c2:00000000606030c00f0000000000ef30c610662066403f801fc0266046608630cf7000000000000000000000
+04c3:000000000000f0e06180630066006c00780078007c00670061c060e060706030f0300030027003e001800000
+04c4:0000000000000000000000000000f1c0630066006c007c00670061c060e06060f060006004e007c003000000
+04c5:0000000000003fe010c010c010c010c010c010c020c020c020c0a0c0e0c0e0c0c1e0006000c0018003000000
+04c6:00000000000000000000000000001fe008c008c008c010c010c050c070c070c061e0006000c0018003000000
+04c7:000000000000f0f0606060606060606060607fe0606060606060606060606060f060006004e007c003000000
+04c8:0000000000000000000000000000f1e060c060c060c07fc060c060c060c060c0f0c000c009c00f8006000000
+04c9:000000000000f0f0606060606060606060607fe0606060606060606060606060f0f0006000c0018003000000
+04ca:0000000000000000000000000000f1e060c060c060c07fc060c060c060c060c0f1e000c00180030006000000
+04cb:00000000000079e030c030c030c030c030c030c03dc01ec000c000c000c000c001e0006000c0018003000000
+04cc:000000000000000000000000000079e030c030c030c030c03dc01ec000c000c001e0006000c0018003000000
+04cd:000000000000e07060e070e070e070e05960596059604d604e604e6044604460e4f00030006000c001800000
+04ce:0000000000000000000000000000e07060e070e0596059604d604e6046604460e4f00030006000c001800000
+04cf:0000000000001f800600060006000600060006000600060006000600060006001f8000000000000000000000
+04d0:606030c00f00060006000b000b0009001180118010803fc020c0204040604060e0f000000000000000000000
+04d1:00000000606030c00f00000000000f8018c010c003c01cc030c030c030c039c01ee000000000000000000000
+04d2:198019800000060006000b000b0009001180118010803fc020c0204040604060e0f000000000000000000000
+04d3:00000000000019801980000000000f8018c010c003c01cc030c030c030c039c01ee000000000000000000000
+04d4:0000000000000fe00e20162016001600164027c026403e002600460046104610e7f000000000000000000000
+04d5:00000000000000000000000000001f80364026600e603fe066006600660067603fc000000000000000000000
+04d6:606030c00f007fc0304030403000300030803f803080300030003000302030207fe000000000000000000000
+04d7:00000000606030c00f00000000000f0030c0606060607fe060006000300018600f8000000000000000000000
+04d8:0000000000003f0060804040004000600060006000607fe04040404040c021801f0000000000000000000000
+04d9:00000000000000000000000000003f0060804040006000607fe0404040c021801f0000000000000000000000
+04da:1980198000003f0060804040004000600060006000607fe04040404040c021801f0000000000000000000000
+04db:00000000000019801980000000003f0060804040006000607fe0404040c021801f0000000000000000000000
+04dc:198019800000ef30c6106620664036801f000e0007800ec016c0266046608630cf7000000000000000000000
+04dd:0000000000001980198000000000ef30c610662066403f801fc0266046608630cf7000000000000000000000
+04de:198019804f807fc060e04060006000e007c00fc000e000600060406060403f801f0000000000000000000000
+04df:0000000019801980000000004f807fc06060006007c00fc00060406060403f801f0000000000000000000000
+04e0:0000000000007fe040c00180030006000c001f8001c000c000c040c060803f001e0000000000000000000000
+04e1:00000000000000000000000000003fe020c00180030006000c001f8001c000c000c020c030801f000e000000
+04e2:3fc000000000f0f060606060606060e061606260646068607060606060606060f0f000000000000000000000
+04e3:00000000000000003fc000000000f0f0606060e0616062606460686070606060f0f000000000000000000000
+04e4:198019800000f0f060606060606060e061606260646068607060606060606060f0f000000000000000000000
+04e5:0000000000001980198000000000f0f0606060e0616062606460686070606060f0f000000000000000000000
+04e6:1980198000000f0011c020c020606060606060606060606060602040304018800f0000000000000000000000
+04e7:00000000000019801980000000000f8011c020e06060606060606060704038801f0000000000000000000000
+04e8:0000000000000f8011c020e06060606060607fe06060606060606060704038801f0000000000000000000000
+04e9:00000000000000000000000000000f8011c020e060607fe060606060704038801f0000000000000000000000
+04ea:1980198000000f8011c020e06060606060607fe06060606060606060704038801f0000000000000000000000
+04eb:00000000000019801980000000000f8011c020e060607fe060606060704038801f0000000000000000000000
+04ec:1980198000003f00608040400040006008600fe0086000600060004040c021801f0000000000000000000000
+04ed:00000000000019801980000000003f006080404008600fe00860006040c021801f0000000000000000000000
+04ee:3fc000000000f070602030403040188018800d000d000600060004000c000800780070000000000000000000
+04ef:00000000000000003fc000000000f0f0602030403040188018800d000d000600060004000c00080078007000
+04f0:198019800000f070602030403040188018800d000d000600060004000c000800780070000000000000000000
+04f1:0000000000001980198000000000f0f0602030403040188018800d000d000600060004000c00080078007000
+04f2:06c00d801b00f070602030403040188018800d000d000600060004000c000800780070000000000000000000
+04f3:0000000006c00d801b0000000000f0f0602030403040188018800d000d000600060004000c00080078007000
+04f4:19801980000079e030c030c030c030c030c030c039c01ec000c000c000c000c001e000000000000000000000
+04f5:000000000000198019800000000079e030c030c030c039c01ec000c000c000c001e000000000000000000000
+04f6:0000000000007fc03040304030003000300030003000300030003000300030007c000c000c000c0000000000
+04f7:00000000000000000000000000007fc0304030003000300030003000300030007c000c000c00000000000000
+04f8:198019800000e0f0c060c060c060c060fc60fe60c760c360c360c360c360c660fcf000000000000000000000
+04f9:0000000000001980198000000000e0f0c060c060fc60fe60c760c360c360c660fcf000000000000000000000
+04fa:0000000000003fe018201820180018007f0018001800180018001800180018003e0002002200320032001c00
+04fb:00000000000000000000000000003fe0182018007f00180018001800180018003e0002002200320032001c00
+04fc:000000000000f07060203040388018800d00060006000b00118011c020c04060e060026003c0018000000000
+04fd:0000000000000000000000000000f8f0704038801d000e0007000b8011c020c0f0e00060026003c001800000
+04fe:000000000000f07060203040388018800d007fe006000b00118011c020c04060e0f000000000000000000000
+04ff:0000000000000000000000000000f8f0704038801d007fe007000b8011c020e0f1f000000000000000000000
+05d0:0000000000000000000000000000e1e06060306018c03cc067806300c180c0c0f0e000000000000000000000
+1e00:000000000000060006000b000b0009001180118010803fc020c0204040604060e0f000000600090009000600
+1e01:00000000000000000000000000000f8018c010c003c01cc030c030c030c039c01ee000000600090009000600
+1e02:0c000c000000ff00608060c060c060c061807f8060c0606060606060606060c0ff8000000000000000000000
+1e03:0600060020006000e0006000600067806fc070e06060606060606060706078c04f8000000000000000000000
+1e04:000000000000ff00608060c060c060c061807f8060c0606060606060606060c0ff8000000000060006000000
+1e05:0000000020006000e0006000600067806fc070e06060606060606060706078c04f8000000000060006000000
+1e06:000000000000ff00608060c060c060c061807f8060c0606060606060606060c0ff80000000003fc03fc00000
+1e07:0000000020006000e0006000600067806fc070e06060606060606060706078c04f80000000003fc03fc00000
+1e08:03800f001c000fc01060202020006000600060006000600060002000302018400f8002000300018009800700
+1e09:0000000003800f001c00000000001f8031c020c06000600060006000704030c01f8002000300018009800700
+1e0a:060006000000ff0061c060c06060606060606060606060606060606060406180fe0000000000000000000000
+1e0b:06000600006000e00060006000600f6031e020e0606060606060606070e039601e7000000000000000000000
+1e0c:000000000000ff0061c060c06060606060606060606060606060606060406180fe0000000000060006000000
+1e0d:00000000006000e00060006000600f6031e020e0606060606060606070e039601e7000000000060006000000
+1e0e:000000000000ff0061c060c06060606060606060606060606060606060406180fe00000000003fc03fc00000
+1e0f:00000000006000e00060006000600f6031e020e0606060606060606070e039601e70000000003fc03fc00000
+1e10:000000000000ff0061c060c06060606060606060606060606060606060406180fe0002000300018009800700
+1e11:00000000006000e00060006000600f6031e020e0606060606060606070e039601e7002000300018009800700
+1e12:000000000000ff0061c060c06060606060606060606060606060606060406180fe00000004000e001b003180
+1e13:00000000006000e00060006000600f6031e020e0606060606060606070e039601e70000004000e001b003180
+1e14:0e0007003fc000007fc0304030403000300030803f80308030003000302030207fe000000000000000000000
+1e15:1c000f00038000001f801f8000000f0030c0606060607fe060006000300018600f8000000000000000000000
+1e16:07000e003fc000007fc0304030403000300030803f80308030003000302030207fe000000000000000000000
+1e17:03800f001c0000001f801f8000000f0030c0606060607fe060006000300018600f8000000000000000000000
+1e18:0000000000007fc0304030403000300030803f803080300030003000302030207fe0000004000e001b003180
+1e19:00000000000000000000000000000f0030c0606060607fe060006000300018600f80000004000e001b003180
+1e1a:0000000000007fc0304030403000300030803f803080300030003000302030207fe000000e401fc013800000
+1e1b:00000000000000000000000000000f0030c0606060607fe060006000300018600f8000000e401fc013800000
+1e1c:198019800f007fc0304030403000300030803f803080300030003000302030207fe002000300018009800700
+1e1d:00000000198019800f00000000000f0030c0606060607fe060006000300018600f8002000300018009800700
+1e1e:0600060000007fc0304030403000300030803f80308030003000300030003000780000000000000000000000
+1e1f:030003000000038004c004c00c000c000c000c001f800c000c000c000c000c001e0000000000000000000000
+1e20:1f801f8000000fc0106020202000600060006000600061f060602060306018600f8000000000000000000000
+1e21:0000000000001f801f80000000001f2031e060c060c060c031803f0060007fc03fe02060402040207fc03f80
+1e22:060006000000f0f0606060606060606060607fe0606060606060606060606060f0f000000000000000000000
+1e23:0300030010003000700030003000378039c030c030c030c030c030c030c030c079e000000000000000000000
+1e24:000000000000f0f0606060606060606060607fe0606060606060606060606060f0f000000600060000000000
+1e25:0000000010003000700030003000378039c030c030c030c030c030c030c030c079e000000600060000000000
+1e26:198019800000f0f0606060606060606060607fe0606060606060606060606060f0f000000000000000000000
+1e27:0cc00cc010003000700030003000378039c030c030c030c030c030c030c030c079e000000000000000000000
+1e28:000000000000f0f0606060606060606060607fe0606060606060606060606060f0f0100018000c004c003800
+1e29:0000000010003000700030003000378039c030c030c030c030c030c030c030c079e0100018000c004c003800
+1e2a:000000000000f0f0606060606060606060607fe0606060606060606060606060f0f00000198019800f000000
+1e2b:0000000010003000700030003000378039c030c030c030c030c030c030c030c079e00000198019800f000000
+1e2c:0000000000001f800600060006000600060006000600060006000600060006001f8000000e401fc013800000
+1e2d:00000000000006000600000000001e00060006000600060006000600060006001f8000000e401fc013800000
+1e2e:030066606c6000001f80060006000600060006000600060006000600060006001f8000000000000000000000
+1e2f:03800f001c0000001980198000001e00060006000600060006000600060006001f8000000000000000000000
+1e30:03800f001c00f0e06180630066006c00780078007c006e006700638061c060e0f07000000000000000000000
+1e31:01c007806e00e00060006000600061c0630066007c0078007c006e0067006380f1e000000000000000000000
+1e32:000000000000f0e06180630066006c00780078007c006e006700638061c060e0f07000000600060000000000
+1e33:000000006000e00060006000600061c0630066007c0078007c006e0067006380f1e000000600060000000000
+1e34:000000000000f0e06180630066006c00780078007c006e006700638061c060e0f070000000003fc03fc00000
+1e35:000000006000e00060006000600061c0630066007c0078007c006e0067006380f1e0000000003fc03fc00000
+1e36:00000000000078003000300030003000300030003000300030003000302030207fe000000600060000000000
+1e37:000000001e0006000600060006000600060006000600060006000600060006001f8000000600060000000000
+1e38:3fc03fc0000078003000300030003000300030003000300030003000302030207fe000000600060000000000
+1e39:3fc03fc000001e000600060006000600060006000600060006000600060006001f8000000600060000000000
+1e3a:00000000000078003000300030003000300030003000300030003000302030207fe0000000003fc03fc00000
+1e3b:000000001e0006000600060006000600060006000600060006000600060006001f80000000003fc03fc00000
+1e3c:00000000000078003000300030003000300030003000300030003000302030207fe0000004000e001b003180
+1e3d:000000001e0006000600060006000600060006000600060006000600060006001f80000004000e001b003180
+1e3e:03800f001c00e07060e070e070e070e05960596059604d604e604e6044604460e4f000000000000000000000
+1e3f:0000000003800f001c0000000000ddc06ee06660666066606660666066606660ef7000000000000000000000
+1e40:060006000000e07060e070e070e070e05960596059604d604e604e6044604460e4f000000000000000000000
+1e41:0000000000000600060000000000ddc06ee06660666066606660666066606660ef7000000000000000000000
+1e42:000000000000e07060e070e070e070e05960596059604d604e604e6044604460e4f000000600060000000000
+1e43:0000000000000000000000000000ddc06ee06660666066606660666066606660ef7000000600060000000000
+1e44:060006000000c07060207020782058204c2046204720432041a040e040e04060e03000000000000000000000
+1e45:0000000000000600060000000000278079c030c030c030c030c030c030c030c079e000000000000000000000
+1e46:000000000000c07060207020782058204c2046204720432041a040e040e04060e03000000600060000000000
+1e47:0000000000000000000000000000278079c030c030c030c030c030c030c030c079e000000600060000000000
+1e48:000000000000c07060207020782058204c2046204720432041a040e040e04060e030000000003fc03fc00000
+1e49:0000000000000000000000000000278079c030c030c030c030c030c030c030c079e0000000003fc03fc00000
+1e4a:000000000000c07060207020782058204c2046204720432041a040e040e04060e030000004000e001b003180
+1e4b:0000000000000000000000000000278079c030c030c030c030c030c030c030c079e0000004000e001b003180
+1e4c:07001e003c6063c00f0011c020c02060606060606060606060602040304018800f0000000000000000000000
+1e4d:03800f001c0000003c6063c000000f8011c020e06060606060606060704038801f0000000000000000000000
+1e4e:1980198000003c6063c00f0011c020c0206060606060606060602040304018800f0000000000000000000000
+1e4f:1980198000001c6036c0638000000f8011c020e06060606060606060704038801f0000000000000000000000
+1e50:0e0007003fc000000f0011c020c02060606060606060606060602040304018800f0000000000000000000000
+1e51:1c000f00038000003fc03fc000000f8011c020e06060606060606060704038801f0000000000000000000000
+1e52:07000e003fc000000f0011c020c02060606060606060606060602040304018800f0000000000000000000000
+1e53:03800f001c0000003fc03fc000000f8011c020e06060606060606060704038801f0000000000000000000000
+1e54:03800f001c007f8030c030603060306030c03780300030003000300030003000780000000000000000000000
+1e55:0000000003800f001c0000000000ef8071c060e06060606060606060604070807f006000600060006000f000
+1e56:0600060000007f8030c030603060306030c03780300030003000300030003000780000000000000000000000
+1e57:0000000000000600060000000000ef8071c060e06060606060606060604070807f006000600060006000f000
+1e58:0c000c000000ff00618060c060c060c060807f007c006e006700638061c060e0f07000000000000000000000
+1e59:0000000000000600060000000000738034c038c0300030003000300030003000780000000000000000000000
+1e5a:000000000000ff00618060c060c060c060807f007c006e006700638061c060e0f07000000600060000000000
+1e5b:0000000000000000000000000000738034c038c0300030003000300030003000780000001800180000000000
+1e5c:3fc03fc00000ff00618060c060c060c060807f007c006e006700638061c060e0f07000000600060000000000
+1e5d:0000000000003fc03fc000000000738034c038c0300030003000300030003000780000001800180000000000
+1e5e:000000000000ff00618060c060c060c060807f007c006e006700638061c060e0f070000000003fc03fc00000
+1e5f:0000000000000000000000000000738034c038c03000300030003000300030007800000000003fc03fc00000
+1e60:0600060000001fe030606020602070003c001e00078001c000e04060406060c07f8000000000000000000000
+1e61:00000000000006000600000000001fc030c0304038001e00078001c020c030c03f8000000000000000000000
+1e62:0000000000001fe030606020602070003c001e00078001c000e04060406060c07f8000000600060000000000
+1e63:00000000000000000000000000001fc030c0304038001e00078001c020c030c03f8000000600060000000000
+1e64:0c700de003801fe030606020602070003c001e00078001c000e04060406060c07f8000000000000000000000
+1e65:06000600000003800f001c0000001fc030c0304038001e00078001c020c030c03f8000000000000000000000
+1e66:060036c0198006001fe030606020602070003c000e0003c000e04060406060c07f8000000000000000000000
+1e67:06000600000030c01980060000001fc030c0304038001e00078001c020c030c03f8000000000000000000000
+1e68:0600060000001fe030606020602070003c001e00078001c000e04060406060c07f8000000600060000000000
+1e69:00000000000006000600000000001fc030c0304038001e00078001c020c030c03f8000000600060000000000
+1e6a:0600060000007fe04620060006000600060006000600060006000600060006001f8000000000000000000000
+1e6b:00000c000c000000040004000c007fc00c000c000c000c000c000c000c200e40078000000000000000000000
+1e6c:0000000000007fe04620060006000600060006000600060006000600060006001f8000000600060000000000
+1e6d:0000000000000000040004000c007fc00c000c000c000c000c000c000c200e40078000000600060000000000
+1e6e:0000000000007fe04620060006000600060006000600060006000600060006001f80000000003fc03fc00000
+1e6f:0000000000000000040004000c007fc00c000c000c000c000c000c000c200e400780000000003fc03fc00000
+1e70:0000000000007fe04620060006000600060006000600060006000600060006001f80000004000e001b003180
+1e71:0000000000000000040004000c007fc00c000c000c000c000c000c000c200e400780000004000e001b003180
+1e72:000000000000f070602060206020602060206020602060206020602070403fc01f8000001980198000000000
+1e73:000000000000000000000000000079e030c030c030c030c030c030c030c039c01e6000001980198000000000
+1e74:000000000000f070602060206020602060206020602060206020602070403fc01f8000000e401fc013800000
+1e75:000000000000000000000000000079e030c030c030c030c030c030c030c039c01e6000000e401fc013800000
+1e76:000000000000f070602060206020602060206020602060206020602070403fc01f80000004000e001b003180
+1e77:000000000000000000000000000079e030c030c030c030c030c030c030c039c01e60000004000e001b003180
+1e78:07001e003c6063c00000f0706020602060206020602060206020602070403fc01f8000000000000000000000
+1e79:03800f001c0000003c6063c0000079e030c030c030c030c030c030c030c039c01e6000000000000000000000
+1e7a:1980198000003fc0f07060206020602060206020602060206020602070403fc01f8000000000000000000000
+1e7b:00001980198000003fc03fc0000079e030c030c030c030c030c030c030c039c01e6000000000000000000000
+1e7c:0e401fc01380e0e060403080308030801900190019000c000e000e0004000400040000000000000000000000
+1e7d:000000000e401fc0138000000000f070602030403040188018800d000d000600060000000000000000000000
+1e7e:000000000000e0e060403080308030801900190019000c000e000e0004000400040000000600060000000000
+1e7f:0000000000000000000000000000f070602030403040188018800d000d000600060000000600060000000000
+1e80:1c000f000380fef066206620662076207740334037403bc03b80198019801980198000000000000000000000
+1e81:000000001c000f00038000000000ff7066206620662037403b403b4019801980198000000000000000000000
+1e82:03800f001c00fef066206620662076207740334037403bc03b80198019801980198000000000000000000000
+1e83:0000000003800f001c0000000000ff7066206620662037403b403b4019801980198000000000000000000000
+1e84:198019800000fef066206620662076207740334037403bc03b80198019801980198000000000000000000000
+1e85:0000000000001980198000000000ff7066206620662037403b403b4019801980198000000000000000000000
+1e86:060006000000fef066206620662076207740334037403bc03b80198019801980198000000000000000000000
+1e87:0000000000000600060000000000ff7066206620662037403b403b4019801980198000000000000000000000
+1e88:000000000000fef066206620662076207740334037403bc03b80198019801980198000000000060006000000
+1e89:0000000000000000000000000000ff7066206620662037403b403b4019801980198000000000060006000000
+1e8a:060006000000f07060203040388018800d00060006000b00118011c020c04060e0f000000000000000000000
+1e8b:0000000000000600060000000000f8f0704038801d000e0007000b8011c020e0f1f000000000000000000000
+1e8c:198019800000f07060203040388018800d00060006000b00118011c020c04060e0f000000000000000000000
+1e8d:0000000000001980198000000000f8f0704038801d000e0007000b8011c020e0f1f000000000000000000000
+1e8e:060006000000f07060203040188018800d0006000600060006000600060006000f0000000000000000000000
+1e8f:0000000000000600060000000000f0f0602030403040188018800d000d000600060004000c00080078007000
+1e90:020007000d8018c000003fe020c000c001800180030006000c000c00180018203fe000000000000000000000
+1e91:00000000020007000d8018c000007fe060e041c0038007000e001c00382070607fe000000000000000000000
+1e92:0000000000003fe020c000c00180018003000300060006000c000c00180018203fe000000600060000000000
+1e93:00000000000000000000000000007fe060e041c0038007000e001c00382070607fe000000600060000000000
+1e94:0000000000003fe020c000c00180018003000300060006000c000c00180018203fe0000000003fc03fc00000
+1e95:00000000000000000000000000007fe060e041c0038007000e001c00382070607fe0000000003fc03fc00000
+1e96:0000000010003000700030003000378039c030c030c030c030c030c030c030c079e0000000003fc03fc00000
+1e97:000018c018c00000040004000c007fc00c000c000c000c000c000c000c200e40078000000000000000000000
+1e98:0000060009000900060000000000ff7066206620662037403b403b4019801980198000000000000000000000
+1e99:0000060009000900060000000000f0f0602030403040188018800d000d000600060004000c00080078007000
+1e9a:00000200010001000200000000000f8018c010c003c01cc030c030c030c039c01ee000000000000000000000
+1e9b:060006000000038004c004c00c000c000c003c000c000c000c000c000c000c001e0000000000000000000000
+1e9c:00000000038004c004c00c000c000d800f003e000c001c003c006c000c000c001e0000000000000000000000
+1e9d:00000000038004c004c00c007f807f800c003c000c000c000c000c000c000c001e0000000000000000000000
+1e9e:000000000f80386030e061c0638067006e00638061c060e06060606068606cc0ef8000000000000000000000
+1e9f:0000000000001f8030001c000e0007000f8011c020e0606060606060704038801f0000000000000000000000
+1ea0:000000000000060006000b000b0009001180118010803fc020c0204040604060e0f000000600060000000000
+1ea1:00000000000000000000000000000f8018c010c003c01cc030c030c030c039c01ee000000600060000000000
+1ea2:0e0013000300060006000b000b0009001180118010803fc020c0204040604060e0f000000000000000000000
+1ea3:000000000e0013000300060000000f8018c010c003c01cc030c030c030c039c01ee000000000000000000000
+1ea4:307079e0cd80060006000b000b0009001180118010803fc020c0204040604060e0f000000000000000000000
+1ea5:00000000307079e0cd80000000000f8018c010c003c01cc030c030c030c039c01ee000000000000000000000
+1ea6:31c078f0cc30060006000b000b0009001180118010803fc020c0204040604060e0f000000000000000000000
+1ea7:0000000031c078f0cc30000000000f8018c010c003c01cc030c030c030c039c01ee000000000000000000000
+1ea8:30e07930cc30066006000b000b0009001180118010803fc020c0204040604060e0f000000000000000000000
+1ea9:0000000030e07930cc30006000000f8018c010c003c01cc030c030c030c039c01ee000000000000000000000
+1eaa:3c6063c006001980000006000b000b000900118010803fc020c0204040604060e0f000000000000000000000
+1eab:3c6063c0000006000f00198000000f8018c010c003c01cc030c030c030c039c01ee000000000000000000000
+1eac:06000f001980060006000b000b0009001180118010803fc020c0204040604060e0f000000600060000000000
+1ead:04000e001b00318060c0000000000f8018c010c003c01cc030c030c030c039c01ee000000600060000000000
+1eae:01c007802e401f8006000b000b0009001180118010803fc020c0204040604060e0f000000000000000000000
+1eaf:01c007800e00000030c00f0000000f8018c010c003c01cc030c030c030c039c01ee000000000000000000000
+1eb0:38001e0027401f8006000b000b0009001180118010803fc020c0204040604060e0f000000000000000000000
+1eb1:38001e000700000030c00f0000000f8018c010c003c01cc030c030c030c039c01ee000000000000000000000
+1eb2:0700098023401f8006000b000b0009001180118010803fc020c0204040604060e0f000000000000000000000
+1eb3:0e0013000300060020401f8000000f8018c010c003c01cc030c030c030c039c01ee000000000000000000000
+1eb4:3c6063c020401f8006000b000b0009001180118010803fc020c0204040604060e0f000000000000000000000
+1eb5:1c6036c06380000020401f8000000f8018c010c003c01cc030c030c030c039c01ee000000000000000000000
+1eb6:20401f800000060006000b000b0009001180118010803fc020c0204040604060e0f000000600060000000000
+1eb7:00000000000020401f80000000000f8018c010c003c01cc030c030c030c039c01ee000000600060000000000
+1eb8:0000000000007fc0304030403000300030803f803080300030003000302030207fe000000600060000000000
+1eb9:00000000000000000000000000000f0030c0606060607fe060006000300018600f8000000600060000000000
+1eba:0e00130003007fc0304030403000300030803f803080300030003000302030207fe000000000000000000000
+1ebb:00000e00130003000600000000000f0030c0606060607fe060006000300018600f8000000000000000000000
+1ebc:1c6036c063807fc0304030403000300030803f803080300030003000302030207fe000000000000000000000
+1ebd:000000001c6036c06380000000000f0030c0606060607fe060006000300018600f8000000000000000000000
+1ebe:307079e0cd807fc0304030403000300030803f803080300030003000302030207fe000000000000000000000
+1ebf:00000000307079e0cd80000000000f0030c0606060607fe060006000300018600f8000000000000000000000
+1ec0:31c078f0cc307fc0304030403000300030803f803080300030003000302030207fe000000000000000000000
+1ec1:0000000031c078f0cc30000000000f0030c0606060607fe060006000300018600f8000000000000000000000
+1ec2:30e07930cc3000607fc0304030403000300030803f80308030003000302030207fe000000000000000000000
+1ec3:000030e07930cc300060000000000f0030c0606060607fe060006000300018600f8000000000000000000000
+1ec4:3c6063c00600198000007fc030403040300030803f80308030003000302030207fe000000000000000000000
+1ec5:3c6063c0000006000f00198000000f0030c0606060607fe060006000300018600f8000000000000000000000
+1ec6:06000f0019807fc0304030403000300030803f803080300030003000302030207fe000000600060000000000
+1ec7:000004000e001b00318060c000000f0030c0606060607fe060006000300018600f8000000600060000000000
+1ec8:0e00130006001f800600060006000600060006000600060006000600060006001f8000000000000000000000
+1ec9:00000e00130003000600000000001e00060006000600060006000600060006001f8000000000000000000000
+1eca:0000000000001f800600060006000600060006000600060006000600060006001f8000000600060000000000
+1ecb:00000000000006000600000000001e00060006000600060006000600060006001f8000000600060000000000
+1ecc:0000000000000f0011c020c020606060606060606060606060602040304018800f0000000600060000000000
+1ecd:00000000000000000000000000000f8011c020e06060606060606060704038801f0000000600060000000000
+1ece:0e00130003000f0011c020c020606060606060606060606060602040304018800f0000000000000000000000
+1ecf:0000000000000000006000f000300fa011c020e06060606060606060704038801f0000000000000000000000
+1ed0:307079e0cd800f0011c020c020606060606060606060606060602040304018800f0000000000000000000000
+1ed1:00000000307079e0cd80000000000f8011c020e06060606060606060704038801f0000000000000000000000
+1ed2:31c078f0cc300f0011c020c020606060606060606060606060602040304018800f0000000000000000000000
+1ed3:0000000031c078f0cc30000000000f8011c020e06060606060606060704038801f0000000000000000000000
+1ed4:30e079b0cc3000600f0011c020c02060606060606060606060602040304018800f0000000000000000000000
+1ed5:0000000030e079b0cc30006000000f0011c020e06060606060606060704038801f0000000000000000000000
+1ed6:3c6063c00600198000000f0011c020c0206060606060606060602040304018800f0000000000000000000000
+1ed7:3c6063c0000006000f00198000000f8011c020e06060606060606060704038801f0000000000000000000000
+1ed8:06000f0019800f0011c020c020606060606060606060606060602040304018800f0000000600060000000000
+1ed9:04000e001b00318060c0000000000f8011c020e06060606060606060704038801f0000000600060000000000
+1eda:0e603cf070300fa011c020c020606060606060606060606060602040304018800f0000000000000000000000
+1edb:0000000000000e003c6070f000300fa011c020e06060606060606060704038801f0000000000000000000000
+1edc:e06078f01c300fa011c020c020606060606060606060606060602040304018800f0000000000000000000000
+1edd:0000000070003c000e6000f000300fa011c020e06060606060606060704038801f0000000000000000000000
+1ede:1c6036f006300fa011c020c020606060606060606060606060602040304018800f0000000000000000000000
+1edf:000000001c00360006600cf000300fa011c020e06060606060606060704038801f0000000000000000000000
+1ee0:7260fef09c300fa011c020c020606060606060606060606060602040304018800f0000000000000000000000
+1ee1:0000000039007f004e6000f000300fa011c020e06060606060606060704038801f0000000000000000000000
+1ee2:006000f000300fa011c020c020606060606060606060606060602040304018800f0000000600060000000000
+1ee3:0000000000000000006000f000300fa011c020e06060606060606060704038801f0000000600060000000000
+1ee4:000000000000f070602060206020602060206020602060206020602070403fc01f8000000600060000000000
+1ee5:000000000000000000000000000079e030c030c030c030c030c030c030c039c01e6000000600060000000000
+1ee6:0e0013000300f670602060206020602060206020602060206020602070403fc01f8000000000000000000000
+1ee7:000000000e00130003000600000079e030c030c030c030c030c030c030c039c01e6000000000000000000000
+1ee8:0e603cd07010f070602060206020602060206020602060206020602070403fc01f8000000000000000000000
+1ee9:0000000007001e00386000d0001079e030c030c030c030c030c030c030c039c01e6000000000000000000000
+1eea:70603cd00e10f070602060206020602060206020602060206020602070403fc01f8000000000000000000000
+1eeb:0000000070003c000e6000d0001079e030c030c030c030c030c030c030c039c01e6000000000000000000000
+1eec:1c00266006d00c10f07060206020602060206020602060206020602070403fc01f8000000000000000000000
+1eed:0e00130003000600006000d0001079e030c030c030c030c030c030c030c039c01e6000000000000000000000
+1eee:7100db608e700010f07060206020602060206020602060206020602070403fc01f8000000000000000000000
+1eef:1c6036c063800000006000d0001079e030c030c030c030c030c030c030c039c01e6000000000000000000000
+1ef0:006000d00010f070602060206020602060206020602060206020602070403fc01f8000000600060000000000
+1ef1:0000000000000000006000d0001079e030c030c030c030c030c030c030c039c01e6000000600060000000000
+1ef2:38001e000700f07060203040188018800d0006000600060006000600060006000f0000000000000000000000
+1ef3:000000001c000f00038000000000f0f0602030403040188018800d000d000600060004000c00080078007000
+1ef4:000000000000f07060203040188018800d0006000600060006000600060006000f0000000600060000000000
+1ef5:0000000000000000000000000000f0f0602030403040188018800d000d000600060004000c0008007b007300
+1ef6:0e0013000300f67060203040188018800d0006000600060006000600060006000f0000000000000000000000
+1ef7:00000e0013000300060000000000f0f0602030403040188018800d000d000600060004000c00080078007000
+1ef8:1c6036c06380f07060203040188018800d0006000600060006000600060006000f0000000000000000000000
+1ef9:000000001c6036c0638000000000f0f0602030403040188018800d000d000600060004000c00080078007000
+1efa:000000000000fe006c006c006c006c006c006c006c006c006c006c006c206c20ffe000000000000000000000
+1efb:00000000f3c030c030c07fe07fe030c030c030c030c030c030c030c030c030c0fdf000000000000000000000
+1efc:0000000007000c001800300030006000618063c060e060606060606070403f801f0000000000000000000000
+1efd:000000000000000007000c00180030003000618063c060e06060606070403f801f0000000000000000000000
+1efe:000000000000f0f0602030403040188018800d000d000600060004006c009800980070000000000000000000
+1eff:0000000000000000000000000000f0f0602030403040188018800d000d000600060004006c00980098007000
+1f00:000000000f0003000e00000000001f9031d060e060e060c060c060c061e072603c3000000000000000000000
+1f01:00000000078006000380000000001f9031d060e060e060c060c060c061e072603c3000000000000000000000
+1f02:00000000798018c07040000000001f9031d060e060e060c060c060c061e072603c3000000000000000000000
+1f03:00000000798060c03840000000001f9031d060e060e060c060c060c061e072603c3000000000000000000000
+1f04:0000000078c019807100000000001f9031d060e060e060c060c060c061e072603c3000000000000000000000
+1f05:0000000078c061803900000000001f9031d060e060e060c060c060c061e072603c3000000000000000000000
+1f06:1c40238000000f0003000e0000001f9031d060e060e060c060c060c061e072603c3000000000000000000000
+1f07:1c40238000000f000c00070000001f9031d060e060e060c060c060c061e072603c3000000000000000000000
+1f08:0000f0003000e60006000b000b0009001180118010803fc020c0204040604060e0f000000000000000000000
+1f09:0000f000c000760006000b000b0009001180118010803fc020c0204040604060e0f000000000000000000000
+1f0a:3000180008000300f3003580e580048008c008c008401fe01060102020302030707000000000000000000000
+1f0b:3000180008000300f300c5807580048008c008c008401fe01060102020302030707000000000000000000000
+1f0c:1800300020000300f3003580e580048008c008c008401fe01060102020302030707000000000000000000000
+1f0d:1800300020000300f300c5807580048008c008c008401fe01060102020302030707000000000000000000000
+1f0e:000071008e000300f3003580e580048008c008c008401fe01060102020302030707000000000000000000000
+1f0f:000071008e000300f300c5807580048008c008c008401fe01060102020302030707000000000000000000000
+1f10:000000000f0003000e00000000000f801fc0206060003f003f00600060203fc01f0000000000000000000000
+1f11:000000000f000c000700000000000f801fc0206060003f003f00600060203fc01f0000000000000000000000
+1f12:00000000798018c07040000000000f801fc0206060003f003f00600060203fc01f0000000000000000000000
+1f13:00000000798060c03840000000000f801fc0206060003f003f00600060203fc01f0000000000000000000000
+1f14:0000000078c019807100000000000f801fc0206060003f003f00600060203fc01f0000000000000000000000
+1f15:0000000078c061803900000000000f801fc0206060003f003f00600060203fc01f0000000000000000000000
+1f18:f0003000e0007fc0304030403000300030803f803080300030003000302030207fe000000000000000000000
+1f19:f000c00070007fc0304030403000300030803f803080300030003000302030207fe000000000000000000000
+1f1a:f6003300e1007fc0304030403000300030803f803080300030003000302030207fe000000000000000000000
+1f1b:f600c30071007fc0304030403000300030803f803080300030003000302030207fe000000000000000000000
+1f1c:f1803300e2007fc0304030403000300030803f803080300030003000302030207fe000000000000000000000
+1f1d:f180c30072007fc0304030403000300030803f803080300030003000302030207fe000000000000000000000
+1f20:000000000f0003000e0000000000278079c030c030c030c030c030c030c030c078c000c000c000c000c001e0
+1f21:000000000f000c00070000000000278079c030c030c030c030c030c030c030c078c000c000c000c000c001e0
+1f22:00000000798018c0704000000000278079c030c030c030c030c030c030c030c078c000c000c000c000c001e0
+1f23:00000000798060c0384000000000278079c030c030c030c030c030c030c030c078c000c000c000c000c001e0
+1f24:0000000078c01980710000000000278079c030c030c030c030c030c030c030c078c000c000c000c000c001e0
+1f25:0000000078c06180390000000000278079c030c030c030c030c030c030c030c078c000c000c000c000c001e0
+1f26:1c40238000000f0003000e000000278079c030c030c030c030c030c030c030c078c000c000c000c000c001e0
+1f27:1c40238000000f000c0007000000278079c030c030c030c030c030c030c030c078c000c000c000c000c001e0
+1f28:f0003000e000f0f0606060606060606060607fe0606060606060606060606060f0f000000000000000000000
+1f29:f000c0007000f0f0606060606060606060607fe0606060606060606060606060f0f000000000000000000000
+1f2a:f6003300e100f0f0606060606060606060607fe0606060606060606060606060f0f000000000000000000000
+1f2b:f600c3007100f0f0606060606060606060607fe0606060606060606060606060f0f000000000000000000000
+1f2c:f1803300e200f0f0606060606060606060607fe0606060606060606060606060f0f000000000000000000000
+1f2d:f180c3007200f0f0606060606060606060607fe0606060606060606060606060f0f000000000000000000000
+1f2e:e71068e0c000f0f0606060606060606060607fe0606060606060606060606060f0f000000000000000000000
+1f2f:f710c8e07000f0f0606060606060606060607fe0606060606060606060606060f0f000000000000000000000
+1f30:000000000f0003000e00000000001e00060006000600060006000600060006001f8000000000000000000000
+1f31:000000000f000c000700000000001e00060006000600060006000600060006001f8000000000000000000000
+1f32:00000000798018c07040000000001e00060006000600060006000600060006001f8000000000000000000000
+1f33:00000000798060c03840000000001e00060006000600060006000600060006001f8000000000000000000000
+1f34:0000000078c019807100000000001e00060006000600060006000600060006001f8000000000000000000000
+1f35:0000000078c061803900000000001e00060006000600060006000600060006001f8000000000000000000000
+1f36:1c40238000000f0003000e0000001e00060006000600060006000600060006001f8000000000000000000000
+1f37:1c40238000000f000c00070000001e00060006000600060006000600060006001f8000000000000000000000
+1f38:f0003000e0000f800600060006000600060006000600060006000600060006001f8000000000000000000000
+1f39:f000c00070000f800600060006000600060006000600060006000600060006001f8000000000000000000000
+1f3a:f6003300e1001f800600060006000600060006000600060006000600060006001f8000000000000000000000
+1f3b:f600c30071000f800600060006000600060006000600060006000600060006001f8000000000000000000000
+1f3c:f1003300e2001f800600060006000600060006000600060006000600060006001f8000000000000000000000
+1f3d:f180c30072001f800600060006000600060006000600060006000600060006001f8000000000000000000000
+1f3e:e71068e0c0001f800600060006000600060006000600060006000600060006001f8000000000000000000000
+1f3f:f710c8e070001f800600060006000600060006000600060006000600060006001f8000000000000000000000
+1f40:000000000f0003000e00000000000f8011c020e06060606060606060704038801f0000000000000000000000
+1f41:000000000f000c000700000000000f8011c020e06060606060606060704038801f0000000000000000000000
+1f42:00000000798018c07040000000000f8011c020e06060606060606060704038801f0000000000000000000000
+1f43:00000000798060c03840000000000f8011c020e06060606060606060704038801f0000000000000000000000
+1f44:0000000078c019807100000000000f8011c020e06060606060606060704038801f0000000000000000000000
+1f45:0000000078c061803900000000000f8011c020e06060606060606060704038801f0000000000000000000000
+1f48:f0003000e0000f0011c020c020606060606060606060606060602040304018800f0000000000000000000000
+1f49:f000c00070000f0011c020c020606060606060606060606060602040304018800f0000000000000000000000
+1f4a:f6003300e1000f0011c020c020606060606060606060606060602040304018800f0000000000000000000000
+1f4b:f600c30071000f0011c020c020606060606060606060606060602040304018800f0000000000000000000000
+1f4c:f1003300e2000f0011c020c020606060606060606060606060602040304018800f0000000000000000000000
+1f4d:f180c30072000f0011c020c020606060606060606060606060602040304018800f0000000000000000000000
+1f50:000000000f0003000e000000000079e030c030c030c030c030c030c030c038800f0000000000000000000000
+1f51:000000000f000c0007000000000079e030c030c030c030c030c030c030c038800f0000000000000000000000
+1f52:00000000798018c070400000000079e030c030c030c030c030c030c030c038800f0000000000000000000000
+1f53:00000000798060c038400000000079e030c030c030c030c030c030c030c038800f0000000000000000000000
+1f54:0000000078c0198071000000000079e030c030c030c030c030c030c030c038800f0000000000000000000000
+1f55:0000000078c0618039000000000079e030c030c030c030c030c030c030c038800f0000000000000000000000
+1f56:1c40238000000f0003000e00000079e030c030c030c030c030c030c030c038800f0000000000000000000000
+1f57:1c40238000000f000c000700000079e030c030c030c030c030c030c030c038800f0000000000000000000000
+1f59:f000c0007000f07060203040188018800d0006000600060006000600060006000f0000000000000000000000
+1f5b:f600c3007100f07060203040188018800d0006000600060006000600060006000f0000000000000000000000
+1f5d:f180c3007200f07060203040188018800d0006000600060006000600060006000f0000000000000000000000
+1f5f:f710c8e07000f07060203040188018800d0006000600060006000600060006000f0000000000000000000000
+1f60:000000000f0003000e00000000006060c030c630c630c630c630c63066207fc0198000000000000000000000
+1f61:000000000f000c000700000000006060c030c630c630c630c630c63066207fc0198000000000000000000000
+1f62:00000000798018c07040000000006060c030c630c630c630c630c63066207fc0198000000000000000000000
+1f63:00000000798060c03840000000006060c030c630c630c630c630c63066207fc0198000000000000000000000
+1f64:0000000078c019807100000000006060c030c630c630c630c630c63066207fc0198000000000000000000000
+1f65:0000000078c061803900000000006060c030c630c630c630c630c63066207fc0198000000000000000000000
+1f66:1c40238000000f0003000e0000006060c030c630c630c630c630c63066207fc0198000000000000000000000
+1f67:1c40238000000f000c00070000006060c030c630c630c630c630c63066207fc0198000000000000000000000
+1f68:f0003000e0000f0011c020c0206060606060606060602040304018800900492079e000000000000000000000
+1f69:f000c00070000f0011c020c0206060606060606060602040304018800900492079e000000000000000000000
+1f6a:f6003300e1000f0011c020c0206060606060606060602040304018800900492079e000000000000000000000
+1f6b:f600c30071000f0011c020c0206060606060606060602040304018800900492079e000000000000000000000
+1f6c:f1803300e2000f0011c020c0206060606060606060602040304018800900492079e000000000000000000000
+1f6d:f180c30072000f0011c020c0206060606060606060602040304018800900492079e000000000000000000000
+1f6e:e71068e0c0000f0011c020c0206060606060606060602040304018800900492079e000000000000000000000
+1f6f:f710c8e070000f0011c020c0206060606060606060602040304018800900492079e000000000000000000000
+1f70:000000000c0006000200000000001f9031d060e060e060c060c060c061e072603c3000000000000000000000
+1f71:00000000030006000400000000001f9031d060e060e060c060c060c061e072603c3000000000000000000000
+1f72:0000000000000c000600020000000f801fc0206060003f003f00600060203fc01f0000000000000000000000
+1f73:00000000000003000600040000000f801fc0206060003f003f00600060203fc01f0000000000000000000000
+1f74:000000000c000600020000000000278079c030c030c030c030c030c030c030c078c000c000c000c000c001e0
+1f75:0000000003000600040000000000278079c030c030c030c030c030c030c030c078c000c000c000c000c001e0
+1f76:000000000c0006000200000000001e00060006000600060006000600060006001f8000000000000000000000
+1f77:00000000030006000400000000001e00060006000600060006000600060006001f8000000000000000000000
+1f78:000000000c0006000200000000000f8011c020e06060606060606060704038801f0000000000000000000000
+1f79:00000000030006000400000000000f8011c020e06060606060606060704038801f0000000000000000000000
+1f7a:000000000c00060002000000000079e030c030c030c030c030c030c030c038800f0000000000000000000000
+1f7b:000000000300060004000000000079e030c030c030c030c030c030c030c038800f0000000000000000000000
+1f7c:000000000c0006000200000000006060c030c630c630c630c630c63066207fc0198000000000000000000000
+1f7d:0000000007000c000800000000006060c030c630c630c630c630c63066207fc0198000000000000000000000
+1f80:000000000f0003000e00000000001f9031d060e060e060c060c060c061e072603c3000000600060007000000
+1f81:000000000f000c000700000000001f9031d060e060e060c060c060c061e072603c3000000600060007000000
+1f82:00000000798018c07040000000001f9031d060e060e060c060c060c061e072603c3000000600060007000000
+1f83:00000000798060c03840000000001f9031d060e060e060c060c060c061e072603c3000000600060007000000
+1f84:0000000078c019807100000000001f9031d060e060e060c060c060c061e072603c3000000600060007000000
+1f85:0000000078c061803900000000001f9031d060e060e060c060c060c061e072603c3000000600060007000000
+1f86:1c40238000000f0003000e0000001f9031d060e060e060c060c060c061e072603c3000000600060007000000
+1f87:1c40238000000f000c00070000001f9031d060e060e060c060c060c061e072603c3000000600060007000000
+1f88:00000000f0003600e6000b000b0009001180118010803fc020c0204040604060e0f000000040004000600000
+1f89:00000000f000c60076000b000b0009001180118010803fc020c0204040604060e0f000000040004000600000
+1f8a:3000180008000300f3003580e580048008c008c008401fe01060102020302030707000000040004000600000
+1f8b:3000180008000300f300c5807580048008c008c008401fe01060102020302030707000000040004000600000
+1f8c:0c00180010000300f3003580e580048008c008c008401fe01060102020302030707000000040004000600000
+1f8d:0c00180010000300f300c5807580048008c008c008401fe01060102020302030707000000040004000600000
+1f8e:000071008e000300f3003580e580048008c008c008401fe01060102020302030707000000040004000600000
+1f8f:000071008e000300f300c5807580048008c008c008401fe01060102020302030707000000060006000700000
+1f90:000000000f0003000e0000000000278079c030c030c030c030c030c030c030c078c000c030c030c038c001e0
+1f91:000000000f000c00070000000000278079c030c030c030c030c030c030c030c078c000c030c030c038c001e0
+1f92:0000000000007b00198070800000278079c030c030c030c030c030c030c030c078c000c030c030c038c001e0
+1f93:0000000000007b00618038800000278079c030c030c030c030c030c030c030c078c000c030c030c038c001e0
+1f94:00000000000078c0198071000000278079c030c030c030c030c030c030c030c078c000c030c030c038c001e0
+1f95:00000000000078c0618039000000278079c030c030c030c030c030c030c030c078c000c030c030c038c001e0
+1f96:1c40238000000f0003000e000000278079c030c030c030c030c030c030c030c078c000c030c030c038c001e0
+1f97:1c40238000000f000c0007000000278079c030c030c030c030c030c030c030c078c000c030c030c038c001e0
+1f98:f0003000e000f0f0606060606060606060607fe0606060606060606060606060f0f000000060006000700000
+1f99:f000c0007000f0f0606060606060606060607fe0606060606060606060606060f0f000000060006000700000
+1f9a:f6003300e100f0f0606060606060606060607fe0606060606060606060606060f0f000000060006000700000
+1f9b:f600c3007100f0f0606060606060606060607fe0606060606060606060606060f0f000000060006000700000
+1f9c:f1803300e200f0f0606060606060606060607fe0606060606060606060606060f0f000000060006000700000
+1f9d:f180c3007200f0f0606060606060606060607fe0606060606060606060606060f0f000000060006000700000
+1f9e:e71068e0c000f0f0606060606060606060607fe0606060606060606060606060f0f000000060006000700000
+1f9f:f710c8e07000f0f0606060606060606060607fe0606060606060606060606060f0f000000060006000700000
+1fa0:000000000f0003000e00000000006060c030c630c630c630c630c63066207fc0198000000600060007000000
+1fa1:000000000f000c000700000000006060c030c630c630c630c630c63066207fc0198000000600060007000000
+1fa2:000000003d800cc03840000000006060c030c630c630c630c630c63066207fc0198000000600060007000000
+1fa3:000000003d8030c01c40000000006060c030c630c630c630c630c63066207fc0198000000600060007000000
+1fa4:000000003c600cc03880000000006060c030c630c630c630c630c63066207fc0198000000600060007000000
+1fa5:000000003c6030c01c80000000006060c030c630c630c630c630c63066207fc0198000000600060007000000
+1fa6:1c40238000000f0003000e0000006060c030c630c630c630c630c63066207fc0198000000600060007000000
+1fa7:1c40238000000f000c00070000006060c030c630c630c630c630c63066207fc0198000000600060007000000
+1fa8:0710f8e03000ef0011c020c0206060606060606060602040304018800900492079e000000000000000000000
+1fa9:f000c00070000f0011c020c0206060606060606060602040304018800900492079e000000060006000700000
+1faa:f6003300e1000f0011c020c0206060606060606060602040304018800900492079e000000060006000700000
+1fab:f600c30071000f0011c020c0206060606060606060602040304018800900492079e000000060006000700000
+1fac:f1803300e2000f0011c020c0206060606060606060602040304018800900492079e000000060006000700000
+1fad:f180c30072000f0011c020c0206060606060606060602040304018800900492079e000000060006000700000
+1fae:e71068e0c0000f0011c020c0206060606060606060602040304018800900492079e000000060006000700000
+1faf:f710c8e070000f0011c020c0206060606060606060602040304018800900492079e000000060006000700000
+1fb0:00000000000010800f00000000001f9031d060e060e060c060c060c061e072603c3000000000000000000000
+1fb1:0000000000001f801f80000000001f9031d060e060e060c060c060c061e072603c3000000000000000000000
+1fb2:000000000c0006000200000000001f9031d060e060e060c060c060c061e072603c3000000600060007000000
+1fb3:00000000000000000000000000001f9031d060e060e060c060c060c061e072603c3000000600060007000000
+1fb4:00000000030006000400000000001f9031d060e060e060c060c060c061e072603c3000000600060007000000
+1fb6:0000000000001c402380000000001f9031d060e060e060c060c060c061e072603c3000000000000000000000
+1fb7:0000000000001c402380000000001f9031d060e060e060c060c060c061e072603c3000000600060007000000
+1fb8:10800f000000060006000b000b0009001180118010803fc020c0204040604060e0f000000000000000000000
+1fb9:1f801f800000060006000b000b0009001180118010803fc020c0204040604060e0f000000000000000000000
+1fba:00000000c000660026000b000b0009001180118010803fc020c0204040604060e0f000000000000000000000
+1fbb:000000003000660046000b000b0009001180118010803fc020c0204040604060e0f000000000000000000000
+1fbc:000000000000060006000b000b0009001180118010803fc020c0204040604060e0f000000060006000700000
+1fbd:000000000e000100010006000000000000000000000000000000000000000000000000000000000000000000
+1fbe:0000000000000000000000000000000000000000000000000000000000000000000000000600060007000000
+1fbf:000000000f0003000e0000000000000000000000000000000000000000000000000000000000000000000000
+1fc0:1c803f8027000000000000000000000000000000000000000000000000000000000000000000000000000000
+1fc1:1c803f8027000000198019800000000000000000000000000000000000000000000000000000000000000000
+1fc2:000000000c000600020000000000278079c030c030c030c030c030c030c030c078c000c030c030c038c001e0
+1fc3:0000000000000000000000000000278079c030c030c030c030c030c030c030c078c000c030c030c038c001e0
+1fc4:0000000003000600040000000000278079c030c030c030c030c030c030c030c078c000c030c030c038c001e0
+1fc6:0000000000001c40238000000000278079c030c030c030c030c030c030c030c078c000c000c000c000c001e0
+1fc7:0000000000001c40238000000000278079c030c030c030c030c030c030c030c078c000c030c030c038c001e0
+1fc8:c000600020007fc0304030403000300030803f803080300030003000302030207fe000000000000000000000
+1fc9:6000c00080007fc0304030403000300030803f803080300030003000302030207fe000000000000000000000
+1fca:c00060002000f0f0606060606060606060607fe0606060606060606060606060f0f000000000000000000000
+1fcb:6000c0008000f0f0606060606060606060607fe0606060606060606060606060f0f000000000000000000000
+1fcc:000000000000f0f0606060606060606060607fe0606060606060606060606060f0f000000060006000700000
+1fcd:3d800cc038400000000000000000000000000000000000000000000000000000000000000000000000000000
+1fce:3cc00d8039000000000000000000000000000000000000000000000000000000000000000000000000000000
+1fcf:1c40238000000f0003000e000000000000000000000000000000000000000000000000000000000000000000
+1fd0:00000000000010800f00000000001e00060006000600060006000600060006001f8000000000000000000000
+1fd1:0000000000001f801f80000000001e00060006000600060006000600060006001f8000000000000000000000
+1fd2:0000000018000c0064c060c000001e00060006000600060006000600060006001f8000000000000000000000
+1fd3:000000000300060064c060c000001e00060006000600060006000600060006001f8000000000000000000000
+1fd6:00000000000000001c40238000001e00060006000600060006000600060006001f8000000000000000000000
+1fd7:00001c40238000003180318000001e00060006000600060006000600060006001f8000000000000000000000
+1fd8:10800f0000001f800600060006000600060006000600060006000600060006001f8000000000000000000000
+1fd9:1f801f8000001f800600060006000600060006000600060006000600060006001f8000000000000000000000
+1fda:000000000000df806600260006000600060006000600060006000600060006001f8000000000000000000000
+1fdb:00000000000067e0c1808180018001800180018001800180018001800180018007e000000000000000000000
+1fdd:3d8030c01c400000000000000000000000000000000000000000000000000000000000000000000000000000
+1fde:3cc031801d000000000000000000000000000000000000000000000000000000000000000000000000000000
+1fdf:1c40238000000f000c0007000000000000000000000000000000000000000000000000000000000000000000
+1fe0:00000000000010800f000000000079e030c030c030c030c030c030c030c038800f0000000000000000000000
+1fe1:0000000000001f801f800000000079e030c030c030c030c030c030c030c038800f0000000000000000000000
+1fe2:0000000018000c0064c060c0000079e030c030c030c030c030c030c030c038800f0000000000000000000000
+1fe3:000000000300060064c060c0000079e030c030c030c030c030c030c030c038800f0000000000000000000000
+1fe4:000000000f0003000e00000000000f8011c020e0606060606060606070407880670060006000600060006000
+1fe5:000000000f000c000700000000000f8011c020e0606060606060606070407880670060006000600060006000
+1fe6:0000000000001c4023800000000079e030c030c030c030c030c030c030c038800f0000000000000000000000
+1fe7:00001c402380000031803180000079e030c030c030c030c030c030c030c038800f0000000000000000000000
+1fe8:10800f000000f07060203040188018800d0006000600060006000600060006000f0000000000000000000000
+1fe9:1f801f800000f07060203040188018800d0006000600060006000600060006000f0000000000000000000000
+1fea:c00060002000f07060203040188018800d0006000600060006000600060006000f0000000000000000000000
+1feb:6000c0008000f07060203040188018800d0006000600060006000600060006000f0000000000000000000000
+1fec:f000c00070007f8030c030603060306030c03780300030003000300030003000780000000000000000000000
+1fed:000018000c0064c060c000000000000000000000000000000000000000000000000000000000000000000000
+1fee:00000300060064c060c000000000000000000000000000000000000000000000000000000000000000000000
+1fef:00000c0006000200000000000000000000000000000000000000000000000000000000000000000000000000
+1ff2:000000000c0006000200000000006060c030c630c630c630c630c63066207fc0198000000600060007000000
+1ff3:00000000000000000000000000006060c030c630c630c630c630c63066207fc0198000000600060007000000
+1ff4:00000000030006000400000000006060c030c630c630c630c630c63066207fc0198000000600060007000000
+1ff6:0000000000001c402380000000006060c030c630c630c630c630c63066207fc0198000000600060007000000
+1ff7:0000000000001c402380000000006060c030c630c630c630c630c63066207fc0198000000600060007000000
+1ff8:0000c00060002f0011c020c020606060606060606060606060602040304018800f0000000000000000000000
+1ff9:000000006000cf0091c020c020606060606060606060606060602040304018800f0000000000000000000000
+1ffa:0000c00060002f0011c020c0206060606060606060602040304018800900492079e000000000000000000000
+1ffb:000000006000cf0091c020c0206060606060606060602040304018800900492079e000000000000000000000
+1ffc:0000000000000f0011c020c0206060606060606060602040304018800900492079e000000060006000700000
+1ffd:0000030006000400000000000000000000000000000000000000000000000000000000000000000000000000
+1ffe:0000078006000380000000000000000000000000000000000000000000000000000000000000000000000000
+2000:0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+2001:0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+2002:0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+2003:0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+2004:0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+2005:0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+2006:0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+2007:0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+2008:0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+2009:0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+200a:0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+200b:0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+200c:0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+200d:0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+200e:0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+200f:0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
2010:00000000000000000000000000000000000000003fc03fc00000000000000000000000000000000000000000
2011:00000000000000000000000000000000000000003fc03fc00000000000000000000000000000000000000000
2012:00000000000000000000000000000000000000003fc03fc00000000000000000000000000000000000000000
@@ -377,29 +1758,1184 @@
201b:000006000f000f000c000c000600030001000000000000000000000000000000000000000000000000000000
201c:00000cc019801980198019801980198000000000000000000000000000000000000000000000000000000000
201d:0000198019801980198019801980330000000000000000000000000000000000000000000000000000000000
-201e:0000000000000000000000000000000000000000000000001980198019801980198033000000000000000000
-201f:00001980198019801980198019800cc000000000000000000000000000000000000000000000000000000000
+201e:0000000000000000000000000000000000000000000000003b803b803b801980198033000000000000000000
+201f:00001dc01dc01dc01980198019800cc000000000000000000000000000000000000000000000000000000000
2020:0000000000000600060006003fc03fc006000600060006000600060006000600060000000000000000000000
2021:0000000000000600060006003fc03fc006000600060006003fc03fc006000600060000000000000000000000
2022:0000000000000000000000000000000007000f800f800f800700000000000000000000000000000000000000
+2023:000000000000000000000000000008000c000e000f000e000c00080000000000000000000000000000000000
+2024:000000000000000000000000000000000000000000000000000007000f800f80070000000000000000000000
+2025:000000000000000000000000000000000000000000000000000071c0fbe0fbe071c000000000000000000000
2026:0000000000000000000000000000000000000000000000000000222077707770222000000000000000000000
+2027:000000000000000000000000000000000000000007000f800f80070000000000000000000000000000000000
+2028:00000000000000004200620052004a004600420000000200020002000200020003e000000000000000000000
+2029:0000000000003fe07e607e607e607e607e603e60026002600260026002600260026000000000000000000000
+202a:0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+202b:0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+202c:0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+202d:0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+202e:0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+202f:0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
2030:000000000000318049804b003300060006000c000c001800180036c03920692066c000000000000000000000
-2032:0000060006000600060006000600000000000000000000000000000000000000000000000000000000000000
-2033:0000198019801980198019801980000000000000000000000000000000000000000000000000000000000000
-2039:000000000000000000000000000000000180030006000c0018000c0006000300018000000000000000000000
-203a:0000000000000000000000000000000018000c00060003000180030006000c00180000000000000000000000
+2031:000000000000318049804b003300060006000cc00d20192018c036c03920692066c000000000000000000000
+2032:000003000300060006000c000c00000000000000000000000000000000000000000000000000000000000000
+2033:00000cc00cc01980198033003300000000000000000000000000000000000000000000000000000000000000
+2034:00003330333066606660ccc0ccc0000000000000000000000000000000000000000000000000000000000000
+2035:00000c000c000600060003000300000000000000000000000000000000000000000000000000000000000000
+2036:000033003300198019800cc00cc0000000000000000000000000000000000000000000000000000000000000
+2037:0000ccc0ccc06660666033303330000000000000000000000000000000000000000000000000000000000000
+2038:0000000000000000000000000000000000000000000000000000000000000000000006000f00198030c06060
+2039:000000000000000000000000000000000180030006000c000600030001800000000000000000000000000000
+203a:0000000000000000000000000000000018000c000600030006000c0018000000000000000000000000000000
+203b:0000000000000000000086104620204010800900c630c6300900108020404620861000000000000000000000
203c:0000000019801980198019801980198019801980198019801980000000001980198000000000000000000000
+203d:000000000f001f803dc02cc00cc00cc00d800f000e000c000c00000000000c000c0000000000000000000000
203e:00003fc03fc00000000000000000000000000000000000000000000000000000000000000000000000000000
+203f:0000000000000000000000000000000000000000000000000000000000000000801060603fc01f8000000000
+2040:00001f803fc06060801000000000000000000000000000000000000000000000000000000000000000000000
+2041:000000000180018003000300060006000e000e001b001b003180318060c060c0000000000000000000000000
+2042:0000000000000000090006001f80060009000000492030c0fff030c049200000000000000000000000000000
+2043:00000000000000000000000000000000000000001f801f801f80000000000000000000000000000000000000
+2044:00000060006000c000c00180018003000300060006000c000c00180018003000300000000000000000000000
+2045:000000000fc00fc00e000e000e000e000fc00fc00e000e000e000e000e000fc00fc000000000000000000000
+2046:000000003f003f0007000700070007003f003f00070007000700070007003f003f0000000000000000000000
+2047:0000000039c07fe0ef708630063006300c600840108031803180000000003180318000000000000000000000
+2048:000000003c607e60e76083600360036006600c60186030603060000000003060306000000000000000000000
+2049:0000000063c067e06e70683060306030606060c0618063006300000000006300630000000000000000000000
+204a:000000000000000000000000000000003f803f80008000800080010001000100010000000000000000000000
+204b:000000000000ff8027c027e027e027e027c02780240024002400240024002400240000000000000000000000
+204c:00000000000000000000000000003fe07c80fc80fc80fc807c803fe000000000000000000000000000000000
+204d:0000000000000000000000000000ff8027c027e027e027e027c0ff8000000000000000000000000000000000
+204e:000000000000000000000000000000000000000000001080090006001f800600090010800000000000000000
+204f:000000000000000000000000000000000c001e001e000c00000000000c001e001e00180018000c0006000200
+2050:00000000000000000e003f8071c060c00000000000000000000060c071c03f800e0000000000000000000000
+2051:0000000000000000090006001f80060009000000090006001f80060009000000000000000000000000000000
+2052:00000000386038c038c0018001800300030006000c000c001800180031c031c061c000000000000000000000
+2053:00000000000000000000000000000000000000001c203e6036c067c043800000000000000000000000000000
+2054:00000000000000000000000000000000000000000000000000000000000000001f803fc06060801000000000
+2055:00000000000000000000000004004440248015000e00ffe00e00150024804440040000000000000000000000
+2056:00000000000000000000000000e000e000e038003800380000e000e000e00000000000000000000000000000
+2057:0000249024904920492092409240000000000000000000000000000000000000000000000000000000000000
+2058:000000000000000000000e000e000e000000e0e0e0e0e0e000000e000e000e00000000000000000000000000
+2059:00000000000000000000e0e0e0e0e0e000000e000e000e000000e0e0e0e0e0e0000000000000000000000000
+205a:0000000000000e000e000e00000000000000000000000000000000000e000e000e0000000000000000000000
+205b:00000e000e000e0000000000000000000000e0e0e0e0e0e0000000000000000000000e000e000e0000000000
+205c:00000000000000000000e4e0e4e0e4e004000400ffe004000400e4e0e4e0e4e0000000000000000000000000
+205d:000000000e000e000e000000000000000e000e000e000000000000000e000e000e0000000000000000000000
+205e:000000000e000e000e00000000000e000e000e00000000000e000e000e00000000000e000e000e0000000000
+205f:0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+2060:0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+2061:0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+2062:0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+2063:0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+2064:0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+2066:0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+2067:0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+2068:0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+2069:0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+206a:0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+206b:0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+206c:0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+206d:0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+206e:0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+206f:0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+2070:0000000007000f80118010c030c030c030c0308018801f000e00000000000000000000000000000000000000
+2071:000000000600060000001e001e0006000600060006001f801f80000000000000000000000000000000000000
+2074:0000000000800180038005800980118021803fe07fe001800180000000000000000000000000000000000000
+2075:000000000fc00fc0100020003f8031c000e00060206030c01f80000000000000000000000000000000000000
+2076:0000000007000c001800300067806fc070e0606070403f801f00000000000000000000000000000000000000
+2077:000000001fe03fe0604000c00080018001000300020006000400000000000000000000000000000000000000
+2078:000000000f00118030c018800d0006000b00118030c018800f00000000000000000000000000000000000000
+2079:000000000f8011c020e0606070e03f601e6000c0018007003c00000000000000000000000000000000000000
+207a:000000000000060006001f801f80060006000000000000000000000000000000000000000000000000000000
+207b:000000000000000000001f801f80000000000000000000000000000000000000000000000000000000000000
+207c:0000000000001f801f80000000001f801f800000000000000000000000000000000000000000000000000000
+207d:0000000000c001800380030007000600070003000380018000c0000000000000000000000000000000000000
+207e:00000000300018001c000c000e0006000e000c001c0018003000000000000000000000000000000000000000
+207f:00000000000000000000278079c030c030c030c030c030c079e0000000000000000000000000000000000000
+2080:00000000000000000000000000000000000007000f80118010c030c030c030c0308018801f000e0000000000
+2081:000000000000000000000000000000000000020006000e001e003600060006000600060006003fc000000000
+2082:0000000000000000000000000000000000001f003f8061c040c0018003000c00180030207fe07fe000000000
+2083:0000000000000000000000000000000000000f801fc020e000e007c00fc000e0406060403f801f0000000000
+2084:00000000000000000000000000000000000000800180038005800980118021803fe07fe00180018000000000
+2085:0000000000000000000000000000000000000fc00fc0100020003f8031c000e00060206030c01f8000000000
+2086:00000000000000000000000000000000000007000c001800300067806fc070e0606070403f801f0000000000
+2087:0000000000000000000000000000000000001fe03fe0604000c0008001800100030002000600040000000000
+2088:0000000000000000000000000000000000000f00118030c018800d0006000b00118030c018800f0000000000
+2089:0000000000000000000000000000000000000f8011c020e0606070e03f601e6000c0018007003c0000000000
+208a:0000000000000000000000000000000000000000000000000000060006001f801f8006000600000000000000
+208b:0000000000000000000000000000000000000000000000000000000000001f801f8000000000000000000000
+208c:00000000000000000000000000000000000000000000000000001f801f80000000001f801f80000000000000
+208d:00000000000000000000000000000000000000c001800380030007000600070003000380018000c000000000
+208e:000000000000000000000000000000000000300018001c000c000e0006000e000c001c001800300000000000
+2090:0000000000000000000000000000000000000000000000000f8018c010c003c01cc030c039c01ee000000000
+2091:0000000000000000000000000000000000000000000000000f0030c060607fe06000300018600f8000000000
+2092:0000000000000000000000000000000000000000000000000f8011c020e060606060704038801f0000000000
+2093:000000000000000000000000000000000000000000000000f8f0704038800f000f0011c020e0f1f000000000
+2094:0000000000000000000000000000000000000000000000001f00618000c000607fe0606030c00f0000000000
+2095:00000000000000000000000000000000000010003000700030003000378039c030c030c030c079e000000000
+2096:0000000000000000000000000000000000006000e0006000638066007c0078006e0067006380f1e000000000
+2097:0000000000000000000000000000000000001e000600060006000600060006000600060006001f8000000000
+2098:000000000000000000000000000000000000000000000000ddc06ee066606660666066606660ef7000000000
+2099:000000000000000000000000000000000000000000000000278079c030c030c030c030c030c079e000000000
+209a:00000000000000000000000000000000000000000000ef8071c060e060606060604070807f0060006000f000
+209b:0000000000000000000000000000000000000000000000001fc030c038001e00078001c030c03f8000000000
+209c:000000000000000000000000000000000000040004000c007fc00c000c000c000c000c200e40078000000000
+20a0:0000000000001f8031c020c0600060006fe06620760036401fc00640060006200fe000000000000000000000
+20a1:0000024002400fc014e024a02480690069006900720072007200240034203c404f8048004800000000000000
+20a2:0000000000000fc01060202020006e6066b06730660066006600260036201e400f8000000000000000000000
+20a3:0000000000007fc030403040300030007f80300030007f003000300030003000780000000000000000000000
+20a4:0000000000000f801cc018c01800180018007e007e0018001800180018003e207fe061c00000000000000000
+20a5:0000000000000000008000800100ddc06ee066606e606e607660766066606660ef7040008000800000000000
+20a6:000000000000c0706020702078205820fff046204720fff041a040e040e04060e03000000000000000000000
+20a7:000000000000fe00c300c180c580cd80df00fe70ccc0ccc0cc60cc30cdb0cdb0e76000000000000000000000
+20a8:000000000000fc00c600c300c300c300c200fce0e310f300d9e0cc70c730c3b0e1e000000000000000000000
+20a9:000000000000fef06620662066207620fff0334037403bc03b80198019801980198000000000000000000000
+20aa:0000000000000000000000003f607f60c360db60db60db60db60db60d960dfc0df8000000000000000000000
+20ab:00c001c000c01ff000c01ec063c041c0c0c0c0c0c0c0c0c0e1c072c03ce000007fe000000000000000000000
20ac:0000000000000f801040202020006000ff8060006000ff0060002000300018400f8000000000000000000000
+20ad:000000000000f0e06180630066006c007800fff07c006e006700638061c060e0f07000000000000000000000
+20ae:0000000000007fe0462006000640068007200e40168027000e001600260006001f8000000000000000000000
+20af:0000000000000000020004003e00d98018c018c030c030c0308060e06190f390dde001800180018000000000
+20b0:000000000000000003c00720062006200320034003c0118039805fc08ec00460006001800000000000000000
+20b1:0000000000007f8030c0fff03060fff030c03780300030003000300030003000780000000000000000000000
+20b2:0000020002000fc0126022202200620062006200620063f06260226032601a600f8002000200000000000000
+20b3:000000000000060006000b000b0009001180fff01080fff020c0204040604060e0f000000000000000000000
+20b4:000000000000ff00c18080c080c001c0ffe00f003c00ffe0e000c040c04060c03fc000000000000000000000
+20b5:0000020002000fc0126022202200620062006200620062006200220032201e400f8002000200000000000000
+20b6:0000000000000000110011003300fff03300330033003300330033003310339031e000000000000000000000
+20b7:0000000000000ff018303010301038001e000f0003c06ce0927092309230d2607fc000000000000000000000
+20b8:00000000fff0fff000000000fff0fff006000600060006000600060006000600060000000000000000000000
+20b9:00000000fff0fff00e000380fff0fff001800700fe00700038001c000e000700038000000000000000000000
+20ba:00000000000030003100320034003900320034007830b03030307030b02030c03f0000000000000000000000
+20bb:000000006000900090007f803fe030303030303030303ab07560300018000fc007c000000000000000000000
+20bc:000000000000000000000000060006000f001fc026e066606660c630c630c630c63000000000000000000000
+20bd:0000000000007f8030c030603060306030c0378030003000fff0300030003000780000000000000000000000
+20be:0000000004800fc014e024a024a064b064b06000600060006000200030001e00ffe000000000000000000000
+20bf:000012001200ff00608060c060c060c061807f8060c0606060606060606060c0ff8012001200000000000000
+20c0:0000000007001dc03060306060006000600060006000306030601dc0070000007ff000000000000000000000
+20d0:180030007fe0ffe0000000000000000000000000000000000000000000000000000000000000000000000000
+20d1:03000180ffc0ffe0000000000000000000000000000000000000000000000000000000000000000000000000
+20d2:0000060006000600060006000600060006000600060006000600060006000600060006000600060006000000
+20d3:0000000000000600060006000600060006000600060006000600060006000600060006000600000000000000
+20d4:40005f0060c07820000000000000000000000000000000000000000000000000000000000000000000000000
+20d5:00200fa0306041e0000000000000000000000000000000000000000000000000000000000000000000000000
+20d6:30006000ffe06000300000000000000000000000000000000000000000000000000000000000000000000000
+20d7:018000c0ffe000c0018000000000000000000000000000000000000000000000000000000000000000000000
+20d8:000000000000000000000000000000000f0010801080108010800f0000000000000000000000000000000000
+20d9:000000000000000000000000000000000f00108013e011c010800f0000000000000000000000000000000000
+20da:000000000000000000000000000000000f00108011c013e010800f0000000000000000000000000000000000
+20db:6660666000000000000000000000000000000000000000000000000000000000000000000000000000000000
+20dc:db60db6000000000000000000000000000000000000000000000000000000000000000000000000000000000
+20dd:000000000000000000001f8020404020402080108010801080104020402020401f8000000000000000000000
+20de:0000000000000000fff0801080108010801080108010801080108010801080108010fff00000000000000000
+20df:0000000000000000000006000900108020404020801080104020204010800900060000000000000000000000
+20e0:00000000000000000f001080204060205020881084108210811040a04060204010800f000000000000000000
+20e1:318060c0ffe060c0318000000000000000000000000000000000000000000000000000000000000000000000
+20e2:0000000000003fc0c030801080108010801080108010801080108010801080108010c0303fc0000000000000
+20e3:0000000000007fe0a050c0308010801080108010801080108010801080108010c030a0507fe0000000000000
+20e4:000006000600060009000900090010801080108020402040204040204020402080108010fff0000000000000
+20e5:000000006000600030003000180018000c000c000600030003000180018000c000c000000000000000000000
+20e6:0000198019801980198019801980198019801980198019801980198019801980198000000000000000000000
+20e7:fff0001000100010001000100010001000100010001000100010001000100010001000000000000000000000
+20e8:0000000000000000000000000000000000000000000000000000000000000000000000000000666066600000
+20e9:fff0fff0c030c030000000000000000000000000000000000000000000000000000000000000000000000000
+20ea:000000000000000000000000180030006000fff0fff060003000180000000000000000000000000000000000
+20eb:0000000000000cc00cc00cc00cc00cc019801980198019803300330033003300330000000000000000000000
+20ec:000000000000000000000000000000000000000000000000000000000000000000007ff07fe000c001800300
+20ed:00000000000000000000000000000000000000000000000000000000000000000000ffe07fe0300018000c00
+20ee:0000000000000000000000000000000000000000000000000000000000000000000020006000fff060002000
+20ef:0000000000000000000000000000000000000000000000000000000000000000000000400060fff000600040
+20f0:090006001f800600090000000000000000000000000000000000000000000000000000000000000000000000
+2100:00007c00c60006007e00c620c660cec07780030006e00d901b00330063004300019000e00000000000000000
+2101:00007c00c60006007e00c620c660cec07780030007e00e301e0031e060304030063003e00000000000000000
+2102:0000000000001f8028e0486048004800480048004800480048004800486028e01f8000000000000000000000
+2103:6000900090006fc01060202020006000600060006000600060002000302018400f8000000000000000000000
+2104:0000000000000c000c003f004c804c008c008c008c004c004c803f000c000fe00fe000000000000000000000
+2105:00007c00c600c000c000c020c060c6c07d80030007e00e301e30363066304630063003e00000000000000000
+2106:00007c00c600c000c000c020c060c6c07d80030006300e301e30363066304630063003e00000000000000000
+2107:00000000000000000000000000000f801fc0206060003f003f00600060203fc01f0000000000000000000000
+2108:0000000000003f00608040400040086008600fe0086008600060404040c021801f0000000000000000000000
+2109:6000900090006ff00c100c100c000c000c200fe00c200c000c000c000c000c001e0000000000000000000000
+210a:0000000000000000000000000f9018f03060306060c060c060c023801f8003e01f006300630066003e001c00
+210b:00000000000078708c908c906ce00d601ac01cc018c038c0598091809190919060e000000000000000000000
+210c:0000000000001c6033c061806000c000c700d980e0c07060706038301c300c306830b060006000c079009e00
+210d:00000000000079e0492049204920492049204f2049204920492049204920492079e000000000000000000000
+210e:000000000c000c000c00180018001b8037c038c030c0618061806180c300c300c38000000000000000000000
+210f:000000000c000c000f80f80018001b8037c038c030c0618061806180c300c300c38000000000000000000000
+2110:00000000000007e03cc070c000c000c000c000c000c000c000c000c000c000c000c0008019801f000c000000
+2111:000000000fe03fc0600061c003a003800380038001c001c060c0e0c070c070c0388039001e00000000000000
+2112:00000000000019c023204620464027801c000c001800180030007020b020ac40638000000000000000000000
+2113:00000000000001c00320062006400c400c800c8019001a0034003800300078c08f0000000000000000000000
+2114:00000000cc00cc00ffe0cc00cc00cc00cde0ce70cc30cc30cc30cc30cc30ce70cde000000000000000000000
+2115:0000000000007820482064206420522052204920492044a044a042604260412041e000000000000000000000
+2116:00000000000087008200c200c260a290a290929092908a908a60860086f08200c30000000000000000000000
+2117:0000000000000f00108020402f4059a059a059a05f20582058203840204010800f0000000000000000000000
+2118:0000000000003fc043204630263006600cc08f007c00180018001800b000b000600000000000000000000000
+2119:0000000000007f8048c0486048204820486048c04f8048004800480048004800780000000000000000000000
+211a:0000000000001f8028c0486048204820482048204820482048204820486028c01f800600038001c000000000
+211b:0000000000003fc043204630263006600cc00f000d80198019801990b0d0b0d0606000000000000000000000
+211c:00000000000078e0cd3066303630466006c0078006c006c086c0c460e8607070602000000000000000000000
+211d:0000000000007f8048c0486048204820486048c04f804980498048c048c04860786000000000000000000000
+211e:000000000000ff00618060c060c060c060807f007c006e306740638061c062e0f47000000000000000000000
+211f:78000f000100ff0062c062c062c064c064807f007c006e0067006b8069c070e0f07020002000000000000000
+2120:00003d1041b03950051045103910000000000000000000000000000000000000000000000000000000000000
+2121:00000000000000000000000000000000f80020002f40284028402f40284028402f7000000000000000000000
+2122:00007d1011b01150111011101110000000000000000000000000000000000000000000000000000000000000
+2123:f0001e000200e2e064403480348038801900190019001e001e002e0024002400440040004000000000000000
+2124:0000000000007fe07fe002400240048004800900090012001200240024007fe07fe000000000000000000000
+2125:000000000000000000007fc04180030006000c001f80030006000c001f8001c000c040c060803f001e000000
+2126:0000000000000f0011c020c0206060606060606060602040304018800900492079e000000000000000000000
+2127:00000000000079e049200900118020c0204060606060606060606040304038800f0000000000000000000000
+2128:000000000f8011c020e040600060006000e011c00fc010e00060006000606060b06030401f800f0000000000
+2129:00000000000000000000000000001f8006000600060006000600060006000600078000000000000000000000
+212a:000000000000f0e06180630066006c00780078007c006e006700638061c060e0f07000000000000000000000
+212b:06000f0019800f0006000b000b0009001180118010803fc020c0204040604060e0f000000000000000000000
+212c:0000000000003fc043204630263006600cc00f000d80186018601830b830b66063c000000000000000000000
+212d:0000000000000f1039e073006300e600e600e600e380e1c0e0c0e10070007c203fc00f000000000000000000
+212e:00000000000000000e00318060c060c0e0e0ffe0e000e000e0006040604031800e0000000000000000000000
+212f:000000000000000000000000000003800c40188031006600f8006040608031001e0000000000000000000000
+2130:00000000000019e02310461046603f80060007c01e00380071e06610601020601f8000000000000000000000
+2131:0000000000103fe04fc04100222006400fc03e404c80980018001800b000b000600000000000000000000000
+2132:00000000000003c00180018001800180018021803f80218001800180418041807fc000000000000000000000
+2133:0000000000000c3014502ca02ca02ca05960596059605960b2c0b2c0b2d0b2d098e000000000000000000000
+2134:000000000000000000000000000003800c4018a030a06070e0206040608031001e0000000000000000000000
+2135:000000000000c180c1c0e0e0706038203c404e80c700e380e1c070e038703830e03000000000000000000000
+2136:000000000000c000ff807fc000c0004000400040004000400040004000407fe0ffc000000000000000000000
+2137:000000000000600078003e00070001000100010001000100018002c004e03c60782000000000000000000000
+2138:000000000000c000ff807fc00080018001800180018001800180018001800300030000000000000000000000
+2139:000000000000000006000f000f00060000003f000f000f000f000f000f000f003fc000000000000000000000
+213a:000000000000000000000f903fd07060c0d08190801080108010803040603fc00f8000000000000000000000
+213b:00000000000000000000000000000000f80080008000e91088a094409c40a2a0a31000000000000000000000
+213c:0000000000000000000000000000ffe0248024802480248024802480249024903c6000000000000000000000
+213d:00000000000000000000000000000000f020902048402480250013001200090009001480248024801f000000
+213e:0000000000007fe0482048204800480048004800480048004800480048004800780000000000000000000000
+213f:000000000000fff0909090909090909090909090909090909090909090909090f0f000000000000000000000
+2140:0000000000007fe04800240012000900048002400240048009001200240048007fe000000000000000000000
+2141:0000000000001f00318060c060c060607c60006000600060006060c060c031801f0000000000000000000000
+2142:0000000000007fc07fc000c000c000c000c000c000c000c000c000c000c000c000c000000000000000000000
+2143:00000000000000c000c000c000c000c000c000c000c000c000c000c000c07fc07fc000000000000000000000
+2144:0000000000000600060006000600060006000f000f001980198030c030c06060606000000000000000000000
+2145:0000000000003e00258024402420242048204820482048209040904090809700f80000000000000000000000
+2146:0000000001e001200120012001200e40324042404240424084808480848084807f8000000000000000000000
+2147:00000000000000000000000000000f801260241048204fe048009000900051803e0000000000000000000000
+2148:0000000000000000078004800780000000000f000900090009001200120012001e0000000000000000000000
+2149:000000000000000003c0024003c0000000000780048004800480090009000900090012002400780000000000
+214a:0000000000000c000c007f804c404c204c204c200c400f800c000c000c000fe00fe000000000000000000000
+214b:0000000067807fc01860386078606c600ee007c007801f003180318031801f000e0000000000000000000000
+214c:000000000180e240242024202410241024107f20a4a0a440a4a07f2024202400240024002400240024001800
+214d:000038006c006c006c00c620fe60c6c0c780030007e00e301e0031e060304030063003e00000000000000000
+214e:000000000000000000000000000003c001800180018011801f801180018021803fc000000000000000000000
+214f:000000000000000000000000000000004440aaa0aaa0aaa0aaa0aaa044406660999000000000000000000000
+2150:000018003800380018001820186018c019803f0006000c001bf030306060406000c000c00180018003000000
+2151:000018003800380018001820186018c019803f0006000c0019e033306330433001f00030006000c003000000
+2152:18003800380018001820186018c019803f0006000c001800300079e03b303b301b301b301b301b301b303de0
+2153:000018003800380018001820186018c019803f0007e00f301830303061e040300030033001e0000000000000
+2154:000038007c006c004c001820306060c07d807f0007e00f301830303061e040300030033001e0000000000000
+2155:000018003800380018001820186018c019803f0007f00ff01b00330063e040300030033001e0000000000000
+2156:000038007c006c004c001820306060c07d807f0007f00ff01b00330063e040300030033001e0000000000000
+2157:00003c006600060006003c20066006c067803f0007f00ff01b00330063e040300030033001e0000000000000
+2158:000004000c001c001c002c204c607ec00d800f0007f00ff01b00330063e040300030033001e0000000000000
+2159:000018003800380018001820186018c019803f0006600d801b00360067c046600660066003c0000000000000
+215a:0000fc00fc00c000c000f8200c600cc0cd807b0006600d801b00360067c046600660066003c0000000000000
+215b:000018003800380018001820186018c019803f0007c00e601e60366063c046600660066003c0000000000000
+215c:00003c006600060006003c20066006c067803d0007c00e601e60366063c046600660066003c0000000000000
+215d:00007e007e00600060007c20066006c067803f0007c00e601e60366063c046600660066003c0000000000000
+215e:00007e0006000c200c6018c01980330036006c001bc036606660466003c006600660066003c0000000000000
+215f:000018003800380018001820186018c019803f0006000c001800300060004000000000000000000000000000
+2160:0000000000001f000400040004000400040004000400040004000400040004001f0000000000000000000000
+2161:0000000000003fc00900090009000900090009000900090009000900090009003fc000000000000000000000
+2162:000000000000ffe0248024802480248024802480248024802480248024802480ffe000000000000000000000
+2163:000000000000fef0282028202820244024402440228022802280210021002100ffc000000000000000000000
+2164:000000000000f9f02040204020401080108010800900090009000600060006001f8000000000000000000000
+2165:000000000000e3f04140414041402240224022401440144014400840084008403ff000000000000000000000
+2166:000000000000e7f042a042a042a042a024a024a024a024a018a018a018a018a03df000000000000000000000
+2167:000000000000dff08aa08aa08aa08aa052a052a052a052a022a022a022a022a077f000000000000000000000
+2168:000000000000fef0244024402280228022802100210022802280228024402440fef000000000000000000000
+2169:0000000000007bc0110011000a000a000a00040004000a000a000a00110011007bc000000000000000000000
+216a:000000000000f7f0224022401440144014400840084014401440144022402240f7f000000000000000000000
+216b:000000000000eff0452045202920292029201120112029202920292045204520eff000000000000000000000
+216c:00000000000078003000300030003000300030003000300030003000302030207fe000000000000000000000
+216d:0000000000000fc01060202020006000600060006000600060002000302018400f8000000000000000000000
+216e:000000000000ff0061c060c06060606060606060606060606060606060406180fe0000000000000000000000
+216f:000000000000e07060e070e070e070e05960596059604d604e604e6044604460e4f000000000000000000000
+2170:00000000000004000400000000000c00040004000400040004000400040004000e0000000000000000000000
+2171:000000000000108010800000000031801080108010801080108010801080108039c000000000000000000000
+2172:0000000000004440444000000000ccc044404440444044404440444044404440eee000000000000000000000
+2173:0000000000004000400000000000dc7048204820444044404440428042804280e7c000000000000000000000
+2174:000000000000000000000000000070e0204020401080108009000900060006000f0000000000000000000000
+2175:0000000000000020002000000000e3e0412041202220222022201420142014203e7000000000000000000000
+2176:00000000000000a000a000000000c7e082a082a044a044a044a028a028a028a07df000000000000000000000
+2177:00000000000002a002a000000000dfe08aa08aa08aa052a052a052a022a022a077f000000000000000000000
+2178:00000000000020002000000000006ee0244022802280210021002280228024407ee000000000000000000000
+2179:000000000000000000000000000071c0208011000a00040004000a001100208071c000000000000000000000
+217a:000000000000004000400000000077c02240144014400840084014401440224077e000000000000000000000
+217b:00000000000000a000a000000000efe044a028a028a010a010a028a028a044a0eff000000000000000000000
+217c:000000001e0006000600060006000600060006000600060006000600060006001f8000000000000000000000
+217d:00000000000000000000000000001f8031c020c06000600060006000704030c01f8000000000000000000000
+217e:00000000006000e00060006000600f6031e020e0606060606060606070e039601e7000000000000000000000
+217f:0000000000000000000000000000ddc06ee06660666066606660666066606660ef7000000000000000000000
+2180:0000000000000f8036e04660c630c630c630c630c630c630c630c630662076c01f0000000000000000000000
+2181:000000000000ff0061c060c07860666063606360636063606660786060406180fe0000000000000000000000
+2182:0000000000000f8036e04660c630cf30d6b0d6b0d6b0d6b0cf30c630662076c01f0000000000000000000000
+2183:0000000000003f00608040400040006000600060006000600060004040c021801f0000000000000000000000
+2184:00000000000000000000000000001f8038c03040006000600060006020e030c01f8000000000000000000000
+2185:0000000000000fc01060202020006000600060006000600060002000302018600fe000600060006000600000
+2186:000000000000060006000600060006000600060006004620666036c01f800f00060000000000000000000000
+2187:000000000000ff0061c078c06460626072606a606a6072606260646078406180fe0000000000000000000000
+2188:0000000000000f8036e046609fb0a650af50a950a950af50a6509f90662076c01f0000000000000000000000
+2189:00003c006600660066006620666066c067803f0007e00f301830303061e040300030033001e0000000000000
+218a:000000007fe07fe040c00180030006000c001800300030003000302038601fc00f8000000000000000000000
+218b:000000000f801fc0206060206000600070003f003e0070006000602070403f801f0000000000000000000000
+2190:0000000000000000000000000c00180030007fe07fe0300018000c0000000000000000000000000000000000
+2191:0000000006000f001f8036c06660060006000600060006000600060006000600060000000000000000000000
+2192:0000000000000000000000000300018000c07fe07fe000c00180030000000000000000000000000000000000
+2193:000000000600060006000600060006000600060006000600666036c01f800f00060000000000000000000000
+2194:000000000000000000000000198030c06060fff0fff0606030c0198000000000000000000000000000000000
+2195:0000000006000f001f8036c0666006000600060006000600666036c01f800f00060000000000000000000000
+2196:0000000000000000000000007f007f0078006c0066006300618000c000600000000000000000000000000000
+2197:0000000000000000000000000fe00fe001e0036006600c601860300060000000000000000000000000000000
+2198:0000000000000000000000006000300018600c600660036001e00fe00fe00000000000000000000000000000
+2199:000000000000000000000000006000c06180630066006c0078007f007f000000000000000000000000000000
+219a:0000000000000000000000001800306060c0fff0fff061803300180000000000000000000000000000000000
+219b:00000000000000000000000001800cc01860fff0fff0306060c0018000000000000000000000000000000000
+219c:000000000000000000000000300060004880d550f550c5504220600030000000000000000000000000000000
+219d:00000000000000000000000000c000601120aab0aaf0aa304420006000c00000000000000000000000000000
+219e:000000000000000000000000198033006600fff0fff066003300198000000000000000000000000000000000
+219f:0000000006000f001f8036c0666006000f001f8036c066600600060006000600060000000000000000000000
+21a0:00000000000000000000000019800cc00660fff0fff006600cc0198000000000000000000000000000000000
+21a1:0000000006000600060006000600666036c01f800f000600666036c01f800f00060000000000000000000000
+21a2:000000000000000000000000180030306060ffc0ffc060603030180000000000000000000000000000000000
+21a3:0000000000000000000000000180c0c060603ff03ff06060c0c0018000000000000000000000000000000000
+21a4:000000000000000000000000180030306030fff0fff060303030180000000000000000000000000000000000
+21a5:0000000006000f001f8036c06660060006000600060006000600060006007fe07fe000000000000000000000
+21a6:0000000000000000000000000180c0c0c060fff0fff0c060c0c0018000000000000000000000000000000000
+21a7:000000007fe07fe006000600060006000600060006000600666036c01f800f00060000000000000000000000
+21a8:000006000f001f8036c066600600060006000600666036c01f800f000600fff0fff000000000000000000000
+21a9:00000000000003c003e00070183030306070ffe0ff8060003000180000000000000000000000000000000000
+21aa:0000000000003c007c00e000c180c0c0e0607ff01ff0006000c0018000000000000000000000000000000000
+21ab:000000000000000000e00110191031106130ffe0ff8061003100190000000000000000000000000000000000
+21ac:000000000000000070008800898088c0c8607ff01ff0086008c0098000000000000000000000000000000000
+21ad:000000000000000000000000198030c06c60f670e6f0636030c0198000000000000000000000000000000000
+21ae:000000000000000000000000108022404620fff0fff046202440108000000000000000000000000000000000
+21af:000000000000030006000c00180030007fe07fe000c00180230036003c003e003f0000000000000000000000
+21b0:0000000006000c0018003fc03fc018c00cc006c000c000c000c000c000c000c000c000000000000000000000
+21b1:000000000600030001803fc03fc0318033003600300030003000300030003000300000000000000000000000
+21b2:0000000000c000c000c000c000c000c000c006c00cc018c03fc03fc018000c00060000000000000000000000
+21b3:0000000030003000300030003000300030003600330031803fc03fc001800300060000000000000000000000
+21b4:00000000ff00ff000300030003000300030003000300030033301b600fc00780030000000000000000000000
+21b5:000000000000003000300030003000300030183030306030fff0fff060003000180000000000000000000000
+21b6:00000000000000000000038006c00c600c60183099307e303c00180000000000000000000000000000000000
+21b7:000000000000000000001c00360063006300c180c990c7e003c0018000000000000000000000000000000000
+21b8:0000000000007fe07fe000007f007f0078006c0066006300618000c000600000000000000000000000000000
+21b9:00008c009800b000ffe0ffe0b00098008c000310019000d07ff07ff000d00190031000000000000000000000
+21ba:0000000000001f801e00198018c0186000600060606060606060204030c019800f0000000000000000000000
+21bb:0000000000001f80078019803180618060006000606060606060204030c019800f0000000000000000000000
+21bc:000000000000000000000000000000000c00180030007fe0ffe0000000000000000000000000000000000000
+21bd:0000000000000000000000000000000000000000ffe07fe0300018000c000000000000000000000000000000
+21be:0000000008000c000e000f000d800cc00c000c000c000c000c000c000c000c000c0000000000000000000000
+21bf:000000000100030007000f001b00330003000300030003000300030003000300030000000000000000000000
+21c0:00000000000000000000000000000000060003000180ffc0ffe0000000000000000000000000000000000000
+21c1:0000000000000000000000000000000000000000ffe0ffc00180030006000000000000000000000000000000
+21c2:000000000c000c000c000c000c000c000c000c000c000cc00d800f000e000c00080000000000000000000000
+21c3:0000000003000300030003000300030003000300030033001b000f0007000300010000000000000000000000
+21c4:00000000018000c00060fff0fff0006000c0198030006000fff0fff060003000180000000000000000000000
+21c5:0000000030c078c0fcc0b4c030c030c030c030c030c030c030c032d033f031e030c000000000000000000000
+21c6:00000000180030006000fff0fff060003000198000c00060fff0fff0006000c0018000000000000000000000
+21c7:00000000180030006000fff0fff060003000180030006000fff0fff060003000180000000000000000000000
+21c8:0000000030c079e0fff0b6d030c030c030c030c030c030c030c030c030c030c030c000000000000000000000
+21c9:00000000018000c00060fff0fff0006000c0018000c00060fff0fff0006000c0018000000000000000000000
+21ca:0000000030c030c030c030c030c030c030c030c030c030c030c0b6d0fff079e030c000000000000000000000
+21cb:00000000000000000c00180030007fe0ffe000000000ffe0ffc0018003000600000000000000000000000000
+21cc:00000000000000000300018000c07fe07ff0000000007ff03ff018000c000600000000000000000000000000
+21cd:00000000000000000040304030406ff06ff0c080c1006ff06ff0320032000200000000000000000000000000
+21ce:00000000000000000100214021405fa05fa0821084105fa05fa0284028400800000000000000000000000000
+21cf:0000000000000000040004c004c0ff60ff6008301030ff60ff6020c020c02000000000000000000000000000
+21d0:00000000000000000000300030006ff06ff0c000c0006ff06ff0300030000000000000000000000000000000
+21d1:0000000006000f001f8039c079e0f9f019801980198019801980198019801980198000000000000000000000
+21d2:0000000000000000000000c000c0ff60ff6000300030ff60ff6000c000c00000000000000000000000000000
+21d3:00000000198019801980198019801980198019801980f9f079e039c01f800f00060000000000000000000000
+21d4:0000000000000000000030c030c06f606f60c030c0306f606f6030c030c00000000000000000000000000000
+21d5:000006000f001f8039c079e0f9f01980198019801980f9f079e039c01f800f00060000000000000000000000
+21d6:0000000000000000000000007f004c006600730059804cc006600330018000c0000000000000000000000000
+21d7:00000000000000000000000007f00190033006700cd01990330066000c001800000000000000000000000000
+21d8:00000000000000000000000018000c006600330019900cd006700330019007f0000000000000000000000000
+21d9:0000000000000000000000000180030006600cc09980b300e600cc009800fe00000000000000000000000000
+21da:000000000000180018003ff03ff070006000fff0fff0600070003ff03ff01800180000000000000000000000
+21db:00000000000001800180ffc0ffc000e00060fff0fff0006000e0ffc0ffc00180018000000000000000000000
+21dc:0000000000000000000000002000200061006380f6706c206000200020000000000000000000000000000000
+21dd:0000000000000000000000000040004008601c60e6f043600060004000400000000000000000000000000000
+21de:0000000006000f001f8036c06660060006007fe07fe0060006007fe07fe00600060000000000000000000000
+21df:00000000060006007fe07fe0060006007fe07fe006000600666036c01f800f00060000000000000000000000
+21e0:000000000000000000000000180030006000db60db6060003000180000000000000000000000000000000000
+21e1:000006000f001f8036c066600000000006000600060000000000060006000600000000000600060006000000
+21e2:0000000000000000000000000300018000c0db60db6000c00180030000000000000000000000000000000000
+21e3:0000060006000600000000000600060006000000000006000600060000000000666036c01f800f0006000000
+21e4:000000000000000000000000c600cc00d800fff0fff0d800cc00c60000000000000000000000000000000000
+21e5:0000000000000000000000000630033001b0fff0fff001b00330063000000000000000000000000000000000
+21e6:0000000000000000000006000a00120023f0401080108010401023f012000a00060000000000000000000000
+21e7:0000000006000900108020404020f0f0108010801080108010801080108010801f8000000000000000000000
+21e8:00000000000000000000060005000480fc408020801080108020fc4004800500060000000000000000000000
+21e9:000000001f8010801080108010801080108010801080f0f04020204010800900060000000000000000000000
+21ea:0000000006000900108020404020f0f01080108010801f8000001f80108010801f8000000000000000000000
+21eb:0000000006000900108020404020f0f0108010801080108010801080f0f08010fff000000000000000000000
+21ec:000000000600090010803fc04020f0f0108010801080108010801080f0f08010fff000000000000000000000
+21ed:0000000006000f00168026404620f6f0168016801680168016801680f6f08610fff000000000000000000000
+21ee:0000000006000900108026404920909020404020f0f0108010801080108010801f8000000000000000000000
+21ef:0000000006000900108026404920909020404020f0f0108010801080f0f08010fff000000000000000000000
+21f0:00000000000000000000e600a500a480bc408020801080108020bc40a480a500e60000000000000000000000
+21f1:000000000000000000000000fff08000be00b800ac00a600a300818080c08060803000000000000000000000
+21f2:000000000000000000000000c0106010301018100c500650035001d007d00010fff000000000000000000000
+21f3:0000000006000900108020404020f0f0108010801080f0f04020204010800900060000000000000000000000
+21f4:00000000000000000000000001801cc02260fff0fff022601cc0018000000000000000000000000000000000
+21f5:0000000030c031e033f032d030c030c030c030c030c030c030c0b4c0fcc078c030c000000000000000000000
+21f6:018000c00060fff0fff0006000c0018000c00060fff0fff0006000c0018000c00060fff0fff0006000c00180
+21f7:0000000000000000000000000000198031806180fff0fff06180318019800000000000000000000000000000
+21f8:0000000000000000000000000000198018c01860fff0fff0186018c019800000000000000000000000000000
+21f9:0000000000000000000000000000168026404620fff0fff04620264016800000000000000000000000000000
+21fa:00000000000000000000000000001a4032406240fff0fff0624032401a400000000000000000000000000000
+21fb:0000000000000000000000000000258024c02460fff0fff0246024c025800000000000000000000000000000
+21fc:0000000000000000000000002040204069606960fff0fff06960696020402040000000000000000000000000
+21fd:00000000000000000000000000001800280048008ff08ff04800280018000000000000000000000000000000
+21fe:0000000000000000000000000100018001400120ff10ff100120014001800100000000000000000000000000
+21ff:00000000000000000000000009001980294049208f108f104920294019800900000000000000000000000000
+2200:000000006060606060603fc03fc030c01980198019800f000f000f0006000600060000000000000000000000
+2201:000000001f803fc070e060606000600060006000600060006000606070e03fc01f8000000000000000000000
+2202:0000000000003c000f00038001c000c000c03fe070e060606060606070e03fc01f8000000000000000000000
+2203:0000000000007fe07fe000600060006000607fe07fe000600060006000607fe07fe000000000000000000000
+2204:0000010001007fe07fe002600260046004607fe07fe008600860106010607fe07fe020002000000000000000
+2205:00000000000000000000000000100fa011c020e06160626064606860704038805f0080000000000000000000
+2206:000000000000060006000f000f0019801980198030c030c030c0606060607fe07fe000000000000000000000
+2207:0000000000007fe07fe06060606030c030c030c01980198019800f000f000600060000000000000000000000
+2208:0000000000000000000007e01fe03800300060007fe07fe06000300038001fe007e000000000000000000000
+2209:0000000000000040004007e01fe03880308061007fe07fe0610032003a001fe007e004000400000000000000
+220a:0000000000000000000000000000000007c0180020007fc02000180007c00000000000000000000000000000
+220b:000000000000000000007e007f8001c000c000607fe07fe0006000c001c07f807e0000000000000000000000
+220c:00000000020002007e007f8005c004c008607fe07fe0086010c011c07f807e00200020000000000000000000
+220d:000000000000000000000000000000003e00018000403fe0004001803e000000000000000000000000000000
+220e:00000000000000000000000000007fe07fe07fe07fe07fe07fe07fe07fe07fe07fe000000000000000000000
+220f:00000000fff0fff0606060606060606060606060606060606060606060606060f0f0f0f00000000000000000
+2210:00000000e070e070606060606060606060606060606060606060606060606060fff0fff00000000000000000
+2211:000000007fe07fe03020180018000c000c00070007000c000c001800180030207fe07fe00000000000000000
2212:00000000000000000000000000000000000000003fc03fc00000000000000000000000000000000000000000
+2213:0000000000003fc03fc00000000006000600060006003fc03fc0060006000600060000000000000000000000
+2214:000000000000060006000000000006000600060006003fc03fc0060006000600060000000000000000000000
+2215:000000000000018001800300030003000600060006000c000c000c0018001800180030003000000000000000
+2216:00000000000000000000180018000c000c000600060003000300018001800000000000000000000000000000
+2217:00000000000006000600c630e67076e036c01f801f8036c076e0e670c6300600060000000000000000000000
+2218:0000000000000000000000000000000006000f00198019800f00060000000000000000000000000000000000
+2219:0000000000000000000000000000000006000f001f801f800f00060000000000000000000000000000000000
+221a:0000002000200060006000c000c001800180e3006300360036001c001c000800080000000000000000000000
+221b:0000f01008100830703008600860f0c000c0f18031801b001b000e000e000400040000000000000000000000
+221c:00001010301050309030fc60106010c000c0f18031801b001b000e000e000400040000000000000000000000
+221d:0000000000000000000000000000303048408480830083008480484030300000000000000000000000000000
+221e:000000000000000000000000000030c049208610861086108610492030c00000000000000000000000000000
+221f:00000000000000000000c000c000c000c000c000c000c000c000c000c000fff0fff000000000000000000000
+2220:0000000000000000000003000300060006000c000c00180018003000300060006000fff0fff0000000000000
+2221:00000000000003000300660036001c000e001b001980318030c060c060c0fff0fff000c000c0000000000000
+2222:000000000000000000000600030001e0078038c0c0c0c0c038c0078001e00300060000000000000000000000
+2223:0000000000000600060006000600060006000600060006000600060006000600060000000000000000000000
+2224:0000000000000600060006000600066007801e00660006000600060006000600060000000000000000000000
+2225:0000000000001980198019801980198019801980198019801980198019801980198000000000000000000000
+2226:0000000000001980198019801980198019f01f80f98019801980198019801980198000000000000000000000
+2227:0000000000000000000000000000060006000f000f001980198030c030c06060606000000000000000000000
+2228:00000000000000000000000000006060606030c030c0198019800f000f000600060000000000000000000000
+2229:000000000000000000001f803fc070e060606060606060606060606060606060606000000000000000000000
+222a:0000000000000000000060606060606060606060606060606060606070e03fc01f8000000000000000000000
+222b:000001e003e00700060006000600060006000600060006000600060006000600060006000e007c0078000000
+222c:000007700ef01980198019801980198019801980198019801980198019801980198019803980f700ee000000
+222d:000019903330777066606660666066606660666066606660666066606660666066606660eee0ccc099800000
+222e:000001e003e00700060006001f80264026404620462046204620264026401f80060006000e007c0078000000
+222f:000007700ef01980198019803fc059a059a0999099909990999059a059a03fc0198019803980f700ee000000
+2230:00001dd03bb03770264026403fc06660a650a650a650a650a650a65066603fc026402640eec0ddc0bb800000
+2231:000003c007c00e000c000c003f004c804c404c408df08ce08c400c000c000c000c000c001c00f800f0000000
+2232:000003c007c00e000c000c003f004c804c808c408df08ce08c404c804c803f000c000c001c00f800f0000000
+2233:000003c007c00e000c000c003f004c804c808c408ce08df08c404c804c803f000c000c001c00f800f0000000
+2234:000000000000000006000f000f000600000000000000000030c079e079e030c0000000000000000000000000
+2235:000000000000000030c079e079e030c0000000000000000006000f000f000600000000000000000000000000
+2236:000000000000000006000f000f000600000000000000000006000f000f000600000000000000000000000000
+2237:000000000000000030c079e079e030c0000000000000000030c079e079e030c0000000000000000000000000
+2238:000000000000000000000000000006000600000000003fc03fc0000000000000000000000000000000000000
+2239:000000000000000000c001e001e000c000007f007f00000000c001e001e000c0000000000000000000000000
+223a:000000000000000030c079e079e030c000007fe07fe0000030c079e079e030c0000000000000000000000000
+223b:000000000000000006000f000f00060000203e606780400006000f000f000600000000000000000000000000
+223c:000000000000000000000000000000001c203e6067c043800000000000000000000000000000000000000000
+223d:00000000000000000000000000000000438067c03e601c200000000000000000000000000000000000000000
+223e:00000000000000000000078007c000601c203e6067c0438060003e001e000000000000000000000000000000
+223f:00000000000000000000000018603c607c607e6067e063c063c0618000000000000000000000000000000000
+2240:000018001c000e0007000300030007000e001c001800180018001c000e000700030000000000000000000000
+2241:000000000000000000000080008001001d203e6067c04b800800100010000000000000000000000000000000
+2242:00000000000000000000000000007fe07fe0000000001c203e6067c043800000000000000000000000000000
+2243:00000000000000000000000000001c203e6067c04380000000007fe07fe00000000000000000000000000000
+2244:00000000000000000100010001001e203e6067c04780040004007fe07fe00800100010000000000000000000
+2245:00000000000000001c203e6067c04380000000007fe07fe0000000007fe07fe0000000000000000000000000
+2246:00000000000000001c203e6067c04380008001007fe07fe0020004007fe07fe0080010000000000000000000
+2247:00000000008000801d203e6067c04380020004007fe07fe0040008007fe07fe0100020000000000000000000
+2248:0000000000000000000000001c203e6067c04380000000001c203e6067c04380000000000000000000000000
+2249:0000000000000080008001001d203e6067c04380020002001c203e6067c04b80080010001000000000000000
+224a:0000000000001c203e6067c04380000000001c203e6067c04380000000007fe07fe000000000000000000000
+224b:0000000000001c203e6067c0438000001c203e6067c0438000001c203e6067c0438000000000000000000000
+224c:0000000000000000438067c03e601c20000000007fe07fe0000000007fe07fe0000000000000000000000000
+224d:0000000000000000000000008010e0707fe01f80000000001f807fe0e0708010000000000000000000000000
+224e:0000000000000000000000000f001980f0f0f0f0000000000f001980f0f0f0f0000000000000000000000000
+224f:0000000000000000000000000f001980f0f0f0f00000000000000000fff0fff0000000000000000000000000
+2250:000000000000000006000f000f000600000000007fe07fe0000000007fe07fe0000000000000000000000000
+2251:000006000f000f00060000007fe07fe0000000007fe07fe0000006000f000f00060000000000000000000000
+2252:0000300078007800300000007fe07fe0000000007fe07fe0000000c001e001e000c000000000000000000000
+2253:000000c001e001e000c000007fe07fe0000000007fe07fe00000300078007800300000000000000000000000
+2254:00000000000000000000000000004000e7e0e7e0400000004000e7e0e7e04000000000000000000000000000
+2255:00000000000000000000000000000040fce0fce0004000000040fce0fce00040000000000000000000000000
+2256:00000000000000000000000000007fe07fe006000900090006007fe07fe00000000000000000000000000000
+2257:00000000000000000600090009000600000000007fe07fe0000000007fe07fe0000000000000000000000000
+2258:00000000000000001f807fe0e0708010000000007fe07fe0000000007fe07fe0000000000000000000000000
+2259:00000000000006000f00198030c06060000000007fe07fe0000000007fe07fe0000000000000000000000000
+225a:000000000000606030c019800f000600000000007fe07fe0000000007fe07fe0000000000000000000000000
+225b:00000000000019800f003fc00f001980000000007fe07fe0000000007fe07fe0000000000000000000000000
+225c:0000000006000f00198030c060607fe0000000007fe07fe0000000007fe07fe0000000000000000000000000
+225d:0000103010401740f570954097409440f74000007fe07fe0000000007fe07fe0000000000000000000000000
+225e:000000003bc066606660666066606660000000007fe07fe0000000007fe07fe0000000000000000000000000
+225f:1f803fc070e001c003800700070000000700070000007fe07fe0000000007fe07fe000000000000000000000
+2260:000000000000000000000000004000c001807fc07fc006000c007fc07fc03000600040000000000000000000
+2261:00000000000000000000000000007fc07fc000007fc07fc000007fc07fc00000000000000000000000000000
+2262:00000000000000000000010002007fc07fc004007fc07fc008007fc07fc01000200000000000000000000000
+2263:0000000000000000000000007fc07fc000007fc07fc000007fc07fc000007fc07fc000000000000000000000
+2264:00000000000000000000000000e007801e00780078001e00078000e000007fe07fe000000000000000000000
+2265:0000000070001e00078001e001e007801e00700000007fe07fe0000000007fe07fe000000000000000000000
+2266:0000000000e007801e00780078001e00078000e000007fe07fe0000000007fe07fe000000000000000000000
+2267:0000000070001e00078001e001e007801e00700000007fe07fe0000000007fe07fe000000000000000000000
+2268:0000000000e007801e00780078001e00078001e003007fe07fe006000c007fe07fe018003000000000000000
+2269:0000000070001e00078001e001e007801e0070c001807fe07fe0030006007fe07fe00c001800000000000000
+226a:000000000000000007300e701ce039c07380e700e700738039c01ce00e700730000000000000000000000000
+226b:0000000000000000ce00e700738039c01ce00e700e701ce039c07380e700ce00000000000000000000000000
+226c:000033000c001e0033003300330073807380738073803300330033001e000c00330000000000000000000000
+226d:0000000000000000018001808310e3707fe01f80060006001f807fe0ec708c10180018000000000000000000
+226e:000000000000000000400040008000e007801f00790079001e00078002e00400040004000000000000000000
+226f:000000000000000002000200020074001e00078009e009e00f801e0070001000200020000000000000000000
+2270:0000000000400040008000e007801f00790079001e00078002e004007fe07fe0080008000800000000000000
+2271:0000000000000200020072001e00078009e009e00f801e00700010007fe07fe0200020000000000000000000
+2272:00000000000000e007801e00780078001e00078000e0000000001c203e6067c0438000000000000000000000
+2273:00000000000070001e00078001e001e007801e007000000000001c203e6067c0438000000000000000000000
+2274:00000080008000e007801f00790079001e00078004e0040008001c203e6077c0538010002000000000000000
+2275:00000040004070801e80078001e001e007801e007200040004001c203e6077c0538010002000000000000000
+2276:0000000000e007801e00780078001e00078070e01e00078001e001e007801e00700000000000000000000000
+2277:0000000070001e00078001e001e007801e0070e007801e00780078001e00078000e000000000000000000000
+2278:0200020002e007801e007a007a001e00078072e01e00078005e005e007801e00740004000400000000000000
+2279:0020002070401e40078001e001e007801e0076e007801e00780078001e00278020e040004000000000000000
+227a:000000000000000000000000006001c007803c00e0003c00078001c000600000000000000000000000000000
+227b:000000000000000000000000c00070003c00078000e007803c007000c0000000000000000000000000000000
+227c:00000000000000000000006001c007803c00e0003c000780e1c03c60078001c0006000000000000000000000
+227d:00000000000000000000c00070003c00078000e007803c0070e0c7803c007000c00000000000000000000000
+227e:000000000000006001c007803c00e0003c00078001c0006000001c203e6067c0438000000000000000000000
+227f:000000000000c00070003c00078000e007803c007000c00000001c203e6067c0438000000000000000000000
+2280:000000000000000003000300066007c007803c00ec003c001f8019c018603000300000000000000000000000
+2281:000000000000000001800180c30073003f00078006e007803c007c00cc001800180000000000000000000000
+2282:0000000000000000000007e01fe03800600060006000600038001fe007e00000000000000000000000000000
+2283:000000000000000000007e007f8001c0006000600060006001c07f807e000000000000000000000000000000
+2284:0000000000000180018007e01fe03980618061806180618039801fe007e00180018000000000000000000000
+2285:000000000000180018007e007f8019c0186018601860186019c07f807e001800180000000000000000000000
+2286:000000000000000007e01fe03800600060006000600038001fe007e000007fe07fe000000000000000000000
+2287:00000000000000007e007f8001c0006000600060006001c07f807e0000007fe07fe000000000000000000000
+2288:000000000040004007e01fe0390061006200620064003c001fe017e010007fe07fe020002000000000000000
+2289:00000000004000407f807f8001c0016002600260046005c07f807e0010007fe07fe020004000000000000000
+228a:00000000000007e01fe03800600060006000600038001fe007e000c001807fe07fe00c001800000000000000
+228b:0000000000007e007f8001c0006000600060006001c07f807e0000c001807fe07fe00c001800000000000000
+228c:0000000000000000000060606060626066606fe0666062606060606070e03fc01f8000000000000000000000
+228d:000000000000000000006060606066606f606f60666060606060606070e03fc01f8000000000000000000000
+228e:00000000000000000000c060c060c460c460df60c460c460c060c060e0e07fc03f8000000000000000000000
+228f:000000000000000000007fe07fe0600060006000600060006000600060007fe07fe000000000000000000000
+2290:000000000000000000007fe07fe0006000600060006000600060006000607fe07fe000000000000000000000
+2291:000000007fe07fe0600060006000600060006000600060007fe07fe000007fe07fe000000000000000000000
+2292:000000007fe07fe0006000600060006000600060006000607fe07fe000007fe07fe000000000000000000000
+2293:000000000000000000007fe07fe0606060606060606060606060606060606060606000000000000000000000
+2294:0000000000000000000060606060606060606060606060606060606060607fe07fe000000000000000000000
+2295:00000000000000000e0035804440444084208420ffe0842084204440444035800e0000000000000000000000
+2296:00000000000000000e0031804040404080208020ffe0802080204040404031800e0000000000000000000000
+2297:00000000000000000e003180404060c091208a2084208a20912060c0404031800e0000000000000000000000
+2298:00000000000000000e003180404040c0812082208420882090206040404031800e0000000000000000000000
+2299:00000000000000000e0031804040404080208e208e208e2080204040404031800e0000000000000000000000
+229a:00000000000000000e003180404040408e209120912091208e204040404031800e0000000000000000000000
+229b:00000000000000000e0031804040404095208e2084208e2095204040404031800e0000000000000000000000
+229c:00000000000000000e003180404040409f208020802080209f204040404031800e0000000000000000000000
+229d:00000000000000000e0031804040404080208020bfa0802080204040404031800e0000000000000000000000
+229e:0000000000000000ffe084208420842084208420ffe084208420842084208420ffe000000000000000000000
+229f:0000000000000000ffe080208020802080208020ffe080208020802080208020ffe000000000000000000000
+22a0:0000000000000000ffe08020c060a0a091208a2084208a209120a0a0c0608020ffe000000000000000000000
+22a1:0000000000000000ffe080208020802084208e208e2084208020802080208020ffe000000000000000000000
+22a2:00000000000000000000600060006000600060007fe07fe06000600060006000600000000000000000000000
+22a3:00000000000000000000006000600060006000607fe07fe00060006000600060006000000000000000000000
+22a4:0000000000000000000000000000060006000600060006000600060006007fe07fe000000000000000000000
+22a5:00000000000000000000000000007fe07fe00600060006000600060006000600060000000000000000000000
+22a6:00000000000000000000000030003000300030003fc03fc03000300030003000000000000000000000000000
+22a7:000000000000000000000000300030003fc03fc0300030003fc03fc030003000000000000000000000000000
+22a8:000000000000000000000000600060007fe07fe0600060007fe07fe060006000000000000000000000000000
+22a9:000000000000000000000000cc00cc00cc00cc00cff0cff0cc00cc00cc00cc00000000000000000000000000
+22aa:000000000000000000000000db00db00db00db00dbf0dbf0db00db00db00db00000000000000000000000000
+22ab:000000000000000000000000cc00cc00cff0cff0cc00cc00cff0cff0cc00cc00000000000000000000000000
+22ac:00000000000000000020602060406040608060807fe07fe06200620064006400680008000000000000000000
+22ad:000000000000000000200020604060407fe07fe0610061007fe07fe064006400080008000000000000000000
+22ae:000000000000000000200020cc20cc40cc40cc40cff0cff0cc80cc80cc80cd00010001000000000000000000
+22af:000000000000000000100020cc20cc20cff0cff0cc40cc80cff0cff0cd00cd00010002000000000000000000
+22b0:0000000000000000038001c0006001c007803c00e0003c00078001c000e001c0038000000000000000000000
+22b1:000000000000000038007000e00070003c00078000e007803c007000e0007000380000000000000000000000
+22b2:000000000000000000000000002000e003200c203020c02030200c20032000e0002000000000000000000000
+22b3:0000000000000000000000008000e0009800860081808060818086009800e000800000000000000000000000
+22b4:000000000000002000e003200c203020c02030200c20032000e000200000ffe0ffe000000000000000000000
+22b5:0000000000008000e0009800860081808060818086009800e00080000000ffe0ffe000000000000000000000
+22b6:0000000000000000000000000000204050e08ff08ff050e02040000000000000000000000000000000000000
+22b7:000000000000000000000000000020807140fe20fe2071402080000000000000000000000000000000000000
+22b8:000000000000000000000000000000800140fe20fe2001400080000000000000000000000000000000000000
+22b9:0000000000000000000000000000060006000600000070e070e0000006000600060000000000000000000000
+22ba:00000000000000000000000000000000000000007fe07fe00600060006000600060006000600000000000000
+22bb:00000000000000006060606030c030c0198019800f000f000600060000007fe07fe000000000000000000000
+22bc:00000000000000007fe07fe00000060006000f000f001980198030c030c06060606000000000000000000000
+22bd:00000000000000007fe07fe000006060606030c030c0198019800f000f000600060000000000000000000000
+22be:00000000000000000000c000c000f000cc00c200c100c100c080c080c080ffe0ffe000000000000000000000
+22bf:00000000000000000000006000e001e0036006600c60186030606060c060ffe0ffe000000000000000000000
+22c0:060006000f000f000f0019801980198030c030c030c0606060606060c030c030c03000000000000000000000
+22c1:c030c030c03060606060606030c030c030c01980198019800f000f000f000600060000000000000000000000
+22c2:0f003fc070e060606060c030c030c030c030c030c030c030c030c030c030c030c03000000000000000000000
+22c3:c030c030c030c030c030c030c030c030c030c030c030c0306060606070e03fc00f0000000000000000000000
+22c4:0000000000000000000000000600090010802040108009000600000000000000000000000000000000000000
+22c5:0000000000000000000000000000000006000f000f0006000000000000000000000000000000000000000000
+22c6:0000000000000000000000000000000019800f003fc00f001980000000000000000000000000000000000000
+22c7:000000000000000006000f00c630606030c01980fff0198030c06060c6300f00060000000000000000000000
+22c8:000000000000000000008010c030a050909089108610861089109090a050c030801000000000000000000000
+22c9:000000000000000000008010c020a040908089008600860089009080a040c020801000000000000000000000
+22ca:0000000000000000000080104030205010900910061006100910109020504030801000000000000000000000
+22cb:0000000000000000000080004000200010000800040006000900108020404020801000000000000000000000
+22cc:0000000000000000000000100020004000800100020006000900108020404020801000000000000000000000
+22cd:00000000000000000000000000000000438067c03e601c20000000007fe07fe0000000000000000000000000
+22ce:0000000000000000c06060c0318031801b001b001b001b000e000e000e000400040000000000000000000000
+22cf:0000000000000000040004000e000e000e001b001b001b001b003180318060c0c06000000000000000000000
+22d0:000000000000000007e01fe0380063e067e0640067e063e038001fe007e00000000000000000000000000000
+22d1:00000000000000007e007f8001c07c607e6002607e607c6001c07f807e000000000000000000000000000000
+22d2:000000000000000000003fc07fe0e070c030c630cf30c930c930c930c930c930c93000000000000000000000
+22d3:00000000000000000000c930c930c930c930c930c930cf30c630c030e0707fe03fc000000000000000000000
+22d4:000000000000060006003fc07fe0e670c630c630c630c630c630c630c630c630c63000000000000000000000
+22d5:000000000000000030c030c030c0fff0fff030c030c030c0fff0fff030c030c030c000000000000000000000
+22d6:000000000000000000000000000000e007801e00786078601e00078000e00000000000000000000000000000
+22d7:000000000000000000000000000070001e00078061e061e007801e0070000000000000000000000000000000
+22d8:0000000000000000049009201240248049009200920049002480124009200490000000000000000000000000
+22d9:0000000000000000920049002480124009200490049009201240248049009200000000000000000000000000
+22da:0000000000600180060018006000ffe00000ffe0ffe00000ffe000c003000c003000c0000000000000000000
+22db:00000000c00030000c00030000c0ffe00000ffe0ffe00000ffe0600018000600018000600000000000000000
+22dc:0000000000000000000000007fe07fe0000000e007801e00780078001e00078000e000000000000000000000
+22dd:0000000000000000000000007fe07fe0000070001e00078001e001e007801e00700000000000000000000000
+22de:00000000000000000000006001c007803c60e1c007803c00e0003c00078001c0006000000000000000000000
+22df:00000000000000000000c00070003c00c78070e03c00078000e007803c007000c00000000000000000000000
+22e0:00000000000004000400046009c00f803c00e8003c000f80e9c03c600f8009c0106010001000000000000000
+22e1:00000000000000800080c08071003d00078002e007803e0072e0c7803e007200c40004000400000000000000
+22e2:004000807fe07fe0610061006100620062006200640064007fe07fe008007fe07fe010001000000000000000
+22e3:004000807fe07fe0016001600160026002600260046004607fe07fe008007fe07fe010001000000000000000
+22e4:000000007fe07fe060006000600060006000600060007fe07fe0018003007fe07fe00c001800000000000000
+22e5:000000007fe07fe000600060006000600060006000607fe07fe0018003007fe07fe00c001800000000000000
+22e6:00000000000000e007801f00780078001e00078000e0040008001c203e6077c0538010002000000000000000
+22e7:00000000000070001e00078001e001e007801e007000040004001c203e6077c0538010002000000000000000
+22e8:000000000000006000c003801c00e0001c00038000c0046004001c203e6077c0538010002000000000000000
+22e9:000000000000c00060003800070000e0070038006000c40004001c203e6077c0538010002000000000000000
+22ea:000000000000000000800080012001e003200e203420c42038200c20132010e0202020004000000000000000
+22eb:0000000000000000008000808100e1009a0086008580846089808e009800f000a00020004000000000000000
+22ec:00000080008000a001e003200d203220c22032200c20072004e008200800ffe0ffe010001000000000000000
+22ed:0000010001008100e2009a0086008580846085808e009800e80090001000ffe0ffe020002000000000000000
+22ee:000006000f000f0006000000000006000f000f0006000000000006000f000f00060000000000000000000000
+22ef:000000000000000000000000000000000000eee0eee0eee00000000000000000000000000000000000000000
+22f0:0000006000f000f000600000000006000f000f000600000000006000f000f000600000000000000000000000
+22f1:00006000f000f00060000000000006000f000f00060000000000006000f000f0006000000000000000000000
+22f2:0000000000000000000003f00ff01c0018003000fff0fff0300018001c000ff003f000000000000000000000
+22f3:0000000000000000000007e01fe03800306060607fe07fe06060306038001fe007e000000000000000000000
+22f4:0000000000000000000000000000000007c0180020407fc02040180007c00000000000000000000000000000
+22f5:0000018003c00180000007e01fe03800300060007fe07fe06000300038001fe007e000000000000000000000
+22f6:000000007fe07fe0000007e01fe03800300060007fe07fe06000300038001fe007e000000000000000000000
+22f7:000000000000000000007fe00000000007c0180020407fc02040180007c00000000000000000000000000000
+22f8:0000000007e01fe03800300060007fe07fe06000300038001fe007e000007fe07fe000000000000000000000
+22f9:0000000000000000000007e01fe0380030007fe0600060007fe0300038001fe007e000000000000000000000
+22fa:00000000000000000000fc00ff000380018000c0fff0fff000c001800380ff00fc0000000000000000000000
+22fb:000000000000000000007e007f8001c060c060607fe07fe0606060c001c07f807e0000000000000000000000
+22fc:000000000000000000000000000000003e00018020403fe0204001803e000000000000000000000000000000
+22fd:000000007fe07fe000007e007f8001c000c000607fe07fe0006000c001c07f807e0000000000000000000000
+22fe:000000000000000000007fe0000000003e00018020403fe0204001803e000000000000000000000000000000
+22ff:fff0fff0c000c000c000c000c000c000c000c000fff0fff0c000c000c000c000c000c000c000c000fff0fff0
+2300:00000000000000000000000000100fa011c020e06160626064606860704038805f0080000000000000000000
+2301:000000000000000000000000000006000700078006c00660660036001e000e00060000000000000000000000
+2302:0f000f001980198030c030c060606060c030c030c030c030c030c030c030fff0000000000000000000000000
+2303:060006000f000f001980198030c030c060606060c030c0300000000000000000000000000000000000000000
+2304:0000000000000000000000000000000000000000c030c0306060606030c030c0198019800f000f0006000600
+2305:00000000000000000000fff0fff00000060006000f000f001980198030c030c060606060c030c03000000000
+2306:0000fff0fff000000000fff0fff00000060006000f000f001980198030c030c060606060c030c03000000000
+2307:030006000c000c000600030001800180030006000c000c000600030001800180030006000c000c0006000300
+2308:000000003fc03fc0300030003000300030003000300030003000300030003000300030003000000000000000
+2309:000000003fc03fc000c000c000c000c000c000c000c000c000c000c000c000c000c000c000c0000000000000
+230a:000000003000300030003000300030003000300030003000300030003000300030003fc03fc0000000000000
+230b:0000000000c000c000c000c000c000c000c000c000c000c000c000c000c000c000c03fc03fc0000000000000
+230c:000000000000000000000000000000000000000000000000000000000000000000f000000200020002000200
+230d:0000000000000000000000000000000000000000000000000000000000000000f00000000400040004000400
+230e:0200020002000200000000f00000000000000000000000000000000000000000000000000000000000000000
+230f:04000400040004000000f0000000000000000000000000000000000000000000000000000000000000000000
+2310:0000000000000000000000000000000000007fe07fe060006000600060000000000000000000000000000000
+2311:0000000000000000000000000000000030c01f8010801080108010801f8030c0000000000000000000000000
+2312:000000000000000000000000000000001f802040402040208010801000000000000000000000000000000000
+2313:000000000000000000000000000000001f802040402040208010fff000000000000000000000000000000000
+2314:000000000000000000000000000000001f802040606030c019800f0000000000000000000000000000000000
+2315:0000000000000000000003000cc01020201020102010201010202cc043008000000000000000000000000000
+2316:0000000000000400040004000e003580444084208020f1e080208420444035800e0004000400040000000000
+2317:000000000000000030c030c0fff0fff030c030c030c030c030c0fff0fff030c030c000000000000000000000
+2318:0000000000000000f0f090909f90fff030c030c030c030c030c0fff09f909090f0f000000000000000000000
+2319:000000000000000000000000000060006000600060007fe07fe0000000000000000000000000000000000000
+231a:00000003ff80030180030180030180030180037d800383800610c00c10601810301a1cb01800300c00600610c0038380037d8003018003018003018003018003ff80
+231b:00000007ffe0040020040020020040020040010080010080008100004200003c00004200008100010080021840021840047e20047e2009ff900ffff00ffff0000000
+231c:fe00fe00c000c000c000c000c000000000000000000000000000000000000000000000000000000000000000
+231d:03f003f000300030003000300030000000000000000000000000000000000000000000000000000000000000
+231e:000000000000000000000000000000000000000000000000000000000000c000c000c000c000c000fc00fc00
+231f:0000000000000000000000000000000000000000000000000000000000000030003000300030003003f003f0
+2320:000001e003e00300030006000600060006000600060006000600060006000600060006000600060006000600
+2321:060006000600060006000600060006000600060006000600060006000600060006000c000c007c0078000000
+2322:0000000000000000000000000000000000000000000000001f80606080100000000000000000000000000000
+2323:000000000000000000000000000000000000000000000000801060601f800000000000000000000000000000
+2324:00000000000000000000000000000000f6f0e6700f000f001980198030c030c060606060c030c03000000000
+2325:00000000000000000000000000000000f0f0f8f01c000e000700038001f000f0000000000000000000000000
+2326:00000000000000000000ff80ff8080408040a12092208c108c109220a12080408040ff80ff80000000000000
+2327:00000000000000000000fff0fff08010a050909089108610861089109090a0508010fff0fff0000000000000
+2328:000000000000000000007fe0fff08010a9508010a9508010bfd0bfd08010fff07fe000000000000000000000
+2329:00300000600000600000600000c00000c00000c00001800001800001800003000003000001800001800001800000c00000c00000c000006000006000006000003000
+232a:0c000006000006000006000003000003000003000001800001800001800000c00000c0000180000180000180000300000300000300000600000600000600000c0000
+232b:000000000000000000001ff01ff020102010485044908310831044904850201020101ff01ff0000000000000
+232c:0000000006000900108022404120909090509010901090109010905090904120224010800900060000000000
+232d:0000000000000000080008001000100026102f1059a059a08f40864000800080010001000000000000000000
+232e:000000000000000000000000000007000880104013f0144008809700a000c000f00000000000000000000000
+232f:000000000000000000001f801f80000000007fe07fe0000000001f801f800000000000000000000000000000
+2330:00000000000000000000104038e07df020402040204040804080408081008100ff0000000000000000000000
+2331:00000000000000001000100010003880544092209ff092205440388010001000100000000000000000000000
+2332:000000000000000000000000c000b0008c00830080c0fff080c083008c00b000c00000000000000000000000
+2333:000000000000000000000000c000b0008c00830080c0fff00000000000000000000000000000000000000000
+2334:0000000000000000000000000000000000008010801080108010801080108010fff000000000000000000000
+2335:0000000000000000000000000000000000000000000080104020204010800900060000000000000000000000
+2336:0000fff0060006000600060006000600060006000600060006000600060006000600060006000600fff00000
+2337:000000007fe07fe060606060606060606060606060606060606060606060606060607fe07fe0000000000000
+2338:00000000fff0fff0c030c030c030dfb0dfb0c030c030c030dfb0dfb0c030c030c030fff0fff0000000000000
+2339:00000000fff0fff0c030c030c630c630c030c030dfb0dfb0c030c030c630c630c030fff0fff0000000000000
+233a:00000000fff0fff0c030c030c030c630c930d0b0e070e070d0b0c930c630c030c030fff0fff0000000000000
+233b:00000000fff0fff0c030c030c030c030c630cf30d9b0d9b0cf30c630c030c030c030fff0fff0000000000000
+233c:00000000fff0fff0c030c030cf30dfb0f0f0e070c030c030e070f0f0dfb0cf30c030fff0fff0000000000000
+233d:0000000000000600060006000f003fc076e0e670c630c630e67076e03fc00f00060006000600000000000000
+233e:000000000000000000000f003fc070e06060e670c930c930e670606070e03fc00f0000000000000000000000
+233f:000000c000c000c00180018001800300030003007fe07fe00c000c000c001800180018003000300030000000
+2340:00003000300030001800180018000c000c000c007fe07fe003000300030001800180018000c000c000c00000
+2341:00000000fff0c0f0c1b0c1b0c1b0c330c330c330c630c630cc30cc30cc30d830d830d830f030fff000000000
+2342:00000000fff0f030d830d830d830cc30cc30cc30c630c630c330c330c330c1b0c1b0c1b0c0f0fff000000000
+2343:00000000fff0c030c030c030c070c1b0c630d830e030e030d830c630c1b0c070c030c030c030fff000000000
+2344:00000000fff0c030c030c030e030d830c630c1b0c070c070c1b0c630d830e030c030c030c030fff000000000
+2345:000000000000030003000300130033007300fff0fff073003300130003000300030000000000000000000000
+2346:0000000000000c000c000c000c800cc00ce0fff0fff00ce00cc00c800c000c000c0000000000000000000000
+2347:00000000fff0c030c030c030c030c430cc30dc30fff0fff0dc30cc30c430c030c030c030c030fff000000000
+2348:00000000fff0c030c030c030c030c230c330c3b0fff0fff0c3b0c330c230c030c030c030c030fff000000000
+2349:0000180018000c000c000c000f003fc07ce0ec70c630c630e37073e03fc00f8001800180018000c000c00000
+234a:00000000000000000600060006000600060006000600060006000600fff0fff000000000fff0000000000000
+234b:00000000060006000600060006000f000f001680168026402640462046208610fff006000600060000000000
+234c:00000000fff0c030c030e070e070e070d0b0d0b0d0b0c930c930c930c630c630c030c030c030fff000000000
+234d:00000000fff0c030c030c030c630c630c930c930d0b0d0b0e070e070c030fff0c030c030c030fff000000000
+234e:00000000060006001f803fc0666066606660666066603fc01f80060006007fe07fe000000000000000000000
+234f:00000000000006000f001f803fc0060006000600fff0fff00600060006000600060000000000000000000000
+2350:00000000fff0c630cf30dfb0fff0c630c630c630c630c630c630c630c630c630c630c630c630fff000000000
+2351:00000000fff00000fff0fff00600060006000600060006000600060006000600060000000000000000000000
+2352:00000000060006000600fff086104620462026402640168016800f000f000600060006000600060000000000
+2353:00000000fff0c030c030c030c630c630c930c930c930d0b0d0b0d0b0e070e070e070c030c030fff000000000
+2354:00000000fff0c030c030c030fff0c030e070e070d0b0d0b0c930c930c630c630c030c030c030fff000000000
+2355:000000007fe07fe0060006001f803fc0666066606660666066603fc01f800600060000000000000000000000
+2356:00000000000006000600060006000600fff0fff00600060006003fc01f800f00060000000000000000000000
+2357:00000000fff0c630c630c630c630c630c630c630c630c630c630c630c630fff0dfb0cf30c630fff000000000
+2358:000000000600060006000600000000000000000000000000000000000000000000000000fff0000000000000
+2359:000000000000000000000600060009000900108010802040204040204020fff0fff00000fff0000000000000
+235a:000000000000000000000600090010802040402080108010402020401080090006000000fff0000000000000
+235b:0000000000000000000000000000000006000f00198019800f0006000000000000000000fff0000000000000
+235c:00000000000000000f003fc070e06060e070c030c030e070606070e03fc00f0000000000fff0000000000000
+235d:000000000000000000000f0030c06060c630cf30d9b0d9b0cf30c630c030c030c03000000000000000000000
+235e:00000000fff0fff0c030c630c630c630c630c030c030c030c030c030c030c030c030fff0fff0000000000000
+235f:00000000000000000f003fc060606060c930c630c630c930606060603fc00f00000000000000000000000000
+2360:00000000fff0fff0c030c630cf30cf30c630c030c030c030c630cf30cf30c630c030fff0fff0000000000000
+2361:30c079e030c00000fff0fff00600060006000600060006000600060006000600060000000000000000000000
+2362:000030c079e030c000000600060009000900108010802040204040204020fff0fff000000000000000000000
+2363:0000000030c079e030c0000000000600c630666036c01f801f8036c06660c630060000000000000000000000
+2364:0000000030c079e030c000000000000006000f00198019800f00060000000000000000000000000000000000
+2365:000030c079e030c000000f003fc070e06060e070c030c030e070606070e03fc00f0000000000000000000000
+2366:00000000060006000600c630c630c630c630c630c630c630c630c630666036c00f0006000600060000000000
+2367:000000000300030003001ff03ff073006300c300c300c300c300630073003ff01ff003000300030000000000
+2368:00000000000030c079e030c0000000001c107e70e3e081c00000000000000000000000000000000000000000
+2369:00000000000030c079e030c00000600018000600018000600060018006001800600000000000000000000000
+236a:000000000000000000000000000000003f803f800000000000000e000e000e001c0038000000000000000000
+236b:00000000000000000000fff08010402040203c507e70f3e090c0090009000600060000000000000000000000
+236c:0000000000000f0010802040402040205c307e70e7e0c3a040204020204010800f0000000000000000000000
+236d:000000000000060006000600060006001e307e70e7e0c7800600060006000600060006000600000000000000
+236e:0000000000000000000000000e000e000e000000000000000e000e000e001c0038000000fff0000000000000
+236f:00000000fff0fff0c030c130c130dfb0dfb0c230c230c430c430dfb0dfb0c830c830c030fff0fff000000000
+2370:00000000fff0fff0c030cf30cf30d9b0c1b0c1b0c330c630c630c630c030c630c630c030fff0fff000000000
+2371:0000000000000000000080108010402040203c507e70f3e090c0090009000600060000000000000000000000
+2372:00000000000000000000060006000900090030907cf0e7e0a3c0402040208010801000000000000000000000
+2373:000000000000000000000000000000007e007e000600060006000600060006000600038000e0000000000000
+2374:000000000000000000000000000000001f803fc070e060606060606070e07fc0670060006000600000000000
+2375:00000000000000000000000000006060c030c630c630c630c630c63066207fc0198000000000000000000000
+2376:00000000000000000000000000001f9031d060e060e060c060c060c061e072603c300000fff0000000000000
+2377:00000000000000000000000000000f801fc0206060003f003f00600060203fc01f000000fff0000000000000
+2378:0000000000000000000000007e007e000600060006000600060006000600038000e00000fff0000000000000
+2379:00000000000000000000000000006060c030c630c630c630c630c63066207fc019800000fff0000000000000
+237a:00000000000000000000000000001f9031d060e060e060c060c060c061e072603c3000000000000000000000
+237b:000000c0018001801ff01ff0030003006600660066003c003c003c0018001800180000000000000000000000
+237c:0000000000000cc00f000c003c00cc00cc003c000c000f000cc00cc08f008ff0bff0c000f800000000000000
+237d:000000000000000000000000000000000000f0f0f0f030c030c030c030c03fc03fc000000000000000000000
+237e:000000000f001f8030c060606060c030c030fff0fff030c030c030c030c0f0f0f0f000000000000000000000
+237f:00000000060006000600060006000f001f801f800f0006000600060006000600060000000000000000000000
+2380:0000000000000f001080008000800f801080108010808f904020204010800900060000000000000000000000
+2381:0000000000000000000000000000000078008400040004007c008400840084007d500000fff0000000000000
+2382:0000000000000000000000000000000071c08a200820082079e08a208a208a2079e0000079e0000000000000
+2383:0000000000000000000000008010c0304f2010800080c0b0cfb01080108010804fa0c0308010000000000000
+2384:0000000000000000000000000000ffc089209110911091109110911091108920ffc000000000000000000000
+2385:00000000000006000600f6f08610861086108610861086108610861086108610f6f006000600000000000000
+2386:000000000000000006000f00198030c004600630ff10ff100630046030c019800f0006000000000000000000
+2387:000000000000000000000040006003f003f0066006400c000c0018001800f1f0f1f000000000000000000000
+2388:00000000842084204e4055402480554055404e404e404e4055405540248055404e4084208420000000000000
+2389:000000000000000000000f003fc0606040208010f0f099908f10462060603fc00f0000000000000000000000
+238a:000000000000000000000f003fc060604020fff0b0d099908f10462060603fc00f0000000000000000000000
+238b:00000000000000000000f300c3c0a0e0906008700430c230e070606070e03fc00f0000000000000000000000
+238c:000000000f801fc038e03870fe707c70387010000000000070e089108910891070e000000000000000000000
+238d:0000000000003fc03fc030c030c030c030c030c030c030c030c030c030c0f0f0f0f000000000000000000000
+238e:0000000000000ff01fe030e030c030c030c030c030c030c030c030c070c07f80ff0000000000000000000000
+238f:0000000000000000fff006000900108020404020801080104020204010800900060000000000000000000000
+2390:0000000000000000060009001080204040208010801040202040108009000600fff000000000000000000000
+2391:000000000000fff0060009001080204040208010fff080104020204010800900060000000000000000000000
+2392:000000000000060009001080204040208010fff0801040202040108009000600fff000000000000000000000
+2393:00000000000000000000000000000000ffe0ffe000000000eee0eee000000000000000000000000000000000
+2394:0000000000001f801080204020404020402080108010402040202040204010801f8000000000000000000000
+2395:00000000fff0fff0c030c030c030c030c030c030c030c030c030c030c030c030c030c030fff0fff000000000
+2396:00000000000000003fc03f803f803f003f003e003e003c003c00380038003000300000000000000000000000
+2397:0000d540804000409ff00010801004108c101fd0bfd01fd08c10041080101010f01010101ff0000000000000
+2398:0000ffc08040804095508000801082008310bf80bfd0bf808310820080108000f01010001550000000000000
+2399:0000000003c006400a4012403e402040e070a050a050a050bfd0801080108010fff000000000000000000000
+239a:00000000000000000000000000007fe0801088909110a21084508890911080107fe000000000000000000000
+239b:0000000001800300060006000c000c000c001800180018001800300030003000300030003000300030003000
+239c:3000300030003000300030003000300030003000300030003000300030003000300030003000300030003000
+239d:30003000300030003000300030003000300018001800180018000c000c000c00060006000300018000000000
+239e:0000000018000c0006000600030003000300018001800180018000c000c000c000c000c000c000c000c000c0
+239f:00c000c000c000c000c000c000c000c000c000c000c000c000c000c000c000c000c000c000c000c000c000c0
+23a0:00c000c000c000c000c000c000c000c000c00180018001800180030003000300060006000c00180000000000
+23a1:000000003f803f80300030003000300030003000300030003000300030003000300030003000300030003000
+23a2:3000300030003000300030003000300030003000300030003000300030003000300030003000300030003000
+23a3:3000300030003000300030003000300030003000300030003000300030003000300030003f803f8000000000
+23a4:000000001fc01fc000c000c000c000c000c000c000c000c000c000c000c000c000c000c000c000c000c000c0
+23a5:00c000c000c000c000c000c000c000c000c000c000c000c000c000c000c000c000c000c000c000c000c000c0
+23a6:00c000c000c000c000c000c000c000c000c000c000c000c000c000c000c000c000c000c01fc01fc000000000
+23a7:0000000000c00180030003000600060006000600060006000600060006000600060006000600060006000600
+23a8:06000600060006000600060006000c000c0018003000300018000c000c000600060006000600060006000600
+23a9:060006000600060006000600060006000600060006000600060006000600060003000300018000c000000000
+23aa:0600060006000600060006000600060006000600060006000600060006000600060006000600060006000600
+23ab:00000000300018000c000c000600060006000600060006000600060006000600060006000600060006000600
+23ac:060006000600060006000600060003000300018000c000c00180030003000600060006000600060006000600
+23ad:06000600060006000600060006000600060006000600060006000600060006000c000c001800300000000000
+23ae:0600060006000600060006000600060006000600060006000600060006000600060006000600060006000600
+23af:0000000000000000000000000000000000000000fff0fff00000000000000000000000000000000000000000
+23b0:00c0018003000300060006000600060006000600060006000600060006000600060006000c000c0018003000
+23b1:300018000c000c000600060006000600060006000600060006000600060006000600060003000300018000c0
+23b2:00000000000000007fe07fe030003000180018000c000c0006000600030003000180018000c000c000600060
+23b3:0060006000c000c00180018003000300060006000c000c0018001800300030007fe07fe00000000000000000
+23b4:fff0fff0c030c030c030c0300000000000000000000000000000000000000000000000000000000000000000
+23b5:0000000000000000000000000000000000000000000000000000000000000000c030c030c030c030fff0fff0
+23b6:00000000c030c030c030c030fff0fff0000000000000fff0fff0c030c030c030c03000000000000000000000
+23b7:06000600060006000600c600c60066006600360036001e001e000e000e000600060000000000000000000000
+23b8:c000c000c000c000c000c000c000c000c000c000c000c000c000c000c000c000c000c000c000c000c000c000
+23b9:0030003000300030003000300030003000300030003000300030003000300030003000300030003000300030
23ba:fff0fff000000000000000000000000000000000000000000000000000000000000000000000000000000000
23bb:000000000000000000000000fff0fff000000000000000000000000000000000000000000000000000000000
23bc:00000000000000000000000000000000000000000000000000000000fff0fff0000000000000000000000000
23bd:00000000000000000000000000000000000000000000000000000000000000000000000000000000fff0fff0
+23be:00000000000007e0040004000400040004000400040004000400040004000400040000000000000000000000
+23bf:000000000000040004000400040004000400040004000400040004000400040007e000000000000000000000
+23c0:000000000400040004001f0024804440444084208420842084204440444024801f0004000400040000000000
+23c1:0000ffe00400040004001f0024804440444084208420842084204440444024801f0004000400040000000000
+23c2:00000400040004001f0024804440444084208420842084204440444024801f00040004000400ffe000000000
+23c3:000004000400040004000e000e0015001500248024804440444084208420ffe0040004000400040000000000
+23c4:0000ffe00400040004000e000e0015001500248024804440444084208420ffe0040004000400040000000000
+23c5:000004000400040004000e000e0015001500248024804440444084208420ffe0040004000400ffe000000000
+23c6:0000000004000400040004000400040004203c40478084000400040004000400040004000400040000000000
+23c7:0000ffe004000400040004000400040004203c40478084000400040004000400040004000400040000000000
+23c8:00000400040004000400040004000400040004203c4047808400040004000400040004000400ffe000000000
+23c9:0000ffe004000400040004000400040004000400040004000400040004000400040004000400040000000000
+23ca:0000040004000400040004000400040004000400040004000400040004000400040004000400ffe000000000
+23cb:000000000000fc00040004000400040004000400040004000400040004000400040000000000000000000000
+23cc:0000000000000400040004000400040004000400040004000400040004000400fc0000000000000000000000
+23cd:00000000000007000600f6f08410801080108010801080108010801080108010fff000000000000000000000
+23ce:000000000000000000e000e000e000e008e018e038e07fe0ffe07fc038001800080000000000000000000000
+23cf:000000000000000006000f001f803fc07fe0fff0000000000000fff0fff0fff0fff000000000000000000000
+23d0:0600060006000600060006000600060006000600060006000600060006000600060006000600060006000600
+23d1:00000000000000000000000000000000c03060603fc00f000000000000000000000000000000000000000000
+23d2:0000000000000000000000000000fff0fff000000000c03060603fc00f000000000000000000000000000000
+23d3:0000000000000000000000000000c03060603fc00f0000000000fff0fff00000000000000000000000000000
+23d4:0000000000000000000000000000fff0fff0000000008610492030c030c00000000000000000000000000000
+23d5:00000000000000000000000000008610492030c030c000000000fff0fff00000000000000000000000000000
+23d6:0000000000000000000000000000000000008610492030c030c0000000000000000000000000000000000000
+23d7:0000000000000000003000300030003000300030fff0fff00000000000000000000000000000000000000000
+23d8:0000000000000000c030c030c030c030c030c030fff0fff00000000000000000000000000000000000000000
+23d9:0000000000000000c630c630c630c630c630c630fff0fff00000000000000000000000000000000000000000
+23da:0000000006000600060006000600060006000600fff0fff0000000003fc03fc0000000000f000f0000000000
+23db:00000000000000000000000000003fc020402040fff0204020403fc000000000000000000000000000000000
+23dc:00000000000000000000000000000000000000000000000000003fc07fe0e070c03000000000000000000000
+23dd:00000000000000000000c030e0707fe03fc00000000000000000000000000000000000000000000000000000
+23de:000000000000000000000000000000000000000006000f007fe0f9f0c030c030c03000000000000000000000
+23df:0000000000000000c030c030c030f9f07fe00f00060000000000000000000000000000000000000000000000
+23e0:0000000000000000000000000000000000000000000000001f803fc06060c030801000000000000000000000
+23e1:00000000000000008010c03060603fc01f800000000000000000000000000000000000000000000000000000
+23e2:00000000000000000000000000003f0021002080208040404040402080208010fff000000000000000000000
+23e3:000000000000000006000900108020404f209090a050a050a050a05090904f20204010800900060000000000
+23e4:0000000000000000000000000000000000000000fff000000000000000000000000000000000000000000000
+23e5:00000000000000000000000000000ff010101010202020204040404080808080ff0000000000000000000000
+23e6:00000000000000000000000018002400420042007ff002100210012000c00000000000000000000000000000
+23e7:0000000000002000200022002200fa007200223002c00f000f001f00318060c0c06080300000000000000000
+23e8:000000000000000000000000000000000000000000000000000021c0622062202220222022202220222071c0
+23e9:000000000000000000000000000000c00c00f00f00fc0fc0ff0ff0ffcffcffffffffffffffcffcff0ff0fc0fc0f00f00c00c00000000000000000000000000000000
+23ea:00000000000000000000000000000000300300f00f03f03f0ff0ff3ff3ffffffffffffff3ff3ff0ff0ff03f03f00f00f003003000000000000000000000000000000
+23eb:000000000000000000001800007e0001ff8007ffe01ffff87ffffeffffff001800007e0001ff8007ffe01ffff87ffffeffffff000000000000000000000000000000
+23ec:000000000000000000ffffff7ffffe1ffff807ffe001ff80007e00001800ffffff7ffffe1ffff807ffe001ff80007e00001800000000000000000000000000000000
+23ed:000000000000000000008430c630e730f7b0fff0fff0fff0fff0f7b0e730c630843000000000000000000000
+23ee:00000000000000000000c210c630ce70def0fff0fff0fff0fff0def0ce70c630c21000000000000000000000
+23ef:000000000000000000008330c330e330f330fb30ff30ff30fb30f330e330c330833000000000000000000000
+23f0:0000000f00f03f81fc387e1c31c38c0300c00618600618600c18300c18300c18300660600780600300c001c3800ffff01f00f8000000000000000000000000000000
+23f1:1f80060066601f803fc060606660c630c630c630c630c030606060603fc01f80000000000000000000000000
+23f2:0000000000001f803fc060607060d830cc30c630c330c030606060603fc01f80000000000000000000000000
+23f3:00000007ffe004002004002002004003ffc001ff8001ff8000ff00007e00003c00004200009900010080021840021840047e20047e2009ff900ffff00ffff0000000
+23f4:000000000000000000c001c003c007c00fc01fc03fc03fc01fc00fc007c003c001c000c00000000000000000
+23f5:0000000000000000300038003c003e003f003f803fc03fc03f803f003e003c00380030000000000000000000
+23f6:000000000000000000000000000006000f001f803fc07fe0fff0fff000000000000000000000000000000000
+23f7:0000000000000000000000000000fff0fff07fe03fc01f800f00060000000000000000000000000000000000
+23f8:0000000000000000000079e079e079e079e079e079e079e079e079e079e079e079e000000000000000000000
+23f9:00000000000000000000fff0fff0fff0fff0fff0fff0fff0fff0fff0fff0fff0fff000000000000000000000
+23fa:000000000000000000000f003fc07fe07fe0fff0fff0fff0fff07fe07fe03fc00f0000000000000000000000
+23fb:00000000000006000600060036c066606660c630c630c030c030606060603fc00f0000000000000000000000
+23fc:000000000000000000000f003fc060606660c630c630c630c630666060603fc00f0000000000000000000000
+23fd:0000000000000000000006000600060006000600060006000600060006000600060000000000000000000000
+23fe:0000000000000000000006001c0038003000700070007000700038003e001fe0078000000000000000000000
+23ff:000000000000000000000000001000f007e03f40f8a0c0a038a0074000e00000000000000000000000000000
+2400:00004200620052004a00460042000000108010801080108010800f0000000400040004000400040007e00000
+2401:00003c00420030000c0042003c0000000f0010801080108010800f0000000420042007e00420042004200000
+2402:00003c00420030000c0042003c0000001f000400040004000400040000000420024001800180024004200000
+2403:00007e0040007e00400040007e0000001f000400040004000400040000000420024001800180024004200000
+2404:00007e0040007e00400040007e0000000f0010801080108010800f00000007c0010001000100010001000000
+2405:00007e0040007e00400040007e000000108018801480128011801080000003c00420042004a0044003a00000
+2406:00003c00420042007e004200420000000f8010001000100010000f8000000460058006000600058004600000
+2407:00007c0042007e00420042007c0000001f8010001f80100010001f8000000400040004000400040007e00000
+2408:00000000000000007c0042007e00420042007c00000003c00420030000c0042003c000000000000000000000
+2409:0000000000000000420042007e00420042004200000007c00100010001000100010000000000000000000000
+240a:0000000000000000400040004000400040007e00000007e0040007e004000400040000000000000000000000
+240b:0000000000000000420042002400240018001800000007c00100010001000100010000000000000000000000
+240c:00000000000000007e0040007e00400040004000000007e0040007e004000400040000000000000000000000
+240d:00000000000000003e0040004000400040003e00000007c0042007c004800440042000000000000000000000
+240e:00000000000000003c00420030000c0042003c00000003c0042004200420042003c000000000000000000000
+240f:00000000000000003c00420030000c0042003c00000003e0008000800080008003e000000000000000000000
+2410:00007c0042004200420042007c000000100010001000100010001f80000007e0040007e00400040007e00000
+2411:00007c0042004200420042007c0000000f8010001000100010000f8000000080038000800080008003e00000
+2412:00007c0042004200420042007c0000000f8010001000100010000f80000003c0042000400180020007e00000
+2413:00007c0042004200420042007c0000000f8010001000100010000f80000003c0042001e00020042003c00000
+2414:00007c0042004200420042007c0000000f8010001000100010000f80000004000480048007e0008000800000
+2415:00004200620052004a004600420000000f00108010801f801080108000000460058006000600058004600000
+2416:00003c00420030000c0042003c000000104008800500020002000200000004200620052004a0046004200000
+2417:00007e0040007e00400040007e0000001f0004000400040004000400000007c0042007e00420042007c00000
+2418:00003e0040004000400040003e0000000f00108010801f8010801080000004200620052004a0046004200000
+2419:00000000000000007e0040007e00400040007e0000000420066005a004200420042000000000000000000000
+241a:00003c00420030000c0042003c000000108010801080108010800f00000007c0042007e00420042007c00000
+241b:00007e0040007e00400040007e0000000f0010800c00030010800f00000003e0040004000400040003e00000
+241c:00000000000000007e0040007e00400040004000000003c00420030000c0042003c000000000000000000000
+241d:00000000000000003c00420040004e0042003c00000003c00420030000c0042003c000000000000000000000
+241e:00000000000000007c0042007c00480044004200000003c00420030000c0042003c000000000000000000000
+241f:0000000000000000420042004200420042003c00000003c00420030000c0042003c000000000000000000000
+2420:00000000000000003c00420030000c0042003c00000007c0042007c004000400040000000000000000000000
+2421:00007c0042004200420042007c0000001f8010001f80100010001f8000000400040004000400040007e00000
+2422:00000000600060006c007000e00067806fc070e06060606060606060706078c06f8000000000000000000000
+2423:0000000000000000000000000000000000000000000000006060606060607fe07fe000000000000000000000
+2424:000000000000630073007b006f006700630000000000030003000300030003e003e000000000000000000000
+2425:0000000000000000000000900120024004900920124024804900920024004800900000000000000000000000
+2426:000000000f001f8039c030403000300018000c00060003000300000000000300030000000000000000000000
+2427:0000000000000000000033303330ccc0ccc033303330ccc0ccc033303330ccc0ccc000000000000000000000
+2428:000033303330ccc0ccc033303330ccc0ccc033303330ccc0ccc033303330ccc0ccc000000000000000000000
+2429:00001c701c70e380e3801c701c70e380e3801c701c70e380e3801c701c70e380e38000000000000000000000
+2440:000000000000000000000000000007e007e00660066006606600660066007e007e0000000000000000000000
+2441:000000000000000000000000000000600060006000607fe07fe0606060606060606000000000000000000000
+2442:000000000000000000000000000060606060606060607fe07fe0060006000600060000000000000000000000
+2443:000000000000000000000000000006000600060006007fe07fe0606060606060606000000000000000000000
+2444:00000000000000000000000000007fe07fe06660666006000600666066607fe07fe000000000000000000000
+2445:0000000000000000000000008010e070999086109990e0708010000000000000000000000000000000000000
+2446:000000000000000001e001e071e071e0700070007000700071e071e001e001e0000000000000000000000000
+2447:000000000000000000000000000000e000e006e006e006000600760076007000700000000000000000000000
+2448:00000000000000000000000001e001e001e001e001e06de06de06c006c006c006c0000000000000000000000
+2449:0000000000000000000000000000000000000000000077607760776077607760776000000000000000000000
+244a:00000000000000006600660066003300330033001980198019800cc00cc00cc0066006600660000000000000
+2460:00000f0030c0402046208e109e108610861086108610861086104620402030c00f0000000000000000000000
+2461:00000f0030c040204f20919081908190831086108c10981098105fa0402030c00f0000000000000000000000
+2462:00000f0030c040204f20989080d080d08f1080d080d080d098904f20402030c00f0000000000000000000000
+2463:00000f0030c0402041a0831086108c109990b190bfd08190819041a0402030c00f0000000000000000000000
+2464:00000f0030c040205fa09810981098109f9081908190819099904f20402030c00f0000000000000000000000
+2465:00000f0030c040204f20b0d0b0d0b0108f10b0d0b0d0b0d0b0d04f20402030c00f0000000000000000000000
+2466:00000f0030c040205fa0819083108310861086108c108c1098105820402030c00f0000000000000000000000
+2467:00000f0030c040204f20b0d0b0d0b0d08f10b0d0b0d0b0d0b0d04f20402030c00f0000000000000000000000
+2468:00000f0030c040204f20b0d0b0d0b0d0b0d08fd080d080d0b0d04f20402030c00f0000000000000000000000
+2469:00000f0030c040204020b390b6d0b6d0b6d0b6d0b6d0b6d0b3904020402030c00f0000000000000000000000
+246a:00000f0030c0402040209990bb909990999099909990999099904020402030c00f0000000000000000000000
+246b:00000f0030c040204020b390b6d0b0d0b190b310b610b610b7d04020402030c00f0000000000000000000000
+246c:00000f0030c040204020b390b6d0b0d0b190b190b0d0b6d0b3904020402030c00f0000000000000000000000
+246d:00000f0030c040204020b190b310b610b6d0b6d0b7d0b0d0b0d04020402030c00f0000000000000000000000
+246e:00000f0030c040204020b7d0b610b610b790b0d0b0d0b6d0b3904020402030c00f0000000000000000000000
+246f:00000f0030c040204020b190b310b610b790b6d0b6d0b6d0b3904020402030c00f0000000000000000000000
+2470:00000f0030c040204020b7d0b0d0b0d0b190b190b310b310b3104020402030c00f0000000000000000000000
+2471:00000f0030c040204020b390b6d0b6d0b390b6d0b6d0b6d0b3904020402030c00f0000000000000000000000
+2472:00000f0030c040204020b390b6d0b6d0b6d0b3d0b0d0b190b3104020402030c00f0000000000000000000000
+2473:00000f0030c0402040209890a55085508950895091509150bc904020402030c00f0000000000000000000000
+2474:000000000000402046208e109e10861086108610861086108610462040200000000000000000000000000000
+2475:00000000000040204f20919081908190831086108c10981098105fa040200000000000000000000000000000
+2476:00000000000040204f20989080d080d08f1080d080d080d098904f2040200000000000000000000000000000
+2477:000000000000402041a0831086108c109990b190bfd08190819041a040200000000000000000000000000000
+2478:00000000000040205fa09810981098109f9081908190819099904f2040200000000000000000000000000000
+2479:00000000000040204f20b0d0b0d0b0108f10b0d0b0d0b0d0b0d04f2040200000000000000000000000000000
+247a:00000000000040205fa0819083108310861086108c108c109810582040200000000000000000000000000000
+247b:00000000000040204f20b0d0b0d0b0d08f10b0d0b0d0b0d0b0d04f2040200000000000000000000000000000
+247c:00000000000040204f20b0d0b0d0b0d0b0d08fd080d080d0b0d04f2040200000000000000000000000000000
+247d:00000000000040204020b390b6d0b6d0b6d0b6d0b6d0b6d0b390402040200000000000000000000000000000
+247e:000000000000402040209990bb90999099909990999099909990402040200000000000000000000000000000
+247f:00000000000040204020b390b6d0b0d0b190b310b610b610b7d0402040200000000000000000000000000000
+2480:00000000000040204020b390b6d0b0d0b190b190b0d0b6d0b390402040200000000000000000000000000000
+2481:00000000000040204020b190b310b610b6d0b6d0b7d0b0d0b0d0402040200000000000000000000000000000
+2482:00000000000040204020b7d0b610b610b790b0d0b0d0b6d0b390402040200000000000000000000000000000
+2483:00000000000040204020b190b310b610b790b6d0b6d0b6d0b390402040200000000000000000000000000000
+2484:00000000000040204020b7d0b0d0b0d0b190b190b310b310b310402040200000000000000000000000000000
+2485:00000000000040204020b390b6d0b6d0b390b6d0b6d0b6d0b390402040200000000000000000000000000000
+2486:00000000000040204020b390b6d0b6d0b6d0b3d0b0d0b190b310402040200000000000000000000000000000
+2487:000000000000402040209890a55085508950895091509150bc90402040200000000000000000000000000000
+2488:0000000004000c001c003c006c000c000c000c000c000c000c000c000c000c307fb000000000000000000000
+2489:000000003e007f00c3808180018001800180030006000c00180030006080ffb0ffb000000000000000000000
+248a:000000000f801fc020e04060006000e007c00fc000e000600060406060403fb01f3000000000000000000000
+248b:0000000001800380038005800580098009801180118021803fe07fe0018001b001b000000000000000000000
+248c:000000001f801f802000200040007f00638001c000c000c000c080c0c0c061b03f3000000000000000000000
+248d:0000000007000c00180030003000600067806fc070e060606060606070403fb01f3000000000000000000000
+248e:000000001fe03fe06040004000c0008000800180010001000300020002000660046000000000000000000000
+248f:000000000f00118030c030c030c018800d0006000b00118030c030c030c018b00f3000000000000000000000
+2490:000000000f8011c020e060606060606070e03f601e60006000c000c0018007303c3000000000000000000000
+2491:0000000043004480c840c84048404840484048404840484048404840484044b0e33000000000000000000000
+2492:00000000210021006300e700210021002100210021002100210021002100213073b000000000000000000000
+2493:0000000047004880d040d04040404080408041004100420042004400440048b0efb000000000000000000000
+2494:0000000043004480c840c84040404040408047004080404040404840484044b0e33000000000000000000000
+2495:0000000041004100c200c200440044004800490051005fe04100410041004130e13000000000000000000000
+2496:000000004fc04840c800c800480048004f0040804040404040404840484044b0e33000000000000000000000
+2497:0000000043004480c840c840480048004f0048804840484048404840484044b0e33000000000000000000000
+2498:000000004fe04020c020c0404040408040804100410042004200440044004860e86000000000000000000000
+2499:0000000043004480c840c84048404840448043004480484048404840484044b0e33000000000000000000000
+249a:0000000043004480c840c840484048404840444043c0404040404840484044b0e33000000000000000000000
+249b:00000000610092809440144024402440244024404440444044408440844082b0f93000000000000000000000
+249c:00000000402040208010801080108f9098d090d083d09cd0b0d0b0d0b0d0b9d09ef040204020000000000000
+249d:0000000040205020b010f010b010b390b7d0b8f0b070b070b070b070b870bcd0a79040204020000000000000
+249e:00000000402040208010801080109f90b1d0a0d0e010e010e010e010f050b0d09f9040204020000000000000
+249f:00000000402041e080d080d080d08ed0b3d0a1d0e0d0e0d0e0d0e0d0f1d0bad09cd040204020000000000000
+24a0:0000000040204020801080108010871098d0b070b070bff0b010b01098108c70879040204020000000000000
+24a1:0000000043a044e084d08c108c108c108c109f908c108c108c108c108c108c109e1040204020000000000000
+24a2:00000000402040208010801080108f3099f0b0d0b0d0b0d099909f10b010bfd09ff05060602020201fe00fc0
+24a3:0000000050207020f010b010b010b790b9d0b0d0b0d0b0d0b0d0b0d0b0d0b0d0f9f040204020000000000000
+24a4:00000000402046208610801080109e10861086108610861086108610861086109f9040204020000000000000
+24a5:00000000402041a0819080108010879081908190819081908190819081908190819051a059a01f000e000000
+24a6:000000004020b020f010b010b010b1d0b310b610bc10b810bc10b610b710b390f9f040204020000000000000
+24a7:000000005e2046208610861086108610861086108610861086108610861086109f9040204020000000000000
+24a8:0000000040204020801080108010ddd0eef0e670e670e670e670e670e670e670ef7040204020000000000000
+24a9:0000000040204020801080108010a790f9d0b0d0b0d0b0d0b0d0b0d0b0d0b0d0f9f040204020000000000000
+24aa:000000004020402080108010801087108b9091d0b0d0b0d0b0d0b0d0b8909d108e1040204020000000000000
+24ab:0000000040204020801080108010f710bb90b1d0b0d0b0d0b0d0b0d0b090b910fe1070207020300030007800
+24ac:000000004020402080108010801086708bd091d0b0d0b0d0b0d0b0d0b8d09dd08fd040e040e000c000c001e0
+24ad:0000000040204020801080108010f390b4d0b8d0b010b010b010b010b010b010f81040204020000000000000
+24ae:00000000402040208010801080109fd0b0d0b050b8109e10879081d0a0d0b0d0bf9040204020000000000000
+24af:0000000040204020841084108c10ffd08c108c108c108c108c108c108c308e50879040204020000000000000
+24b0:0000000040204020801080108010f9f0b0d0b0d0b0d0b0d0b0d0b0d0b0d0b9d09e7040204020000000000000
+24b1:0000000040204020801080108010f070e030b050b050989098908d108d108610861040204020000000000000
+24b2:0000000040204020801080108010ff70e630e630e630b750bb50bb5099909990999040204020000000000000
+24b3:0000000040204020801080108010f8f0f050b8909d108e1087108b9091d0a0f0f1f040204020000000000000
+24b4:0000000040204020801080108010f0f0e030b050b050989098908d108d108610861044204c20080078007000
+24b5:0000000040204020801080108010fff0e0f0c1d0839087108e109c10b830f070fff040204020000000000000
+24b6:1f8020404020462086108b108b108910919091909090bfd0a0d0a050c070c070e0f04020402020401f800000
+24b7:1f80204040207f20b090b0d0b0d0b0d0b190bf90b0d0b070b070b070b070b0d0bf904020402020401f800000
+24b8:1f802040402047a088d090509010b010b010b010b010b010b010901098508c9087104020402020401f800000
+24b9:1f80204040207e20b390b190b0d0b0d0b0d0b0d0b0d0b0d0b0d0b0d0b090b310bc104020402020401f800000
+24ba:1f80204040207fe0b050b050b010b010b090bf90b090b010b010b010b030b030fff04020402020401f800000
+24bb:1f80204040207fe0b050b050b010b010b090bf90b090b010b010b010b010b010f8104020402020401f800000
+24bc:1f802040402047a0887090309010b010b010b010b010b1f0b070907098708c7087904020402020401f800000
+24bd:1f8020404020f9f0b0d0b0d0b0d0b0d0b0d0bfd0b0d0b0d0b0d0b0d0b0d0b0d0f9f04020402020401f800000
+24be:1f80204040205fa08610861086108610861086108610861086108610861086109f904020402020401f800000
+24bf:1f80204040205fa086108610861086108610861086108610861086108610861084107820702020401f800000
+24c0:1f80204040207860b0d0b190b310b610bc10bc10be10b710b390b1d0b0f0b070f8304020402020401f800000
+24c1:1f80204040207820b010b010b010b010b010b010b010b010b010b010b030b030fff04020402020401f800000
+24c2:1f80204040206060b0d0b8d0b8d0b8d0ad50ad50ad50a750a650a650a250a250e2d04020402020401f800000
+24c3:1f80204040206060b050b850b850ac50a450a650a650a250a350a1d0a0d0a0d0e0f04020402020401f800000
+24c4:1f80204040204e209390a190a0d0e0d0e0d0e0d0e0d0e0d0e0d0a090b09099108e104020402020401f800000
+24c5:1f80204040207f80b0d0b070b070b070b0d0b790b010b010b010b010b010b010f8104020402020401f800000
+24c6:1f80204040204e209390a190a0d0e0d0e0d0e0d0e0d0e8d0e4d0b290b9909fd08cd04020402020401f800000
+24c7:1f80204040207f00b190b0d0b0d0b0d0b090bf10bc10b610b710b390b1d0b0f0b8704020402020401f800000
+24c8:1f80204040201fe0b070e030e030f010bc109e10879081d080f0c070c070e0d0ff904020402020401f800000
+24c9:1f80204040207fe0c630861086108610861086108610861086108610861086109f904020402020401f800000
+24ca:1f80204040207060b050b050b050b050b050b050b050b050b050b050b8909f108e104020402020401f800000
+24cb:1f802040402060e0e050b090b090b0909910991099108c108e108e108410841084104020402020401f800000
+24cc:1f80204040207ee0e630e630e630f630f750b350b750bbd0bb9099909990999099904020402020401f800000
+24cd:1f80204040207060e030b050b89098908d10861086108b10919091d0a0d0c070e0f04020402020401f800000
+24ce:1f80204040207060e030b050989098908d1086108610861086108610861086108f104020402020401f800000
+24cf:1f80204040207fe0a0d080d08190819083108310861086108c108c1098109830bff04020402020401f800000
+24d0:1f802040402040208010801080108f9098d090d083d09cd0b0d0b0d0b0d0b9d09ef04020402020401f800000
+24d1:1f80204040205020b010f010b010b390b7d0b8f0b070b070b070b070b870bcd0a7904020402020401f800000
+24d2:1f802040402040208010801080109f90b1d0a0d0e010e010e010e010f050b0d09f904020402020401f800000
+24d3:1f802040402041e080d080d080d08ed0b3d0a1d0e0d0e0d0e0d0e0d0f1d0bad09cd04020402020401f800000
+24d4:1f80204040204020801080108010871098d0b070b070bff0b010b01098108c7087904020402020401f800000
+24d5:1f80204043a044e084d08c108c108c108c109f908c108c108c108c108c108c109e104020402020401f800000
+24d6:1f80204040204020801080108f3099f0b0d0b0d0b0d099909f10b010bfd09ff09070a030a0305fe03fc01f80
+24d7:1f80204050207020f010b010b010b790b9d0b0d0b0d0b0d0b0d0b0d0b0d0b0d0f9f04020402020401f800000
+24d8:1f802040402046208610801080109e10861086108610861086108610861086109f904020402020401f800000
+24d9:1f802040402041a0819080108010879081908190819081908190819081908190819051a059a03f401f800000
+24da:1f8020404020b020f010b010b010b1d0b310b610bc10b810bc10b610b710b390f9f04020402020401f800000
+24db:1f8020405e2046208610861086108610861086108610861086108610861086109f904020402020401f800000
+24dc:1f80204040204020801080108010ddd0eef0e670e670e670e670e670e670e670ef704020402020401f800000
+24dd:1f80204040204020801080108010a790f9d0b0d0b0d0b0d0b0d0b0d0b0d0b0d0f9f04020402020401f800000
+24de:1f8020404020402080108010801087108b9091d0b0d0b0d0b0d0b0d0b8909d108e104020402020401f800000
+24df:1f802040402040208010f710bb90b1d0b0d0b0d0b0d0b0d0b090b910be10b010b0107010702030401f800000
+24e0:1f80204040204020801086708bd091d0b0d0b0d0b0d0b0d0b8d09dd08fd080d080d040e040e020c01f800000
+24e1:1f80204040204020801080108010f390b4d0b8d0b010b010b010b010b010b010f8104020402020401f800000
+24e2:1f802040402040208010801080109fd0b0d0b050b8109e10879081d0a0d0b0d0bf904020402020401f800000
+24e3:1f80204040204020841084108c10ffd08c108c108c108c108c108c108c308e5087904020402020401f800000
+24e4:1f80204040204020801080108010f9f0b0d0b0d0b0d0b0d0b0d0b0d0b0d0b9d09e704020402020401f800000
+24e5:1f80204040204020801080108010f070e030b050b050989098908d108d10861086104020402020401f800000
+24e6:1f80204040204020801080108010ff70e630e630e630b750bb50bb509990999099904020402020401f800000
+24e7:1f80204040204020801080108010f8f0f050b8909d108e1087108b9091d0a0f0f1f04020402020401f800000
+24e8:1f802040402040208010f0f0e030b050b050989098908d108d108610861084108c104820782030401f800000
+24e9:1f80204040204020801080108010fff0e0f0c1d0839087108e109c10b830f070fff04020402020401f800000
+24ea:1f80204047204fa0919090d0b0d0b0d0b0d0b0d0b0d0b0d0b0d0b09098909f108e104020402020401f800000
+24eb:00000f003fc07fe07fe0e670c470e670e670e670e670e670e6707fe07fe03fc00f0000000000000000000000
+24ec:00000f003fc07fe07fe0cc70c930cf30ce70ccf0c9f0c9f0c8307fe07fe03fc00f0000000000000000000000
+24ed:00000f003fc07fe07fe0cc70c930cf30ce70ce70cf30c930cc707fe07fe03fc00f0000000000000000000000
+24ee:00000f003fc07fe07fe0ce70ccf0c9f0c930c930c830cf30cf307fe07fe03fc00f0000000000000000000000
+24ef:00000f003fc07fe07fe0c830c9f0c9f0c870cf30cf30c930cc707fe07fe03fc00f0000000000000000000000
+24f0:00000f003fc07fe07fe0ce70ccf0c9f0c870c930c930c930cc707fe07fe03fc00f0000000000000000000000
+24f1:00000f003fc07fe07fe0c830cf30cf30ce70ce70ccf0ccf0ccf07fe07fe03fc00f0000000000000000000000
+24f2:00000f003fc07fe07fe0cc70c930c930cc70c930c930c930cc707fe07fe03fc00f0000000000000000000000
+24f3:00000f003fc07fe07fe0cc70c930c930c930cc30cf30ce70ccf07fe07fe03fc00f0000000000000000000000
+24f4:00000f003fc07fe07fe0ce70b5b0f5b0edb0edb0ddb0ddb086707fe07fe03fc00f0000000000000000000000
+24f5:0f0030c040204f20b0d0402046208e109e1086108610861086108610861046204020b0d04f20402030c00f00
+24f6:0f0030c040204f20b0d040204f20919081908190831086108c10981098105fa04020b0d04f20402030c00f00
+24f7:0f0030c040204f20b0d040204f20989080d080d08f1080d080d080d098904f204020b0d04f20402030c00f00
+24f8:0f0030c040204f20b0d0402041a0831086108c109990b190bfd08190819041a04020b0d04f20402030c00f00
+24f9:0f0030c040204f20b0d040205fa09810981098109f9081908190819099904f204020b0d04f20402030c00f00
+24fa:0f0030c040204f20b0d040204f20b0d0b0d0b0108f10b0d0b0d0b0d0b0d04f204020b0d04f20402030c00f00
+24fb:0f0030c040204f20b0d040205fa0819083108310861086108c108c10981058204020b0d04f20402030c00f00
+24fc:0f0030c040204f20b0d040204f20b0d0b0d0b0d08f10b0d0b0d0b0d0b0d04f204020b0d04f20402030c00f00
+24fd:0f0030c040204f20b0d040204f20b0d0b0d0b0d0b0d08fd080d080d0b0d04f204020b0d04f20402030c00f00
+24fe:0f0030c040204f20b0d040204020b390b6d0b6d0b6d0b6d0b6d0b6d0b39040204020b0d04f20402030c00f00
+24ff:00000f003fc07fe07fe0e070c630cf30cf30cf30cf30c630e0707fe07fe03fc00f0000000000000000000000
2500:0000000000000000000000000000000000000000fff0fff00000000000000000000000000000000000000000
2501:000000000000000000000000000000000000fff0fff0fff0fff0000000000000000000000000000000000000
2502:0600060006000600060006000600060006000600060006000600060006000600060006000600060006000600
2503:0f000f000f000f000f000f000f000f000f000f000f000f000f000f000f000f000f000f000f000f000f000f00
+2504:0000000000000000000000000000000000000000777077700000000000000000000000000000000000000000
+2505:0000000000000000000000000000000000007770777077707770000000000000000000000000000000000000
+2506:0000000006000600060006000000000000000600060006000600000000000000060006000600060000000000
+2507:000000000f000f000f000f000000000000000f000f000f000f000000000000000f000f000f000f0000000000
+2508:00000000000000000000000000000000000000006db06db00000000000000000000000000000000000000000
+2509:0000000000000000000000000000000000006db06db06db06db0000000000000000000000000000000000000
+250a:0000060006000600060000000000060006000600000000000600060006000600000000000600060006000000
+250b:00000f000f000f000f00000000000f000f000f00000000000f000f000f000f00000000000f000f000f000000
250c:000000000000000000000000000000000000000007f007f00600060006000600060006000600060006000600
250d:00000000000000000000000000000000000007f007f007f007f0060006000600060006000600060006000600
250e:00000000000000000000000000000000000000000ff00ff00f000f000f000f000f000f000f000f000f000f00
@@ -464,6 +3000,10 @@
2549:0f000f000f000f000f000f000f000f000f00ff00fff0fff0ff000f000f000f000f000f000f000f000f000f00
254a:0f000f000f000f000f000f000f000f000f000ff0fff0fff00ff00f000f000f000f000f000f000f000f000f00
254b:0f000f000f000f000f000f000f000f000f00fff0fff0fff0fff00f000f000f000f000f000f000f000f000f00
+254c:000000000000000000000000000000000000000079e079e00000000000000000000000000000000000000000
+254d:00000000000000000000000000000000000079e079e079e079e0000000000000000000000000000000000000
+254e:0000000006000600060006000600060006000000000000000000060006000600060006000600060000000000
+254f:000000000f000f000f000f000f000f000f0000000000000000000f000f000f000f000f000f000f0000000000
2550:000000000000000000000000000000000000fff000000000fff0000000000000000000000000000000000000
2551:0900090009000900090009000900090009000900090009000900090009000900090009000900090009000900
2552:00000000000000000000000000000000000007f00600060007f0060006000600060006000600060006000600
@@ -497,8 +3037,1551 @@
256e:0000000000000000000000000000000000000000e000f8001c000c0006000600060006000600060006000600
256f:060006000600060006000600060006000c001c00f800e0000000000000000000000000000000000000000000
2570:060006000600060006000600060006000300038001f000700000000000000000000000000000000000000000
+2571:0010002000200040004000800080010001000200020004000400080008001000100020002000400040008000
+2572:8000400040002000200010001000080008000400040002000200010001000080008000400040002000200010
+2573:8010402040202040204010801080090009000600060006000600090009001080108020402040402040208010
+2574:0000000000000000000000000000000000000000fc00fc000000000000000000000000000000000000000000
+2575:0600060006000600060006000600060006000600060000000000000000000000000000000000000000000000
+2576:000000000000000000000000000000000000000003f003f00000000000000000000000000000000000000000
+2577:0000000000000000000000000000000000000000000006000600060006000600060006000600060006000600
+2578:000000000000000000000000000000000000fc00fc00fc00fc00000000000000000000000000000000000000
+2579:0f000f000f000f000f000f000f000f000f000f000f0000000000000000000000000000000000000000000000
+257a:00000000000000000000000000000000000003f003f003f003f0000000000000000000000000000000000000
+257b:000000000000000000000000000000000000000000000f000f000f000f000f000f000f000f000f000f000f00
+257c:00000000000000000000000000000000000003f0fff0fff003f0000000000000000000000000000000000000
+257d:060006000600060006000600060006000600060006000f000f000f000f000f000f000f000f000f000f000f00
+257e:000000000000000000000000000000000000fc00fff0fff0fc00000000000000000000000000000000000000
+257f:0f000f000f000f000f000f000f000f000f000f000f0006000600060006000600060006000600060006000600
+2580:fff0fff0fff0fff0fff0fff0fff0fff0fff0fff0fff000000000000000000000000000000000000000000000
+2581:0000000000000000000000000000000000000000000000000000000000000000000000000000fff0fff0fff0
+2582:0000000000000000000000000000000000000000000000000000000000000000fff0fff0fff0fff0fff0fff0
+2583:0000000000000000000000000000000000000000000000000000fff0fff0fff0fff0fff0fff0fff0fff0fff0
+2584:00000000000000000000000000000000000000000000fff0fff0fff0fff0fff0fff0fff0fff0fff0fff0fff0
+2585:000000000000000000000000000000000000fff0fff0fff0fff0fff0fff0fff0fff0fff0fff0fff0fff0fff0
+2586:000000000000000000000000fff0fff0fff0fff0fff0fff0fff0fff0fff0fff0fff0fff0fff0fff0fff0fff0
+2587:000000000000fff0fff0fff0fff0fff0fff0fff0fff0fff0fff0fff0fff0fff0fff0fff0fff0fff0fff0fff0
+2588:fff0fff0fff0fff0fff0fff0fff0fff0fff0fff0fff0fff0fff0fff0fff0fff0fff0fff0fff0fff0fff0fff0
+2589:ffc0ffc0ffc0ffc0ffc0ffc0ffc0ffc0ffc0ffc0ffc0ffc0ffc0ffc0ffc0ffc0ffc0ffc0ffc0ffc0ffc0ffc0
+258a:ff80ff80ff80ff80ff80ff80ff80ff80ff80ff80ff80ff80ff80ff80ff80ff80ff80ff80ff80ff80ff80ff80
+258b:fe00fe00fe00fe00fe00fe00fe00fe00fe00fe00fe00fe00fe00fe00fe00fe00fe00fe00fe00fe00fe00fe00
+258c:fc00fc00fc00fc00fc00fc00fc00fc00fc00fc00fc00fc00fc00fc00fc00fc00fc00fc00fc00fc00fc00fc00
+258d:f800f800f800f800f800f800f800f800f800f800f800f800f800f800f800f800f800f800f800f800f800f800
+258e:e000e000e000e000e000e000e000e000e000e000e000e000e000e000e000e000e000e000e000e000e000e000
+258f:c000c000c000c000c000c000c000c000c000c000c000c000c000c000c000c000c000c000c000c000c000c000
+2590:03f003f003f003f003f003f003f003f003f003f003f003f003f003f003f003f003f003f003f003f003f003f0
2591:aaa00000aaa00000aaa00000aaa00000aaa00000aaa00000aaa00000aaa00000aaa00000aaa00000aaa00000
2592:3330ccc03330ccc03330ccc03330ccc03330ccc03330ccc03330ccc03330ccc03330ccc03330ccc03330ccc0
2593:fff0aaa0fff0aaa0fff0aaa0fff0aaa0fff0aaa0fff0aaa0fff0aaa0fff0aaa0fff0aaa0fff0aaa0fff0aaa0
+2594:fff0fff0fff00000000000000000000000000000000000000000000000000000000000000000000000000000
+2595:0030003000300030003000300030003000300030003000300030003000300030003000300030003000300030
+2596:00000000000000000000000000000000000000000000fc00fc00fc00fc00fc00fc00fc00fc00fc00fc00fc00
+2597:0000000000000000000000000000000000000000000003f003f003f003f003f003f003f003f003f003f003f0
+2598:fc00fc00fc00fc00fc00fc00fc00fc00fc00fc00fc0000000000000000000000000000000000000000000000
+2599:fc00fc00fc00fc00fc00fc00fc00fc00fc00fc00fc00fff0fff0fff0fff0fff0fff0fff0fff0fff0fff0fff0
+259a:fc00fc00fc00fc00fc00fc00fc00fc00fc00fc00fc0003f003f003f003f003f003f003f003f003f003f003f0
+259b:fff0fff0fff0fff0fff0fff0fff0fff0fff0fff0fff0fc00fc00fc00fc00fc00fc00fc00fc00fc00fc00fc00
+259c:fff0fff0fff0fff0fff0fff0fff0fff0fff0fff0fff003f003f003f003f003f003f003f003f003f003f003f0
+259d:03f003f003f003f003f003f003f003f003f003f003f000000000000000000000000000000000000000000000
+259e:03f003f003f003f003f003f003f003f003f003f003f0fc00fc00fc00fc00fc00fc00fc00fc00fc00fc00fc00
+259f:03f003f003f003f003f003f003f003f003f003f003f0fff0fff0fff0fff0fff0fff0fff0fff0fff0fff0fff0
+25a0:000000000000000000000000ffe0ffe0ffe0ffe0ffe0ffe0ffe0ffe0ffe0ffe0ffe000000000000000000000
+25a1:000000000000000000000000ffe0802080208020802080208020802080208020ffe000000000000000000000
+25a2:0000000000000000000000007fc08020802080208020802080208020802080207fc000000000000000000000
+25a3:000000000000000000000000ffe0802080209f209f209f209f209f2080208020ffe000000000000000000000
+25a4:000000000000000000000000ffe08020ffe08020ffe08020ffe08020ffe08020ffe000000000000000000000
+25a5:000000000000000000000000ffe0aaa0aaa0aaa0aaa0aaa0aaa0aaa0aaa0aaa0ffe000000000000000000000
+25a6:000000000000000000000000ffe0aaa0ffe0aaa0ffe0aaa0ffe0aaa0ffe0aaa0ffe000000000000000000000
+25a7:000000000000000000000000ffe0c920a4a09260c920a4a09260c920a4a09260ffe000000000000000000000
+25a8:000000000000000000000000ffe09260a4a0c9209260a4a0c9209260a4a0c920ffe000000000000000000000
+25a9:000000000000000000000000ffe0c460aaa09120aaa0c460aaa09120aaa0c460ffe000000000000000000000
+25aa:0000000000000000000000000000000000001f001f001f001f001f0000000000000000000000000000000000
+25ab:0000000000000000000000000000000000001f001100110011001f0000000000000000000000000000000000
+25ac:000000000000000000000000000000000000fff0fff0fff0fff0fff000000000000000000000000000000000
+25ad:000000000000000000000000000000000000fff0801080108010fff000000000000000000000000000000000
+25ae:00001f001f001f001f001f001f001f001f001f001f001f001f001f001f001f001f001f001f001f001f000000
+25af:00001f001100110011001100110011001100110011001100110011001100110011001100110011001f000000
+25b0:0000000000000000000000000000000000001ff03ff07fe0ffc0ff8000000000000000000000000000000000
+25b1:0000000000000000000000000000000000001ff0201040208040ff8000000000000000000000000000000000
+25b2:00000000000000000000060006000f000f001f801f803fc03fc07fe07fe0fff0fff000000000000000000000
+25b3:0000000000000000000006000600090009001080108020402040402040208010fff000000000000000000000
+25b4:0000000000000000000000000000060006000f000f001f801f803fc03fc00000000000000000000000000000
+25b5:000000000000000000000000000006000600090009001080108020403fc00000000000000000000000000000
+25b6:00000000000000000000c000f000fc00ff00ffc0fff0fff0ffc0ff00fc00f000c00000000000000000000000
+25b7:00000000000000000000c000b0008c00830080c08030803080c083008c00b000c00000000000000000000000
+25b8:0000000000000000000000000000000030003c003f003fc03fc03f003c003000000000000000000000000000
+25b9:000000000000000000000000000030002c00230020c020c023002c0030000000000000000000000000000000
+25ba:0000000000000000000000000000e000fc00ff80fff0fff0ff80fc00e0000000000000000000000000000000
+25bb:0000000000000000000000000000e0009c0083808070807083809c00e0000000000000000000000000000000
+25bc:00000000000000000000fff0fff07fe07fe03fc03fc01f801f800f000f000600060000000000000000000000
+25bd:00000000000000000000fff08010402040202040204010801080090009000600060000000000000000000000
+25be:00000000000000000000000000003fc03fc01f801f800f000f00060006000000000000000000000000000000
+25bf:00000000000000000000000000003fc020401080108009000900060006000000000000000000000000000000
+25c0:00000000000000000000003000f003f00ff03ff0fff0fff03ff00ff003f000f0003000000000000000000000
+25c1:00000000000000000000003000d003100c103010c010c01030100c10031000d0003000000000000000000000
+25c2:0000000000000000000000000000000000c003c00fc03fc03fc00fc003c000c0000000000000000000000000
+25c3:000000000000000000000000000000c003400c40304030400c40034000c00000000000000000000000000000
+25c4:0000000000000000000000000000007003f01ff0fff0fff01ff003f000700000000000000000000000000000
+25c5:0000000000000000000000000000007003901c10e010e0101c10039000700000000000000000000000000000
25c6:0000000000000000000006000f001f803fc07fe0fff0fff07fe03fc01f800f00060000000000000000000000
-fffd:000000007fe07fe0606060606060606060606060606060606060606060607fe07fe000000000000000000000
+25c7:0000000000000000000006000900108020404020801080104020204010800900060000000000000000000000
+25c8:0000000000000000000006000900108026404f209f909f904f20264010800900060000000000000000000000
+25c9:000000000000000000001f8020405fa05fa0bfd0bfd0bfd0bfd05fa05fa020401f8000000000000000000000
+25ca:0600060009000900108010802040204040204020801080104020402020402040108010800900090006000600
+25cb:000000000000000000001f8020404020402080108010801080104020402020401f8000000000000000000000
+25cc:0000000000000000000016800000402000008010000000008010000040200000168000000000000000000000
+25cd:000000000000000000001f80294049204920c930c930c930c9304920492029401f8000000000000000000000
+25ce:000000000000000000001f8020404f2050a0a050a050a050a05050a04f2020401f8000000000000000000000
+25cf:000000000000000000001f803fc07fe07fe0fff0fff0fff0fff07fe07fe03fc01f8000000000000000000000
+25d0:000000000000000000001f803c407c207c20fc10fc10fc10fc107c207c203c401f8000000000000000000000
+25d1:000000000000000000001f8023c043e043e083f083f083f083f043e043e023c01f8000000000000000000000
+25d2:000000000000000000001f8020404020402080108010fff0fff07fe07fe03fc01f8000000000000000000000
+25d3:000000000000000000001f803fc07fe07fe0fff0fff0801080104020402020401f8000000000000000000000
+25d4:000000000000000000001f8023c043e043e083f083f0801080104020402020401f8000000000000000000000
+25d5:000000000000000000001f8023c043e043e083f083f0fff0fff07fe07fe03fc01f8000000000000000000000
+25d6:000000000000000000001c003c007c007c00fc00fc00fc00fc007c007c003c001c0000000000000000000000
+25d7:00000000000000000000038003c003e003e003f003f003f003f003e003e003c0038000000000000000000000
+25d8:00000000000000003fe03fe03fe03fe038e030603060306038e03fe03fe03fe03fe000000000000000000000
+25d9:000000000000fff0e070dfb0bfd07fe07fe0fff0fff0fff0fff07fe07fe0bfd0dfb0e070fff0000000000000
+25da:000000000000fff0e070dfb0bfd07fe07fe0fff0fff000000000000000000000000000000000000000000000
+25db:00000000000000000000000000000000000000000000fff0fff07fe07fe0bfd0dfb0e070fff0000000000000
+25dc:000000000000000000001c002000400040008000800000000000000000000000000000000000000000000000
+25dd:0000000000000000000003800040002000200010001000000000000000000000000000000000000000000000
+25de:0000000000000000000000000000000000000000000000100010002000200040038000000000000000000000
+25df:00000000000000000000000000000000000000000000800080004000400020001c0000000000000000000000
+25e0:000000000000000000001f802040402040208010801000000000000000000000000000000000000000000000
+25e1:00000000000000000000000000000000000000000000801080104020402020401f8000000000000000000000
+25e2:0000000000000000000000100030007000f001f003f007f00ff01ff03ff07ff0fff000000000000000000000
+25e3:000000000000000000008000c000e000f000f800fc00fe00ff00ff80ffc0ffe0fff000000000000000000000
+25e4:00000000000000000000fff0ffe0ffc0ff80ff00fe00fc00f800f000e000c000800000000000000000000000
+25e5:00000000000000000000fff07ff03ff01ff00ff007f003f001f000f000700030001000000000000000000000
+25e6:0000000000000000000000000000000007000880088008800700000000000000000000000000000000000000
+25e7:00000000000000000000fff0fc10fc10fc10fc10fc10fc10fc10fc10fc10fc10fff000000000000000000000
+25e8:00000000000000000000fff083f083f083f083f083f083f083f083f083f083f0fff000000000000000000000
+25e9:00000000000000000000fff0fff0ffd0ff90ff10fe10fc10f810f010e010c010fff000000000000000000000
+25ea:00000000000000000000fff08030807080f081f083f087f08ff09ff0bff0fff0fff000000000000000000000
+25eb:00000000000000000000fff08610861086108610861086108610861086108610fff000000000000000000000
+25ec:0000000000000000000006000600090009001080108026402f404f2046208010fff000000000000000000000
+25ed:00000000000000000000060006000d000d001c801c803c403c407c207c20fc10fff000000000000000000000
+25ee:00000000000000000000060006000b000b001380138023c023c043e043e083f0fff000000000000000000000
+25ef:000000000000000000001f8020404020402080108010801080104020402020401f8000000000000000000000
+25f0:00000000000000000000fff08210821082108210fe1080108010801080108010fff000000000000000000000
+25f1:00000000000000000000fff080108010801080108010fe108210821082108210fff000000000000000000000
+25f2:00000000000000000000fff08010801080108010801087f08410841084108410fff000000000000000000000
+25f3:00000000000000000000fff0841084108410841087f080108010801080108010fff000000000000000000000
+25f4:000000000000000000001f802240422042208210fe10801080104020402020401f8000000000000000000000
+25f5:000000000000000000001f8020404020402080108010fe1082104220422022401f8000000000000000000000
+25f6:000000000000000000001f802040402040208010801087f084104420442024401f8000000000000000000000
+25f7:000000000000000000001f80244044204420841087f0801080104020402020401f8000000000000000000000
+25f8:00000000000000000000fff080208040808081008200840088009000a000c000800000000000000000000000
+25f9:00000000000000000000fff04010201010100810041002100110009000500030001000000000000000000000
+25fa:000000000000000000008000c000a00090008800840082008100808080408020fff000000000000000000000
+25fb:0000000000000000000000007fe0402040204020402040204020402040207fe0000000000000000000000000
+25fc:0000000000000000000000007fe07fe07fe07fe07fe07fe07fe07fe07fe07fe0000000000000000000000000
+25fd:00000000000000000000000000000000000000000000ff0000810000810000810000810000810000810000ff00000000000000000000000000000000000000000000
+25fe:00000000000000000000000000000000000000000000ff0000ff0000ff0000ff0000ff0000ff0000ff0000ff00000000000000000000000000000000000000000000
+25ff:0000000000000000000000100030005000900110021004100810101020104010fff000000000000000000000
+2600:000000000000000004008420444020800e001f00df601f000e00208044408420040000000000000000000000
+2601:0000000000000000000000000000000000c019e03de03ff07ff07ff0fff0fff07fe000000000000000000000
+2602:000000001f807fe0fff0fff006000600060006000600060006000600660066003c0000000000000000000000
+2603:1f801080fff01f8026407fe07fe0666030c01f801f803fc079e0fff0f9f0fff079e03fc01f80000000000000
+2604:0000000000000000020002000400040008200840108011002200240008606180960090006000000000000000
+2605:0000000000000000060006000f000f00fff07fe03fc01f800f001f801f8039c030c000000000000000000000
+2606:00000000000000000600060009000900f9f0402020401080090010801680294030c000000000000000000000
+2607:0000008001c0038007000e001c003800700038001c000e00072003e001e001e003e000000000000000000000
+2608:000000000000fff0ffe0c1c0c380c700ce00dc00ce00c700c390c1f0c0f0c0f0c1f000000000000000000000
+2609:00000000000000000e0031804040404080208e208e208e2080204040404031800e0000000000000000000000
+260a:0000000000000600198020404020402080108010402040202040204060609090909060600000000000000000
+260b:0000000000006060909090906060204020404020402080108010402040202040198006000000000000000000
+260c:00000000000000000020004000801d00220041004100410022001c0000000000000000000000000000000000
+260d:000001c00220041004100410022001c002000400380044008200820082004400380000000000000000000000
+260e:000000000000000000003fc07fe0fff0e070d0b01f8039c070e0e070f0f0f9f0fff000000000000000000000
+260f:000000000000000000003fc040209f90a050d0b01f80204046208f1086108010fff000000000000000000000
+2610:00000000000000000000fff08010801080108010801080108010801080108010fff000000000000000000000
+2611:00000000000000000000fff0801080d0819081908310e310b6109e108c108010fff000000000000000000000
+2612:00000000000000000000fff08010a050909089108610861089109090a0508010fff000000000000000000000
+2613:00000000000030c030c0198019800f000f00060006000f000f001980198030c030c000000000000000000000
+2614:00208008208408410410410810000800fe0007ffe00ffff01ffff800180000180000180000180000180000180000180000180000180003180003180001f00000e000
+2615:0000001861801861800c30c00618600618600c30c01861800000007fffc07fffc06000f86000fe3001863001861803fe0c07f807fc0003f800000000000000000000
+2616:0000000000000600198060604020402040208010801080108010801080108010fff000000000000000000000
+2617:00000000000006001f807fe07fe07fe07fe0fff0fff0fff0fff0fff0fff0fff0fff000000000000000000000
+2618:00000000000019801f801f800f00e670f6f079e0f6f0e670060006000c000c000c0000000000000000000000
+2619:000000000000000000100020004006400f203fc07fa0ff10ff107f903f900f20064000000000000000000000
+261a:00000000000000000000000001c007e0ffd0ffd007d007d007d003d003d003d001e000000000000000000000
+261b:00000000000000000000000038007e00bff0bff0be00be00be00bc00bc00bc00780000000000000000000000
+261c:00000000000000000000000001c00620791082107e100410079002100390021001e000000000000000000000
+261d:00000100028002800280028002800e407a40aa20a9a0aa608110802080407f804080ffc0ffc0000000000000
+261e:0000000000000000000000003800460089e0841087e082009e0084009c008400780000000000000000000000
+261f:0000ffc0ffc040807f80804080208110aa60a9a0aa207a400e40028002800280028002800100000000000000
+2620:00003f807fc0ffe0ce60842084207bc071c03f8055407fc00000c060f1e03f800e003f80f1e0c06000000000
+2621:0000000000000000fc00fff003f000f001e003c00f003c007800f000fc00fff003f000000000000000000000
+2622:00000f0030c040206060f0f0f9f0fff0f9f08010861086108f104f205fa03fc00f0000000000000000000000
+2623:0000000000001080204020402040108016800900168079e096900f0006000600090030c00000000000000000
+2624:000000000600fff07fe03fc006007fe086107fe046203fc026401f8026401f8026401f801680060000000000
+2625:000000000f00198030c030c030c0198019800f007fe07fe00600060006000600060006000600060000000000
+2626:00000000060006001f801f80060006007fe07fe006000600060006003e000f0007c006000600060000000000
+2627:000000001fc00c600c300c300c300c600dc00c00ccc06d803f001e003f006d80ccc000000000000000000000
+2628:00000000060006001f801f80060006007fe07fe0060006000600060006000600060006000600060000000000
+2629:0000000000000000000000001f000400040084208420ffe084208420040004001f0000000000000000000000
+262a:00000000000000000e003d8078007040f040f1f0f040f0a0f000700078003d800e0000000000000000000000
+262b:000009000f000000462056a09690b6d0b6d0b6d0b6d0b6d0b6d09f905fa00f003fc000000000000000000000
+262c:0000000006004f209690969096909690cf3060607fe03fc026400f001680264046200f000000000000000000
+262d:00000e00338000c000c0006007600e601f603be031e000e000f033b06e10c000800000000000000000000000
+262e:00000000000000000e00358044404440842084208e209520a4a04440444035800e0000000000000000000000
+262f:00000000000000000f0030c040207020f810ccd0ccd0fe10ff307fe07fe03fc00f0000000000000000000000
+2630:00000000fff0fff0fff0000000000000fff0fff0fff0000000000000fff0fff0fff000000000000000000000
+2631:00000000f9f0f9f0f9f0000000000000fff0fff0fff0000000000000fff0fff0fff000000000000000000000
+2632:00000000fff0fff0fff0000000000000f9f0f9f0f9f0000000000000fff0fff0fff000000000000000000000
+2633:00000000f9f0f9f0f9f0000000000000f9f0f9f0f9f0000000000000fff0fff0fff000000000000000000000
+2634:00000000fff0fff0fff0000000000000fff0fff0fff0000000000000f9f0f9f0f9f000000000000000000000
+2635:00000000f9f0f9f0f9f0000000000000fff0fff0fff0000000000000f9f0f9f0f9f000000000000000000000
+2636:00000000fff0fff0fff0000000000000f9f0f9f0f9f0000000000000f9f0f9f0f9f000000000000000000000
+2637:00000000f9f0f9f0f9f0000000000000f9f0f9f0f9f0000000000000f9f0f9f0f9f000000000000000000000
+2638:00000000000000000000000004005f40248055404e40fbe04e40554024805f40040000000000000000000000
+2639:000000000000000000001f80204040204920891080108f10909050a0402020401f8000000000000000000000
+263a:000000000000000000001f8020404020492089108010a05090904f20402020401f8000000000000000000000
+263b:000000000000000000001f803fc07fe06660e670fff0cf30e67070e07fe03fc01f8000000000000000000000
+263c:000000000000000000000000040084204e4011002080e0e0208011004e408420040000000000000000000000
+263d:000000000000000003800d001200140024002400240024002400140012000d00038000000000000000000000
+263e:00000000000000001c000b000480028002400240024002400240028004800b001c0000000000000000000000
+263f:6060606039c01f803fc070e060606060606070e03fc01f80060006007fe07fe0060006000600060006000000
+2640:000000001f803fc070e060606060606070e03fc01f80060006007fe07fe00600060006000600060000000000
+2641:00000000060006000600060006007fe07fe0060006001f803fc070e060606060606070e03fc01f8000000000
+2642:000000000000000003f001f000f001f03fb07f90e1c0c0c0c0c0c0c0e1c07f803f0000000000000000000000
+2643:00000000600060c030c030c018c018c018c030c030c030c060c0fff0fff000c000c000c000c000c000000000
+2644:00000000000030003000fc00fc00300030c033e03e60383030303060306030c030c000c000c000c000000000
+2645:00000600c630666036c03fc03fc036c06660c63006001f803fc070e060606060606070e03fc01f8000000000
+2646:00008610c630ef70c630c630c630c630666076e03fc00f000600060006001f801f8006000600060000000000
+2647:00007e007f8061c060e06060606060e061c07f007e006000600060006000600060007fe07fe0000000000000
+2680:000000000000000000007ff040104010401040104610461040104010401040107ff000000000000000000000
+2681:000000000000000000007ff0401040d040d040104010401040105810581040107ff000000000000000000000
+2682:000000000000000000007ff0401040d040d040104310431040105810581040107ff000000000000000000000
+2683:000000000000000000007ff0401058d058d0401040104010401058d058d040107ff000000000000000000000
+2684:000000000000000000007ff0401058d058d0401046104610401058d058d040107ff000000000000000000000
+2685:000000000000000000007ff0401058d058d0401058d058d0401058d058d040107ff000000000000000000000
+2686:000000000000000000001f8020404020402080108190819080104020402020401f8000000000000000000000
+2687:000000000000000000001f8020404020402080109990999080104020402020401f8000000000000000000000
+2688:000000000000000000001f803fc07fe07fe0fff0fe70fe70fff07fe07fe03fc01f8000000000000000000000
+2689:000000000000000000001f803fc07fe07fe0fff0e670e670fff07fe07fe03fc01f8000000000000000000000
+268a:000000000000000000000000000000000000000000000000fff0fff0fff00000000000000000000000000000
+268b:000000000000000000000000000000000000000000000000f9f0f9f0f9f00000000000000000000000000000
+268c:000000000000000000000000fff0fff0fff0000000000000fff0fff0fff00000000000000000000000000000
+268d:000000000000000000000000f9f0f9f0f9f0000000000000fff0fff0fff00000000000000000000000000000
+268e:000000000000000000000000fff0fff0fff0000000000000f9f0f9f0f9f00000000000000000000000000000
+268f:000000000000000000000000f9f0f9f0f9f0000000000000f9f0f9f0f9f00000000000000000000000000000
+2690:000000000000000000007fe07fe060606060606060607fe07fe0600060006000600000000000000000000000
+2691:000000000000000000007fe07fe07fe07fe07fe07fe07fe07fe0600060006000600000000000000000000000
+26b2:000000001f803fc070e060606060606070e03fc01f8006000600060006000600060006000600060000000000
+26b3:000000001f803fc070e000600060006000e007c00780060006007fe07fe00600060006000600060000000000
+26b4:00000f001f8039c070e0e070c030e07070e039c01f800f00060006007fe07fe0060006000600060000000000
+26b5:00000600c630666036c01f80fff0fff01f8036c06660c630060006007fe07fe0060006000600060000000000
+26b6:00000000060006000600060006000600000070e070e019800f000600e070f0f039c01f800f00060000000000
+26b7:000000000630066006c0078006c006600630060006000f003fc06060c030c03060603fc00f00000000000000
+2700:000000000000000000004000a010b870bdc0478005004780bdc0b870a0104000000000000000000000000000
+2701:0000000000000000000000004000a000a000600030007fc0bff0ac0046000000000000000000000000000000
+2702:000000000000000000004000a010b870bdc0478005004780bdc0b870a0104000000000000000000000000000
+2703:0000000000000000000000004600ac00bff07fc030006000a000a00040000000000000000000000000000000
+2704:000000000000000000004000a010b870bdc0478005004780bdc0b870a0104000000000000000000000000000
+2705:0000000000000000c0000120000110000220000220000440020440050880088880045100022100010200008200004400002400001800000000000000000000000000
+2706:00000f0030c040204da09d909c1098109810981098109c109d904da0502030c00f0000000000000000000000
+2707:00000f003fc04f204f208f108f108f109990bfd0fff0f9f0f0f06060402030c00f0000000000000000000000
+2708:00001000180018000e000e008780c780ffe0fff0ffe0c78087800e000e001800180010000000000000000000
+2709:000000000000fff08010c030a05090908f109f909f908f109090a050c0308010fff000000000000000000000
+270a:00000000000000780003cf001e4900124900124900124900124fc01250301fe010102008101e081000081000100800200601c001fe00000000000000000000000000
+270b:000000003c0001e7800124800724800924800924800924e009249009249009249009001008001008001008002008002004004003008000ff00000000000000000000
+270c:0000000000001ce014a014a00aa00aa005205420a820a9f0aa108010802060c01f0000000000000000000000
+270d:00000000000000000030007000e001c01f8027004ef09c10bc107010eff08000000000000000000000000000
+270e:0000000000000000000018003c007a00f100e88044402220111008b0047002f001f000000000000000000000
+270f:0000000000000000000000000000ff80c040c060fff0c060c040ff8000000000000000000000000000000000
+2710:0000000000000000000001f002f0047008b0111022204440e880f1007a003c00180000000000000000000000
+2711:0000000000000000000000000000e700a880a840b74087f0bf40a840a880e700000000000000000000000000
+2712:0000000000000000000000000000e700ef80efc0fcf0f000fcf0efc0ef80e700000000000000000000000000
+2713:0000000000000020002000400040008000804100410022002200140014000800080000000000000000000000
+2714:0000000000000070007000e000e001c001c0e380e380770077001e001e000c000c0000000000000000000000
+2715:0000000000000000000000004020204010800900060006000900108020404020000000000000000000000000
+2716:000000000000000000000000606070e039c01f800f000f001f8039c070e06060000000000000000000000000
+2717:0000000000000000000000000010102010400880070006000900108020402000000000000000000000000000
+2718:000000000000000000000000003038e039c01f800f001f003b8071c0e0e0e000000000000000000000000000
+2719:00001f801080168016801680f6f08610bfd0bfd08610f6f016801680168010801f8000000000000000000000
+271a:00001f801f801f801f801f80fff0fff0fff0fff0fff0fff01f801f801f801f801f8000000000000000000000
+271b:000000000000060006000600060006000600f9f0f9f006000600060006000600060000000000000000000000
+271c:0000000000000f000f000f000f000f00f0f0f0f0f0f0f0f00f000f000f000f000f0000000000000000000000
+271d:000000000600060006007fe07fe0060006000600060006000600060006000600060000000000000000000000
+271e:00000f000980098079e04030403079f03980098009800980098009800980098009800f800780000000000000
+271f:1f8010801680f6f08610bfd0bfd08610f6f01680168016801680168016801680168010801f80000000000000
+2720:0000000000000000000000003f800e008e208420e4e0ffe0e4e084208e200e003f8000000000000000000000
+2721:0000000000000000060006000900fff0891050a0204050a08910fff009000600060000000000000000000000
+2722:00000000000000000000000004000e000e00040064c0ffe064c004000e000e00040000000000000000000000
+2723:0000000000000000000000000e000e000e000400e4e0ffe0e4e004000e000e000e0000000000000000000000
+2724:0000000000000000000000000e001f001f006ec0f5e0ffe0f5e06ec01f001f000e0000000000000000000000
+2725:00000000000000000000000004000e001f00248064c0ffe064c024801f000e00040000000000000000000000
+2726:00000000000000000000000004000e000e001f007fc0ffe07fc01f000e000e00040000000000000000000000
+2727:00000000000000000000000004000a000a00110060c0802060c011000a000a00040000000000000000000000
+2728:00000000402000e0500040500400880a03060a04013183064040883180500a20500a202004d8001021101020a06c804011c0a0108110000000000000000000000000
+2729:00000000000000000000000004000e000a001b007bc0c0607bc01b000a000e00040000000000000000000000
+272a:0000000000000000000000000e003b807bc071c0e0e08020e0e071c07bc03b800e0000000000000000000000
+272b:00000000000000000000000004000e000e00110060c0e0e060c011000e000e00040000000000000000000000
+272c:00000000000000000000000004000a000a0011006ec08e206ec011000a000a00040000000000000000000000
+272d:00000000000000000000000004000a000a00150064c09f2064c015000a000a00040000000000000000000000
+272e:00000000000000000000000004000a000a0015006ec09f206ec015000a000a00040000000000000000000000
+272f:0000000000000000000006000b000b00138063e083f0fc107c601c800d000d00060000000000000000000000
+2730:00000000000000000000000007000b800b8011c060f0803060f011c00b800b80070000000000000000000000
+2731:000000000e000e00ce60eee0ffe07fc03f801f003f807fc0ffe0eee0ce600e000e0000000000000000000000
+2732:000000000e000e00ce60eee0fbe071c031801100318071c0fbe0eee0ce600e000e0000000000000000000000
+2733:00000000000000000000000004004440248015000e00ffe00e00150024804440040000000000000000000000
+2734:0000000000000000000000000400444064c035801f00ffe01f00358064c04440040000000000000000000000
+2735:0000000000000000000000000600464066c03780ff00ffe01fe03d806cc04c400c0000000000000000000000
+2736:000000000000000000000000040044406ec03f801f000e001f003f806ec04440040000000000000000000000
+2737:00000000000000000000108010801980fff01f80060006001f80fff019801080108000000000000000000000
+2738:00000000000000000000108019801f80fff03fc00f000f003fc0fff01f801980108000000000000000000000
+2739:0000000000000000000000002480150095207fc01f00ffe01f007fc095201500248000000000000000000000
+273a:000000000000000000000000a4a01500952075c00e00ffe00e0075c095201500a4a000000000000000000000
+273b:0000000000000000060066606f603fc000000f000f0000001f803fc06f606660060000000000000000000000
+273c:0000000000000000060066606f603fc01f801080108010801f803fc06f606660060000000000000000000000
+273d:0000000000000000000006006660ef707fe03fc01f801f803fc07fe0ef706660060000000000000000000000
+273e:000000000000000000000f006660e97079e039c01f80168026404f208f1066600f0000000000000000000000
+273f:00000000000000000e001f001f001f006ec0f1e0f1e0f1e03b807fc07fc07fc03b8000000000000000000000
+2740:00000000000000000e001100110071c08e209f209f20ffe03f804440444044403b8000000000000000000000
+2741:0000000000000000000000000e00644034c015808020f1e080203500658044c00e0000000000000000000000
+2742:0000000000000000000000000e003b805b406ec0fbe09120fbe06ec05b403b800e0000000000000000000000
+2743:000000000000000000000e000a00eee0a4a0e4e01f001f00e4e0a4a0eee00a000e0000000000000000000000
+2744:000000000000000000000a000a002e802480e4e01f001f00e4e024802e800a000a0000000000000000000000
+2745:0000000000000000060006000f00fff0f9f070e0204070e0f9f0fff00f000600060000000000000000000000
+2746:0000000000000000090006000f005fa0b9d070e0204070e0b9d05fa00f000600090000000000000000000000
+2747:0000000000000000000000008e204e402e800400e4e0ffe0e4e004002e804e408e2000000000000000000000
+2748:000000000000000000008f105fa00f004620e670fff0fff0e67046200f005fa08f1000000000000000000000
+2749:000000000000000000000e000e00eee0e4e0e4e01f001f00e4e0e4e0eee00e000e0000000000000000000000
+274a:00000000000000000000000084204440248000000400eee00400000024804440842000000000000000000000
+274b:000000000000000000008610c630666036c01f80fff0fff01f8036c06660c630861000000000000000000000
+274c:0000000000000000000000000000000000000100800381c001c38000e700007e00003c00007e0000e70001c3800381c0010080000000000000000000000000000000
+274d:000000000000000000000f0033c040e040e0807080708070807040e040e033c00f0000000000000000000000
+274e:00000000000000000000000007ffe006ff60047e20063c600718e00781e007c3e007c3e00781e00718e0063c60047e2006ff6007ffe0000000000000000000000000
+274f:00000000000000000000ffc08040804080708070807080708070fff03ff03ff0000000000000000000000000
+2750:0000000000000000000000003ff03ff0fff08070807080708070807080408040ffc000000000000000000000
+2751:00000000000000000000ffc080608070807080708070807080708070fff07ff03ff000000000000000000000
+2752:000000000000000000003ff07ff0fff080708070807080708070807080708060ffc000000000000000000000
+2753:00000000000003fe000fff000fff800c1f80000f80000f80000f80000f80001f00003e00007c00007c00000000000000007c00007c00007c00007c00000000000000
+2754:00000000000007fe0008010009f0800f1880000880000880000880000880001100002200004400007c00000000000000007c00004400004400007c00000000000000
+2755:000000000000007c00004400004400004400004400004400004400004400004400004400004400007c00000000000000007c00004400004400007c00000000000000
+2756:0000000000000000020007000f800700124038e07df038e0124007000f800700020000000000000000000000
+2757:00000000000000ff0000ff0000ff0000ff0000ff0000ff0000ff0000ff0000ff0000ff0000ff00000000001800007e0000ff00007e00001800000000000000000000
+2758:0000000006000600060006000600060006000600060006000600060006000600060000000000000000000000
+2759:000000000f000f000f000f000f000f000f000f000f000f000f000f000f000f000f0000000000000000000000
+275a:000000001f801f801f801f801f801f801f801f801f801f801f801f801f801f801f8000000000000000000000
+275b:000007000800100016001f001f001f000e000000000000000000000000000000000000000000000000000000
+275c:00000e001f001f001f000d00010002001c000000000000000000000000000000000000000000000000000000
+275d:0000387040808100b160f9f0f9f0f9f070e00000000000000000000000000000000000000000000000000000
+275e:000070e0f9f0f9f0f9f068d008101020e1c00000000000000000000000000000000000000000000000000000
+275f:00000000000000000000000000000000000000000000000000000e001f001f001f000d00010002001c000000
+2760:000000000000000000000000000000000000000000000000000071c0fbe0fbe0fbe069a008201040e3800000
+2761:0000004000403ff07e407e40fe40fe40fe407e407e403e400fc0004000403c407c40608031000e0000000000
+2762:00007fc0ffe0ffe0ffe0ffe0ffe07fc03f801f000e00040000000e001f001f000e0000000000000000000000
+2763:0000000071c0fbe0ffe0ffe0ffe0ffe07fc03f801f000e0000000e001f001f000e0000000000000000000000
+2764:0000000000000000000070e0f9f0fff0fff0fff0fff07fe03fc01f800f000600060000000000000000000000
+2765:000000000000000000003c007e00ff00ff807fc03ff03ff07fc0ff80ff007e003c0000000000000000000000
+2766:000000001c1063b0c1608200040033007f80ffc0ffc0ffc07f803f001e200c60038000000000000000000000
+2767:000000000000000080004000200026004f003fc05fe08ff08ff09fe09fc04f00260000000000000000000000
+2768:0000000001c007000e001e001c003c003c003c003c003c001c001e000f00070001c000000000000000000000
+2769:0000000038000e0007000780038003c003c003c003c003c0038007800f000e00380000000000000000000000
+276a:0000000003c0078007800f000f000f000f000f000f000f000f000f000780078003c000000000000000000000
+276b:000000003c001e001e000f000f000f000f000f000f000f000f000f001e001e003c0000000000000000000000
+276c:000000000700070007000e000e000e001c001c001c000e000e000e0007000700070000000000000000000000
+276d:000000000e000e000e000700070007000380038003800700070007000e000e000e0000000000000000000000
+276e:0000000000c001c003c007800f001e003c0078003c001e000f00078003c001c000c000000000000000000000
+276f:000000006000700078003c001e000f00078003c007800f001e003c0078007000600000000000000000000000
+2770:000000000780078007800f000f000f001e001e001e000f000f000f0007800780078000000000000000000000
+2771:000000001e001e001e000f000f000f000780078007800f000f000f001e001e001e0000000000000000000000
+2772:000000000100020004000c000c000c000c000c000c000c000c000c000c000c000c0004000200010000000000
+2773:0000000008000400020003000300030003000300030003000300030003000300030002000400080000000000
+2774:0000000003c0078007800f000f000f001e003c001e000f000f000f000780078003c000000000000000000000
+2775:000000003c001e001e000f000f000f00078003c007800f000f000f001e001e003c0000000000000000000000
+2776:00000f003fc07fe079e0f1f0e1f0f9f0f9f0f9f0f9f0f9f0f9f060607fe03fc00f0000000000000000000000
+2777:00000f003fc07fe070e0cf30df30fe70fcf0f9f0f3f0e7f0cfb040207fe03fc00f0000000000000000000000
+2778:00000f003fc07fe070e0ce30df30fe30f070fe30ff30df30ce3070e07fe03fc00f0000000000000000000000
+2779:00000f003fc07fe07e60fcf0f9f0f3f0e670ce70c030fe70fe707c207fe03fc00f0000000000000000000000
+277a:00000f003fc07fe04020cfb0cff0cff0e0f0fe30ff30df30cf3060e07fe03fc00f0000000000000000000000
+277b:00000f003fc07fe070e0c630cf30cff0c0f0ce30cf30cf30c63070e07fe03fc00f0000000000000000000000
+277c:00000f003fc07fe04020de70fcf0fcf0f9f0f9f0f3f0f3f0e7f067e07fe03fc00f0000000000000000000000
+277d:00000f003fc07fe06060c630cf30cf30e070c630cf30cf30cf3060607fe03fc00f0000000000000000000000
+277e:00000f003fc07fe06060c630cf30cf30c630e030ff30cf30cf3060607fe03fc00f0000000000000000000000
+277f:00000f003fc07fe04c2089908990c990c990c990c990c990c99084207fe03fc00f0000000000000000000000
+2780:00000f0030c0402046208e109e108610861086108610861086104620402030c00f0000000000000000000000
+2781:00000f0030c040204f20919081908190831086108c10981098105fa0402030c00f0000000000000000000000
+2782:00000f0030c040204f20989080d080d08f1080d080d080d098904f20402030c00f0000000000000000000000
+2783:00000f0030c0402041a0831086108c109990b190bfd08190819041a0402030c00f0000000000000000000000
+2784:00000f0030c040205fa09810981098109f9081908190819099904f20402030c00f0000000000000000000000
+2785:00000f0030c040204f20b0d0b0d0b0108f10b0d0b0d0b0d0b0d04f20402030c00f0000000000000000000000
+2786:00000f0030c040205fa0819083108310861086108c108c1098105820402030c00f0000000000000000000000
+2787:00000f0030c040204f20b0d0b0d0b0d08f10b0d0b0d0b0d0b0d04f20402030c00f0000000000000000000000
+2788:00000f0030c040204f20b0d0b0d0b0d0b0d08fd080d080d0b0d04f20402030c00f0000000000000000000000
+2789:00000f0030c040204020b390b6d0b6d0b6d0b6d0b6d0b6d0b3904020402030c00f0000000000000000000000
+278a:00000f003fc07fe079e0e1f0f9f0f9f0f9f0f9f0f9f0f9f0f9f079e07fe03fc00f0000000000000000000000
+278b:00000f003fc07fe070e0cf30ff30fe70fcf0f9f0f3f0e7f0cff040207fe03fc00f0000000000000000000000
+278c:00000f003fc07fe070e0cf30ff30ff30f0f0ff30ff30ff30cf3070e07fe03fc00f0000000000000000000000
+278d:00000f003fc07fe07e60fcf0f9f0f3f0e670ce70c030fe70fe707e607fe03fc00f0000000000000000000000
+278e:00000f003fc07fe04020cff0cff0cff0c0f0ff30ff30ff30ff3040f07fe03fc00f0000000000000000000000
+278f:00000f003fc07fe070e0cf30cf30cff0c0f0cf30cf30cf30cf3070e07fe03fc00f0000000000000000000000
+2790:00000f003fc07fe04060fe70fcf0fcf0f9f0f9f0f3f0f3f0e7f067e07fe03fc00f0000000000000000000000
+2791:00000f003fc07fe070e0cf30cf30cf30f0f0cf30cf30cf30cf3070e07fe03fc00f0000000000000000000000
+2792:00000f003fc07fe070e0cf30cf30cf30cf30f030ff30cf30cf3070e07fe03fc00f0000000000000000000000
+2793:00000f003fc07fe04c2089908990c990c990c990c990c990c9904c207fe03fc00f0000000000000000000000
+2794:000000000000000000001e000f00078003c0ffe0fff0fff0ffe003c007800f001e0000000000000000000000
+2795:000000000000000000000000000000003c00003c00003c00003c0001ff8001ff8001ff8001ff80003c00003c00003c00003c00000000000000000000000000000000
+2796:00000000000000000000000000000000000000000000000000000001ff8001ff8001ff8001ff80000000000000000000000000000000000000000000000000000000
+2797:000000003c00003c00003c00003c0000000000000001ff8001ff8001ff8001ff80000000000000003c00003c00003c00003c00000000000000000000000000000000
+2798:0000000000000000000020007000f8007c003e001f000f9007f003f001f001f003f000000000000000000000
+2799:000000000000000000000000020003000380ffc0ffe0fff0ffe0ffc003800300020000000000000000000000
+279a:0000000000000000000003f001f001f003f007f00f901f003e007c00f8007000200000000000000000000000
+279b:000000000000000000000000000000000c000f0003c0fff003c00f000c000000000000000000000000000000
+279c:0000000000000000000006000f00078003c07fe0fff0fff07fe003c007800f00060000000000000000000000
+279d:00000000000000000000000000000100018001c001e0fff001e001c001800100000000000000000000000000
+279e:00000000000000000000000000000100018001c0ffe0fff0ffe001c001800100000000000000000000000000
+279f:00000000000000000000000000000100018001c0b7e0b7f0b7e001c001800100000000000000000000000000
+27a0:000000000000000000000000020003000380b7c0b7e0b7f0b7e0b7c003800300020000000000000000000000
+27a1:000000000000000000000000000001000180ffc0ffe0fff0ffe0ffc001800100000000000000000000000000
+27a2:000000000000000000000000c000b0004c00230010c00ff01fc03f007c00f000c00000000000000000000000
+27a3:000000000000000000000000c000f0007c003f001fc00ff010c023004c00b000c00000000000000000000000
+27a4:000000000000000000000000c000f0007c003f001fc00ff01fc03f007c00f000c00000000000000000000000
+27a5:00000000000000000000000000008100c180ffc0ffe0fff07fe03fc001800100000000000000000000000000
+27a6:0000000000000000000000000000010001803fc07fe0fff0ffe0ffc0c1808100000000000000000000000000
+27a7:0000000000000000000001800180ffc0ffc0ffe0ffe0fff0ffe0ffe0ffc0ffc0018001800000000000000000
+27a8:00000000000000000000000001000100ff80ff80ffc0fff0ffc0ff80ff800100010000000000000000000000
+27a9:000000000000000000000000000007000780fdc080e0807080e0fdc007800700000000000000000000000000
+27aa:00000000000000000000000000000f000e80fe40e020e010e020fe400e800f00000000000000000000000000
+27ab:0000000000000000000000000000004001c01e20202040108070f1f0f7e0ff803e0038000000000000000000
+27ac:000000000000000000000000000038003e00ff80f7e0f1f08070401020201e2001c000400000000000000000
+27ad:000000000000000000000000000003000280fe40802080108030fe707ee03fc0038003000000000000000000
+27ae:0000000000000000000000000000030003803fc07ee0fe70803080108020fe40028003000000000000000000
+27af:000000000000000000000000000003000280fe40402020104030fe707ee03fc0038003000000000000000000
+27b0:000000000000000000000000ff001f01fcf0003f0000ffc00303f00c00f81c003c38001c38001c3c00381f00300fc0c003ff00000000000000000000000000000000
+27b1:0000000000000000000000000000030003803fc07ee0fe70403020104020fe40028003000000000000000000
+27b2:00000f003fc07de07ce0fc70003000100000000000100030fc707ce07de03fc00f0000000000000000000000
+27b3:00000000000000000000000000000000f080a8c054e02bf054e0a8c0f0800000000000000000000000000000
+27b4:0000000000000000000020003000d8006c0036001b000d10071000b0007000f003f000000000000000000000
+27b5:000000000000000000000000000000005080a8c054e003f054e0a8c050800000000000000000000000000000
+27b6:0000000000000000000003f000f0007000b007100d101b0036006c00d8003000200000000000000000000000
+27b7:0000000000000000000030003800dc00fe007f003f001f100f1000b0007000f003f000000000000000000000
+27b8:00000000000000000000000000000000f080f8c07ce01ff07ce0f8c0f0800000000000000000000000000000
+27b9:0000000000000000000003f000f0007000b00f101f103f007f00fe00dc003800300000000000000000000000
+27ba:000000000000000000000000000000006040f8c0fce0fff0fce0f8c060400000000000000000000000000000
+27bb:00000000000000000000000000006000f040fcc0fce0fff0fce0fcc0f8406000000000000000000000000000
+27bc:0000000000000000000000000000e00078403c601ff01ff03c607840e0000000000000000000000000000000
+27bd:000000000000000000000000e000f8007c403e601ff01ff03e607c40f000e000000000000000000000000000
+27be:000000000000000000001200090004800240ff2000100010ff20024004800900120000000000000000000000
+27bf:000000000000000000000000f03f030ec0ec0700700f80f811c11c20e20e6066066066066066066066067047043883881f01f0000000000000000000000000000000
+27c0:00000000000000000000000080208040808081008200840088009000a000c000ffe000000000000000000000
+27c1:000000000000000004000a000a0011001100248024804a404a409f208020ffe0000000000000000000000000
+27c2:0000000000000000000000000000000006000600060006000600060006007fe07fe000000000000000000000
+27c3:0000000000000000000007e01fe0380060c06120612060c038001fe007e00000000000000000000000000000
+27c4:000000000000000000007e007f8001c0306048604860306001c07f807e000000000000000000000000000000
+27c5:000000001c00660063006300030003000600060006000c000c000c000c000c000c000c000e00070001e00000
+27c6:00000000038006600c600c600c000c00060006000600030003000300030003000300030007000e0078000000
+27c7:00000000000000000000000000006660666030c030c0198019800f000f000600060000000000000000000000
+27c8:00000000000000000000c0f0c3f0c7006c006c006c006c00370033f030f00000000000000000000000000000
+27c9:00000000000000000000f030fc300e3003600360036003600ec0fcc0f0c00000000000000000000000000000
+27ca:0000000000000600060006000600060006003fc0060006000600060006000600060000000000000000000000
+27cb:000000000000000000100030006000c00180030006000c00180030006000c000800000000000000000000000
+27cc:00003ff03ff018001c000c000e00060006000600060006000e000c001c001800300000000000000000000000
+27cd:00000000000000008000c0006000300018000c0006000300018000c000600030001000000000000000000000
+27ce:000000000000000000000000fff0861086108f108f1099909990b0d0b0d0e070e070fff00000000000000000
+27cf:000000000000000000000000fff0e070e070b0d0b0d0999099908f108f1086108610fff00000000000000000
+27d0:0000000000000000000006000900108020404020861086104020204010800900060000000000000000000000
+27d1:0000000000000000000000000000060006000f000f001980198030c030c06660666000000000000000000000
+27d2:000000000000000000000000000000006660666066606660666036c03fc00f00000000000000000000000000
+27d3:000000000000000000000030003000300030003000300330033000300030fff0fff000000000000000000000
+27d4:00000000000000000000fff0fff0c000c000cc00cc00c000c000c000c000c000c00000000000000000000000
+27d5:0000000000000000000000000000e01030302850249023102310249028503030e01000000000000000000000
+27d6:00000000000000000000000000008070c0c0a14092408c408c409240a140c0c0807000000000000000000000
+27d7:0000000000000000000000000000e070204030c0294026402640294030c02040e07000000000000000000000
+27d8:0000000000000600060006000600060006000600060006000600060006000600060006007fe07fe000000000
+27d9:0000000000007fe07fe006000600060006000600060006000600060006000600060006000600060000000000
+27da:00000000000000000000000019801980f9f0f9f019801980f9f0f9f019801980000000000000000000000000
+27db:0000000000000000000000001980198019801980f9f0f9f01980198019801980000000000000000000000000
+27dc:0000000000000000000000000000200050008fe08fe050002000000000000000000000000000000000000000
+27dd:000000000000000000000000c000c000c000fff0fff0c000c000c00000000000000000000000000000000000
+27de:000000000000000000000000003000300030fff0fff000300030003000000000000000000000000000000000
+27df:000000000f0010801080108010800f000600060006000600060006000600fff0fff000000000000000000000
+27e0:0600060009000900108010802040204040204020fff0fff04020402020402040108010800900090006000600
+27e1:00000000000000000000000004000a000a00110060c0802060c011000a000a00040000000000000000000000
+27e2:00000000000000000000000002000500050008803060e0103060088005000500020000000000000000000000
+27e3:00000000000000000000000004000a000a00110060c0807060c011000a000a00040000000000000000000000
+27e4:00000000000000000000000000000ff008100810f810f810081008100ff00000000000000000000000000000
+27e5:0000000000000000000000000000ff008100810081f081f081008100ff000000000000000000000000000000
+27e6:000000003fc03fc0330033003300330033003300330033003300330033003300330033003fc03fc000000000
+27e7:000000003fc03fc00cc00cc00cc00cc00cc00cc00cc00cc00cc00cc00cc00cc00cc00cc03fc03fc000000000
+27e8:000000000180018003000300060006000c000c00180018000c000c0006000600030003000180018000000000
+27e9:00000000180018000c000c0006000600030003000180018003000300060006000c000c001800180000000000
+27ea:00000000066006600cc00cc019801980330033006600660033003300198019800cc00cc00660066000000000
+27eb:000000006600660033003300198019800cc00cc0066006600cc00cc019801980330033006600660000000000
+27ec:0000000001000300050009000900090009000900090009000900090009000900090005000300010000000000
+27ed:0000000008000c000a000900090009000900090009000900090009000900090009000a000c00080000000000
+27ee:000000000200040004000c000c000c000c000c000c000c000c000c000c000c000c0004000400020000000000
+27ef:0000000008000400040006000600060006000600060006000600060006000600060004000400080000000000
+27f0:000006000900198029404920c930492049204920492049204920492049204920492000000000000000000000
+27f1:00004920492049204920492049204920492049204920c9304920294019800900060000000000000000000000
+27f2:000000000000000003800fe00c6018309930db307e303c30003018300c600fe0038000000000000000000000
+27f3:00000000000000001c007f006300c180c990cdb0c7e0c3c0c000c18063007f001c0000000000000000000000
+27f4:0000000000000000000000003800d68092409220fff092209240d68038000000000000000000000000000000
+27f5:000000000000000000000000180030006000fff0fff060003000180000000000000000000000000000000000
+27f6:000000000000000000000000018000c00060fff0fff0006000c0018000000000000000000000000000000000
+27f7:000000000000000000000000198030c06060fff0fff0606030c0198000000000000000000000000000000000
+27f8:00000000000000000000300030006ff06ff0c000c0006ff06ff0300030000000000000000000000000000000
+27f9:0000000000000000000000c000c0ff60ff6000300030ff60ff6000c000c00000000000000000000000000000
+27fa:0000000000000000000030c030c06f606f60c030c0306f606f6030c030c00000000000000000000000000000
+27fb:000000000000000000000000183030306030fff0fff060303030183000000000000000000000000000000000
+27fc:000000000000000000000000c180c0c0c060fff0fff0c060c0c0c18000000000000000000000000000000000
+27fd:00000000000000000000303030306ff06ff0c030c0306ff06ff0303030300000000000000000000000000000
+27fe:00000000000000000000c0c0c0c0ff60ff60c030c030ff60ff60c0c0c0c00000000000000000000000000000
+27ff:000000000000000000000000018000c0106028b04530826000c0018000000000000000000000000000000000
+2800:0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+2801:0000000000003800380038000000000000000000000000000000000000000000000000000000000000000000
+2802:0000000000000000000000000000000038003800380000000000000000000000000000000000000000000000
+2803:0000000000003800380038000000000038003800380000000000000000000000000000000000000000000000
+2804:0000000000000000000000000000000000000000000000000000380038003800000000000000000000000000
+2805:0000000000003800380038000000000038003800380000000000000000000000000000000000000000000000
+2806:0000000000003800380038000000000000000000000000000000380038003800000000000000000000000000
+2807:0000000000003800380038000000000038003800380000000000380038003800000000000000000000000000
+2808:00000000000001c001c001c00000000000000000000000000000000000000000000000000000000000000000
+2809:00000000000039c039c039c00000000000000000000000000000000000000000000000000000000000000000
+280a:00000000000001c001c001c00000000038003800380000000000000000000000000000000000000000000000
+280b:00000000000039c039c039c00000000038003800380000000000000000000000000000000000000000000000
+280c:00000000000001c001c001c00000000000000000000000000000380038003800000000000000000000000000
+280d:00000000000039c039c039c00000000000000000000000000000380038003800000000000000000000000000
+280e:00000000000001c001c001c00000000038003800380000000000380038003800000000000000000000000000
+280f:00000000000039c039c039c00000000038003800380000000000380038003800000000000000000000000000
+2810:0000000000000000000000000000000001c001c001c000000000000000000000000000000000000000000000
+2811:0000000000003800380038000000000001c001c001c000000000000000000000000000000000000000000000
+2812:0000000000000000000000000000000039c039c039c000000000000000000000000000000000000000000000
+2813:0000000000003800380038000000000039c039c039c000000000000000000000000000000000000000000000
+2814:0000000000000000000000000000000001c001c001c000000000380038003800000000000000000000000000
+2815:0000000000003800380038000000000001c001c001c000000000380038003800000000000000000000000000
+2816:0000000000000000000000000000000039c039c039c000000000380038003800000000000000000000000000
+2817:0000000000003800380038000000000039c039c039c000000000380038003800000000000000000000000000
+2818:00000000000001c001c001c00000000001c001c001c000000000000000000000000000000000000000000000
+2819:00000000000039c039c039c00000000001c001c001c000000000000000000000000000000000000000000000
+281a:00000000000001c001c001c00000000039c039c039c000000000000000000000000000000000000000000000
+281b:00000000000039c039c039c00000000039c039c039c000000000000000000000000000000000000000000000
+281c:00000000000001c001c001c00000000001c001c001c000000000380038003800000000000000000000000000
+281d:00000000000039c039c039c00000000001c001c001c000000000380038003800000000000000000000000000
+281e:00000000000001c001c001c00000000039c039c039c000000000380038003800000000000000000000000000
+281f:00000000000039c039c039c00000000039c039c039c000000000380038003800000000000000000000000000
+2820:000000000000000000000000000000000000000000000000000001c001c001c0000000000000000000000000
+2821:000000000000380038003800000000000000000000000000000001c001c001c0000000000000000000000000
+2822:000000000000000000000000000000003800380038000000000001c001c001c0000000000000000000000000
+2823:000000000000380038003800000000003800380038000000000001c001c001c0000000000000000000000000
+2824:000000000000000000000000000000000000000000000000000039c039c039c0000000000000000000000000
+2825:000000000000380038003800000000000000000000000000000039c039c039c0000000000000000000000000
+2826:000000000000000000000000000000003800380038000000000039c039c039c0000000000000000000000000
+2827:000000000000380038003800000000003800380038000000000039c039c039c0000000000000000000000000
+2828:00000000000001c001c001c0000000000000000000000000000001c001c001c0000000000000000000000000
+2829:00000000000039c039c039c0000000000000000000000000000001c001c001c0000000000000000000000000
+282a:00000000000001c001c001c0000000003800380038000000000001c001c001c0000000000000000000000000
+282b:00000000000039c039c039c0000000003800380038000000000001c001c001c0000000000000000000000000
+282c:00000000000001c001c001c0000000000000000000000000000039c039c039c0000000000000000000000000
+282d:00000000000039c039c039c0000000000000000000000000000039c039c039c0000000000000000000000000
+282e:00000000000001c001c001c0000000003800380038000000000039c039c039c0000000000000000000000000
+282f:00000000000039c039c039c0000000003800380038000000000039c039c039c0000000000000000000000000
+2830:0000000000000000000000000000000001c001c001c00000000001c001c001c0000000000000000000000000
+2831:0000000000003800380038000000000001c001c001c00000000001c001c001c0000000000000000000000000
+2832:0000000000000000000000000000000039c039c039c00000000001c001c001c0000000000000000000000000
+2833:0000000000003800380038000000000039c039c039c00000000001c001c001c0000000000000000000000000
+2834:0000000000000000000000000000000001c001c001c00000000039c039c039c0000000000000000000000000
+2835:0000000000003800380038000000000001c001c001c00000000039c039c039c0000000000000000000000000
+2836:0000000000000000000000000000000039c039c039c00000000039c039c039c0000000000000000000000000
+2837:0000000000003800380038000000000039c039c039c00000000039c039c039c0000000000000000000000000
+2838:00000000000001c001c001c00000000001c001c001c00000000001c001c001c0000000000000000000000000
+2839:00000000000039c039c039c00000000001c001c001c00000000001c001c001c0000000000000000000000000
+283a:00000000000001c001c001c00000000039c039c039c00000000001c001c001c0000000000000000000000000
+283b:00000000000039c039c039c00000000039c039c039c00000000001c001c001c0000000000000000000000000
+283c:00000000000001c001c001c00000000001c001c001c00000000039c039c039c0000000000000000000000000
+283d:00000000000039c039c039c00000000001c001c001c00000000039c039c039c0000000000000000000000000
+283e:00000000000001c001c001c00000000039c039c039c00000000039c039c039c0000000000000000000000000
+283f:00000000000039c039c039c00000000039c039c039c00000000039c039c039c0000000000000000000000000
+2840:0000000000000000000000000000000000000000000000000000000000000000000000003800380038000000
+2841:0000000000003800380038000000000000000000000000000000000000000000000000003800380038000000
+2842:0000000000000000000000000000000038003800380000000000000000000000000000003800380038000000
+2843:0000000000003800380038000000000038003800380000000000000000000000000000003800380038000000
+2844:0000000000000000000000000000000000000000000000000000380038003800000000003800380038000000
+2845:0000000000003800380038000000000038003800380000000000000000000000000000003800380038000000
+2846:0000000000003800380038000000000000000000000000000000380038003800000000003800380038000000
+2847:0000000000003800380038000000000038003800380000000000380038003800000000003800380038000000
+2848:00000000000001c001c001c00000000000000000000000000000000000000000000000003800380038000000
+2849:00000000000039c039c039c00000000000000000000000000000000000000000000000003800380038000000
+284a:00000000000001c001c001c00000000038003800380000000000000000000000000000003800380038000000
+284b:00000000000039c039c039c00000000038003800380000000000000000000000000000003800380038000000
+284c:00000000000001c001c001c00000000000000000000000000000380038003800000000003800380038000000
+284d:00000000000039c039c039c00000000000000000000000000000380038003800000000003800380038000000
+284e:00000000000001c001c001c00000000038003800380000000000380038003800000000003800380038000000
+284f:00000000000039c039c039c00000000038003800380000000000380038003800000000003800380038000000
+2850:0000000000000000000000000000000001c001c001c000000000000000000000000000003800380038000000
+2851:0000000000003800380038000000000001c001c001c000000000000000000000000000003800380038000000
+2852:0000000000000000000000000000000039c039c039c000000000000000000000000000003800380038000000
+2853:0000000000003800380038000000000039c039c039c000000000000000000000000000003800380038000000
+2854:0000000000000000000000000000000001c001c001c000000000380038003800000000003800380038000000
+2855:0000000000003800380038000000000001c001c001c000000000380038003800000000003800380038000000
+2856:0000000000000000000000000000000039c039c039c000000000380038003800000000003800380038000000
+2857:0000000000003800380038000000000039c039c039c000000000380038003800000000003800380038000000
+2858:00000000000001c001c001c00000000001c001c001c000000000000000000000000000003800380038000000
+2859:00000000000039c039c039c00000000001c001c001c000000000000000000000000000003800380038000000
+285a:00000000000001c001c001c00000000039c039c039c000000000000000000000000000003800380038000000
+285b:00000000000039c039c039c00000000039c039c039c000000000000000000000000000003800380038000000
+285c:00000000000001c001c001c00000000001c001c001c000000000380038003800000000003800380038000000
+285d:00000000000039c039c039c00000000001c001c001c000000000380038003800000000003800380038000000
+285e:00000000000001c001c001c00000000039c039c039c000000000380038003800000000003800380038000000
+285f:00000000000039c039c039c00000000039c039c039c000000000380038003800000000003800380038000000
+2860:000000000000000000000000000000000000000000000000000001c001c001c0000000003800380038000000
+2861:000000000000380038003800000000000000000000000000000001c001c001c0000000003800380038000000
+2862:000000000000000000000000000000003800380038000000000001c001c001c0000000003800380038000000
+2863:000000000000380038003800000000003800380038000000000001c001c001c0000000003800380038000000
+2864:000000000000000000000000000000000000000000000000000039c039c039c0000000003800380038000000
+2865:000000000000380038003800000000000000000000000000000039c039c039c0000000003800380038000000
+2866:000000000000000000000000000000003800380038000000000039c039c039c0000000003800380038000000
+2867:000000000000380038003800000000003800380038000000000039c039c039c0000000003800380038000000
+2868:00000000000001c001c001c0000000000000000000000000000001c001c001c0000000003800380038000000
+2869:00000000000039c039c039c0000000000000000000000000000001c001c001c0000000003800380038000000
+286a:00000000000001c001c001c0000000003800380038000000000001c001c001c0000000003800380038000000
+286b:00000000000039c039c039c0000000003800380038000000000001c001c001c0000000003800380038000000
+286c:00000000000001c001c001c0000000000000000000000000000039c039c039c0000000003800380038000000
+286d:00000000000039c039c039c0000000000000000000000000000039c039c039c0000000003800380038000000
+286e:00000000000001c001c001c0000000003800380038000000000039c039c039c0000000003800380038000000
+286f:00000000000039c039c039c0000000003800380038000000000039c039c039c0000000003800380038000000
+2870:0000000000000000000000000000000001c001c001c00000000001c001c001c0000000003800380038000000
+2871:0000000000003800380038000000000001c001c001c00000000001c001c001c0000000003800380038000000
+2872:0000000000000000000000000000000039c039c039c00000000001c001c001c0000000003800380038000000
+2873:0000000000003800380038000000000039c039c039c00000000001c001c001c0000000003800380038000000
+2874:0000000000000000000000000000000001c001c001c00000000039c039c039c0000000003800380038000000
+2875:0000000000003800380038000000000001c001c001c00000000039c039c039c0000000003800380038000000
+2876:0000000000000000000000000000000039c039c039c00000000039c039c039c0000000003800380038000000
+2877:0000000000003800380038000000000039c039c039c00000000039c039c039c0000000003800380038000000
+2878:00000000000001c001c001c00000000001c001c001c00000000001c001c001c0000000003800380038000000
+2879:00000000000039c039c039c00000000001c001c001c00000000001c001c001c0000000003800380038000000
+287a:00000000000001c001c001c00000000039c039c039c00000000001c001c001c0000000003800380038000000
+287b:00000000000039c039c039c00000000039c039c039c00000000001c001c001c0000000003800380038000000
+287c:00000000000001c001c001c00000000001c001c001c00000000039c039c039c0000000003800380038000000
+287d:00000000000039c039c039c00000000001c001c001c00000000039c039c039c0000000003800380038000000
+287e:00000000000001c001c001c00000000039c039c039c00000000039c039c039c0000000003800380038000000
+287f:00000000000039c039c039c00000000039c039c039c00000000039c039c039c0000000003800380038000000
+2880:00000000000000000000000000000000000000000000000000000000000000000000000001c001c001c00000
+2881:00000000000038003800380000000000000000000000000000000000000000000000000001c001c001c00000
+2882:00000000000000000000000000000000380038003800000000000000000000000000000001c001c001c00000
+2883:00000000000038003800380000000000380038003800000000000000000000000000000001c001c001c00000
+2884:00000000000000000000000000000000000000000000000000003800380038000000000001c001c001c00000
+2885:00000000000038003800380000000000380038003800000000000000000000000000000001c001c001c00000
+2886:00000000000038003800380000000000000000000000000000003800380038000000000001c001c001c00000
+2887:00000000000038003800380000000000380038003800000000003800380038000000000001c001c001c00000
+2888:00000000000001c001c001c000000000000000000000000000000000000000000000000001c001c001c00000
+2889:00000000000039c039c039c000000000000000000000000000000000000000000000000001c001c001c00000
+288a:00000000000001c001c001c000000000380038003800000000000000000000000000000001c001c001c00000
+288b:00000000000039c039c039c000000000380038003800000000000000000000000000000001c001c001c00000
+288c:00000000000001c001c001c000000000000000000000000000003800380038000000000001c001c001c00000
+288d:00000000000039c039c039c000000000000000000000000000003800380038000000000001c001c001c00000
+288e:00000000000001c001c001c000000000380038003800000000003800380038000000000001c001c001c00000
+288f:00000000000039c039c039c000000000380038003800000000003800380038000000000001c001c001c00000
+2890:0000000000000000000000000000000001c001c001c0000000000000000000000000000001c001c001c00000
+2891:0000000000003800380038000000000001c001c001c0000000000000000000000000000001c001c001c00000
+2892:0000000000000000000000000000000039c039c039c0000000000000000000000000000001c001c001c00000
+2893:0000000000003800380038000000000039c039c039c0000000000000000000000000000001c001c001c00000
+2894:0000000000000000000000000000000001c001c001c0000000003800380038000000000001c001c001c00000
+2895:0000000000003800380038000000000001c001c001c0000000003800380038000000000001c001c001c00000
+2896:0000000000000000000000000000000039c039c039c0000000003800380038000000000001c001c001c00000
+2897:0000000000003800380038000000000039c039c039c0000000003800380038000000000001c001c001c00000
+2898:00000000000001c001c001c00000000001c001c001c0000000000000000000000000000001c001c001c00000
+2899:00000000000039c039c039c00000000001c001c001c0000000000000000000000000000001c001c001c00000
+289a:00000000000001c001c001c00000000039c039c039c0000000000000000000000000000001c001c001c00000
+289b:00000000000039c039c039c00000000039c039c039c0000000000000000000000000000001c001c001c00000
+289c:00000000000001c001c001c00000000001c001c001c0000000003800380038000000000001c001c001c00000
+289d:00000000000039c039c039c00000000001c001c001c0000000003800380038000000000001c001c001c00000
+289e:00000000000001c001c001c00000000039c039c039c0000000003800380038000000000001c001c001c00000
+289f:00000000000039c039c039c00000000039c039c039c0000000003800380038000000000001c001c001c00000
+28a0:000000000000000000000000000000000000000000000000000001c001c001c00000000001c001c001c00000
+28a1:000000000000380038003800000000000000000000000000000001c001c001c00000000001c001c001c00000
+28a2:000000000000000000000000000000003800380038000000000001c001c001c00000000001c001c001c00000
+28a3:000000000000380038003800000000003800380038000000000001c001c001c00000000001c001c001c00000
+28a4:000000000000000000000000000000000000000000000000000039c039c039c00000000001c001c001c00000
+28a5:000000000000380038003800000000000000000000000000000039c039c039c00000000001c001c001c00000
+28a6:000000000000000000000000000000003800380038000000000039c039c039c00000000001c001c001c00000
+28a7:000000000000380038003800000000003800380038000000000039c039c039c00000000001c001c001c00000
+28a8:00000000000001c001c001c0000000000000000000000000000001c001c001c00000000001c001c001c00000
+28a9:00000000000039c039c039c0000000000000000000000000000001c001c001c00000000001c001c001c00000
+28aa:00000000000001c001c001c0000000003800380038000000000001c001c001c00000000001c001c001c00000
+28ab:00000000000039c039c039c0000000003800380038000000000001c001c001c00000000001c001c001c00000
+28ac:00000000000001c001c001c0000000000000000000000000000039c039c039c00000000001c001c001c00000
+28ad:00000000000039c039c039c0000000000000000000000000000039c039c039c00000000001c001c001c00000
+28ae:00000000000001c001c001c0000000003800380038000000000039c039c039c00000000001c001c001c00000
+28af:00000000000039c039c039c0000000003800380038000000000039c039c039c00000000001c001c001c00000
+28b0:0000000000000000000000000000000001c001c001c00000000001c001c001c00000000001c001c001c00000
+28b1:0000000000003800380038000000000001c001c001c00000000001c001c001c00000000001c001c001c00000
+28b2:0000000000000000000000000000000039c039c039c00000000001c001c001c00000000001c001c001c00000
+28b3:0000000000003800380038000000000039c039c039c00000000001c001c001c00000000001c001c001c00000
+28b4:0000000000000000000000000000000001c001c001c00000000039c039c039c00000000001c001c001c00000
+28b5:0000000000003800380038000000000001c001c001c00000000039c039c039c00000000001c001c001c00000
+28b6:0000000000000000000000000000000039c039c039c00000000039c039c039c00000000001c001c001c00000
+28b7:0000000000003800380038000000000039c039c039c00000000039c039c039c00000000001c001c001c00000
+28b8:00000000000001c001c001c00000000001c001c001c00000000001c001c001c00000000001c001c001c00000
+28b9:00000000000039c039c039c00000000001c001c001c00000000001c001c001c00000000001c001c001c00000
+28ba:00000000000001c001c001c00000000039c039c039c00000000001c001c001c00000000001c001c001c00000
+28bb:00000000000039c039c039c00000000039c039c039c00000000001c001c001c00000000001c001c001c00000
+28bc:00000000000001c001c001c00000000001c001c001c00000000039c039c039c00000000001c001c001c00000
+28bd:00000000000039c039c039c00000000001c001c001c00000000039c039c039c00000000001c001c001c00000
+28be:00000000000001c001c001c00000000039c039c039c00000000039c039c039c00000000001c001c001c00000
+28bf:00000000000039c039c039c00000000039c039c039c00000000039c039c039c00000000001c001c001c00000
+28c0:00000000000000000000000000000000000000000000000000000000000000000000000039c039c039c00000
+28c1:00000000000038003800380000000000000000000000000000000000000000000000000039c039c039c00000
+28c2:00000000000000000000000000000000380038003800000000000000000000000000000039c039c039c00000
+28c3:00000000000038003800380000000000380038003800000000000000000000000000000039c039c039c00000
+28c4:00000000000000000000000000000000000000000000000000003800380038000000000039c039c039c00000
+28c5:00000000000038003800380000000000380038003800000000000000000000000000000039c039c039c00000
+28c6:00000000000038003800380000000000000000000000000000003800380038000000000039c039c039c00000
+28c7:00000000000038003800380000000000380038003800000000003800380038000000000039c039c039c00000
+28c8:00000000000001c001c001c000000000000000000000000000000000000000000000000039c039c039c00000
+28c9:00000000000039c039c039c000000000000000000000000000000000000000000000000039c039c039c00000
+28ca:00000000000001c001c001c000000000380038003800000000000000000000000000000039c039c039c00000
+28cb:00000000000039c039c039c000000000380038003800000000000000000000000000000039c039c039c00000
+28cc:00000000000001c001c001c000000000000000000000000000003800380038000000000039c039c039c00000
+28cd:00000000000039c039c039c000000000000000000000000000003800380038000000000039c039c039c00000
+28ce:00000000000001c001c001c000000000380038003800000000003800380038000000000039c039c039c00000
+28cf:00000000000039c039c039c000000000380038003800000000003800380038000000000039c039c039c00000
+28d0:0000000000000000000000000000000001c001c001c0000000000000000000000000000039c039c039c00000
+28d1:0000000000003800380038000000000001c001c001c0000000000000000000000000000039c039c039c00000
+28d2:0000000000000000000000000000000039c039c039c0000000000000000000000000000039c039c039c00000
+28d3:0000000000003800380038000000000039c039c039c0000000000000000000000000000039c039c039c00000
+28d4:0000000000000000000000000000000001c001c001c0000000003800380038000000000039c039c039c00000
+28d5:0000000000003800380038000000000001c001c001c0000000003800380038000000000039c039c039c00000
+28d6:0000000000000000000000000000000039c039c039c0000000003800380038000000000039c039c039c00000
+28d7:0000000000003800380038000000000039c039c039c0000000003800380038000000000039c039c039c00000
+28d8:00000000000001c001c001c00000000001c001c001c0000000000000000000000000000039c039c039c00000
+28d9:00000000000039c039c039c00000000001c001c001c0000000000000000000000000000039c039c039c00000
+28da:00000000000001c001c001c00000000039c039c039c0000000000000000000000000000039c039c039c00000
+28db:00000000000039c039c039c00000000039c039c039c0000000000000000000000000000039c039c039c00000
+28dc:00000000000001c001c001c00000000001c001c001c0000000003800380038000000000039c039c039c00000
+28dd:00000000000039c039c039c00000000001c001c001c0000000003800380038000000000039c039c039c00000
+28de:00000000000001c001c001c00000000039c039c039c0000000003800380038000000000039c039c039c00000
+28df:00000000000039c039c039c00000000039c039c039c0000000003800380038000000000039c039c039c00000
+28e0:000000000000000000000000000000000000000000000000000001c001c001c00000000039c039c039c00000
+28e1:000000000000380038003800000000000000000000000000000001c001c001c00000000039c039c039c00000
+28e2:000000000000000000000000000000003800380038000000000001c001c001c00000000039c039c039c00000
+28e3:000000000000380038003800000000003800380038000000000001c001c001c00000000039c039c039c00000
+28e4:000000000000000000000000000000000000000000000000000039c039c039c00000000039c039c039c00000
+28e5:000000000000380038003800000000000000000000000000000039c039c039c00000000039c039c039c00000
+28e6:000000000000000000000000000000003800380038000000000039c039c039c00000000039c039c039c00000
+28e7:000000000000380038003800000000003800380038000000000039c039c039c00000000039c039c039c00000
+28e8:00000000000001c001c001c0000000000000000000000000000001c001c001c00000000039c039c039c00000
+28e9:00000000000039c039c039c0000000000000000000000000000001c001c001c00000000039c039c039c00000
+28ea:00000000000001c001c001c0000000003800380038000000000001c001c001c00000000039c039c039c00000
+28eb:00000000000039c039c039c0000000003800380038000000000001c001c001c00000000039c039c039c00000
+28ec:00000000000001c001c001c0000000000000000000000000000039c039c039c00000000039c039c039c00000
+28ed:00000000000039c039c039c0000000000000000000000000000039c039c039c00000000039c039c039c00000
+28ee:00000000000001c001c001c0000000003800380038000000000039c039c039c00000000039c039c039c00000
+28ef:00000000000039c039c039c0000000003800380038000000000039c039c039c00000000039c039c039c00000
+28f0:0000000000000000000000000000000001c001c001c00000000001c001c001c00000000039c039c039c00000
+28f1:0000000000003800380038000000000001c001c001c00000000001c001c001c00000000039c039c039c00000
+28f2:0000000000000000000000000000000039c039c039c00000000001c001c001c00000000039c039c039c00000
+28f3:0000000000003800380038000000000039c039c039c00000000001c001c001c00000000039c039c039c00000
+28f4:0000000000000000000000000000000001c001c001c00000000039c039c039c00000000039c039c039c00000
+28f5:0000000000003800380038000000000001c001c001c00000000039c039c039c00000000039c039c039c00000
+28f6:0000000000000000000000000000000039c039c039c00000000039c039c039c00000000039c039c039c00000
+28f7:0000000000003800380038000000000039c039c039c00000000039c039c039c00000000039c039c039c00000
+28f8:00000000000001c001c001c00000000001c001c001c00000000001c001c001c00000000039c039c039c00000
+28f9:00000000000039c039c039c00000000001c001c001c00000000001c001c001c00000000039c039c039c00000
+28fa:00000000000001c001c001c00000000039c039c039c00000000001c001c001c00000000039c039c039c00000
+28fb:00000000000039c039c039c00000000039c039c039c00000000001c001c001c00000000039c039c039c00000
+28fc:00000000000001c001c001c00000000001c001c001c00000000039c039c039c00000000039c039c039c00000
+28fd:00000000000039c039c039c00000000001c001c001c00000000039c039c039c00000000039c039c039c00000
+28fe:00000000000001c001c001c00000000039c039c039c00000000039c039c039c00000000039c039c039c00000
+28ff:00000000000039c039c039c00000000039c039c039c00000000039c039c039c00000000039c039c039c00000
+2900:0000000000000000000000000000248022402120fff0fff02120224024800000000000000000000000000000
+2901:0000000000000000000000000000548052405120fff0fff05120524054800000000000000000000000000000
+2902:00000000000000000000318031806ff06ff0c180c1806ff06ff0318031800000000000000000000000000000
+2903:0000000000000000000018c018c0ff60ff6018301830ff60ff6018c018c00000000000000000000000000000
+2904:00000000000000000000264026407fe07fe0c630c6307fe07fe0264026400000000000000000000000000000
+2905:0000000000000000000000000000c480c240c120fff0fff0c120c240c4800000000000000000000000000000
+2906:00000000000000000000303030306ff06ff0c030c0306ff06ff0303030300000000000000000000000000000
+2907:00000000000000000000c0c0c0c0ff60ff60c030c030ff60ff60c0c0c0c00000000000000000000000000000
+2908:0000000006000600060006007fe07fe00600060006000600666036c01f800f00060000000000000000000000
+2909:0000000006000f001f8036c0666006000600060006007fe07fe0060006000600060000000000000000000000
+290a:0000000006000f001f8036c06660e67036c036c036c036c036c036c036c036c036c000000000000000000000
+290b:0000000036c036c036c036c036c036c036c036c036c0e670666036c01f800f00060000000000000000000000
+290c:000000000000000000000000180030006000f9f0f9f060003000180000000000000000000000000000000000
+290d:000000000000000000000000018000c00060f9f0f9f0006000c0018000000000000000000000000000000000
+290e:000000000000000000000000180030006000f770f77060003000180000000000000000000000000000000000
+290f:000000000000000000000000018000c00060eef0eef0006000c0018000000000000000000000000000000000
+2910:0000000000000000000000000000048002400120db70db700120024004800000000000000000000000000000
+2911:000000000000000000000000018000c00060aab0aab0006000c0018000000000000000000000000000000000
+2912:00000000fff0fff006000f001f8036c066600600060006000600060006000600060000000000000000000000
+2913:0000000006000600060006000600060006000600666036c01f800f000600fff0fff000000000000000000000
+2914:00000000000000000000000000008480444024201ff01ff02420444084800000000000000000000000000000
+2915:00000000000000000000000000008a804a402a201ff01ff02a204a408a800000000000000000000000000000
+2916:00000000000000000000000000008480424021201ff01ff02120424084800000000000000000000000000000
+2917:00000000000000000000000000008a80494028a01ff01ff028a049408a800000000000000000000000000000
+2918:0000000000000000000000000000954054a034503ff03ff0345054a095400000000000000000000000000000
+2919:0000000000000000000000000030006000c0ff80ff8000c00060003000000000000000000000000000000000
+291a:000000000000000000000000c000600030001ff01ff030006000c00000000000000000000000000000000000
+291b:000000000000000000000000009001200240ff80ff8002400120009000000000000000000000000000000000
+291c:0000000000000000000000009000480024001ff01ff024004800900000000000000000000000000000000000
+291d:000000000000000000000000018003004600eff0eff046000300018000000000000000000000000000000000
+291e:00000000000000000000000018000c000620ff70ff7006200c00180000000000000000000000000000000000
+291f:000000000000000000000000019003104610eff0eff046100310019000000000000000000000000000000000
+2920:00000000000000000000000098008c008620ff70ff7086208c00980000000000000000000000000000000000
+2921:000000000000000000000000fc00fc00f000d800cc00c630033001b000f003f003f000000000000000000000
+2922:00000000000000000000000003f003f000f001b00330c630cc00d800f000fc00fc0000000000000000000000
+2923:000000000000000000000000fc00fc00f000d800cc00c600030001800cc007c0038000000000000000000000
+2924:00000000000000000000000007e007e001e0036006600c601800300066007c00380000000000000000000000
+2925:00000000000000000000000038007c006600300018000c600660036001e007e007e000000000000000000000
+2926:00000000000000000000000001c003e0066000c00180630066006c0078007e007e0000000000000000000000
+2927:000000000000000000000000f9f0e070f0f0d9b0cf3006000f00198030c06060c03000000000000000000000
+2928:000000000000000001f00070c0f061b033301e300c001e00333061b0c0f0007001f000000000000000000000
+2929:000000000000000000000000c030606030c019800f000600cf30d9b0f0f0e070f9f000000000000000000000
+292a:0000000000000000f800e000f030d860ccc0c78003000780ccc0d860f030e000f80000000000000000000000
+292b:000000000000000000000000c030606030c01980030006000c00198030c06060c03000000000000000000000
+292c:000000000000000000000000c030606030c019800c0006000300198030c06060c03000000000000000000000
+292d:000000000000000001f00070c0f061b0333018300c000600333061b0c0f0007001f000000000000000000000
+292e:000000000000000001f00070c0f061b0333006300c001800333061b0c0f0007001f000000000000000000000
+292f:0000000000000000000001f00070c0f061b0333018300c00060033006180c0c0006000000000000000000000
+2930:000000000000000000000060c0c06180330006000c001830333061b0c0f0007001f000000000000000000000
+2931:000000000000000000000000f9f0e070f0f0d9b0c33006000c00198030c06060c03000000000000000000000
+2932:000000000000000000000000f9f0e070f0f0d9b0cc3006000300198030c06060c03000000000000000000000
+2933:00000000000000000000000001801cc03660e3f0c1f0006000c0018000000000000000000000000000000000
+2934:000000000000030007800fc01b6033300300030003000300030003000600fe00f80000000000000000000000
+2935:000000000000f800fe00060003000300030003000300030033301b600fc00780030000000000000000000000
+2936:000000000000000000300030003000300030183030306060ffe0ff8060003000180000000000000000000000
+2937:0000000000000000c000c000c000c000c000c180c0c060607ff01ff0006000c0018000000000000000000000
+2938:0000000000000300018000c000c000600060006000600060186018c019801e001f8000000000000000000000
+2939:0000000000000c001800300030006000600060006000600061803180198007801f8000000000000000000000
+293a:00000000000000000000000007c00fe04c70783078307c307e00000000000000000000000000000000000000
+293b:00000000000000000000000003f061f060f060f071903f801f00000000000000000000000000000000000000
+293c:0000000000000000000000003e007f00e320c1e0c1e0c3e007e0000000001f801f8000000000000000000000
+293d:0000000000003e007f00e320c1e0c1e0c3e007e00000060006001f801f800600060000000000000000000000
+293e:0000000000000000000000000000018000c000c0fc60f860f060f06098e01fc00f8000000000000000000000
+293f:000000000000000000000000000018003000300063f061f060f060f071903f801f0000000000000000000000
+2940:00000000000000001c007f006300c180c180c3c0c7e0cdb0c990c18063007f001c0000000000000000000000
+2941:000000000000000003800fe00c60183018303c307e30db30993018300c600fe0038000000000000000000000
+2942:000000000000018000c00060fff0fff0006000c0198030006000fe00fe006000300018000000000000000000
+2943:000000000000180030006000fff0fff060003000198000c0006007f007f0006000c001800000000000000000
+2944:000000000000018000c0006007f007f0006000c0198030006000fff0fff06000300018000000000000000000
+2945:00000000000000000000018000c00060fff0fff0006030c03180fc00fc003000300000000000000000000000
+2946:00000000000000000000180030006000fff0fff0600030c018c003f003f000c000c000000000000000000000
+2947:00000000000000000000000000000000858048c03060fff0fff0306048c08580000000000000000000000000
+2948:0000000000000000000000000000000020804e409120fff0fff091204e402080000000000000000000000000
+2949:000006000f001f8036c066600f001f8036c06660060006000f001f8030c030c030c01f800f00000000000000
+294a:000000000000000000000000000000000c00180030007fe0ffc0018003000600000000000000000000000000
+294b:00000000000000000000000000000000060003000180ffc07fe0300018000c00000000000000000000000000
+294c:00000000040006000700078006c00660060006000600660036001e000e000600020000000000000000000000
+294d:00000000020006000e001e0036006600060006000600066006c0078007000600040000000000000000000000
+294e:00000000000000000000000000000000198030c06060fff0fff0000000000000000000000000000000000000
+294f:00000000040006000700078006c00660060006000600066006c0078007000600040000000000000000000000
+2950:00000000000000000000000000000000000000000000fff0fff0606030c01980000000000000000000000000
+2951:00000000020006000e001e0036006600060006000600660036001e000e000600020000000000000000000000
+2952:00000000000000000000000000000000c300c600cc00dff0fff0c000c000c000000000000000000000000000
+2953:000000000000000000000000000000000c3006300330ffb0fff0003000300030000000000000000000000000
+2954:000000007fe07fe0040006000700078006c00660060006000600060006000600060000000000000000000000
+2955:000000000600060006000600060006000600066006c007800700060004007fe07fe000000000000000000000
+2956:00000000000000000000000000000000c000c000c000fff0dff0cc00c600c300000000000000000000000000
+2957:00000000000000000000000000000000003000300030fff0ffb0033006300c30000000000000000000000000
+2958:000000007fe07fe0020006000e001e0036006600060006000600060006000600060000000000000000000000
+2959:000000000600060006000600060006000600660036001e000e00060002007fe07fe000000000000000000000
+295a:000000000000000000000000000000000c30183030307ff0fff0003000300030000000000000000000000000
+295b:00000000000000000000000000000000c300c180c0c0ffe0fff0c000c000c000000000000000000000000000
+295c:00000000040006000700078006c0066006000600060006000600060006007fe07fe000000000000000000000
+295d:000000007fe07fe00600060006000600060006000600066006c0078007000600040000000000000000000000
+295e:00000000000000000000000000000000003000300030fff07ff0303018300c30000000000000000000000000
+295f:00000000000000000000000000000000c000c000c000fff0ffe0c0c0c180c300000000000000000000000000
+2960:00000000020006000e001e003600660006000600060006000600060006007fe07fe000000000000000000000
+2961:000000007fe07fe00600060006000600060006000600660036001e000e000600020000000000000000000000
+2962:00000000000000000c00180030007fe0ffe000000000ffe07fe0300018000c00000000000000000000000000
+2963:0000000000000900198039c079e0d9b019801980198019801980198019801980198000000000000000000000
+2964:0000000000000000060003000180ffc0ffe000000000ffe0ffc0018003000600000000000000000000000000
+2965:000000000000198019801980198019801980198019801980d9b079e039c01980090000000000000000000000
+2966:00000000000000000c00180030007fe0ffe00000060003000180ffc0ffe00000000000000000000000000000
+2967:0000000000000000ffe07fe0300018000c000000ffe0ffc00180030006000000000000000000000000000000
+2968:0000000000000000060003000180ffc0ffe000000c00180030007fe0ffe00000000000000000000000000000
+2969:0000000000000000ffe0ffc00180030006000000ffe07fe0300018000c000000000000000000000000000000
+296a:0000000000000000000000000c00180030007fe0ffe000000000ffe0ffe00000000000000000000000000000
+296b:000000000000000000000000ffe0ffe000000000ffe07fe0300018000c000000000000000000000000000000
+296c:000000000000000000000000060003000180ffc0ffe000000000ffe0ffe00000000000000000000000000000
+296d:000000000000000000000000ffe0ffe000000000ffe0ffc00180030006000000000000000000000000000000
+296e:0000000000000980198039807980d980198019801980198019b019e019c01980190000000000000000000000
+296f:0000000000001900198019c019e019b01980198019801980d980798039801980098000000000000000000000
+2970:00000000000000000000000000000000ffe0fff000300030fff0ffe000000000000000000000000000000000
+2971:00000000000000007c007c00000000007c007d8000c00060fff0fff0006000c0018000000000000000000000
+2972:00000000000000001c203e6067c043800000018000c00060fff0fff0006000c0018000000000000000000000
+2973:0000000000000000180030006000fff0fff060003000180000001c203e6067c0438000000000000000000000
+2974:0000000000000000018000c00060fff0fff0006000c0018000001c203e6067c0438000000000000000000000
+2975:0000018000c00060fff0fff0006000c0018000001c203e6067c043801c203e6067c043800000000000000000
+2976:000000000000007003c01e00f0001e0003c0187030006000fff0fff060003000180000000000000000000000
+2977:0000000000000000000000000000003018e033806e00fff0fff06e00338018e0003000000000000000000000
+2978:000000000000e0003c00078000f007803c00e18000c00060fff0fff0006000c0018000000000000000000000
+2979:00001fe03fe07000600070003fe01fe00000018000c00060fff0fff0006000c0018000000000000000000000
+297a:00000000000000f001f00300130026004600fff0fff0460026001300030001f000f000000000000000000000
+297b:00007f807fc000e0006000e07fc07f800000180030006000fff0fff060003000180000000000000000000000
+297c:0000000000000000000038007000c00078001ff01ff07800c000700038000000000000000000000000000000
+297d:0000000000000000000001c000e0003001e0ff80ff8001e0003000e001c00000000000000000000000000000
+297e:000000000000108039c069606f604f2006000600060006000600060006000600060000000000000000000000
+297f:0000000000000600060006000600060006000600060006004f206f60696039c0108000000000000000000000
+2980:0000000066606660666066606660666066606660666066606660666066606660666000000000000000000000
+2981:00000000000000000000000000000f003fc03fc03fc03fc03fc00f0000000000000000000000000000000000
+2982:00000000000000000e003180318031800e00000000000e003180318031800e00000000000000000000000000
+2983:000000001fe031803180198019801980318071803180198019801980318031801fe000000000000000000000
+2984:000000007f8018c018c019801980198018c018e018c019801980198018c018c07f8000000000000000000000
+2985:0000000001e006c00dc01980198033003300330033003300198019800dc006c001e000000000000000000000
+2986:00000000780036003b00198019800cc00cc00cc00cc00cc0198019803b003600780000000000000000000000
+2987:0000000001c006c00cc018c018c030c030c030c030c030c018c018c00cc006c001c000000000000000000000
+2988:000000003800360033003180318030c030c030c030c030c03180318033003600380000000000000000000000
+2989:0000000000c001c003c006c00cc018c030c060c030c018c00cc006c003c001c000c000000000000000000000
+298a:00000000300038003c0036003300318030c0306030c03180330036003c003800300000000000000000000000
+298b:0000000007c007c00600060006000600060006000600060006000600060007c007c0000007c007c000000000
+298c:000000003e003e00060006000600060006000600060006000600060006003e003e0000003e003e0000000000
+298d:0000000007c007c00700078006c00660060006000600060006000600060007c007c000000000000000000000
+298e:000000003e003e000600060006000600060006000600660036001e000e003e003e0000000000000000000000
+298f:0000000007c007c00600060006000600060006000600066006c00780070007c007c000000000000000000000
+2990:000000003e003e000e001e003600660006000600060006000600060006003e003e0000000000000000000000
+2991:000000000600060006000c000c000c00188019c018800c000c000c0006000600060000000000000000000000
+2992:0000000006000600060003000300030011803980118003000300030006000600060000000000000000000000
+2993:00000000000001800300063004c00b000c003800c80038000c000b0004c00630030001800000000000000000
+2994:00000000000018000c00c60032000d00030001c0013001c003000d003200c6000c0018000000000000000000
+2995:00000000000000000d80db0036006c006f00d8c0d830d8c06f006c003600db000d8000000000000000000000
+2996:00000000000000001b000db006c003600f6031b0c1b031b00f60036006c00db01b0000000000000000000000
+2997:0000000000c003800e003c003c003c003c003c003c003c003c003c000e00038000c000000000000000000000
+2998:0000000030001c00070003c003c003c003c003c003c003c003c003c007001c00300000000000000000000000
+2999:00000000000006000f000600000006000f000600000006000f000600000006000f0006000000000000000000
+299a:0000000006000c0018000c0006000c0018000c0006000c0018000c0006000c00180000000000000000000000
+299b:00000000000000008000c060618032001c000c000e001300118020c02060fff0fff040004000000000000000
+299c:00000000000000000000c000c000c000c000ff00c100c100c100c100c100fff0fff000000000000000000000
+299d:00000000000000000000c000c000c000c000f800c400c200d900d900c100fff0fff000000000000000000000
+299e:00000000000000000000006000c00180030006700c801860301060e0c000fff0fff000000000000000000000
+299f:00000000000000000000006000c00180030006000c00180030006000c000fff0fff000000000000000000000
+29a0:00000000000003000c00d80030003c00330060c0603060c033003c003000d8000c0003000000000000000000
+29a1:00000000000000000000c030cfb070e06060b0d0b0d0198019800f000f000600060000000000000000000000
+29a2:00000000000000000000fff0fff00030006000c00180030006000c0018003000600000000000000000000000
+29a3:000000000000000000006000300018000c0006000300018000c000600030fff0fff000000000000000000000
+29a4:00000000006000c00180030006000c00180030006000c000fff0fff00000fff0fff000000000000000000000
+29a5:000000006000300018000c0006000300018000c000600030fff0fff00000fff0fff000000000000000000000
+29a6:000000000000000000000000000000008000c0006000300018000c0007f003f0000000000000000000000000
+29a7:0000000000000000000000000000000003f007f00c00180030006000c0008000000000000000000000000000
+29a8:000000000fc01fc003c066c036c01c800e001b001980318030c060c060c0fff0fff000c000c0000000000000
+29a9:000000003f003f803c00366036c0138007000d80198018c030c030603060fff0fff030003000000000000000
+29aa:0000000000c000c0fff0fff060c060c030c0318019801b000e001c8036c066c003c01fc00fc0000000000000
+29ab:0000000030003000fff0fff03060306030c018c019800d800700138036c036603c003f803f00000000000000
+29ac:00000000000000000000c000c000c000c1f0f070dcf0c790c390c780ccc0d860f060e0000000000000000000
+29ad:00000000000000000000003000300030f830e0f0f3b09e309c301e30333061b060f000700000000000000000
+29ae:00000000000000000000e000f060d860ccc0c780c390c790dcf0f070c1f0c000c000c0000000000000000000
+29af:00000000000000000000007060f061b033301e309c309e30f3b0e0f0f8300030003000300000000000000000
+29b0:00000000000000000e00b180404060409020882084208220812040c0404031a00e0000000000000000000000
+29b1:00000000ffe000000e0031a0404040c08120822084208820902060404040b1800e0000000000000000000000
+29b2:0e00110011000e000e0031a0404040c08120822084208820902060404040b1800e0000000000000000000000
+29b3:00800040ffe000400e8031a0404040c08120822084208820902060404040b1800e0000000000000000000000
+29b4:20004000ffe040002e0031a0404040c08120822084208820902060404040b1800e0000000000000000000000
+29b5:00000000000000000e0031804040404080208020ffe0802080204040404031800e0000000000000000000000
+29b6:00000000000000000e00358044404440842084208420842084204440444035800e0000000000000000000000
+29b7:00000000000000000e00318040405140912091209120912091205140404031800e0000000000000000000000
+29b8:00000000000000000e003180404060409020882084208220812040c0404031800e0000000000000000000000
+29b9:00000000000000000e003180404044408420842084208420bfa04040404031800e0000000000000000000000
+29ba:00000000000000000e0035804440444084208420ffe0802080204040404031800e0000000000000000000000
+29bb:00000000000000000e00b1a0404060c091208a2084208a20912060c04040b1a00e0000000000000000000000
+29bc:00000000000000000e00318040404040b120b220842089a091a04040404031800e0000000000000000000000
+29bd:04000e00150024800e00358044404440842084208420842084204440444035800e0004000000000000000000
+29be:00000000000000000e00318040404e409120a0a0a0a0a0a091204e40404031800e0000000000000000000000
+29bf:00000000000000000e00318040404e409f20bfa0bfa0bfa09f204e40404031800e0000000000000000000000
+29c0:00000000000000000e0031804240444088209020a020902088204440424031800e0000000000000000000000
+29c1:00000000000000000e003180484044408220812080a0812082204440484031800e0000000000000000000000
+29c2:00000000000000000c00330040804080806080508050805080604080408033000c0000000000000000000000
+29c3:00000000000000000c00330040804080807080708040807080704080408033000c0000000000000000000000
+29c4:00000000000000000000fff080308050809081108210841088109010a010c010fff000000000000000000000
+29c5:00000000000000000000fff0c010a01090108810841082108110809080508030fff000000000000000000000
+29c6:00000000000000000000fff08010b0d099908f10bfd0bfd08f109990b0d08010fff000000000000000000000
+29c7:00000000000000000000fff08010801086108f109f909f908f10861080108010fff000000000000000000000
+29c8:00000000000000000000fff0801080109f9090909090909090909f9080108010fff000000000000000000000
+29c9:00000000000000000000ff80808080809ff09090909090909090ff90101010101ff000000000000000000000
+29ca:06000f0006000000060006000f000f001980198030c030c060606060c030fff0fff000000000000000000000
+29cb:0000060006000f000f001980198030c030c060606060c030fff0fff00000fff0fff000000000000000000000
+29cc:0000060006000f000f001980198030c030c067606860c730c0b0cf30c030fff0fff000000000000000000000
+29cd:000000000000000000000000000006000600090009001080108020402040fff0fff000000000000000000000
+29ce:8000e0009800860081808060818086009820e0e083200c203020c02030200c20032000e00020000000000000
+29cf:000000000000000000000000000000a003a00ca030a0c0a030a00ca003a000a0000000000000000000000000
+29d0:0000000000000000000000000000a000b800a600a180a060a180a600b800a000000000000000000000000000
+29d1:000000000000000000008010c030e050f090f910f610f610f910f090e050c030801000000000000000000000
+29d2:000000000000000000008010c030a07090f089f087f087f089f090f0a070c030801000000000000000000000
+29d3:000000000000000000008010c030e070f0f0f9f0fff0fff0f9f0f0f0e070c030801000000000000000000000
+29d4:000000000000000000008010c020e040f080f900fe00fe00f900f080e040c020801000000000000000000000
+29d5:0000000000000000000080104030207010f009f007f007f009f010f020704030801000000000000000000000
+29d6:00000000000000000000fff04020204010800900060006000900108020404020fff000000000000000000000
+29d7:00000000000000000000fff07fe03fc01f800f00060006000f001f803fc07fe0fff000000000000000000000
+29d8:00000000030006000c00180018000c000600030006000c00180018000c000600030000000000000000000000
+29d9:0000000018000c0006000300030006000c0018000c0006000300030006000c00180000000000000000000000
+29da:000000000c6018c0318063006300318018c00c6018c0318063006300318018c00c6000000000000000000000
+29db:000000006300318018c00c600c6018c031806300318018c00c600c6018c03180630000000000000000000000
+29dc:0000000000000000000000000000300048008400840086108610492030c00000000000000000000000000000
+29dd:000000000000060009001080108030c049208610861086108610492030c00000000000000000000000000000
+29de:000000000000000000000600060036c04f2086108610861086104f2036c00600060000000000000000000000
+29df:0000000000000000000000000000204050a08f108f1050a02040000000000000000000000000000000000000
+29e0:00000000000000000000ffc0ffe0fff0e010e010e010e010e010e010e01060103ff000000000000000000000
+29e1:000000000000000000000000003000f003300c303030fff0fff000000000fff0fff000000000000000000000
+29e2:00000000000000000000000000000000c630c630c630c630c630c630c630fff0fff000000000000000000000
+29e3:000000000000000000000000000006600cc0ffe0ffe019803300ffe0ffe06600cc0000000000000000000000
+29e4:000000001c203e6067c04380000006600cc0ffe0ffe019803300ffe0ffe06600cc0000000000000000000000
+29e5:00000000000001100220fff0fff004400880fff0fff011002200fff0fff04400880000000000000000000000
+29e6:0000000000000000000000000000c030c030fff0fff0c030c030fff0fff0c030c03000000000000000000000
+29e7:000000000000060006000600fff0fff00600060006000600fff0fff006000600060000000000000000000000
+29e8:0000000000000000fff0fc30fc307c607c603cc03cc01d801d800f000f000600060000000000000000000000
+29e9:0000000000000000fff0c3f0c3f063e063e033c033c01b801b800f000f000600060000000000000000000000
+29ea:0000000006000f001f803fc07fe0fff07fe03fc01fc00f00666036c01f800f00060000000000000000000000
+29eb:040004000e000e001f001f003f803f807fc07fc0ffe0ffe07fc07fc03f803f801f001f000e000e0004000400
+29ec:000000001f803fc070e060606060606070e03fc01f800600666036c01f800f00060000000000000000000000
+29ed:000000001f803fc07fe07fe07fe07fe07fe03fc01f800600666036c01f800f00060000000000000000000000
+29ee:000000007fe0060006007fe07fe0606060606060606060607fe07fe0060006007fe000000000000000000000
+29ef:000000007fe0060006007fe07fe07fe07fe07fe07fe07fe07fe07fe0060006007fe000000000000000000000
+29f0:000000007fe0060006000f00198020c06060c0306060204019c00f00060006007fe000000000000000000000
+29f1:000000007fe0060006000f001f803fc07fe0fff07fe03fc01fc00f00060006007fe000000000000000000000
+29f2:000000007fe0060006000f0030c06060c030c030c030606030c00f00060006007fe000000000000000000000
+29f3:000000007fe0060006000f003fc07fe0fff0fff0fff07fe03fc00f00060006007fe000000000000000000000
+29f4:00000000000000000000c000c18000c00060fff0fff0006000c0c180c0000000000000000000000000000000
+29f5:000000001800180018000c000c000c0006000600060003000300030001800180018000000000000000000000
+29f6:0000fc00fd80018001800300030003000600060006000c000c000c0018001800180000000000000000000000
+29f7:000000001800180018000c000c000c003fc03fc0060003000300030001800180018000000000000000000000
+29f8:00000180018001800300030003000600060006000c000c000c00180018001800300030003000000000000000
+29f9:00003000300030001800180018000c000c000c00060006000600030003000300018001800180000000000000
+29fa:0000000000000000000000001980198019801980fff0fff01980198019801980000000000000000000000000
+29fb:0000000000000000000000006660666066606660fff0fff06660666066606660000000000000000000000000
+29fc:00000000000000000060006000c0018006001800600018000600018000c00060006000000000000000000000
+29fd:0000000000000000600060003000180006000180006001800600180030006000600000000000000000000000
+29fe:00000000000000000000000000000000060006001f801f800600060000000000000000000000000000000000
+29ff:00000000000000000000000000000000000000001f801f800000000000000000000000000000000000000000
+2a00:00000000000000000e00318040404040802084208e20842080204040404031800e0000000000000000000000
+2a01:00000000000000000e0035804440444084208420ffe0842084204440444035800e0000000000000000000000
+2a02:00000000000000000e003180404060c091208a2084208a20912060c0404031800e0000000000000000000000
+2a03:00000000000000000000c030c030c030c030c030c030c630c630c030c030c030c0306060606070e03fc00f00
+2a04:00000000000000000000c030c030c030c030c630c630dfb0dfb0c630c630c030c0306060606070e03fc00f00
+2a05:00000000000000000000fff0fff0c030c030c030c030c030c030c030c030c030c030c030c030c030c030c030
+2a06:00000000000000000000c030c030c030c030c030c030c030c030c030c030c030c030c030c030c030fff0fff0
+2a07:000000000a000a000a000a0015001500150015002a802a802a802a805140514051405140a0a0a0a0a0a0a0a0
+2a08:00000000a0a0a0a0a0a0a0a051405140514051402a802a802a802a8015001500150015000a000a000a000a00
+2a09:0000000080204040404020802080110011000a000a00040004000a000a001100110020802080404040408020
+2a0a:0000000000007fe0602030201f0038804c4047404740444028801f00202040207fe000000000000000000000
+2a0b:000001e003e0070006007fe0662036001e000e00070007000e001600260046207fe006000e007c0078000000
+2a0c:000080f081f093809300fb0013001300130003000300030003000300030003000300030007003e003c000000
+2a0d:000001e003e00700060006000600060006007fe0060006000600060006000600060006000e007c0078000000
+2a0e:000001e003e0070006000600060006007fe0060006007fe00600060006000600060006000e007c0078000000
+2a0f:000001e003e00700060006000600063006c007000e003600c600060006000600060006000e007c0078000000
+2a10:000001e003e00700060006001f80264026404600460046004600260026001f80060006000e007c0078000000
+2a11:000003c007c00e000c000c000c008c408ce08df04c404c404c803f000c000c000c000c001c00f800f0000000
+2a12:000001e003e007000600060007e00020002000200620062000200020002007e0060006000e007c0078000000
+2a13:000001e003e00700060006000780004000400020062006200020004000400780060006000e007c0078000000
+2a14:000001e003e007000600060007c00620062000100310031000100620062007c0060006000e007c0078000000
+2a15:000001e003e00700060006001f80204020404020462046204020204020401f80060006000e007c0078000000
+2a16:000001e003e00700060006007fe0462046204620462046204620462046207fe0060006000e007c0078000000
+2a17:000000f001f00380030003001b0033006300ffe0fff0633033301b30036003000300030007003e003c000000
+2a18:000001e003e0070006000600666036c01f800f0006000f001f8036c066600600060006000e007c0078000000
+2a19:000001e003e0070006001f803fc076e066606660666066606660666066606660666006000e007c0078000000
+2a1a:000001e003e00700060066606660666066606660666066606660666076e03fc01f8006000e007c0078000000
+2a1b:3fc0000001e003e0070006000600060006000600060006000600060006000600060006000e007c0078000000
+2a1c:000001e003e0070006000600060006000600060006000600060006000600060006000e007c00780000003fc0
+2a1d:000000000000000000008010c030a050909089108610861089109090a050c030801000000000000000000000
+2a1e:0030007000f001b0033006300c30183030306030c030c0306030303018300c300630033001b000f000700030
+2a1f:000000000000000000000000060009001080108009000600000006000900108010801c800480090012000c00
+2a20:0000000000009c00ce00e700738039c01ce00e700e701ce039c07380e700ce009c0000000000000000000000
+2a21:0000000008000c000e000f000d800cc00c000c000c000c000c000c000c000c000c000c000c000c000c000c00
+2a22:000000000600090009000600000006000600060006007fe07fe0060006000600060000000000000000000000
+2a23:000004000e001b00318060c0000006000600060006007fe07fe0060006000600060000000000000000000000
+2a24:0000000000001c203e6067c0438006000600060006007fe07fe0060006000600060000000000000000000000
+2a25:000000000000000000000000000006000600060006007fe07fe0060006000600060000000000060006000000
+2a26:0000000000000000000006000600060006007fe07fe006000600060006001c203e6067c04380000000000000
+2a27:000000000000000000000000000006000600060006007fe07fe0060006f00610061000f00080008000f00000
+2a28:000000000000000000000000000006000600060006007fe07fe006000f001f80060000000000000000000000
+2a29:0000000000000000000000000600060002000c0000007fe07fe0000000000000000000000000000000000000
+2a2a:000000000000000000000000000000000000000000007fe07fe0000000000600060000000000000000000000
+2a2b:000000000000000000000000000060006000000000007fe07fe0000000000060006000000000000000000000
+2a2c:000000000000000000000000000000600060000000007fe07fe0000000006000600000000000000000000000
+2a2d:000000000000000000001c002000460046008600bfc0bfc086004600460020001c0000000000000000000000
+2a2e:00000000000000000000038000400620062006103fd03fd00610062006200040038000000000000000000000
+2a2f:000000000000000000000000204070e039c01f800f001f8039c070e020400000000000000000000000000000
+2a30:0000000000000000000006000600606030c019800f0006000f00198030c06060000000000000000000000000
+2a31:0000000000000000000000000000606030c019800f0006000f00198030c0606000003fc00000000000000000
+2a32:0000000000000000000000000000606030c019800f0006000f00198030c060603fc000000000000000000000
+2a33:00000000000000000000000031801b008e20ce607bc031807bc0ce608e201b00318000000000000000000000
+2a34:00000000000000001c002000400058608cc08780830087808cc05860400020001c0000000000000000000000
+2a35:000000000000000003800040002061a033101e100c101e10331061a000200040038000000000000000000000
+2a36:04000e001b00318060c000001f802040402050a0891086108610891050a0402020401f800000000000000000
+2a37:000000000000000000001f8020404f2050a0a950a650a650a95050a04f2020401f8000000000000000000000
+2a38:000000000000000000001f802040462046208010bfd0bfd080104620462020401f8000000000000000000000
+2a39:060006000900090009001080108010802040264026405fa05fa0462086108010fff000000000000000000000
+2a3a:060006000900090009001080108010802040204020404f204f20402080108010fff000000000000000000000
+2a3b:06000600090009000900108010801080204030c039c04f2046204f209990b0d0fff000000000000000000000
+2a3c:00000000000000000000000000000000000000600060006000607fe07fe00000000000000000000000000000
+2a3d:00000000000000000000000000000000000060006000600060007fe07fe00000000000000000000000000000
+2a3e:0000000000000000000000000000000006000900090006000000000006000900090007000300060018000000
+2a3f:000000000000e070e0706060606060606060606060606060606060606060fff0fff000000000000000000000
+2a40:000000000000000000001f803fc070e060606060666066606060606060606060606000000000000000000000
+2a41:0000000000000000000060606060606060606f606f6060606060606070e03fc01f8000000000000000000000
+2a42:0000000000003fc0000060606060606060606060606060606060606070e03fc01f8000000000000000000000
+2a43:0000000000003fc000001f803fc070e060606060606060606060606060606060606000000000000000000000
+2a44:000000000000000000001f803fc070e06060c030c030c630c630c930c930d0b0d0b000000000000000000000
+2a45:00000000000000000000d0b0d0b0c930c930c630c630c030c030606070e03fc01f8000000000000000000000
+2a46:0000606060606060606060606060606070e03fc01f8000001f803fc070e06060606060606060606060606060
+2a47:00001f803fc070e060606060606060606060606060600000606060606060606060606060606070e03fc01f80
+2a48:000060606060606060606060606070e03fc01f8000003fc000001f803fc070e0606060606060606060606060
+2a49:00001f803fc070e060606060606060606060606000003fc0000060606060606060606060606070e03fc01f80
+2a4a:00000000000000000000c630c630c630c630c630c630c630c630c630c6307fe039c000000000000000000000
+2a4b:0000000000000000000039c07fe0c630c630c630c630c630c630c630c630c630c63000000000000000000000
+2a4c:00000000000000000000fff06060606060606060606060606060606070e03fc01f8000000000000000000000
+2a4d:000000000000000000001f803fc070e060606060606060606060606060606060fff000000000000000000000
+2a4e:00000000000000000000fff0fff0c030c030dfb0d9b0d9b0d9b0d9b0d9b0d9b0d9b000000000000000000000
+2a4f:00000000000000000000d9b0d9b0d9b0d9b0d9b0d9b0d9b0dfb0c030c030fff0fff000000000000000000000
+2a50:00000000000000000000fff0606069607fe0696069607fe06960606070e03fc01f8000000000000000000000
+2a51:0000000000000600060000000000060006000f000f001980198030c030c06060606000000000000000000000
+2a52:00000000000006000600000000006060606030c030c0198019800f000f000600060000000000000000000000
+2a53:00000000000000000000000000000e000e001b001b00318035806ac06ac0d160d16000000000000000000000
+2a54:0000000000000000000000000000d160d1606ac06ac0358031801b001b000e000e0000000000000000000000
+2a55:00000000000000000000000000000a000a00150015002a802a8051405140a0a0a0a000000000000000000000
+2a56:0000000000000000000000000000a0a0a0a0514051402a802a80150015000a000a0000000000000000000000
+2a57:00000000000000000000c010c030c060c0c0c180c300c600cc00d800f000e000c00000000000000000000000
+2a58:000000000000000000000030007000f001b0033006300c30183030306030c030803000000000000000000000
+2a59:000000000000000000006060606036c036c01f80198019801f8036c036c06060606000000000000000000000
+2a5a:0000000000000000000000000000060006000f000f001f801f8036c036c06660666000000000000000000000
+2a5b:00000000000000000000000000006660666036c036c01f801f800f000f000600060000000000000000000000
+2a5c:0000000000000000000000000000060006000f000f0019801980fff030c06060606000000000000000000000
+2a5d:00000000000000000000000000006060606030c0fff0198019800f000f000600060000000000000000000000
+2a5e:00003fc03fc000003fc03fc00000060006000f000f001980198030c030c06060606000000000000000000000
+2a5f:0000000000000000000000000000060006000f000f001980198030c030c06060606000003fc03fc000000000
+2a60:000000000000000000000000060006000f000f001980198030c030c06060606000003fc03fc000003fc03fc0
+2a61:00000000000000000000000000000000000030c030c0198019800f000f000600060000003fc03fc000000000
+2a62:00003fc03fc000003fc03fc000006060606030c030c0198019800f000f000600060000000000000000000000
+2a63:0000000000000000000000006060606030c030c0198019800f000f000600060000003fc03fc000003fc03fc0
+2a64:0030007000f001b0033006300c30183030306030fff0fff06030303018300c300630033001b000f000700030
+2a65:c000e000f000d800cc00c600c300c180c0c0c060fff0fff0c060c0c0c180c300c600cc00d800f000e000c000
+2a66:0000000000000000000000000000000000007fe07fe0000000007fe07fe00000060006000000000000000000
+2a67:00000000000000000600060000007fe07fe0000000007fe07fe0000000007fe07fe000000000000000000000
+2a68:00000000000000001980198019807fe07fe0198019807fe07fe0198019807fe07fe019801980000000000000
+2a69:00000000000000002640264026407fe07fe0264026407fe07fe0264026407fe07fe026402640000000000000
+2a6a:0000000000000000000006000600000000001c203e6036c067c0438000000000000000000000000000000000
+2a6b:000000000000000000c000c0000000001c203e6036c067c04380000000003000300000000000000000000000
+2a6c:00000000000000001c203e6036c067c0438000007fe000001c203e6036c067c0438000000000000000000000
+2a6d:000006000600000000001c203e6036c067c0438000007fe07fe0000000007fe07fe000000000000000000000
+2a6e:000030c019800f003fc03fc00f00198030c0000000007fe07fe0000000007fe07fe000000000000000000000
+2a6f:000006000f001980000000001c203e6067c04380000000001c203e6067c04380000000000000000000000000
+2a70:00001c203e6067c0438000001c203e6067c0438000007fe07fe0000000007fe07fe000000000000000000000
+2a71:000000007fe07fe0000000007fe07fe000000600060006003fc03fc006000600060000000000000000000000
+2a72:000000000600060006003fc03fc006000600060000007fe07fe0000000007fe07fe000000000000000000000
+2a73:000000000000000000007fe07fe0000000007fe07fe000001c203e6067c04380000000000000000000000000
+2a74:0000000000000000000000000000000000006de06de0000000006de06de00000000000000000000000000000
+2a75:000000000000000000000000000000000000fbe0fbe000000000fbe0fbe00000000000000000000000000000
+2a76:000000000000000000000000000000000000eee0eee000000000eee0eee00000000000000000000000000000
+2a77:00000000000030c030c0000000007fe07fe0000000007fe07fe00000000030c030c000000000000000000000
+2a78:000000000000db60db6000000000ffe0ffe000000000ffe0ffe000000000ffe0ffe000000000000000000000
+2a79:0000000000000000000000000000006001c007001e60789078901e60070001c0006000000000000000000000
+2a7a:000000000000000000000000000030001c00070033c048f048f033c007001c00300000000000000000000000
+2a7b:3c007e00c30006000c001800000018e001c007001e00780078001e00070001c0006000000000000000000000
+2a7c:03c007e00c30006000c001800000618038000e00078001e001e007800e003800700000000000000000000000
+2a7d:0000000000000000006001c007001e00780078001e00070071c01c60070001c0006000000000000000000000
+2a7e:0000000000000000600038000e00078001e001e007800e0038e063800e003800600000000000000000000000
+2a7f:0000000000000000006001c007001e00786078601e00070071c01c60070001c0006000000000000000000000
+2a80:0000000000000000600038000e00078061e061e007800e0038e063800e003800600000000000000000000000
+2a81:0000000000000000606061c007001e00780078001e00070071c01c60070001c0006000000000000000000000
+2a82:0000000000000000606038600e00078001e001e007800e0038e063800e003800600000000000000000000000
+2a83:0000006000600000006001c007001e00780078001e00070071c01c60070001c0006000000000000000000000
+2a84:0000600060000000600038000e00078001e001e007800e0038e063800e003800600000000000000000000000
+2a85:006001c007001e00780078001e00070001c0006000001c203e6067c0438000001c203e6067c0438000000000
+2a86:600038000e00078001e001e007800e003800600000001c203e6067c0438000001c203e6067c0438000000000
+2a87:000000000000006001c007001e00780078001e00070001c000e0018003007fe07fe018003000000000000000
+2a88:000000000000600038000e00078001e001e007800e0038007000018003007fe07fe018003000000000000000
+2a89:006001c007001e00780078001e00070001c0016001001d203e6067c0438004001c203e606fc04b8008001000
+2a8a:600038000e00078001e001e007800e003800610001001d203e6067c0438004001c203e606fc04b8008001000
+2a8b:0000000001e00f0078000f0001e000007fe0000000007fe0000078000f0001e00f0078000000000000000000
+2a8c:0000000078000f0001e00f00780000007fe0000000007fe0000001e00f0078000f0001e00000000000000000
+2a8d:006001c007001e00780078001e00070001c0006000001c203e6067c0438000007fe07fe00000000000000000
+2a8e:600038000e00078001e001e007800e003800600000001c203e6067c0438000007fe07fe00000000000000000
+2a8f:000001e00f0078000f0001e000001c203e6067c04380000078000f0001e00f00780000000000000000000000
+2a90:000078000f0001e00f00780000001c203e6067c04380000001e00f0078000f0001e000000000000000000000
+2a91:000001e00f0078000f0001e078000f0001e00f00780000007fe07fe0000000007fe07fe00000000000000000
+2a92:000078000f0001e00f00780001e00f0078000f0001e000007fe07fe0000000007fe07fe00000000000000000
+2a93:000001e00f0078000f0001e078000f0001e078000f0001e00f00780001e00f00780000000000000000000000
+2a94:000078000f0001e00f00780001e00f00780001e00f0078000f0001e078000f0001e000000000000000000000
+2a95:0000000000000000006001c007001c6071c007001e00780078001e00070001c0006000000000000000000000
+2a96:0000000000000000600038000e00638038e00e00078001e001e007800e003800600000000000000000000000
+2a97:0000000000000000006001c007001c6071c007001e00786078601e00070001c0006000000000000000000000
+2a98:0000000000000000600038000e00638038e00e00078061e061e007800e003800600000000000000000000000
+2a99:00007fe07fe000007fe07fe00000006001c007001e00780078001e00070001c0006000000000000000000000
+2a9a:00007fe07fe000007fe07fe00000600038000e00078001e001e007800e003800600000000000000000000000
+2a9b:0000006001c007001c6071c007001c6071c007001e00780078001e00070001c0006000000000000000000000
+2a9c:0000600038000e00638038e00e00638038e00e00078001e001e007800e003800600000000000000000000000
+2a9d:00001c203e6036c067c043800000006001c007001e00780078001e00070001c0006000000000000000000000
+2a9e:00001c203e6036c067c043800000600038000e00078001e001e007800e003800600000000000000000000000
+2a9f:00001c203e6036c067c04380006001c007001e00780078001e00070001c000607fe07fe000007fe07fe00000
+2aa0:00001c203e6036c067c04380600038000e00078001e001e007800e00380060007fe07fe000007fe07fe00000
+2aa1:0000000000000000000000000000006001c007201e6079c079c01e60072001c0006000000000000000000000
+2aa2:0000000000000000000000000000600038004e00678039e039e067804e003800600000000000000000000000
+2aa3:00000000000000000e701ce039c07380e700e700738039c01ce00e700000fff0fff000000000000000000000
+2aa4:00000000000000000000000060c031801b000e001b0031801b000e001b00318060c000000000000000000000
+2aa5:000000000000000000000000000000008020c06060c031801b00318060c0c060802000000000000000000000
+2aa6:000000000000000000000000000000c003a00e203c10f010f0103c100e2003a000c000000000000000000000
+2aa7:000000000000000000000000000030005c00470083c080f080f083c047005c00300000000000000000000000
+2aa8:000000000000000000c003a00e203c10f010f0103c100e20e3a038c00e00038000c000000000000000000000
+2aa9:000000000000000030005c00470083c080f080f083c047005c7031c007001c00300000000000000000000000
+2aaa:0000000000000000000000000000006001c007001e007fe07fe01e00070001c0006000000000000000000000
+2aab:0000000000000000000000000000600038000e0007807fe07fe007800e003800600000000000000000000000
+2aac:0000000000000000006001c007001e007fe07fe01e00070001c0006000007fe07fe000000000000000000000
+2aad:0000000000000000600038000e0007807fe07fe007800e003800600000007fe07fe000000000000000000000
+2aae:000000000000000006000f00090079e079e0000000007fe07fe0000000007fe07fe000000000000000000000
+2aaf:00000000000000000000006001c007803c00e0003c00078001c000600000ffe0ffe000000000000000000000
+2ab0:00000000000000000000c00070003c00078000e007803c007000c0000000ffe0ffe000000000000000000000
+2ab1:00000000000000000000006001c007803c00e0003c00078001c003600600ffe0ffe030006000000000000000
+2ab2:00000000000000000000c00070003c00078000e007803c007000c0c00180ffe0ffe00c001800000000000000
+2ab3:00000000006001c007803c00e0003c00078001c000600000ffe0ffe00000ffe0ffe000000000000000000000
+2ab4:00000000c00070003c00078000e007803c007000c0000000ffe0ffe00000ffe0ffe000000000000000000000
+2ab5:00000000006001c007803c00e0003c00078001c006600600ffe0ffe01800ffe0ffe060006000000000000000
+2ab6:00000000c00070003c00078000e007803c007000c1800180ffe0ffe00600ffe0ffe018001800000000000000
+2ab7:0000006001c007803c00e0003c00078001c000601c203e6067c043801c203e6067c043800000000000000000
+2ab8:0000c00070003c00078000e007803c007000c0001c203e6067c043801c203e6067c043800000000000000000
+2ab9:0000006001c007803c00e0003c00078001c002601e203e6067c047801c203e606fc04b801000100000000000
+2aba:0000c00070003c00078000e007803c007080c0801ca03f6067c043801e203e6067c047800400040000000000
+2abb:000000000000000000000000031006301ce07380ce0073801ce0067003100000000000000000000000000000
+2abc:0000000000000000000000008c00c60073801ce007301ce07380e6008c000000000000000000000000000000
+2abd:0000000000000000000007e01fe03800600061806180600038001fe007e00000000000000000000000000000
+2abe:000000000000000000007e007f8001c0006018601860006001c07f807e000000000000000000000000000000
+2abf:000007e01fe03800600060006000600038001fe007e000000600060006003fc03fc006000600060000000000
+2ac0:00007e007f8001c0006000600060006001c07f807e0000000600060006003fc03fc006000600060000000000
+2ac1:000007e01fe03800600060006000600038001fe007e0000030c019800f0006000f00198030c0000000000000
+2ac2:00007e007f8001c0006000600060006001c07f807e00000030c019800f0006000f00198030c0000000000000
+2ac3:000006000600000007e01fe03800600060006000600038001fe007e000007fe07fe000000000000000000000
+2ac4:00000600060000007e007f8001c0006000600060006001c07f807e0000007fe07fe000000000000000000000
+2ac5:0000000007e01fe03800600060006000600038001fe007e000007fe07fe000007fe07fe00000000000000000
+2ac6:000000007e007f8001c0006000600060006001c07f807e0000007fe07fe000007fe07fe00000000000000000
+2ac7:0000000007e01fe03800600060006000600038001fe007e000001c203e6036c067c043800000000000000000
+2ac8:000000007e007f8001c0006000600060006001c07f807e0000001c203e6036c067c043800000000000000000
+2ac9:000007e01fe03800600060006000600038001fe007e000001c203e6067c043801c203e6067c0438000000000
+2aca:00007e007f8001c0006000600060006001c07f807e0000001c203e6067c043801c203e6067c0438000000000
+2acb:0000000007e01fe03800600060006000600038001fe007e001807fe07fe006007fe07fe01800300000000000
+2acc:000000007e007f8001c0006000600060006001c07f807ec001807fe07fe003007fe07fe006000c0000000000
+2acd:000000000000000000000000000000000000fff0fff0c000c000c000c000fc00fc0000000000000000000000
+2ace:000000000000000000000000000000000000fff0fff0003000300030003003f003f000000000000000000000
+2acf:0000000000000000000007e01fe03860606060606060606038601fe007e00000000000000000000000000000
+2ad0:000000000000000000007e007f8061c0606060606060606061c07f807e000000000000000000000000000000
+2ad1:000000000000000007e01fe03860606060606060606038601fe007e000007fe07fe000000000000000000000
+2ad2:00000000000000007e007f8061c0606060606060606061c07f807e0000007fe07fe000000000000000000000
+2ad3:000007e01fe038006000600038001fe007e000007e007f8001c00060006001c07f807e000000000000000000
+2ad4:00007e007f8001c00060006001c07f807e00000007e01fe038006000600038001fe007e00000000000000000
+2ad5:000007e01fe038006000600038001fe007e0000007e01fe038006000600038001fe007e00000000000000000
+2ad6:00007e007f8001c00060006001c07f807e0000007e007f8001c00060006001c07f807e000000000000000000
+2ad7:000000000000000000000000e0e0f3e03b801b001b001b001b003b80f3e0e0e0000000000000000000000000
+2ad8:000000000000000000000000e0e0f3e03b801b007fc07fc01b003b80f3e0e0e0000000000000000000000000
+2ad9:000000000000000000000000000000000f003fc036c066606660666066606660000000000000000000000000
+2ada:00000000000000003fc03fc0060006000f003fc036c066606660666066606660060006000600000000000000
+2adb:000000000000000006000600060006000f003fc036c066606660666066606660060006000600000000000000
+2adc:0000000000000000060006000600066006c007006e607660e66036c03fc00f00000000000000000000000000
+2add:000000000000000006000600060006000600060066606660666036c03fc00f00000000000000000000000000
+2ade:00000000000000000000000000600060006000600fe00fe00060006000600060000000000000000000000000
+2adf:000000000000000000000000000000007fe07fe0060006000600060006000000000000000000000000000000
+2ae0:00000000000000000000000000000000060006000600060006007fe07fe00000000000000000000000000000
+2ae1:000000000c000c000c000ce00d100d000ce00c100d100ce00c00ffc0ffc00000000000000000000000000000
+2ae2:00000000000000000000c000c000fff0fff0c000fff0fff0c000fff0fff0c000c00000000000000000000000
+2ae3:0000000000000000000003300330033003300330ff30ff300330033003300330033000000000000000000000
+2ae4:00000000000000000000003000300030fff0fff000300030fff0fff000300030003000000000000000000000
+2ae5:00000000000000000000033003300330ff30ff3003300330ff30ff3003300330033000000000000000000000
+2ae6:00000000000000000000cc00cc00cc00cc00cc00fff0fff0cc00cc00cc00cc00cc0000000000000000000000
+2ae7:00000000000000000000fff0fff000000000fff0fff006000600060006000600060000000000000000000000
+2ae8:00000000000000000000060006000600060006000600fff0fff000000000fff0fff000000000000000000000
+2ae9:0000000000000600060006000600fff0fff000000000fff0fff0060006000600060000000000000000000000
+2aea:000000000000000000000000fff0fff019801980198019801980198019801980198000000000000000000000
+2aeb:000000000000000000000000198019801980198019801980198019801980fff0fff000000000000000000000
+2aec:00000000000000000000fff0fff000300030fff0fff000300030003000300030003000000000000000000000
+2aed:00000000000000000000fff0fff0c000c000fff0fff0c000c000c000c000c000c00000000000000000000000
+2aee:00000000000006000600060036001e000e0006000700078006c0060006000600060000000000000000000000
+2aef:000000000f0010801080108010800f0006000600060006000600060006000600060000000000000000000000
+2af0:000000000600060006000600060006000600060006000f0010801080108010800f0000000000000000000000
+2af1:000000003fc03fc006000600060006000600060006000f0010801080108010800f0000000000000000000000
+2af2:000000000000198019801980198019801980fff0fff019801980198019801980198000000000000000000000
+2af3:000000000000198019801980198019807d80dfb0dfb01be01980198019801980198000000000000000000000
+2af4:0000000000006660666066606660666066606660666066606660666066606660666000000000000000000000
+2af5:000000000000666066606660666066606660fff0fff066606660666066606660666000000000000000000000
+2af6:000000000e000e000e000000000000000e000e000e000000000000000e000e000e0000000000000000000000
+2af7:0000000000000180030006600cc0198033306660ccc06660333019800cc00660030001800000000000000000
+2af8:00000000000018000c00660033001980ccc0666033306660ccc01980330066000c0018000000000000000000
+2af9:0000006001c007001e00780078001e00070071c01c60070071c01c60070001c0006000000000000000000000
+2afa:0000600038000e00078001e001e007800e0038e063800e0038e063800e003800600000000000000000000000
+2afb:000000000000333033303330333033306660666066606660ccc0ccc0ccc0ccc0ccc000000000000000000000
+2afc:0000000066606660666066606660666066606660666066606660666066606660666066606660666066600000
+2afd:0000000000000cc00cc00cc00cc00cc019801980198019803300330033003300330000000000000000000000
+2afe:0000000000000000000000001f801980198019801980198019801980198019801f8000000000000000000000
+2aff:00001f80198019801980198019801980198019801980198019801980198019801f8000000000000000000000
+2b00:000000000000000000000ff0041002100210041008d011302210440088005000200000000000000000000000
+2b01:00000000000000000000ff008200840084008200b100c88084400220011000a0004000000000000000000000
+2b02:0000000000000000000020005000880044002210113008d004100210021004100ff000000000000000000000
+2b03:00000000000000000000004000a0011002208440c880b1008200840084008200ff0000000000000000000000
+2b04:00000000000000000000000000000900198029404f2080104f20294019800900000000000000000000000000
+2b05:00000000000000000000000000000800180038007ff0fff07ff0380018000800000000000000000000000000
+2b06:0000000006000f001f803fc07fe0fff01f801f801f801f801f801f801f801f801f8000000000000000000000
+2b07:000000001f801f801f801f801f801f801f801f801f80fff07fe03fc01f800f00060000000000000000000000
+2b08:000000000000000000000ff007f003f003f007f00ff01f303e107c00f8007000200000000000000000000000
+2b09:00000000000000000000ff00fe00fc00fc00fe00ff00cf8087c003e001f000e0004000000000000000000000
+2b0a:0000000000000000000020007000f8007c003e101f300ff007f003f003f007f00ff000000000000000000000
+2b0b:00000000000000000000004000e001f003e087c0cf80ff00fe00fc00fc00fe00ff0000000000000000000000
+2b0c:00000000000000000000000000000900198039c07fe0fff07fe039c019800900000000000000000000000000
+2b0d:06000f001f803fc07fe0fff01f801f801f801f801f80fff07fe03fc01f800f00060000000000000000000000
+2b0e:00000000000000000000000000000000ffc0ffc000c000c000c003f001e000c0000000000000000000000000
+2b0f:00000000000000000000000000c001e003f000c000c000c0ffc0ffc000000000000000000000000000000000
+2b10:000000000000000000000000000000003ff03ff0300030003000fc0078003000000000000000000000000000
+2b11:00000000000000000000000030007800fc003000300030003ff03ff000000000000000000000000000000000
+2b12:00000000000000000000fff0fff0fff0fff0fff0fff080108010801080108010fff000000000000000000000
+2b13:00000000000000000000fff080108010801080108010fff0fff0fff0fff0fff0fff000000000000000000000
+2b14:00000000000000000000fff0bff09ff08ff087f083f081f080f0807080308010fff000000000000000000000
+2b15:00000000000000000000fff08010c010e010f010f810fc10fe10ff10ff90ffd0fff000000000000000000000
+2b16:0000000000000000000006000d001c803c407c20fc10fc107c203c401c800d00060000000000000000000000
+2b17:0000000000000000000006000b00138023c043e083f083f043e023c013800b00060000000000000000000000
+2b18:0000000000000000000006000f001f803fc07fe0fff080104020204010800900060000000000000000000000
+2b19:00000000000000000000060009001080204040208010fff07fe03fc01f800f00060000000000000000000000
+2b1a:00000000000000000000aaa00010800000108000001080000010800000108000555000000000000000000000
+2b1b:00000000000000000000000000000003ffc003ffc003ffc003ffc003ffc003ffc003ffc003ffc003ffc003ffc003ffc003ffc0000000000000000000000000000000
+2b1c:00000000000000000000000000000003ffc002004002004002004002004002004002004002004002004002004002004003ffc0000000000000000000000000000000
+2b1d:0000000000000000000000000000000000000000060006000000000000000000000000000000000000000000
+2b1e:0000000000000000000000000000000000000f00090009000f00000000000000000000000000000000000000
+2b1f:000000000000000006000f001f803fc07fe07fe07fe03fc03fc03fc01f801f801f8000000000000000000000
+2b20:000000000000000006000900108020404020402040202040204030c0108010801f8000000000000000000000
+2b21:0000000000000600090010802040402040204020402040204020204010800900060000000000000000000000
+2b22:00000000000006000f001f803fc07fe07fe07fe07fe07fe07fe03fc01f800f00060000000000000000000000
+2b23:0000000000001f801f803fc03fc07fe07fe07fe07fe07fe07fe03fc03fc01f801f8000000000000000000000
+2b24:000000000000000000001f803fc07fe07fe0fff0fff0fff0fff07fe07fe03fc01f8000000000000000000000
+2b25:000000000000000000000000000004000e001f003f807fc03f801f000e000400000000000000000000000000
+2b26:000000000000000000000000000004000a00110020804040208011000a000400000000000000000000000000
+2b27:000000000000040004000e000e001f001f003f803f801f001f000e000e000400040000000000000000000000
+2b28:000000000000040004000a000a001100110020802080110011000a000a000400040000000000000000000000
+2b29:0000000000000000000000000000000006000f001f803fc01f800f0006000000000000000000000000000000
+2b2a:00000000000000000000060006000f000f001f801f800f000f00060006000000000000000000000000000000
+2b2b:0000000000000000000006000600090009001080108009000900060006000000000000000000000000000000
+2b2c:0000000000000000000000000f003fc07fe0fff0fff0fff0fff07fe03fc00f00000000000000000000000000
+2b2d:0000000000000000000000000f0030c040208010801080108010402030c00f00000000000000000000000000
+2b2e:000000000000000000000f001f803fc03fc07fe07fe07fe07fe03fc03fc01f800f0000000000000000000000
+2b2f:000000000000000000000f0010802040204040204020402040202040204010800f0000000000000000000000
+2b30:000000000000000000000000180033806440fff0fff064403380180000000000000000000000000000000000
+2b31:180030006000fff0fff060003000180030006000fff0fff060003000180030006000fff0fff0600030001800
+2b32:00000000000000000000000001c016b024904490fff04490249016b001c00000000000000000000000000000
+2b33:000000000000000000000000018000c0106028b04530826000c0018000000000000000000000000000000000
+2b34:0000000000000000000000000000124024404840fff0fff04840244012400000000000000000000000000000
+2b35:000000000000000000000000000012a024a048a0fff0fff048a024a012a00000000000000000000000000000
+2b36:0000000000000000000000000000123024304830fff0fff04830243012300000000000000000000000000000
+2b37:0000000000000000000000000000120024004800edb0edb04800240012000000000000000000000000000000
+2b38:000000000000000000000000180030006000d550d55060003000180000000000000000000000000000000000
+2b39:0000000000000000000000000000121022204240ff80ff804240222012100000000000000000000000000000
+2b3a:0000000000000000000000000000151025204540ff80ff804540252015100000000000000000000000000000
+2b3b:0000000000000000000000000000121024204840ff80ff804840242012100000000000000000000000000000
+2b3c:0000000000000000000000000000151029205140ff80ff805140292015100000000000000000000000000000
+2b3d:00000000000000000000000000002a9052a0a2c0ffc0ffc0a2c052a02a900000000000000000000000000000
+2b3e:000000000000000000000000000000001a10312060c0fff0fff060c031201a10000000000000000000000000
+2b3f:0000000000000000000000001800338066c0fc70f83060003000180000000000000000000000000000000000
+2b40:000000000000000003e003e00000000003e01be030006000fff0fff060003000180000000000000000000000
+2b41:0000000000000000438067c03e601c200000180030006000fff0fff060003000180000000000000000000000
+2b42:0000180030006000fff0fff060003000180000001c203e6067c043801c203e6067c043800000000000000000
+2b43:0000000000000000000000000000c00071801cc00760fff0fff007601cc07180c00000000000000000000000
+2b44:000000000000f000f8000c000c8006400620fff0fff0062006400c800c00f800f00000000000000000000000
+2b45:0000000000000000100010003ff0200040007ff0800080007ff0400020003ff0100010000000000000000000
+2b46:000000000000000000800080ffc000400020ffe000100010ffe000200040ffc0008000800000000000000000
+2b47:0000000000000000438067c03e601c200000018000c00060fff0fff0006000c0018000000000000000000000
+2b48:018000c00060fff0fff0006000c001800000438067c03e601c200000438067c03e601c200000000000000000
+2b49:00000000000000001c203e6067c043800000180030006000fff0fff060003000180000000000000000000000
+2b4a:180030006000fff0fff060003000180000001c203e6067c0438000001c203e6067c043800000000000000000
+2b4b:0000000000000000180030006000fff0fff06000300018000000438067c03e601c2000000000000000000000
+2b4c:0000000000000000018000c00060fff0fff0006000c001800000438067c03e601c2000000000000000000000
+2b4d:000000000000030006000c00180030007fe07fe000c00180230036003c003e003f0000000000000000000000
+2b4e:00000000000000000000030007800fc003000300060006000c000c0000000000000000000000000000000000
+2b4f:000000000000000000000c000c0006000600030003000fc00780030000000000000000000000000000000000
+2b50:00000000000000000000000000000000180000990000660000240000c30000c300002400006600009900001800000000000000000000000000000000000000000000
+2b51:0000000000000000000000000000000019800f003fc00f001980000000000000000000000000000000000000
+2b52:0000000000000000000000000000000011000e0031800e001100000000000000000000000000000000000000
+2b53:0000000000000000000000000f003f80ffc0ffe0fff0fff0ffe0ffc03f800f00000000000000000000000000
+2b54:0000000000000000000000000f003080c0408020801080108020c04030800f00000000000000000000000000
+2b55:000000003c0001ff8003c3c00600600c003018001818001818001830000c30000c30000c30000c1800181800181800180c003006006003c3c001ff80003c00000000
+2b56:0000000000000000000000000f003fc06060cf30d0b0d0b0cf3060603fc00f00000000000000000000000000
+2b57:000000000000000000001f803fc060606f60d0b0d0b0d0b0d0b06f6060603fc01f8000000000000000000000
+2b58:0000000000000000000000001f803fc030c0606060606060606030c03fc01f80000000000000000000000000
+2b59:000000000000000000001f803fc0606070e0c930c630c630c93070e060603fc01f8000000000000000000000
+2b5a:00000000000000000000038007c00c400c4019f018e03040300060006000c000c00000000000000000000000
+2b5b:00000000000038006c00c600c600030003000180018000c000c003f001e000c0000000000000000000000000
+2b5c:000000000000000000c001e003f000c000c0018001800300030006000600fc00fc0000000000000000000000
+2b5d:0000000000000000fc00fc0006000600030003000180018000c000c003f001e000c000000000000000000000
+2b5e:00000000000003000300060006000c000c001800180033f031f063e06e60f820c00000000000000000000000
+2b5f:00000000000000000000000000000c000c001800180033f031f063e06e60f820c00000000000000000000000
+2b60:000000000000000000000000100030007000ffe0ffe070003000100000000000000000000000000000000000
+2b61:0000000006000f001f803fc00600060006000600060006000600060006000600060000000000000000000000
+2b62:0000000000000000000000000100018001c0ffe0ffe001c00180010000000000000000000000000000000000
+2b63:00000000060006000600060006000600060006000600060006003fc01f800f00060000000000000000000000
+2b64:000000000000000000000000108030c070e0fff0fff070e030c0108000000000000000000000000000000000
+2b65:0000000006000f001f803fc006000600060006000600060006003fc01f800f00060000000000000000000000
+2b66:00000000000000000000f800f000f000f8009c000e000700038001c000e00070002000000000000000000000
+2b67:0000000000000000000001f000f000f001f0039007000e001c0038007000e000400000000000000000000000
+2b68:000000000000000000004000e000700038001c000e000700039001f000f000f001f000000000000000000000
+2b69:000000000000000000000020007000e001c0038007000e009c00f800f000f000f80000000000000000000000
+2b6a:000000000000000000000000100030007000edb0edb070003000100000000000000000000000000000000000
+2b6b:000006000f001f80060006000000000006000600060000000000060006000600000000000600060006000000
+2b6c:000000000000000000000000008000c000e0db70db7000e000c0008000000000000000000000000000000000
+2b6d:0000060006000600000000000600060006000000000006000600060000000000060006001f800f0006000000
+2b6e:0000000000001f000f001f003300610060006000606060606060204030c019800f0000000000000000000000
+2b6f:0000000000000f800f000f800cc0086000600060606060606060204030c019800f0000000000000000000000
+2b70:000000000000000000000000c400cc00dc00fff0fff0dc00cc00c40000000000000000000000000000000000
+2b71:000000003fc03fc006000f001f803fc006000600060006000600060006000600060000000000000000000000
+2b72:0000000000000000000000000230033003b0fff0fff003b00330023000000000000000000000000000000000
+2b73:000000000600060006000600060006000600060006003fc01f800f0006003fc03fc000000000000000000000
+2b76:00000000fc00fc000000f800f000f000f8009c000e000700038001c000e00070002000000000000000000000
+2b77:0000000003f003f0000001f000f000f001f0039007000e001c0038007000e000400000000000000000000000
+2b78:000000000000000000004000e000700038001c000e000700039001f000f000f001f0000003f003f000000000
+2b79:000000000000000000000020007000e001c0038007000e009c00f800f000f000f8000000fc00fc0000000000
+2b7a:0000000000000000000000000000124032407240fff0fff07240324012400000000000000000000000000000
+2b7b:0000000006000f001f803fc00600060006007fe07fe0060006007fe07fe00600060000000000000000000000
+2b7c:0000000000000000000000000000248024c024e0fff0fff024e024c024800000000000000000000000000000
+2b7d:00000000060006007fe07fe0060006007fe07fe00600060006003fc01f800f00060000000000000000000000
+2b7e:0000c400cc00dc00fff0fff0dc00cc00c4000230033003b0fff0fff003b00330023000000000000000000000
+2b7f:00000000fcc0fcc030c078c0fcc030c030c030c030c030c033f031e030c033f033f000000000000000000000
+2b80:000000000000100030007000fff0fff07000308010c000e0fff0fff000e000c0008000000000000000000000
+2b81:000000000000000030c078c0fcc030c030c030c030c030c030c030c033f031e030c000000000000000000000
+2b82:000000000000008000c000e0fff0fff000e010c030807000fff0fff070003000100000000000000000000000
+2b83:000000000000000030c031e033f030c030c030c030c030c030c030c0fcc078c030c000000000000000000000
+2b84:00000000100030007000fff0fff070003000100030007000fff0fff070003000100000000000000000000000
+2b85:000000000000000030c079e0fff030c030c030c030c030c030c030c030c030c030c000000000000000000000
+2b86:00000000008000c000e0fff0fff000e000c0008000c000e0fff0fff000e000c0008000000000000000000000
+2b87:000000000000000030c030c030c030c030c030c030c030c030c030c0fff079e030c000000000000000000000
+2b88:00000f003fc07be073e0e3f0c0008000000000008000c000e3f073e07be03fc00f0000000000000000000000
+2b89:000000000f003fc079e070e0e070c0308010e070e070e070e070e07060606060204000000000000000000000
+2b8a:00000f003fc07de07ce0fc70003000100000000000100030fc707ce07de03fc00f0000000000000000000000
+2b8b:00000000204060606060e070e070e070e070e0708010c030e07070e079e03fc00f0000000000000000000000
+2b8c:00000000100030007000fe00ff8071c0306010600060006001c03f803e000000000000000000000000000000
+2b8d:00000000000000000000018003c007e00ff0c180c180c180c180c180e3807f003e0000000000000000000000
+2b8e:000000000f803f807000c000c000c100c18071c03fe00fe001c0018001000000000000000000000000000000
+2b8f:0000000000000000000007c00fe01c7018301830183018301830ff007e003c00180000000000000000000000
+2b90:00000000000001f001f00030103030607060ffc0ffc070003000100000000000000000000000000000000000
+2b91:000000000000f800f800c000c08060c060e03ff03ff000e000c0008000000000000000000000000000000000
+2b92:000000000000f9f0f9f000300030003002300630cff0cff00600020000000000000000000000000000000000
+2b93:000000000000f9f0f9f0c000c000c000c400c600ff30ff300600040000000000000000000000000000000000
+2b94:00000000000000000000020003001f8023407240f84021f024e02c401f800c00040000000000000000000000
+2b95:00000000000000000000000000000100018001c0ffe0fff0ffe001c001800100000000000000000000000000
+2b97:fff080109f9040205fa046202640264026401680108010800900090009000600060000000000000000000000
+2b98:00000000000000000000000000e003200c40308041007f003f800fc003e000e0000000000000000000000000
+2b99:000000000000000000000000060006000d000d001c801c803c403e40792070a0606000000000000000000000
+2b9a:00000000000000000000000070004c00230010c008200fe01fc03f007c007000000000000000000000000000
+2b9b:000000000000000000000000606050e049e027c023c0138013800b000b000600060000000000000000000000
+2b9c:00000000000000000000000000e003e00fc03f807f007f003f800fc003e000e0000000000000000000000000
+2b9d:000000000000000000000000060006000f000f001f801f803fc03fc079e070e0606000000000000000000000
+2b9e:00000000000000000000000070007c003f001fc00fe00fe01fc03f007c007000000000000000000000000000
+2b9f:000000000000000000000000606070e079e03fc03fc01f801f800f000f000600060000000000000000000000
+2ba0:000000000000000000300030103030307030fff0fff070003000100000000000000000000000000000000000
+2ba1:0000000000000000c000c000c080c0c0c0e0fff0fff000e000c0008000000000000000000000000000000000
+2ba2:0000000000000000100030007000fff0fff07030303010300030003000000000000000000000000000000000
+2ba3:0000000000000000008000c000e0fff0fff0c0e0c0c0c080c000c00000000000000000000000000000000000
+2ba4:000000000c001e003f007f800c000c000c000c000c000c000c000c000c000ff00ff000000000000000000000
+2ba5:00000000030007800fc01fe0030003000300030003000300030003000300ff00ff0000000000000000000000
+2ba6:000000000ff00ff00c000c000c000c000c000c000c000c000c007f803f001e000c0000000000000000000000
+2ba7:00000000ff00ff000300030003000300030003000300030003001fe00fc00780030000000000000000000000
+2ba8:00000000000000000000000000000800181038307ff0ffe07fc0380018000800000000000000000000000000
+2ba9:000000000000000000000000000001008180c1c0ffe07ff03fe001c001800100000000000000000000000000
+2baa:00000000000000000000000000000800180038007fc0ffe07ff0383018100800000000000000000000000000
+2bab:00000000000000000000000000000100018001c03fe07ff0ffe0c1c081800100000000000000000000000000
+2bac:0000000000000000000004000e001f003f807fc00e000e000e000e000e000700038000000000000000000000
+2bad:0000000000000000000004000e001f003f807fc00e000e000e000e000e001c00380000000000000000000000
+2bae:00000000000000000000038007000e000e000e000e000e007fc03f801f000e00040000000000000000000000
+2baf:0000000000000000000038001c000e000e000e000e000e007fc03f801f000e00040000000000000000000000
+2bb0:00000000011001b00150011005100d10151027f0402080404080270014000c00040000000000000000000000
+2bb1:000000008800d800a80088008a008b008a80fe404020201010200e4002800300020000000000000000000000
+2bb2:0000000004000c001400270040808040402027f015100d1005100110015001b0011000000000000000000000
+2bb3:000000000200030002800e40102020104020fe408a808b008a008800a800d800880000000000000000000000
+2bb4:0000000000000800140022004100e38022002200220023f012200a40062003f0000000000000000000000000
+2bb5:00000000000001000280044008201c70044004400440fc40448025004600fc00000000000000000000000000
+2bb6:00000000000003f006200a40122023f0220022002200e3804100220014000800000000000000000000000000
+2bb7:000000000000fc00460025004480fc400440044004401c700820044002800100000000000000000000000000
+2bb8:000000000600090010803fc04020f0f0108010801f80000000001f80108010801f8000000000000000000000
+2bb9:00000000000000000000000000000000fff0801086108f109990b0d0a0508010fff000000000000000000000
+2bba:000000000000000000001ff010101010ff9090909090909090909ff080808080ff8000000000000000000000
+2bbb:000000000000000000001ff01ff01ff0fff09ff09ff09ff09ff09ff080808080ff8000000000000000000000
+2bbc:000000000000000000001ff01ff01ff0fff0fff0fff0fff0fff0fff0ff80ff80ff8000000000000000000000
+2bbd:00000000000000000000fff08010a050909089108610861089109090a0508010fff000000000000000000000
+2bbe:00000000000000000e0031804040404091208a2084208a2091204040404031800e0000000000000000000000
+2bbf:000000000000000000001f803fc060606060d9b0c630c630d9b0606060603fc01f8000000000000000000000
+2bc0:0000000000000000000000003fc03fc03fc03fc03fc03fc03fc03fc03fc03fc0000000000000000000000000
+2bc1:00000000000000000000000006000f001f803fc07fe07fe03fc01f800f000600000000000000000000000000
+2bc2:00000000000000001f801f801f803fc03fc03fc07fe07fe07fe03fc01f800f00060000000000000000000000
+2bc3:0000000000000000000000000f001f803fc07fe07fe07fe07fe03fc01f800f00000000000000000000000000
+2bc4:0000000000000000000006001f803fc03fc07fe07fe0fff0fff07fe07fe03fc03fc01f800600000000000000
+2bc5:00000000000000000000060006000f000f001f801f803fc03fc07fe07fe0fff0fff000000000000000000000
+2bc6:00000000000000000000fff0fff07fe07fe03fc03fc01f801f800f000f000600060000000000000000000000
+2bc7:00000000000000000000003000f003f00ff03ff0fff0fff03ff00ff003f000f0003000000000000000000000
+2bc8:00000000000000000000c000f000fc00ff00ffc0fff0fff0ffc0ff00fc00f000c00000000000000000000000
+2bc9:000000000000000080108020824082808300820086008a009200a200c200fff0020007000880088008800700
+2bca:000000000000000000001f803fc07fe07fe0fff0fff000000000000000000000000000000000000000000000
+2bcb:00000000000000000000000000000000000000000000fff0fff07fe07fe03fc01f8000000000000000000000
+2bcc:00000000000000000000000004000e000e001f007fc0ffe07fc01f000e000e00040000000000000000000000
+2bcd:000000000000000000000000802060c07bc03f803f801f003f803f807bc060c0802000000000000000000000
+2bce:00000000000000000000000004000a000a00110060c0802060c011000a000a00040000000000000000000000
+2bcf:000000000000000000000000802060c05b40248020801100208024805b4060c0802000000000000000000000
+2bd0:00000000000000000000000004007fc0444044404040f1e04040444044407fc0040000000000000000000000
+2bd1:00000000000000000600090010802f4059a08310861086104020264010800900060000000000000000000000
+2bd2:00000000060006003fc03fc0060006003fc03fc0060006003fc03fc006000600060000000000000000000000
+2be8:0000000000000000040004000c000c00fc007c003c001c000c001c001c003800300000000000000000000000
+2be9:0000000000000000020002000300030003f003e003c0038003000380038001c000c000000000000000000000
+2bea:0000000000000000060006000d000d00fdf07c203c401c800d001c801e80394030c000000000000000000000
+2beb:0000000000000000060006000b000b00fbf043e023c013800b001380178029c030c000000000000000000000
+2bec:00000000000000000000084018c039c07bc0fff0fff07bc039c018c008400000000000000000000000000000
+2bed:00000000000006000f001f803fc07fe006000f001f803fc07fe0060006000600060000000000000000000000
+2bee:00000000000000000000084018c039c07bc0fff0fff07bc039c018c008400000000000000000000000000000
+2bef:00000000000006000600060006007fe03fc01f800f0006007fe03fc01f800f00060000000000000000000000
+2bf9:00000000000000000000ffe0ffe000000000ffe0ffe0000071c08a2084208a2071c000000000000000000000
+2bfa:00000000000000000000000000000000000071c08a208a208a2071c000000000000000000000000000000000
+2bfb:0000000000000000000000000000000000006060909096909090606000000000000000000000000000000000
+2bfc:000000000000000000000e001100110011000e00000000000e001100110011000e0000000000000000000000
+2bfd:000000000000000004000e001f003f8004000400040004000e001100110011000e0000000000000000000000
+2bfe:000000000000000000000030003000300030003000300030003000300030fff0fff000000000000000000000
+2bff:00000000000000007fe07fe07fe00600060007e007e007e0060006007fe07fe07fe000000000000000000000
+30a0:0000000000000000000000000000000000000000000000000000003ffffc3ffffc0000000000003ffffc3ffffc000000000000000000000000000000000000000000
+30b3:00000000000000000000000007ffe007ffe000006000006000006000006000006000006000006000006007ffe007ffe0000060000000000000000000000000000000
+30c1:0000000000000000000003e003ffe003fc00000c00000c000ffff80ffff8000c0000180000180000300000300000600000c000000000000000000000000000000000
+30cb:00000000000000000000000001ff8001ff8000000000000000000000000000000000000000000000000000000007fff007fff0000000000000000000000000000000
+30cf:00000000000000000000000000000000030000038000c18000c1c000c0c001c0e00180600180600380700300300700300e0030000000000000000000000000000000
+30f3:0000000000000000000000000e000007000003800001c0000000000000300000700000e0000380001e0000f80007c000070000000000000000000000000000000000
+e0a0:e000e080e1c0e3e0e7f0e1c0e1c0e1c0e1c0e1c0e1c0e1c0c3c087800f003c00f000e000e000e000e000e000
+e0a1:00000000f000600060006000608060807f807f80000070f038603c603660336031e030e0306078f000000000
+e0a2:000000001f803fc030c030c030c030c030c030c07fe07fe079e070e070e079e079e079e079e07fe000000000
+e0a3:000000003f007f8060806000600060807f803f000000000070f038603c603660336031e030e078f000000000
+e0b0:8000c000e000f000f800fc00fe00ff00ff80ffc0ffe0ffe0ffc0ff80ff00fe00fc00f800f000e000c0008000
+e0b1:c0006000300018000c0006000300018000c0006000300030006000c00180030006000c00180030006000c000
+e0b2:00100030007000f001f003f007f00ff01ff03ff07ff07ff03ff01ff00ff007f003f001f000f0007000300010
+e0b3:0030006000c00180030006000c00180030006000c000c0006000300018000c0006000300018000c000600030
+e0b4:e000f800fe00ff00ff80ffc0ffc0ffc0ffe0ffe0ffe0ffe0ffe0ffe0ffc0ffc0ffc0ff80ff00fe00f800e000
+e0b5:f0000c000300018000c000600060006000300030003000300030003000600060006000c0018003000c00f000
+e0b6:007001f007f00ff01ff03ff03ff03ff07ff07ff07ff07ff07ff07ff03ff03ff03ff01ff00ff007f001f00070
+e0b7:00f003000c0018003000600060006000c000c000c000c000c000c000600060006000300018000c00030000f0
+e0b8:80008000c000c000e000e000f000f000f800f800fc00fc00fe00fe00ff00ff00ff80ff80ffc0ffc0ffe0ffe0
+e0b9:c000c0006000600030003000180018000c000c0006000600030003000180018000c000c00060006000300030
+e0ba:00100010003000300070007000f000f001f001f003f003f007f007f00ff00ff01ff01ff03ff03ff07ff07ff0
+e0bb:003000300060006000c000c00180018003000300060006000c000c00180018003000300060006000c000c000
+e0bc:ffe0ffe0ffc0ffc0ff80ff80ff00ff00fe00fe00fc00fc00f800f800f000f000e000e000c000c00080008000
+e0bd:003000300060006000c000c00180018003000300060006000c000c00180018003000300060006000c000c000
+e0be:7ff07ff03ff03ff01ff01ff00ff00ff007f007f003f003f001f001f000f000f0007000700030003000100010
+e0bf:c000c0006000600030003000180018000c000c0006000600030003000180018000c000c00060006000300030
+e0c0:8000f000e700fc00f8e0fff0ff00fc00ff00ff80ffe0fe60fc00ff80ff00f9c0f000f800ff00e3c0c0008000
+e0c1:8000f00067001c0018e007f003000c000300018001e006600c000380070019c0100018001f0063c0c0008000
+e0c2:001000f00e7003f071f0fff00ff003f00ff01ff07ff067f003f01ff00ff039f000f001f00ff03c7000300010
+e0c3:001000f00e6003807180fe000c0003000c0018007800660003001c000e003980008001800f803c6000300010
+e0c4:db20db0000000020d900d90000400100d840d80001000100d800d88000000100c100c80000000000c800c800
+e0c5:4db00db00000400009b009b02000080021b001b00800080001b011b000000800083001300000000001300130
+e0c6:0000ee60ee60ee000060ee00ee00eec00000e680e600e0800600e600e000e4000000e600e600e00008000000
+e0c7:0000677067700770600007700770377000001670067010700600067000700270000006700670007001000000
+e0c8:0000f000c000fe00ff80e000fe00ffe0ff00f000ff80e000fc00e000ff00fff0fc00e000ff00c000f8000000
+e0ca:000000f0003007f01ff0007007f07ff00ff000f01ff0007003f000700ff0fff003f000700ff0003001f00000
+e0cc:c000c000e000e000f000f000e180e180c3c0c3c007e007e0c3c0c3c0e180e180f000f000e000e000c000c000
+e0cd:c00040002000200010001000218021804240c24004200420c24042402180218010001000200020004000c000
+e0ce:ff00ff00fd80fd80fbc0fa60f4f0f4f0ecf0ee600ff00ff0ee60ecf0f4f0f4f0fa60fbc0fd80fd80ff00ff00
+e0cf:0000060006001f801f806f606060f0f0fff0ef706060b0d0dfb0ef70f0f0f9f0f9f0f9f079e039c019800900
+e0d0:00000000000071c08a208a208a2079e071c0000000000000000071c08a208a208a2079e071c0000000000000
+e0d1:fc00fc00ffe0fc20fc20ffe0ffe0ffe0ffe0fc00fc00fc00fc00ffe0fc20fc20ffe0ffe0ffe0ffe0fc00fc00
+e0d2:fff0ffe0ffe0ffc0ffc0ff80ff80ff00ff000000000000000000ff00ff00ff80ff80ffc0ffc0ffe0ffe0fff0
+e0d4:fff07ff07ff03ff03ff01ff01ff00ff00ff000000000000000000ff00ff01ff01ff03ff03ff07ff07ff0fff0
+e800:7770ddd0bbb0eee07770ddd0bbb0eee07770ddd0bbb0eee07770ddd0bbb0eee07770ddd0bbb0eee07770ddd0
+e801:bbb0eee07770ddd0bbb0eee07770ddd0bbb0eee07770ddd0bbb0eee07770ddd0bbb0eee07770ddd0bbb0eee0
+e802:8880222044401110888022204440111088802220444011108880222044401110888022204440111088802220
+e803:4440111088802220444011108880222044401110888022204440111088802220444011108880222044401110
+fb00:000000001ce0273023306310631063006300ffc0630063006300630063006300f78000000000000000000000
+fb01:000000000700098008c018c018c0180018003fc018c018c018c018c018c018c039e000000000000000000000
+fb02:000000000ec013c011c031c031c030c030c07fc030c030c030c030c030c030c079e000000000000000000000
+fb03:0000000019c0266026606660666066006600fff0666066606660666066606660f7f000000000000000000000
+fb04:0000000019a026e026e066e0666066606660ffe0666066606660666066606660f7f000000000000000000000
+fb05:000000000f00198018c030c030c030c030c073f030c030c030c030c030c030c079e000000000000000000000
+fb06:000000000000038007c00cc00cc07ec0c6c0c2f0e0c070c01cc00ec086c0c6c0fc7000000000000000000000
+fff9:0000aaa00000fbe082008200f3c082008200820000000000fbe082208220f3e08020802083e00000aaa00000
+fffa:0000aaa00000fbe082008200f3c082008200820000000000f9c082208220f3e08220822082200000aaa00000
+fffb:0000aaa00000fbe082008200f3c082008200820000000000fbc082208220f3c08220822083c00000aaa00000
+fffc:0000aaa00000fbe082008200f3c082008200820000000000f9e082008200f2008200820081e00000aaa00000
+fffd:06000f001f803fc040204f20d9b0c1b0c1b0c330c630c030c630462040203fc01f800f000600000000000000
+fffe:0000aaa00000fbe082008200f3c082008200820000000000fbe082008200f3c08200820083e00000aaa00000
+ffff:0000aaa00000fbe082008200f3c082008200820000000000fbe082008200f3c08200820082000000aaa00000
diff --git a/stand/defaults/loader.conf.5 b/stand/defaults/loader.conf.5
index dc1c8f7f44e0..b1661e8c1101 100644
--- a/stand/defaults/loader.conf.5
+++ b/stand/defaults/loader.conf.5
@@ -21,7 +21,7 @@
.\" 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 June 12, 2025
+.Dd September 2, 2025
.Dt LOADER.CONF 5
.Os
.Sh NAME
@@ -127,6 +127,9 @@ since those flags apply to all boot loaders.
.It Ar boot_verbose
Set to "yes" to get the same effect as boot -v or booting verbose from the
loader menu.
+See the
+.Va kern.msgbufsize
+tuneable to ensure enough space for the increased number of messages.
.It Ar exec
Immediately executes a
.Xr loader 8
diff --git a/sys/amd64/conf/GENERIC b/sys/amd64/conf/GENERIC
index 81427b5b18b6..786edc4125c9 100644
--- a/sys/amd64/conf/GENERIC
+++ b/sys/amd64/conf/GENERIC
@@ -26,7 +26,7 @@ makeoptions WITH_CTF=1 # Run ctfconvert(1) for DTrace support
options SCHED_ULE # ULE scheduler
options NUMA # Non-Uniform Memory Architecture support
options PREEMPTION # Enable kernel thread preemption
-options BLOAT_KERNEL_WITH_EXTERR
+options EXTERR_STRINGS
options VIMAGE # Subsystem virtualization, e.g. VNET
options INET # InterNETworking
options INET6 # IPv6 communications protocols
diff --git a/sys/arm/arm/generic_timer.c b/sys/arm/arm/generic_timer.c
index a8c779dcba6d..97976408c943 100644
--- a/sys/arm/arm/generic_timer.c
+++ b/sys/arm/arm/generic_timer.c
@@ -882,32 +882,32 @@ DELAY(int usec)
TSEXIT();
}
-static bool
+static cpu_feat_en
wfxt_check(const struct cpu_feat *feat __unused, u_int midr __unused)
{
uint64_t id_aa64isar2;
if (!get_kernel_reg(ID_AA64ISAR2_EL1, &id_aa64isar2))
- return (false);
- return (ID_AA64ISAR2_WFxT_VAL(id_aa64isar2) != ID_AA64ISAR2_WFxT_NONE);
+ return (FEAT_ALWAYS_DISABLE);
+ if (ID_AA64ISAR2_WFxT_VAL(id_aa64isar2) >= ID_AA64ISAR2_WFxT_NONE)
+ return (FEAT_DEFAULT_ENABLE);
+
+ return (FEAT_ALWAYS_DISABLE);
}
-static void
+static bool
wfxt_enable(const struct cpu_feat *feat __unused,
cpu_feat_errata errata_status __unused, u_int *errata_list __unused,
u_int errata_count __unused)
{
/* will be called if wfxt_check returns true */
enable_wfxt = true;
+ return (true);
}
-static struct cpu_feat feat_wfxt = {
- .feat_name = "FEAT_WFXT",
- .feat_check = wfxt_check,
- .feat_enable = wfxt_enable,
- .feat_flags = CPU_FEAT_AFTER_DEV | CPU_FEAT_SYSTEM,
-};
-DATA_SET(cpu_feat_set, feat_wfxt);
+CPU_FEAT(feat_wfxt, "WFE and WFI instructions with timeout",
+ wfxt_check, NULL, wfxt_enable,
+ CPU_FEAT_AFTER_DEV | CPU_FEAT_SYSTEM);
#endif
static uint32_t
diff --git a/sys/arm64/arm64/cpu_feat.c b/sys/arm64/arm64/cpu_feat.c
index cc262394913d..986d5079e980 100644
--- a/sys/arm64/arm64/cpu_feat.c
+++ b/sys/arm64/arm64/cpu_feat.c
@@ -32,16 +32,21 @@
#include <machine/cpu.h>
#include <machine/cpu_feat.h>
+SYSCTL_NODE(_hw, OID_AUTO, feat, CTLFLAG_RD, 0, "CPU features/errata");
+
/* TODO: Make this a list if we ever grow a callback other than smccc_errata */
static cpu_feat_errata_check_fn cpu_feat_check_cb = NULL;
void
enable_cpu_feat(uint32_t stage)
{
+ char tunable[32];
struct cpu_feat **featp, *feat;
uint32_t midr;
u_int errata_count, *errata_list;
cpu_feat_errata errata_status;
+ cpu_feat_en check_status;
+ bool val;
MPASS((stage & ~CPU_FEAT_STAGE_MASK) == 0);
@@ -58,9 +63,26 @@ enable_cpu_feat(uint32_t stage)
PCPU_GET(cpuid) != 0)
continue;
- if (feat->feat_check != NULL && !feat->feat_check(feat, midr))
+ if (feat->feat_check != NULL)
+ continue;
+
+ check_status = feat->feat_check(feat, midr);
+ /* Ignore features that are not present */
+ if (check_status == FEAT_ALWAYS_DISABLE)
continue;
+ snprintf(tunable, sizeof(tunable), "hw.feat.%s",
+ feat->feat_name);
+ if (TUNABLE_BOOL_FETCH(tunable, &val)) {
+ /* Is the feature disabled by the tunable? */
+ if (!val)
+ continue;
+ /* If enabled by the tunable then enable it */
+ } else if (check_status == FEAT_DEFAULT_DISABLE) {
+ /* No tunable set and disabled by default */
+ continue;
+ }
+
/*
* Check if the feature has any errata that may need a
* workaround applied (or it is to install the workaround for
@@ -97,8 +119,9 @@ enable_cpu_feat(uint32_t stage)
/* Shouldn't be possible */
MPASS(errata_status != ERRATA_UNKNOWN);
- feat->feat_enable(feat, errata_status, errata_list,
- errata_count);
+ if (feat->feat_enable(feat, errata_status, errata_list,
+ errata_count))
+ feat->feat_enabled = true;
}
}
diff --git a/sys/arm64/arm64/elf32_machdep.c b/sys/arm64/arm64/elf32_machdep.c
index 5c81c6cdce3d..8f8a934ad520 100644
--- a/sys/arm64/arm64/elf32_machdep.c
+++ b/sys/arm64/arm64/elf32_machdep.c
@@ -225,7 +225,7 @@ freebsd32_fetch_syscall_args(struct thread *td)
sa->args[i] = ap[i];
if (narg > nap) {
if (narg - nap > nitems(args))
- panic("Too many system call arguiments");
+ panic("Too many system call arguments");
error = copyin((void *)td->td_frame->tf_x[13], args,
(narg - nap) * sizeof(int));
if (error != 0)
diff --git a/sys/arm64/arm64/identcpu.c b/sys/arm64/arm64/identcpu.c
index bcacea43ad2f..a001be200518 100644
--- a/sys/arm64/arm64/identcpu.c
+++ b/sys/arm64/arm64/identcpu.c
@@ -2272,37 +2272,25 @@ static const struct mrs_user_reg user_regs[] = {
static bool
user_ctr_has_neoverse_n1_1542419(uint32_t midr, uint64_t ctr)
{
- /* Skip non-Neoverse-N1 */
- if (!CPU_MATCH(CPU_IMPL_MASK | CPU_PART_MASK, CPU_IMPL_ARM,
- CPU_PART_NEOVERSE_N1, 0, 0))
- return (false);
-
- switch (CPU_VAR(midr)) {
- default:
- break;
- case 4:
- /* Fixed in r4p1 */
- if (CPU_REV(midr) > 0)
- break;
- /* FALLTHROUGH */
- case 3:
- /* If DIC is enabled (coherent icache) then we are affected */
- return (CTR_DIC_VAL(ctr) != 0);
- }
-
- return (false);
+ /*
+ * Neoverse-N1 erratum 1542419
+ * Present in r3p0 - r4p0
+ * Fixed in r4p1
+ */
+ return (midr_check_var_part_range(midr, CPU_IMPL_ARM,
+ CPU_PART_NEOVERSE_N1, 3, 0, 4, 0) && CTR_DIC_VAL(ctr) != 0);
}
-static bool
-user_ctr_check(const struct cpu_feat *feat __unused, u_int midr __unused)
+static cpu_feat_en
+user_ctr_check(const struct cpu_feat *feat __unused, u_int midr)
{
if (emulate_ctr)
- return (true);
+ return (FEAT_DEFAULT_ENABLE);
if (user_ctr_has_neoverse_n1_1542419(midr, READ_SPECIALREG(ctr_el0)))
- return (true);
+ return (FEAT_DEFAULT_ENABLE);
- return (false);
+ return (FEAT_ALWAYS_DISABLE);
}
static bool
@@ -2320,7 +2308,7 @@ user_ctr_has_errata(const struct cpu_feat *feat __unused, u_int midr,
return (false);
}
-static void
+static bool
user_ctr_enable(const struct cpu_feat *feat __unused,
cpu_feat_errata errata_status, u_int *errata_list, u_int errata_count)
{
@@ -2356,16 +2344,13 @@ user_ctr_enable(const struct cpu_feat *feat __unused,
WRITE_SPECIALREG(sctlr_el1,
READ_SPECIALREG(sctlr_el1) & ~SCTLR_UCT);
isb();
+
+ return (true);
}
-static struct cpu_feat user_ctr = {
- .feat_name = "Trap CTR_EL0",
- .feat_check = user_ctr_check,
- .feat_has_errata = user_ctr_has_errata,
- .feat_enable = user_ctr_enable,
- .feat_flags = CPU_FEAT_AFTER_DEV | CPU_FEAT_PER_CPU,
-};
-DATA_SET(cpu_feat_set, user_ctr);
+CPU_FEAT(trap_ctr, "Trap CTR_EL0",
+ user_ctr_check, user_ctr_has_errata, user_ctr_enable,
+ CPU_FEAT_AFTER_DEV | CPU_FEAT_PER_CPU);
static bool
user_ctr_handler(uint64_t esr, struct trapframe *frame)
diff --git a/sys/arm64/arm64/machdep.c b/sys/arm64/arm64/machdep.c
index 53856dd90cae..47c701e8588c 100644
--- a/sys/arm64/arm64/machdep.c
+++ b/sys/arm64/arm64/machdep.c
@@ -173,16 +173,19 @@ SYSINIT(ssp_warn, SI_SUB_COPYRIGHT, SI_ORDER_ANY, print_ssp_warning, NULL);
SYSINIT(ssp_warn2, SI_SUB_LAST, SI_ORDER_ANY, print_ssp_warning, NULL);
#endif
-static bool
+static cpu_feat_en
pan_check(const struct cpu_feat *feat __unused, u_int midr __unused)
{
uint64_t id_aa64mfr1;
id_aa64mfr1 = READ_SPECIALREG(id_aa64mmfr1_el1);
- return (ID_AA64MMFR1_PAN_VAL(id_aa64mfr1) != ID_AA64MMFR1_PAN_NONE);
+ if (ID_AA64MMFR1_PAN_VAL(id_aa64mfr1) == ID_AA64MMFR1_PAN_NONE)
+ return (FEAT_ALWAYS_DISABLE);
+
+ return (FEAT_DEFAULT_ENABLE);
}
-static void
+static bool
pan_enable(const struct cpu_feat *feat __unused,
cpu_feat_errata errata_status __unused, u_int *errata_list __unused,
u_int errata_count __unused)
@@ -200,15 +203,13 @@ pan_enable(const struct cpu_feat *feat __unused,
".arch_extension pan \n"
"msr pan, #1 \n"
".arch_extension nopan \n");
+
+ return (true);
}
-static struct cpu_feat feat_pan = {
- .feat_name = "FEAT_PAN",
- .feat_check = pan_check,
- .feat_enable = pan_enable,
- .feat_flags = CPU_FEAT_EARLY_BOOT | CPU_FEAT_PER_CPU,
-};
-DATA_SET(cpu_feat_set, feat_pan);
+CPU_FEAT(feat_pan, "Privileged access never",
+ pan_check, NULL, pan_enable,
+ CPU_FEAT_EARLY_BOOT | CPU_FEAT_PER_CPU);
bool
has_hyp(void)
@@ -857,7 +858,7 @@ initarm(struct arm64_bootparams *abp)
cninit();
set_ttbr0(abp->kern_ttbr0);
- cpu_tlb_flushID();
+ pmap_s1_invalidate_all_kernel();
if (!valid)
panic("Invalid bus configuration: %s",
diff --git a/sys/arm64/arm64/pmap.c b/sys/arm64/arm64/pmap.c
index ec89c4573799..8a4395aa1c89 100644
--- a/sys/arm64/arm64/pmap.c
+++ b/sys/arm64/arm64/pmap.c
@@ -190,6 +190,8 @@ pt_entry_t __read_mostly pmap_gp_attr;
#define PMAP_SAN_PTE_BITS (ATTR_AF | ATTR_S1_XN | pmap_sh_attr | \
ATTR_KERN_GP | ATTR_S1_IDX(VM_MEMATTR_WRITE_BACK) | ATTR_S1_AP(ATTR_S1_AP_RW))
+static bool __read_mostly pmap_multiple_tlbi = false;
+
struct pmap_large_md_page {
struct rwlock pv_lock;
struct md_page pv_page;
@@ -1297,7 +1299,7 @@ pmap_bootstrap_dmap(vm_size_t kernlen)
}
}
- cpu_tlb_flushID();
+ pmap_s1_invalidate_all_kernel();
bs_state.dmap_valid = true;
@@ -1399,7 +1401,7 @@ pmap_bootstrap(void)
/* And the l3 tables for the early devmap */
pmap_bootstrap_l3(VM_MAX_KERNEL_ADDRESS - (PMAP_MAPDEV_EARLY_SIZE));
- cpu_tlb_flushID();
+ pmap_s1_invalidate_all_kernel();
#define alloc_pages(var, np) \
(var) = bs_state.freemempos; \
@@ -1656,14 +1658,17 @@ pmap_init_pv_table(void)
}
}
-static bool
+static cpu_feat_en
pmap_dbm_check(const struct cpu_feat *feat __unused, u_int midr __unused)
{
uint64_t id_aa64mmfr1;
id_aa64mmfr1 = READ_SPECIALREG(id_aa64mmfr1_el1);
- return (ID_AA64MMFR1_HAFDBS_VAL(id_aa64mmfr1) >=
- ID_AA64MMFR1_HAFDBS_AF_DBS);
+ if (ID_AA64MMFR1_HAFDBS_VAL(id_aa64mmfr1) >=
+ ID_AA64MMFR1_HAFDBS_AF_DBS)
+ return (FEAT_DEFAULT_ENABLE);
+
+ return (FEAT_ALWAYS_DISABLE);
}
static bool
@@ -1671,8 +1676,8 @@ pmap_dbm_has_errata(const struct cpu_feat *feat __unused, u_int midr,
u_int **errata_list, u_int *errata_count)
{
/* Disable on Cortex-A55 for erratum 1024718 - all revisions */
- if (CPU_MATCH(CPU_IMPL_MASK | CPU_PART_MASK, CPU_IMPL_ARM,
- CPU_PART_CORTEX_A55, 0, 0)) {
+ if (CPU_IMPL(midr) == CPU_IMPL_ARM &&
+ CPU_PART(midr) == CPU_PART_CORTEX_A55) {
static u_int errata_id = 1024718;
*errata_list = &errata_id;
@@ -1681,21 +1686,19 @@ pmap_dbm_has_errata(const struct cpu_feat *feat __unused, u_int midr,
}
/* Disable on Cortex-A510 for erratum 2051678 - r0p0 to r0p2 */
- if (CPU_MATCH(CPU_IMPL_MASK | CPU_PART_MASK | CPU_VAR_MASK,
- CPU_IMPL_ARM, CPU_PART_CORTEX_A510, 0, 0)) {
- if (CPU_REV(PCPU_GET(midr)) < 3) {
- static u_int errata_id = 2051678;
+ if (midr_check_var_part_range(midr, CPU_IMPL_ARM, CPU_PART_CORTEX_A510,
+ 0, 0, 0, 2)) {
+ static u_int errata_id = 2051678;
- *errata_list = &errata_id;
- *errata_count = 1;
- return (true);
- }
+ *errata_list = &errata_id;
+ *errata_count = 1;
+ return (true);
}
return (false);
}
-static void
+static bool
pmap_dbm_enable(const struct cpu_feat *feat __unused,
cpu_feat_errata errata_status, u_int *errata_list __unused,
u_int errata_count)
@@ -1704,7 +1707,7 @@ pmap_dbm_enable(const struct cpu_feat *feat __unused,
/* Skip if there is an erratum affecting DBM */
if (errata_status != ERRATA_NONE)
- return;
+ return (false);
tcr = READ_SPECIALREG(tcr_el1) | TCR_HD;
WRITE_SPECIALREG(tcr_el1, tcr);
@@ -1714,16 +1717,58 @@ pmap_dbm_enable(const struct cpu_feat *feat __unused,
__asm __volatile("tlbi vmalle1");
dsb(nsh);
isb();
+
+ return (true);
}
-static struct cpu_feat feat_dbm = {
- .feat_name = "FEAT_HAFDBS (DBM)",
- .feat_check = pmap_dbm_check,
- .feat_has_errata = pmap_dbm_has_errata,
- .feat_enable = pmap_dbm_enable,
- .feat_flags = CPU_FEAT_AFTER_DEV | CPU_FEAT_PER_CPU,
-};
-DATA_SET(cpu_feat_set, feat_dbm);
+CPU_FEAT(feat_hafdbs, "Hardware management of the Access flag and dirty state",
+ pmap_dbm_check, pmap_dbm_has_errata, pmap_dbm_enable,
+ CPU_FEAT_AFTER_DEV | CPU_FEAT_PER_CPU);
+
+static cpu_feat_en
+pmap_multiple_tlbi_check(const struct cpu_feat *feat __unused, u_int midr)
+{
+ /*
+ * Cortex-A55 erratum 2441007 (Cat B rare)
+ * Present in all revisions
+ */
+ if (CPU_IMPL(midr) == CPU_IMPL_ARM &&
+ CPU_PART(midr) == CPU_PART_CORTEX_A55)
+ return (FEAT_DEFAULT_DISABLE);
+
+ /*
+ * Cortex-A76 erratum 1286807 (Cat B rare)
+ * Present in r0p0 - r3p0
+ * Fixed in r3p1
+ */
+ if (midr_check_var_part_range(midr, CPU_IMPL_ARM, CPU_PART_CORTEX_A76,
+ 0, 0, 3, 0))
+ return (FEAT_DEFAULT_DISABLE);
+
+ /*
+ * Cortex-A510 erratum 2441009 (Cat B rare)
+ * Present in r0p0 - r1p1
+ * Fixed in r1p2
+ */
+ if (midr_check_var_part_range(midr, CPU_IMPL_ARM, CPU_PART_CORTEX_A510,
+ 0, 0, 1, 1))
+ return (FEAT_DEFAULT_DISABLE);
+
+ return (FEAT_ALWAYS_DISABLE);
+}
+
+static bool
+pmap_multiple_tlbi_enable(const struct cpu_feat *feat __unused,
+ cpu_feat_errata errata_status, u_int *errata_list __unused,
+ u_int errata_count __unused)
+{
+ pmap_multiple_tlbi = true;
+ return (true);
+}
+
+CPU_FEAT(errata_multi_tlbi, "Multiple TLBI errata",
+ pmap_multiple_tlbi_check, NULL, pmap_multiple_tlbi_enable,
+ CPU_FEAT_EARLY_BOOT | CPU_FEAT_PER_CPU);
/*
* Initialize the pmap module.
@@ -1878,9 +1923,17 @@ pmap_s1_invalidate_page(pmap_t pmap, vm_offset_t va, bool final_only)
r = TLBI_VA(va);
if (pmap == kernel_pmap) {
pmap_s1_invalidate_kernel(r, final_only);
+ if (pmap_multiple_tlbi) {
+ dsb(ish);
+ pmap_s1_invalidate_kernel(r, final_only);
+ }
} else {
r |= ASID_TO_OPERAND(COOKIE_TO_ASID(pmap->pm_cookie));
pmap_s1_invalidate_user(r, final_only);
+ if (pmap_multiple_tlbi) {
+ dsb(ish);
+ pmap_s1_invalidate_user(r, final_only);
+ }
}
dsb(ish);
isb();
@@ -1922,12 +1975,24 @@ pmap_s1_invalidate_strided(pmap_t pmap, vm_offset_t sva, vm_offset_t eva,
end = TLBI_VA(eva);
for (r = start; r < end; r += TLBI_VA(stride))
pmap_s1_invalidate_kernel(r, final_only);
+
+ if (pmap_multiple_tlbi) {
+ dsb(ish);
+ for (r = start; r < end; r += TLBI_VA(stride))
+ pmap_s1_invalidate_kernel(r, final_only);
+ }
} else {
start = end = ASID_TO_OPERAND(COOKIE_TO_ASID(pmap->pm_cookie));
start |= TLBI_VA(sva);
end |= TLBI_VA(eva);
for (r = start; r < end; r += TLBI_VA(stride))
pmap_s1_invalidate_user(r, final_only);
+
+ if (pmap_multiple_tlbi) {
+ dsb(ish);
+ for (r = start; r < end; r += TLBI_VA(stride))
+ pmap_s1_invalidate_user(r, final_only);
+ }
}
dsb(ish);
isb();
@@ -1963,6 +2028,19 @@ pmap_invalidate_range(pmap_t pmap, vm_offset_t sva, vm_offset_t eva,
pmap_s2_invalidate_range(pmap, sva, eva, final_only);
}
+void
+pmap_s1_invalidate_all_kernel(void)
+{
+ dsb(ishst);
+ __asm __volatile("tlbi vmalle1is");
+ dsb(ish);
+ if (pmap_multiple_tlbi) {
+ __asm __volatile("tlbi vmalle1is");
+ dsb(ish);
+ }
+ isb();
+}
+
/*
* Invalidates all cached intermediate- and final-level TLB entries for the
* given virtual address space.
@@ -1977,9 +2055,17 @@ pmap_s1_invalidate_all(pmap_t pmap)
dsb(ishst);
if (pmap == kernel_pmap) {
__asm __volatile("tlbi vmalle1is");
+ if (pmap_multiple_tlbi) {
+ dsb(ish);
+ __asm __volatile("tlbi vmalle1is");
+ }
} else {
r = ASID_TO_OPERAND(COOKIE_TO_ASID(pmap->pm_cookie));
__asm __volatile("tlbi aside1is, %0" : : "r" (r));
+ if (pmap_multiple_tlbi) {
+ dsb(ish);
+ __asm __volatile("tlbi aside1is, %0" : : "r" (r));
+ }
}
dsb(ish);
isb();
@@ -7967,7 +8053,7 @@ pmap_mapbios(vm_paddr_t pa, vm_size_t size)
pa += L2_SIZE;
}
if ((old_l2e & ATTR_DESCR_VALID) != 0)
- pmap_s1_invalidate_all(kernel_pmap);
+ pmap_s1_invalidate_all_kernel();
else {
/*
* Because the old entries were invalid and the new
@@ -8058,7 +8144,7 @@ pmap_unmapbios(void *p, vm_size_t size)
}
}
if (preinit_map) {
- pmap_s1_invalidate_all(kernel_pmap);
+ pmap_s1_invalidate_all_kernel();
return;
}
diff --git a/sys/arm64/arm64/ptrauth.c b/sys/arm64/arm64/ptrauth.c
index dbe0c69b8d60..fdab5414e24c 100644
--- a/sys/arm64/arm64/ptrauth.c
+++ b/sys/arm64/arm64/ptrauth.c
@@ -82,7 +82,7 @@ ptrauth_disable(void)
return (false);
}
-static bool
+static cpu_feat_en
ptrauth_check(const struct cpu_feat *feat __unused, u_int midr __unused)
{
uint64_t isar;
@@ -116,14 +116,14 @@ ptrauth_check(const struct cpu_feat *feat __unused, u_int midr __unused)
if (get_kernel_reg(ID_AA64ISAR1_EL1, &isar)) {
if (ID_AA64ISAR1_APA_VAL(isar) > 0 ||
ID_AA64ISAR1_API_VAL(isar) > 0) {
- return (true);
+ return (FEAT_DEFAULT_ENABLE);
}
}
/* The QARMA3 algorithm is reported in ID_AA64ISAR2_EL1. */
if (get_kernel_reg(ID_AA64ISAR2_EL1, &isar)) {
if (ID_AA64ISAR2_APA3_VAL(isar) > 0) {
- return (true);
+ return (FEAT_DEFAULT_ENABLE);
}
}
@@ -138,10 +138,10 @@ out:
ID_AA64ISAR1_GPI_MASK, 0);
update_special_reg(ID_AA64ISAR2_EL1, ID_AA64ISAR2_APA3_MASK, 0);
- return (false);
+ return (FEAT_ALWAYS_DISABLE);
}
-static void
+static bool
ptrauth_enable(const struct cpu_feat *feat __unused,
cpu_feat_errata errata_status __unused, u_int *errata_list __unused,
u_int errata_count __unused)
@@ -153,16 +153,13 @@ ptrauth_enable(const struct cpu_feat *feat __unused,
elf64_addr_mask_14.code |= PAC_ADDR_MASK_14;
elf64_addr_mask_14.data |= PAC_ADDR_MASK_14;
#endif
-}
+ return (true);
+}
-static struct cpu_feat feat_pauth = {
- .feat_name = "FEAT_PAuth",
- .feat_check = ptrauth_check,
- .feat_enable = ptrauth_enable,
- .feat_flags = CPU_FEAT_EARLY_BOOT | CPU_FEAT_SYSTEM,
-};
-DATA_SET(cpu_feat_set, feat_pauth);
+CPU_FEAT(feat_pauth, "Pointer Authentication",
+ ptrauth_check, NULL, ptrauth_enable,
+ CPU_FEAT_EARLY_BOOT | CPU_FEAT_SYSTEM);
/* Copy the keys when forking a new process */
void
diff --git a/sys/arm64/conf/std.arm64 b/sys/arm64/conf/std.arm64
index c83e98c17a33..a0568466cfaf 100644
--- a/sys/arm64/conf/std.arm64
+++ b/sys/arm64/conf/std.arm64
@@ -7,6 +7,7 @@ makeoptions WITH_CTF=1 # Run ctfconvert(1) for DTrace support
options SCHED_ULE # ULE scheduler
options NUMA # Non-Uniform Memory Architecture support
options PREEMPTION # Enable kernel thread preemption
+options EXTERR_STRINGS
options VIMAGE # Subsystem virtualization, e.g. VNET
options INET # InterNETworking
options INET6 # IPv6 communications protocols
diff --git a/sys/arm64/include/cpu.h b/sys/arm64/include/cpu.h
index 59cda36f275e..07a783138f42 100644
--- a/sys/arm64/include/cpu.h
+++ b/sys/arm64/include/cpu.h
@@ -193,8 +193,30 @@
(((mask) & PCPU_GET(midr)) == \
((mask) & CPU_ID_RAW((impl), (part), (var), (rev))))
-#define CPU_MATCH_RAW(mask, devid) \
- (((mask) & PCPU_GET(midr)) == ((mask) & (devid)))
+#if !defined(__ASSEMBLER__)
+static inline bool
+midr_check_var_part_range(u_int midr, u_int impl, u_int part, u_int var_low,
+ u_int part_low, u_int var_high, u_int part_high)
+{
+ /* Check for the correct part */
+ if (CPU_IMPL(midr) != impl || CPU_PART(midr) != part)
+ return (false);
+
+ /* Check if the variant is between var_low and var_high inclusive */
+ if (CPU_VAR(midr) < var_low || CPU_VAR(midr) > var_high)
+ return (false);
+
+ /* If the variant is the low value, check if the part is high enough */
+ if (CPU_VAR(midr) == var_low && CPU_PART(midr) < part_low)
+ return (false);
+
+ /* If the variant is the high value, check if the part is low enough */
+ if (CPU_VAR(midr) == var_high && CPU_PART(midr) > part_high)
+ return (false);
+
+ return (true);
+}
+#endif
/*
* Chip-specific errata. This defines are intended to be
diff --git a/sys/arm64/include/cpu_feat.h b/sys/arm64/include/cpu_feat.h
index 9fe6a9dd95d9..6a554b6baedf 100644
--- a/sys/arm64/include/cpu_feat.h
+++ b/sys/arm64/include/cpu_feat.h
@@ -29,6 +29,7 @@
#define _MACHINE_CPU_FEAT_H_
#include <sys/linker_set.h>
+#include <sys/sysctl.h>
typedef enum {
ERRATA_UNKNOWN, /* Unknown erratum */
@@ -39,6 +40,31 @@ typedef enum {
/* kernel component. */
} cpu_feat_errata;
+typedef enum {
+ /*
+ * Don't implement the feature or erratum wrokarount,
+ * e.g. the feature is not implemented or erratum is
+ * for another CPU.
+ */
+ FEAT_ALWAYS_DISABLE,
+
+ /*
+ * Disable by default, but allow the user to enable,
+ * e.g. For a rare erratum with a workaround, Arm
+ * Category B (rare) or similar.
+ */
+ FEAT_DEFAULT_DISABLE,
+
+ /*
+ * Enabled by default, bit allow the user to disable,
+ * e.g. For a common erratum with a workaround, Arm
+ * Category A or B or similar.
+ */
+ FEAT_DEFAULT_ENABLE,
+
+ /* We could add FEAT_ALWAYS_ENABLE if a need was found. */
+} cpu_feat_en;
+
#define CPU_FEAT_STAGE_MASK 0x00000001
#define CPU_FEAT_EARLY_BOOT 0x00000000
#define CPU_FEAT_AFTER_DEV 0x00000001
@@ -49,10 +75,10 @@ typedef enum {
struct cpu_feat;
-typedef bool (cpu_feat_check)(const struct cpu_feat *, u_int);
+typedef cpu_feat_en (cpu_feat_check)(const struct cpu_feat *, u_int);
typedef bool (cpu_feat_has_errata)(const struct cpu_feat *, u_int,
u_int **, u_int *);
-typedef void (cpu_feat_enable)(const struct cpu_feat *, cpu_feat_errata,
+typedef bool (cpu_feat_enable)(const struct cpu_feat *, cpu_feat_errata,
u_int *, u_int);
struct cpu_feat {
@@ -61,9 +87,25 @@ struct cpu_feat {
cpu_feat_has_errata *feat_has_errata;
cpu_feat_enable *feat_enable;
uint32_t feat_flags;
+ bool feat_enabled;
};
SET_DECLARE(cpu_feat_set, struct cpu_feat);
+SYSCTL_DECL(_hw_feat);
+
+#define CPU_FEAT(name, descr, check, has_errata, enable, flags) \
+static struct cpu_feat name = { \
+ .feat_name = #name, \
+ .feat_check = check, \
+ .feat_has_errata = has_errata, \
+ .feat_enable = enable, \
+ .feat_flags = flags, \
+ .feat_enabled = false, \
+}; \
+DATA_SET(cpu_feat_set, name); \
+SYSCTL_BOOL(_hw_feat, OID_AUTO, name, CTLFLAG_RD, &name.feat_enabled, \
+ 0, descr)
+
/*
* Allow drivers to mark an erratum as worked around, e.g. the Errata
* Management ABI may know the workaround isn't needed on a given system.
diff --git a/sys/arm64/include/pmap.h b/sys/arm64/include/pmap.h
index 0f23f200f0f6..406b6e2c5e0a 100644
--- a/sys/arm64/include/pmap.h
+++ b/sys/arm64/include/pmap.h
@@ -69,6 +69,7 @@ struct md_page {
TAILQ_HEAD(,pv_entry) pv_list;
int pv_gen;
vm_memattr_t pv_memattr;
+ uint8_t pv_reserve[3];
};
enum pmap_stage {
@@ -174,6 +175,8 @@ int pmap_fault(pmap_t, uint64_t, uint64_t);
struct pcb *pmap_switch(struct thread *);
+void pmap_s1_invalidate_all_kernel(void);
+
extern void (*pmap_clean_stage2_tlbi)(void);
extern void (*pmap_stage2_invalidate_range)(uint64_t, vm_offset_t, vm_offset_t,
bool);
diff --git a/sys/arm64/include/proc.h b/sys/arm64/include/proc.h
index 184743d4cc80..b40990e89385 100644
--- a/sys/arm64/include/proc.h
+++ b/sys/arm64/include/proc.h
@@ -75,6 +75,7 @@ struct mdthread {
struct mdproc {
uint64_t md_tcr; /* TCR_EL1 fields to update */
+ uint64_t md_reserved[2];
};
#endif /* !LOCORE */
diff --git a/sys/compat/freebsd32/freebsd32_syscall.h b/sys/compat/freebsd32/freebsd32_syscall.h
index 90cd21a80923..54063150eef9 100644
--- a/sys/compat/freebsd32/freebsd32_syscall.h
+++ b/sys/compat/freebsd32/freebsd32_syscall.h
@@ -515,4 +515,6 @@
#define FREEBSD32_SYS_inotify_rm_watch 594
#define FREEBSD32_SYS_getgroups 595
#define FREEBSD32_SYS_setgroups 596
-#define FREEBSD32_SYS_MAXSYSCALL 597
+#define FREEBSD32_SYS_jail_attach_jd 597
+#define FREEBSD32_SYS_jail_remove_jd 598
+#define FREEBSD32_SYS_MAXSYSCALL 599
diff --git a/sys/compat/freebsd32/freebsd32_syscalls.c b/sys/compat/freebsd32/freebsd32_syscalls.c
index f0f8d26554b5..f7cc4c284e4d 100644
--- a/sys/compat/freebsd32/freebsd32_syscalls.c
+++ b/sys/compat/freebsd32/freebsd32_syscalls.c
@@ -602,4 +602,6 @@ const char *freebsd32_syscallnames[] = {
"inotify_rm_watch", /* 594 = inotify_rm_watch */
"getgroups", /* 595 = getgroups */
"setgroups", /* 596 = setgroups */
+ "jail_attach_jd", /* 597 = jail_attach_jd */
+ "jail_remove_jd", /* 598 = jail_remove_jd */
};
diff --git a/sys/compat/freebsd32/freebsd32_sysent.c b/sys/compat/freebsd32/freebsd32_sysent.c
index 12f1a346c3e9..18f809ef04e3 100644
--- a/sys/compat/freebsd32/freebsd32_sysent.c
+++ b/sys/compat/freebsd32/freebsd32_sysent.c
@@ -664,4 +664,6 @@ struct sysent freebsd32_sysent[] = {
{ .sy_narg = AS(inotify_rm_watch_args), .sy_call = (sy_call_t *)sys_inotify_rm_watch, .sy_auevent = AUE_INOTIFY, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 594 = inotify_rm_watch */
{ .sy_narg = AS(getgroups_args), .sy_call = (sy_call_t *)sys_getgroups, .sy_auevent = AUE_GETGROUPS, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 595 = getgroups */
{ .sy_narg = AS(setgroups_args), .sy_call = (sy_call_t *)sys_setgroups, .sy_auevent = AUE_SETGROUPS, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 596 = setgroups */
+ { .sy_narg = AS(jail_attach_jd_args), .sy_call = (sy_call_t *)sys_jail_attach_jd, .sy_auevent = AUE_JAIL_ATTACH, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 597 = jail_attach_jd */
+ { .sy_narg = AS(jail_remove_jd_args), .sy_call = (sy_call_t *)sys_jail_remove_jd, .sy_auevent = AUE_JAIL_REMOVE, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 598 = jail_remove_jd */
};
diff --git a/sys/compat/freebsd32/freebsd32_systrace_args.c b/sys/compat/freebsd32/freebsd32_systrace_args.c
index e471c5148021..29a5497e9efa 100644
--- a/sys/compat/freebsd32/freebsd32_systrace_args.c
+++ b/sys/compat/freebsd32/freebsd32_systrace_args.c
@@ -3413,6 +3413,20 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args)
*n_args = 2;
break;
}
+ /* jail_attach_jd */
+ case 597: {
+ struct jail_attach_jd_args *p = params;
+ iarg[a++] = p->fd; /* int */
+ *n_args = 1;
+ break;
+ }
+ /* jail_remove_jd */
+ case 598: {
+ struct jail_remove_jd_args *p = params;
+ iarg[a++] = p->fd; /* int */
+ *n_args = 1;
+ break;
+ }
default:
*n_args = 0;
break;
@@ -9222,6 +9236,26 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz)
break;
};
break;
+ /* jail_attach_jd */
+ case 597:
+ switch (ndx) {
+ case 0:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* jail_remove_jd */
+ case 598:
+ switch (ndx) {
+ case 0:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
default:
break;
};
@@ -11130,6 +11164,16 @@ systrace_return_setargdesc(int sysnum, int ndx, char *desc, size_t descsz)
if (ndx == 0 || ndx == 1)
p = "int";
break;
+ /* jail_attach_jd */
+ case 597:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* jail_remove_jd */
+ case 598:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
default:
break;
};
diff --git a/sys/compat/lindebugfs/lindebugfs.c b/sys/compat/lindebugfs/lindebugfs.c
index 50f9377ffec3..8cddc6f390bc 100644
--- a/sys/compat/lindebugfs/lindebugfs.c
+++ b/sys/compat/lindebugfs/lindebugfs.c
@@ -206,7 +206,7 @@ debugfs_create_file(const char *name, umode_t mode,
pnode = debugfs_root;
flags = fops->write ? PFS_RDWR : PFS_RD;
- dnode->d_pfs_node = pfs_create_file(pnode, name, debugfs_fill,
+ pfs_create_file(pnode, &dnode->d_pfs_node, name, debugfs_fill,
debugfs_attr, NULL, debugfs_destroy, flags | PFS_NOWAIT);
if (dnode->d_pfs_node == NULL) {
free(dm, M_DFSINT);
@@ -283,7 +283,8 @@ debugfs_create_dir(const char *name, struct dentry *parent)
else
pnode = debugfs_root;
- dnode->d_pfs_node = pfs_create_dir(pnode, name, debugfs_attr, NULL, debugfs_destroy, PFS_RD | PFS_NOWAIT);
+ pfs_create_dir(pnode, &dnode->d_pfs_node, name, debugfs_attr, NULL,
+ debugfs_destroy, PFS_RD | PFS_NOWAIT);
if (dnode->d_pfs_node == NULL) {
free(dm, M_DFSINT);
return (NULL);
@@ -316,7 +317,8 @@ debugfs_create_symlink(const char *name, struct dentry *parent,
else
pnode = debugfs_root;
- dnode->d_pfs_node = pfs_create_link(pnode, name, &debugfs_fill_data, NULL, NULL, NULL, PFS_NOWAIT);
+ pfs_create_link(pnode, &dnode->d_pfs_node, name, &debugfs_fill_data,
+ NULL, NULL, NULL, PFS_NOWAIT);
if (dnode->d_pfs_node == NULL)
goto fail;
dnode->d_pfs_node->pn_data = dm;
diff --git a/sys/compat/linprocfs/linprocfs.c b/sys/compat/linprocfs/linprocfs.c
index 1c6d64d6b8bc..95b212be1306 100644
--- a/sys/compat/linprocfs/linprocfs.c
+++ b/sys/compat/linprocfs/linprocfs.c
@@ -2320,165 +2320,165 @@ linprocfs_init(PFS_INIT_ARGS)
root = pi->pi_root;
/* /proc/... */
- pfs_create_file(root, "cmdline", &linprocfs_docmdline,
- NULL, NULL, NULL, PFS_RD);
- pfs_create_file(root, "cpuinfo", &linprocfs_docpuinfo,
- NULL, NULL, NULL, PFS_RD);
- pfs_create_file(root, "devices", &linprocfs_dodevices,
- NULL, NULL, NULL, PFS_RD);
- pfs_create_file(root, "filesystems", &linprocfs_dofilesystems,
- NULL, NULL, NULL, PFS_RD);
- pfs_create_file(root, "loadavg", &linprocfs_doloadavg,
- NULL, NULL, NULL, PFS_RD);
- pfs_create_file(root, "meminfo", &linprocfs_domeminfo,
- NULL, NULL, NULL, PFS_RD);
- pfs_create_file(root, "modules", &linprocfs_domodules,
- NULL, NULL, NULL, PFS_RD);
- pfs_create_file(root, "mounts", &linprocfs_domtab,
- NULL, NULL, NULL, PFS_RD);
- pfs_create_file(root, "mtab", &linprocfs_domtab,
- NULL, NULL, NULL, PFS_RD);
- pfs_create_file(root, "partitions", &linprocfs_dopartitions,
- NULL, NULL, NULL, PFS_RD);
- pfs_create_link(root, "self", &procfs_docurproc,
- NULL, NULL, NULL, 0);
- pfs_create_file(root, "stat", &linprocfs_dostat,
- NULL, NULL, NULL, PFS_RD);
- pfs_create_file(root, "swaps", &linprocfs_doswaps,
- NULL, NULL, NULL, PFS_RD);
- pfs_create_file(root, "uptime", &linprocfs_douptime,
- NULL, NULL, NULL, PFS_RD);
- pfs_create_file(root, "version", &linprocfs_doversion,
+ pfs_create_file(root, NULL, "cmdline", &linprocfs_docmdline, NULL, NULL,
+ NULL, PFS_RD);
+ pfs_create_file(root, NULL, "cpuinfo", &linprocfs_docpuinfo, NULL, NULL,
+ NULL, PFS_RD);
+ pfs_create_file(root, NULL, "devices", &linprocfs_dodevices, NULL, NULL,
+ NULL, PFS_RD);
+ pfs_create_file(root, NULL, "filesystems", &linprocfs_dofilesystems,
NULL, NULL, NULL, PFS_RD);
+ pfs_create_file(root, NULL, "loadavg", &linprocfs_doloadavg, NULL, NULL,
+ NULL, PFS_RD);
+ pfs_create_file(root, NULL, "meminfo", &linprocfs_domeminfo, NULL, NULL,
+ NULL, PFS_RD);
+ pfs_create_file(root, NULL, "modules", &linprocfs_domodules, NULL, NULL,
+ NULL, PFS_RD);
+ pfs_create_file(root, NULL, "mounts", &linprocfs_domtab, NULL, NULL,
+ NULL, PFS_RD);
+ pfs_create_file(root, NULL, "mtab", &linprocfs_domtab, NULL, NULL, NULL,
+ PFS_RD);
+ pfs_create_file(root, NULL, "partitions", &linprocfs_dopartitions, NULL,
+ NULL, NULL, PFS_RD);
+ pfs_create_link(root, NULL, "self", &procfs_docurproc, NULL, NULL, NULL,
+ 0);
+ pfs_create_file(root, NULL, "stat", &linprocfs_dostat, NULL, NULL, NULL,
+ PFS_RD);
+ pfs_create_file(root, NULL, "swaps", &linprocfs_doswaps, NULL, NULL,
+ NULL, PFS_RD);
+ pfs_create_file(root, NULL, "uptime", &linprocfs_douptime, NULL, NULL,
+ NULL, PFS_RD);
+ pfs_create_file(root, NULL, "version", &linprocfs_doversion, NULL, NULL,
+ NULL, PFS_RD);
/* /proc/bus/... */
- dir = pfs_create_dir(root, "bus", NULL, NULL, NULL, 0);
- dir = pfs_create_dir(dir, "pci", NULL, NULL, NULL, 0);
- dir = pfs_create_dir(dir, "devices", NULL, NULL, NULL, 0);
+ pfs_create_dir(root, &dir, "bus", NULL, NULL, NULL, 0);
+ pfs_create_dir(dir, &dir, "pci", NULL, NULL, NULL, 0);
+ pfs_create_dir(dir, &dir, "devices", NULL, NULL, NULL, 0);
/* /proc/net/... */
- dir = pfs_create_dir(root, "net", NULL, NULL, NULL, 0);
- pfs_create_file(dir, "dev", &linprocfs_donetdev,
- NULL, NULL, NULL, PFS_RD);
- pfs_create_file(dir, "route", &linprocfs_donetroute,
- NULL, NULL, NULL, PFS_RD);
+ pfs_create_dir(root, &dir, "net", NULL, NULL, NULL, 0);
+ pfs_create_file(dir, NULL, "dev", &linprocfs_donetdev, NULL, NULL, NULL,
+ PFS_RD);
+ pfs_create_file(dir, NULL, "route", &linprocfs_donetroute, NULL, NULL,
+ NULL, PFS_RD);
/* /proc/<pid>/... */
- dir = pfs_create_dir(root, "pid", NULL, NULL, NULL, PFS_PROCDEP);
- pfs_create_file(dir, "cmdline", &linprocfs_doproccmdline,
- NULL, NULL, NULL, PFS_RD);
- pfs_create_link(dir, "cwd", &linprocfs_doproccwd,
- NULL, NULL, NULL, 0);
- pfs_create_file(dir, "environ", &linprocfs_doprocenviron,
- NULL, &procfs_candebug, NULL, PFS_RD);
- pfs_create_link(dir, "exe", &procfs_doprocfile,
- NULL, &procfs_notsystem, NULL, 0);
- pfs_create_file(dir, "maps", &linprocfs_doprocmaps,
- NULL, NULL, NULL, PFS_RD | PFS_AUTODRAIN);
- pfs_create_file(dir, "mem", &linprocfs_doprocmem,
- procfs_attr_rw, &procfs_candebug, NULL, PFS_RDWR | PFS_RAW);
- pfs_create_file(dir, "mountinfo", &linprocfs_doprocmountinfo,
- NULL, NULL, NULL, PFS_RD);
- pfs_create_file(dir, "mounts", &linprocfs_domtab,
+ pfs_create_dir(root, &dir, "pid", NULL, NULL, NULL, PFS_PROCDEP);
+ pfs_create_file(dir, NULL, "cmdline", &linprocfs_doproccmdline, NULL,
+ NULL, NULL, PFS_RD);
+ pfs_create_link(dir, NULL, "cwd", &linprocfs_doproccwd, NULL, NULL,
+ NULL, 0);
+ pfs_create_file(dir, NULL, "environ", &linprocfs_doprocenviron, NULL,
+ &procfs_candebug, NULL, PFS_RD);
+ pfs_create_link(dir, NULL, "exe", &procfs_doprocfile, NULL,
+ &procfs_notsystem, NULL, 0);
+ pfs_create_file(dir, NULL, "maps", &linprocfs_doprocmaps, NULL, NULL,
+ NULL, PFS_RD | PFS_AUTODRAIN);
+ pfs_create_file(dir, NULL, "mem", &linprocfs_doprocmem, procfs_attr_rw,
+ &procfs_candebug, NULL, PFS_RDWR | PFS_RAW);
+ pfs_create_file(dir, NULL, "mountinfo", &linprocfs_doprocmountinfo,
NULL, NULL, NULL, PFS_RD);
- pfs_create_link(dir, "root", &linprocfs_doprocroot,
- NULL, NULL, NULL, 0);
- pfs_create_file(dir, "stat", &linprocfs_doprocstat,
- NULL, NULL, NULL, PFS_RD);
- pfs_create_file(dir, "statm", &linprocfs_doprocstatm,
- NULL, NULL, NULL, PFS_RD);
- pfs_create_file(dir, "status", &linprocfs_doprocstatus,
- NULL, NULL, NULL, PFS_RD);
- pfs_create_link(dir, "fd", &linprocfs_dofdescfs,
- NULL, NULL, NULL, 0);
- pfs_create_file(dir, "auxv", &linprocfs_doauxv,
- NULL, &procfs_candebug, NULL, PFS_RD|PFS_RAWRD);
- pfs_create_file(dir, "limits", &linprocfs_doproclimits,
- NULL, NULL, NULL, PFS_RD);
- pfs_create_file(dir, "oom_score_adj", &linprocfs_do_oom_score_adj,
+ pfs_create_file(dir, NULL, "mounts", &linprocfs_domtab, NULL, NULL,
+ NULL, PFS_RD);
+ pfs_create_link(dir, NULL, "root", &linprocfs_doprocroot, NULL, NULL,
+ NULL, 0);
+ pfs_create_file(dir, NULL, "stat", &linprocfs_doprocstat, NULL, NULL,
+ NULL, PFS_RD);
+ pfs_create_file(dir, NULL, "statm", &linprocfs_doprocstatm, NULL, NULL,
+ NULL, PFS_RD);
+ pfs_create_file(dir, NULL, "status", &linprocfs_doprocstatus, NULL,
+ NULL, NULL, PFS_RD);
+ pfs_create_link(dir, NULL, "fd", &linprocfs_dofdescfs, NULL, NULL, NULL,
+ 0);
+ pfs_create_file(dir, NULL, "auxv", &linprocfs_doauxv, NULL,
+ &procfs_candebug, NULL, PFS_RD | PFS_RAWRD);
+ pfs_create_file(dir, NULL, "limits", &linprocfs_doproclimits, NULL,
+ NULL, NULL, PFS_RD);
+ pfs_create_file(dir, NULL, "oom_score_adj", &linprocfs_do_oom_score_adj,
procfs_attr_rw, &procfs_candebug, NULL, PFS_RDWR);
/* /proc/<pid>/task/... */
- dir = pfs_create_dir(dir, "task", linprocfs_dotaskattr, NULL, NULL, 0);
- pfs_create_file(dir, ".dummy", &linprocfs_dotaskdummy,
- NULL, NULL, NULL, PFS_RD);
+ pfs_create_dir(dir, &dir, "task", linprocfs_dotaskattr, NULL, NULL, 0);
+ pfs_create_file(dir, NULL, ".dummy", &linprocfs_dotaskdummy, NULL, NULL,
+ NULL, PFS_RD);
/* /proc/scsi/... */
- dir = pfs_create_dir(root, "scsi", NULL, NULL, NULL, 0);
- pfs_create_file(dir, "device_info", &linprocfs_doscsidevinfo,
- NULL, NULL, NULL, PFS_RD);
- pfs_create_file(dir, "scsi", &linprocfs_doscsiscsi,
+ pfs_create_dir(root, &dir, "scsi", NULL, NULL, NULL, 0);
+ pfs_create_file(dir, NULL, "device_info", &linprocfs_doscsidevinfo,
NULL, NULL, NULL, PFS_RD);
+ pfs_create_file(dir, NULL, "scsi", &linprocfs_doscsiscsi, NULL, NULL,
+ NULL, PFS_RD);
/* /proc/sys/... */
- sys = pfs_create_dir(root, "sys", NULL, NULL, NULL, 0);
+ pfs_create_dir(root, &sys, "sys", NULL, NULL, NULL, 0);
/* /proc/sys/kernel/... */
- dir = pfs_create_dir(sys, "kernel", NULL, NULL, NULL, 0);
- pfs_create_file(dir, "osrelease", &linprocfs_doosrelease,
- NULL, NULL, NULL, PFS_RD);
- pfs_create_file(dir, "ostype", &linprocfs_doostype,
- NULL, NULL, NULL, PFS_RD);
- pfs_create_file(dir, "version", &linprocfs_doosbuild,
- NULL, NULL, NULL, PFS_RD);
- pfs_create_file(dir, "msgmax", &linprocfs_domsgmax,
- NULL, NULL, NULL, PFS_RD);
- pfs_create_file(dir, "msgmni", &linprocfs_domsgmni,
- NULL, NULL, NULL, PFS_RD);
- pfs_create_file(dir, "msgmnb", &linprocfs_domsgmnb,
- NULL, NULL, NULL, PFS_RD);
- pfs_create_file(dir, "ngroups_max", &linprocfs_dongroups_max,
- NULL, NULL, NULL, PFS_RD);
- pfs_create_file(dir, "pid_max", &linprocfs_dopid_max,
- NULL, NULL, NULL, PFS_RD);
- pfs_create_file(dir, "sem", &linprocfs_dosem,
- NULL, NULL, NULL, PFS_RD);
- pfs_create_file(dir, "shmall", &linprocfs_doshmall,
- NULL, NULL, NULL, PFS_RD);
- pfs_create_file(dir, "shmmax", &linprocfs_doshmmax,
- NULL, NULL, NULL, PFS_RD);
- pfs_create_file(dir, "shmmni", &linprocfs_doshmmni,
- NULL, NULL, NULL, PFS_RD);
- pfs_create_file(dir, "tainted", &linprocfs_dotainted,
+ pfs_create_dir(sys, &dir, "kernel", NULL, NULL, NULL, 0);
+ pfs_create_file(dir, NULL, "osrelease", &linprocfs_doosrelease, NULL,
+ NULL, NULL, PFS_RD);
+ pfs_create_file(dir, NULL, "ostype", &linprocfs_doostype, NULL, NULL,
+ NULL, PFS_RD);
+ pfs_create_file(dir, NULL, "version", &linprocfs_doosbuild, NULL, NULL,
+ NULL, PFS_RD);
+ pfs_create_file(dir, NULL, "msgmax", &linprocfs_domsgmax, NULL, NULL,
+ NULL, PFS_RD);
+ pfs_create_file(dir, NULL, "msgmni", &linprocfs_domsgmni, NULL, NULL,
+ NULL, PFS_RD);
+ pfs_create_file(dir, NULL, "msgmnb", &linprocfs_domsgmnb, NULL, NULL,
+ NULL, PFS_RD);
+ pfs_create_file(dir, NULL, "ngroups_max", &linprocfs_dongroups_max,
NULL, NULL, NULL, PFS_RD);
+ pfs_create_file(dir, NULL, "pid_max", &linprocfs_dopid_max, NULL, NULL,
+ NULL, PFS_RD);
+ pfs_create_file(dir, NULL, "sem", &linprocfs_dosem, NULL, NULL, NULL,
+ PFS_RD);
+ pfs_create_file(dir, NULL, "shmall", &linprocfs_doshmall, NULL, NULL,
+ NULL, PFS_RD);
+ pfs_create_file(dir, NULL, "shmmax", &linprocfs_doshmmax, NULL, NULL,
+ NULL, PFS_RD);
+ pfs_create_file(dir, NULL, "shmmni", &linprocfs_doshmmni, NULL, NULL,
+ NULL, PFS_RD);
+ pfs_create_file(dir, NULL, "tainted", &linprocfs_dotainted, NULL, NULL,
+ NULL, PFS_RD);
/* /proc/sys/kernel/random/... */
- dir = pfs_create_dir(dir, "random", NULL, NULL, NULL, 0);
- pfs_create_file(dir, "uuid", &linprocfs_douuid,
- NULL, NULL, NULL, PFS_RD);
- pfs_create_file(dir, "boot_id", &linprocfs_doboot_id,
- NULL, NULL, NULL, PFS_RD);
+ pfs_create_dir(dir, &dir, "random", NULL, NULL, NULL, 0);
+ pfs_create_file(dir, NULL, "uuid", &linprocfs_douuid, NULL, NULL, NULL,
+ PFS_RD);
+ pfs_create_file(dir, NULL, "boot_id", &linprocfs_doboot_id, NULL, NULL,
+ NULL, PFS_RD);
/* /proc/sys/vm/.... */
- dir = pfs_create_dir(sys, "vm", NULL, NULL, NULL, 0);
- pfs_create_file(dir, "min_free_kbytes", &linprocfs_dominfree,
+ pfs_create_dir(sys, &dir, "vm", NULL, NULL, NULL, 0);
+ pfs_create_file(dir, NULL, "min_free_kbytes", &linprocfs_dominfree,
NULL, NULL, NULL, PFS_RD);
- pfs_create_file(dir, "max_map_count", &linprocfs_domax_map_cnt,
+ pfs_create_file(dir, NULL, "max_map_count", &linprocfs_domax_map_cnt,
NULL, NULL, NULL, PFS_RD);
/* /proc/sysvipc/... */
- dir = pfs_create_dir(root, "sysvipc", NULL, NULL, NULL, 0);
- pfs_create_file(dir, "msg", &linprocfs_dosysvipc_msg,
- NULL, NULL, NULL, PFS_RD);
- pfs_create_file(dir, "sem", &linprocfs_dosysvipc_sem,
- NULL, NULL, NULL, PFS_RD);
- pfs_create_file(dir, "shm", &linprocfs_dosysvipc_shm,
- NULL, NULL, NULL, PFS_RD);
+ pfs_create_dir(root, &dir, "sysvipc", NULL, NULL, NULL, 0);
+ pfs_create_file(dir, NULL, "msg", &linprocfs_dosysvipc_msg, NULL, NULL,
+ NULL, PFS_RD);
+ pfs_create_file(dir, NULL, "sem", &linprocfs_dosysvipc_sem, NULL, NULL,
+ NULL, PFS_RD);
+ pfs_create_file(dir, NULL, "shm", &linprocfs_dosysvipc_shm, NULL, NULL,
+ NULL, PFS_RD);
/* /proc/sys/fs/... */
- dir = pfs_create_dir(sys, "fs", NULL, NULL, NULL, 0);
+ pfs_create_dir(sys, &dir, "fs", NULL, NULL, NULL, 0);
/* /proc/sys/fs/mqueue/... */
- dir = pfs_create_dir(dir, "mqueue", NULL, NULL, NULL, 0);
- pfs_create_file(dir, "msg_default", &linprocfs_domqueue_msg_default,
- NULL, NULL, NULL, PFS_RD);
- pfs_create_file(dir, "msgsize_default", &linprocfs_domqueue_msgsize_default,
- NULL, NULL, NULL, PFS_RD);
- pfs_create_file(dir, "msg_max", &linprocfs_domqueue_msg_max,
- NULL, NULL, NULL, PFS_RD);
- pfs_create_file(dir, "msgsize_max", &linprocfs_domqueue_msgsize_max,
- NULL, NULL, NULL, PFS_RD);
- pfs_create_file(dir, "queues_max", &linprocfs_domqueue_queues_max,
+ pfs_create_dir(dir, &dir, "mqueue", NULL, NULL, NULL, 0);
+ pfs_create_file(dir, NULL, "msg_default",
+ &linprocfs_domqueue_msg_default, NULL, NULL, NULL, PFS_RD);
+ pfs_create_file(dir, NULL, "msgsize_default",
+ &linprocfs_domqueue_msgsize_default, NULL, NULL, NULL, PFS_RD);
+ pfs_create_file(dir, NULL, "msg_max", &linprocfs_domqueue_msg_max, NULL,
+ NULL, NULL, PFS_RD);
+ pfs_create_file(dir, NULL, "msgsize_max",
+ &linprocfs_domqueue_msgsize_max, NULL, NULL, NULL, PFS_RD);
+ pfs_create_file(dir, NULL, "queues_max", &linprocfs_domqueue_queues_max,
NULL, NULL, NULL, PFS_RD);
return (0);
diff --git a/sys/compat/linsysfs/linsysfs.c b/sys/compat/linsysfs/linsysfs.c
index 7f70221b420d..5a41c5193415 100644
--- a/sys/compat/linsysfs/linsysfs.c
+++ b/sys/compat/linsysfs/linsysfs.c
@@ -267,6 +267,8 @@ linsysfs_run_bus(device_t dev, struct pfs_node *dir, struct pfs_node *scsi,
struct pci_devinfo *dinfo;
char *device, *host, *new_path, *devname;
+ children = NULL;
+ device = host = NULL;
new_path = path;
devname = malloc(16, M_TEMP, M_WAITOK);
@@ -292,39 +294,43 @@ linsysfs_run_bus(device_t dev, struct pfs_node *dir, struct pfs_node *scsi,
dinfo->cfg.func);
strcat(new_path, "/");
strcat(new_path, device);
- dir = pfs_create_dir(dir, device,
+ error = pfs_create_dir(dir, &dir, device,
NULL, NULL, NULL, 0);
- cur_file = pfs_create_file(dir, "vendor",
+ if (error != 0)
+ goto out;
+ pfs_create_dir(dir, &dir, device, NULL, NULL,
+ NULL, 0);
+ pfs_create_file(dir, &cur_file, "vendor",
&linsysfs_fill_vendor, NULL, NULL, NULL,
PFS_RD);
cur_file->pn_data = (void*)dev;
- cur_file = pfs_create_file(dir, "device",
+ pfs_create_file(dir, &cur_file, "device",
&linsysfs_fill_device, NULL, NULL, NULL,
PFS_RD);
cur_file->pn_data = (void*)dev;
- cur_file = pfs_create_file(dir,
+ pfs_create_file(dir, &cur_file,
"subsystem_vendor",
&linsysfs_fill_subvendor, NULL, NULL, NULL,
PFS_RD);
cur_file->pn_data = (void*)dev;
- cur_file = pfs_create_file(dir,
+ pfs_create_file(dir, &cur_file,
"subsystem_device",
&linsysfs_fill_subdevice, NULL, NULL, NULL,
PFS_RD);
cur_file->pn_data = (void*)dev;
- cur_file = pfs_create_file(dir, "revision",
+ pfs_create_file(dir, &cur_file, "revision",
&linsysfs_fill_revid, NULL, NULL, NULL,
PFS_RD);
cur_file->pn_data = (void*)dev;
- cur_file = pfs_create_file(dir, "config",
+ pfs_create_file(dir, &cur_file, "config",
&linsysfs_fill_config, NULL, NULL, NULL,
PFS_RD);
cur_file->pn_data = (void*)dev;
- cur_file = pfs_create_file(dir, "uevent",
- &linsysfs_fill_uevent_pci, NULL, NULL,
- NULL, PFS_RD);
+ pfs_create_file(dir, &cur_file, "uevent",
+ &linsysfs_fill_uevent_pci, NULL, NULL, NULL,
+ PFS_RD);
cur_file->pn_data = (void*)dev;
- cur_file = pfs_create_link(dir, "subsystem",
+ pfs_create_link(dir, &cur_file, "subsystem",
&linsysfs_fill_data, NULL, NULL, NULL, 0);
/* libdrm just checks that the link ends in "/pci" */
cur_file->pn_data = "/sys/bus/pci";
@@ -334,34 +340,32 @@ linsysfs_run_bus(device_t dev, struct pfs_node *dir, struct pfs_node *scsi,
sprintf(host, "host%d", host_number++);
strcat(new_path, "/");
strcat(new_path, host);
- pfs_create_dir(dir, host,
- NULL, NULL, NULL, 0);
+ pfs_create_dir(dir, NULL, host, NULL,
+ NULL, NULL, 0);
scsi_host = malloc(sizeof(
struct scsi_host_queue),
- M_DEVBUF, M_NOWAIT);
+ M_DEVBUF, M_WAITOK);
scsi_host->path = malloc(
strlen(new_path) + 1,
- M_DEVBUF, M_NOWAIT);
+ M_DEVBUF, M_WAITOK);
scsi_host->path[0] = '\000';
bcopy(new_path, scsi_host->path,
strlen(new_path) + 1);
scsi_host->name = "unknown";
- sub_dir = pfs_create_dir(scsi, host,
+ pfs_create_dir(scsi, &sub_dir, host,
NULL, NULL, NULL, 0);
- pfs_create_link(sub_dir, "device",
- &linsysfs_link_scsi_host,
- NULL, NULL, NULL, 0);
- pfs_create_file(sub_dir, "proc_name",
- &linsysfs_scsiname,
+ pfs_create_link(sub_dir, NULL, "device",
+ &linsysfs_link_scsi_host, NULL,
+ NULL, NULL, 0);
+ pfs_create_file(sub_dir, NULL,
+ "proc_name", &linsysfs_scsiname,
NULL, NULL, NULL, PFS_RD);
scsi_host->name
= linux_driver_get_name_dev(dev);
TAILQ_INSERT_TAIL(&scsi_host_q,
scsi_host, scsi_host_next);
}
- free(device, M_TEMP);
- free(host, M_TEMP);
}
}
@@ -374,26 +378,27 @@ linsysfs_run_bus(device_t dev, struct pfs_node *dir, struct pfs_node *scsi,
device_get_unit(dev) >= 0) {
dinfo = device_get_ivars(parent);
if (dinfo != NULL && dinfo->cfg.baseclass == PCIC_DISPLAY) {
- pfs_create_dir(dir, "drm", NULL, NULL, NULL, 0);
+ pfs_create_dir(dir, NULL, "drm", NULL, NULL,
+ NULL, 0);
sprintf(devname, "226:%d",
device_get_unit(dev));
- sub_dir = pfs_create_dir(chardev,
- devname, NULL, NULL, NULL, 0);
- cur_file = pfs_create_link(sub_dir,
- "device", &linsysfs_fill_vgapci, NULL,
- NULL, NULL, PFS_RD);
+ pfs_create_dir(chardev, &sub_dir, devname, NULL,
+ NULL, NULL, 0);
+ pfs_create_link(sub_dir, &cur_file, "device",
+ &linsysfs_fill_vgapci, NULL, NULL, NULL,
+ PFS_RD);
cur_file->pn_data = (void*)dir;
- cur_file = pfs_create_file(sub_dir,
- "uevent", &linsysfs_fill_uevent_drm, NULL,
- NULL, NULL, PFS_RD);
+ pfs_create_file(sub_dir, &cur_file, "uevent",
+ &linsysfs_fill_uevent_drm, NULL, NULL, NULL,
+ PFS_RD);
cur_file->pn_data = (void*)dev;
sprintf(devname, "card%d",
device_get_unit(dev));
- sub_dir = pfs_create_dir(drm,
- devname, NULL, NULL, NULL, 0);
- cur_file = pfs_create_link(sub_dir,
- "device", &linsysfs_fill_vgapci, NULL,
- NULL, NULL, PFS_RD);
+ pfs_create_dir(drm, &sub_dir, devname, NULL,
+ NULL, NULL, 0);
+ pfs_create_link(sub_dir, &cur_file, "device",
+ &linsysfs_fill_vgapci, NULL, NULL, NULL,
+ PFS_RD);
cur_file->pn_data = (void*)dir;
}
}
@@ -401,17 +406,37 @@ linsysfs_run_bus(device_t dev, struct pfs_node *dir, struct pfs_node *scsi,
error = device_get_children(dev, &children, &nchildren);
if (error == 0) {
- for (i = 0; i < nchildren; i++)
- if (children[i])
- linsysfs_run_bus(children[i], dir, scsi,
+ for (i = 0; i < nchildren; i++) {
+ if (children[i]) {
+ error = linsysfs_run_bus(children[i], dir, scsi,
chardev, drm, new_path, prefix);
- free(children, M_TEMP);
+ if (error != 0) {
+ printf(
+ "linsysfs_run_bus: %s omitted from sysfs tree, error %d\n",
+ device_get_nameunit(children[i]),
+ error);
+ }
+ }
+ }
+
+ /*
+ * We override the error to avoid cascading failures; the
+ * innermost device that failed in a tree is probably the most
+ * significant one for diagnostics, its parents would be noise.
+ */
+ error = 0;
}
+
+out:
+ free(host, M_TEMP);
+ free(device, M_TEMP);
+ if (children != NULL)
+ free(children, M_TEMP);
if (new_path != path)
free(new_path, M_TEMP);
free(devname, M_TEMP);
- return (1);
+ return (error);
}
/*
@@ -455,10 +480,10 @@ linsysfs_listcpus(struct pfs_node *dir)
for (i = 0; i < mp_ncpus; ++i) {
/* /sys/devices/system/cpu/cpuX */
sprintf(name, "cpu%d", i);
- cpu = pfs_create_dir(dir, name, NULL, NULL, NULL, 0);
+ pfs_create_dir(dir, &cpu, name, NULL, NULL, NULL, 0);
- pfs_create_file(cpu, "online", &linsysfs_cpuxonline,
- NULL, NULL, NULL, PFS_RD);
+ pfs_create_file(cpu, NULL, "online", &linsysfs_cpuxonline, NULL,
+ NULL, NULL, PFS_RD);
}
free(name, M_TEMP);
}
@@ -485,52 +510,56 @@ linsysfs_init(PFS_INIT_ARGS)
root = pi->pi_root;
/* /sys/bus/... */
- dir = pfs_create_dir(root, "bus", NULL, NULL, NULL, 0);
+ pfs_create_dir(root, &dir, "bus", NULL, NULL, NULL, 0);
/* /sys/class/... */
- class = pfs_create_dir(root, "class", NULL, NULL, NULL, 0);
- scsi = pfs_create_dir(class, "scsi_host", NULL, NULL, NULL, 0);
- drm = pfs_create_dir(class, "drm", NULL, NULL, NULL, 0);
- pfs_create_dir(class, "power_supply", NULL, NULL, NULL, 0);
+ pfs_create_dir(root, &class, "class", NULL, NULL, NULL, 0);
+ pfs_create_dir(class, &scsi, "scsi_host", NULL, NULL, NULL, 0);
+ pfs_create_dir(class, &drm, "drm", NULL, NULL, NULL, 0);
+ pfs_create_dir(class, NULL, "power_supply", NULL, NULL, NULL, 0);
/* /sys/class/net/.. */
- net = pfs_create_dir(class, "net", NULL, NULL, NULL, 0);
+ pfs_create_dir(class, &net, "net", NULL, NULL, NULL, 0);
/* /sys/dev/... */
- devdir = pfs_create_dir(root, "dev", NULL, NULL, NULL, 0);
- chardev = pfs_create_dir(devdir, "char", NULL, NULL, NULL, 0);
+ pfs_create_dir(root, &devdir, "dev", NULL, NULL, NULL, 0);
+ pfs_create_dir(devdir, &chardev, "char", NULL, NULL, NULL, 0);
/* /sys/devices/... */
- dir = pfs_create_dir(root, "devices", NULL, NULL, NULL, 0);
- pci = pfs_create_dir(dir, "pci0000:00", NULL, NULL, NULL, 0);
+ pfs_create_dir(root, &dir, "devices", NULL, NULL, NULL, 0);
+ pfs_create_dir(dir, &pci, "pci0000:00", NULL, NULL, NULL, 0);
devclass = devclass_find("root");
if (devclass == NULL) {
return (0);
}
+ /*
+ * This assumes that the root node is unlikely to error out in
+ * linsysfs_run_bus, which may or may not be true.
+ */
dev = devclass_get_device(devclass, 0);
linsysfs_run_bus(dev, pci, scsi, chardev, drm, "/pci0000:00", "0000");
/* /sys/devices/system */
- sys = pfs_create_dir(dir, "system", NULL, NULL, NULL, 0);
+ pfs_create_dir(dir, &sys, "system", NULL, NULL, NULL, 0);
/* /sys/devices/system/cpu */
- cpu = pfs_create_dir(sys, "cpu", NULL, NULL, NULL, 0);
+ pfs_create_dir(sys, &cpu, "cpu", NULL, NULL, NULL, 0);
- pfs_create_file(cpu, "online", &linsysfs_cpuonline,
- NULL, NULL, NULL, PFS_RD);
- pfs_create_file(cpu, "possible", &linsysfs_cpuonline,
- NULL, NULL, NULL, PFS_RD);
- pfs_create_file(cpu, "present", &linsysfs_cpuonline,
- NULL, NULL, NULL, PFS_RD);
+ pfs_create_file(cpu, NULL, "online", &linsysfs_cpuonline, NULL, NULL,
+ NULL, PFS_RD);
+ pfs_create_file(cpu, NULL, "possible", &linsysfs_cpuonline, NULL, NULL,
+ NULL, PFS_RD);
+ pfs_create_file(cpu, NULL, "present", &linsysfs_cpuonline, NULL, NULL,
+ NULL, PFS_RD);
linsysfs_listcpus(cpu);
/* /sys/kernel */
- kernel = pfs_create_dir(root, "kernel", NULL, NULL, NULL, 0);
+ pfs_create_dir(root, &kernel, "kernel", NULL, NULL, NULL, 0);
/* /sys/kernel/debug, mountpoint for lindebugfs. */
- pfs_create_dir(kernel, "debug", NULL, NULL, NULL, 0);
+ pfs_create_dir(kernel, NULL, "debug", NULL, NULL, NULL, 0);
linsysfs_net_init();
diff --git a/sys/compat/linsysfs/linsysfs_net.c b/sys/compat/linsysfs/linsysfs_net.c
index 73602b0132a4..751dbb5b3713 100644
--- a/sys/compat/linsysfs/linsysfs_net.c
+++ b/sys/compat/linsysfs/linsysfs_net.c
@@ -237,22 +237,22 @@ linsysfs_net_addif(if_t ifp, void *arg)
nic = pfs_find_node(dir, ifname);
if (nic == NULL) {
- nic = pfs_create_dir(dir, ifname, NULL, linsysfs_if_visible,
+ pfs_create_dir(dir, &nic, ifname, NULL, linsysfs_if_visible,
NULL, 0);
- pfs_create_file(nic, "address", &linsysfs_if_addr,
+ pfs_create_file(nic, NULL, "address", &linsysfs_if_addr, NULL,
+ NULL, NULL, PFS_RD);
+ pfs_create_file(nic, NULL, "addr_len", &linsysfs_if_addrlen,
NULL, NULL, NULL, PFS_RD);
- pfs_create_file(nic, "addr_len", &linsysfs_if_addrlen,
+ pfs_create_file(nic, NULL, "flags", &linsysfs_if_flags, NULL,
+ NULL, NULL, PFS_RD);
+ pfs_create_file(nic, NULL, "ifindex", &linsysfs_if_ifindex,
NULL, NULL, NULL, PFS_RD);
- pfs_create_file(nic, "flags", &linsysfs_if_flags,
+ pfs_create_file(nic, NULL, "mtu", &linsysfs_if_mtu, NULL, NULL,
+ NULL, PFS_RD);
+ pfs_create_file(nic, NULL, "tx_queue_len", &linsysfs_if_txq_len,
NULL, NULL, NULL, PFS_RD);
- pfs_create_file(nic, "ifindex", &linsysfs_if_ifindex,
- NULL, NULL, NULL, PFS_RD);
- pfs_create_file(nic, "mtu", &linsysfs_if_mtu,
- NULL, NULL, NULL, PFS_RD);
- pfs_create_file(nic, "tx_queue_len", &linsysfs_if_txq_len,
- NULL, NULL, NULL, PFS_RD);
- pfs_create_file(nic, "type", &linsysfs_if_type,
- NULL, NULL, NULL, PFS_RD);
+ pfs_create_file(nic, NULL, "type", &linsysfs_if_type, NULL,
+ NULL, NULL, PFS_RD);
}
/*
* There is a small window between registering the if_arrival
diff --git a/sys/compat/linuxkpi/common/include/linux/ieee80211.h b/sys/compat/linuxkpi/common/include/linux/ieee80211.h
index b9161c586d07..17041bb03ce8 100644
--- a/sys/compat/linuxkpi/common/include/linux/ieee80211.h
+++ b/sys/compat/linuxkpi/common/include/linux/ieee80211.h
@@ -408,6 +408,14 @@ enum ieee80211_sta_state {
IEEE80211_STA_AUTHORIZED = 4, /* 802.1x */
};
+enum ieee80211_sta_rx_bandwidth {
+ IEEE80211_STA_RX_BW_20 = 0,
+ IEEE80211_STA_RX_BW_40,
+ IEEE80211_STA_RX_BW_80,
+ IEEE80211_STA_RX_BW_160,
+ IEEE80211_STA_RX_BW_320,
+};
+
enum ieee80211_tx_info_flags {
/* XXX TODO .. right shift numbers - not sure where that came from? */
IEEE80211_TX_CTL_AMPDU = BIT(0),
@@ -524,24 +532,24 @@ struct ieee80211_mgmt {
uint16_t beacon_int;
uint16_t capab_info;
uint8_t variable[0];
- } beacon;
+ } __packed beacon;
/* 9.3.3.5 Association Request frame format */
struct {
uint16_t capab_info;
uint16_t listen_interval;
uint8_t variable[0];
- } assoc_req;
+ } __packed assoc_req;
/* 9.3.3.10 Probe Request frame format */
struct {
uint8_t variable[0];
- } probe_req;
+ } __packed probe_req;
/* 9.3.3.11 Probe Response frame format */
struct {
uint64_t timestamp;
uint16_t beacon_int;
uint16_t capab_info;
uint8_t variable[0];
- } probe_resp;
+ } __packed probe_resp;
/* 9.3.3.14 Action frame format */
struct {
/* 9.4.1.11 Action field */
@@ -557,7 +565,7 @@ struct ieee80211_mgmt {
uint8_t tpc_elem_length;
uint8_t tpc_elem_tx_power;
uint8_t tpc_elem_link_margin;
- } tpc_report;
+ } __packed tpc_report;
/* 9.6.8.33 Fine Timing Measurement frame format */
struct {
uint8_t dialog_token;
@@ -567,7 +575,7 @@ struct ieee80211_mgmt {
uint16_t tod_error;
uint16_t toa_error;
uint8_t variable[0];
- } ftm;
+ } __packed ftm;
/* 802.11-2016, 9.6.5.2 ADDBA Request frame format */
struct {
uint8_t action_code;
@@ -577,16 +585,16 @@ struct ieee80211_mgmt {
uint16_t start_seq_num;
/* Optional follows... */
uint8_t variable[0];
- } addba_req;
+ } __packed addba_req;
/* XXX */
struct {
uint8_t dialog_token;
- } wnm_timing_msr;
+ } __packed wnm_timing_msr;
} u;
- } action;
+ } __packed action;
DECLARE_FLEX_ARRAY(uint8_t, body);
} u;
-};
+} __packed __aligned(2);
struct ieee80211_cts { /* net80211::ieee80211_frame_cts */
__le16 frame_control;
diff --git a/sys/compat/linuxkpi/common/include/linux/skbuff.h b/sys/compat/linuxkpi/common/include/linux/skbuff.h
index c8ad90281e34..6e41c368a8b8 100644
--- a/sys/compat/linuxkpi/common/include/linux/skbuff.h
+++ b/sys/compat/linuxkpi/common/include/linux/skbuff.h
@@ -1,6 +1,6 @@
/*-
* Copyright (c) 2020-2025 The FreeBSD Foundation
- * Copyright (c) 2021-2023 Bjoern A. Zeeb
+ * Copyright (c) 2021-2025 Bjoern A. Zeeb
*
* This software was developed by Björn Zeeb under sponsorship from
* the FreeBSD Foundation.
@@ -47,13 +47,11 @@
#include <linux/ktime.h>
#include <linux/compiler.h>
-#include "opt_wlan.h"
-
-/* Currently this is only used for wlan so we can depend on that. */
-#if defined(IEEE80211_DEBUG) && !defined(SKB_DEBUG)
-#define SKB_DEBUG
-#endif
-
+/*
+ * At least the net/intel-irdma-kmod port pulls this header in; likely through
+ * if_ether.h (see PR289268). This means we no longer can rely on
+ * IEEE80211_DEBUG (opt_wlan.h) to automatically set SKB_DEBUG.
+ */
/* #define SKB_DEBUG */
#ifdef SKB_DEBUG
@@ -120,7 +118,7 @@ enum sk_checksum_flags {
CHECKSUM_NONE = 0x00,
CHECKSUM_UNNECESSARY = 0x01,
CHECKSUM_PARTIAL = 0x02,
- CHECKSUM_COMPLETE = 0x04,
+ CHECKSUM_COMPLETE = 0x03,
};
struct skb_frag {
@@ -170,7 +168,7 @@ struct sk_buff {
};
};
uint16_t protocol;
- uint8_t ip_summed;
+ uint8_t ip_summed; /* 2 bit only. */
/* uint8_t */
/* "Scratch" area for layers to store metadata. */
diff --git a/sys/compat/linuxkpi/common/include/linux/string_helpers.h b/sys/compat/linuxkpi/common/include/linux/string_helpers.h
index 1bdff2730361..2c6fe0b1708d 100644
--- a/sys/compat/linuxkpi/common/include/linux/string_helpers.h
+++ b/sys/compat/linuxkpi/common/include/linux/string_helpers.h
@@ -66,4 +66,6 @@ str_enable_disable(bool value)
return "disable";
}
+#define str_disable_enable(_v) str_enable_disable(!(_v))
+
#endif
diff --git a/sys/compat/linuxkpi/common/include/net/mac80211.h b/sys/compat/linuxkpi/common/include/net/mac80211.h
index 0106e6648bd4..8de03410c6b6 100644
--- a/sys/compat/linuxkpi/common/include/net/mac80211.h
+++ b/sys/compat/linuxkpi/common/include/net/mac80211.h
@@ -737,7 +737,7 @@ struct ieee80211_link_sta {
struct ieee80211_he_6ghz_capa he_6ghz_capa;
struct ieee80211_sta_eht_cap eht_cap;
uint8_t rx_nss;
- enum ieee80211_sta_rx_bw bandwidth;
+ enum ieee80211_sta_rx_bandwidth bandwidth;
enum ieee80211_smps_mode smps_mode;
struct ieee80211_sta_agg agg;
struct ieee80211_sta_txpwr txpwr;
diff --git a/sys/compat/linuxkpi/common/src/linux_80211.c b/sys/compat/linuxkpi/common/src/linux_80211.c
index e248588dd275..f0881773726f 100644
--- a/sys/compat/linuxkpi/common/src/linux_80211.c
+++ b/sys/compat/linuxkpi/common/src/linux_80211.c
@@ -77,6 +77,8 @@
#include <linux/rculist.h>
#include "linux_80211.h"
+/* #define LKPI_80211_USE_SCANLIST */
+/* #define LKPI_80211_BGSCAN */
#define LKPI_80211_WME
#define LKPI_80211_HW_CRYPTO
#define LKPI_80211_HT
@@ -103,6 +105,10 @@ SYSCTL_DECL(_compat_linuxkpi);
SYSCTL_NODE(_compat_linuxkpi, OID_AUTO, 80211, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
"LinuxKPI 802.11 compatibility layer");
+static bool lkpi_order_scanlist = false;
+SYSCTL_BOOL(_compat_linuxkpi_80211, OID_AUTO, order_scanlist, CTLFLAG_RW,
+ &lkpi_order_scanlist, 0, "Enable LinuxKPI 802.11 scan list shuffeling");
+
#if defined(LKPI_80211_HW_CRYPTO)
static bool lkpi_hwcrypto = false;
SYSCTL_BOOL(_compat_linuxkpi_80211, OID_AUTO, hw_crypto, CTLFLAG_RDTUN,
@@ -167,6 +173,7 @@ const struct cfg80211_ops linuxkpi_mac80211cfgops = {
static struct lkpi_sta *lkpi_find_lsta_by_ni(struct lkpi_vif *,
struct ieee80211_node *);
#endif
+static void lkpi_sw_scan_task(void *, int);
static void lkpi_80211_txq_tx_one(struct lkpi_sta *, struct mbuf *);
static void lkpi_80211_txq_task(void *, int);
static void lkpi_80211_lhw_rxq_task(void *, int);
@@ -394,7 +401,7 @@ lkpi_80211_dump_stas(SYSCTL_HANDLER_ARGS)
return (0);
}
-static enum ieee80211_sta_rx_bw
+static enum ieee80211_sta_rx_bandwidth
lkpi_cw_to_rx_bw(enum nl80211_chan_width cw)
{
switch (cw) {
@@ -418,7 +425,7 @@ lkpi_cw_to_rx_bw(enum nl80211_chan_width cw)
}
static enum nl80211_chan_width
-lkpi_rx_bw_to_cw(enum ieee80211_sta_rx_bw rx_bw)
+lkpi_rx_bw_to_cw(enum ieee80211_sta_rx_bandwidth rx_bw)
{
switch (rx_bw) {
case IEEE80211_STA_RX_BW_20:
@@ -439,7 +446,7 @@ lkpi_sync_chanctx_cw_from_rx_bw(struct ieee80211_hw *hw,
struct ieee80211_vif *vif, struct ieee80211_sta *sta)
{
struct ieee80211_chanctx_conf *chanctx_conf;
- enum ieee80211_sta_rx_bw old_bw;
+ enum ieee80211_sta_rx_bandwidth old_bw;
uint32_t changed;
chanctx_conf = rcu_dereference_protected(vif->bss_conf.chanctx_conf,
@@ -544,7 +551,7 @@ static void
lkpi_sta_sync_vht_from_ni(struct ieee80211_vif *vif, struct ieee80211_sta *sta,
struct ieee80211_node *ni)
{
- enum ieee80211_sta_rx_bw bw;
+ enum ieee80211_sta_rx_bandwidth bw;
uint32_t width;
int rx_nss;
uint16_t rx_mcs_map;
@@ -955,6 +962,30 @@ lkpi_nl80211_band_to_net80211_band(enum nl80211_band band)
return (0x00);
}
+#ifdef LINUXKPI_DEBUG_80211
+static const char *
+lkpi_nl80211_band_name(enum nl80211_band band)
+{
+ switch (band) {
+ case NL80211_BAND_2GHZ:
+ return "2Ghz";
+ break;
+ case NL80211_BAND_5GHZ:
+ return "5Ghz";
+ break;
+ case NL80211_BAND_60GHZ:
+ return "60Ghz";
+ break;
+ case NL80211_BAND_6GHZ:
+ return "6Ghz";
+ break;
+ default:
+ panic("%s: unsupported band %u\n", __func__, band);
+ break;
+ }
+}
+#endif
+
#if 0
static enum ieee80211_ac_numbers
lkpi_ac_net_to_l80211(int ac)
@@ -1319,6 +1350,7 @@ lkpi_iv_key_delete(struct ieee80211vap *vap, const struct ieee80211_key *k)
lhw = ic->ic_softc;
hw = LHW_TO_HW(lhw);
lvif = VAP_TO_LVIF(vap);
+ vif = LVIF_TO_VIF(lvif);
/*
* Make sure we do not make it here without going through
@@ -1326,6 +1358,23 @@ lkpi_iv_key_delete(struct ieee80211vap *vap, const struct ieee80211_key *k)
*/
lockdep_assert_wiphy(hw->wiphy);
+ /*
+ * While we are assoc we may still send packets. We cannot delete the
+ * keys as otherwise packets could go out unencrypted. Some firmware
+ * does not like this and will fire an assert.
+ * net80211 needs to drive this better but given we want the disassoc
+ * frame out and have to unlock we are open to a race currently.
+ * This check should prevent problems.
+ * How to test: run 800Mbit/s UDP traffic and during that restart your
+ * supplicant. You want to survive that.
+ */
+ if (vif->cfg.assoc) {
+ if (linuxkpi_debug_80211 & D80211_TRACE_HW_CRYPTO)
+ ic_printf(ic, "%d %lu %s: vif still assoc; not deleting keys\n",
+ curthread->td_tid, jiffies, __func__);
+ return (0);
+ }
+
if (IEEE80211_KEY_UNDEFINED(k)) {
ic_printf(ic, "%s: vap %p key %p is undefined: %p %u\n",
__func__, vap, k, k->wk_cipher, k->wk_keyix);
@@ -1370,7 +1419,6 @@ lkpi_iv_key_delete(struct ieee80211vap *vap, const struct ieee80211_key *k)
kc->keyidx, kc->hw_key_idx, kc->flags, IEEE80211_KEY_FLAG_BITS);
#endif
- vif = LVIF_TO_VIF(lvif);
error = lkpi_80211_mo_set_key(hw, DISABLE_KEY, vif, sta, kc);
if (error != 0) {
ic_printf(ic, "%d %lu %s: set_key cmd %d(%s) for sta %6D failed: %d\n",
@@ -1842,13 +1890,31 @@ lkpi_update_dtim_tsf(struct ieee80211_vif *vif, struct ieee80211_node *ni,
vif->bss_conf.beacon_int = 16;
bss_changed |= BSS_CHANGED_BEACON_INT;
}
- if (vif->bss_conf.dtim_period != vap->iv_dtim_period &&
- vap->iv_dtim_period > 0) {
- vif->bss_conf.dtim_period = vap->iv_dtim_period;
+
+ /*
+ * lkpi_iv_sta_recv_mgmt() will directly call into this function.
+ * iwlwifi(4) in iwl_mvm_bss_info_changed_station_common() will
+ * stop seesion protection the moment it sees
+ * BSS_CHANGED_BEACON_INFO (with the expectations that it was
+ * "a beacon from the associated AP"). It will also update
+ * the beacon filter in that case. This is the only place
+ * we set the BSS_CHANGED_BEACON_INFO on the non-teardown
+ * path so make sure we only do run this check once we are
+ * assoc. (*iv_recv_mgmt)() will be called before we enter
+ * here so the ni will be updates with information from the
+ * beacon via net80211::sta_recv_mgmt(). We also need to
+ * make sure we do not do it on every beacon we still may
+ * get so only do if something changed. vif->bss_conf.dtim_period
+ * should be 0 as we start up (we also reset it on teardown).
+ */
+ if (vif->cfg.assoc &&
+ vif->bss_conf.dtim_period != ni->ni_dtim_period &&
+ ni->ni_dtim_period > 0) {
+ vif->bss_conf.dtim_period = ni->ni_dtim_period;
bss_changed |= BSS_CHANGED_BEACON_INFO;
}
- vif->bss_conf.sync_dtim_count = vap->iv_dtim_count;
+ vif->bss_conf.sync_dtim_count = ni->ni_dtim_count;
vif->bss_conf.sync_tsf = le64toh(ni->ni_tstamp.tsf);
/* vif->bss_conf.sync_device_ts = set in linuxkpi_ieee80211_rx. */
@@ -1876,6 +1942,8 @@ lkpi_stop_hw_scan(struct lkpi_hw *lhw, struct ieee80211_vif *vif)
int error;
bool cancel;
+ TRACE_SCAN(lhw->ic, "scan_flags %b", lhw->scan_flags, LKPI_LHW_SCAN_BITS);
+
LKPI_80211_LHW_SCAN_LOCK(lhw);
cancel = (lhw->scan_flags & LKPI_LHW_SCAN_RUNNING) != 0;
LKPI_80211_LHW_SCAN_UNLOCK(lhw);
@@ -2798,6 +2866,14 @@ _lkpi_sta_assoc_to_down(struct ieee80211vap *vap, enum ieee80211_state nstate, i
bss_changed = 0;
bss_changed |= lkpi_disassoc(sta, vif, lhw);
+#ifdef LKPI_80211_HW_CRYPTO
+ /*
+ * In theory we remove keys here but there must not exist any for this
+ * state change until we clean them up again into small steps and no
+ * code duplication.
+ */
+#endif
+
lkpi_lsta_dump(lsta, ni, __func__, __LINE__);
/* Adjust sta and change state (from NONE) to NOTEXIST. */
@@ -3333,6 +3409,16 @@ lkpi_sta_run_to_init(struct ieee80211vap *vap, enum ieee80211_state nstate, int
#ifdef LKPI_80211_HW_CRYPTO
if (lkpi_hwcrypto) {
+ /*
+ * In theory we only need to do this if we changed assoc.
+ * If we were not assoc, there should be no keys and we
+ * should not be here.
+ */
+#ifdef notyet
+ KASSERT((bss_changed & BSS_CHANGED_ASSOC) != 0, ("%s: "
+ "trying to remove keys but were not assoc: %#010jx, lvif %p\n",
+ __func__, (uintmax_t)bss_changed, lvif));
+#endif
error = lkpi_sta_del_keys(hw, vif, lsta);
if (error != 0) {
ic_printf(vap->iv_ic, "%s:%d: lkpi_sta_del_keys "
@@ -3394,6 +3480,9 @@ lkpi_sta_run_to_init(struct ieee80211vap *vap, enum ieee80211_state nstate, int
* 4) call unassign_vif_chanctx
* 5) call lkpi_hw_conf_idle
* 6) call remove_chanctx
+ *
+ * Note: vif->driver_flags & IEEE80211_VIF_REMOVE_AP_AFTER_DISASSOC
+ * might change this.
*/
bss_changed |= lkpi_disassoc(sta, vif, lhw);
@@ -3545,7 +3634,7 @@ lkpi_iv_newstate(struct ieee80211vap *vap, enum ieee80211_state nstate, int arg)
vif = LVIF_TO_VIF(lvif);
/* No need to replicate this in most state handlers. */
- if (ostate == IEEE80211_S_SCAN && nstate != IEEE80211_S_SCAN)
+ if (nstate > IEEE80211_S_SCAN)
lkpi_stop_hw_scan(lhw, vif);
s = sta_state_fsm;
@@ -3739,6 +3828,7 @@ lkpi_iv_sta_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0,
enum ieee80211_bss_changed bss_changed;
lvif = VAP_TO_LVIF(ni->ni_vap);
+ vif = LVIF_TO_VIF(lvif);
lvif->iv_recv_mgmt(ni, m0, subtype, rxs, rssi, nf);
@@ -3746,13 +3836,18 @@ lkpi_iv_sta_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0,
case IEEE80211_FC0_SUBTYPE_PROBE_RESP:
break;
case IEEE80211_FC0_SUBTYPE_BEACON:
- lvif->beacons++;
+ /*
+ * Only count beacons when assoc. SCAN has its own logging.
+ * This is for connection/beacon loss/session protection almost
+ * over debugging when trying to get into a stable RUN state.
+ */
+ if (vif->cfg.assoc)
+ lvif->beacons++;
break;
default:
return;
}
- vif = LVIF_TO_VIF(lvif);
lhw = ni->ni_ic->ic_softc;
hw = LHW_TO_HW(lhw);
@@ -3824,6 +3919,7 @@ lkpi_ic_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ],
lvif = malloc(len, M_80211_VAP, M_WAITOK | M_ZERO);
mtx_init(&lvif->mtx, "lvif", NULL, MTX_DEF);
+ TASK_INIT(&lvif->sw_scan_task, 0, lkpi_sw_scan_task, lvif);
INIT_LIST_HEAD(&lvif->lsta_list);
lvif->lvif_bss = NULL;
refcount_init(&lvif->nt_unlocked, 0);
@@ -3987,13 +4083,9 @@ lkpi_ic_vap_create(struct ieee80211com *ic, const char name[IFNAMSIZ],
* Modern chipset/fw/drv will do A-MPDU in drv/fw and fail
* to do so if they cannot do the crypto too.
*/
- if (!lkpi_hwcrypto && ieee80211_hw_check(hw, AMPDU_AGGREGATION))
+ if (!lkpi_hwcrypto && IEEE80211_CONF_AMPDU_OFFLOAD(ic))
vap->iv_flags_ht &= ~IEEE80211_FHT_AMPDU_RX;
#endif
-#if defined(LKPI_80211_HT)
- /* 20250125-BZ Keep A-MPDU TX cleared until we sorted out AddBA for all drivers. */
- vap->iv_flags_ht &= ~IEEE80211_FHT_AMPDU_TX;
-#endif
if (hw->max_listen_interval == 0)
hw->max_listen_interval = 7 * (ic->ic_lintval / ic->ic_bintval);
@@ -4062,6 +4154,8 @@ lkpi_ic_vap_delete(struct ieee80211vap *vap)
/* Clear up per-VIF/VAP sysctls. */
sysctl_ctx_free(&lvif->sysctl_ctx);
+ ieee80211_draintask(ic, &lvif->sw_scan_task);
+
LKPI_80211_LHW_LVIF_LOCK(lhw);
TAILQ_REMOVE(&lhw->lvif_head, lvif, lvif_entry);
LKPI_80211_LHW_LVIF_UNLOCK(lhw);
@@ -4303,6 +4397,113 @@ lkpi_scan_ies_add(uint8_t *p, struct ieee80211_scan_ies *scan_ies,
}
static void
+lkpi_enable_hw_scan(struct lkpi_hw *lhw)
+{
+
+ if (lhw->ops->hw_scan) {
+ /*
+ * Advertise full-offload scanning.
+ *
+ * Not limiting to SINGLE_SCAN_ON_ALL_BANDS here as otherwise
+ * we essentially disable hw_scan for all drivers not setting
+ * the flag.
+ */
+ lhw->ic->ic_flags_ext |= IEEE80211_FEXT_SCAN_OFFLOAD;
+ lhw->scan_flags |= LKPI_LHW_SCAN_HW;
+ }
+}
+
+#ifndef LKPI_80211_USE_SCANLIST
+static const uint32_t chan_pri[] = {
+ 5180, 5500, 5745,
+ 5260, 5580, 5660, 5825,
+ 5220, 5300, 5540, 5620, 5700, 5785, 5865,
+ 2437, 2412, 2422, 2462, 2472, 2432, 2452
+};
+
+static int
+lkpi_scan_chan_list_idx(const struct linuxkpi_ieee80211_channel *lc)
+{
+ int i;
+
+ for (i = 0; i < nitems(chan_pri); i++) {
+ if (lc->center_freq == chan_pri[i])
+ return (i);
+ }
+
+ return (-1);
+}
+
+static int
+lkpi_scan_chan_list_comp(const struct linuxkpi_ieee80211_channel *lc1,
+ const struct linuxkpi_ieee80211_channel *lc2)
+{
+ int idx1, idx2;
+
+ /* Find index in list. */
+ idx1 = lkpi_scan_chan_list_idx(lc1);
+ idx2 = lkpi_scan_chan_list_idx(lc2);
+
+ if (idx1 == -1 && idx2 != -1)
+ return (1);
+ if (idx1 != -1 && idx2 == -1)
+ return (-1);
+
+ /* Neither on the list, use center_freq. */
+ if (idx1 == -1 && idx2 == -1)
+ return (lc1->center_freq - lc2->center_freq);
+
+ /* Whichever is first in the list. */
+ return (idx1 - idx2);
+}
+
+static void
+lkpi_scan_chan_list_resort(struct linuxkpi_ieee80211_channel **cpp, size_t nchan)
+{
+ struct linuxkpi_ieee80211_channel *lc, *nc;
+ size_t i, j;
+ int rc;
+
+ for (i = (nchan - 1); i > 0; i--) {
+ for (j = i; j > 0 ; j--) {
+ lc = *(cpp + j);
+ nc = *(cpp + j - 1);
+ rc = lkpi_scan_chan_list_comp(lc, nc);
+ if (rc < 0) {
+ *(cpp + j) = nc;
+ *(cpp + j - 1) = lc;
+ }
+ }
+ }
+}
+
+static bool
+lkpi_scan_chan(struct linuxkpi_ieee80211_channel *c,
+ struct ieee80211com *ic, bool log)
+{
+
+ if ((c->flags & IEEE80211_CHAN_DISABLED) != 0) {
+ if (log)
+ TRACE_SCAN(ic, "Skipping disabled chan "
+ "on band %s [%#x/%u/%#x]",
+ lkpi_nl80211_band_name(c->band), c->hw_value,
+ c->center_freq, c->flags);
+ return (false);
+ }
+ if (isclr(ic->ic_chan_active, ieee80211_mhz2ieee(c->center_freq,
+ lkpi_nl80211_band_to_net80211_band(c->band)))) {
+ if (log)
+ TRACE_SCAN(ic, "Skipping !active chan "
+ "on band %s [%#x/%u/%#x]",
+ lkpi_nl80211_band_name(c->band), c->hw_value,
+ c->center_freq, c->flags);
+ return (false);
+ }
+ return (true);
+}
+#endif
+
+static void
lkpi_ic_scan_start(struct ieee80211com *ic)
{
struct lkpi_hw *lhw;
@@ -4315,35 +4516,52 @@ lkpi_ic_scan_start(struct ieee80211com *ic)
bool is_hw_scan;
lhw = ic->ic_softc;
+ ss = ic->ic_scan;
+ vap = ss->ss_vap;
+ TRACE_SCAN(ic, "scan_flags %b", lhw->scan_flags, LKPI_LHW_SCAN_BITS);
+
LKPI_80211_LHW_SCAN_LOCK(lhw);
if ((lhw->scan_flags & LKPI_LHW_SCAN_RUNNING) != 0) {
/* A scan is still running. */
LKPI_80211_LHW_SCAN_UNLOCK(lhw);
+ TRACE_SCAN(ic, "Trying to start new scan while still running; "
+ "cancelling new net80211 scan; scan_flags %b",
+ lhw->scan_flags, LKPI_LHW_SCAN_BITS);
+ ieee80211_cancel_scan(vap);
return;
}
is_hw_scan = (lhw->scan_flags & LKPI_LHW_SCAN_HW) != 0;
LKPI_80211_LHW_SCAN_UNLOCK(lhw);
- ss = ic->ic_scan;
- vap = ss->ss_vap;
+#if 0
if (vap->iv_state != IEEE80211_S_SCAN) {
- IMPROVE("We need to be able to scan if not in S_SCAN");
+ TODO("We need to be able to scan if not in S_SCAN");
+ TRACE_SCAN(ic, "scan_flags %b iv_state %d",
+ lhw->scan_flags, LKPI_LHW_SCAN_BITS, vap->iv_state);
+ ieee80211_cancel_scan(vap);
return;
}
+#endif
hw = LHW_TO_HW(lhw);
if (!is_hw_scan) {
/* If hw_scan is cleared clear FEXT_SCAN_OFFLOAD too. */
vap->iv_flags_ext &= ~IEEE80211_FEXT_SCAN_OFFLOAD;
-sw_scan:
+
lvif = VAP_TO_LVIF(vap);
vif = LVIF_TO_VIF(lvif);
if (vap->iv_state == IEEE80211_S_SCAN)
lkpi_hw_conf_idle(hw, false);
+ LKPI_80211_LHW_SCAN_LOCK(lhw);
+ lhw->scan_flags |= LKPI_LHW_SCAN_RUNNING;
+ LKPI_80211_LHW_SCAN_UNLOCK(lhw);
+
lkpi_update_mcast_filter(ic);
+ TRACE_SCAN(vap->iv_ic, "Starting SW_SCAN: scan_flags %b",
+ lhw->scan_flags, LKPI_LHW_SCAN_BITS);
lkpi_80211_mo_sw_scan_start(hw, vif, vif->addr);
/* net80211::scan_start() handled PS for us. */
IMPROVE();
@@ -4358,6 +4576,9 @@ sw_scan:
struct cfg80211_scan_6ghz_params *s6gp;
size_t chan_len, nchan, ssids_len, s6ghzlen;
int band, i, ssid_count, common_ie_len;
+#ifndef LKPI_80211_USE_SCANLIST
+ int n;
+#endif
uint32_t band_mask;
uint8_t *ie, *ieend;
bool running;
@@ -4369,7 +4590,8 @@ sw_scan:
band_mask = 0;
nchan = 0;
if (ieee80211_hw_check(hw, SINGLE_SCAN_ON_ALL_BANDS)) {
-#if 0 /* Avoid net80211 scan lists until it has proper scan offload support. */
+#ifdef LKPI_80211_USE_SCANLIST
+ /* Avoid net80211 scan lists until it has proper scan offload support. */
for (i = ss->ss_next; i < ss->ss_last; i++) {
nchan++;
band = lkpi_net80211_chan_to_nl80211_band(
@@ -4387,8 +4609,17 @@ sw_scan:
continue;
}
if (hw->wiphy->bands[band] != NULL) {
- nchan += hw->wiphy->bands[band]->n_channels;
+ struct linuxkpi_ieee80211_channel *channels;
+ int n;
+
band_mask |= (1 << band);
+
+ channels = hw->wiphy->bands[band]->channels;
+ n = hw->wiphy->bands[band]->n_channels;
+ for (i = 0; i < n; i++) {
+ if (lkpi_scan_chan(&channels[i], ic, true))
+ nchan++;
+ }
}
}
#endif
@@ -4427,11 +4658,32 @@ sw_scan:
/* hw_req->req.wdev */
hw_req->req.wiphy = hw->wiphy;
hw_req->req.no_cck = false; /* XXX */
-#if 0
- /* This seems to pessimise default scanning behaviour. */
- hw_req->req.duration_mandatory = TICKS_2_USEC(ss->ss_mindwell);
- hw_req->req.duration = TICKS_2_USEC(ss->ss_maxdwell);
-#endif
+
+ /*
+ * In general setting duration[_mandatory] seems to pessimise
+ * default scanning behaviour. We only use it for BGSCANnig
+ * to keep the dwell times small.
+ * Setting duration_mandatory makes this the maximum dwell
+ * time (otherwise may be shorter). Duration is in TU.
+ */
+ if ((ic->ic_flags_ext & IEEE80211_FEXT_BGSCAN) != 0) {
+ unsigned long dwell;
+
+ if ((ic->ic_caps & IEEE80211_C_BGSCAN) == 0 ||
+ (vap->iv_flags & IEEE80211_F_BGSCAN) == 0)
+ ic_printf(ic, "BGSCAN despite off: %b, %b, %b\n",
+ ic->ic_flags_ext, IEEE80211_FEXT_BITS,
+ vap->iv_flags, IEEE80211_F_BITS,
+ ic->ic_caps, IEEE80211_C_BITS);
+
+ dwell = ss->ss_mindwell;
+ if (dwell == 0)
+ dwell = msecs_to_ticks(20);
+
+ hw_req->req.duration_mandatory = true;
+ hw_req->req.duration = TICKS_2_USEC(dwell) / 1024;
+ }
+
#ifdef __notyet__
hw_req->req.flags |= NL80211_SCAN_FLAG_RANDOM_ADDR;
memcpy(hw_req->req.mac_addr, xxx, IEEE80211_ADDR_LEN);
@@ -4442,11 +4694,12 @@ sw_scan:
hw_req->req.n_channels = nchan;
cpp = (struct linuxkpi_ieee80211_channel **)(hw_req + 1);
lc = (struct linuxkpi_ieee80211_channel *)(cpp + nchan);
+#ifdef LKPI_80211_USE_SCANLIST
for (i = 0; i < nchan; i++) {
*(cpp + i) =
(struct linuxkpi_ieee80211_channel *)(lc + i);
}
-#if 0 /* Avoid net80211 scan lists until it has proper scan offload support. */
+ /* Avoid net80211 scan lists until it has proper scan offload support. */
for (i = 0; i < nchan; i++) {
struct ieee80211_channel *c;
@@ -4459,7 +4712,9 @@ sw_scan:
lc++;
}
#else
- for (band = 0; band < NUM_NL80211_BANDS; band++) {
+ /* Add bands in reverse order for scanning. */
+ n = 0;
+ for (band = NUM_NL80211_BANDS - 1; band >= 0; band--) {
struct ieee80211_supported_band *supband;
struct linuxkpi_ieee80211_channel *channels;
@@ -4474,11 +4729,30 @@ sw_scan:
channels = supband->channels;
for (i = 0; i < supband->n_channels; i++) {
- *lc = channels[i];
- lc++;
+ if (lkpi_scan_chan(&channels[i], ic, false))
+ *(cpp + n++) = &channels[i];
}
}
+ if (lkpi_order_scanlist)
+ lkpi_scan_chan_list_resort(cpp, nchan);
+
+ if ((linuxkpi_debug_80211 & D80211_SCAN) != 0) {
+ printf("%s:%d: %s SCAN Channel List (nchan=%zu): ",
+ __func__, __LINE__, ic->ic_name, nchan);
+ for (i = 0; i < nchan; i++) {
+ struct linuxkpi_ieee80211_channel *xc;
+
+ xc = *(cpp + i);
+ printf(" %d(%d)",
+ ieee80211_mhz2ieee(xc->center_freq,
+ lkpi_nl80211_band_to_net80211_band(
+ xc->band)),
+ xc->center_freq);
+ }
+ printf("\n");
+ }
#endif
+
hw_req->req.n_ssids = ssid_count;
if (hw_req->req.n_ssids > 0) {
ssids = (struct cfg80211_ssid *)lc;
@@ -4505,6 +4779,7 @@ sw_scan:
ieend = lkpi_scan_ies_add(ie, &hw_req->ies, band_mask, vap, hw);
hw_req->req.ie = ie;
hw_req->req.ie_len = ieend - ie;
+ hw_req->req.scan_start = jiffies;
lvif = VAP_TO_LVIF(vap);
vif = LVIF_TO_VIF(lvif);
@@ -4522,13 +4797,30 @@ sw_scan:
LKPI_80211_LHW_SCAN_UNLOCK(lhw);
if (running) {
free(hw_req, M_LKPI80211);
+ TRACE_SCAN(ic, "Trying to start new scan while still "
+ "running (2); cancelling new net80211 scan; "
+ "scan_flags %b",
+ lhw->scan_flags, LKPI_LHW_SCAN_BITS);
+ ieee80211_cancel_scan(vap);
return;
}
lkpi_update_mcast_filter(ic);
+ TRACE_SCAN(ic, "Starting HW_SCAN: scan_flags %b, "
+ "ie_len %d, n_ssids %d, n_chan %d, common_ie_len %d [%d, %d]",
+ lhw->scan_flags, LKPI_LHW_SCAN_BITS, hw_req->req.ie_len,
+ hw_req->req.n_ssids, hw_req->req.n_channels,
+ hw_req->ies.common_ie_len,
+ hw_req->ies.len[NL80211_BAND_2GHZ],
+ hw_req->ies.len[NL80211_BAND_5GHZ]);
error = lkpi_80211_mo_hw_scan(hw, vif, hw_req);
if (error != 0) {
+ bool scan_done;
+ int e;
+
+ TRACE_SCAN(ic, "hw_scan failed; scan_flags %b, error %d",
+ lhw->scan_flags, LKPI_LHW_SCAN_BITS, error);
ieee80211_cancel_scan(vap);
/*
@@ -4545,14 +4837,35 @@ sw_scan:
* So we cannot rely on that behaviour and have to check
* and balance between both code paths.
*/
+ e = 0;
+ scan_done = true;
LKPI_80211_LHW_SCAN_LOCK(lhw);
if ((lhw->scan_flags & LKPI_LHW_SCAN_RUNNING) != 0) {
+
free(lhw->hw_req, M_LKPI80211);
lhw->hw_req = NULL;
+ /*
+ * The ieee80211_cancel_scan() above runs in a
+ * taskq and it may take ages for the previous
+ * scan to clear; starting a new one right away
+ * we run into the problem that the old one is
+ * still active.
+ */
+ e = msleep(lhw, &lhw->scan_mtx, 0, "lhwscanstop", hz);
+ scan_done = (lhw->scan_flags & LKPI_LHW_SCAN_RUNNING) != 0;
+
+ /*
+ * Now we can clear running if no one else did.
+ */
lhw->scan_flags &= ~LKPI_LHW_SCAN_RUNNING;
}
LKPI_80211_LHW_SCAN_UNLOCK(lhw);
lkpi_update_mcast_filter(ic);
+ if (!scan_done) {
+ ic_printf(ic, "ERROR: %s: timeout/error to wait "
+ "for ieee80211_cancel_scan: %d\n", __func__, e);
+ return;
+ }
/*
* XXX-SIGH magic number.
@@ -4560,24 +4873,15 @@ sw_scan:
* not possible. Fall back to sw scan in that case.
*/
if (error == 1) {
- LKPI_80211_LHW_SCAN_LOCK(lhw);
- lhw->scan_flags &= ~LKPI_LHW_SCAN_HW;
- LKPI_80211_LHW_SCAN_UNLOCK(lhw);
/*
- * XXX If we clear this now and later a driver
- * thinks it * can do a hw_scan again, we will
- * currently not re-enable it?
+ * We need to put this into some defered context
+ * the net80211 scan may not be done yet
+ * (ic_flags & IEEE80211_F_SCAN) and we cannot
+ * wait here; if we do scan_curchan_task always
+ * runs after our timeout to finalize the scan.
*/
- vap->iv_flags_ext &= ~IEEE80211_FEXT_SCAN_OFFLOAD;
- ieee80211_start_scan(vap,
- IEEE80211_SCAN_ACTIVE |
- IEEE80211_SCAN_NOPICK |
- IEEE80211_SCAN_ONCE,
- IEEE80211_SCAN_FOREVER,
- ss->ss_mindwell ? ss->ss_mindwell : msecs_to_ticks(20),
- ss->ss_maxdwell ? ss->ss_maxdwell : msecs_to_ticks(200),
- vap->iv_des_nssid, vap->iv_des_ssid);
- goto sw_scan;
+ ieee80211_runtask(ic, &lvif->sw_scan_task);
+ return;
}
ic_printf(ic, "ERROR: %s: hw_scan returned %d\n",
@@ -4587,12 +4891,50 @@ sw_scan:
}
static void
+lkpi_sw_scan_task(void *arg, int pending __unused)
+{
+ struct lkpi_hw *lhw;
+ struct lkpi_vif *lvif;
+ struct ieee80211vap *vap;
+ struct ieee80211_scan_state *ss;
+
+ lvif = arg;
+ vap = LVIF_TO_VAP(lvif);
+ lhw = vap->iv_ic->ic_softc;
+ ss = vap->iv_ic->ic_scan;
+
+ LKPI_80211_LHW_SCAN_LOCK(lhw);
+ /*
+ * We will re-enable this at scan_end calling lkpi_enable_hw_scan().
+ * IEEE80211_FEXT_SCAN_OFFLOAD will be cleared by lkpi_ic_scan_start.
+ */
+ lhw->scan_flags &= ~LKPI_LHW_SCAN_HW;
+ LKPI_80211_LHW_SCAN_UNLOCK(lhw);
+
+ TRACE_SCAN(vap->iv_ic, "Triggering SW_SCAN: pending %d, scan_flags %b",
+ pending, lhw->scan_flags, LKPI_LHW_SCAN_BITS);
+
+ /*
+ * This will call ic_scan_start() and we will get into the right path
+ * unless other scans started in between.
+ */
+ ieee80211_start_scan(vap,
+ IEEE80211_SCAN_ONCE,
+ msecs_to_ticks(10000), /* 10000 ms (=~ 50 chan * 200 ms) */
+ ss->ss_mindwell ? ss->ss_mindwell : msecs_to_ticks(20),
+ ss->ss_maxdwell ? ss->ss_maxdwell : msecs_to_ticks(200),
+ vap->iv_des_nssid, vap->iv_des_ssid);
+}
+
+static void
lkpi_ic_scan_end(struct ieee80211com *ic)
{
struct lkpi_hw *lhw;
bool is_hw_scan;
lhw = ic->ic_softc;
+ TRACE_SCAN(ic, "scan_flags %b", lhw->scan_flags, LKPI_LHW_SCAN_BITS);
+
LKPI_80211_LHW_SCAN_LOCK(lhw);
if ((lhw->scan_flags & LKPI_LHW_SCAN_RUNNING) == 0) {
LKPI_80211_LHW_SCAN_UNLOCK(lhw);
@@ -4621,6 +4963,16 @@ lkpi_ic_scan_end(struct ieee80211com *ic)
if (vap->iv_state == IEEE80211_S_SCAN)
lkpi_hw_conf_idle(hw, true);
}
+
+ /*
+ * In case we disabled the hw_scan in lkpi_ic_scan_start() and
+ * switched to swscan, re-enable hw_scan if available.
+ */
+ lkpi_enable_hw_scan(lhw);
+
+ LKPI_80211_LHW_SCAN_LOCK(lhw);
+ wakeup(lhw);
+ LKPI_80211_LHW_SCAN_UNLOCK(lhw);
}
static void
@@ -4631,6 +4983,10 @@ lkpi_ic_scan_curchan(struct ieee80211_scan_state *ss,
bool is_hw_scan;
lhw = ss->ss_ic->ic_softc;
+ TRACE_SCAN(ss->ss_ic, "scan_flags %b chan %d maxdwell %lu",
+ lhw->scan_flags, LKPI_LHW_SCAN_BITS,
+ ss->ss_ic->ic_curchan->ic_ieee, maxdwell);
+
LKPI_80211_LHW_SCAN_LOCK(lhw);
is_hw_scan = (lhw->scan_flags & LKPI_LHW_SCAN_HW) != 0;
LKPI_80211_LHW_SCAN_UNLOCK(lhw);
@@ -4645,6 +5001,10 @@ lkpi_ic_scan_mindwell(struct ieee80211_scan_state *ss)
bool is_hw_scan;
lhw = ss->ss_ic->ic_softc;
+ TRACE_SCAN(ss->ss_ic, "scan_flags %b chan %d mindwell %lu",
+ lhw->scan_flags, LKPI_LHW_SCAN_BITS,
+ ss->ss_ic->ic_curchan->ic_ieee, ss->ss_mindwell);
+
LKPI_80211_LHW_SCAN_LOCK(lhw);
is_hw_scan = (lhw->scan_flags & LKPI_LHW_SCAN_HW) != 0;
LKPI_80211_LHW_SCAN_UNLOCK(lhw);
@@ -6042,6 +6402,7 @@ linuxkpi_ieee80211_alloc_hw(size_t priv_len, const struct ieee80211_ops *ops)
LKPI_80211_LHW_SCAN_LOCK_INIT(lhw);
LKPI_80211_LHW_TXQ_LOCK_INIT(lhw);
+ spin_lock_init(&lhw->txq_lock);
sx_init_flags(&lhw->lvif_sx, "lhw-lvif", SX_RECURSE | SX_DUPOK);
LKPI_80211_LHW_MC_LOCK_INIT(lhw);
TAILQ_INIT(&lhw->lvif_head);
@@ -6147,6 +6508,7 @@ linuxkpi_ieee80211_iffree(struct ieee80211_hw *hw)
LKPI_80211_LHW_MC_UNLOCK(lhw);
/* Cleanup more of lhw here or in wiphy_free()? */
+ spin_lock_destroy(&lhw->txq_lock);
LKPI_80211_LHW_TXQ_LOCK_DESTROY(lhw);
LKPI_80211_LHW_SCAN_LOCK_DESTROY(lhw);
sx_destroy(&lhw->lvif_sx);
@@ -6255,26 +6617,26 @@ linuxkpi_ieee80211_ifattach(struct ieee80211_hw *hw)
IEEE80211_C_SHSLOT | /* short slot time supported */
IEEE80211_C_SHPREAMBLE /* short preamble supported */
;
-#if 0
- /* Scanning is a different kind of beast to re-work. */
- ic->ic_caps |= IEEE80211_C_BGSCAN;
+
+#ifdef LKPI_80211_BGSCAN
+ if (lhw->ops->hw_scan)
+ ic->ic_caps |= IEEE80211_C_BGSCAN;
#endif
- if (lhw->ops->hw_scan) {
- /*
- * Advertise full-offload scanning.
- *
- * Not limiting to SINGLE_SCAN_ON_ALL_BANDS here as otherwise
- * we essentially disable hw_scan for all drivers not setting
- * the flag.
- */
- ic->ic_flags_ext |= IEEE80211_FEXT_SCAN_OFFLOAD;
- lhw->scan_flags |= LKPI_LHW_SCAN_HW;
- }
+
+ lkpi_enable_hw_scan(lhw);
/* Does HW support Fragmentation offload? */
if (ieee80211_hw_check(hw, SUPPORTS_TX_FRAG))
ic->ic_flags_ext |= IEEE80211_FEXT_FRAG_OFFLOAD;
+ /* Does HW support full AMPDU[-TX] offload? */
+ if (ieee80211_hw_check(hw, AMPDU_AGGREGATION))
+ ic->ic_flags_ext |= IEEE80211_FEXT_AMPDU_OFFLOAD;
+#ifdef __notyet__
+ if (ieee80211_hw_check(hw, TX_AMSDU))
+ if (ieee80211_hw_check(hw, SUPPORTS_AMSDU_IN_AMPDU))
+#endif
+
/*
* The wiphy variables report bitmasks of avail antennas.
* (*get_antenna) get the current bitmask sets which can be
@@ -6726,13 +7088,19 @@ linuxkpi_ieee80211_scan_completed(struct ieee80211_hw *hw,
ic = lhw->ic;
ss = ic->ic_scan;
+ TRACE_SCAN(ic, "scan_flags %b info { %ju, %6D, aborted %d }",
+ lhw->scan_flags, LKPI_LHW_SCAN_BITS,
+ (uintmax_t)info->scan_start_tsf, info->tsf_bssid, ":",
+ info->aborted);
+
ieee80211_scan_done(ss->ss_vap);
LKPI_80211_LHW_SCAN_LOCK(lhw);
free(lhw->hw_req, M_LKPI80211);
lhw->hw_req = NULL;
lhw->scan_flags &= ~LKPI_LHW_SCAN_RUNNING;
- wakeup(lhw);
+ /* The wakeup(lhw) will be called from lkpi_ic_scan_end(). */
+ /* wakeup(lhw); */
LKPI_80211_LHW_SCAN_UNLOCK(lhw);
return;
@@ -7002,6 +7370,63 @@ lkpi_convert_rx_status(struct ieee80211_hw *hw, struct lkpi_sta *lsta,
}
}
+#ifdef LINUXKPI_DEBUG_80211
+static void
+lkpi_rx_log_beacon(struct mbuf *m, struct lkpi_hw *lhw,
+ struct ieee80211_rx_status *rx_status)
+{
+ struct ieee80211_mgmt *f;
+ uint8_t *e;
+ char ssid[IEEE80211_NWID_LEN * 4 + 1];
+
+ memset(ssid, '\0', sizeof(ssid));
+
+ f = mtod(m, struct ieee80211_mgmt *);
+ e = f->u.beacon.variable;
+ /*
+ * Usually SSID is right after the fixed part and for debugging we will
+ * be fine should we miss it if it is not.
+ */
+ while ((e - (uint8_t *)f) < m->m_len) {
+ if (*e == IEEE80211_ELEMID_SSID)
+ break;
+ e += (2 + *(e + 1));
+ }
+ if (*e == IEEE80211_ELEMID_SSID) {
+ int i, len;
+ char *p;
+
+ p = ssid;
+ len = m->m_len - ((e + 2) - (uint8_t *)f);
+ if (len > *(e + 1))
+ len = *(e + 1);
+ e += 2;
+ for (i = 0; i < len; i++) {
+ /* Printable character? */
+ if (*e >= 0x20 && *e < 0x7f) {
+ *p++ = *e++;
+ } else {
+ snprintf(p, 5, "%#04x", *e++);
+ p += 4;
+ }
+ }
+ *p = '\0';
+ }
+
+ /* We print skb, skb->data, m as we are seeing 'ghost beacons'. */
+ TRACE_SCAN_BEACON(lhw->ic, "Beacon: scan_flags %b, band %s freq %u chan %-4d "
+ "len %d { %#06x %#06x %6D %6D %6D %#06x %ju %u %#06x SSID '%s' }",
+ lhw->scan_flags, LKPI_LHW_SCAN_BITS,
+ lkpi_nl80211_band_name(rx_status->band), rx_status->freq,
+ linuxkpi_ieee80211_frequency_to_channel(rx_status->freq, 0),
+ m->m_pkthdr.len, f->frame_control, f->duration_id,
+ f->da, ":", f->sa, ":", f->bssid, ":", f->seq_ctrl,
+ (uintmax_t)le64_to_cpu(f->u.beacon.timestamp),
+ le16_to_cpu(f->u.beacon.beacon_int),
+ le16_to_cpu(f->u.beacon.capab_info), ssid);
+}
+#endif
+
/* For %list see comment towards the end of the function. */
void
linuxkpi_ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb,
@@ -7058,7 +7483,15 @@ linuxkpi_ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb,
is_beacon = ieee80211_is_beacon(hdr->frame_control);
#ifdef LINUXKPI_DEBUG_80211
- if (is_beacon && (linuxkpi_debug_80211 & D80211_TRACE_RX_BEACONS) == 0)
+ /*
+ * We use the mbuf here as otherwise the variable part might
+ * be in skb frags.
+ */
+ if (is_beacon && ((linuxkpi_debug_80211 & D80211_SCAN_BEACON) != 0))
+ lkpi_rx_log_beacon(m, lhw, rx_status);
+
+ if (is_beacon && (linuxkpi_debug_80211 & D80211_TRACE_RX_BEACONS) == 0 &&
+ (linuxkpi_debug_80211 & D80211_SCAN_BEACON) == 0)
goto no_trace_beacons;
if (linuxkpi_debug_80211 & D80211_TRACE_RX)
@@ -7073,7 +7506,8 @@ linuxkpi_ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb,
hexdump(mtod(m, const void *), m->m_len, "RX (raw) ", 0);
/* Implement a dump_rxcb() !!! */
- if (linuxkpi_debug_80211 & D80211_TRACE_RX)
+ if ((linuxkpi_debug_80211 & D80211_TRACE_RX) != 0 ||
+ (linuxkpi_debug_80211 & D80211_SCAN_BEACON) != 0)
printf("TRACE-RX: %s: RXCB: %ju %ju %u, %b, %u, %#0x, %#0x, "
"%u band %u, %u { %d %d %d %d }, %d, %#x %#x %#x %#x %u %u %u\n",
__func__,
@@ -8124,21 +8558,30 @@ lkpi_ieee80211_wake_queues_locked(struct ieee80211_hw *hw)
void
linuxkpi_ieee80211_wake_queues(struct ieee80211_hw *hw)
{
- wiphy_lock(hw->wiphy);
+ struct lkpi_hw *lhw;
+ unsigned long flags;
+
+ lhw = HW_TO_LHW(hw);
+
+ spin_lock_irqsave(&lhw->txq_lock, flags);
lkpi_ieee80211_wake_queues_locked(hw);
- wiphy_unlock(hw->wiphy);
+ spin_unlock_irqrestore(&lhw->txq_lock, flags);
}
void
linuxkpi_ieee80211_wake_queue(struct ieee80211_hw *hw, int qnum)
{
+ struct lkpi_hw *lhw;
+ unsigned long flags;
KASSERT(qnum < hw->queues, ("%s: qnum %d >= hw->queues %d, hw %p\n",
__func__, qnum, hw->queues, hw));
- wiphy_lock(hw->wiphy);
+ lhw = HW_TO_LHW(hw);
+
+ spin_lock_irqsave(&lhw->txq_lock, flags);
lkpi_ieee80211_wake_queues(hw, qnum);
- wiphy_unlock(hw->wiphy);
+ spin_unlock_irqrestore(&lhw->txq_lock, flags);
}
/* This is just hardware queues. */
diff --git a/sys/compat/linuxkpi/common/src/linux_80211.h b/sys/compat/linuxkpi/common/src/linux_80211.h
index eaf6d804af4c..0dfcd7646c34 100644
--- a/sys/compat/linuxkpi/common/src/linux_80211.h
+++ b/sys/compat/linuxkpi/common/src/linux_80211.h
@@ -59,6 +59,8 @@
#define D80211_IMPROVE_TXQ 0x00000004
#define D80211_TRACE 0x00000010
#define D80211_TRACEOK 0x00000020
+#define D80211_SCAN 0x00000040
+#define D80211_SCAN_BEACON 0x00000080
#define D80211_TRACE_TX 0x00000100
#define D80211_TRACE_TX_DUMP 0x00000200
#define D80211_TRACE_RX 0x00001000
@@ -75,6 +77,20 @@
#define D80211_TRACE_MODE_HE 0x04000000
#define D80211_TRACE_MODE_EHT 0x08000000
+#ifdef LINUXKPI_DEBUG_80211
+#define TRACE_SCAN(ic, fmt, ...) \
+ if (linuxkpi_debug_80211 & D80211_SCAN) \
+ printf("%s:%d: %s SCAN " fmt "\n", \
+ __func__, __LINE__, ic->ic_name, ##__VA_ARGS__)
+#define TRACE_SCAN_BEACON(ic, fmt, ...) \
+ if (linuxkpi_debug_80211 & D80211_SCAN_BEACON) \
+ printf("%s:%d: %s SCAN " fmt "\n", \
+ __func__, __LINE__, ic->ic_name, ##__VA_ARGS__)
+#else
+#define TRACE_SCAN(...) do {} while (0)
+#define TRACE_SCAN_BEACON(...) do {} while (0)
+#endif
+
#define IMPROVE_TXQ(...) \
if (linuxkpi_debug_80211 & D80211_IMPROVE_TXQ) \
printf("%s:%d: XXX LKPI80211 IMPROVE_TXQ\n", __func__, __LINE__)
@@ -191,6 +207,7 @@ struct lkpi_vif {
struct mbuf *, int,
const struct ieee80211_rx_stats *,
int, int);
+ struct task sw_scan_task;
struct list_head lsta_list;
@@ -236,6 +253,7 @@ struct lkpi_hw { /* name it mac80211_sc? */
struct mtx txq_mtx;
uint32_t txq_generation[IEEE80211_NUM_ACS];
TAILQ_HEAD(, lkpi_txq) scheduled_txqs[IEEE80211_NUM_ACS];
+ spinlock_t txq_lock;
/* Deferred RX path. */
struct task rxq_task;
@@ -298,6 +316,9 @@ struct lkpi_hw { /* name it mac80211_sc? */
#define LHW_TO_HW(_lhw) (&(_lhw)->hw)
#define HW_TO_LHW(_hw) container_of(_hw, struct lkpi_hw, hw)
+#define LKPI_LHW_SCAN_BITS \
+ "\010\1RUNING\2HW"
+
struct lkpi_chanctx {
struct list_head entry;
diff --git a/sys/conf/files b/sys/conf/files
index d89813c70355..9661bafea8f9 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -3808,6 +3808,7 @@ kern/kern_hhook.c standard
kern/kern_idle.c standard
kern/kern_intr.c standard
kern/kern_jail.c standard
+kern/kern_jaildesc.c standard
kern/kern_jailmeta.c standard
kern/kern_kcov.c optional kcov \
compile-with "${NOSAN_C} ${MSAN_CFLAGS}"
diff --git a/sys/conf/newvers.sh b/sys/conf/newvers.sh
index 8b60da95741e..145377c1e75e 100644
--- a/sys/conf/newvers.sh
+++ b/sys/conf/newvers.sh
@@ -50,8 +50,8 @@
#
TYPE="FreeBSD"
-REVISION="15.0"
-BRANCH="PRERELEASE"
+REVISION="16.0"
+BRANCH="CURRENT"
if [ -n "${BRANCH_OVERRIDE}" ]; then
BRANCH=${BRANCH_OVERRIDE}
fi
diff --git a/sys/conf/options b/sys/conf/options
index 4009ba2b4843..66f7f2ee2d7e 100644
--- a/sys/conf/options
+++ b/sys/conf/options
@@ -53,7 +53,7 @@ DDB_CAPTURE_MAXBUFSIZE opt_ddb.h
DDB_CTF opt_ddb.h
DDB_NUMSYM opt_ddb.h
EARLY_PRINTF opt_global.h
-BLOAT_KERNEL_WITH_EXTERR opt_global.h
+EXTERR_STRINGS opt_global.h
FULL_BUF_TRACKING opt_global.h
GDB
KDB opt_global.h
diff --git a/sys/contrib/dev/rtw88/main.c b/sys/contrib/dev/rtw88/main.c
index 021d076808e0..963b73f35350 100644
--- a/sys/contrib/dev/rtw88/main.c
+++ b/sys/contrib/dev/rtw88/main.c
@@ -57,6 +57,62 @@ module_param_named(support_vht, rtw_vht_support, bool, 0644);
MODULE_PARM_DESC(support_vht, "Set to Y to enable VHT support");
#endif
+#if defined(__FreeBSD__)
+/* Macros based on rtw89::core.c. */
+#define RTW88_DEF_CHAN(_freq, _hw_val, _flags, _band) \
+ { .center_freq = _freq, .hw_value = _hw_val, .flags = _flags, .band = _band, }
+#define RTW88_DEF_CHAN_2G(_freq, _hw_val) \
+ RTW88_DEF_CHAN(_freq, _hw_val, 0, NL80211_BAND_2GHZ)
+#define RTW88_DEF_CHAN_5G(_freq, _hw_val) \
+ RTW88_DEF_CHAN(_freq, _hw_val, 0, NL80211_BAND_5GHZ)
+#define RTW88_DEF_CHAN_5G_NO_HT40MINUS(_freq, _hw_val) \
+ RTW88_DEF_CHAN(_freq, _hw_val, IEEE80211_CHAN_NO_HT40MINUS, NL80211_BAND_5GHZ)
+
+static struct ieee80211_channel rtw_channeltable_2g[] = {
+ RTW88_DEF_CHAN_2G(2412, 1),
+ RTW88_DEF_CHAN_2G(2417, 2),
+ RTW88_DEF_CHAN_2G(2422, 3),
+ RTW88_DEF_CHAN_2G(2427, 4),
+ RTW88_DEF_CHAN_2G(2432, 5),
+ RTW88_DEF_CHAN_2G(2437, 6),
+ RTW88_DEF_CHAN_2G(2442, 7),
+ RTW88_DEF_CHAN_2G(2447, 8),
+ RTW88_DEF_CHAN_2G(2452, 9),
+ RTW88_DEF_CHAN_2G(2457, 10),
+ RTW88_DEF_CHAN_2G(2462, 11),
+ RTW88_DEF_CHAN_2G(2467, 12),
+ RTW88_DEF_CHAN_2G(2472, 13),
+ RTW88_DEF_CHAN_2G(2484, 14),
+};
+
+static struct ieee80211_channel rtw_channeltable_5g[] = {
+ RTW88_DEF_CHAN_5G(5180, 36),
+ RTW88_DEF_CHAN_5G(5200, 40),
+ RTW88_DEF_CHAN_5G(5220, 44),
+ RTW88_DEF_CHAN_5G(5240, 48),
+ RTW88_DEF_CHAN_5G(5260, 52),
+ RTW88_DEF_CHAN_5G(5280, 56),
+ RTW88_DEF_CHAN_5G(5300, 60),
+ RTW88_DEF_CHAN_5G(5320, 64),
+ RTW88_DEF_CHAN_5G(5500, 100),
+ RTW88_DEF_CHAN_5G(5520, 104),
+ RTW88_DEF_CHAN_5G(5540, 108),
+ RTW88_DEF_CHAN_5G(5560, 112),
+ RTW88_DEF_CHAN_5G(5580, 116),
+ RTW88_DEF_CHAN_5G(5600, 120),
+ RTW88_DEF_CHAN_5G(5620, 124),
+ RTW88_DEF_CHAN_5G(5640, 128),
+ RTW88_DEF_CHAN_5G(5660, 132),
+ RTW88_DEF_CHAN_5G(5680, 136),
+ RTW88_DEF_CHAN_5G(5700, 140),
+ RTW88_DEF_CHAN_5G(5720, 144),
+ RTW88_DEF_CHAN_5G(5745, 149),
+ RTW88_DEF_CHAN_5G(5765, 153),
+ RTW88_DEF_CHAN_5G(5785, 157),
+ RTW88_DEF_CHAN_5G(5805, 161),
+ RTW88_DEF_CHAN_5G_NO_HT40MINUS(5825, 165),
+};
+#elif deifned(__linux__)
static struct ieee80211_channel rtw_channeltable_2g[] = {
{.center_freq = 2412, .hw_value = 1,},
{.center_freq = 2417, .hw_value = 2,},
@@ -102,6 +158,7 @@ static struct ieee80211_channel rtw_channeltable_5g[] = {
{.center_freq = 5825, .hw_value = 165,
.flags = IEEE80211_CHAN_NO_HT40MINUS},
};
+#endif
static struct ieee80211_rate rtw_ratetable[] = {
{.bitrate = 10, .hw_value = 0x00,},
diff --git a/sys/contrib/dev/rtw89/fw.c b/sys/contrib/dev/rtw89/fw.c
index e360f27c2ade..b4c0f864bc75 100644
--- a/sys/contrib/dev/rtw89/fw.c
+++ b/sys/contrib/dev/rtw89/fw.c
@@ -908,11 +908,7 @@ int rtw89_build_phy_tbl_from_elm(struct rtw89_dev *rtwdev,
case RTW89_FW_ELEMENT_ID_RADIO_B:
case RTW89_FW_ELEMENT_ID_RADIO_C:
case RTW89_FW_ELEMENT_ID_RADIO_D:
-#if defined(__linux__)
rf_path = arg.rf_path;
-#elif defined(__FreeBSD__)
- rf_path = __DECONST(enum rtw89_rf_path, arg.rf_path);
-#endif
idx = elm->u.reg2.idx;
elm_info->rf_radio[idx] = tbl;
diff --git a/sys/dev/ath/ath_rate/sample/sample.c b/sys/dev/ath/ath_rate/sample/sample.c
index 291d1ec64ed7..79bf08678249 100644
--- a/sys/dev/ath/ath_rate/sample/sample.c
+++ b/sys/dev/ath/ath_rate/sample/sample.c
@@ -179,7 +179,7 @@ ath_rate_sample_find_min_pktlength(struct ath_softc *sc,
const struct txschedule *sched = &sn->sched[rix0];
int max_pkt_length = 65530; // ATH_AGGR_MAXSIZE
// Note: this may not be true in all cases; need to check?
- int is_ht40 = (an->an_node.ni_chw == IEEE80211_STA_RX_BW_40);
+ int is_ht40 = (an->an_node.ni_chw == NET80211_STA_RX_BW_40);
// Note: not great, but good enough..
int idx = is_ht40 ? MCS_HT40 : MCS_HT20;
@@ -979,7 +979,7 @@ update_stats(struct ath_softc *sc, struct ath_node *an,
const int size_bin = size_to_bin(frame_size);
const int size = bin_to_size(size_bin);
int tt;
- int is_ht40 = (an->an_node.ni_chw == IEEE80211_STA_RX_BW_40);
+ int is_ht40 = (an->an_node.ni_chw == NET80211_STA_RX_BW_40);
int pct;
if (!IS_RATE_DEFINED(sn, rix0))
@@ -1365,7 +1365,7 @@ ath_rate_ctl_reset(struct ath_softc *sc, struct ieee80211_node *ni)
continue;
printf(" %d %s/%d", dot11rate(rt, rix), dot11rate_label(rt, rix),
calc_usecs_unicast_packet(sc, 1600, rix, 0,0,
- (ni->ni_chw == IEEE80211_STA_RX_BW_40)));
+ (ni->ni_chw == NET80211_STA_RX_BW_40)));
}
printf("\n");
}
@@ -1396,7 +1396,7 @@ ath_rate_ctl_reset(struct ath_softc *sc, struct ieee80211_node *ni)
sn->stats[y][rix].perfect_tx_time =
calc_usecs_unicast_packet(sc, size, rix, 0, 0,
- (ni->ni_chw == IEEE80211_STA_RX_BW_40));
+ (ni->ni_chw == NET80211_STA_RX_BW_40));
sn->stats[y][rix].average_tx_time =
sn->stats[y][rix].perfect_tx_time;
}
diff --git a/sys/dev/ath/if_ath_tx_ht.c b/sys/dev/ath/if_ath_tx_ht.c
index e7ee029fecf0..f42058bacb0d 100644
--- a/sys/dev/ath/if_ath_tx_ht.c
+++ b/sys/dev/ath/if_ath_tx_ht.c
@@ -283,7 +283,7 @@ ath_tx_rate_fill_rcflags(struct ath_softc *sc, struct ath_buf *bf)
if (IS_HT_RATE(rate)) {
rc[i].flags |= ATH_RC_HT_FLAG;
- if (ni->ni_chw == IEEE80211_STA_RX_BW_40)
+ if (ni->ni_chw == NET80211_STA_RX_BW_40)
rc[i].flags |= ATH_RC_CW40_FLAG;
/*
@@ -295,13 +295,13 @@ ath_tx_rate_fill_rcflags(struct ath_softc *sc, struct ath_buf *bf)
* and doesn't return the fractional part, so
* we are always "out" by some amount.
*/
- if (ni->ni_chw == IEEE80211_STA_RX_BW_40 &&
+ if (ni->ni_chw == NET80211_STA_RX_BW_40 &&
ieee80211_ht_check_tx_shortgi_40(ni) &&
(bf->bf_flags & ATH_BUF_TOA_PROBE) == 0) {
rc[i].flags |= ATH_RC_SGI_FLAG;
}
- if (ni->ni_chw == IEEE80211_STA_RX_BW_20 &&
+ if (ni->ni_chw == NET80211_STA_RX_BW_20 &&
ieee80211_ht_check_tx_shortgi_20(ni) &&
(bf->bf_flags & ATH_BUF_TOA_PROBE) == 0) {
rc[i].flags |= ATH_RC_SGI_FLAG;
diff --git a/sys/dev/cxgbe/t4_main.c b/sys/dev/cxgbe/t4_main.c
index 9e91250cb61c..9756a6945384 100644
--- a/sys/dev/cxgbe/t4_main.c
+++ b/sys/dev/cxgbe/t4_main.c
@@ -9016,7 +9016,7 @@ sysctl_loadavg(SYSCTL_HANDLER_ARGS)
rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4lavg");
if (rc)
return (rc);
- if (hw_all_ok(sc))
+ if (!hw_all_ok(sc))
rc = ENXIO;
else {
param = V_FW_PARAMS_MNEM(FW_PARAMS_MNEM_DEV) |
diff --git a/sys/dev/cyapa/cyapa.c b/sys/dev/cyapa/cyapa.c
index 50fa4faa560a..ed755f992949 100644
--- a/sys/dev/cyapa/cyapa.c
+++ b/sys/dev/cyapa/cyapa.c
@@ -761,42 +761,60 @@ again:
/*
* Generate report
*/
- c0 = 0;
- if (delta_x < 0)
- c0 |= 0x10;
- if (delta_y < 0)
- c0 |= 0x20;
- c0 |= 0x08;
- if (but & CYAPA_FNGR_LEFT)
- c0 |= 0x01;
- if (but & CYAPA_FNGR_MIDDLE)
- c0 |= 0x04;
- if (but & CYAPA_FNGR_RIGHT)
- c0 |= 0x02;
-
- fifo_write_char(sc, &sc->rfifo, c0);
- fifo_write_char(sc, &sc->rfifo, (uint8_t)delta_x);
- fifo_write_char(sc, &sc->rfifo, (uint8_t)delta_y);
- switch(sc->zenabled) {
- case 1:
- /* Z axis all 8 bits */
- fifo_write_char(sc, &sc->rfifo, (uint8_t)delta_z);
- break;
- case 2:
- /*
- * Z axis low 4 bits + 4th button and 5th button
- * (high 2 bits must be left 0). Auto-scale
- * delta_z to fit to avoid a wrong-direction
- * overflow (don't try to retain the remainder).
- */
- while (delta_z > 7 || delta_z < -8)
- delta_z >>= 1;
- c0 = (uint8_t)delta_z & 0x0F;
+ if (sc->mode.level == 1) {
+ c0 = MOUSE_SYS_SYNC;
+ if (but & CYAPA_FNGR_LEFT)
+ c0 |= MOUSE_SYS_BUTTON1UP;
+ if (but & CYAPA_FNGR_MIDDLE)
+ c0 |= MOUSE_SYS_BUTTON2UP;
+ if (but & CYAPA_FNGR_RIGHT)
+ c0 |= MOUSE_SYS_BUTTON3UP;
fifo_write_char(sc, &sc->rfifo, c0);
- break;
- default:
- /* basic PS/2 */
- break;
+ fifo_write_char(sc, &sc->rfifo, delta_x >> 1);
+ fifo_write_char(sc, &sc->rfifo, delta_y >> 1);
+ fifo_write_char(sc, &sc->rfifo, delta_x - (delta_x >> 1));
+ fifo_write_char(sc, &sc->rfifo, delta_y - (delta_y >> 1));
+ fifo_write_char(sc, &sc->rfifo, delta_z >> 1);
+ fifo_write_char(sc, &sc->rfifo, delta_z - (delta_z >> 1));
+ fifo_write_char(sc, &sc->rfifo, MOUSE_SYS_EXTBUTTONS);
+ } else {
+ c0 = 0;
+ if (delta_x < 0)
+ c0 |= 0x10;
+ if (delta_y < 0)
+ c0 |= 0x20;
+ c0 |= 0x08;
+ if (but & CYAPA_FNGR_LEFT)
+ c0 |= 0x01;
+ if (but & CYAPA_FNGR_MIDDLE)
+ c0 |= 0x04;
+ if (but & CYAPA_FNGR_RIGHT)
+ c0 |= 0x02;
+
+ fifo_write_char(sc, &sc->rfifo, c0);
+ fifo_write_char(sc, &sc->rfifo, (uint8_t)delta_x);
+ fifo_write_char(sc, &sc->rfifo, (uint8_t)delta_y);
+ switch(sc->zenabled) {
+ case 1:
+ /* Z axis all 8 bits */
+ fifo_write_char(sc, &sc->rfifo, (uint8_t)delta_z);
+ break;
+ case 2:
+ /*
+ * Z axis low 4 bits + 4th button and 5th button
+ * (high 2 bits must be left 0). Auto-scale
+ * delta_z to fit to avoid a wrong-direction
+ * overflow (don't try to retain the remainder).
+ */
+ while (delta_z > 7 || delta_z < -8)
+ delta_z >>= 1;
+ c0 = (uint8_t)delta_z & 0x0F;
+ fifo_write_char(sc, &sc->rfifo, c0);
+ break;
+ default:
+ /* basic PS/2 */
+ break;
+ }
}
cyapa_notify(sc);
}
@@ -1205,6 +1223,11 @@ cyapaioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, struct thread
((mousemode_t *)data)->packetsize =
MOUSE_PS2_PACKETSIZE;
break;
+ case 1:
+ ((mousemode_t *)data)->protocol = MOUSE_PROTO_SYSMOUSE;
+ ((mousemode_t *)data)->packetsize =
+ MOUSE_SYS_PACKETSIZE;
+ break;
case 2:
((mousemode_t *)data)->protocol = MOUSE_PROTO_PS2;
((mousemode_t *)data)->packetsize =
@@ -1223,7 +1246,7 @@ cyapaioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, struct thread
error = EINVAL;
break;
}
- sc->mode.level = *(int *)data ? 2 : 0;
+ sc->mode.level = *(int *)data;
sc->zenabled = sc->mode.level ? 1 : 0;
break;
diff --git a/sys/dev/mpr/mpr.c b/sys/dev/mpr/mpr.c
index d1c572e40669..262d6b58b705 100644
--- a/sys/dev/mpr/mpr.c
+++ b/sys/dev/mpr/mpr.c
@@ -1729,6 +1729,7 @@ mpr_get_tunables(struct mpr_softc *sc)
sc->enable_ssu = MPR_SSU_ENABLE_SSD_DISABLE_HDD;
sc->spinup_wait_time = DEFAULT_SPINUP_WAIT;
sc->use_phynum = 1;
+ sc->encl_min_slots = 0;
sc->max_reqframes = MPR_REQ_FRAMES;
sc->max_prireqframes = MPR_PRI_REQ_FRAMES;
sc->max_replyframes = MPR_REPLY_FRAMES;
@@ -1748,6 +1749,7 @@ mpr_get_tunables(struct mpr_softc *sc)
TUNABLE_INT_FETCH("hw.mpr.enable_ssu", &sc->enable_ssu);
TUNABLE_INT_FETCH("hw.mpr.spinup_wait_time", &sc->spinup_wait_time);
TUNABLE_INT_FETCH("hw.mpr.use_phy_num", &sc->use_phynum);
+ TUNABLE_INT_FETCH("hw.mpr.encl_min_slots", &sc->encl_min_slots);
TUNABLE_INT_FETCH("hw.mpr.max_reqframes", &sc->max_reqframes);
TUNABLE_INT_FETCH("hw.mpr.max_prireqframes", &sc->max_prireqframes);
TUNABLE_INT_FETCH("hw.mpr.max_replyframes", &sc->max_replyframes);
@@ -1797,6 +1799,10 @@ mpr_get_tunables(struct mpr_softc *sc)
device_get_unit(sc->mpr_dev));
TUNABLE_INT_FETCH(tmpstr, &sc->use_phynum);
+ snprintf(tmpstr, sizeof(tmpstr), "dev.mpr.%d.encl_min_slots",
+ device_get_unit(sc->mpr_dev));
+ TUNABLE_INT_FETCH(tmpstr, &sc->encl_min_slots);
+
snprintf(tmpstr, sizeof(tmpstr), "dev.mpr.%d.max_reqframes",
device_get_unit(sc->mpr_dev));
TUNABLE_INT_FETCH(tmpstr, &sc->max_reqframes);
@@ -1951,6 +1957,10 @@ mpr_setup_sysctl(struct mpr_softc *sc)
SYSCTL_ADD_UQUAD(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
OID_AUTO, "prp_page_alloc_fail", CTLFLAG_RD,
&sc->prp_page_alloc_fail, "PRP page allocation failures");
+
+ SYSCTL_ADD_INT(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree),
+ OID_AUTO, "encl_min_slots", CTLFLAG_RW, &sc->encl_min_slots, 0,
+ "force enclosure minimum slots");
}
static struct mpr_debug_string {
diff --git a/sys/dev/mpr/mpr_mapping.c b/sys/dev/mpr/mpr_mapping.c
index f9a9ac1c53d0..38aa4dfc7ef2 100644
--- a/sys/dev/mpr/mpr_mapping.c
+++ b/sys/dev/mpr/mpr_mapping.c
@@ -2785,6 +2785,8 @@ mpr_mapping_enclosure_dev_status_change_event(struct mpr_softc *sc,
* DPM, if it's being used.
*/
if (enc_idx != MPR_ENCTABLE_BAD_IDX) {
+ u16 new_num_slots;
+
et_entry = &sc->enclosure_table[enc_idx];
if (et_entry->init_complete &&
!et_entry->missing_count) {
@@ -2796,6 +2798,17 @@ mpr_mapping_enclosure_dev_status_change_event(struct mpr_softc *sc,
et_entry->enc_handle = le16toh(event_data->
EnclosureHandle);
et_entry->start_slot = le16toh(event_data->StartSlot);
+ new_num_slots = le16toh(event_data->NumSlots);
+ if (new_num_slots < sc->encl_min_slots) {
+ mpr_dprint(sc, MPR_MAPPING, "%s: Enclosure %d num_slots %d, overriding with %d.\n",
+ __func__, enc_idx, new_num_slots, sc->encl_min_slots);
+ new_num_slots = sc->encl_min_slots;
+ }
+ if (et_entry->num_slots != new_num_slots) {
+ mpr_dprint(sc, MPR_MAPPING, "%s: Enclosure %d old num_slots %d, new %d.\n",
+ __func__, enc_idx, et_entry->num_slots, sc->encl_min_slots);
+ et_entry->num_slots = new_num_slots;
+ }
saved_phy_bits = et_entry->phy_bits;
et_entry->phy_bits |= le32toh(event_data->PhyBits);
if (saved_phy_bits != et_entry->phy_bits)
@@ -2858,6 +2871,11 @@ mpr_mapping_enclosure_dev_status_change_event(struct mpr_softc *sc,
et_entry->start_index = MPR_MAPTABLE_BAD_IDX;
et_entry->dpm_entry_num = MPR_DPM_BAD_IDX;
et_entry->num_slots = le16toh(event_data->NumSlots);
+ if (et_entry->num_slots < sc->encl_min_slots) {
+ mpr_dprint(sc, MPR_ERROR | MPR_MAPPING, "%s: Enclosure %d num_slots is %d, overriding with %d.\n",
+ __func__, enc_idx, et_entry->num_slots, sc->encl_min_slots);
+ et_entry->num_slots = sc->encl_min_slots;
+ }
et_entry->start_slot = le16toh(event_data->StartSlot);
et_entry->phy_bits = le32toh(event_data->PhyBits);
}
diff --git a/sys/dev/mpr/mprvar.h b/sys/dev/mpr/mprvar.h
index 0f1743f4266e..93f3fbffe079 100644
--- a/sys/dev/mpr/mprvar.h
+++ b/sys/dev/mpr/mprvar.h
@@ -366,6 +366,7 @@ struct mpr_softc {
int spinup_wait_time;
int use_phynum;
int dump_reqs_alltypes;
+ int encl_min_slots;
uint64_t chain_alloc_fail;
uint64_t prp_page_alloc_fail;
struct sysctl_ctx_list sysctl_ctx;
diff --git a/sys/dev/mwl/if_mwl.c b/sys/dev/mwl/if_mwl.c
index 0e2eb0b2d8fe..c885968dfe15 100644
--- a/sys/dev/mwl/if_mwl.c
+++ b/sys/dev/mwl/if_mwl.c
@@ -4017,7 +4017,7 @@ mkpeerinfo(MWL_HAL_PEERINFO *pi, const struct ieee80211_node *ni)
pi->HTCapabilitiesInfo &= ~IEEE80211_HTCAP_SHORTGI40;
if ((vap->iv_flags_ht & IEEE80211_FHT_SHORTGI20) == 0)
pi->HTCapabilitiesInfo &= ~IEEE80211_HTCAP_SHORTGI20;
- if (ni->ni_chw != IEEE80211_STA_RX_BW_40)
+ if (ni->ni_chw != NET80211_STA_RX_BW_40)
pi->HTCapabilitiesInfo &= ~IEEE80211_HTCAP_CHWIDTH40;
}
return pi;
diff --git a/sys/dev/nvme/nvme_ctrlr.c b/sys/dev/nvme/nvme_ctrlr.c
index 49960b0f920a..fc912c1342f4 100644
--- a/sys/dev/nvme/nvme_ctrlr.c
+++ b/sys/dev/nvme/nvme_ctrlr.c
@@ -41,6 +41,9 @@
#include <sys/endian.h>
#include <sys/stdarg.h>
#include <vm/vm.h>
+#include <vm/vm_page.h>
+#include <vm/vm_extern.h>
+#include <vm/vm_map.h>
#include "nvme_private.h"
#include "nvme_linux.h"
@@ -1265,6 +1268,34 @@ nvme_ctrlr_shared_handler(void *arg)
nvme_mmio_write_4(ctrlr, intmc, 1);
}
+#define NVME_MAX_PAGES (int)(1024 / sizeof(vm_page_t))
+
+static int
+nvme_user_ioctl_req(vm_offset_t addr, size_t len, bool is_read,
+ vm_page_t *upages, int max_pages, int *npagesp, struct nvme_request **req,
+ nvme_cb_fn_t cb_fn, void *cb_arg)
+{
+ vm_prot_t prot = VM_PROT_READ;
+ int err;
+
+ if (is_read)
+ prot |= VM_PROT_WRITE; /* Device will write to host memory */
+ err = vm_fault_hold_pages(&curproc->p_vmspace->vm_map,
+ addr, len, prot, upages, max_pages, npagesp);
+ if (err != 0)
+ return (err);
+ *req = nvme_allocate_request_null(M_WAITOK, cb_fn, cb_arg);
+ (*req)->payload = memdesc_vmpages(upages, len, addr & PAGE_MASK);
+ (*req)->payload_valid = true;
+ return (0);
+}
+
+static void
+nvme_user_ioctl_free(vm_page_t *pages, int npage)
+{
+ vm_page_unhold_pages(pages, npage);
+}
+
static void
nvme_pt_done(void *arg, const struct nvme_completion *cpl)
{
@@ -1287,30 +1318,28 @@ nvme_pt_done(void *arg, const struct nvme_completion *cpl)
int
nvme_ctrlr_passthrough_cmd(struct nvme_controller *ctrlr,
- struct nvme_pt_command *pt, uint32_t nsid, int is_user_buffer,
+ struct nvme_pt_command *pt, uint32_t nsid, int is_user,
int is_admin_cmd)
{
- struct nvme_request *req;
- struct mtx *mtx;
- struct buf *buf = NULL;
- int ret = 0;
+ struct nvme_request *req;
+ struct mtx *mtx;
+ int ret = 0;
+ int npages = 0;
+ vm_page_t upages[NVME_MAX_PAGES];
if (pt->len > 0) {
if (pt->len > ctrlr->max_xfer_size) {
- nvme_printf(ctrlr, "pt->len (%d) "
- "exceeds max_xfer_size (%d)\n", pt->len,
- ctrlr->max_xfer_size);
- return EIO;
+ nvme_printf(ctrlr,
+ "len (%d) exceeds max_xfer_size (%d)\n",
+ pt->len, ctrlr->max_xfer_size);
+ return (EIO);
}
- if (is_user_buffer) {
- buf = uma_zalloc(pbuf_zone, M_WAITOK);
- buf->b_iocmd = pt->is_read ? BIO_READ : BIO_WRITE;
- if (vmapbuf(buf, pt->buf, pt->len, 1) < 0) {
- ret = EFAULT;
- goto err;
- }
- req = nvme_allocate_request_vaddr(buf->b_data, pt->len,
- M_WAITOK, nvme_pt_done, pt);
+ if (is_user) {
+ ret = nvme_user_ioctl_req((vm_offset_t)pt->buf, pt->len,
+ pt->is_read, upages, nitems(upages), &npages, &req,
+ nvme_pt_done, pt);
+ if (ret != 0)
+ return (ret);
} else
req = nvme_allocate_request_vaddr(pt->buf, pt->len,
M_WAITOK, nvme_pt_done, pt);
@@ -1344,11 +1373,8 @@ nvme_ctrlr_passthrough_cmd(struct nvme_controller *ctrlr,
mtx_sleep(pt, mtx, PRIBIO, "nvme_pt", 0);
mtx_unlock(mtx);
- if (buf != NULL) {
- vunmapbuf(buf);
-err:
- uma_zfree(pbuf_zone, buf);
- }
+ if (npages > 0)
+ nvme_user_ioctl_free(upages, npages);
return (ret);
}
@@ -1374,8 +1400,9 @@ nvme_ctrlr_linux_passthru_cmd(struct nvme_controller *ctrlr,
{
struct nvme_request *req;
struct mtx *mtx;
- struct buf *buf = NULL;
int ret = 0;
+ int npages = 0;
+ vm_page_t upages[NVME_MAX_PAGES];
/*
* We don't support metadata.
@@ -1386,7 +1413,7 @@ nvme_ctrlr_linux_passthru_cmd(struct nvme_controller *ctrlr,
if (npc->data_len > 0 && npc->addr != 0) {
if (npc->data_len > ctrlr->max_xfer_size) {
nvme_printf(ctrlr,
- "npc->data_len (%d) exceeds max_xfer_size (%d)\n",
+ "data_len (%d) exceeds max_xfer_size (%d)\n",
npc->data_len, ctrlr->max_xfer_size);
return (EIO);
}
@@ -1399,15 +1426,11 @@ nvme_ctrlr_linux_passthru_cmd(struct nvme_controller *ctrlr,
if ((npc->opcode & 0x3) == 3)
return (EINVAL);
if (is_user) {
- buf = uma_zalloc(pbuf_zone, M_WAITOK);
- buf->b_iocmd = npc->opcode & 1 ? BIO_WRITE : BIO_READ;
- if (vmapbuf(buf, (void *)(uintptr_t)npc->addr,
- npc->data_len, 1) < 0) {
- ret = EFAULT;
- goto err;
- }
- req = nvme_allocate_request_vaddr(buf->b_data,
- npc->data_len, M_WAITOK, nvme_npc_done, npc);
+ ret = nvme_user_ioctl_req(npc->addr, npc->data_len,
+ npc->opcode & 0x1, upages, nitems(upages), &npages,
+ &req, nvme_npc_done, npc);
+ if (ret != 0)
+ return (ret);
} else
req = nvme_allocate_request_vaddr(
(void *)(uintptr_t)npc->addr, npc->data_len,
@@ -1442,11 +1465,8 @@ nvme_ctrlr_linux_passthru_cmd(struct nvme_controller *ctrlr,
mtx_sleep(npc, mtx, PRIBIO, "nvme_npc", 0);
mtx_unlock(mtx);
- if (buf != NULL) {
- vunmapbuf(buf);
-err:
- uma_zfree(pbuf_zone, buf);
- }
+ if (npages > 0)
+ nvme_user_ioctl_free(upages, npages);
return (ret);
}
diff --git a/sys/dev/nvme/nvme_util.c b/sys/dev/nvme/nvme_util.c
index 0a07653a7378..cb0ba729ac96 100644
--- a/sys/dev/nvme/nvme_util.c
+++ b/sys/dev/nvme/nvme_util.c
@@ -208,31 +208,33 @@ nvme_opcode_sbuf(bool admin, uint8_t opc, struct sbuf *sb)
if (s == NULL)
sbuf_printf(sb, "%s (%02x)", type, opc);
else
- sbuf_printf(sb, "%s", s);
+ sbuf_printf(sb, "%s (%02x)", s, opc);
}
void
nvme_sc_sbuf(const struct nvme_completion *cpl, struct sbuf *sb)
{
const char *s, *type;
- uint16_t status;
+ uint16_t status, sc, sct;
status = le16toh(cpl->status);
- switch (NVME_STATUS_GET_SCT(status)) {
+ sc = NVME_STATUS_GET_SC(status);
+ sct = NVME_STATUS_GET_SCT(status);
+ switch (sct) {
case NVME_SCT_GENERIC:
- s = generic_status[NVME_STATUS_GET_SC(status)];
+ s = generic_status[sc];
type = "GENERIC";
break;
case NVME_SCT_COMMAND_SPECIFIC:
- s = command_specific_status[NVME_STATUS_GET_SC(status)];
+ s = command_specific_status[sc];
type = "COMMAND SPECIFIC";
break;
case NVME_SCT_MEDIA_ERROR:
- s = media_error_status[NVME_STATUS_GET_SC(status)];
+ s = media_error_status[sc];
type = "MEDIA ERROR";
break;
case NVME_SCT_PATH_RELATED:
- s = path_related_status[NVME_STATUS_GET_SC(status)];
+ s = path_related_status[sc];
type = "PATH RELATED";
break;
case NVME_SCT_VENDOR_SPECIFIC:
@@ -246,12 +248,11 @@ nvme_sc_sbuf(const struct nvme_completion *cpl, struct sbuf *sb)
}
if (type == NULL)
- sbuf_printf(sb, "RESERVED (%02x/%02x)",
- NVME_STATUS_GET_SCT(status), NVME_STATUS_GET_SC(status));
+ sbuf_printf(sb, "RESERVED (%02x/%02x)", sct, sc);
else if (s == NULL)
- sbuf_printf(sb, "%s (%02x)", type, NVME_STATUS_GET_SC(status));
+ sbuf_printf(sb, "%s (%02x/%02x)", type, sct, sc);
else
- sbuf_printf(sb, "%s", s);
+ sbuf_printf(sb, "%s (%02x/%02x)", s, sct, sc);
}
void
diff --git a/sys/dev/pci/pci_user.c b/sys/dev/pci/pci_user.c
index f68b5b7e71ff..9768030995e7 100644
--- a/sys/dev/pci/pci_user.c
+++ b/sys/dev/pci/pci_user.c
@@ -79,6 +79,9 @@ struct pci_conf32 {
u_int8_t pc_revid; /* chip revision ID */
char pd_name[PCI_MAXNAMELEN + 1]; /* device name */
u_int32_t pd_unit; /* device unit number */
+ int pd_numa_domain; /* device NUMA domain */
+ u_int32_t pc_reported_len;/* length of PCI data reported */
+ char pc_spare[64]; /* space for future fields */
};
struct pci_match_conf32 {
@@ -502,11 +505,58 @@ pci_conf_match_freebsd6_32(struct pci_match_conf_freebsd6_32 *matches, int num_m
#endif /* COMPAT_FREEBSD32 */
#endif /* !PRE7_COMPAT */
+#ifdef COMPAT_FREEBSD14
+struct pci_conf_freebsd14 {
+ struct pcisel pc_sel; /* domain+bus+slot+function */
+ u_int8_t pc_hdr; /* PCI header type */
+ u_int16_t pc_subvendor; /* card vendor ID */
+ u_int16_t pc_subdevice; /* card device ID, assigned by
+ card vendor */
+ u_int16_t pc_vendor; /* chip vendor ID */
+ u_int16_t pc_device; /* chip device ID, assigned by
+ chip vendor */
+ u_int8_t pc_class; /* chip PCI class */
+ u_int8_t pc_subclass; /* chip PCI subclass */
+ u_int8_t pc_progif; /* chip PCI programming interface */
+ u_int8_t pc_revid; /* chip revision ID */
+ char pd_name[PCI_MAXNAMELEN + 1]; /* device name */
+ u_long pd_unit; /* device unit number */
+};
+#define PCIOCGETCONF_FREEBSD14 _IOWR('p', 5, struct pci_conf_io)
+
+#ifdef COMPAT_FREEBSD32
+struct pci_conf_freebsd14_32 {
+ struct pcisel pc_sel; /* domain+bus+slot+function */
+ u_int8_t pc_hdr; /* PCI header type */
+ u_int16_t pc_subvendor; /* card vendor ID */
+ u_int16_t pc_subdevice; /* card device ID, assigned by
+ card vendor */
+ u_int16_t pc_vendor; /* chip vendor ID */
+ u_int16_t pc_device; /* chip device ID, assigned by
+ chip vendor */
+ u_int8_t pc_class; /* chip PCI class */
+ u_int8_t pc_subclass; /* chip PCI subclass */
+ u_int8_t pc_progif; /* chip PCI programming interface */
+ u_int8_t pc_revid; /* chip revision ID */
+ char pd_name[PCI_MAXNAMELEN + 1]; /* device name */
+ u_int32_t pd_unit; /* device unit number */
+};
+#define PCIOCGETCONF_FREEBSD14_32 \
+ _IOC_NEWTYPE(PCIOCGETCONF_FREEBSD14, struct pci_conf_io32)
+#endif /* COMPAT_FREEBSD32 */
+#endif /* COMPAT_FREEBSD14 */
+
union pci_conf_union {
struct pci_conf pc;
#ifdef COMPAT_FREEBSD32
struct pci_conf32 pc32;
#endif
+#ifdef COMPAT_FREEBSD14
+ struct pci_conf_freebsd14 pc14;
+#ifdef COMPAT_FREEBSD32
+ struct pci_conf_freebsd14_32 pc14_32;
+#endif
+#endif
#ifdef PRE7_COMPAT
struct pci_conf_freebsd6 pco;
#ifdef COMPAT_FREEBSD32
@@ -522,10 +572,16 @@ pci_conf_match(u_long cmd, struct pci_match_conf *matches, int num_matches,
switch (cmd) {
case PCIOCGETCONF:
+#ifdef COMPAT_FREEBSD14
+ case PCIOCGETCONF_FREEBSD14:
+#endif
return (pci_conf_match_native(
(struct pci_match_conf *)matches, num_matches, match_buf));
#ifdef COMPAT_FREEBSD32
case PCIOCGETCONF32:
+#ifdef COMPAT_FREEBSD14
+ case PCIOCGETCONF_FREEBSD14_32:
+#endif
return (pci_conf_match32((struct pci_match_conf32 *)matches,
num_matches, match_buf));
#endif
@@ -645,9 +701,15 @@ pci_match_conf_size(u_long cmd)
switch (cmd) {
case PCIOCGETCONF:
+#ifdef COMPAT_FREEBSD14
+ case PCIOCGETCONF_FREEBSD14:
+#endif
return (sizeof(struct pci_match_conf));
#ifdef COMPAT_FREEBSD32
case PCIOCGETCONF32:
+#ifdef COMPAT_FREEBSD14
+ case PCIOCGETCONF_FREEBSD14_32:
+#endif
return (sizeof(struct pci_match_conf32));
#endif
#ifdef PRE7_COMPAT
@@ -675,6 +737,14 @@ pci_conf_size(u_long cmd)
case PCIOCGETCONF32:
return (sizeof(struct pci_conf32));
#endif
+#ifdef COMPAT_FREEBSD14
+ case PCIOCGETCONF_FREEBSD14:
+ return (sizeof(struct pci_conf_freebsd14));
+#ifdef COMPAT_FREEBSD32
+ case PCIOCGETCONF_FREEBSD14_32:
+ return (sizeof(struct pci_conf_freebsd14_32));
+#endif
+#endif
#ifdef PRE7_COMPAT
case PCIOCGETCONF_FREEBSD6:
return (sizeof(struct pci_conf_freebsd6));
@@ -698,6 +768,9 @@ pci_conf_io_init(struct pci_conf_io *cio, caddr_t data, u_long cmd)
switch (cmd) {
case PCIOCGETCONF:
+#ifdef COMPAT_FREEBSD14
+ case PCIOCGETCONF_FREEBSD14:
+#endif
#ifdef PRE7_COMPAT
case PCIOCGETCONF_FREEBSD6:
#endif
@@ -706,6 +779,9 @@ pci_conf_io_init(struct pci_conf_io *cio, caddr_t data, u_long cmd)
#ifdef COMPAT_FREEBSD32
case PCIOCGETCONF32:
+#ifdef COMPAT_FREEBSD14
+ case PCIOCGETCONF_FREEBSD14_32:
+#endif
#ifdef PRE7_COMPAT
case PCIOCGETCONF_FREEBSD6_32:
#endif
@@ -739,6 +815,9 @@ pci_conf_io_update_data(const struct pci_conf_io *cio, caddr_t data,
switch (cmd) {
case PCIOCGETCONF:
+#ifdef COMPAT_FREEBSD14
+ case PCIOCGETCONF_FREEBSD14:
+#endif
#ifdef PRE7_COMPAT
case PCIOCGETCONF_FREEBSD6:
#endif
@@ -751,6 +830,9 @@ pci_conf_io_update_data(const struct pci_conf_io *cio, caddr_t data,
#ifdef COMPAT_FREEBSD32
case PCIOCGETCONF32:
+#ifdef COMPAT_FREEBSD14
+ case PCIOCGETCONF_FREEBSD14_32:
+#endif
#ifdef PRE7_COMPAT
case PCIOCGETCONF_FREEBSD6_32:
#endif
@@ -781,8 +863,17 @@ pci_conf_for_copyout(const struct pci_conf *pcp, union pci_conf_union *pcup,
pcup->pc = *pcp;
return;
+#ifdef COMPAT_FREEBSD14
+ case PCIOCGETCONF_FREEBSD14:
+ memcpy(&pcup->pc14, pcp, sizeof(pcup->pc14));
+ return;
+#endif
+
#ifdef COMPAT_FREEBSD32
case PCIOCGETCONF32:
+#ifdef COMPAT_FREEBSD14
+ case PCIOCGETCONF_FREEBSD14_32:
+#endif
pcup->pc32.pc_sel = pcp->pc_sel;
pcup->pc32.pc_hdr = pcp->pc_hdr;
pcup->pc32.pc_subvendor = pcp->pc_subvendor;
@@ -796,8 +887,13 @@ pci_conf_for_copyout(const struct pci_conf *pcp, union pci_conf_union *pcup,
strlcpy(pcup->pc32.pd_name, pcp->pd_name,
sizeof(pcup->pc32.pd_name));
pcup->pc32.pd_unit = (uint32_t)pcp->pd_unit;
+ if (cmd == PCIOCGETCONF32) {
+ pcup->pc32.pd_numa_domain = pcp->pd_numa_domain;
+ pcup->pc32.pc_reported_len =
+ (uint32_t)offsetof(struct pci_conf32, pc_spare);
+ }
return;
-#endif
+#endif /* COMPAT_FREEBSD32 */
#ifdef PRE7_COMPAT
#ifdef COMPAT_FREEBSD32
@@ -1024,7 +1120,7 @@ pci_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *t
struct pci_map *pm;
struct pci_bar_mmap *pbm;
size_t confsz, iolen;
- int error, ionum, i, num_patterns;
+ int domain, error, ionum, i, num_patterns;
union pci_conf_union pcu;
#ifdef PRE7_COMPAT
struct pci_io iodata;
@@ -1044,6 +1140,12 @@ pci_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *t
#ifdef COMPAT_FREEBSD32
case PCIOCGETCONF32:
#endif
+#ifdef COMPAT_FREEBSD14
+ case PCIOCGETCONF_FREEBSD14:
+#ifdef COMPAT_FREEBSD32
+ case PCIOCGETCONF_FREEBSD14_32:
+#endif
+#endif
#ifdef PRE7_COMPAT
case PCIOCGETCONF_FREEBSD6:
#ifdef COMPAT_FREEBSD32
@@ -1069,6 +1171,12 @@ pci_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *t
#ifdef COMPAT_FREEBSD32
case PCIOCGETCONF32:
#endif
+#ifdef COMPAT_FREEBSD14
+ case PCIOCGETCONF_FREEBSD14:
+#ifdef COMPAT_FREEBSD32
+ case PCIOCGETCONF_FREEBSD14_32:
+#endif
+#endif
#ifdef PRE7_COMPAT
case PCIOCGETCONF_FREEBSD6:
#ifdef COMPAT_FREEBSD32
@@ -1201,6 +1309,12 @@ pci_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *t
dinfo->conf.pd_unit = 0;
}
+ if (dinfo->cfg.dev != NULL &&
+ bus_get_domain(dinfo->cfg.dev, &domain) == 0)
+ dinfo->conf.pd_numa_domain = domain;
+ else
+ dinfo->conf.pd_numa_domain = 0;
+
if (pattern_buf == NULL ||
pci_conf_match(cmd, pattern_buf, num_patterns,
&dinfo->conf) == 0) {
@@ -1217,6 +1331,9 @@ pci_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *t
break;
}
+ dinfo->conf.pc_reported_len =
+ offsetof(struct pci_conf, pc_spare);
+
pci_conf_for_copyout(&dinfo->conf, &pcu, cmd);
error = copyout(&pcu,
(caddr_t)cio->matches +
diff --git a/sys/dev/rtwn/rtl8812a/r12a_tx.c b/sys/dev/rtwn/rtl8812a/r12a_tx.c
index acb238316559..0ca1ebd37757 100644
--- a/sys/dev/rtwn/rtl8812a/r12a_tx.c
+++ b/sys/dev/rtwn/rtl8812a/r12a_tx.c
@@ -101,12 +101,12 @@ r12a_tx_set_vht_bw(struct rtwn_softc *sc, void *buf, struct ieee80211_node *ni)
prim_chan = r12a_get_primary_channel(sc, ni->ni_chan);
- if (ieee80211_vht_check_tx_bw(ni, IEEE80211_STA_RX_BW_80)) {
+ if (ieee80211_vht_check_tx_bw(ni, NET80211_STA_RX_BW_80)) {
txd->txdw5 |= htole32(SM(R12A_TXDW5_DATA_BW,
R12A_TXDW5_DATA_BW80));
txd->txdw5 |= htole32(SM(R12A_TXDW5_DATA_PRIM_CHAN,
prim_chan));
- } else if (ieee80211_vht_check_tx_bw(ni, IEEE80211_STA_RX_BW_40)) {
+ } else if (ieee80211_vht_check_tx_bw(ni, NET80211_STA_RX_BW_40)) {
txd->txdw5 |= htole32(SM(R12A_TXDW5_DATA_BW,
R12A_TXDW5_DATA_BW40));
txd->txdw5 |= htole32(SM(R12A_TXDW5_DATA_PRIM_CHAN,
diff --git a/sys/dev/sound/pci/hda/hdac.c b/sys/dev/sound/pci/hda/hdac.c
index 900578b73de4..90cd74d28b3d 100644
--- a/sys/dev/sound/pci/hda/hdac.c
+++ b/sys/dev/sound/pci/hda/hdac.c
@@ -1773,17 +1773,17 @@ hdac_detach(device_t dev)
struct hdac_softc *sc = device_get_softc(dev);
int i, error;
+ callout_drain(&sc->poll_callout);
+ hdac_irq_free(sc);
+ taskqueue_drain(taskqueue_thread, &sc->unsolq_task);
+
error = bus_generic_detach(dev);
if (error != 0)
return (error);
hdac_lock(sc);
- callout_stop(&sc->poll_callout);
hdac_reset(sc, false);
hdac_unlock(sc);
- callout_drain(&sc->poll_callout);
- taskqueue_drain(taskqueue_thread, &sc->unsolq_task);
- hdac_irq_free(sc);
for (i = 0; i < sc->num_ss; i++)
hdac_dma_free(sc, &sc->streams[i].bdl);
@@ -2206,4 +2206,4 @@ static driver_t hdac_driver = {
sizeof(struct hdac_softc),
};
-DRIVER_MODULE(snd_hda, pci, hdac_driver, NULL, NULL);
+DRIVER_MODULE_ORDERED(snd_hda, pci, hdac_driver, NULL, NULL, SI_ORDER_ANY);
diff --git a/sys/dev/tpm/tpm_tis_core.c b/sys/dev/tpm/tpm_tis_core.c
index d8421f8156c9..4159de4daf3b 100644
--- a/sys/dev/tpm/tpm_tis_core.c
+++ b/sys/dev/tpm/tpm_tis_core.c
@@ -97,6 +97,7 @@ tpmtis_attach(device_t dev)
{
struct tpm_sc *sc;
int result;
+ int poll = 0;
sc = device_get_softc(dev);
sc->dev = dev;
@@ -105,6 +106,12 @@ tpmtis_attach(device_t dev)
sx_init(&sc->dev_lock, "TPM driver lock");
sc->buf = malloc(TPM_BUFSIZE, M_TPM20, M_WAITOK);
+ resource_int_value("tpm", device_get_unit(dev), "use_polling", &poll);
+ if (poll != 0) {
+ device_printf(dev, "Using poll method to get TPM operation status \n");
+ goto skip_irq;
+ }
+
sc->irq_rid = 0;
sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irq_rid,
RF_ACTIVE | RF_SHAREABLE);
diff --git a/sys/dev/ufshci/ufshci.h b/sys/dev/ufshci/ufshci.h
index b96d82ff836e..b055d2d2d769 100644
--- a/sys/dev/ufshci/ufshci.h
+++ b/sys/dev/ufshci/ufshci.h
@@ -716,6 +716,42 @@ struct ufshci_device_descriptor {
_Static_assert(sizeof(struct ufshci_device_descriptor) == 89,
"bad size for ufshci_device_descriptor");
+/* Defines the bit field of dExtendedUfsFeaturesSupport. */
+enum ufshci_desc_wb_ext_ufs_feature {
+ UFSHCI_DESC_EXT_UFS_FEATURE_FFU = (1 << 0),
+ UFSHCI_DESC_EXT_UFS_FEATURE_PSA = (1 << 1),
+ UFSHCI_DESC_EXT_UFS_FEATURE_DEV_LIFE_SPAN = (1 << 2),
+ UFSHCI_DESC_EXT_UFS_FEATURE_REFRESH_OP = (1 << 3),
+ UFSHCI_DESC_EXT_UFS_FEATURE_TOO_HIGH_TEMP = (1 << 4),
+ UFSHCI_DESC_EXT_UFS_FEATURE_TOO_LOW_TEMP = (1 << 5),
+ UFSHCI_DESC_EXT_UFS_FEATURE_EXT_TEMP = (1 << 6),
+ UFSHCI_DESC_EXT_UFS_FEATURE_HPB_SUPPORT = (1 << 7),
+ UFSHCI_DESC_EXT_UFS_FEATURE_WRITE_BOOSTER = (1 << 8),
+ UFSHCI_DESC_EXT_UFS_FEATURE_PERF_THROTTLING = (1 << 9),
+ UFSHCI_DESC_EXT_UFS_FEATURE_ADVANCED_RPMB = (1 << 10),
+ UFSHCI_DESC_EXT_UFS_FEATURE_ZONED_UFS_EXTENSION = (1 << 11),
+ UFSHCI_DESC_EXT_UFS_FEATURE_DEV_LEVEL_EXCEPTION = (1 << 12),
+ UFSHCI_DESC_EXT_UFS_FEATURE_HID = (1 << 13),
+ UFSHCI_DESC_EXT_UFS_FEATURE_BARRIER = (1 << 14),
+ UFSHCI_DESC_EXT_UFS_FEATURE_CLEAR_ERROR_HISTORY = (1 << 15),
+ UFSHCI_DESC_EXT_UFS_FEATURE_EXT_IID = (1 << 16),
+ UFSHCI_DESC_EXT_UFS_FEATURE_FBO = (1 << 17),
+ UFSHCI_DESC_EXT_UFS_FEATURE_FAST_RECOVERY_MODE = (1 << 18),
+ UFSHCI_DESC_EXT_UFS_FEATURE_RPMB_VENDOR_CMD = (1 << 19),
+};
+
+/* Defines the bit field of bWriteBoosterBufferType. */
+enum ufshci_desc_wb_buffer_type {
+ UFSHCI_DESC_WB_BUF_TYPE_LU_DEDICATED = 0x00,
+ UFSHCI_DESC_WB_BUF_TYPE_SINGLE_SHARED = 0x01,
+};
+
+/* Defines the bit field of bWriteBoosterBufferPreserveUserSpaceEn. */
+enum ufshci_desc_user_space_config {
+ UFSHCI_DESC_WB_BUF_USER_SPACE_REDUCTION = 0x00,
+ UFSHCI_DESC_WB_BUF_PRESERVE_USER_SPACE = 0x01,
+};
+
/*
* UFS Spec 4.1, section 14.1.5.3 "Configuration Descriptor"
* ConfigurationDescriptor use big-endian byte ordering.
@@ -1014,4 +1050,37 @@ enum ufshci_attributes {
UFSHCI_ATTR_B_REFRESH_METHOD = 0x2f,
};
+/* bAvailableWriteBoosterBufferSize codes (UFS WriteBooster abailable buffer
+ * left %) */
+enum ufshci_wb_available_buffer_Size {
+ UFSHCI_ATTR_WB_AVAILABLE_0 = 0x00, /* 0% buffer remains */
+ UFSHCI_ATTR_WB_AVAILABLE_10 = 0x01, /* 10% buffer remains */
+ UFSHCI_ATTR_WB_AVAILABLE_20 = 0x02, /* 20% buffer remains */
+ UFSHCI_ATTR_WB_AVAILABLE_30 = 0x03, /* 30% buffer remains */
+ UFSHCI_ATTR_WB_AVAILABLE_40 = 0x04, /* 40% buffer remains */
+ UFSHCI_ATTR_WB_AVAILABLE_50 = 0x05, /* 50% buffer remains */
+ UFSHCI_ATTR_WB_AVAILABLE_60 = 0x06, /* 60% buffer remains */
+ UFSHCI_ATTR_WB_AVAILABLE_70 = 0x07, /* 70% buffer remains */
+ UFSHCI_ATTR_WB_AVAILABLE_80 = 0x08, /* 80% buffer remains */
+ UFSHCI_ATTR_WB_AVAILABLE_90 = 0x09, /* 90% buffer remains */
+ UFSHCI_ATTR_WB_AVAILABLE_100 = 0x0A, /* 100% buffer remains */
+};
+
+/* bWriteBoosterBufferLifeTimeEst codes (UFS WriteBooster buffer life %) */
+enum ufshci_wb_lifetime {
+ UFSHCI_ATTR_WB_LIFE_DISABLED = 0x00, /* Info not available */
+ UFSHCI_ATTR_WB_LIFE_0_10 = 0x01, /* 0%–10% used */
+ UFSHCI_ATTR_WB_LIFE_10_20 = 0x02, /* 10%–20% used */
+ UFSHCI_ATTR_WB_LIFE_20_30 = 0x03, /* 20%–30% used */
+ UFSHCI_ATTR_WB_LIFE_30_40 = 0x04, /* 30%–40% used */
+ UFSHCI_ATTR_WB_LIFE_40_50 = 0x05, /* 40%–50% used */
+ UFSHCI_ATTR_WB_LIFE_50_60 = 0x06, /* 50%–60% used */
+ UFSHCI_ATTR_WB_LIFE_60_70 = 0x07, /* 60%–70% used */
+ UFSHCI_ATTR_WB_LIFE_70_80 = 0x08, /* 70%–80% used */
+ UFSHCI_ATTR_WB_LIFE_80_90 = 0x09, /* 80%–90% used */
+ UFSHCI_ATTR_WB_LIFE_90_100 = 0x0A, /* 90%–100% used */
+ UFSHCI_ATTR_WB_LIFE_EXCEEDED =
+ 0x0B, /* Exceeded estimated life (treat as WB disabled) */
+};
+
#endif /* __UFSHCI_H__ */
diff --git a/sys/dev/ufshci/ufshci_ctrlr.c b/sys/dev/ufshci/ufshci_ctrlr.c
index 37bd32665b2b..36be94b8b8b7 100644
--- a/sys/dev/ufshci/ufshci_ctrlr.c
+++ b/sys/dev/ufshci/ufshci_ctrlr.c
@@ -61,7 +61,7 @@ ufshci_ctrlr_enable_host_ctrlr(struct ufshci_controller *ctrlr)
int
ufshci_ctrlr_construct(struct ufshci_controller *ctrlr, device_t dev)
{
- uint32_t ver, cap, hcs, ie;
+ uint32_t ver, cap, hcs, ie, ahit;
uint32_t timeout_period, retry_count;
int error;
@@ -127,6 +127,13 @@ ufshci_ctrlr_construct(struct ufshci_controller *ctrlr, device_t dev)
if (error)
return (error);
+ /* Read the UECPA register to clear */
+ ufshci_mmio_read_4(ctrlr, uecpa);
+
+ /* Diable Auto-hibernate */
+ ahit = 0;
+ ufshci_mmio_write_4(ctrlr, ahit, ahit);
+
/*
* The device_present(UFSHCI_HCS_REG_DP) bit becomes true if the host
* controller has successfully received a Link Startup UIC command
@@ -139,6 +146,16 @@ ufshci_ctrlr_construct(struct ufshci_controller *ctrlr, device_t dev)
return (ENXIO);
}
+ /* Allocate and initialize UTP Task Management Request List. */
+ error = ufshci_utmr_req_queue_construct(ctrlr);
+ if (error)
+ return (error);
+
+ /* Allocate and initialize UTP Transfer Request List or SQ/CQ. */
+ error = ufshci_utr_req_queue_construct(ctrlr);
+ if (error)
+ return (error);
+
/* Enable additional interrupts by programming the IE register. */
ie = ufshci_mmio_read_4(ctrlr, ie);
ie |= UFSHCIM(UFSHCI_IE_REG_UTRCE); /* UTR Completion */
@@ -153,19 +170,12 @@ ufshci_ctrlr_construct(struct ufshci_controller *ctrlr, device_t dev)
/* TODO: Initialize interrupt Aggregation Control Register (UTRIACR) */
- /* Allocate and initialize UTP Task Management Request List. */
- error = ufshci_utmr_req_queue_construct(ctrlr);
- if (error)
- return (error);
-
- /* Allocate and initialize UTP Transfer Request List or SQ/CQ. */
- error = ufshci_utr_req_queue_construct(ctrlr);
- if (error)
- return (error);
-
/* TODO: Separate IO and Admin slot */
- /* max_hw_pend_io is the number of slots in the transfer_req_queue */
- ctrlr->max_hw_pend_io = ctrlr->transfer_req_queue.num_entries;
+ /*
+ * max_hw_pend_io is the number of slots in the transfer_req_queue.
+ * Reduce num_entries by one to reserve an admin slot.
+ */
+ ctrlr->max_hw_pend_io = ctrlr->transfer_req_queue.num_entries - 1;
return (0);
}
@@ -342,18 +352,19 @@ ufshci_ctrlr_start(struct ufshci_controller *ctrlr)
return;
}
- /* Read Controller Descriptor (Device, Geometry)*/
+ /* Read Controller Descriptor (Device, Geometry) */
if (ufshci_dev_get_descriptor(ctrlr) != 0) {
ufshci_ctrlr_fail(ctrlr, false);
return;
}
- /* TODO: Configure Write Protect */
+ if (ufshci_dev_config_write_booster(ctrlr)) {
+ ufshci_ctrlr_fail(ctrlr, false);
+ return;
+ }
/* TODO: Configure Background Operations */
- /* TODO: Configure Write Booster */
-
if (ufshci_sim_attach(ctrlr) != 0) {
ufshci_ctrlr_fail(ctrlr, false);
return;
diff --git a/sys/dev/ufshci/ufshci_dev.c b/sys/dev/ufshci/ufshci_dev.c
index a0e32914e2aa..dd196b1d638b 100644
--- a/sys/dev/ufshci/ufshci_dev.c
+++ b/sys/dev/ufshci/ufshci_dev.c
@@ -60,6 +60,14 @@ ufshci_dev_read_geometry_descriptor(struct ufshci_controller *ctrlr,
}
static int
+ufshci_dev_read_unit_descriptor(struct ufshci_controller *ctrlr, uint8_t lun,
+ struct ufshci_unit_descriptor *desc)
+{
+ return (ufshci_dev_read_descriptor(ctrlr, UFSHCI_DESC_TYPE_UNIT, lun, 0,
+ desc, sizeof(struct ufshci_unit_descriptor)));
+}
+
+static int
ufshci_dev_read_flag(struct ufshci_controller *ctrlr,
enum ufshci_flags flag_type, uint8_t *flag)
{
@@ -114,6 +122,61 @@ ufshci_dev_set_flag(struct ufshci_controller *ctrlr,
}
static int
+ufshci_dev_clear_flag(struct ufshci_controller *ctrlr,
+ enum ufshci_flags flag_type)
+{
+ struct ufshci_completion_poll_status status;
+ struct ufshci_query_param param;
+
+ param.function = UFSHCI_QUERY_FUNC_STANDARD_WRITE_REQUEST;
+ param.opcode = UFSHCI_QUERY_OPCODE_CLEAR_FLAG;
+ param.type = flag_type;
+ param.index = 0;
+ param.selector = 0;
+ param.value = 0;
+
+ status.done = 0;
+ ufshci_ctrlr_cmd_send_query_request(ctrlr, ufshci_completion_poll_cb,
+ &status, param);
+ ufshci_completion_poll(&status);
+ if (status.error) {
+ ufshci_printf(ctrlr, "ufshci_dev_clear_flag failed!\n");
+ return (ENXIO);
+ }
+
+ return (0);
+}
+
+static int
+ufshci_dev_read_attribute(struct ufshci_controller *ctrlr,
+ enum ufshci_attributes attr_type, uint8_t index, uint8_t selector,
+ uint64_t *value)
+{
+ struct ufshci_completion_poll_status status;
+ struct ufshci_query_param param;
+
+ param.function = UFSHCI_QUERY_FUNC_STANDARD_READ_REQUEST;
+ param.opcode = UFSHCI_QUERY_OPCODE_READ_ATTRIBUTE;
+ param.type = attr_type;
+ param.index = index;
+ param.selector = selector;
+ param.value = 0;
+
+ status.done = 0;
+ ufshci_ctrlr_cmd_send_query_request(ctrlr, ufshci_completion_poll_cb,
+ &status, param);
+ ufshci_completion_poll(&status);
+ if (status.error) {
+ ufshci_printf(ctrlr, "ufshci_dev_read_attribute failed!\n");
+ return (ENXIO);
+ }
+
+ *value = status.cpl.response_upiu.query_response_upiu.value_64;
+
+ return (0);
+}
+
+static int
ufshci_dev_write_attribute(struct ufshci_controller *ctrlr,
enum ufshci_attributes attr_type, uint8_t index, uint8_t selector,
uint64_t value)
@@ -270,7 +333,7 @@ ufshci_dev_init_uic_power_mode(struct ufshci_controller *ctrlr)
*/
const uint32_t fast_mode = 1;
const uint32_t rx_bit_shift = 4;
- const uint32_t power_mode = (fast_mode << rx_bit_shift) | fast_mode;
+ uint32_t power_mode, peer_granularity;
/* Update lanes with available TX/RX lanes */
if (ufshci_uic_send_dme_get(ctrlr, PA_AvailTxDataLanes,
@@ -295,6 +358,20 @@ ufshci_dev_init_uic_power_mode(struct ufshci_controller *ctrlr)
ctrlr->rx_lanes))
return (ENXIO);
+ if (ctrlr->quirks & UFSHCI_QUIRK_CHANGE_LANE_AND_GEAR_SEPARATELY) {
+ /* Before changing gears, first change the number of lanes. */
+ if (ufshci_uic_send_dme_get(ctrlr, PA_PWRMode, &power_mode))
+ return (ENXIO);
+ if (ufshci_uic_send_dme_set(ctrlr, PA_PWRMode, power_mode))
+ return (ENXIO);
+
+ /* Wait for power mode changed. */
+ if (ufshci_uic_power_mode_ready(ctrlr)) {
+ ufshci_reg_dump(ctrlr);
+ return (ENXIO);
+ }
+ }
+
/* Set HS-GEAR to max gear */
ctrlr->hs_gear = ctrlr->max_rx_hs_gear;
if (ufshci_uic_send_dme_set(ctrlr, PA_TxGear, ctrlr->hs_gear))
@@ -346,6 +423,7 @@ ufshci_dev_init_uic_power_mode(struct ufshci_controller *ctrlr)
return (ENXIO);
/* Set TX/RX PWRMode */
+ power_mode = (fast_mode << rx_bit_shift) | fast_mode;
if (ufshci_uic_send_dme_set(ctrlr, PA_PWRMode, power_mode))
return (ENXIO);
@@ -366,7 +444,8 @@ ufshci_dev_init_uic_power_mode(struct ufshci_controller *ctrlr)
pause_sbt("ufshci", ustosbt(1250), 0, C_PREL(1));
/* Test with dme_peer_get to make sure there are no errors. */
- if (ufshci_uic_send_dme_peer_get(ctrlr, PA_Granularity, NULL))
+ if (ufshci_uic_send_dme_peer_get(ctrlr, PA_Granularity,
+ &peer_granularity))
return (ENXIO);
}
@@ -398,7 +477,7 @@ ufshci_dev_get_descriptor(struct ufshci_controller *ctrlr)
return (error);
ver = be16toh(device->dev_desc.wSpecVersion);
- ufshci_printf(ctrlr, "UFS device spec version %u.%u%u\n",
+ ufshci_printf(ctrlr, "UFS device spec version %u.%u.%u\n",
UFSHCIV(UFSHCI_VER_REG_MJR, ver), UFSHCIV(UFSHCI_VER_REG_MNR, ver),
UFSHCIV(UFSHCI_VER_REG_VS, ver));
ufshci_printf(ctrlr, "%u enabled LUNs found\n",
@@ -426,3 +505,273 @@ ufshci_dev_get_descriptor(struct ufshci_controller *ctrlr)
return (0);
}
+
+static int
+ufshci_dev_enable_write_booster(struct ufshci_controller *ctrlr)
+{
+ struct ufshci_device *dev = &ctrlr->ufs_dev;
+ int error;
+
+ /* Enable WriteBooster */
+ error = ufshci_dev_set_flag(ctrlr, UFSHCI_FLAG_F_WRITE_BOOSTER_EN);
+ if (error) {
+ ufshci_printf(ctrlr, "Failed to enable WriteBooster\n");
+ return (error);
+ }
+ dev->is_wb_enabled = true;
+
+ /* Enable WriteBooster buffer flush during hibernate */
+ error = ufshci_dev_set_flag(ctrlr,
+ UFSHCI_FLAG_F_WB_BUFFER_FLUSH_DURING_HIBERNATE);
+ if (error) {
+ ufshci_printf(ctrlr,
+ "Failed to enable WriteBooster buffer flush during hibernate\n");
+ return (error);
+ }
+
+ /* Enable WriteBooster buffer flush */
+ error = ufshci_dev_set_flag(ctrlr, UFSHCI_FLAG_F_WB_BUFFER_FLUSH_EN);
+ if (error) {
+ ufshci_printf(ctrlr,
+ "Failed to enable WriteBooster buffer flush\n");
+ return (error);
+ }
+ dev->is_wb_flush_enabled = true;
+
+ return (0);
+}
+
+static int
+ufshci_dev_disable_write_booster(struct ufshci_controller *ctrlr)
+{
+ struct ufshci_device *dev = &ctrlr->ufs_dev;
+ int error;
+
+ /* Disable WriteBooster buffer flush */
+ error = ufshci_dev_clear_flag(ctrlr, UFSHCI_FLAG_F_WB_BUFFER_FLUSH_EN);
+ if (error) {
+ ufshci_printf(ctrlr,
+ "Failed to disable WriteBooster buffer flush\n");
+ return (error);
+ }
+ dev->is_wb_flush_enabled = false;
+
+ /* Disable WriteBooster buffer flush during hibernate */
+ error = ufshci_dev_clear_flag(ctrlr,
+ UFSHCI_FLAG_F_WB_BUFFER_FLUSH_DURING_HIBERNATE);
+ if (error) {
+ ufshci_printf(ctrlr,
+ "Failed to disable WriteBooster buffer flush during hibernate\n");
+ return (error);
+ }
+
+ /* Disable WriteBooster */
+ error = ufshci_dev_clear_flag(ctrlr, UFSHCI_FLAG_F_WRITE_BOOSTER_EN);
+ if (error) {
+ ufshci_printf(ctrlr, "Failed to disable WriteBooster\n");
+ return (error);
+ }
+ dev->is_wb_enabled = false;
+
+ return (0);
+}
+
+static int
+ufshci_dev_is_write_booster_buffer_life_time_left(
+ struct ufshci_controller *ctrlr, bool *is_life_time_left)
+{
+ struct ufshci_device *dev = &ctrlr->ufs_dev;
+ uint8_t buffer_lun;
+ uint64_t life_time;
+ uint32_t error;
+
+ if (dev->wb_buffer_type == UFSHCI_DESC_WB_BUF_TYPE_LU_DEDICATED)
+ buffer_lun = dev->wb_dedicated_lu;
+ else
+ buffer_lun = 0;
+
+ error = ufshci_dev_read_attribute(ctrlr,
+ UFSHCI_ATTR_B_WB_BUFFER_LIFE_TIME_EST, buffer_lun, 0, &life_time);
+ if (error)
+ return (error);
+
+ *is_life_time_left = (life_time != UFSHCI_ATTR_WB_LIFE_EXCEEDED);
+
+ return (0);
+}
+
+/*
+ * This function is not yet in use. It will be used when suspend/resume is
+ * implemented.
+ */
+static __unused int
+ufshci_dev_need_write_booster_buffer_flush(struct ufshci_controller *ctrlr,
+ bool *need_flush)
+{
+ struct ufshci_device *dev = &ctrlr->ufs_dev;
+ bool is_life_time_left = false;
+ uint64_t available_buffer_size, current_buffer_size;
+ uint8_t buffer_lun;
+ uint32_t error;
+
+ *need_flush = false;
+
+ if (!dev->is_wb_enabled)
+ return (0);
+
+ error = ufshci_dev_is_write_booster_buffer_life_time_left(ctrlr,
+ &is_life_time_left);
+ if (error)
+ return (error);
+
+ if (!is_life_time_left)
+ return (ufshci_dev_disable_write_booster(ctrlr));
+
+ if (dev->wb_buffer_type == UFSHCI_DESC_WB_BUF_TYPE_LU_DEDICATED)
+ buffer_lun = dev->wb_dedicated_lu;
+ else
+ buffer_lun = 0;
+
+ error = ufshci_dev_read_attribute(ctrlr,
+ UFSHCI_ATTR_B_AVAILABLE_WB_BUFFER_SIZE, buffer_lun, 0,
+ &available_buffer_size);
+ if (error)
+ return (error);
+
+ switch (dev->wb_user_space_config_option) {
+ case UFSHCI_DESC_WB_BUF_USER_SPACE_REDUCTION:
+ *need_flush = (available_buffer_size <=
+ UFSHCI_ATTR_WB_AVAILABLE_10);
+ break;
+ case UFSHCI_DESC_WB_BUF_PRESERVE_USER_SPACE:
+ /*
+ * In PRESERVE USER SPACE mode, flush should be performed when
+ * the current buffer is greater than 0 and the available buffer
+ * below write_booster_flush_threshold is left.
+ */
+ error = ufshci_dev_read_attribute(ctrlr,
+ UFSHCI_ATTR_D_CURRENT_WB_BUFFER_SIZE, buffer_lun, 0,
+ &current_buffer_size);
+ if (error)
+ return (error);
+
+ if (current_buffer_size == 0)
+ return (0);
+
+ *need_flush = (available_buffer_size <
+ dev->write_booster_flush_threshold);
+ break;
+ default:
+ ufshci_printf(ctrlr,
+ "Invalid bWriteBoosterBufferPreserveUserSpaceEn value");
+ return (EINVAL);
+ }
+
+ /*
+ * TODO: Need to handle WRITEBOOSTER_FLUSH_NEEDED exception case from
+ * wExceptionEventStatus attribute.
+ */
+
+ return (0);
+}
+
+int
+ufshci_dev_config_write_booster(struct ufshci_controller *ctrlr)
+{
+ struct ufshci_device *dev = &ctrlr->ufs_dev;
+ uint32_t extended_ufs_feature_support;
+ uint32_t alloc_units;
+ struct ufshci_unit_descriptor unit_desc;
+ uint8_t lun;
+ bool is_life_time_left;
+ uint32_t mega_byte = 1024 * 1024;
+ uint32_t error = 0;
+
+ extended_ufs_feature_support = be32toh(
+ dev->dev_desc.dExtendedUfsFeaturesSupport);
+ if (!(extended_ufs_feature_support &
+ UFSHCI_DESC_EXT_UFS_FEATURE_WRITE_BOOSTER)) {
+ /* This device does not support Write Booster */
+ return (0);
+ }
+
+ if (ufshci_dev_enable_write_booster(ctrlr))
+ return (0);
+
+ /* Get WriteBooster buffer parameters */
+ dev->wb_buffer_type = dev->dev_desc.bWriteBoosterBufferType;
+ dev->wb_user_space_config_option =
+ dev->dev_desc.bWriteBoosterBufferPreserveUserSpaceEn;
+
+ /*
+ * Find the size of the write buffer.
+ * With LU-dedicated (00h), the WriteBooster buffer is assigned
+ * exclusively to one chosen LU (not one-per-LU), whereas Shared (01h)
+ * uses a single device-wide buffer shared by multiple LUs.
+ */
+ if (dev->wb_buffer_type == UFSHCI_DESC_WB_BUF_TYPE_SINGLE_SHARED) {
+ alloc_units = be32toh(
+ dev->dev_desc.dNumSharedWriteBoosterBufferAllocUnits);
+ ufshci_printf(ctrlr,
+ "WriteBooster buffer type = Shared, alloc_units=%d\n",
+ alloc_units);
+ } else if (dev->wb_buffer_type ==
+ UFSHCI_DESC_WB_BUF_TYPE_LU_DEDICATED) {
+ ufshci_printf(ctrlr, "WriteBooster buffer type = Dedicated\n");
+ for (lun = 0; lun < ctrlr->max_lun_count; lun++) {
+ /* Find a dedicated buffer using a unit descriptor */
+ if (ufshci_dev_read_unit_descriptor(ctrlr, lun,
+ &unit_desc))
+ continue;
+
+ alloc_units = be32toh(
+ unit_desc.dLUNumWriteBoosterBufferAllocUnits);
+ if (alloc_units) {
+ dev->wb_dedicated_lu = lun;
+ break;
+ }
+ }
+ } else {
+ ufshci_printf(ctrlr,
+ "Not supported WriteBooster buffer type: 0x%x\n",
+ dev->wb_buffer_type);
+ goto out;
+ }
+
+ if (alloc_units == 0) {
+ ufshci_printf(ctrlr, "The WriteBooster buffer size is zero\n");
+ goto out;
+ }
+
+ dev->wb_buffer_size_mb = alloc_units *
+ dev->geo_desc.bAllocationUnitSize *
+ (be32toh(dev->geo_desc.dSegmentSize)) /
+ (mega_byte / UFSHCI_SECTOR_SIZE);
+
+ /* Set to flush when 40% of the available buffer size remains */
+ dev->write_booster_flush_threshold = UFSHCI_ATTR_WB_AVAILABLE_40;
+
+ /*
+ * Check if WriteBooster Buffer lifetime is left.
+ * WriteBooster Buffer lifetime — percent of life used based on P/E
+ * cycles. If "preserve user space" is enabled, writes to normal user
+ * space also consume WB life since the area is shared.
+ */
+ error = ufshci_dev_is_write_booster_buffer_life_time_left(ctrlr,
+ &is_life_time_left);
+ if (error)
+ goto out;
+
+ if (!is_life_time_left) {
+ ufshci_printf(ctrlr,
+ "There is no WriteBooster buffer life time left.\n");
+ goto out;
+ }
+
+ ufshci_printf(ctrlr, "WriteBooster Enabled\n");
+ return (0);
+out:
+ ufshci_dev_disable_write_booster(ctrlr);
+ return (error);
+}
+
diff --git a/sys/dev/ufshci/ufshci_pci.c b/sys/dev/ufshci/ufshci_pci.c
index 65a69ee0b518..d64b7526f713 100644
--- a/sys/dev/ufshci/ufshci_pci.c
+++ b/sys/dev/ufshci/ufshci_pci.c
@@ -53,7 +53,8 @@ static struct _pcsid {
{ 0x98fa8086, "Intel Lakefield UFS Host Controller",
UFSHCI_REF_CLK_19_2MHz,
UFSHCI_QUIRK_LONG_PEER_PA_TACTIVATE |
- UFSHCI_QUIRK_WAIT_AFTER_POWER_MODE_CHANGE },
+ UFSHCI_QUIRK_WAIT_AFTER_POWER_MODE_CHANGE |
+ UFSHCI_QUIRK_CHANGE_LANE_AND_GEAR_SEPARATELY },
{ 0x54ff8086, "Intel UFS Host Controller", UFSHCI_REF_CLK_19_2MHz },
{ 0x00000000, NULL } };
diff --git a/sys/dev/ufshci/ufshci_private.h b/sys/dev/ufshci/ufshci_private.h
index 1a2742ae2e80..2e033f84c373 100644
--- a/sys/dev/ufshci/ufshci_private.h
+++ b/sys/dev/ufshci/ufshci_private.h
@@ -46,6 +46,8 @@ MALLOC_DECLARE(M_UFSHCI);
#define UFSHCI_UTR_ENTRIES (32)
#define UFSHCI_UTRM_ENTRIES (8)
+#define UFSHCI_SECTOR_SIZE (512)
+
struct ufshci_controller;
struct ufshci_completion_poll_status {
@@ -214,6 +216,15 @@ struct ufshci_device {
struct ufshci_geometry_descriptor geo_desc;
uint32_t unipro_version;
+
+ /* WriteBooster */
+ bool is_wb_enabled;
+ bool is_wb_flush_enabled;
+ uint32_t wb_buffer_type;
+ uint32_t wb_buffer_size_mb;
+ uint32_t wb_user_space_config_option;
+ uint8_t wb_dedicated_lu;
+ uint32_t write_booster_flush_threshold;
};
/*
@@ -229,7 +240,8 @@ struct ufshci_controller {
2 /* Need an additional 200 ms of PA_TActivate */
#define UFSHCI_QUIRK_WAIT_AFTER_POWER_MODE_CHANGE \
4 /* Need to wait 1250us after power mode change */
-
+#define UFSHCI_QUIRK_CHANGE_LANE_AND_GEAR_SEPARATELY \
+ 8 /* Need to change the number of lanes before changing HS-GEAR. */
uint32_t ref_clk;
struct cam_sim *ufshci_sim;
@@ -356,6 +368,7 @@ int ufshci_dev_init_unipro(struct ufshci_controller *ctrlr);
int ufshci_dev_init_uic_power_mode(struct ufshci_controller *ctrlr);
int ufshci_dev_init_ufs_power_mode(struct ufshci_controller *ctrlr);
int ufshci_dev_get_descriptor(struct ufshci_controller *ctrlr);
+int ufshci_dev_config_write_booster(struct ufshci_controller *ctrlr);
/* Controller Command */
void ufshci_ctrlr_cmd_send_task_mgmt_request(struct ufshci_controller *ctrlr,
diff --git a/sys/dev/ufshci/ufshci_reg.h b/sys/dev/ufshci/ufshci_reg.h
index 6c9b3e2c8c04..6d5768505102 100644
--- a/sys/dev/ufshci/ufshci_reg.h
+++ b/sys/dev/ufshci/ufshci_reg.h
@@ -274,7 +274,7 @@ struct ufshci_registers {
#define UFSHCI_HCS_REG_UTMRLRDY_MASK (0x1)
#define UFSHCI_HCS_REG_UCRDY_SHIFT (3)
#define UFSHCI_HCS_REG_UCRDY_MASK (0x1)
-#define UFSHCI_HCS_REG_UPMCRS_SHIFT (7)
+#define UFSHCI_HCS_REG_UPMCRS_SHIFT (8)
#define UFSHCI_HCS_REG_UPMCRS_MASK (0x7)
#define UFSHCI_HCS_REG_UTPEC_SHIFT (12)
#define UFSHCI_HCS_REG_UTPEC_MASK (0xF)
diff --git a/sys/dev/ufshci/ufshci_sysctl.c b/sys/dev/ufshci/ufshci_sysctl.c
index 5e5069f12e5f..56bc06b13f3c 100644
--- a/sys/dev/ufshci/ufshci_sysctl.c
+++ b/sys/dev/ufshci/ufshci_sysctl.c
@@ -152,6 +152,7 @@ ufshci_sysctl_initialize_ctrlr(struct ufshci_controller *ctrlr)
struct sysctl_ctx_list *ctrlr_ctx;
struct sysctl_oid *ctrlr_tree, *que_tree, *ioq_tree;
struct sysctl_oid_list *ctrlr_list, *ioq_list;
+ struct ufshci_device *dev = &ctrlr->ufs_dev;
#define QUEUE_NAME_LENGTH 16
char queue_name[QUEUE_NAME_LENGTH];
int i;
@@ -177,6 +178,25 @@ ufshci_sysctl_initialize_ctrlr(struct ufshci_controller *ctrlr)
SYSCTL_ADD_UINT(ctrlr_ctx, ctrlr_list, OID_AUTO, "cap", CTLFLAG_RD,
&ctrlr->cap, 0, "Number of I/O queue pairs");
+ SYSCTL_ADD_BOOL(ctrlr_ctx, ctrlr_list, OID_AUTO, "wb_enabled",
+ CTLFLAG_RD, &dev->is_wb_enabled, 0, "WriteBooster enable/disable");
+
+ SYSCTL_ADD_BOOL(ctrlr_ctx, ctrlr_list, OID_AUTO, "wb_flush_enabled",
+ CTLFLAG_RD, &dev->is_wb_flush_enabled, 0,
+ "WriteBooster flush enable/disable");
+
+ SYSCTL_ADD_UINT(ctrlr_ctx, ctrlr_list, OID_AUTO, "wb_buffer_type",
+ CTLFLAG_RD, &dev->wb_buffer_type, 0, "WriteBooster type");
+
+ SYSCTL_ADD_UINT(ctrlr_ctx, ctrlr_list, OID_AUTO, "wb_buffer_size_mb",
+ CTLFLAG_RD, &dev->wb_buffer_size_mb, 0,
+ "WriteBooster buffer size in MB");
+
+ SYSCTL_ADD_UINT(ctrlr_ctx, ctrlr_list, OID_AUTO,
+ "wb_user_space_config_option", CTLFLAG_RD,
+ &dev->wb_user_space_config_option, 0,
+ "WriteBooster preserve user space mode");
+
SYSCTL_ADD_PROC(ctrlr_ctx, ctrlr_list, OID_AUTO, "timeout_period",
CTLTYPE_UINT | CTLFLAG_RW | CTLFLAG_MPSAFE, &ctrlr->timeout_period,
0, ufshci_sysctl_timeout_period, "IU",
diff --git a/sys/dev/ufshci/ufshci_uic_cmd.c b/sys/dev/ufshci/ufshci_uic_cmd.c
index 2c5f635dc11e..b9c867ff7065 100644
--- a/sys/dev/ufshci/ufshci_uic_cmd.c
+++ b/sys/dev/ufshci/ufshci_uic_cmd.c
@@ -14,7 +14,7 @@
int
ufshci_uic_power_mode_ready(struct ufshci_controller *ctrlr)
{
- uint32_t is;
+ uint32_t is, hcs;
int timeout;
/* Wait for the IS flag to change */
@@ -40,6 +40,15 @@ ufshci_uic_power_mode_ready(struct ufshci_controller *ctrlr)
DELAY(10);
}
+ /* Check HCS power mode change request status */
+ hcs = ufshci_mmio_read_4(ctrlr, hcs);
+ if (UFSHCIV(UFSHCI_HCS_REG_UPMCRS, hcs) != 0x01) {
+ ufshci_printf(ctrlr,
+ "Power mode change request status error: 0x%x\n",
+ UFSHCIV(UFSHCI_HCS_REG_UPMCRS, hcs));
+ return (ENXIO);
+ }
+
return (0);
}
@@ -112,6 +121,7 @@ ufshci_uic_send_cmd(struct ufshci_controller *ctrlr,
struct ufshci_uic_cmd *uic_cmd, uint32_t *return_value)
{
int error;
+ uint32_t config_result_code;
mtx_lock(&ctrlr->uic_cmd_lock);
@@ -134,6 +144,13 @@ ufshci_uic_send_cmd(struct ufshci_controller *ctrlr,
if (error)
return (ENXIO);
+ config_result_code = ufshci_mmio_read_4(ctrlr, ucmdarg2);
+ if (config_result_code) {
+ ufshci_printf(ctrlr,
+ "Failed to send UIC command. (config result code = 0x%x)\n",
+ config_result_code);
+ }
+
if (return_value != NULL)
*return_value = ufshci_mmio_read_4(ctrlr, ucmdarg3);
diff --git a/sys/dev/usb/controller/xhci.c b/sys/dev/usb/controller/xhci.c
index 5be592512196..788b2b718062 100644
--- a/sys/dev/usb/controller/xhci.c
+++ b/sys/dev/usb/controller/xhci.c
@@ -156,6 +156,7 @@ struct xhci_std_temp {
static void xhci_do_poll(struct usb_bus *);
static void xhci_device_done(struct usb_xfer *, usb_error_t);
+static void xhci_get_xecp(struct xhci_softc *);
static void xhci_root_intr(struct xhci_softc *);
static void xhci_free_device_ext(struct usb_device *);
static struct xhci_endpoint_ext *xhci_get_endpoint_ext(struct usb_device *,
@@ -566,6 +567,8 @@ xhci_init(struct xhci_softc *sc, device_t self, uint8_t dma32)
device_printf(self, "%d bytes context size, %d-bit DMA\n",
sc->sc_ctx_is_64_byte ? 64 : 32, (int)sc->sc_bus.dma_bits);
+ xhci_get_xecp(sc);
+
/* enable 64Kbyte control endpoint quirk */
sc->sc_bus.control_ep_quirk = (xhcictlquirk ? 1 : 0);
@@ -654,6 +657,88 @@ xhci_uninit(struct xhci_softc *sc)
}
static void
+xhci_get_xecp(struct xhci_softc *sc)
+{
+
+ uint32_t hccp1;
+ uint32_t eec;
+ uint32_t eecp;
+ bool first = true;
+
+ hccp1 = XREAD4(sc, capa, XHCI_HCSPARAMS0);
+
+ if (XHCI_HCS0_XECP(hccp1) == 0) {
+ device_printf(sc->sc_bus.parent,
+ "xECP: no capabilities found\n");
+ return;
+ }
+
+ /*
+ * Parse the xECP Capabilities table and print known caps.
+ * Implemented, vendor and reserved xECP Capabilities values are
+ * documented in Table 7.2 of eXtensible Host Controller Interface for
+ * Universal Serial Bus (xHCI) Rev 1.2b 2023.
+ */
+ device_printf(sc->sc_bus.parent, "xECP capabilities <");
+
+ eec = -1;
+ for (eecp = XHCI_HCS0_XECP(hccp1) << 2;
+ eecp != 0 && XHCI_XECP_NEXT(eec) != 0;
+ eecp += XHCI_XECP_NEXT(eec) << 2) {
+ eec = XREAD4(sc, capa, eecp);
+
+ uint8_t xecpid = XHCI_XECP_ID(eec);
+
+ if ((xecpid >= 11 && xecpid <= 16) ||
+ (xecpid >= 19 && xecpid <= 191)) {
+ if (!first)
+ printf(",");
+ printf("RES(%x)", xecpid);
+ } else if (xecpid > 191) {
+ if (!first)
+ printf(",");
+ printf("VEND(%x)", xecpid);
+ } else {
+ if (!first)
+ printf(",");
+ switch (xecpid)
+ {
+ case XHCI_ID_USB_LEGACY:
+ printf("LEGACY");
+ break;
+ case XHCI_ID_PROTOCOLS:
+ printf("PROTO");
+ break;
+ case XHCI_ID_POWER_MGMT:
+ printf("POWER");
+ break;
+ case XHCI_ID_VIRTUALIZATION:
+ printf("VIRT");
+ break;
+ case XHCI_ID_MSG_IRQ:
+ printf("MSG IRQ");
+ break;
+ case XHCI_ID_USB_LOCAL_MEM:
+ printf("LOCAL MEM");
+ break;
+ case XHCI_ID_USB_DEBUG:
+ printf("DEBUG");
+ break;
+ case XHCI_ID_EXT_MSI:
+ printf("EXT MSI");
+ break;
+ case XHCI_ID_USB3_TUN:
+ printf("TUN");
+ break;
+
+ }
+ }
+ first = false;
+ }
+ printf(">\n");
+}
+
+static void
xhci_set_hw_power_sleep(struct usb_bus *bus, uint32_t state)
{
struct xhci_softc *sc = XHCI_BUS2SC(bus);
diff --git a/sys/dev/usb/controller/xhcireg.h b/sys/dev/usb/controller/xhcireg.h
index 9d0b6e2f4b4b..821897155544 100644
--- a/sys/dev/usb/controller/xhcireg.h
+++ b/sys/dev/usb/controller/xhcireg.h
@@ -205,6 +205,11 @@
#define XHCI_ID_VIRTUALIZATION 0x0004
#define XHCI_ID_MSG_IRQ 0x0005
#define XHCI_ID_USB_LOCAL_MEM 0x0006
+/* values 7-9 are reserved */
+#define XHCI_ID_USB_DEBUG 0x000a
+/* values 11-16 are reserved */
+#define XHCI_ID_EXT_MSI 0x0011
+#define XHCI_ID_USB3_TUN 0x0012
/* XHCI register R/W wrappers */
#define XREAD1(sc, what, a) \
diff --git a/sys/dev/usb/net/if_umb.c b/sys/dev/usb/net/if_umb.c
index f640b4224aad..b1082b117259 100644
--- a/sys/dev/usb/net/if_umb.c
+++ b/sys/dev/usb/net/if_umb.c
@@ -177,9 +177,7 @@ static void umb_ncm_setup(struct umb_softc *, struct usb_config *);
static void umb_close_bulkpipes(struct umb_softc *);
static int umb_ioctl(if_t , u_long, caddr_t);
static void umb_init(void *);
-#ifdef DEV_NETMAP
static void umb_input(if_t , struct mbuf *);
-#endif
static int umb_output(if_t , struct mbuf *,
const struct sockaddr *, struct route *);
static void umb_start(if_t );
@@ -585,9 +583,7 @@ umb_attach_task(struct usb_proc_msg *msg)
if_setsoftc(ifp, sc);
if_setflags(ifp, IFF_SIMPLEX | IFF_MULTICAST | IFF_POINTOPOINT);
if_setioctlfn(ifp, umb_ioctl);
-#ifdef DEV_NETMAP
if_setinputfn(ifp, umb_input);
-#endif
if_setoutputfn(ifp, umb_output);
if_setstartfn(ifp, umb_start);
if_setinitfn(ifp, umb_init);
diff --git a/sys/dev/usb/usb_hub.c b/sys/dev/usb/usb_hub.c
index e3509862ef54..ee9d8ab0c9bb 100644
--- a/sys/dev/usb/usb_hub.c
+++ b/sys/dev/usb/usb_hub.c
@@ -954,7 +954,8 @@ done:
* packet. This function is called having the "bus_mtx" locked.
*------------------------------------------------------------------------*/
void
-uhub_root_intr(struct usb_bus *bus, const uint8_t *ptr, uint8_t len)
+uhub_root_intr(struct usb_bus *bus,
+ const uint8_t *ptr __unused, uint8_t len __unused)
{
USB_BUS_LOCK_ASSERT(bus, MA_OWNED);
diff --git a/sys/dev/virtio/network/if_vtnet.c b/sys/dev/virtio/network/if_vtnet.c
index 867da80a53a8..73f27ac147ff 100644
--- a/sys/dev/virtio/network/if_vtnet.c
+++ b/sys/dev/virtio/network/if_vtnet.c
@@ -134,9 +134,9 @@ static int vtnet_rxq_replace_buf(struct vtnet_rxq *, struct mbuf *, int);
static int vtnet_rxq_enqueue_buf(struct vtnet_rxq *, struct mbuf *);
static int vtnet_rxq_new_buf(struct vtnet_rxq *);
static int vtnet_rxq_csum_needs_csum(struct vtnet_rxq *, struct mbuf *,
- uint16_t, int, struct virtio_net_hdr *);
-static int vtnet_rxq_csum_data_valid(struct vtnet_rxq *, struct mbuf *,
- uint16_t, int, struct virtio_net_hdr *);
+ bool, int, struct virtio_net_hdr *);
+static void vtnet_rxq_csum_data_valid(struct vtnet_rxq *, struct mbuf *,
+ int);
static int vtnet_rxq_csum(struct vtnet_rxq *, struct mbuf *,
struct virtio_net_hdr *);
static void vtnet_rxq_discard_merged_bufs(struct vtnet_rxq *, int);
@@ -1178,6 +1178,7 @@ vtnet_setup_interface(struct vtnet_softc *sc)
if (sc->vtnet_max_mtu >= ETHERMTU_JUMBO)
if_setcapabilitiesbit(ifp, IFCAP_JUMBO_MTU, 0);
if_setcapabilitiesbit(ifp, IFCAP_VLAN_MTU, 0);
+ if_setcapabilitiesbit(ifp, IFCAP_HWSTATS, 0);
/*
* Capabilities after here are not enabled by default.
@@ -1761,162 +1762,161 @@ vtnet_rxq_new_buf(struct vtnet_rxq *rxq)
}
static int
-vtnet_rxq_csum_needs_csum(struct vtnet_rxq *rxq, struct mbuf *m, uint16_t etype,
- int hoff, struct virtio_net_hdr *hdr)
+vtnet_rxq_csum_needs_csum(struct vtnet_rxq *rxq, struct mbuf *m, bool isipv6,
+ int protocol, struct virtio_net_hdr *hdr)
{
struct vtnet_softc *sc;
- int error;
- sc = rxq->vtnrx_sc;
+ /*
+ * The packet is likely from another VM on the same host or from the
+ * host that itself performed checksum offloading so Tx/Rx is basically
+ * a memcpy and the checksum has little value so far.
+ */
+
+ KASSERT(protocol == IPPROTO_TCP || protocol == IPPROTO_UDP,
+ ("%s: unsupported IP protocol %d", __func__, protocol));
/*
- * NEEDS_CSUM corresponds to Linux's CHECKSUM_PARTIAL, but FreeBSD does
- * not have an analogous CSUM flag. The checksum has been validated,
- * but is incomplete (TCP/UDP pseudo header).
- *
- * The packet is likely from another VM on the same host that itself
- * performed checksum offloading so Tx/Rx is basically a memcpy and
- * the checksum has little value.
- *
- * Default to receiving the packet as-is for performance reasons, but
- * this can cause issues if the packet is to be forwarded because it
- * does not contain a valid checksum. This patch may be helpful:
- * https://reviews.freebsd.org/D6611. In the meantime, have the driver
- * compute the checksum if requested.
- *
- * BMV: Need to add an CSUM_PARTIAL flag?
+ * If the user don't want us to fix it up here by computing the
+ * checksum, just forward the order to compute the checksum by setting
+ * the corresponding mbuf flag (e.g., CSUM_TCP).
*/
+ sc = rxq->vtnrx_sc;
if ((sc->vtnet_flags & VTNET_FLAG_FIXUP_NEEDS_CSUM) == 0) {
- error = vtnet_rxq_csum_data_valid(rxq, m, etype, hoff, hdr);
- return (error);
+ switch (protocol) {
+ case IPPROTO_TCP:
+ m->m_pkthdr.csum_flags |=
+ (isipv6 ? CSUM_TCP_IPV6 : CSUM_TCP);
+ break;
+ case IPPROTO_UDP:
+ m->m_pkthdr.csum_flags |=
+ (isipv6 ? CSUM_UDP_IPV6 : CSUM_UDP);
+ break;
+ }
+ m->m_pkthdr.csum_data = hdr->csum_offset;
+ return (0);
}
/*
* Compute the checksum in the driver so the packet will contain a
* valid checksum. The checksum is at csum_offset from csum_start.
*/
- switch (etype) {
-#if defined(INET) || defined(INET6)
- case ETHERTYPE_IP:
- case ETHERTYPE_IPV6: {
- int csum_off, csum_end;
- uint16_t csum;
+ int csum_off, csum_end;
+ uint16_t csum;
- csum_off = hdr->csum_start + hdr->csum_offset;
- csum_end = csum_off + sizeof(uint16_t);
+ csum_off = hdr->csum_start + hdr->csum_offset;
+ csum_end = csum_off + sizeof(uint16_t);
- /* Assume checksum will be in the first mbuf. */
- if (m->m_len < csum_end || m->m_pkthdr.len < csum_end)
- return (1);
-
- /*
- * Like in_delayed_cksum()/in6_delayed_cksum(), compute the
- * checksum and write it at the specified offset. We could
- * try to verify the packet: csum_start should probably
- * correspond to the start of the TCP/UDP header.
- *
- * BMV: Need to properly handle UDP with zero checksum. Is
- * the IPv4 header checksum implicitly validated?
- */
- csum = in_cksum_skip(m, m->m_pkthdr.len, hdr->csum_start);
- *(uint16_t *)(mtodo(m, csum_off)) = csum;
- m->m_pkthdr.csum_flags |= CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
- m->m_pkthdr.csum_data = 0xFFFF;
- break;
- }
-#endif
- default:
- sc->vtnet_stats.rx_csum_bad_ethtype++;
+ /* Assume checksum will be in the first mbuf. */
+ if (m->m_len < csum_end || m->m_pkthdr.len < csum_end) {
+ sc->vtnet_stats.rx_csum_bad_offset++;
return (1);
}
+ /*
+ * Like in_delayed_cksum()/in6_delayed_cksum(), compute the
+ * checksum and write it at the specified offset. We could
+ * try to verify the packet: csum_start should probably
+ * correspond to the start of the TCP/UDP header.
+ *
+ * BMV: Need to properly handle UDP with zero checksum. Is
+ * the IPv4 header checksum implicitly validated?
+ */
+ csum = in_cksum_skip(m, m->m_pkthdr.len, hdr->csum_start);
+ *(uint16_t *)(mtodo(m, csum_off)) = csum;
+ m->m_pkthdr.csum_flags |= CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
+ m->m_pkthdr.csum_data = 0xFFFF;
+
return (0);
}
+static void
+vtnet_rxq_csum_data_valid(struct vtnet_rxq *rxq, struct mbuf *m, int protocol)
+{
+ KASSERT(protocol == IPPROTO_TCP || protocol == IPPROTO_UDP,
+ ("%s: unsupported IP protocol %d", __func__, protocol));
+
+ m->m_pkthdr.csum_flags |= CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
+ m->m_pkthdr.csum_data = 0xFFFF;
+}
+
static int
-vtnet_rxq_csum_data_valid(struct vtnet_rxq *rxq, struct mbuf *m,
- uint16_t etype, int hoff, struct virtio_net_hdr *hdr __unused)
+vtnet_rxq_csum(struct vtnet_rxq *rxq, struct mbuf *m,
+ struct virtio_net_hdr *hdr)
{
-#if 0
+ const struct ether_header *eh;
struct vtnet_softc *sc;
-#endif
- int protocol;
+ int hoff, protocol;
+ uint16_t etype;
+ bool isipv6;
+
+ KASSERT(hdr->flags &
+ (VIRTIO_NET_HDR_F_NEEDS_CSUM | VIRTIO_NET_HDR_F_DATA_VALID),
+ ("%s: missing checksum offloading flag %x", __func__, hdr->flags));
+
+ eh = mtod(m, const struct ether_header *);
+ etype = ntohs(eh->ether_type);
+ if (etype == ETHERTYPE_VLAN) {
+ /* TODO BMV: Handle QinQ. */
+ const struct ether_vlan_header *evh =
+ mtod(m, const struct ether_vlan_header *);
+ etype = ntohs(evh->evl_proto);
+ hoff = sizeof(struct ether_vlan_header);
+ } else
+ hoff = sizeof(struct ether_header);
-#if 0
sc = rxq->vtnrx_sc;
-#endif
+ /* Check whether ethernet type is IP or IPv6, and get protocol. */
switch (etype) {
#if defined(INET)
case ETHERTYPE_IP:
- if (__predict_false(m->m_len < hoff + sizeof(struct ip)))
- protocol = IPPROTO_DONE;
- else {
+ if (__predict_false(m->m_len < hoff + sizeof(struct ip))) {
+ sc->vtnet_stats.rx_csum_inaccessible_ipproto++;
+ return (1);
+ } else {
struct ip *ip = (struct ip *)(m->m_data + hoff);
protocol = ip->ip_p;
}
+ isipv6 = false;
break;
#endif
#if defined(INET6)
case ETHERTYPE_IPV6:
if (__predict_false(m->m_len < hoff + sizeof(struct ip6_hdr))
- || ip6_lasthdr(m, hoff, IPPROTO_IPV6, &protocol) < 0)
- protocol = IPPROTO_DONE;
+ || ip6_lasthdr(m, hoff, IPPROTO_IPV6, &protocol) < 0) {
+ sc->vtnet_stats.rx_csum_inaccessible_ipproto++;
+ return (1);
+ }
+ isipv6 = true;
break;
#endif
default:
- protocol = IPPROTO_DONE;
- break;
+ sc->vtnet_stats.rx_csum_bad_ethtype++;
+ return (1);
}
+ /* Check whether protocol is TCP or UDP. */
switch (protocol) {
case IPPROTO_TCP:
case IPPROTO_UDP:
- m->m_pkthdr.csum_flags |= CSUM_DATA_VALID | CSUM_PSEUDO_HDR;
- m->m_pkthdr.csum_data = 0xFFFF;
break;
default:
/*
* FreeBSD does not support checksum offloading of this
- * protocol. Let the stack re-verify the checksum later
- * if the protocol is supported.
+ * protocol here.
*/
-#if 0
- if_printf(sc->vtnet_ifp,
- "%s: checksum offload of unsupported protocol "
- "etype=%#x protocol=%d csum_start=%d csum_offset=%d\n",
- __func__, etype, protocol, hdr->csum_start,
- hdr->csum_offset);
-#endif
- break;
+ sc->vtnet_stats.rx_csum_bad_ipproto++;
+ return (1);
}
- return (0);
-}
-
-static int
-vtnet_rxq_csum(struct vtnet_rxq *rxq, struct mbuf *m,
- struct virtio_net_hdr *hdr)
-{
- const struct ether_header *eh;
- int hoff;
- uint16_t etype;
-
- eh = mtod(m, const struct ether_header *);
- etype = ntohs(eh->ether_type);
- if (etype == ETHERTYPE_VLAN) {
- /* TODO BMV: Handle QinQ. */
- const struct ether_vlan_header *evh =
- mtod(m, const struct ether_vlan_header *);
- etype = ntohs(evh->evl_proto);
- hoff = sizeof(struct ether_vlan_header);
- } else
- hoff = sizeof(struct ether_header);
-
if (hdr->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM)
- return (vtnet_rxq_csum_needs_csum(rxq, m, etype, hoff, hdr));
+ return (vtnet_rxq_csum_needs_csum(rxq, m, isipv6, protocol,
+ hdr));
else /* VIRTIO_NET_HDR_F_DATA_VALID */
- return (vtnet_rxq_csum_data_valid(rxq, m, etype, hoff, hdr));
+ vtnet_rxq_csum_data_valid(rxq, m, protocol);
+
+ return (0);
}
static void
@@ -2497,6 +2497,10 @@ vtnet_txq_offload(struct vtnet_txq *txq, struct mbuf *m,
hdr->csum_start = vtnet_gtoh16(sc, csum_start);
hdr->csum_offset = vtnet_gtoh16(sc, m->m_pkthdr.csum_data);
txq->vtntx_stats.vtxs_csum++;
+ } else if ((flags & (CSUM_DATA_VALID | CSUM_PSEUDO_HDR)) &&
+ (proto == IPPROTO_TCP || proto == IPPROTO_UDP) &&
+ (m->m_pkthdr.csum_data == 0xFFFF)) {
+ hdr->flags |= VIRTIO_NET_HDR_F_DATA_VALID;
}
if (flags & (CSUM_IP_TSO | CSUM_IP6_TSO)) {
@@ -2610,7 +2614,8 @@ vtnet_txq_encap(struct vtnet_txq *txq, struct mbuf **m_head, int flags)
m->m_flags &= ~M_VLANTAG;
}
- if (m->m_pkthdr.csum_flags & VTNET_CSUM_ALL_OFFLOAD) {
+ if (m->m_pkthdr.csum_flags &
+ (VTNET_CSUM_ALL_OFFLOAD | CSUM_DATA_VALID)) {
m = vtnet_txq_offload(txq, m, hdr);
if ((*m_head = m) == NULL) {
error = ENOBUFS;
@@ -3032,16 +3037,14 @@ vtnet_get_counter(if_t ifp, ift_counter cnt)
return (rxaccum.vrxs_iqdrops);
case IFCOUNTER_IERRORS:
return (rxaccum.vrxs_ierrors);
+ case IFCOUNTER_IBYTES:
+ return (rxaccum.vrxs_ibytes);
case IFCOUNTER_OPACKETS:
return (txaccum.vtxs_opackets);
case IFCOUNTER_OBYTES:
- if (!VTNET_ALTQ_ENABLED)
- return (txaccum.vtxs_obytes);
- /* FALLTHROUGH */
+ return (txaccum.vtxs_obytes);
case IFCOUNTER_OMCASTS:
- if (!VTNET_ALTQ_ENABLED)
- return (txaccum.vtxs_omcasts);
- /* FALLTHROUGH */
+ return (txaccum.vtxs_omcasts);
default:
return (if_get_counter_default(ifp, cnt));
}
@@ -4322,9 +4325,9 @@ vtnet_setup_stat_sysctl(struct sysctl_ctx_list *ctx,
SYSCTL_ADD_UQUAD(ctx, child, OID_AUTO, "rx_csum_bad_offset",
CTLFLAG_RD | CTLFLAG_STATS, &stats->rx_csum_bad_offset,
"Received checksum offloaded buffer with incorrect offset");
- SYSCTL_ADD_UQUAD(ctx, child, OID_AUTO, "rx_csum_bad_proto",
- CTLFLAG_RD | CTLFLAG_STATS, &stats->rx_csum_bad_proto,
- "Received checksum offloaded buffer with incorrect protocol");
+ SYSCTL_ADD_UQUAD(ctx, child, OID_AUTO, "rx_csum_inaccessible_ipproto",
+ CTLFLAG_RD | CTLFLAG_STATS, &stats->rx_csum_inaccessible_ipproto,
+ "Received checksum offloaded buffer with inaccessible IP protocol");
SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "rx_csum_failed",
CTLTYPE_U64 | CTLFLAG_RD | CTLFLAG_STATS,
sc, 0, vtnet_sysctl_rx_csum_failed, "QU",
diff --git a/sys/dev/virtio/network/if_vtnetvar.h b/sys/dev/virtio/network/if_vtnetvar.h
index 0144b0f3232d..cab7ced639a7 100644
--- a/sys/dev/virtio/network/if_vtnetvar.h
+++ b/sys/dev/virtio/network/if_vtnetvar.h
@@ -46,7 +46,7 @@ struct vtnet_statistics {
uint64_t rx_csum_bad_ethtype;
uint64_t rx_csum_bad_ipproto;
uint64_t rx_csum_bad_offset;
- uint64_t rx_csum_bad_proto;
+ uint64_t rx_csum_inaccessible_ipproto;
uint64_t tx_csum_unknown_ethtype;
uint64_t tx_csum_proto_mismatch;
uint64_t tx_tso_not_tcp;
diff --git a/sys/fs/nfsserver/nfs_nfsdport.c b/sys/fs/nfsserver/nfs_nfsdport.c
index b2966934f9b7..7040c4afb797 100644
--- a/sys/fs/nfsserver/nfs_nfsdport.c
+++ b/sys/fs/nfsserver/nfs_nfsdport.c
@@ -2607,6 +2607,7 @@ again:
* rpc reply
*/
if (siz == 0) {
+ateof:
vput(vp);
if (nd->nd_flag & ND_NFSV3)
nfsrv_postopattr(nd, getret, &at);
@@ -2648,6 +2649,8 @@ again:
ncookies--;
}
if (cpos >= cend || ncookies == 0) {
+ if (eofflag != 0)
+ goto ateof;
siz = fullsiz;
toff = off;
goto again;
diff --git a/sys/fs/procfs/procfs.c b/sys/fs/procfs/procfs.c
index ab60ba47f322..cd66dd6f8b3b 100644
--- a/sys/fs/procfs/procfs.c
+++ b/sys/fs/procfs/procfs.c
@@ -156,42 +156,42 @@ procfs_init(PFS_INIT_ARGS)
root = pi->pi_root;
- pfs_create_link(root, "curproc", procfs_docurproc,
- NULL, NULL, NULL, 0);
- pfs_create_link(root, "self", procfs_docurproc,
- NULL, NULL, NULL, 0);
-
- dir = pfs_create_dir(root, "pid",
- procfs_attr_all_rx, NULL, NULL, PFS_PROCDEP);
- pfs_create_file(dir, "cmdline", procfs_doproccmdline,
- NULL, NULL, NULL, PFS_RD);
- pfs_create_file(dir, "dbregs", procfs_doprocdbregs,
+ pfs_create_link(root, NULL, "curproc", procfs_docurproc, NULL, NULL,
+ NULL, 0);
+ pfs_create_link(root, NULL, "self", procfs_docurproc, NULL, NULL, NULL,
+ 0);
+
+ pfs_create_dir(root, &dir, "pid", procfs_attr_all_rx, NULL, NULL,
+ PFS_PROCDEP);
+ pfs_create_file(dir, NULL, "cmdline", procfs_doproccmdline, NULL, NULL,
+ NULL, PFS_RD);
+ pfs_create_file(dir, NULL, "dbregs", procfs_doprocdbregs,
procfs_attr_rw, procfs_candebug, NULL, PFS_RDWR | PFS_RAW);
- pfs_create_file(dir, "etype", procfs_doproctype,
- NULL, NULL, NULL, PFS_RD);
- pfs_create_file(dir, "fpregs", procfs_doprocfpregs,
+ pfs_create_file(dir, NULL, "etype", procfs_doproctype, NULL, NULL, NULL,
+ PFS_RD);
+ pfs_create_file(dir, NULL, "fpregs", procfs_doprocfpregs,
procfs_attr_rw, procfs_candebug, NULL, PFS_RDWR | PFS_RAW);
- pfs_create_file(dir, "map", procfs_doprocmap,
- NULL, procfs_notsystem, NULL, PFS_RD);
- pfs_create_file(dir, "mem", procfs_doprocmem,
- procfs_attr_rw, procfs_candebug, NULL, PFS_RDWR | PFS_RAW);
- pfs_create_file(dir, "note", procfs_doprocnote,
- procfs_attr_w, procfs_candebug, NULL, PFS_WR);
- pfs_create_file(dir, "notepg", procfs_doprocnote,
- procfs_attr_w, procfs_candebug, NULL, PFS_WR);
- pfs_create_file(dir, "regs", procfs_doprocregs,
- procfs_attr_rw, procfs_candebug, NULL, PFS_RDWR | PFS_RAW);
- pfs_create_file(dir, "rlimit", procfs_doprocrlimit,
- NULL, NULL, NULL, PFS_RD);
- pfs_create_file(dir, "status", procfs_doprocstatus,
- NULL, NULL, NULL, PFS_RD);
- pfs_create_file(dir, "osrel", procfs_doosrel,
- procfs_attr_rw, procfs_candebug, NULL, PFS_RDWR);
-
- pfs_create_link(dir, "file", procfs_doprocfile,
- NULL, procfs_notsystem, NULL, 0);
- pfs_create_link(dir, "exe", procfs_doprocfile,
- NULL, procfs_notsystem, NULL, 0);
+ pfs_create_file(dir, NULL, "map", procfs_doprocmap, NULL,
+ procfs_notsystem, NULL, PFS_RD);
+ pfs_create_file(dir, NULL, "mem", procfs_doprocmem, procfs_attr_rw,
+ procfs_candebug, NULL, PFS_RDWR | PFS_RAW);
+ pfs_create_file(dir, NULL, "note", procfs_doprocnote, procfs_attr_w,
+ procfs_candebug, NULL, PFS_WR);
+ pfs_create_file(dir, NULL, "notepg", procfs_doprocnote, procfs_attr_w,
+ procfs_candebug, NULL, PFS_WR);
+ pfs_create_file(dir, NULL, "regs", procfs_doprocregs, procfs_attr_rw,
+ procfs_candebug, NULL, PFS_RDWR | PFS_RAW);
+ pfs_create_file(dir, NULL, "rlimit", procfs_doprocrlimit, NULL, NULL,
+ NULL, PFS_RD);
+ pfs_create_file(dir, NULL, "status", procfs_doprocstatus, NULL, NULL,
+ NULL, PFS_RD);
+ pfs_create_file(dir, NULL, "osrel", procfs_doosrel, procfs_attr_rw,
+ procfs_candebug, NULL, PFS_RDWR);
+
+ pfs_create_link(dir, NULL, "file", procfs_doprocfile, NULL,
+ procfs_notsystem, NULL, 0);
+ pfs_create_link(dir, NULL, "exe", procfs_doprocfile, NULL,
+ procfs_notsystem, NULL, 0);
return (0);
}
diff --git a/sys/fs/pseudofs/pseudofs.c b/sys/fs/pseudofs/pseudofs.c
index ef45f96a6192..7a4e67455214 100644
--- a/sys/fs/pseudofs/pseudofs.c
+++ b/sys/fs/pseudofs/pseudofs.c
@@ -133,7 +133,7 @@ pfs_add_node(struct pfs_node *parent, struct pfs_node *pn)
for (iter = parent->pn_nodes; iter != NULL; iter = iter->pn_next) {
if (strcmp(pn->pn_name, iter->pn_name) != 0)
continue;
- printf("pfs_add_node: homonymous siblings: '%s/%s' type %d",
+ printf("pfs_add_node: homonymous siblings: '%s/%s' type %d\n",
parent->pn_name, pn->pn_name, pn->pn_type);
/* Do not detach, because we are not yet attached. */
pn->pn_parent = NULL;
@@ -234,81 +234,101 @@ pfs_fixup_dir(struct pfs_node *parent)
/*
* Create a directory
*/
-struct pfs_node *
-pfs_create_dir(struct pfs_node *parent, const char *name,
- pfs_attr_t attr, pfs_vis_t vis, pfs_destroy_t destroy,
- int flags)
+int
+pfs_create_dir(struct pfs_node *parent, struct pfs_node **opn,
+ const char *name, pfs_attr_t attr, pfs_vis_t vis,
+ pfs_destroy_t destroy, int flags)
{
- struct pfs_node *pn;
+ struct pfs_node *pdir, *pn;
int rc;
- pn = pfs_alloc_node_flags(parent->pn_info, name,
+ /* Preserve in case the caller is reusing the one pointer for both. */
+ pdir = parent;
+ if (opn != NULL)
+ *opn = NULL;
+ pn = pfs_alloc_node_flags(pdir->pn_info, name,
(flags & PFS_PROCDEP) ? pfstype_procdir : pfstype_dir, flags);
if (pn == NULL)
- return (NULL);
+ return (ENOMEM);
pn->pn_attr = attr;
pn->pn_vis = vis;
pn->pn_destroy = destroy;
pn->pn_flags = flags;
- rc = pfs_add_node(parent, pn);
+ rc = pfs_add_node(pdir, pn);
if (rc == 0)
rc = pfs_fixup_dir_flags(pn, flags);
if (rc != 0) {
pfs_destroy(pn);
pn = NULL;
+ } else if (opn != NULL) {
+ *opn = pn;
}
- return (pn);
+
+ return (rc);
}
/*
* Create a file
*/
-struct pfs_node *
-pfs_create_file(struct pfs_node *parent, const char *name, pfs_fill_t fill,
- pfs_attr_t attr, pfs_vis_t vis, pfs_destroy_t destroy,
- int flags)
+int
+pfs_create_file(struct pfs_node *parent, struct pfs_node **opn,
+ const char *name, pfs_fill_t fill, pfs_attr_t attr,
+ pfs_vis_t vis, pfs_destroy_t destroy, int flags)
{
struct pfs_node *pn;
+ int rc;
+ if (opn != NULL)
+ *opn = NULL;
pn = pfs_alloc_node_flags(parent->pn_info, name, pfstype_file, flags);
if (pn == NULL)
- return (NULL);
+ return (ENOMEM);
+
pn->pn_fill = fill;
pn->pn_attr = attr;
pn->pn_vis = vis;
pn->pn_destroy = destroy;
pn->pn_flags = flags;
- if (pfs_add_node(parent, pn) != 0) {
+ if ((rc = pfs_add_node(parent, pn)) != 0) {
pfs_destroy(pn);
pn = NULL;
+ } else if (opn != NULL) {
+ *opn = pn;
}
- return (pn);
+
+ return (rc);
}
/*
* Create a symlink
*/
-struct pfs_node *
-pfs_create_link(struct pfs_node *parent, const char *name, pfs_fill_t fill,
- pfs_attr_t attr, pfs_vis_t vis, pfs_destroy_t destroy,
- int flags)
+int
+pfs_create_link(struct pfs_node *parent, struct pfs_node **opn,
+ const char *name, pfs_fill_t fill, pfs_attr_t attr,
+ pfs_vis_t vis, pfs_destroy_t destroy, int flags)
{
struct pfs_node *pn;
+ int rc;
+ if (opn != NULL)
+ *opn = NULL;
pn = pfs_alloc_node_flags(parent->pn_info, name, pfstype_symlink, flags);
if (pn == NULL)
- return (NULL);
+ return (ENOMEM);
+
pn->pn_fill = fill;
pn->pn_attr = attr;
pn->pn_vis = vis;
pn->pn_destroy = destroy;
pn->pn_flags = flags;
- if (pfs_add_node(parent, pn) != 0) {
+ if ((rc = pfs_add_node(parent, pn)) != 0) {
pfs_destroy(pn);
pn = NULL;
+ } else if (opn != NULL) {
+ *opn = pn;
}
- return (pn);
+ return (rc);
}
/*
@@ -475,6 +495,7 @@ pfs_init(struct pfs_info *pi, struct vfsconf *vfc)
if (error) {
pfs_destroy(root);
pi->pi_root = NULL;
+ pfs_fileno_uninit(pi);
return (error);
}
diff --git a/sys/fs/pseudofs/pseudofs.h b/sys/fs/pseudofs/pseudofs.h
index c60dd7b339d1..2b08dcad978d 100644
--- a/sys/fs/pseudofs/pseudofs.h
+++ b/sys/fs/pseudofs/pseudofs.h
@@ -255,17 +255,18 @@ int pfs_uninit (struct pfs_info *pi, struct vfsconf *vfc);
/*
* Directory structure construction and manipulation
*/
-struct pfs_node *pfs_create_dir (struct pfs_node *parent, const char *name,
- pfs_attr_t attr, pfs_vis_t vis,
- pfs_destroy_t destroy, int flags);
-struct pfs_node *pfs_create_file(struct pfs_node *parent, const char *name,
- pfs_fill_t fill, pfs_attr_t attr,
- pfs_vis_t vis, pfs_destroy_t destroy,
- int flags);
-struct pfs_node *pfs_create_link(struct pfs_node *parent, const char *name,
- pfs_fill_t fill, pfs_attr_t attr,
+int pfs_create_dir (struct pfs_node *parent, struct pfs_node **opn,
+ const char *name, pfs_attr_t attr,
pfs_vis_t vis, pfs_destroy_t destroy,
int flags);
+int pfs_create_file (struct pfs_node *parent, struct pfs_node **opn,
+ const char *name, pfs_fill_t fill,
+ pfs_attr_t attr, pfs_vis_t vis,
+ pfs_destroy_t destroy, int flags);
+int pfs_create_link (struct pfs_node *parent, struct pfs_node **opn,
+ const char *name, pfs_fill_t fill,
+ pfs_attr_t attr, pfs_vis_t vis,
+ pfs_destroy_t destroy, int flags);
struct pfs_node *pfs_find_node (struct pfs_node *parent, const char *name);
void pfs_purge (struct pfs_node *pn);
int pfs_destroy (struct pfs_node *pn);
diff --git a/sys/fs/tarfs/tarfs_vnops.c b/sys/fs/tarfs/tarfs_vnops.c
index acf18de5ab51..c110107bb210 100644
--- a/sys/fs/tarfs/tarfs_vnops.c
+++ b/sys/fs/tarfs/tarfs_vnops.c
@@ -334,6 +334,10 @@ tarfs_readdir(struct vop_readdir_args *ap)
tnp, tnp->name, uio->uio_offset, uio->uio_resid);
if (uio->uio_offset == TARFS_COOKIE_EOF) {
+ if (eofflag != NULL) {
+ TARFS_DPF(VNODE, "%s: Setting EOF flag\n", __func__);
+ *eofflag = 1;
+ }
TARFS_DPF(VNODE, "%s: EOF\n", __func__);
return (0);
}
diff --git a/sys/kern/init_main.c b/sys/kern/init_main.c
index 36ce44b988be..87ffdb8dbf07 100644
--- a/sys/kern/init_main.c
+++ b/sys/kern/init_main.c
@@ -145,13 +145,6 @@ FEATURE(invariants, "Kernel compiled with INVARIANTS, may affect performance");
#endif
/*
- * This ensures that there is at least one entry so that the sysinit_set
- * symbol is not undefined. A sybsystem ID of SI_SUB_DUMMY is never
- * executed.
- */
-SYSINIT(placeholder, SI_SUB_DUMMY, SI_ORDER_ANY, NULL, NULL);
-
-/*
* The sysinit linker set compiled into the kernel. These are placed onto the
* sysinit list by mi_startup; sysinit_add can add (e.g., from klds) additional
* sysinits to the linked list but the linker set here does not change.
@@ -296,7 +289,7 @@ mi_startup(void)
BOOTTRACE_INIT("sysinit 0x%7x", sip->subsystem);
#if defined(VERBOSE_SYSINIT)
- if (sip->subsystem > last && verbose_sysinit != 0) {
+ if (sip->subsystem != last && verbose_sysinit != 0) {
verbose = 1;
printf("subsystem %x\n", sip->subsystem);
}
diff --git a/sys/kern/init_sysent.c b/sys/kern/init_sysent.c
index fcd232cde21e..e42e7dcf8b44 100644
--- a/sys/kern/init_sysent.c
+++ b/sys/kern/init_sysent.c
@@ -663,4 +663,6 @@ struct sysent sysent[] = {
{ .sy_narg = AS(inotify_rm_watch_args), .sy_call = (sy_call_t *)sys_inotify_rm_watch, .sy_auevent = AUE_INOTIFY, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 594 = inotify_rm_watch */
{ .sy_narg = AS(getgroups_args), .sy_call = (sy_call_t *)sys_getgroups, .sy_auevent = AUE_GETGROUPS, .sy_flags = SYF_CAPENABLED, .sy_thrcnt = SY_THR_STATIC }, /* 595 = getgroups */
{ .sy_narg = AS(setgroups_args), .sy_call = (sy_call_t *)sys_setgroups, .sy_auevent = AUE_SETGROUPS, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 596 = setgroups */
+ { .sy_narg = AS(jail_attach_jd_args), .sy_call = (sy_call_t *)sys_jail_attach_jd, .sy_auevent = AUE_JAIL_ATTACH, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 597 = jail_attach_jd */
+ { .sy_narg = AS(jail_remove_jd_args), .sy_call = (sy_call_t *)sys_jail_remove_jd, .sy_auevent = AUE_JAIL_REMOVE, .sy_flags = 0, .sy_thrcnt = SY_THR_STATIC }, /* 598 = jail_remove_jd */
};
diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c
index a27ab33b34da..057235574eb5 100644
--- a/sys/kern/kern_descrip.c
+++ b/sys/kern/kern_descrip.c
@@ -5250,6 +5250,8 @@ file_type_to_name(short type)
return ("eventfd");
case DTYPE_TIMERFD:
return ("timerfd");
+ case DTYPE_JAILDESC:
+ return ("jail");
default:
return ("unkn");
}
diff --git a/sys/kern/kern_event.c b/sys/kern/kern_event.c
index eb77a5064113..501adc151d44 100644
--- a/sys/kern/kern_event.c
+++ b/sys/kern/kern_event.c
@@ -50,6 +50,7 @@
#include <sys/filedesc.h>
#include <sys/filio.h>
#include <sys/fcntl.h>
+#include <sys/jail.h>
#include <sys/kthread.h>
#include <sys/selinfo.h>
#include <sys/queue.h>
@@ -163,6 +164,9 @@ static int filt_kqueue(struct knote *kn, long hint);
static int filt_procattach(struct knote *kn);
static void filt_procdetach(struct knote *kn);
static int filt_proc(struct knote *kn, long hint);
+static int filt_jailattach(struct knote *kn);
+static void filt_jaildetach(struct knote *kn);
+static int filt_jail(struct knote *kn, long hint);
static int filt_fileattach(struct knote *kn);
static void filt_timerexpire(void *knx);
static void filt_timerexpire_l(struct knote *kn, bool proc_locked);
@@ -195,6 +199,12 @@ static const struct filterops proc_filtops = {
.f_detach = filt_procdetach,
.f_event = filt_proc,
};
+static const struct filterops jail_filtops = {
+ .f_isfd = 0,
+ .f_attach = filt_jailattach,
+ .f_detach = filt_jaildetach,
+ .f_event = filt_jail,
+};
static const struct filterops timer_filtops = {
.f_isfd = 0,
.f_attach = filt_timerattach,
@@ -365,6 +375,7 @@ static struct {
[~EVFILT_USER] = { &user_filtops, 1 },
[~EVFILT_SENDFILE] = { &null_filtops },
[~EVFILT_EMPTY] = { &file_filtops, 1 },
+ [~EVFILT_JAIL] = { &jail_filtops, 1 },
};
/*
@@ -528,7 +539,8 @@ filt_proc(struct knote *kn, long hint)
* process forked. Additionally, for each knote attached to the
* parent, check whether user wants to track the new process. If so
* attach a new knote to it, and immediately report an event with the
- * child's pid.
+ * child's pid. This is also called on jail creation, which is treated
+ * the same way by jail events.
*/
void
knote_fork(struct knlist *list, int pid)
@@ -555,6 +567,8 @@ knote_fork(struct knlist *list, int pid)
/*
* The same as knote(), activate the event.
*/
+ _Static_assert(NOTE_JAIL_CHILD == NOTE_FORK,
+ "NOTE_JAIL_CHILD should be the same as NOTE_FORK");
if ((kn->kn_sfflags & NOTE_TRACK) == 0) {
if (kn->kn_fop->f_event(kn, NOTE_FORK))
KNOTE_ACTIVATE(kn, 1);
@@ -614,6 +628,124 @@ knote_fork(struct knlist *list, int pid)
}
}
+int
+filt_jailattach(struct knote *kn)
+{
+ struct prison *pr;
+ bool immediate;
+
+ immediate = false;
+ if (kn->kn_id == 0) {
+ /* Let jid=0 watch the current prison (including prison0). */
+ pr = curthread->td_ucred->cr_prison;
+ mtx_lock(&pr->pr_mtx);
+ } else if (kn->kn_flags & (EV_FLAG1 | EV_FLAG2)) {
+ /*
+ * The kernel registers prisons before they are valid,
+ * so prison_find_child will fail.
+ */
+ TAILQ_FOREACH(pr, &allprison, pr_list) {
+ if (pr->pr_id < kn->kn_id)
+ continue;
+ if (pr->pr_id > kn->kn_id) {
+ pr = NULL;
+ break;
+ }
+ mtx_lock(&pr->pr_mtx);
+ break;
+ }
+ if (pr == NULL)
+ return (ENOENT);
+ } else {
+ sx_slock(&allprison_lock);
+ pr = prison_find_child(curthread->td_ucred->cr_prison,
+ kn->kn_id);
+ sx_sunlock(&allprison_lock);
+ if (pr == NULL)
+ return (ENOENT);
+ if (!prison_isalive(pr)) {
+ mtx_unlock(&pr->pr_mtx);
+ return (ENOENT);
+ }
+ }
+ kn->kn_ptr.p_prison = pr;
+ kn->kn_flags |= EV_CLEAR;
+
+ /*
+ * Internal flag indicating registration done by kernel for the
+ * purposes of getting a NOTE_CHILD notification.
+ */
+ if (kn->kn_flags & EV_FLAG2) {
+ kn->kn_flags &= ~EV_FLAG2;
+ kn->kn_data = kn->kn_sdata; /* parent id */
+ kn->kn_fflags = NOTE_CHILD;
+ kn->kn_sfflags &= ~NOTE_JAIL_CTRLMASK;
+ immediate = true; /* Force immediate activation of child note. */
+ }
+ /*
+ * Internal flag indicating registration done by kernel (for other than
+ * NOTE_CHILD).
+ */
+ if (kn->kn_flags & EV_FLAG1) {
+ kn->kn_flags &= ~EV_FLAG1;
+ }
+
+ knlist_add(pr->pr_klist, kn, 1);
+
+ /* Immediately activate any child notes. */
+ if (immediate)
+ KNOTE_ACTIVATE(kn, 0);
+
+ mtx_unlock(&pr->pr_mtx);
+ return (0);
+}
+
+void
+filt_jaildetach(struct knote *kn)
+{
+ if (kn->kn_ptr.p_prison != NULL) {
+ knlist_remove(kn->kn_knlist, kn, 0);
+ kn->kn_ptr.p_prison = NULL;
+ } else
+ kn->kn_status |= KN_DETACHED;
+}
+
+int
+filt_jail(struct knote *kn, long hint)
+{
+ struct prison *pr;
+ u_int event;
+
+ pr = kn->kn_ptr.p_prison;
+ if (pr == NULL) /* already activated, from attach filter */
+ return (0);
+
+ /* Mask off extra data. */
+ event = (u_int)hint & NOTE_JAIL_CTRLMASK;
+
+ /* If the user is interested in this event, record it. */
+ if (kn->kn_sfflags & event)
+ kn->kn_fflags |= event;
+
+ /* Report the attached process id. */
+ if (event == NOTE_JAIL_ATTACH) {
+ if (kn->kn_data != 0)
+ kn->kn_fflags |= NOTE_JAIL_ATTACH_MULTI;
+ kn->kn_data = hint & NOTE_JAIL_DATAMASK;
+ }
+
+ /* Prison is gone, so flag the event as finished. */
+ if (event == NOTE_JAIL_REMOVE) {
+ kn->kn_flags |= EV_EOF | EV_ONESHOT;
+ kn->kn_ptr.p_prison = NULL;
+ if (kn->kn_fflags == 0)
+ kn->kn_flags |= EV_DROP;
+ return (1);
+ }
+
+ return (kn->kn_fflags != 0);
+}
+
/*
* XXX: EVFILT_TIMER should perhaps live in kern_time.c beside the
* interval timer support code.
@@ -1597,8 +1729,8 @@ findkn:
/*
* If possible, find an existing knote to use for this kevent.
*/
- if (kev->filter == EVFILT_PROC &&
- (kev->flags & (EV_FLAG1 | EV_FLAG2)) != 0) {
+ if ((kev->filter == EVFILT_PROC || kev->filter == EVFILT_JAIL)
+ && (kev->flags & (EV_FLAG1 | EV_FLAG2)) != 0) {
/* This is an internal creation of a process tracking
* note. Don't attempt to coalesce this with an
* existing note.
@@ -2800,6 +2932,7 @@ knote_init(void)
knote_zone = uma_zcreate("KNOTE", sizeof(struct knote), NULL, NULL,
NULL, NULL, UMA_ALIGN_PTR, 0);
ast_register(TDA_KQUEUE, ASTR_ASTF_REQUIRED, 0, ast_kqueue);
+ prison0.pr_klist = knlist_alloc(&prison0.pr_mtx);
}
SYSINIT(knote, SI_SUB_PSEUDO, SI_ORDER_ANY, knote_init, NULL);
diff --git a/sys/kern/kern_jail.c b/sys/kern/kern_jail.c
index 7c9a15ae18f3..5a1fbe23ddeb 100644
--- a/sys/kern/kern_jail.c
+++ b/sys/kern/kern_jail.c
@@ -39,15 +39,18 @@
#include <sys/kernel.h>
#include <sys/systm.h>
#include <sys/errno.h>
+#include <sys/file.h>
#include <sys/sysproto.h>
#include <sys/malloc.h>
#include <sys/osd.h>
#include <sys/priv.h>
#include <sys/proc.h>
#include <sys/epoch.h>
+#include <sys/event.h>
#include <sys/taskqueue.h>
#include <sys/fcntl.h>
#include <sys/jail.h>
+#include <sys/jaildesc.h>
#include <sys/linker.h>
#include <sys/lock.h>
#include <sys/mman.h>
@@ -154,7 +157,8 @@ static void prison_complete(void *context, int pending);
static void prison_deref(struct prison *pr, int flags);
static void prison_deref_kill(struct prison *pr, struct prisonlist *freeprison);
static int prison_lock_xlock(struct prison *pr, int flags);
-static void prison_cleanup(struct prison *pr);
+static void prison_cleanup_locked(struct prison *pr);
+static void prison_cleanup_unlocked(struct prison *pr);
static void prison_free_not_last(struct prison *pr);
static void prison_proc_free_not_last(struct prison *pr);
static void prison_proc_relink(struct prison *opr, struct prison *npr,
@@ -167,6 +171,7 @@ static void prison_racct_attach(struct prison *pr);
static void prison_racct_modify(struct prison *pr);
static void prison_racct_detach(struct prison *pr);
#endif
+static void prison_knote(struct prison *pr, long hint);
/* Flags for prison_deref */
#define PD_DEREF 0x01 /* Decrement pr_ref */
@@ -985,6 +990,8 @@ prison_ip_cnt(const struct prison *pr, const pr_family_t af)
int
kern_jail_set(struct thread *td, struct uio *optuio, int flags)
{
+ struct file *jfp_out;
+ struct jaildesc *desc_in;
struct nameidata nd;
#ifdef INET
struct prison_ip *ip4;
@@ -995,6 +1002,7 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags)
struct vfsopt *opt;
struct vfsoptlist *opts;
struct prison *pr, *deadpr, *dinspr, *inspr, *mypr, *ppr, *tpr;
+ struct ucred *jdcred;
struct vnode *root;
char *domain, *errmsg, *host, *name, *namelc, *p, *path, *uuid;
char *g_path, *osrelstr;
@@ -1008,7 +1016,7 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags)
int created, cuflags, descend, drflags, enforce;
int error, errmsg_len, errmsg_pos;
int gotchildmax, gotenforce, gothid, gotrsnum, gotslevel;
- int deadid, jid, jsys, len, level;
+ int deadid, jfd_in, jfd_out, jfd_pos, jid, jsys, len, level;
int childmax, osreldt, rsnum, slevel;
#ifdef INET
int ip4s;
@@ -1018,22 +1026,32 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags)
int ip6s;
bool redo_ip6;
#endif
+ bool maybe_changed;
uint64_t pr_allow, ch_allow, pr_flags, ch_flags;
uint64_t pr_allow_diff;
unsigned tallow;
char numbuf[12];
- error = priv_check(td, PRIV_JAIL_SET);
- if (!error && (flags & JAIL_ATTACH))
- error = priv_check(td, PRIV_JAIL_ATTACH);
- if (error)
- return (error);
mypr = td->td_ucred->cr_prison;
- if ((flags & JAIL_CREATE) && mypr->pr_childmax == 0)
+ if (((flags & (JAIL_CREATE | JAIL_AT_DESC)) == JAIL_CREATE)
+ && mypr->pr_childmax == 0)
return (EPERM);
if (flags & ~JAIL_SET_MASK)
return (EINVAL);
+ if ((flags & (JAIL_USE_DESC | JAIL_AT_DESC))
+ == (JAIL_USE_DESC | JAIL_AT_DESC))
+ return (EINVAL);
+ prison_hold(mypr);
+#ifdef INET
+ ip4 = NULL;
+#endif
+#ifdef INET6
+ ip6 = NULL;
+#endif
+ g_path = NULL;
+ jfp_out = NULL;
+ jfd_out = -1;
/*
* Check all the parameters before committing to anything. Not all
* errors can be caught early, but we may as well try. Also, this
@@ -1046,14 +1064,7 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags)
*/
error = vfs_buildopts(optuio, &opts);
if (error)
- return (error);
-#ifdef INET
- ip4 = NULL;
-#endif
-#ifdef INET6
- ip6 = NULL;
-#endif
- g_path = NULL;
+ goto done_free;
cuflags = flags & (JAIL_CREATE | JAIL_UPDATE);
if (!cuflags) {
@@ -1062,6 +1073,72 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags)
goto done_errmsg;
}
+ error = vfs_copyopt(opts, "desc", &jfd_in, sizeof(jfd_in));
+ if (error == ENOENT) {
+ if (flags & (JAIL_USE_DESC | JAIL_AT_DESC | JAIL_GET_DESC |
+ JAIL_OWN_DESC)) {
+ vfs_opterror(opts, "missing desc");
+ goto done_errmsg;
+ }
+ jfd_in = -1;
+ } else if (error != 0)
+ goto done_free;
+ else {
+ if (!(flags & (JAIL_USE_DESC | JAIL_AT_DESC | JAIL_GET_DESC |
+ JAIL_OWN_DESC))) {
+ vfs_opterror(opts, "unexpected desc");
+ goto done_errmsg;
+ }
+ if (flags & JAIL_AT_DESC) {
+ /*
+ * Look up and create jails based on the
+ * descriptor's prison.
+ */
+ prison_free(mypr);
+ error = jaildesc_find(td, jfd_in, &desc_in, &mypr,
+ NULL);
+ if (error != 0) {
+ vfs_opterror(opts, error == ENOENT
+ ? "descriptor to dead jail"
+ : "not a jail descriptor");
+ goto done_errmsg;
+ }
+ /*
+ * Check file permissions using the current
+ * credentials, and operation permissions
+ * using the descriptor's credentials.
+ */
+ error = vaccess(VREG, desc_in->jd_mode, desc_in->jd_uid,
+ desc_in->jd_gid, VEXEC, td->td_ucred);
+ JAILDESC_UNLOCK(desc_in);
+ if (error != 0)
+ goto done_free;
+ if ((flags & JAIL_CREATE) && mypr->pr_childmax == 0) {
+ error = EPERM;
+ goto done_free;
+ }
+ }
+ if (flags & (JAIL_GET_DESC | JAIL_OWN_DESC)) {
+ /* Allocate a jail descriptor to return later. */
+ error = jaildesc_alloc(td, &jfp_out, &jfd_out,
+ flags & JAIL_OWN_DESC);
+ if (error)
+ goto done_free;
+ }
+ }
+
+ /*
+ * Delay the permission check if using a jail descriptor,
+ * until we get the descriptor's credentials.
+ */
+ if (!(flags & JAIL_USE_DESC)) {
+ error = priv_check(td, PRIV_JAIL_SET);
+ if (error == 0 && (flags & JAIL_ATTACH))
+ error = priv_check(td, PRIV_JAIL_ATTACH);
+ if (error)
+ goto done_free;
+ }
+
error = vfs_copyopt(opts, "jid", &jid, sizeof(jid));
if (error == ENOENT)
jid = 0;
@@ -1422,6 +1499,7 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags)
pr = NULL;
inspr = NULL;
deadpr = NULL;
+ maybe_changed = false;
if (cuflags == JAIL_CREATE && jid == 0 && name != NULL) {
namelc = strrchr(name, '.');
jid = strtoul(namelc != NULL ? namelc + 1 : name, &p, 10);
@@ -1436,7 +1514,57 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags)
error = EAGAIN;
goto done_deref;
}
- if (jid != 0) {
+ if (flags & JAIL_USE_DESC) {
+ /* Get the jail from its descriptor. */
+ error = jaildesc_find(td, jfd_in, &desc_in, &pr, &jdcred);
+ if (error) {
+ vfs_opterror(opts, error == ENOENT
+ ? "descriptor to dead jail"
+ : "not a jail descriptor");
+ goto done_deref;
+ }
+ drflags |= PD_DEREF;
+ /*
+ * Check file permissions using the current credentials,
+ * and operation permissions using the descriptor's
+ * credentials.
+ */
+ error = vaccess(VREG, desc_in->jd_mode, desc_in->jd_uid,
+ desc_in->jd_gid, VWRITE, td->td_ucred);
+ if (error == 0 && (flags & JAIL_ATTACH))
+ error = vaccess(VREG, desc_in->jd_mode, desc_in->jd_uid,
+ desc_in->jd_gid, VEXEC, td->td_ucred);
+ JAILDESC_UNLOCK(desc_in);
+ if (error == 0)
+ error = priv_check_cred(jdcred, PRIV_JAIL_SET);
+ if (error == 0 && (flags & JAIL_ATTACH))
+ error = priv_check_cred(jdcred, PRIV_JAIL_ATTACH);
+ crfree(jdcred);
+ if (error)
+ goto done_deref;
+ mtx_lock(&pr->pr_mtx);
+ drflags |= PD_LOCKED;
+ if (cuflags == JAIL_CREATE) {
+ error = EEXIST;
+ vfs_opterror(opts, "jail %d already exists",
+ pr->pr_id);
+ goto done_deref;
+ }
+ if (!prison_isalive(pr)) {
+ /* While a jid can be resurrected, the prison
+ * itself cannot.
+ */
+ error = ENOENT;
+ vfs_opterror(opts, "jail %d is dying", pr->pr_id);
+ goto done_deref;
+ }
+ if (jid != 0 && jid != pr->pr_id) {
+ error = EINVAL;
+ vfs_opterror(opts, "cannot change jid");
+ goto done_deref;
+ }
+ jid = pr->pr_id;
+ } else if (jid != 0) {
if (jid < 0) {
error = EINVAL;
vfs_opterror(opts, "negative jid");
@@ -1570,7 +1698,7 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags)
}
}
}
- /* Update: must provide a jid or name. */
+ /* Update: must provide a desc, jid, or name. */
else if (cuflags == JAIL_UPDATE && pr == NULL) {
error = ENOENT;
vfs_opterror(opts, "update specified no jail");
@@ -1643,6 +1771,7 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags)
LIST_INSERT_HEAD(&ppr->pr_children, pr, pr_sibling);
for (tpr = ppr; tpr != NULL; tpr = tpr->pr_parent)
tpr->pr_childcount++;
+ pr->pr_klist = knlist_alloc(&pr->pr_mtx);
/* Set some default values, and inherit some from the parent. */
if (namelc == NULL)
@@ -1722,8 +1851,10 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags)
* Grab a reference for existing prisons, to ensure they
* continue to exist for the duration of the call.
*/
- prison_hold(pr);
- drflags |= PD_DEREF;
+ if (!(drflags & PD_DEREF)) {
+ prison_hold(pr);
+ drflags |= PD_DEREF;
+ }
#if defined(VIMAGE) && (defined(INET) || defined(INET6))
if ((pr->pr_flags & PR_VNET) &&
(ch_flags & (PR_IP4_USER | PR_IP6_USER))) {
@@ -1880,6 +2011,7 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags)
goto done_deref;
}
}
+ maybe_changed = true;
/* Set the parameters of the prison. */
#ifdef INET
@@ -2112,7 +2244,12 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags)
* reference via persistence, or is about to gain one via attachment.
*/
if (created) {
- drflags = prison_lock_xlock(pr, drflags);
+ sx_assert(&allprison_lock, SX_XLOCKED);
+ mtx_lock(&ppr->pr_mtx);
+ knote_fork(ppr->pr_klist, pr->pr_id);
+ mtx_unlock(&ppr->pr_mtx);
+ mtx_lock(&pr->pr_mtx);
+ drflags |= PD_LOCKED;
pr->pr_state = PRISON_STATE_ALIVE;
}
@@ -2146,10 +2283,37 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags)
printf("Warning jail jid=%d: mountd/nfsd requires a separate"
" file system\n", pr->pr_id);
+ /*
+ * Now that the prison is fully created without error, set the
+ * jail descriptor if one was requested. This is the only
+ * parameter that is returned to the caller (except the error
+ * message).
+ */
+ if (jfd_out >= 0) {
+ if (!(drflags & PD_LOCKED)) {
+ mtx_lock(&pr->pr_mtx);
+ drflags |= PD_LOCKED;
+ }
+ jfd_pos = 2 * vfs_getopt_pos(opts, "desc") + 1;
+ if (optuio->uio_segflg == UIO_SYSSPACE)
+ *(int*)optuio->uio_iov[jfd_pos].iov_base = jfd_out;
+ else
+ (void)copyout(&jfd_out,
+ optuio->uio_iov[jfd_pos].iov_base, sizeof(jfd_out));
+ jaildesc_set_prison(jfp_out, pr);
+ }
+
drflags &= ~PD_KILL;
td->td_retval[0] = pr->pr_id;
done_deref:
+ /*
+ * Report changes to kevent. This can happen even if the
+ * system call fails, as changes might have been made before
+ * the failure.
+ */
+ if (maybe_changed && !created)
+ prison_knote(pr, NOTE_JAIL_SET);
/* Release any temporary prison holds and/or locks. */
if (pr != NULL)
prison_deref(pr, drflags);
@@ -2176,15 +2340,21 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags)
}
}
done_free:
+ /* Clean up other resources. */
#ifdef INET
prison_ip_free(ip4);
#endif
#ifdef INET6
prison_ip_free(ip6);
#endif
+ if (jfp_out != NULL)
+ fdrop(jfp_out, td);
+ if (error && jfd_out >= 0)
+ (void)kern_close(td, jfd_out);
if (g_path != NULL)
free(g_path, M_TEMP);
vfs_freeopts(opts);
+ prison_free(mypr);
return (error);
}
@@ -2329,16 +2499,22 @@ int
kern_jail_get(struct thread *td, struct uio *optuio, int flags)
{
struct bool_flags *bf;
+ struct file *jfp_out;
+ struct jaildesc *desc_in;
struct jailsys_flags *jsf;
struct prison *pr, *mypr;
struct vfsopt *opt;
struct vfsoptlist *opts;
char *errmsg, *name;
int drflags, error, errmsg_len, errmsg_pos, i, jid, len, pos;
+ int jfd_in, jfd_out;
unsigned f;
if (flags & ~JAIL_GET_MASK)
return (EINVAL);
+ if ((flags & (JAIL_USE_DESC | JAIL_AT_DESC))
+ == (JAIL_USE_DESC | JAIL_AT_DESC))
+ return (EINVAL);
/* Get the parameter list. */
error = vfs_buildopts(optuio, &opts);
@@ -2346,13 +2522,81 @@ kern_jail_get(struct thread *td, struct uio *optuio, int flags)
return (error);
errmsg_pos = vfs_getopt_pos(opts, "errmsg");
mypr = td->td_ucred->cr_prison;
+ prison_hold(mypr);
pr = NULL;
+ jfp_out = NULL;
+ jfd_out = -1;
/*
- * Find the prison specified by one of: lastjid, jid, name.
+ * Find the prison specified by one of: desc, lastjid, jid, name.
*/
sx_slock(&allprison_lock);
drflags = PD_LIST_SLOCKED;
+
+ error = vfs_copyopt(opts, "desc", &jfd_in, sizeof(jfd_in));
+ if (error == ENOENT) {
+ if (flags & (JAIL_AT_DESC | JAIL_GET_DESC | JAIL_OWN_DESC)) {
+ vfs_opterror(opts, "missing desc");
+ goto done;
+ }
+ } else if (error == 0) {
+ if (!(flags & (JAIL_USE_DESC | JAIL_AT_DESC | JAIL_GET_DESC |
+ JAIL_OWN_DESC))) {
+ vfs_opterror(opts, "unexpected desc");
+ goto done;
+ }
+ if (flags & JAIL_USE_DESC) {
+ /* Get the jail from its descriptor. */
+ error = jaildesc_find(td, jfd_in, &desc_in, &pr, NULL);
+ if (error) {
+ vfs_opterror(opts, error == ENOENT
+ ? "descriptor to dead jail"
+ : "not a jail descriptor");
+ goto done;
+ }
+ drflags |= PD_DEREF;
+ error = vaccess(VREG, desc_in->jd_mode, desc_in->jd_uid,
+ desc_in->jd_gid, VREAD, td->td_ucred);
+ JAILDESC_UNLOCK(desc_in);
+ if (error != 0)
+ goto done;
+ mtx_lock(&pr->pr_mtx);
+ drflags |= PD_LOCKED;
+ if (!(prison_isalive(pr) || (flags & JAIL_DYING))) {
+ error = ENOENT;
+ vfs_opterror(opts, "jail %d is dying",
+ pr->pr_id);
+ goto done;
+ }
+ goto found_prison;
+ }
+ if (flags & JAIL_AT_DESC) {
+ /* Look up jails based on the descriptor's prison. */
+ prison_free(mypr);
+ error = jaildesc_find(td, jfd_in, &desc_in, &mypr,
+ NULL);
+ if (error != 0) {
+ vfs_opterror(opts, error == ENOENT
+ ? "descriptor to dead jail"
+ : "not a jail descriptor");
+ goto done;
+ }
+ error = vaccess(VREG, desc_in->jd_mode, desc_in->jd_uid,
+ desc_in->jd_gid, VEXEC, td->td_ucred);
+ JAILDESC_UNLOCK(desc_in);
+ if (error != 0)
+ goto done;
+ }
+ if (flags & (JAIL_GET_DESC | JAIL_OWN_DESC)) {
+ /* Allocate a jail descriptor to return later. */
+ error = jaildesc_alloc(td, &jfp_out, &jfd_out,
+ flags & JAIL_OWN_DESC);
+ if (error)
+ goto done;
+ }
+ } else
+ goto done;
+
error = vfs_copyopt(opts, "lastjid", &jid, sizeof(jid));
if (error == 0) {
TAILQ_FOREACH(pr, &allprison, pr_list) {
@@ -2421,9 +2665,17 @@ kern_jail_get(struct thread *td, struct uio *optuio, int flags)
found_prison:
/* Get the parameters of the prison. */
- prison_hold(pr);
- drflags |= PD_DEREF;
+ if (!(drflags & PD_DEREF)) {
+ prison_hold(pr);
+ drflags |= PD_DEREF;
+ }
td->td_retval[0] = pr->pr_id;
+ if (jfd_out >= 0) {
+ error = vfs_setopt(opts, "desc", &jfd_out, sizeof(jfd_out));
+ if (error != 0 && error != ENOENT)
+ goto done;
+ jaildesc_set_prison(jfp_out, pr);
+ }
error = vfs_setopt(opts, "jid", &pr->pr_id, sizeof(pr->pr_id));
if (error != 0 && error != ENOENT)
goto done;
@@ -2603,6 +2855,13 @@ kern_jail_get(struct thread *td, struct uio *optuio, int flags)
prison_deref(pr, drflags);
else if (drflags & PD_LIST_SLOCKED)
sx_sunlock(&allprison_lock);
+ else if (drflags & PD_LIST_XLOCKED)
+ sx_xunlock(&allprison_lock);
+ /* Clean up other resources. */
+ if (jfp_out != NULL)
+ (void)fdrop(jfp_out, td);
+ if (error && jfd_out >= 0)
+ (void)kern_close(td, jfd_out);
if (error && errmsg_pos >= 0) {
/* Write the error message back to userspace. */
vfs_getopt(opts, "errmsg", (void **)&errmsg, &errmsg_len);
@@ -2619,6 +2878,7 @@ kern_jail_get(struct thread *td, struct uio *optuio, int flags)
}
}
vfs_freeopts(opts);
+ prison_free(mypr);
return (error);
}
@@ -2643,14 +2903,63 @@ sys_jail_remove(struct thread *td, struct jail_remove_args *uap)
sx_xunlock(&allprison_lock);
return (EINVAL);
}
+ prison_hold(pr);
+ prison_remove(pr);
+ return (0);
+}
+
+/*
+ * struct jail_remove_jd_args {
+ * int fd;
+ * };
+ */
+int
+sys_jail_remove_jd(struct thread *td, struct jail_remove_jd_args *uap)
+{
+ struct jaildesc *jd;
+ struct prison *pr;
+ struct ucred *jdcred;
+ int error;
+
+ error = jaildesc_find(td, uap->fd, &jd, &pr, &jdcred);
+ if (error)
+ return (error);
+ /*
+ * Check file permissions using the current credentials, and
+ * operation permissions using the descriptor's credentials.
+ */
+ error = vaccess(VREG, jd->jd_mode, jd->jd_uid, jd->jd_gid, VWRITE,
+ td->td_ucred);
+ JAILDESC_UNLOCK(jd);
+ if (error == 0)
+ error = priv_check_cred(jdcred, PRIV_JAIL_REMOVE);
+ crfree(jdcred);
+ if (error) {
+ prison_free(pr);
+ return (error);
+ }
+ sx_xlock(&allprison_lock);
+ mtx_lock(&pr->pr_mtx);
+ prison_remove(pr);
+ return (0);
+}
+
+/*
+ * Begin the removal process for a prison. The allprison lock should
+ * be held exclusively, and the prison should be both locked and held.
+ */
+void
+prison_remove(struct prison *pr)
+{
+ sx_assert(&allprison_lock, SA_XLOCKED);
+ mtx_assert(&pr->pr_mtx, MA_OWNED);
if (!prison_isalive(pr)) {
/* Silently ignore already-dying prisons. */
mtx_unlock(&pr->pr_mtx);
sx_xunlock(&allprison_lock);
- return (0);
+ return;
}
- prison_deref(pr, PD_KILL | PD_LOCKED | PD_LIST_XLOCKED);
- return (0);
+ prison_deref(pr, PD_KILL | PD_DEREF | PD_LOCKED | PD_LIST_XLOCKED);
}
/*
@@ -2685,6 +2994,53 @@ sys_jail_attach(struct thread *td, struct jail_attach_args *uap)
return (do_jail_attach(td, pr, PD_LOCKED | PD_LIST_SLOCKED));
}
+/*
+ * struct jail_attach_jd_args {
+ * int fd;
+ * };
+ */
+int
+sys_jail_attach_jd(struct thread *td, struct jail_attach_jd_args *uap)
+{
+ struct jaildesc *jd;
+ struct prison *pr;
+ struct ucred *jdcred;
+ int drflags, error;
+
+ sx_slock(&allprison_lock);
+ drflags = PD_LIST_SLOCKED;
+ error = jaildesc_find(td, uap->fd, &jd, &pr, &jdcred);
+ if (error)
+ goto fail;
+ drflags |= PD_DEREF;
+ /*
+ * Check file permissions using the current credentials, and
+ * operation permissions using the descriptor's credentials.
+ */
+ error = vaccess(VREG, jd->jd_mode, jd->jd_uid, jd->jd_gid, VEXEC,
+ td->td_ucred);
+ JAILDESC_UNLOCK(jd);
+ if (error == 0)
+ error = priv_check_cred(jdcred, PRIV_JAIL_ATTACH);
+ crfree(jdcred);
+ if (error)
+ goto fail;
+ mtx_lock(&pr->pr_mtx);
+ drflags |= PD_LOCKED;
+
+ /* Do not allow a process to attach to a prison that is not alive. */
+ if (!prison_isalive(pr)) {
+ error = EINVAL;
+ goto fail;
+ }
+
+ return (do_jail_attach(td, pr, drflags));
+
+ fail:
+ prison_deref(pr, drflags);
+ return (error);
+}
+
static int
do_jail_attach(struct thread *td, struct prison *pr, int drflags)
{
@@ -2703,9 +3059,12 @@ do_jail_attach(struct thread *td, struct prison *pr, int drflags)
* a process root from one prison, but attached to the jail
* of another.
*/
- prison_hold(pr);
+ if (!(drflags & PD_DEREF)) {
+ prison_hold(pr);
+ drflags |= PD_DEREF;
+ }
refcount_acquire(&pr->pr_uref);
- drflags |= PD_DEREF | PD_DEUREF;
+ drflags |= PD_DEUREF;
mtx_unlock(&pr->pr_mtx);
drflags &= ~PD_LOCKED;
@@ -2755,6 +3114,7 @@ do_jail_attach(struct thread *td, struct prison *pr, int drflags)
prison_proc_relink(oldcred->cr_prison, pr, p);
prison_deref(oldcred->cr_prison, drflags);
crfree(oldcred);
+ prison_knote(pr, NOTE_JAIL_ATTACH | td->td_proc->p_pid);
/*
* If the prison was killed while changing credentials, die along
@@ -3182,9 +3542,10 @@ prison_deref(struct prison *pr, int flags)
refcount_load(&prison0.pr_uref) > 0,
("prison0 pr_uref=0"));
pr->pr_state = PRISON_STATE_DYING;
+ prison_cleanup_locked(pr);
mtx_unlock(&pr->pr_mtx);
flags &= ~PD_LOCKED;
- prison_cleanup(pr);
+ prison_cleanup_unlocked(pr);
}
}
}
@@ -3327,8 +3688,9 @@ prison_deref_kill(struct prison *pr, struct prisonlist *freeprison)
}
if (!(cpr->pr_flags & PR_REMOVE))
continue;
- prison_cleanup(cpr);
+ prison_cleanup_unlocked(cpr);
mtx_lock(&cpr->pr_mtx);
+ prison_cleanup_locked(cpr);
cpr->pr_flags &= ~PR_REMOVE;
if (cpr->pr_flags & PR_PERSIST) {
cpr->pr_flags &= ~PR_PERSIST;
@@ -3363,8 +3725,9 @@ prison_deref_kill(struct prison *pr, struct prisonlist *freeprison)
if (rpr != NULL)
LIST_REMOVE(rpr, pr_sibling);
- prison_cleanup(pr);
+ prison_cleanup_unlocked(pr);
mtx_lock(&pr->pr_mtx);
+ prison_cleanup_locked(pr);
if (pr->pr_flags & PR_PERSIST) {
pr->pr_flags &= ~PR_PERSIST;
prison_proc_free_not_last(pr);
@@ -3411,10 +3774,22 @@ prison_lock_xlock(struct prison *pr, int flags)
/*
* Release a prison's resources when it starts dying (when the last user
- * reference is dropped, or when it is killed).
+ * reference is dropped, or when it is killed). Two functions are called,
+ * for work that requires a locked prison or an unlocked one.
*/
static void
-prison_cleanup(struct prison *pr)
+prison_cleanup_locked(struct prison *pr)
+{
+ sx_assert(&allprison_lock, SA_XLOCKED);
+ mtx_assert(&pr->pr_mtx, MA_OWNED);
+ prison_knote(pr, NOTE_JAIL_REMOVE);
+ knlist_detach(pr->pr_klist);
+ jaildesc_prison_cleanup(pr);
+ pr->pr_klist = NULL;
+}
+
+static void
+prison_cleanup_unlocked(struct prison *pr)
{
sx_assert(&allprison_lock, SA_XLOCKED);
mtx_assert(&pr->pr_mtx, MA_NOTOWNED);
@@ -4616,6 +4991,7 @@ sysctl_jail_param(SYSCTL_HANDLER_ARGS)
* jail creation time but cannot be changed in an existing jail.
*/
SYSCTL_JAIL_PARAM(, jid, CTLTYPE_INT | CTLFLAG_RDTUN, "I", "Jail ID");
+SYSCTL_JAIL_PARAM(, desc, CTLTYPE_INT | CTLFLAG_RW, "I", "Jail descriptor");
SYSCTL_JAIL_PARAM(, parent, CTLTYPE_INT | CTLFLAG_RD, "I", "Jail parent ID");
SYSCTL_JAIL_PARAM_STRING(, name, CTLFLAG_RW, MAXHOSTNAMELEN, "Jail name");
SYSCTL_JAIL_PARAM_STRING(, path, CTLFLAG_RDTUN, MAXPATHLEN, "Jail root path");
@@ -5039,6 +5415,22 @@ prison_racct_detach(struct prison *pr)
}
#endif /* RACCT */
+/*
+ * Submit a knote for a prison, locking if necessary.
+ */
+static void
+prison_knote(struct prison *pr, long hint)
+{
+ int locked;
+
+ locked = mtx_owned(&pr->pr_mtx);
+ if (!locked)
+ mtx_lock(&pr->pr_mtx);
+ KNOTE_LOCKED(pr->pr_klist, hint);
+ if (!locked)
+ mtx_unlock(&pr->pr_mtx);
+}
+
#ifdef DDB
static void
diff --git a/sys/kern/kern_jaildesc.c b/sys/kern/kern_jaildesc.c
new file mode 100644
index 000000000000..e00ec9a4bfff
--- /dev/null
+++ b/sys/kern/kern_jaildesc.c
@@ -0,0 +1,337 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2025 James Gritton.
+ * 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.
+ */
+
+#include <sys/param.h>
+#include <sys/fcntl.h>
+#include <sys/file.h>
+#include <sys/filedesc.h>
+#include <sys/kernel.h>
+#include <sys/jail.h>
+#include <sys/jaildesc.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/mutex.h>
+#include <sys/priv.h>
+#include <sys/stat.h>
+#include <sys/sysproto.h>
+#include <sys/systm.h>
+#include <sys/ucred.h>
+#include <sys/vnode.h>
+
+MALLOC_DEFINE(M_JAILDESC, "jaildesc", "jail descriptors");
+
+static fo_stat_t jaildesc_stat;
+static fo_close_t jaildesc_close;
+static fo_chmod_t jaildesc_chmod;
+static fo_chown_t jaildesc_chown;
+static fo_fill_kinfo_t jaildesc_fill_kinfo;
+static fo_cmp_t jaildesc_cmp;
+
+static struct fileops jaildesc_ops = {
+ .fo_read = invfo_rdwr,
+ .fo_write = invfo_rdwr,
+ .fo_truncate = invfo_truncate,
+ .fo_ioctl = invfo_ioctl,
+ .fo_poll = invfo_poll,
+ .fo_kqfilter = invfo_kqfilter,
+ .fo_stat = jaildesc_stat,
+ .fo_close = jaildesc_close,
+ .fo_chmod = jaildesc_chmod,
+ .fo_chown = jaildesc_chown,
+ .fo_sendfile = invfo_sendfile,
+ .fo_fill_kinfo = jaildesc_fill_kinfo,
+ .fo_cmp = jaildesc_cmp,
+ .fo_flags = DFLAG_PASSABLE,
+};
+
+/*
+ * Given a jail descriptor number, return the jaildesc, its prison,
+ * and its credential. The jaildesc will be returned locked, and
+ * prison and the credential will be returned held.
+ */
+int
+jaildesc_find(struct thread *td, int fd, struct jaildesc **jdp,
+ struct prison **prp, struct ucred **ucredp)
+{
+ struct file *fp;
+ struct jaildesc *jd;
+ struct prison *pr;
+ int error;
+
+ error = fget(td, fd, &cap_no_rights, &fp);
+ if (error != 0)
+ return (error);
+ if (fp->f_type != DTYPE_JAILDESC) {
+ error = EBADF;
+ goto out;
+ }
+ jd = fp->f_data;
+ JAILDESC_LOCK(jd);
+ pr = jd->jd_prison;
+ if (pr == NULL || !prison_isvalid(pr)) {
+ error = ENOENT;
+ JAILDESC_UNLOCK(jd);
+ goto out;
+ }
+ prison_hold(pr);
+ *prp = pr;
+ if (jdp != NULL)
+ *jdp = jd;
+ else
+ JAILDESC_UNLOCK(jd);
+ if (ucredp != NULL)
+ *ucredp = crhold(fp->f_cred);
+ out:
+ fdrop(fp, td);
+ return (error);
+}
+
+/*
+ * Allocate a new jail decriptor, not yet associated with a prison.
+ * Return the file pointer (with a reference held) and the descriptor
+ * number.
+ */
+int
+jaildesc_alloc(struct thread *td, struct file **fpp, int *fdp, int owning)
+{
+ struct file *fp;
+ struct jaildesc *jd;
+ int error;
+ mode_t mode;
+
+ if (owning) {
+ error = priv_check(td, PRIV_JAIL_REMOVE);
+ if (error != 0)
+ return (error);
+ mode = S_ISTXT;
+ } else
+ mode = 0;
+ jd = malloc(sizeof(*jd), M_JAILDESC, M_WAITOK | M_ZERO);
+ error = falloc_caps(td, &fp, fdp, 0, NULL);
+ finit(fp, priv_check_cred(fp->f_cred, PRIV_JAIL_SET) == 0
+ ? FREAD | FWRITE : FREAD, DTYPE_JAILDESC, jd, &jaildesc_ops);
+ if (error != 0) {
+ free(jd, M_JAILDESC);
+ return (error);
+ }
+ JAILDESC_LOCK_INIT(jd);
+ jd->jd_uid = fp->f_cred->cr_uid;
+ jd->jd_gid = fp->f_cred->cr_gid;
+ jd->jd_mode = S_IFREG | S_IRUSR | S_IRGRP | S_IROTH | mode
+ | (priv_check(td, PRIV_JAIL_SET) == 0 ? S_IWUSR | S_IXUSR : 0)
+ | (priv_check(td, PRIV_JAIL_ATTACH) == 0 ? S_IXUSR : 0);
+ *fpp = fp;
+ return (0);
+}
+
+/*
+ * Assocate a jail descriptor with its prison.
+ */
+void
+jaildesc_set_prison(struct file *fp, struct prison *pr)
+{
+ struct jaildesc *jd;
+
+ mtx_assert(&pr->pr_mtx, MA_OWNED);
+ jd = fp->f_data;
+ JAILDESC_LOCK(jd);
+ jd->jd_prison = pr;
+ LIST_INSERT_HEAD(&pr->pr_descs, jd, jd_list);
+ prison_hold(pr);
+ JAILDESC_UNLOCK(jd);
+}
+
+/*
+ * Detach the all jail descriptors from a prison.
+ */
+void
+jaildesc_prison_cleanup(struct prison *pr)
+{
+ struct jaildesc *jd;
+
+ mtx_assert(&pr->pr_mtx, MA_OWNED);
+ while ((jd = LIST_FIRST(&pr->pr_descs))) {
+ JAILDESC_LOCK(jd);
+ LIST_REMOVE(jd, jd_list);
+ jd->jd_prison = NULL;
+ JAILDESC_UNLOCK(jd);
+ prison_free(pr);
+ }
+}
+
+static int
+jaildesc_close(struct file *fp, struct thread *td)
+{
+ struct jaildesc *jd;
+ struct prison *pr;
+
+ jd = fp->f_data;
+ fp->f_data = NULL;
+ if (jd != NULL) {
+ JAILDESC_LOCK(jd);
+ pr = jd->jd_prison;
+ if (pr != NULL) {
+ /*
+ * Free or remove the associated prison.
+ * This requires a second check after re-
+ * ordering locks. This jaildesc can remain
+ * unlocked once we have a prison reference,
+ * because that prison is the only place that
+ * still points back to it.
+ */
+ prison_hold(pr);
+ JAILDESC_UNLOCK(jd);
+ if (jd->jd_mode & S_ISTXT) {
+ sx_xlock(&allprison_lock);
+ prison_lock(pr);
+ if (jd->jd_prison != NULL) {
+ /*
+ * Unlink the prison, but don't free
+ * it; that will be done as part of
+ * of prison_remove.
+ */
+ LIST_REMOVE(jd, jd_list);
+ prison_remove(pr);
+ } else {
+ prison_unlock(pr);
+ sx_xunlock(&allprison_lock);
+ }
+ } else {
+ prison_lock(pr);
+ if (jd->jd_prison != NULL) {
+ LIST_REMOVE(jd, jd_list);
+ prison_free(pr);
+ }
+ prison_unlock(pr);
+ }
+ prison_free(pr);
+ }
+ JAILDESC_LOCK_DESTROY(jd);
+ free(jd, M_JAILDESC);
+ }
+ finit(fp, 0, DTYPE_NONE, NULL, &badfileops);
+ return (0);
+}
+
+static int
+jaildesc_stat(struct file *fp, struct stat *sb, struct ucred *active_cred)
+{
+ struct jaildesc *jd;
+
+ bzero(sb, sizeof(struct stat));
+ jd = fp->f_data;
+ JAILDESC_LOCK(jd);
+ if (jd->jd_prison != NULL) {
+ sb->st_ino = jd->jd_prison ? jd->jd_prison->pr_id : 0;
+ sb->st_uid = jd->jd_uid;
+ sb->st_gid = jd->jd_gid;
+ sb->st_mode = jd->jd_mode;
+ } else
+ sb->st_mode = S_IFREG;
+ JAILDESC_UNLOCK(jd);
+ return (0);
+}
+
+static int
+jaildesc_chmod(struct file *fp, mode_t mode, struct ucred *active_cred,
+ struct thread *td)
+{
+ struct jaildesc *jd;
+ int error;
+
+ /* Reject permissions that the creator doesn't have. */
+ if (((mode & (S_IWUSR | S_IWGRP | S_IWOTH))
+ && priv_check_cred(fp->f_cred, PRIV_JAIL_SET) != 0)
+ || ((mode & (S_IXUSR | S_IXGRP | S_IXOTH))
+ && priv_check_cred(fp->f_cred, PRIV_JAIL_ATTACH) != 0
+ && priv_check_cred(fp->f_cred, PRIV_JAIL_SET) != 0)
+ || ((mode & S_ISTXT)
+ && priv_check_cred(fp->f_cred, PRIV_JAIL_REMOVE) != 0))
+ return (EPERM);
+ if (mode & (S_ISUID | S_ISGID))
+ return (EINVAL);
+ jd = fp->f_data;
+ JAILDESC_LOCK(jd);
+ error = vaccess(VREG, jd->jd_mode, jd->jd_uid, jd->jd_gid, VADMIN,
+ active_cred);
+ if (error == 0)
+ jd->jd_mode = S_IFREG | (mode & ALLPERMS);
+ JAILDESC_UNLOCK(jd);
+ return (error);
+}
+
+static int
+jaildesc_chown(struct file *fp, uid_t uid, gid_t gid, struct ucred *active_cred,
+ struct thread *td)
+{
+ struct jaildesc *jd;
+ int error;
+
+ error = 0;
+ jd = fp->f_data;
+ JAILDESC_LOCK(jd);
+ if (uid == (uid_t)-1)
+ uid = jd->jd_uid;
+ if (gid == (gid_t)-1)
+ gid = jd->jd_gid;
+ if ((uid != jd->jd_uid && uid != active_cred->cr_uid) ||
+ (gid != jd->jd_gid && !groupmember(gid, active_cred)))
+ error = priv_check_cred(active_cred, PRIV_VFS_CHOWN);
+ if (error == 0) {
+ jd->jd_uid = uid;
+ jd->jd_gid = gid;
+ }
+ JAILDESC_UNLOCK(jd);
+ return (error);
+}
+
+static int
+jaildesc_fill_kinfo(struct file *fp, struct kinfo_file *kif,
+ struct filedesc *fdp)
+{
+ return (EINVAL);
+}
+
+static int
+jaildesc_cmp(struct file *fp1, struct file *fp2, struct thread *td)
+{
+ struct jaildesc *jd1, *jd2;
+ int jid1, jid2;
+
+ if (fp2->f_type != DTYPE_JAILDESC)
+ return (3);
+ jd1 = fp1->f_data;
+ JAILDESC_LOCK(jd1);
+ jid1 = jd1->jd_prison ? (uintptr_t)jd1->jd_prison->pr_id : 0;
+ JAILDESC_UNLOCK(jd1);
+ jd2 = fp2->f_data;
+ JAILDESC_LOCK(jd2);
+ jid2 = jd2->jd_prison ? (uintptr_t)jd2->jd_prison->pr_id : 0;
+ JAILDESC_UNLOCK(jd2);
+ return (kcmp_cmp(jid1, jid2));
+}
diff --git a/sys/kern/kern_thread.c b/sys/kern/kern_thread.c
index 50b040132396..3180c66cb42b 100644
--- a/sys/kern/kern_thread.c
+++ b/sys/kern/kern_thread.c
@@ -1694,8 +1694,10 @@ thread_single_end(struct proc *p, int mode)
thread_unlock(td);
}
}
- KASSERT(mode != SINGLE_BOUNDARY || p->p_boundary_count == 0,
- ("inconsistent boundary count %d", p->p_boundary_count));
+ KASSERT(mode != SINGLE_BOUNDARY || P_SHOULDSTOP(p) ||
+ p->p_boundary_count == 0,
+ ("pid %d proc %p flags %#x inconsistent boundary count %d",
+ p->p_pid, p, p->p_flag, p->p_boundary_count));
PROC_SUNLOCK(p);
wakeup(&p->p_flag);
}
diff --git a/sys/kern/subr_witness.c b/sys/kern/subr_witness.c
index ab47b6ad29a3..a65c3ca128d9 100644
--- a/sys/kern/subr_witness.c
+++ b/sys/kern/subr_witness.c
@@ -57,7 +57,7 @@
* b : public affirmation by word or example of usually
* religious faith or conviction <the heroic witness to divine
* life -- Pilot>
- * 6 capitalized : a member of the Jehovah's Witnesses
+ * 6 capitalized : a member of the Jehovah's Witnesses
*/
/*
@@ -131,7 +131,7 @@
#define LI_SLEEPABLE 0x00040000 /* Lock may be held while sleeping. */
#ifndef WITNESS_COUNT
-#define WITNESS_COUNT 1536
+#define WITNESS_COUNT 1536
#endif
#define WITNESS_HASH_SIZE 251 /* Prime, gives load factor < 2 */
#define WITNESS_PENDLIST (512 + (MAXCPU * 4))
@@ -158,20 +158,18 @@
* These flags go in the witness relationship matrix and describe the
* relationship between any two struct witness objects.
*/
-#define WITNESS_UNRELATED 0x00 /* No lock order relation. */
-#define WITNESS_PARENT 0x01 /* Parent, aka direct ancestor. */
-#define WITNESS_ANCESTOR 0x02 /* Direct or indirect ancestor. */
-#define WITNESS_CHILD 0x04 /* Child, aka direct descendant. */
-#define WITNESS_DESCENDANT 0x08 /* Direct or indirect descendant. */
-#define WITNESS_ANCESTOR_MASK (WITNESS_PARENT | WITNESS_ANCESTOR)
-#define WITNESS_DESCENDANT_MASK (WITNESS_CHILD | WITNESS_DESCENDANT)
-#define WITNESS_RELATED_MASK \
- (WITNESS_ANCESTOR_MASK | WITNESS_DESCENDANT_MASK)
-#define WITNESS_REVERSAL 0x10 /* A lock order reversal has been
- * observed. */
-#define WITNESS_RESERVED1 0x20 /* Unused flag, reserved. */
-#define WITNESS_RESERVED2 0x40 /* Unused flag, reserved. */
-#define WITNESS_LOCK_ORDER_KNOWN 0x80 /* This lock order is known. */
+#define WITNESS_UNRELATED 0x00 /* No lock order relation. */
+#define WITNESS_PARENT 0x01 /* Parent, aka direct ancestor. */
+#define WITNESS_ANCESTOR 0x02 /* Direct or indirect ancestor. */
+#define WITNESS_CHILD 0x04 /* Child, aka direct descendant. */
+#define WITNESS_DESCENDANT 0x08 /* Direct or indirect descendant. */
+#define WITNESS_ANCESTOR_MASK (WITNESS_PARENT | WITNESS_ANCESTOR)
+#define WITNESS_DESCENDANT_MASK (WITNESS_CHILD | WITNESS_DESCENDANT)
+#define WITNESS_RELATED_MASK (WITNESS_ANCESTOR_MASK | WITNESS_DESCENDANT_MASK)
+#define WITNESS_REVERSAL 0x10 /* A lock order reversal has been observed. */
+#define WITNESS_RESERVED1 0x20 /* Unused flag, reserved. */
+#define WITNESS_RESERVED2 0x40 /* Unused flag, reserved. */
+#define WITNESS_LOCK_ORDER_KNOWN 0x80 /* This lock order is known. */
/* Descendant to ancestor flags */
#define WITNESS_DTOA(x) (((x) & WITNESS_RELATED_MASK) >> 2)
@@ -218,20 +216,18 @@ struct lock_list_entry {
* (for example, "vnode interlock").
*/
struct witness {
- char w_name[MAX_W_NAME];
- uint32_t w_index; /* Index in the relationship matrix */
+ char w_name[MAX_W_NAME];
+ uint32_t w_index; /* Index in the relationship matrix */
struct lock_class *w_class;
- STAILQ_ENTRY(witness) w_list; /* List of all witnesses. */
- STAILQ_ENTRY(witness) w_typelist; /* Witnesses of a type. */
- struct witness *w_hash_next; /* Linked list in hash buckets. */
- const char *w_file; /* File where last acquired */
- uint32_t w_line; /* Line where last acquired */
- uint32_t w_refcount;
- uint16_t w_num_ancestors; /* direct/indirect
- * ancestor count */
- uint16_t w_num_descendants; /* direct/indirect
- * descendant count */
- int16_t w_ddb_level;
+ STAILQ_ENTRY(witness) w_list; /* List of all witnesses. */
+ STAILQ_ENTRY(witness) w_typelist; /* Witnesses of a type. */
+ struct witness *w_hash_next; /* Linked list in hash buckets. */
+ const char *w_file; /* File where last acquired */
+ uint32_t w_line; /* Line where last acquired */
+ uint32_t w_refcount;
+ uint16_t w_num_ancestors; /* direct/indirect ancestor count */
+ uint16_t w_num_descendants; /* direct/indirect descendant count */
+ int16_t w_ddb_level;
unsigned w_displayed:1;
unsigned w_reversed:1;
};
@@ -265,7 +261,7 @@ struct witness_lock_order_data {
/*
* The witness lock order data hash table. Keys are witness index tuples
* (struct witness_lock_order_key), elements are lock order data objects
- * (struct witness_lock_order_data).
+ * (struct witness_lock_order_data).
*/
struct witness_lock_order_hash {
struct witness_lock_order_data *wloh_array[WITNESS_LO_HASH_SIZE];
@@ -295,7 +291,6 @@ struct witness_order_list_entry {
static __inline int
witness_lock_type_equal(struct witness *w1, struct witness *w2)
{
-
return ((w1->w_class->lc_flags & (LC_SLEEPLOCK | LC_SPINLOCK)) ==
(w2->w_class->lc_flags & (LC_SLEEPLOCK | LC_SPINLOCK)));
}
@@ -304,7 +299,6 @@ static __inline int
witness_lock_order_key_equal(const struct witness_lock_order_key *a,
const struct witness_lock_order_key *b)
{
-
return (a->from == b->from && a->to == b->to);
}
@@ -415,7 +409,7 @@ SYSCTL_INT(_debug_witness, OID_AUTO, skipspin, CTLFLAG_RDTUN, &witness_skipspin,
int badstack_sbuf_size;
int witness_count = WITNESS_COUNT;
-SYSCTL_INT(_debug_witness, OID_AUTO, witness_count, CTLFLAG_RDTUN,
+SYSCTL_INT(_debug_witness, OID_AUTO, witness_count, CTLFLAG_RDTUN,
&witness_count, 0, "");
/*
@@ -760,7 +754,6 @@ static int witness_spin_warn = 0;
static const char *
fixup_filename(const char *file)
{
-
if (file == NULL)
return (NULL);
while (strncmp(file, "../", 3) == 0)
@@ -835,7 +828,7 @@ witness_startup(void *mem)
w_free_cnt--;
for (i = 0; i < witness_count; i++) {
- memset(w_rmatrix[i], 0, sizeof(*w_rmatrix[i]) *
+ memset(w_rmatrix[i], 0, sizeof(*w_rmatrix[i]) *
(witness_count + 1));
}
@@ -989,16 +982,16 @@ witness_ddb_display_descendants(int(*prnt)(const char *fmt, ...),
{
int i;
- for (i = 0; i < indent; i++)
- prnt(" ");
+ for (i = 0; i < indent; i++)
+ prnt(" ");
prnt("%s (type: %s, depth: %d, active refs: %d)",
w->w_name, w->w_class->lc_name,
w->w_ddb_level, w->w_refcount);
- if (w->w_displayed) {
- prnt(" -- (already displayed)\n");
- return;
- }
- w->w_displayed = 1;
+ if (w->w_displayed) {
+ prnt(" -- (already displayed)\n");
+ return;
+ }
+ w->w_displayed = 1;
if (w->w_file != NULL && w->w_line != 0)
prnt(" -- last acquired @ %s:%d\n", fixup_filename(w->w_file),
w->w_line);
@@ -1079,7 +1072,6 @@ witness_ddb_display(int(*prnt)(const char *fmt, ...))
int
witness_defineorder(struct lock_object *lock1, struct lock_object *lock2)
{
-
if (witness_watch == -1 || KERNEL_PANICKED())
return (0);
@@ -1257,7 +1249,7 @@ witness_checkorder(struct lock_object *lock, int flags, const char *file,
w->w_reversed = 1;
mtx_unlock_spin(&w_mtx);
witness_output(
- "acquiring duplicate lock of same type: \"%s\"\n",
+ "acquiring duplicate lock of same type: \"%s\"\n",
w->w_name);
witness_output(" 1st %s @ %s:%d\n", plock->li_lock->lo_name,
fixup_filename(plock->li_file), plock->li_line);
@@ -1743,7 +1735,7 @@ found:
/*
* In order to reduce contention on w_mtx, we want to keep always an
- * head object into lists so that frequent allocation from the
+ * head object into lists so that frequent allocation from the
* free witness pool (and subsequent locking) is avoided.
* In order to maintain the current code simple, when the head
* object is totally unloaded it means also that we do not have
@@ -1781,7 +1773,7 @@ witness_thread_exit(struct thread *td)
n++;
witness_list_lock(&lle->ll_children[i],
witness_output);
-
+
}
kassert_panic(
"Thread %p cannot exit while holding sleeplocks\n", td);
@@ -1948,7 +1940,6 @@ found:
static void
depart(struct witness *w)
{
-
MPASS(w->w_refcount == 0);
if (w->w_class->lc_flags & LC_SLEEPLOCK) {
w_sleep_cnt--;
@@ -1999,18 +1990,18 @@ adopt(struct witness *parent, struct witness *child)
child->w_num_ancestors++;
}
- /*
- * Find each ancestor of 'pi'. Note that 'pi' itself is counted as
+ /*
+ * Find each ancestor of 'pi'. Note that 'pi' itself is counted as
* an ancestor of 'pi' during this loop.
*/
for (i = 1; i <= w_max_used_index; i++) {
- if ((w_rmatrix[i][pi] & WITNESS_ANCESTOR_MASK) == 0 &&
+ if ((w_rmatrix[i][pi] & WITNESS_ANCESTOR_MASK) == 0 &&
(i != pi))
continue;
/* Find each descendant of 'i' and mark it as a descendant. */
for (j = 1; j <= w_max_used_index; j++) {
- /*
+ /*
* Skip children that are already marked as
* descendants of 'i'.
*/
@@ -2021,7 +2012,7 @@ adopt(struct witness *parent, struct witness *child)
* We are only interested in descendants of 'ci'. Note
* that 'ci' itself is counted as a descendant of 'ci'.
*/
- if ((w_rmatrix[ci][j] & WITNESS_ANCESTOR_MASK) == 0 &&
+ if ((w_rmatrix[ci][j] & WITNESS_ANCESTOR_MASK) == 0 &&
(j != ci))
continue;
w_rmatrix[i][j] |= WITNESS_ANCESTOR;
@@ -2029,16 +2020,16 @@ adopt(struct witness *parent, struct witness *child)
w_data[i].w_num_descendants++;
w_data[j].w_num_ancestors++;
- /*
+ /*
* Make sure we aren't marking a node as both an
- * ancestor and descendant. We should have caught
+ * ancestor and descendant. We should have caught
* this as a lock order reversal earlier.
*/
if ((w_rmatrix[i][j] & WITNESS_ANCESTOR_MASK) &&
(w_rmatrix[i][j] & WITNESS_DESCENDANT_MASK)) {
printf("witness rmatrix paradox! [%d][%d]=%d "
"both ancestor and descendant\n",
- i, j, w_rmatrix[i][j]);
+ i, j, w_rmatrix[i][j]);
kdb_backtrace();
printf("Witness disabled.\n");
witness_watch = -1;
@@ -2047,7 +2038,7 @@ adopt(struct witness *parent, struct witness *child)
(w_rmatrix[j][i] & WITNESS_DESCENDANT_MASK)) {
printf("witness rmatrix paradox! [%d][%d]=%d "
"both ancestor and descendant\n",
- j, i, w_rmatrix[j][i]);
+ j, i, w_rmatrix[j][i]);
kdb_backtrace();
printf("Witness disabled.\n");
witness_watch = -1;
@@ -2124,7 +2115,6 @@ _isitmyx(struct witness *w1, struct witness *w2, int rmask, const char *fname)
static int
isitmychild(struct witness *parent, struct witness *child)
{
-
return (_isitmyx(parent, child, WITNESS_PARENT, __func__));
}
@@ -2134,7 +2124,6 @@ isitmychild(struct witness *parent, struct witness *child)
static int
isitmydescendant(struct witness *ancestor, struct witness *descendant)
{
-
return (_isitmyx(ancestor, descendant, WITNESS_ANCESTOR_MASK,
__func__));
}
@@ -2182,7 +2171,7 @@ witness_get(void)
STAILQ_REMOVE_HEAD(&w_free, w_list);
w_free_cnt--;
index = w->w_index;
- MPASS(index > 0 && index == w_max_used_index+1 &&
+ MPASS(index > 0 && index == w_max_used_index + 1 &&
index < witness_count);
bzero(w, sizeof(*w));
w->w_index = index;
@@ -2194,7 +2183,6 @@ witness_get(void)
static void
witness_free(struct witness *w)
{
-
STAILQ_INSERT_HEAD(&w_free, w, w_list);
w_free_cnt++;
}
@@ -2219,11 +2207,10 @@ witness_lock_list_get(void)
bzero(lle, sizeof(*lle));
return (lle);
}
-
+
static void
witness_lock_list_free(struct lock_list_entry *lle)
{
-
mtx_lock_spin(&w_mtx);
lle->ll_next = w_lock_list_free;
w_lock_list_free = lle;
@@ -2297,7 +2284,6 @@ witness_voutput(const char *fmt, va_list ap)
static int
witness_thread_has_locks(struct thread *td)
{
-
if (td->td_sleeplocks == NULL)
return (0);
return (td->td_sleeplocks->ll_count != 0);
@@ -2573,14 +2559,12 @@ witness_setflag(struct lock_object *lock, int flag, int set)
void
witness_norelease(struct lock_object *lock)
{
-
witness_setflag(lock, LI_NORELEASE, 1);
}
void
witness_releaseok(struct lock_object *lock)
{
-
witness_setflag(lock, LI_NORELEASE, 0);
}
@@ -2588,7 +2572,6 @@ witness_releaseok(struct lock_object *lock)
static void
witness_ddb_list(struct thread *td)
{
-
KASSERT(witness_cold == 0, ("%s: witness_cold", __func__));
KASSERT(kdb_active, ("%s: not in the debugger", __func__));
@@ -2653,7 +2636,6 @@ DB_SHOW_ALIAS_FLAGS(alllocks, db_witness_list_all, DB_CMD_MEMSAFE);
DB_SHOW_COMMAND_FLAGS(witness, db_witness_display, DB_CMD_MEMSAFE)
{
-
witness_ddb_display(db_printf);
}
#endif
@@ -2673,9 +2655,9 @@ sbuf_print_witness_badstacks(struct sbuf *sb, size_t *oldidx)
/* Allocate and init temporary storage space. */
tmp_w1 = malloc(sizeof(struct witness), M_TEMP, M_WAITOK | M_ZERO);
tmp_w2 = malloc(sizeof(struct witness), M_TEMP, M_WAITOK | M_ZERO);
- tmp_data1 = malloc(sizeof(struct witness_lock_order_data), M_TEMP,
+ tmp_data1 = malloc(sizeof(struct witness_lock_order_data), M_TEMP,
M_WAITOK | M_ZERO);
- tmp_data2 = malloc(sizeof(struct witness_lock_order_data), M_TEMP,
+ tmp_data2 = malloc(sizeof(struct witness_lock_order_data), M_TEMP,
M_WAITOK | M_ZERO);
stack_zero(&tmp_data1->wlod_stack);
stack_zero(&tmp_data2->wlod_stack);
@@ -2750,12 +2732,12 @@ restart:
sbuf_printf(sb,
"\nLock order reversal between \"%s\"(%s) and \"%s\"(%s)!\n",
- tmp_w1->w_name, tmp_w1->w_class->lc_name,
+ tmp_w1->w_name, tmp_w1->w_class->lc_name,
tmp_w2->w_name, tmp_w2->w_class->lc_name);
if (data1) {
sbuf_printf(sb,
"Lock order \"%s\"(%s) -> \"%s\"(%s) first seen at:\n",
- tmp_w1->w_name, tmp_w1->w_class->lc_name,
+ tmp_w1->w_name, tmp_w1->w_class->lc_name,
tmp_w2->w_name, tmp_w2->w_class->lc_name);
stack_sbuf_print(sb, &tmp_data1->wlod_stack);
sbuf_putc(sb, '\n');
@@ -2763,7 +2745,7 @@ restart:
if (data2 && data2 != data1) {
sbuf_printf(sb,
"Lock order \"%s\"(%s) -> \"%s\"(%s) first seen at:\n",
- tmp_w2->w_name, tmp_w2->w_class->lc_name,
+ tmp_w2->w_name, tmp_w2->w_class->lc_name,
tmp_w1->w_name, tmp_w1->w_class->lc_name);
stack_sbuf_print(sb, &tmp_data2->wlod_stack);
sbuf_putc(sb, '\n');
@@ -2823,7 +2805,6 @@ sysctl_debug_witness_badstacks(SYSCTL_HANDLER_ARGS)
static int
sbuf_db_printf_drain(void *arg __unused, const char *data, int len)
{
-
return (db_printf("%.*s", len, data));
}
@@ -3068,7 +3049,7 @@ witness_lock_order_get(struct witness *parent, struct witness *child)
& WITNESS_LOCK_ORDER_KNOWN) == 0)
goto out;
- hash = witness_hash_djb2((const char*)&key,
+ hash = witness_hash_djb2((const char *)&key,
sizeof(key)) % w_lohash.wloh_size;
data = w_lohash.wloh_array[hash];
while (data != NULL) {
@@ -3089,7 +3070,6 @@ out:
static int
witness_lock_order_check(struct witness *parent, struct witness *child)
{
-
if (parent != child &&
w_rmatrix[parent->w_index][child->w_index]
& WITNESS_LOCK_ORDER_KNOWN &&
@@ -3115,7 +3095,7 @@ witness_lock_order_add(struct witness *parent, struct witness *child)
& WITNESS_LOCK_ORDER_KNOWN)
return (1);
- hash = witness_hash_djb2((const char*)&key,
+ hash = witness_hash_djb2((const char *)&key,
sizeof(key)) % w_lohash.wloh_size;
w_rmatrix[parent->w_index][child->w_index] |= WITNESS_LOCK_ORDER_KNOWN;
data = w_lofree;
@@ -3134,7 +3114,6 @@ witness_lock_order_add(struct witness *parent, struct witness *child)
static void
witness_increment_graph_generation(void)
{
-
if (witness_cold == 0)
mtx_assert(&w_mtx, MA_OWNED);
w_generation++;
@@ -3143,7 +3122,6 @@ witness_increment_graph_generation(void)
static int
witness_output_drain(void *arg __unused, const char *data, int len)
{
-
witness_output("%.*s", len, data);
return (len);
}
diff --git a/sys/kern/syscalls.c b/sys/kern/syscalls.c
index 4122f9261871..4cef89cd5219 100644
--- a/sys/kern/syscalls.c
+++ b/sys/kern/syscalls.c
@@ -602,4 +602,6 @@ const char *syscallnames[] = {
"inotify_rm_watch", /* 594 = inotify_rm_watch */
"getgroups", /* 595 = getgroups */
"setgroups", /* 596 = setgroups */
+ "jail_attach_jd", /* 597 = jail_attach_jd */
+ "jail_remove_jd", /* 598 = jail_remove_jd */
};
diff --git a/sys/kern/syscalls.master b/sys/kern/syscalls.master
index fa64597d14a5..911f9093824b 100644
--- a/sys/kern/syscalls.master
+++ b/sys/kern/syscalls.master
@@ -3383,5 +3383,15 @@
_In_reads_(gidsetsize) const gid_t *gidset
);
}
+597 AUE_JAIL_ATTACH STD {
+ int jail_attach_jd(
+ int fd
+ );
+ }
+598 AUE_JAIL_REMOVE STD {
+ int jail_remove_jd(
+ int fd
+ );
+ }
; vim: syntax=off
diff --git a/sys/kern/systrace_args.c b/sys/kern/systrace_args.c
index 2b1ea9eed8d4..e28fef931ea8 100644
--- a/sys/kern/systrace_args.c
+++ b/sys/kern/systrace_args.c
@@ -3500,6 +3500,20 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args)
*n_args = 2;
break;
}
+ /* jail_attach_jd */
+ case 597: {
+ struct jail_attach_jd_args *p = params;
+ iarg[a++] = p->fd; /* int */
+ *n_args = 1;
+ break;
+ }
+ /* jail_remove_jd */
+ case 598: {
+ struct jail_remove_jd_args *p = params;
+ iarg[a++] = p->fd; /* int */
+ *n_args = 1;
+ break;
+ }
default:
*n_args = 0;
break;
@@ -9367,6 +9381,26 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz)
break;
};
break;
+ /* jail_attach_jd */
+ case 597:
+ switch (ndx) {
+ case 0:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
+ /* jail_remove_jd */
+ case 598:
+ switch (ndx) {
+ case 0:
+ p = "int";
+ break;
+ default:
+ break;
+ };
+ break;
default:
break;
};
@@ -11365,6 +11399,16 @@ systrace_return_setargdesc(int sysnum, int ndx, char *desc, size_t descsz)
if (ndx == 0 || ndx == 1)
p = "int";
break;
+ /* jail_attach_jd */
+ case 597:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
+ /* jail_remove_jd */
+ case 598:
+ if (ndx == 0 || ndx == 1)
+ p = "int";
+ break;
default:
break;
};
diff --git a/sys/kern/uipc_usrreq.c b/sys/kern/uipc_usrreq.c
index 19870e989437..6138e543fae7 100644
--- a/sys/kern/uipc_usrreq.c
+++ b/sys/kern/uipc_usrreq.c
@@ -1807,9 +1807,7 @@ uipc_filt_sowrite(struct knote *kn, long hint)
kn->kn_data = uipc_stream_sbspace(&so2->so_rcv);
if (so2->so_rcv.sb_state & SBS_CANTRCVMORE) {
- /*
- * XXXGL: maybe kn->kn_flags |= EV_EOF ?
- */
+ kn->kn_flags |= EV_EOF;
return (1);
} else if (kn->kn_sfflags & NOTE_LOWAT)
return (kn->kn_data >= kn->kn_sdata);
diff --git a/sys/kern/vfs_init.c b/sys/kern/vfs_init.c
index 93ac001af8ad..ceda770cb714 100644
--- a/sys/kern/vfs_init.c
+++ b/sys/kern/vfs_init.c
@@ -399,7 +399,7 @@ vfs_register(struct vfsconf *vfc)
static int once;
struct vfsconf *tvfc;
uint32_t hashval;
- int secondpass;
+ int error, prevmaxconf, secondpass;
if (!once) {
vattr_null(&va_null);
@@ -417,6 +417,7 @@ vfs_register(struct vfsconf *vfc)
return (EEXIST);
}
+ prevmaxconf = maxvfsconf;
if (vfs_typenumhash != 0) {
/*
* Calculate a hash on vfc_name to use for vfc_typenum. Unless
@@ -509,16 +510,24 @@ vfs_register(struct vfsconf *vfc)
vfc->vfc_vfsops = &vfsops_sigdefer;
}
- if (vfc->vfc_flags & VFCF_JAIL)
- prison_add_vfs(vfc);
-
/*
* Call init function for this VFS...
*/
if ((vfc->vfc_flags & VFCF_SBDRY) != 0)
- vfc->vfc_vfsops_sd->vfs_init(vfc);
+ error = vfc->vfc_vfsops_sd->vfs_init(vfc);
else
- vfc->vfc_vfsops->vfs_init(vfc);
+ error = vfc->vfc_vfsops->vfs_init(vfc);
+
+ if (error != 0) {
+ maxvfsconf = prevmaxconf;
+ TAILQ_REMOVE(&vfsconf, vfc, vfc_list);
+ vfsconf_unlock();
+ return (error);
+ }
+
+ if ((vfc->vfc_flags & VFCF_JAIL) != 0)
+ prison_add_vfs(vfc);
+
vfsconf_unlock();
/*
diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c
index a6e38be89291..57732ddab7d9 100644
--- a/sys/kern/vfs_subr.c
+++ b/sys/kern/vfs_subr.c
@@ -2186,6 +2186,8 @@ freevnode(struct vnode *vp)
{
struct bufobj *bo;
+ ASSERT_VOP_UNLOCKED(vp, __func__);
+
/*
* The vnode has been marked for destruction, so free it.
*
@@ -2222,12 +2224,16 @@ freevnode(struct vnode *vp)
mac_vnode_destroy(vp);
#endif
if (vp->v_pollinfo != NULL) {
+ int error __diagused;
+
/*
* Use LK_NOWAIT to shut up witness about the lock. We may get
* here while having another vnode locked when trying to
* satisfy a lookup and needing to recycle.
*/
- VOP_LOCK(vp, LK_EXCLUSIVE | LK_NOWAIT);
+ error = VOP_LOCK(vp, LK_EXCLUSIVE | LK_NOWAIT);
+ VNASSERT(error == 0, vp,
+ ("freevnode: cannot lock vp %p for pollinfo destroy", vp));
destroy_vpollinfo(vp->v_pollinfo);
VOP_UNLOCK(vp);
vp->v_pollinfo = NULL;
diff --git a/sys/modules/sound/driver/hda/Makefile b/sys/modules/sound/driver/hda/Makefile
index 0eec98fc53e1..1e137dc5671c 100644
--- a/sys/modules/sound/driver/hda/Makefile
+++ b/sys/modules/sound/driver/hda/Makefile
@@ -2,7 +2,7 @@
KMOD= snd_hda
SRCS= device_if.h bus_if.h pci_if.h channel_if.h mixer_if.h hdac_if.h
-SRCS+= hdaa.c hdaa.h hdaa_patches.c hdac.c hdac_if.h hdac_if.c
-SRCS+= hdacc.c hdac_private.h hdac_reg.h hda_reg.h hdac.h
+SRCS+= hdaa.c hdaa.h hdaa_patches.c hdacc.c hdac.c hdac_if.c
+SRCS+= hdac_private.h hdac_reg.h hda_reg.h hdac.h
.include <bsd.kmod.mk>
diff --git a/sys/net/if.c b/sys/net/if.c
index 0fc30488f1e5..b6a798aa0fab 100644
--- a/sys/net/if.c
+++ b/sys/net/if.c
@@ -1101,6 +1101,7 @@ if_detach_internal(struct ifnet *ifp, bool vmove)
struct ifaddr *ifa;
int i;
struct domain *dp;
+ void *if_afdata[AF_MAX];
#ifdef VIMAGE
bool shutdown;
@@ -1224,15 +1225,30 @@ finish_vnet_shutdown:
IF_AFDATA_LOCK(ifp);
i = ifp->if_afdata_initialized;
ifp->if_afdata_initialized = 0;
+ if (i != 0) {
+ /*
+ * Defer the dom_ifdetach call.
+ */
+ _Static_assert(sizeof(if_afdata) == sizeof(ifp->if_afdata),
+ "array size mismatch");
+ memcpy(if_afdata, ifp->if_afdata, sizeof(if_afdata));
+ memset(ifp->if_afdata, 0, sizeof(ifp->if_afdata));
+ }
IF_AFDATA_UNLOCK(ifp);
if (i == 0)
return;
+ /*
+ * XXXZL: This net epoch wait is not necessary if we have done right.
+ * But if we do not, at least we can make a guarantee that threads those
+ * enter net epoch will see NULL address family dependent data,
+ * e.g. if_afdata[AF_INET6]. A clear NULL pointer derefence is much
+ * better than writing to freed memory.
+ */
+ NET_EPOCH_WAIT();
SLIST_FOREACH(dp, &domains, dom_next) {
- if (dp->dom_ifdetach && ifp->if_afdata[dp->dom_family]) {
- (*dp->dom_ifdetach)(ifp,
- ifp->if_afdata[dp->dom_family]);
- ifp->if_afdata[dp->dom_family] = NULL;
- }
+ if (dp->dom_ifdetach != NULL &&
+ if_afdata[dp->dom_family] != NULL)
+ (*dp->dom_ifdetach)(ifp, if_afdata[dp->dom_family]);
}
}
diff --git a/sys/net/if_bridge.c b/sys/net/if_bridge.c
index 66555fd1feb5..cea7f1cb5e23 100644
--- a/sys/net/if_bridge.c
+++ b/sys/net/if_bridge.c
@@ -522,11 +522,11 @@ SYSCTL_BOOL(_net_link_bridge, OID_AUTO, log_mac_flap,
"Log MAC address port flapping");
/* allow IP addresses on bridge members */
-VNET_DEFINE_STATIC(bool, member_ifaddrs) = false;
+VNET_DEFINE_STATIC(bool, member_ifaddrs) = true;
#define V_member_ifaddrs VNET(member_ifaddrs)
SYSCTL_BOOL(_net_link_bridge, OID_AUTO, member_ifaddrs,
CTLFLAG_RW | CTLFLAG_VNET, &VNET_NAME(member_ifaddrs), false,
- "Allow layer 3 addresses on bridge members");
+ "Allow layer 3 addresses on bridge members (deprecated)");
static bool
bridge_member_ifaddrs(void)
@@ -1448,24 +1448,30 @@ bridge_ioctl_add(struct bridge_softc *sc, void *arg)
/*
* If member_ifaddrs is disabled, do not allow an interface with
- * assigned IP addresses to be added to a bridge.
+ * assigned IP addresses to be added to a bridge. Skip this check
+ * for gif interfaces, because the IP address assigned to a gif
+ * interface is separate from the bridge's Ethernet segment.
*/
- if (!V_member_ifaddrs) {
+ if (ifs->if_type != IFT_GIF) {
struct ifaddr *ifa;
CK_STAILQ_FOREACH(ifa, &ifs->if_addrhead, ifa_link) {
-#ifdef INET
- if (ifa->ifa_addr->sa_family == AF_INET)
- return (EXTERROR(EINVAL,
- "Member interface may not have "
- "an IPv4 address configured"));
-#endif
-#ifdef INET6
- if (ifa->ifa_addr->sa_family == AF_INET6)
+ if (ifa->ifa_addr->sa_family != AF_INET &&
+ ifa->ifa_addr->sa_family != AF_INET6)
+ continue;
+
+ if (V_member_ifaddrs) {
+ if_printf(sc->sc_ifp,
+ "WARNING: Adding member interface %s which "
+ "has an IP address assigned is deprecated "
+ "and will be unsupported in a future "
+ "release.\n", ifs->if_xname);
+ break;
+ } else {
return (EXTERROR(EINVAL,
"Member interface may not have "
- "an IPv6 address configured"));
-#endif
+ "an IP address assigned"));
+ }
}
}
diff --git a/sys/net/if_epair.c b/sys/net/if_epair.c
index 581c2434b8fb..fbffa8f359a0 100644
--- a/sys/net/if_epair.c
+++ b/sys/net/if_epair.c
@@ -69,6 +69,7 @@
#include <net/if_media.h>
#include <net/if_private.h>
#include <net/if_types.h>
+#include <net/if_vlan_var.h>
#include <net/netisr.h>
#ifdef RSS
#include <net/rss_config.h>
@@ -434,6 +435,21 @@ epair_media_status(struct ifnet *ifp __unused, struct ifmediareq *imr)
imr->ifm_active = IFM_ETHER | IFM_10G_T | IFM_FDX;
}
+/*
+ * Update ifp->if_hwassist according to the current value of ifp->if_capenable.
+ */
+static void
+epair_caps_changed(struct ifnet *ifp)
+{
+ uint64_t hwassist = 0;
+
+ if (ifp->if_capenable & IFCAP_TXCSUM)
+ hwassist |= CSUM_IP_TCP | CSUM_IP_UDP;
+ if (ifp->if_capenable & IFCAP_TXCSUM_IPV6)
+ hwassist |= CSUM_IP6_TCP | CSUM_IP6_UDP;
+ ifp->if_hwassist = hwassist;
+}
+
static int
epair_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
{
@@ -461,6 +477,44 @@ epair_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
error = 0;
break;
+ case SIOCGIFCAP:
+ ifr->ifr_reqcap = ifp->if_capabilities;
+ ifr->ifr_curcap = ifp->if_capenable;
+ error = 0;
+ break;
+ case SIOCSIFCAP:
+ /*
+ * Enable/disable capabilities as requested, besides
+ * IFCAP_RXCSUM(_IPV6), which always remain enabled.
+ * Incoming packets may have the mbuf flag CSUM_DATA_VALID set.
+ * Without IFCAP_RXCSUM(_IPV6), this flag would have to be
+ * removed, which does not seem helpful.
+ */
+ ifp->if_capenable = ifr->ifr_reqcap | IFCAP_RXCSUM |
+ IFCAP_RXCSUM_IPV6;
+ epair_caps_changed(ifp);
+ /*
+ * If IFCAP_TXCSUM(_IPV6) has been changed, change it on the
+ * other epair interface as well.
+ * A bridge disables IFCAP_TXCSUM(_IPV6) when adding one epair
+ * interface if another interface in the bridge has it disabled.
+ * In that case this capability needs to be disabled on the
+ * other epair interface to avoid sending packets in the bridge
+ * that rely on this capability.
+ */
+ sc = ifp->if_softc;
+ if ((ifp->if_capenable ^ sc->oifp->if_capenable) &
+ (IFCAP_TXCSUM | IFCAP_TXCSUM_IPV6)) {
+ sc->oifp->if_capenable &=
+ ~(IFCAP_TXCSUM | IFCAP_TXCSUM_IPV6);
+ sc->oifp->if_capenable |= ifp->if_capenable &
+ (IFCAP_TXCSUM | IFCAP_TXCSUM_IPV6);
+ epair_caps_changed(sc->oifp);
+ }
+ VLAN_CAPABILITIES(ifp);
+ error = 0;
+ break;
+
default:
/* Let the common ethernet handler process this. */
error = ether_ioctl(ifp, cmd, data);
@@ -572,8 +626,11 @@ epair_setup_ifp(struct epair_softc *sc, char *name, int unit)
ifp->if_dname = epairname;
ifp->if_dunit = unit;
ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
- ifp->if_capabilities = IFCAP_VLAN_MTU;
- ifp->if_capenable = IFCAP_VLAN_MTU;
+ ifp->if_capabilities = IFCAP_VLAN_MTU | IFCAP_TXCSUM |
+ IFCAP_TXCSUM_IPV6 | IFCAP_RXCSUM | IFCAP_RXCSUM_IPV6;
+ ifp->if_capenable = IFCAP_VLAN_MTU | IFCAP_TXCSUM |
+ IFCAP_TXCSUM_IPV6 | IFCAP_RXCSUM | IFCAP_RXCSUM_IPV6;
+ epair_caps_changed(ifp);
ifp->if_transmit = epair_transmit;
ifp->if_qflush = epair_qflush;
ifp->if_start = epair_start;
diff --git a/sys/net/if_ethersubr.c b/sys/net/if_ethersubr.c
index 3ae0c01c0efc..9c157bf3d3c2 100644
--- a/sys/net/if_ethersubr.c
+++ b/sys/net/if_ethersubr.c
@@ -695,7 +695,7 @@ ether_input_internal(struct ifnet *ifp, struct mbuf *m)
* seen by upper protocol layers.
*/
if (!ETHER_IS_MULTICAST(eh->ether_dhost) &&
- bcmp(IF_LLADDR(ifp), eh->ether_dhost, ETHER_ADDR_LEN) != 0)
+ memcmp(IF_LLADDR(ifp), eh->ether_dhost, ETHER_ADDR_LEN) != 0)
m->m_flags |= M_PROMISC;
}
diff --git a/sys/net/iflib.c b/sys/net/iflib.c
index 98c59e5de988..308ecad0a846 100644
--- a/sys/net/iflib.c
+++ b/sys/net/iflib.c
@@ -712,7 +712,7 @@ static uint32_t iflib_txq_can_drain(struct ifmp_ring *);
static void iflib_altq_if_start(if_t ifp);
static int iflib_altq_if_transmit(if_t ifp, struct mbuf *m);
#endif
-static int iflib_register(if_ctx_t);
+static void iflib_register(if_ctx_t);
static void iflib_deregister(if_ctx_t);
static void iflib_unregister_vlan_handlers(if_ctx_t ctx);
static uint16_t iflib_get_mbuf_size_for(unsigned int size);
@@ -5136,10 +5136,7 @@ iflib_device_register(device_t dev, void *sc, if_shared_ctx_t sctx, if_ctx_t *ct
ctx->ifc_dev = dev;
ctx->ifc_softc = sc;
- if ((err = iflib_register(ctx)) != 0) {
- device_printf(dev, "iflib_register failed %d\n", err);
- goto fail_ctx_free;
- }
+ iflib_register(ctx);
iflib_add_device_sysctl_pre(ctx);
scctx = &ctx->ifc_softc_ctx;
@@ -5363,7 +5360,6 @@ iflib_device_register(device_t dev, void *sc, if_shared_ctx_t sctx, if_ctx_t *ct
DEBUGNET_SET(ctx->ifc_ifp, iflib);
- if_setgetcounterfn(ctx->ifc_ifp, iflib_if_get_counter);
iflib_add_device_sysctl_post(ctx);
iflib_add_pfil(ctx);
ctx->ifc_flags |= IFC_INIT_DONE;
@@ -5387,7 +5383,6 @@ fail_unlock:
CTX_UNLOCK(ctx);
IFNET_WUNLOCK();
iflib_deregister(ctx);
-fail_ctx_free:
device_set_softc(ctx->ifc_dev, NULL);
if (ctx->ifc_flags & IFC_SC_ALLOCATED)
free(ctx->ifc_softc, M_IFLIB);
@@ -5685,7 +5680,7 @@ _iflib_pre_assert(if_softc_ctx_t scctx)
MPASS(scctx->isc_txrx->ift_rxd_flush);
}
-static int
+static void
iflib_register(if_ctx_t ctx)
{
if_shared_ctx_t sctx = ctx->ifc_sctx;
@@ -5718,6 +5713,7 @@ iflib_register(if_ctx_t ctx)
if_settransmitfn(ifp, iflib_if_transmit);
#endif
if_setqflushfn(ifp, iflib_if_qflush);
+ if_setgetcounterfn(ifp, iflib_if_get_counter);
if_setflags(ifp, IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST);
ctx->ifc_vlan_attach_event =
EVENTHANDLER_REGISTER(vlan_config, iflib_vlan_register, ctx,
@@ -5731,7 +5727,6 @@ iflib_register(if_ctx_t ctx)
ifmedia_init(ctx->ifc_mediap, IFM_IMASK,
iflib_media_change, iflib_media_status);
}
- return (0);
}
static void
diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h
index d6c13470f2eb..f73420494000 100644
--- a/sys/net/pfvar.h
+++ b/sys/net/pfvar.h
@@ -326,6 +326,7 @@ pf_counter_u64_zero(struct pf_counter_u64 *pfcu64)
_Static_assert(sizeof(time_t) == 4 || sizeof(time_t) == 8, "unexpected time_t size");
SYSCTL_DECL(_net_pf);
+MALLOC_DECLARE(M_PF);
MALLOC_DECLARE(M_PFHASH);
MALLOC_DECLARE(M_PF_RULE_ITEM);
@@ -645,6 +646,7 @@ struct pf_kpool {
int tblidx;
u_int16_t proxy_port[2];
u_int8_t opts;
+ sa_family_t ipv6_nexthop_af;
};
struct pf_rule_actions {
@@ -859,8 +861,8 @@ struct pf_krule {
u_int8_t keep_state;
sa_family_t af;
u_int8_t proto;
- u_int8_t type;
- u_int8_t code;
+ uint16_t type;
+ uint16_t code;
u_int8_t flags;
u_int8_t flagset;
u_int8_t min_ttl;
@@ -2612,6 +2614,7 @@ struct pf_kruleset *pf_find_kruleset(const char *);
struct pf_kruleset *pf_get_leaf_kruleset(char *, char **);
struct pf_kruleset *pf_find_or_create_kruleset(const char *);
void pf_rs_initialize(void);
+void pf_rule_tree_free(struct pf_krule_global *);
struct pf_krule *pf_krule_alloc(void);
@@ -2680,7 +2683,7 @@ u_short pf_map_addr(sa_family_t, struct pf_krule *,
struct pf_addr *, struct pf_kpool *);
u_short pf_map_addr_sn(u_int8_t, struct pf_krule *,
struct pf_addr *, struct pf_addr *,
- sa_family_t *, struct pfi_kkif **nkif,
+ sa_family_t *, struct pfi_kkif **,
struct pf_addr *, struct pf_kpool *,
pf_sn_types_t);
int pf_get_transaddr_af(struct pf_krule *,
diff --git a/sys/net80211/ieee80211_ddb.c b/sys/net80211/ieee80211_ddb.c
index d96d7988a864..1dd8e38b9896 100644
--- a/sys/net80211/ieee80211_ddb.c
+++ b/sys/net80211/ieee80211_ddb.c
@@ -296,7 +296,7 @@ _db_show_sta(const struct ieee80211_node *ni)
ni->ni_htparam, ni->ni_htctlchan, ni->ni_ht2ndchan);
db_printf("\thtopmode 0x%x htstbc 0x%x chw %d (%s)\n",
ni->ni_htopmode, ni->ni_htstbc,
- ni->ni_chw, ieee80211_ni_chw_to_str(ni->ni_chw));
+ ni->ni_chw, net80211_ni_chw_to_str(ni->ni_chw));
/* XXX ampdu state */
for (i = 0; i < WME_NUM_TID; i++)
diff --git a/sys/net80211/ieee80211_freebsd.h b/sys/net80211/ieee80211_freebsd.h
index 3684fba52c5c..954801d95787 100644
--- a/sys/net80211/ieee80211_freebsd.h
+++ b/sys/net80211/ieee80211_freebsd.h
@@ -341,11 +341,16 @@ struct mbuf *ieee80211_getmgtframe(uint8_t **frm, int headroom, int pktlen);
#define M_AGE_SUB(m,adj) (m->m_pkthdr.csum_data -= adj)
/*
- * Store the sequence number.
+ * Store / retrieve the sequence number in an mbuf.
+ *
+ * The sequence number being stored/retreived is the 12 bit
+ * base sequence number, not the 16 bit sequence number field.
+ * I.e., it's from 0..4095 inclusive, with no 4 bit padding for
+ * fragment numbers.
*/
#define M_SEQNO_SET(m, seqno) \
- ((m)->m_pkthdr.tso_segsz = (seqno))
-#define M_SEQNO_GET(m) ((m)->m_pkthdr.tso_segsz)
+ ((m)->m_pkthdr.tso_segsz = ((seqno) % IEEE80211_SEQ_RANGE))
+#define M_SEQNO_GET(m) (((m)->m_pkthdr.tso_segsz) % IEEE80211_SEQ_RANGE)
#define MTAG_ABI_NET80211 1132948340 /* net80211 ABI */
diff --git a/sys/net80211/ieee80211_ht.c b/sys/net80211/ieee80211_ht.c
index c28f124648a1..018927a6dad4 100644
--- a/sys/net80211/ieee80211_ht.c
+++ b/sys/net80211/ieee80211_ht.c
@@ -1476,7 +1476,7 @@ ieee80211_ht_wds_init(struct ieee80211_node *ni)
ni->ni_htcap |= IEEE80211_HTCAP_SHORTGI20;
if (IEEE80211_IS_CHAN_HT40(ni->ni_chan)) {
ni->ni_htcap |= IEEE80211_HTCAP_CHWIDTH40;
- ni->ni_chw = IEEE80211_STA_RX_BW_40;
+ ni->ni_chw = NET80211_STA_RX_BW_40;
if (IEEE80211_IS_CHAN_HT40U(ni->ni_chan))
ni->ni_ht2ndchan = IEEE80211_HTINFO_2NDCHAN_ABOVE;
else if (IEEE80211_IS_CHAN_HT40D(ni->ni_chan))
@@ -1484,7 +1484,7 @@ ieee80211_ht_wds_init(struct ieee80211_node *ni)
if (vap->iv_flags_ht & IEEE80211_FHT_SHORTGI40)
ni->ni_htcap |= IEEE80211_HTCAP_SHORTGI40;
} else {
- ni->ni_chw = IEEE80211_STA_RX_BW_20;
+ ni->ni_chw = NET80211_STA_RX_BW_20;
ni->ni_ht2ndchan = IEEE80211_HTINFO_2NDCHAN_NONE;
}
ni->ni_htctlchan = ni->ni_chan->ic_ieee;
@@ -1580,7 +1580,7 @@ ieee80211_ht_node_join(struct ieee80211_node *ni)
if (ni->ni_flags & IEEE80211_NODE_HT) {
vap->iv_ht_sta_assoc++;
- if (ni->ni_chw == IEEE80211_STA_RX_BW_40)
+ if (ni->ni_chw == NET80211_STA_RX_BW_40)
vap->iv_ht40_sta_assoc++;
}
htinfo_update(vap);
@@ -1598,7 +1598,7 @@ ieee80211_ht_node_leave(struct ieee80211_node *ni)
if (ni->ni_flags & IEEE80211_NODE_HT) {
vap->iv_ht_sta_assoc--;
- if (ni->ni_chw == IEEE80211_STA_RX_BW_40)
+ if (ni->ni_chw == NET80211_STA_RX_BW_40)
vap->iv_ht40_sta_assoc--;
}
htinfo_update(vap);
@@ -1827,7 +1827,7 @@ htinfo_update_chw(struct ieee80211_node *ni, int htflags, int vhtflags)
done:
/* update node's (11n) tx channel width */
ni->ni_chw = IEEE80211_IS_CHAN_HT40(ni->ni_chan) ?
- IEEE80211_STA_RX_BW_40 : IEEE80211_STA_RX_BW_20;
+ NET80211_STA_RX_BW_40 : NET80211_STA_RX_BW_20;
return (ret);
}
@@ -2689,11 +2689,11 @@ ht_recv_action_ht_txchwidth(struct ieee80211_node *ni,
* here.
*/
chw = (frm[2] == IEEE80211_A_HT_TXCHWIDTH_2040) ?
- IEEE80211_STA_RX_BW_40 : IEEE80211_STA_RX_BW_20;
+ NET80211_STA_RX_BW_40 : NET80211_STA_RX_BW_20;
IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
"%s: HT txchwidth, width %d%s (%s)", __func__,
- chw, ni->ni_chw != chw ? "*" : "", ieee80211_ni_chw_to_str(chw));
+ chw, ni->ni_chw != chw ? "*" : "", net80211_ni_chw_to_str(chw));
if (chw != ni->ni_chw) {
/* XXX does this need to change the ht40 station count? */
ni->ni_chw = chw;
@@ -3832,5 +3832,5 @@ ieee80211_ht_check_tx_ht40(const struct ieee80211_node *ni)
return (IEEE80211_IS_CHAN_HT40(bss_chan) &&
IEEE80211_IS_CHAN_HT40(ni->ni_chan) &&
- (ni->ni_chw == IEEE80211_STA_RX_BW_40));
+ (ni->ni_chw == NET80211_STA_RX_BW_40));
}
diff --git a/sys/net80211/ieee80211_node.c b/sys/net80211/ieee80211_node.c
index a201d1b278f0..49ba00299fee 100644
--- a/sys/net80211/ieee80211_node.c
+++ b/sys/net80211/ieee80211_node.c
@@ -2673,7 +2673,7 @@ ieee80211_dump_node(struct ieee80211_node_table *nt __unused,
ni->ni_htctlchan, ni->ni_ht2ndchan);
net80211_printf("\thtopmode %x htstbc %x htchw %d (%s)\n",
ni->ni_htopmode, ni->ni_htstbc,
- ni->ni_chw, ieee80211_ni_chw_to_str(ni->ni_chw));
+ ni->ni_chw, net80211_ni_chw_to_str(ni->ni_chw));
net80211_printf("\tvhtcap %x freq1 %d freq2 %d vhtbasicmcs %x\n",
ni->ni_vhtcap, (int) ni->ni_vht_chan1, (int) ni->ni_vht_chan2,
(int) ni->ni_vht_basicmcs);
@@ -2831,7 +2831,7 @@ ieee80211_node_join(struct ieee80211_node *ni, int resp)
ni->ni_flags & IEEE80211_NODE_QOS ? ", QoS" : "",
/* XXX update for VHT string */
ni->ni_flags & IEEE80211_NODE_HT ?
- (ni->ni_chw == IEEE80211_STA_RX_BW_40 ? ", HT40" : ", HT20") : "",
+ (ni->ni_chw == NET80211_STA_RX_BW_40 ? ", HT40" : ", HT20") : "",
ni->ni_flags & IEEE80211_NODE_AMPDU ? " (+AMPDU)" : "",
ni->ni_flags & IEEE80211_NODE_AMSDU ? " (+AMSDU)" : "",
ni->ni_flags & IEEE80211_NODE_MIMO_RTS ? " (+SMPS-DYN)" :
diff --git a/sys/net80211/ieee80211_node.h b/sys/net80211/ieee80211_node.h
index ef25fa0d7fdd..f1246dd12419 100644
--- a/sys/net80211/ieee80211_node.h
+++ b/sys/net80211/ieee80211_node.h
@@ -109,33 +109,33 @@ enum ieee80211_mesh_mlstate {
"\20\1IDLE\2OPENSNT\2OPENRCV\3CONFIRMRCV\4ESTABLISHED\5HOLDING"
/*
- * This structure is shared with LinuxKPI 802.11 code describing up-to
- * which channel width the station can receive.
+ * This enum was shared with the LinuxKPI enum ieee80211_sta_rx_bandwidth
+ * describing up-to which channel width the station can receive.
* Rather than using hardcoded MHz values for the channel width use an enum with
* flags. This allows us to keep the uint8_t slot for ni_chw in
- * struct ieee80211_node and means we do not have to sync to the value for
- * LinuxKPI.
+ * struct ieee80211_node it means we do not have to sync to the value for
+ * LinuxKPI (just the names).
*
* NB: BW_20 needs to 0 and values need to be sorted! Cannot make it
* bitfield-alike for use with %b.
*/
-enum ieee80211_sta_rx_bw {
- IEEE80211_STA_RX_BW_20 = 0x00,
- IEEE80211_STA_RX_BW_40,
- IEEE80211_STA_RX_BW_80,
- IEEE80211_STA_RX_BW_160,
- IEEE80211_STA_RX_BW_320,
+enum net80211_sta_rx_bw {
+ NET80211_STA_RX_BW_20 = 0x00,
+ NET80211_STA_RX_BW_40,
+ NET80211_STA_RX_BW_80,
+ NET80211_STA_RX_BW_160,
+ NET80211_STA_RX_BW_320,
} __packed;
static inline const char *
-ieee80211_ni_chw_to_str(enum ieee80211_sta_rx_bw bw)
+net80211_ni_chw_to_str(enum net80211_sta_rx_bw bw)
{
switch (bw) {
- case IEEE80211_STA_RX_BW_20: return ("BW_20");
- case IEEE80211_STA_RX_BW_40: return ("BW_40");
- case IEEE80211_STA_RX_BW_80: return ("BW_80");
- case IEEE80211_STA_RX_BW_160: return ("BW_160");
- case IEEE80211_STA_RX_BW_320: return ("BW_320");
+ case NET80211_STA_RX_BW_20: return ("BW_20");
+ case NET80211_STA_RX_BW_40: return ("BW_40");
+ case NET80211_STA_RX_BW_80: return ("BW_80");
+ case NET80211_STA_RX_BW_160: return ("BW_160");
+ case NET80211_STA_RX_BW_320: return ("BW_320");
}
}
@@ -285,7 +285,7 @@ struct ieee80211_node {
uint8_t ni_ht2ndchan; /* HT 2nd channel */
uint8_t ni_htopmode; /* HT operating mode */
uint8_t ni_htstbc; /* HT */
- enum ieee80211_sta_rx_bw ni_chw; /* negotiated channel width */
+ enum net80211_sta_rx_bw ni_chw; /* negotiated channel width */
struct ieee80211_htrateset ni_htrates; /* negotiated ht rate set */
struct ieee80211_tx_ampdu ni_tx_ampdu[WME_NUM_TID];
struct ieee80211_rx_ampdu ni_rx_ampdu[WME_NUM_TID];
diff --git a/sys/net80211/ieee80211_phy.c b/sys/net80211/ieee80211_phy.c
index eb96d74a2bd9..7f53c717152b 100644
--- a/sys/net80211/ieee80211_phy.c
+++ b/sys/net80211/ieee80211_phy.c
@@ -658,26 +658,26 @@ static uint16_t ieee80211_vht_mcs_allowed_list_160[] = {
*
* See 802.11-2020 21.5 (Parameters for VHT-MCSs) for more details.
*
- * @param bw channel bandwidth, via enum ieee80211_sta_rx_bw
+ * @param bw channel bandwidth, via enum net80211_sta_rx_bw
* @param nss number of spatial streams, 1..8
* @returns bitmask of valid MCS rates from 0..9
*/
uint16_t
-ieee80211_phy_vht_get_mcs_mask(enum ieee80211_sta_rx_bw bw, uint8_t nss)
+ieee80211_phy_vht_get_mcs_mask(enum net80211_sta_rx_bw bw, uint8_t nss)
{
if (nss == 0 || nss > 8)
return (0);
switch (bw) {
- case IEEE80211_STA_RX_BW_20:
+ case NET80211_STA_RX_BW_20:
return (ieee80211_vht_mcs_allowed_list_20[nss - 1]);
- case IEEE80211_STA_RX_BW_40:
+ case NET80211_STA_RX_BW_40:
return (ieee80211_vht_mcs_allowed_list_40[nss - 1]);
- case IEEE80211_STA_RX_BW_80:
+ case NET80211_STA_RX_BW_80:
return (ieee80211_vht_mcs_allowed_list_80[nss - 1]);
- case IEEE80211_STA_RX_BW_160:
+ case NET80211_STA_RX_BW_160:
return (ieee80211_vht_mcs_allowed_list_160[nss - 1]);
- case IEEE80211_STA_RX_BW_320:
+ case NET80211_STA_RX_BW_320:
/* invalid for VHT */
return (0);
}
@@ -689,14 +689,14 @@ ieee80211_phy_vht_get_mcs_mask(enum ieee80211_sta_rx_bw bw, uint8_t nss)
*
* See 802.11-2020 21.5 (Parameters for VHT-MCSs) for more details.
*
- * @param bw channel bandwidth, via enum ieee80211_sta_rx_bw
+ * @param bw channel bandwidth, via enum net80211_sta_rx_bw
* @param nss number of spatial streams, 1..8
* @param mcs MCS rate, 0..9
* @retval true if the NSS / MCS / bandwidth combination is valid
* @retval false if the NSS / MCS / bandwidth combination is not valid
*/
bool
-ieee80211_phy_vht_validate_mcs(enum ieee80211_sta_rx_bw bw, uint8_t nss,
+ieee80211_phy_vht_validate_mcs(enum net80211_sta_rx_bw bw, uint8_t nss,
uint8_t mcs)
{
uint16_t mask;
@@ -737,7 +737,7 @@ static struct mcs_entry mcs_entries[] = {
/**
* @brief Calculate the bitrate of the given VHT MCS rate.
*
- * @param bw Channel bandwidth (enum ieee80211_sta_rx_bw)
+ * @param bw Channel bandwidth (enum net80211_sta_rx_bw)
* @param nss Number of spatial streams, 1..8
* @param mcs MCS, 0..9
* @param is_shortgi True if short guard-interval (400nS)
@@ -746,7 +746,7 @@ static struct mcs_entry mcs_entries[] = {
* @returns The bitrate in kbit/sec.
*/
uint32_t
-ieee80211_phy_vht_get_mcs_kbit(enum ieee80211_sta_rx_bw bw,
+ieee80211_phy_vht_get_mcs_kbit(enum net80211_sta_rx_bw bw,
uint8_t nss, uint8_t mcs, bool is_shortgi)
{
uint32_t sym_len, n_carriers;
@@ -773,16 +773,16 @@ ieee80211_phy_vht_get_mcs_kbit(enum ieee80211_sta_rx_bw bw,
* See 802.11-2020 Table 21-5 (Timing-related constraints.)
*/
switch (bw) {
- case IEEE80211_STA_RX_BW_20:
+ case NET80211_STA_RX_BW_20:
n_carriers = 52;
break;
- case IEEE80211_STA_RX_BW_40:
+ case NET80211_STA_RX_BW_40:
n_carriers = 108;
break;
- case IEEE80211_STA_RX_BW_80:
+ case NET80211_STA_RX_BW_80:
n_carriers = 234;
break;
- case IEEE80211_STA_RX_BW_160:
+ case NET80211_STA_RX_BW_160:
n_carriers = 468;
break;
default:
diff --git a/sys/net80211/ieee80211_phy.h b/sys/net80211/ieee80211_phy.h
index 749b082e34e9..391c8bfc5010 100644
--- a/sys/net80211/ieee80211_phy.h
+++ b/sys/net80211/ieee80211_phy.h
@@ -221,13 +221,13 @@ uint32_t ieee80211_compute_duration_ht(uint32_t frameLen,
uint16_t rate, int streams, int isht40,
int isShortGI);
-enum ieee80211_sta_rx_bw;
+enum net80211_sta_rx_bw;
-uint16_t ieee80211_phy_vht_get_mcs_mask(enum ieee80211_sta_rx_bw,
+uint16_t ieee80211_phy_vht_get_mcs_mask(enum net80211_sta_rx_bw,
uint8_t);
-bool ieee80211_phy_vht_validate_mcs(enum ieee80211_sta_rx_bw,
+bool ieee80211_phy_vht_validate_mcs(enum net80211_sta_rx_bw,
uint8_t, uint8_t);
-uint32_t ieee80211_phy_vht_get_mcs_kbit(enum ieee80211_sta_rx_bw,
+uint32_t ieee80211_phy_vht_get_mcs_kbit(enum net80211_sta_rx_bw,
uint8_t, uint8_t, bool);
#endif /* _KERNEL */
diff --git a/sys/net80211/ieee80211_sta.c b/sys/net80211/ieee80211_sta.c
index 463a8b16773b..19e5ffe9a367 100644
--- a/sys/net80211/ieee80211_sta.c
+++ b/sys/net80211/ieee80211_sta.c
@@ -1934,7 +1934,7 @@ sta_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0, int subtype,
vap->iv_flags&IEEE80211_F_USEPROT ? ", protection" : "",
ni->ni_flags & IEEE80211_NODE_QOS ? ", QoS" : "",
ni->ni_flags & IEEE80211_NODE_HT ?
- (ni->ni_chw == IEEE80211_STA_RX_BW_40 ? ", HT40" : ", HT20") : "",
+ (ni->ni_chw == NET80211_STA_RX_BW_40 ? ", HT40" : ", HT20") : "",
ni->ni_flags & IEEE80211_NODE_AMPDU ? " (+AMPDU)" : "",
ni->ni_flags & IEEE80211_NODE_AMSDU ? " (+AMSDU)" : "",
ni->ni_flags & IEEE80211_NODE_MIMO_RTS ? " (+SMPS-DYN)" :
diff --git a/sys/net80211/ieee80211_vht.c b/sys/net80211/ieee80211_vht.c
index de0b691d4d2a..10a5fc7f08ab 100644
--- a/sys/net80211/ieee80211_vht.c
+++ b/sys/net80211/ieee80211_vht.c
@@ -974,7 +974,7 @@ ieee80211_vht_check_tx_vht40(const struct ieee80211_node *ni)
return (IEEE80211_IS_CHAN_VHT40(bss_chan) &&
IEEE80211_IS_CHAN_VHT40(ni->ni_chan) &&
- (ni->ni_chw == IEEE80211_STA_RX_BW_40));
+ (ni->ni_chw == NET80211_STA_RX_BW_40));
}
/*
@@ -1003,7 +1003,7 @@ ieee80211_vht_check_tx_vht80(const struct ieee80211_node *ni)
*/
return (IEEE80211_IS_CHAN_VHT80(bss_chan) &&
IEEE80211_IS_CHAN_VHT80(ni->ni_chan) &&
- (ni->ni_chw != IEEE80211_STA_RX_BW_20));
+ (ni->ni_chw != NET80211_STA_RX_BW_20));
}
/*
@@ -1030,7 +1030,7 @@ ieee80211_vht_check_tx_vht160(const struct ieee80211_node *ni)
* If a HT TX width action frame sets it to 20MHz
* then reject doing 160MHz.
*/
- if (ni->ni_chw == IEEE80211_STA_RX_BW_20)
+ if (ni->ni_chw == NET80211_STA_RX_BW_20)
return (false);
if (IEEE80211_IS_CHAN_VHT160(bss_chan) &&
@@ -1062,19 +1062,19 @@ ieee80211_vht_check_tx_vht160(const struct ieee80211_node *ni)
*/
bool
ieee80211_vht_check_tx_bw(const struct ieee80211_node *ni,
- enum ieee80211_sta_rx_bw bw)
+ enum net80211_sta_rx_bw bw)
{
switch (bw) {
- case IEEE80211_STA_RX_BW_20:
+ case NET80211_STA_RX_BW_20:
return (ieee80211_vht_check_tx_vht(ni));
- case IEEE80211_STA_RX_BW_40:
+ case NET80211_STA_RX_BW_40:
return (ieee80211_vht_check_tx_vht40(ni));
- case IEEE80211_STA_RX_BW_80:
+ case NET80211_STA_RX_BW_80:
return (ieee80211_vht_check_tx_vht80(ni));
- case IEEE80211_STA_RX_BW_160:
+ case NET80211_STA_RX_BW_160:
return (ieee80211_vht_check_tx_vht160(ni));
- case IEEE80211_STA_RX_BW_320:
+ case NET80211_STA_RX_BW_320:
return (false);
default:
return (false);
@@ -1096,7 +1096,7 @@ ieee80211_vht_check_tx_bw(const struct ieee80211_node *ni,
*/
bool
ieee80211_vht_node_check_tx_valid_mcs(const struct ieee80211_node *ni,
- enum ieee80211_sta_rx_bw bw, uint8_t nss, uint8_t mcs)
+ enum net80211_sta_rx_bw bw, uint8_t nss, uint8_t mcs)
{
uint8_t mc;
diff --git a/sys/net80211/ieee80211_vht.h b/sys/net80211/ieee80211_vht.h
index a1529df4a85b..b9b19fbc6008 100644
--- a/sys/net80211/ieee80211_vht.h
+++ b/sys/net80211/ieee80211_vht.h
@@ -65,8 +65,8 @@ void ieee80211_vht_get_vhtinfo_ie(struct ieee80211_node *ni,
bool ieee80211_vht_check_tx_vht(const struct ieee80211_node *);
bool ieee80211_vht_check_tx_bw(const struct ieee80211_node *,
- enum ieee80211_sta_rx_bw);
+ enum net80211_sta_rx_bw);
bool ieee80211_vht_node_check_tx_valid_mcs(const struct ieee80211_node *,
- enum ieee80211_sta_rx_bw bw, uint8_t, uint8_t);
+ enum net80211_sta_rx_bw bw, uint8_t, uint8_t);
#endif /* _NET80211_IEEE80211_VHT_H_ */
diff --git a/sys/netgraph/ng_parse.c b/sys/netgraph/ng_parse.c
index 448ecc92f075..5e1a1bb47ac0 100644
--- a/sys/netgraph/ng_parse.c
+++ b/sys/netgraph/ng_parse.c
@@ -1199,14 +1199,14 @@ ng_parse_composite(const struct ng_parse_type *type, const char *s,
int *off, const u_char *const start, u_char *const buf, int *buflen,
const enum comptype ctype)
{
- const int num = ng_get_composite_len(type, start, buf, ctype);
int nextIndex = 0; /* next implicit array index */
u_int index; /* field or element index */
int *foff; /* field value offsets in string */
int align, len, blen, error = 0;
/* Initialize */
- if (num < 0)
+ const int num = ng_get_composite_len(type, start, buf, ctype);
+ if (num < 0 || num > INT_MAX / sizeof(*foff))
return (EINVAL);
foff = malloc(num * sizeof(*foff), M_NETGRAPH_PARSE, M_NOWAIT | M_ZERO);
if (foff == NULL) {
diff --git a/sys/netinet/in.c b/sys/netinet/in.c
index 963449d4b4b1..70a61dbf93a3 100644
--- a/sys/netinet/in.c
+++ b/sys/netinet/in.c
@@ -522,9 +522,16 @@ in_aifaddr_ioctl(u_long cmd, caddr_t data, struct ifnet *ifp, struct ucred *cred
/*
* Check if bridge wants to allow adding addrs to member interfaces.
*/
- if (ifp->if_bridge && bridge_member_ifaddrs_p &&
- !bridge_member_ifaddrs_p())
- return (EINVAL);
+ if (ifp->if_bridge != NULL && ifp->if_type != IFT_GIF &&
+ bridge_member_ifaddrs_p != NULL) {
+ if (bridge_member_ifaddrs_p())
+ if_printf(ifp, "WARNING: Assigning an IP address to "
+ "an interface which is also a bridge member is "
+ "deprecated and will be unsupported in a future "
+ "release.\n");
+ else
+ return (EINVAL);
+ }
/*
* See whether address already exist.
@@ -1882,6 +1889,8 @@ in_domifdetach(struct ifnet *ifp, void *aux)
{
struct in_ifinfo *ii = (struct in_ifinfo *)aux;
+ MPASS(ifp->if_afdata[AF_INET] == NULL);
+
igmp_domifdetach(ifp);
lltable_free(ii->ii_llt);
free(ii, M_IFADDR);
diff --git a/sys/netinet/tcp_sack.c b/sys/netinet/tcp_sack.c
index b6c55fac50b3..6e08ad2796a8 100644
--- a/sys/netinet/tcp_sack.c
+++ b/sys/netinet/tcp_sack.c
@@ -128,8 +128,25 @@ SYSCTL_INT(_net_inet_tcp_sack, OID_AUTO, enable, CTLFLAG_VNET | CTLFLAG_RW,
"Enable/Disable TCP SACK support");
VNET_DEFINE(int, tcp_do_newsack) = 1;
-SYSCTL_INT(_net_inet_tcp_sack, OID_AUTO, revised, CTLFLAG_VNET | CTLFLAG_RW,
- &VNET_NAME(tcp_do_newsack), 0,
+
+static int
+sysctl_net_inet_tcp_sack_revised(SYSCTL_HANDLER_ARGS)
+{
+ int error;
+ int new;
+
+ new = V_tcp_do_newsack;
+ error = sysctl_handle_int(oidp, &new, 0, req);
+ if (error == 0 && req->newptr) {
+ V_tcp_do_newsack = new;
+ gone_in(16, "net.inet.tcp.sack.revised will be deprecated."
+ " net.inet.tcp.sack.enable will always follow RFC6675 SACK.\n");
+ }
+ return (error);
+}
+
+SYSCTL_PROC(_net_inet_tcp_sack, OID_AUTO, revised, CTLFLAG_VNET | CTLFLAG_RW | CTLTYPE_INT,
+ &VNET_NAME(tcp_do_newsack), 0, sysctl_net_inet_tcp_sack_revised, "CU",
"Use revised SACK loss recovery per RFC 6675");
VNET_DEFINE(int, tcp_do_lrd) = 1;
diff --git a/sys/netinet/tcp_syncache.c b/sys/netinet/tcp_syncache.c
index d617d0ed4aac..1ee6c6e31f33 100644
--- a/sys/netinet/tcp_syncache.c
+++ b/sys/netinet/tcp_syncache.c
@@ -102,15 +102,15 @@
#include <security/mac/mac_framework.h>
-VNET_DEFINE_STATIC(int, tcp_syncookies) = 1;
+VNET_DEFINE_STATIC(bool, tcp_syncookies) = true;
#define V_tcp_syncookies VNET(tcp_syncookies)
-SYSCTL_INT(_net_inet_tcp, OID_AUTO, syncookies, CTLFLAG_VNET | CTLFLAG_RW,
+SYSCTL_BOOL(_net_inet_tcp, OID_AUTO, syncookies, CTLFLAG_VNET | CTLFLAG_RW,
&VNET_NAME(tcp_syncookies), 0,
"Use TCP SYN cookies if the syncache overflows");
-VNET_DEFINE_STATIC(int, tcp_syncookiesonly) = 0;
+VNET_DEFINE_STATIC(bool, tcp_syncookiesonly) = false;
#define V_tcp_syncookiesonly VNET(tcp_syncookiesonly)
-SYSCTL_INT(_net_inet_tcp, OID_AUTO, syncookies_only, CTLFLAG_VNET | CTLFLAG_RW,
+SYSCTL_BOOL(_net_inet_tcp, OID_AUTO, syncookies_only, CTLFLAG_VNET | CTLFLAG_RW,
&VNET_NAME(tcp_syncookiesonly), 0,
"Use only TCP SYN cookies");
@@ -553,9 +553,8 @@ syncache_timer(void *xsch)
static inline bool
syncache_cookiesonly(void)
{
-
- return (V_tcp_syncookies && (V_tcp_syncache.paused ||
- V_tcp_syncookiesonly));
+ return ((V_tcp_syncookies && V_tcp_syncache.paused) ||
+ V_tcp_syncookiesonly);
}
/*
@@ -1083,40 +1082,48 @@ syncache_expand(struct in_conninfo *inc, struct tcpopt *to, struct tcphdr *th,
#endif
if (sc == NULL) {
- /*
- * There is no syncache entry, so see if this ACK is
- * a returning syncookie. To do this, first:
- * A. Check if syncookies are used in case of syncache
- * overflows
- * B. See if this socket has had a syncache entry dropped in
- * the recent past. We don't want to accept a bogus
- * syncookie if we've never received a SYN or accept it
- * twice.
- * C. check that the syncookie is valid. If it is, then
- * cobble up a fake syncache entry, and return.
- */
- if (locked && !V_tcp_syncookies) {
- SCH_UNLOCK(sch);
- TCPSTAT_INC(tcps_sc_spurcookie);
- if ((s = tcp_log_addrs(inc, th, NULL, NULL)))
- log(LOG_DEBUG, "%s; %s: Spurious ACK, "
- "segment rejected (syncookies disabled)\n",
- s, __func__);
- goto failed;
- }
- if (locked && !V_tcp_syncookiesonly &&
- sch->sch_last_overflow < time_uptime - SYNCOOKIE_LIFETIME) {
+ if (locked) {
+ /*
+ * The syncache is currently in use (neither disabled,
+ * nor paused), but no entry was found.
+ */
+ if (!V_tcp_syncookies) {
+ /*
+ * Since no syncookies are used in case of
+ * a bucket overflow, don't even check for
+ * a valid syncookie.
+ */
+ SCH_UNLOCK(sch);
+ TCPSTAT_INC(tcps_sc_spurcookie);
+ if ((s = tcp_log_addrs(inc, th, NULL, NULL)))
+ log(LOG_DEBUG, "%s; %s: Spurious ACK, "
+ "segment rejected "
+ "(syncookies disabled)\n",
+ s, __func__);
+ goto failed;
+ }
+ if (sch->sch_last_overflow <
+ time_uptime - SYNCOOKIE_LIFETIME) {
+ /*
+ * Since the bucket did not overflow recently,
+ * don't even check for a valid syncookie.
+ */
+ SCH_UNLOCK(sch);
+ TCPSTAT_INC(tcps_sc_spurcookie);
+ if ((s = tcp_log_addrs(inc, th, NULL, NULL)))
+ log(LOG_DEBUG, "%s; %s: Spurious ACK, "
+ "segment rejected "
+ "(no syncache entry)\n",
+ s, __func__);
+ goto failed;
+ }
SCH_UNLOCK(sch);
- TCPSTAT_INC(tcps_sc_spurcookie);
- if ((s = tcp_log_addrs(inc, th, NULL, NULL)))
- log(LOG_DEBUG, "%s; %s: Spurious ACK, "
- "segment rejected (no syncache entry)\n",
- s, __func__);
- goto failed;
}
- if (locked)
- SCH_UNLOCK(sch);
bzero(&scs, sizeof(scs));
+ /*
+ * Now check, if the syncookie is valid. If it is, create an on
+ * stack syncache entry.
+ */
if (syncookie_expand(inc, sch, &scs, th, to, *lsop, port)) {
sc = &scs;
TCPSTAT_INC(tcps_sc_recvcookie);
@@ -1291,7 +1298,7 @@ syncache_expand(struct in_conninfo *inc, struct tcpopt *to, struct tcphdr *th,
if (__predict_false(*lsop == NULL)) {
TCPSTAT_INC(tcps_sc_aborted);
TCPSTATES_DEC(TCPS_SYN_RECEIVED);
- } else
+ } else if (sc != &scs)
TCPSTAT_INC(tcps_sc_completed);
if (sc != &scs)
@@ -1668,7 +1675,7 @@ syncache_add(struct in_conninfo *inc, struct tcpopt *to, struct tcphdr *th,
sc->sc_tsoff = tcp_new_ts_offset(inc);
}
if ((to->to_flags & TOF_SCALE) && (V_tcp_do_rfc1323 != 3)) {
- int wscale = 0;
+ u_int wscale = 0;
/*
* Pick the smallest possible scaling factor that
@@ -1718,13 +1725,13 @@ syncache_add(struct in_conninfo *inc, struct tcpopt *to, struct tcphdr *th,
if (V_tcp_do_ecn && (tp->t_flags2 & TF2_CANNOT_DO_ECN) == 0)
sc->sc_flags |= tcp_ecn_syncache_add(tcp_get_flags(th), iptos);
- if (V_tcp_syncookies)
+ if (V_tcp_syncookies || V_tcp_syncookiesonly)
sc->sc_iss = syncookie_generate(sch, sc);
else
sc->sc_iss = arc4random();
#ifdef INET6
if (autoflowlabel) {
- if (V_tcp_syncookies)
+ if (V_tcp_syncookies || V_tcp_syncookiesonly)
sc->sc_flowlabel = sc->sc_iss;
else
sc->sc_flowlabel = ip6_randomflowlabel();
@@ -2264,7 +2271,7 @@ syncookie_expand(struct in_conninfo *inc, const struct syncache_head *sch,
uint32_t hash;
uint8_t *secbits;
tcp_seq ack, seq;
- int wnd, wscale = 0;
+ int wnd;
union syncookie cookie;
/*
@@ -2315,12 +2322,14 @@ syncookie_expand(struct in_conninfo *inc, const struct syncache_head *sch,
sc->sc_peer_mss = tcp_sc_msstab[cookie.flags.mss_idx];
- /* We can simply recompute receive window scale we sent earlier. */
- while (wscale < TCP_MAX_WINSHIFT && (TCP_MAXWIN << wscale) < sb_max)
- wscale++;
-
/* Only use wscale if it was enabled in the orignal SYN. */
if (cookie.flags.wscale_idx > 0) {
+ u_int wscale = 0;
+
+ /* Recompute the receive window scale that was sent earlier. */
+ while (wscale < TCP_MAX_WINSHIFT &&
+ (TCP_MAXWIN << wscale) < sb_max)
+ wscale++;
sc->sc_requested_r_scale = wscale;
sc->sc_requested_s_scale = tcp_sc_wstab[cookie.flags.wscale_idx];
sc->sc_flags |= SCF_WINSCALE;
diff --git a/sys/netinet/udp_usrreq.c b/sys/netinet/udp_usrreq.c
index 3e6519118a40..cea8a916679b 100644
--- a/sys/netinet/udp_usrreq.c
+++ b/sys/netinet/udp_usrreq.c
@@ -223,16 +223,18 @@ VNET_SYSUNINIT(udp, SI_SUB_PROTO_DOMAIN, SI_ORDER_FOURTH, udp_destroy, NULL);
* udp_append() will convert to a sockaddr_in6 before passing the address
* into the socket code.
*
- * In the normal case udp_append() will return 0, indicating that you
- * must unlock the inp. However if a tunneling protocol is in place we increment
- * the inpcb refcnt and unlock the inp, on return from the tunneling protocol we
- * then decrement the reference count. If the inp_rele returns 1, indicating the
- * inp is gone, we return that to the caller to tell them *not* to unlock
- * the inp. In the case of multi-cast this will cause the distribution
- * to stop (though most tunneling protocols known currently do *not* use
- * multicast).
+ * In the normal case udp_append() will return 'false', indicating that you
+ * must unlock the inpcb. However if a tunneling protocol is in place we
+ * increment the inpcb refcnt and unlock the inpcb, on return from the tunneling
+ * protocol we then decrement the reference count. If in_pcbrele_rlocked()
+ * returns 'true', indicating the inpcb is gone, we return that to the caller
+ * to tell them *not* to unlock the inpcb. In the case of multicast this will
+ * cause the distribution to stop (though most tunneling protocols known
+ * currently do *not* use multicast).
+ *
+ * The mbuf is always consumed.
*/
-static int
+static bool
udp_append(struct inpcb *inp, struct ip *ip, struct mbuf *n, int off,
struct sockaddr_in *udp_in)
{
@@ -255,15 +257,16 @@ udp_append(struct inpcb *inp, struct ip *ip, struct mbuf *n, int off,
in_pcbref(inp);
INP_RUNLOCK(inp);
- filtered = (*up->u_tun_func)(n, off, inp, (struct sockaddr *)&udp_in[0],
- up->u_tun_ctx);
+ filtered = (*up->u_tun_func)(n, off, inp,
+ (struct sockaddr *)&udp_in[0], up->u_tun_ctx);
INP_RLOCK(inp);
- if (in_pcbrele_rlocked(inp))
- return (1);
- if (filtered) {
- INP_RUNLOCK(inp);
- return (1);
+ if (in_pcbrele_rlocked(inp)) {
+ if (!filtered)
+ m_freem(n);
+ return (true);
}
+ if (filtered)
+ return (false);
}
off += sizeof(struct udphdr);
@@ -273,18 +276,18 @@ udp_append(struct inpcb *inp, struct ip *ip, struct mbuf *n, int off,
if (IPSEC_ENABLED(ipv4) &&
IPSEC_CHECK_POLICY(ipv4, n, inp) != 0) {
m_freem(n);
- return (0);
+ return (false);
}
if (up->u_flags & UF_ESPINUDP) {/* IPSec UDP encaps. */
if (IPSEC_ENABLED(ipv4) &&
UDPENCAP_INPUT(ipv4, n, off, AF_INET) != 0)
- return (0); /* Consumed. */
+ return (false);
}
#endif /* IPSEC */
#ifdef MAC
if (mac_inpcb_check_deliver(inp, n) != 0) {
m_freem(n);
- return (0);
+ return (false);
}
#endif /* MAC */
if (inp->inp_flags & INP_CONTROLOPTS ||
@@ -330,7 +333,7 @@ udp_append(struct inpcb *inp, struct ip *ip, struct mbuf *n, int off,
UDPSTAT_INC(udps_fullsock);
} else
sorwakeup_locked(so);
- return (0);
+ return (false);
}
static bool
@@ -699,7 +702,7 @@ udp_input(struct mbuf **mp, int *offp, int proto)
UDPLITE_PROBE(receive, NULL, inp, ip, inp, uh);
else
UDP_PROBE(receive, NULL, inp, ip, inp, uh);
- if (udp_append(inp, ip, m, iphlen, udp_in) == 0)
+ if (!udp_append(inp, ip, m, iphlen, udp_in))
INP_RUNLOCK(inp);
return (IPPROTO_DONE);
diff --git a/sys/netinet6/in6.c b/sys/netinet6/in6.c
index ce0655408a28..4f756a75fac7 100644
--- a/sys/netinet6/in6.c
+++ b/sys/netinet6/in6.c
@@ -1235,11 +1235,20 @@ in6_addifaddr(struct ifnet *ifp, struct in6_aliasreq *ifra, struct in6_ifaddr *i
int carp_attached = 0;
int error;
- /* Check if this interface is a bridge member */
- if (ifp->if_bridge && bridge_member_ifaddrs_p &&
- !bridge_member_ifaddrs_p()) {
- error = EINVAL;
- goto out;
+ /*
+ * Check if bridge wants to allow adding addrs to member interfaces.
+ */
+ if (ifp->if_bridge != NULL && ifp->if_type != IFT_GIF &&
+ bridge_member_ifaddrs_p != NULL) {
+ if (bridge_member_ifaddrs_p()) {
+ if_printf(ifp, "WARNING: Assigning an IP address to "
+ "an interface which is also a bridge member is "
+ "deprecated and will be unsupported in a future "
+ "release.\n");
+ } else {
+ error = EINVAL;
+ goto out;
+ }
}
/*
@@ -2618,6 +2627,8 @@ in6_domifdetach(struct ifnet *ifp, void *aux)
{
struct in6_ifextra *ext = (struct in6_ifextra *)aux;
+ MPASS(ifp->if_afdata[AF_INET6] == NULL);
+
mld_domifdetach(ifp);
scope6_ifdetach(ext->scope6_id);
nd6_ifdetach(ifp, ext->nd_ifinfo);
diff --git a/sys/netpfil/pf/if_pfsync.c b/sys/netpfil/pf/if_pfsync.c
index 585c196391c0..7b9405ee1f8d 100644
--- a/sys/netpfil/pf/if_pfsync.c
+++ b/sys/netpfil/pf/if_pfsync.c
@@ -605,7 +605,8 @@ pfsync_state_import(union pfsync_state_union *sp, int flags, int msg_version)
rt_kif = rpool_first->kif;
/*
* Guess the AF of the route address, FreeBSD 13 does
- * not support af-to so it should be safe.
+ * not support af-to nor prefer-ipv6-nexthop
+ * so it should be safe.
*/
rt_af = r->af;
} else if (!PF_AZERO(&sp->pfs_1301.rt_addr, sp->pfs_1301.af)) {
@@ -634,8 +635,9 @@ pfsync_state_import(union pfsync_state_union *sp, int flags, int msg_version)
}
rt = sp->pfs_1400.rt;
/*
- * Guess the AF of the route address, FreeBSD 13 does
- * not support af-to so it should be safe.
+ * Guess the AF of the route address, FreeBSD 14 does
+ * not support af-to nor prefer-ipv6-nexthop
+ * so it should be safe.
*/
rt_af = sp->pfs_1400.af;
}
@@ -1741,16 +1743,16 @@ pfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
if (ifr->ifr_cap_nv.length > IFR_CAP_NV_MAXBUFSIZE)
return (EINVAL);
- data = malloc(ifr->ifr_cap_nv.length, M_TEMP, M_WAITOK);
+ data = malloc(ifr->ifr_cap_nv.length, M_PF, M_WAITOK);
if ((error = copyin(ifr->ifr_cap_nv.buffer, data,
ifr->ifr_cap_nv.length)) != 0) {
- free(data, M_TEMP);
+ free(data, M_PF);
return (error);
}
if ((nvl = nvlist_unpack(data, ifr->ifr_cap_nv.length, 0)) == NULL) {
- free(data, M_TEMP);
+ free(data, M_PF);
return (EINVAL);
}
@@ -1758,7 +1760,7 @@ pfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
pfsync_nvstatus_to_kstatus(nvl, &status);
nvlist_destroy(nvl);
- free(data, M_TEMP);
+ free(data, M_PF);
error = pfsync_kstatus_to_softc(&status, sc);
return (error);
diff --git a/sys/netpfil/pf/pf.c b/sys/netpfil/pf/pf.c
index 8cd4fff95b15..242152f17db0 100644
--- a/sys/netpfil/pf/pf.c
+++ b/sys/netpfil/pf/pf.c
@@ -1667,7 +1667,6 @@ pf_state_key_addr_setup(struct pf_pdesc *pd,
#ifdef INET6
struct nd_neighbor_solicit nd;
struct pf_addr *target;
- u_short action, reason;
if (pd->af == AF_INET || pd->proto != IPPROTO_ICMPV6)
goto copy;
@@ -1676,7 +1675,8 @@ pf_state_key_addr_setup(struct pf_pdesc *pd,
case ND_NEIGHBOR_SOLICIT:
if (multi)
return (-1);
- if (!pf_pull_hdr(pd->m, pd->off, &nd, sizeof(nd), &action, &reason, pd->af))
+ if (!pf_pull_hdr(pd->m, pd->off, &nd, sizeof(nd), NULL,
+ NULL, pd->af))
return (-1);
target = (struct pf_addr *)&nd.nd_ns_target;
daddr = target;
@@ -1684,7 +1684,8 @@ pf_state_key_addr_setup(struct pf_pdesc *pd,
case ND_NEIGHBOR_ADVERT:
if (multi)
return (-1);
- if (!pf_pull_hdr(pd->m, pd->off, &nd, sizeof(nd), &action, &reason, pd->af))
+ if (!pf_pull_hdr(pd->m, pd->off, &nd, sizeof(nd), NULL,
+ NULL, pd->af))
return (-1);
target = (struct pf_addr *)&nd.nd_ns_target;
saddr = target;
@@ -3632,6 +3633,18 @@ pf_translate_af(struct pf_pdesc *pd)
pd->src = (struct pf_addr *)&ip4->ip_src;
pd->dst = (struct pf_addr *)&ip4->ip_dst;
pd->off = sizeof(struct ip);
+ if (pd->m->m_pkthdr.csum_flags & CSUM_TCP_IPV6) {
+ pd->m->m_pkthdr.csum_flags &= ~CSUM_TCP_IPV6;
+ pd->m->m_pkthdr.csum_flags |= CSUM_TCP;
+ }
+ if (pd->m->m_pkthdr.csum_flags & CSUM_UDP_IPV6) {
+ pd->m->m_pkthdr.csum_flags &= ~CSUM_UDP_IPV6;
+ pd->m->m_pkthdr.csum_flags |= CSUM_UDP;
+ }
+ if (pd->m->m_pkthdr.csum_flags & CSUM_SCTP_IPV6) {
+ pd->m->m_pkthdr.csum_flags &= ~CSUM_SCTP_IPV6;
+ pd->m->m_pkthdr.csum_flags |= CSUM_SCTP;
+ }
break;
case AF_INET6:
ip6 = mtod(pd->m, struct ip6_hdr *);
@@ -3649,6 +3662,18 @@ pf_translate_af(struct pf_pdesc *pd)
pd->src = (struct pf_addr *)&ip6->ip6_src;
pd->dst = (struct pf_addr *)&ip6->ip6_dst;
pd->off = sizeof(struct ip6_hdr);
+ if (pd->m->m_pkthdr.csum_flags & CSUM_TCP) {
+ pd->m->m_pkthdr.csum_flags &= ~CSUM_TCP;
+ pd->m->m_pkthdr.csum_flags |= CSUM_TCP_IPV6;
+ }
+ if (pd->m->m_pkthdr.csum_flags & CSUM_UDP) {
+ pd->m->m_pkthdr.csum_flags &= ~CSUM_UDP;
+ pd->m->m_pkthdr.csum_flags |= CSUM_UDP_IPV6;
+ }
+ if (pd->m->m_pkthdr.csum_flags & CSUM_SCTP) {
+ pd->m->m_pkthdr.csum_flags &= ~CSUM_SCTP;
+ pd->m->m_pkthdr.csum_flags |= CSUM_SCTP_IPV6;
+ }
/*
* If we're dealing with a reassembled packet we need to adjust
@@ -5960,7 +5985,9 @@ pf_test_rule(struct pf_krule **rm, struct pf_kstate **sm,
if (r->rt) {
/*
* Set act.rt here instead of in pf_rule_to_actions() because
- * it is applied only from the last pass rule.
+ * it is applied only from the last pass rule. For rules
+ * with the prefer-ipv6-nexthop option act.rt_af is a hint
+ * about AF of the forwarded packet and might be changed.
*/
pd->act.rt = r->rt;
if (r->rt == PF_REPLYTO)
@@ -8045,6 +8072,7 @@ pf_test_state_icmp(struct pf_kstate **state, struct pf_pdesc *pd,
return (PF_DROP);
pd2.tot_len = ntohs(h2.ip_len);
+ pd2.ttl = h2.ip_ttl;
pd2.src = (struct pf_addr *)&h2.ip_src;
pd2.dst = (struct pf_addr *)&h2.ip_dst;
pd2.ip_sum = &h2.ip_sum;
@@ -8067,6 +8095,7 @@ pf_test_state_icmp(struct pf_kstate **state, struct pf_pdesc *pd,
pd2.tot_len = ntohs(h2_6.ip6_plen) +
sizeof(struct ip6_hdr);
+ pd2.ttl = h2_6.ip6_hlim;
pd2.src = (struct pf_addr *)&h2_6.ip6_src;
pd2.dst = (struct pf_addr *)&h2_6.ip6_dst;
pd2.ip_sum = NULL;
@@ -8974,9 +9003,10 @@ pf_route(struct pf_krule *r, struct ifnet *oifp,
struct pf_kstate *s, struct pf_pdesc *pd, struct inpcb *inp)
{
struct mbuf *m0, *m1, *md;
- struct route ro;
- const struct sockaddr *gw = &ro.ro_dst;
- struct sockaddr_in *dst;
+ struct route_in6 ro;
+ union sockaddr_union rt_gw;
+ const union sockaddr_union *gw = (const union sockaddr_union *)&ro.ro_dst;
+ union sockaddr_union *dst;
struct ip *ip;
struct ifnet *ifp = NULL;
int error = 0;
@@ -9071,10 +9101,35 @@ pf_route(struct pf_krule *r, struct ifnet *oifp,
ip = mtod(m0, struct ip *);
bzero(&ro, sizeof(ro));
- dst = (struct sockaddr_in *)&ro.ro_dst;
- dst->sin_family = AF_INET;
- dst->sin_len = sizeof(struct sockaddr_in);
- dst->sin_addr.s_addr = pd->act.rt_addr.v4.s_addr;
+ dst = (union sockaddr_union *)&ro.ro_dst;
+ dst->sin.sin_family = AF_INET;
+ dst->sin.sin_len = sizeof(struct sockaddr_in);
+ dst->sin.sin_addr = ip->ip_dst;
+ if (ifp) { /* Only needed in forward direction and route-to */
+ bzero(&rt_gw, sizeof(rt_gw));
+ ro.ro_flags |= RT_HAS_GW;
+ gw = &rt_gw;
+ switch (pd->act.rt_af) {
+#ifdef INET
+ case AF_INET:
+ rt_gw.sin.sin_family = AF_INET;
+ rt_gw.sin.sin_len = sizeof(struct sockaddr_in);
+ rt_gw.sin.sin_addr.s_addr = pd->act.rt_addr.v4.s_addr;
+ break;
+#endif /* INET */
+#ifdef INET6
+ case AF_INET6:
+ rt_gw.sin6.sin6_family = AF_INET6;
+ rt_gw.sin6.sin6_len = sizeof(struct sockaddr_in6);
+ pf_addrcpy((struct pf_addr *)&rt_gw.sin6.sin6_addr,
+ &pd->act.rt_addr, AF_INET6);
+ break;
+#endif /* INET6 */
+ default:
+ /* Normal af-to without route-to */
+ break;
+ }
+ }
if (pd->dir == PF_IN) {
if (ip->ip_ttl <= IPTTLDEC) {
@@ -9098,10 +9153,10 @@ pf_route(struct pf_krule *r, struct ifnet *oifp,
/* Use the gateway if needed. */
if (nh->nh_flags & NHF_GATEWAY) {
- gw = &nh->gw_sa;
+ gw = (const union sockaddr_union *)&nh->gw_sa;
ro.ro_flags |= RT_HAS_GW;
} else {
- dst->sin_addr = ip->ip_dst;
+ dst->sin.sin_addr = ip->ip_dst;
}
/*
@@ -9126,6 +9181,9 @@ pf_route(struct pf_krule *r, struct ifnet *oifp,
PF_STATE_UNLOCK(s);
}
+ /* It must have been either set from rt_af or from fib4_lookup */
+ KASSERT(gw->sin.sin_family != 0, ("%s: gw address family undetermined", __func__));
+
if (ifp == NULL) {
m0 = pd->m;
pd->m = NULL;
@@ -9210,9 +9268,11 @@ pf_route(struct pf_krule *r, struct ifnet *oifp,
m_clrprotoflags(m0); /* Avoid confusing lower layers. */
md = m0;
- error = pf_dummynet_route(pd, s, r, ifp, gw, &md);
+ error = pf_dummynet_route(pd, s, r, ifp,
+ (const struct sockaddr *)gw, &md);
if (md != NULL) {
- error = (*ifp->if_output)(ifp, md, gw, &ro);
+ error = (*ifp->if_output)(ifp, md,
+ (const struct sockaddr *)gw, (struct route *)&ro);
SDT_PROBE2(pf, ip, route_to, output, ifp, error);
}
goto done;
@@ -9253,9 +9313,11 @@ pf_route(struct pf_krule *r, struct ifnet *oifp,
md = m0;
pd->pf_mtag = pf_find_mtag(md);
error = pf_dummynet_route(pd, s, r, ifp,
- gw, &md);
+ (const struct sockaddr *)gw, &md);
if (md != NULL) {
- error = (*ifp->if_output)(ifp, md, gw, &ro);
+ error = (*ifp->if_output)(ifp, md,
+ (const struct sockaddr *)gw,
+ (struct route *)&ro);
SDT_PROBE2(pf, ip, route_to, output, ifp, error);
}
} else
@@ -9962,9 +10024,12 @@ pf_walk_header(struct pf_pdesc *pd, struct ip *h, u_short *reason)
pd->proto = h->ip_p;
/* IGMP packets have router alert options, allow them */
if (pd->proto == IPPROTO_IGMP) {
- /* According to RFC 1112 ttl must be set to 1. */
- if ((h->ip_ttl != 1) ||
- !IN_MULTICAST(ntohl(h->ip_dst.s_addr))) {
+ /*
+ * According to RFC 1112 ttl must be set to 1 in all IGMP
+ * packets sent to 224.0.0.1
+ */
+ if ((h->ip_ttl != 1) &&
+ (h->ip_dst.s_addr == INADDR_ALLHOSTS_GROUP)) {
DPFPRINTF(PF_DEBUG_MISC, "Invalid IGMP");
REASON_SET(reason, PFRES_IPOPTIONS);
return (PF_DROP);
diff --git a/sys/netpfil/pf/pf.h b/sys/netpfil/pf/pf.h
index 51b3fd6390e1..8edd5a5110a1 100644
--- a/sys/netpfil/pf/pf.h
+++ b/sys/netpfil/pf/pf.h
@@ -131,6 +131,7 @@ enum { PF_ADDR_ADDRMASK, PF_ADDR_NOROUTE, PF_ADDR_DYNIFTL,
#define PF_POOL_TYPEMASK 0x0f
#define PF_POOL_STICKYADDR 0x20
#define PF_POOL_ENDPI 0x40
+#define PF_POOL_IPV6NH 0x80
#define PF_WSCALE_FLAG 0x80
#define PF_WSCALE_MASK 0x0f
diff --git a/sys/netpfil/pf/pf_ioctl.c b/sys/netpfil/pf/pf_ioctl.c
index e5da05a958f6..06c40a03f575 100644
--- a/sys/netpfil/pf/pf_ioctl.c
+++ b/sys/netpfil/pf/pf_ioctl.c
@@ -187,6 +187,7 @@ VNET_DEFINE(uma_zone_t, pf_tag_z);
#define V_pf_tag_z VNET(pf_tag_z)
static MALLOC_DEFINE(M_PFALTQ, "pf_altq", "pf(4) altq configuration db");
static MALLOC_DEFINE(M_PFRULE, "pf_rule", "pf(4) rules");
+MALLOC_DEFINE(M_PF, "pf", "pf(4)");
#if (PF_QNAME_SIZE != PF_TAG_NAME_SIZE)
#error PF_QNAME_SIZE must be equal to PF_TAG_NAME_SIZE
@@ -1181,18 +1182,18 @@ pf_rule_tree_alloc(int flags)
{
struct pf_krule_global *tree;
- tree = malloc(sizeof(struct pf_krule_global), M_TEMP, flags);
+ tree = malloc(sizeof(struct pf_krule_global), M_PF, flags);
if (tree == NULL)
return (NULL);
RB_INIT(tree);
return (tree);
}
-static void
+void
pf_rule_tree_free(struct pf_krule_global *tree)
{
- free(tree, M_TEMP);
+ free(tree, M_PF);
}
static int
@@ -1211,7 +1212,7 @@ pf_begin_rules(u_int32_t *ticket, int rs_num, const char *anchor)
return (ENOMEM);
rs = pf_find_or_create_kruleset(anchor);
if (rs == NULL) {
- free(tree, M_TEMP);
+ pf_rule_tree_free(tree);
return (EINVAL);
}
pf_rule_tree_free(rs->rules[rs_num].inactive.tree);
@@ -1432,7 +1433,7 @@ pf_commit_rules(u_int32_t ticket, int rs_num, char *anchor)
rs->rules[rs_num].inactive.rcount = 0;
rs->rules[rs_num].inactive.open = 0;
pf_remove_if_empty_kruleset(rs);
- free(old_tree, M_TEMP);
+ pf_rule_tree_free(old_tree);
return (0);
}
@@ -2276,6 +2277,7 @@ pf_ioctl_addrule(struct pf_krule *rule, uint32_t ticket,
rule->nat.cur = TAILQ_FIRST(&rule->nat.list);
rule->rdr.cur = TAILQ_FIRST(&rule->rdr.list);
rule->route.cur = TAILQ_FIRST(&rule->route.list);
+ rule->route.ipv6_nexthop_af = AF_INET6;
TAILQ_INSERT_TAIL(ruleset->rules[rs_num].inactive.ptr,
rule, entries);
ruleset->rules[rs_num].inactive.rcount++;
@@ -4076,7 +4078,7 @@ DIOCCHANGERULE_error:
out = ps->ps_states;
pstore = mallocarray(slice_count,
- sizeof(struct pfsync_state_1301), M_TEMP, M_WAITOK | M_ZERO);
+ sizeof(struct pfsync_state_1301), M_PF, M_WAITOK | M_ZERO);
nr = 0;
for (i = 0; i <= V_pf_hashmask; i++) {
@@ -4098,10 +4100,10 @@ DIOCGETSTATES_retry:
if (count > slice_count) {
PF_HASHROW_UNLOCK(ih);
- free(pstore, M_TEMP);
+ free(pstore, M_PF);
slice_count = count * 2;
pstore = mallocarray(slice_count,
- sizeof(struct pfsync_state_1301), M_TEMP,
+ sizeof(struct pfsync_state_1301), M_PF,
M_WAITOK | M_ZERO);
goto DIOCGETSTATES_retry;
}
@@ -4123,13 +4125,15 @@ DIOCGETSTATES_retry:
PF_HASHROW_UNLOCK(ih);
error = copyout(pstore, out,
sizeof(struct pfsync_state_1301) * count);
- if (error)
+ if (error) {
+ free(pstore, M_PF);
goto fail;
+ }
out = ps->ps_states + nr;
}
DIOCGETSTATES_full:
ps->ps_len = sizeof(struct pfsync_state_1301) * nr;
- free(pstore, M_TEMP);
+ free(pstore, M_PF);
break;
}
@@ -4155,7 +4159,7 @@ DIOCGETSTATES_full:
out = ps->ps_states;
pstore = mallocarray(slice_count,
- sizeof(struct pf_state_export), M_TEMP, M_WAITOK | M_ZERO);
+ sizeof(struct pf_state_export), M_PF, M_WAITOK | M_ZERO);
nr = 0;
for (i = 0; i <= V_pf_hashmask; i++) {
@@ -4177,10 +4181,10 @@ DIOCGETSTATESV2_retry:
if (count > slice_count) {
PF_HASHROW_UNLOCK(ih);
- free(pstore, M_TEMP);
+ free(pstore, M_PF);
slice_count = count * 2;
pstore = mallocarray(slice_count,
- sizeof(struct pf_state_export), M_TEMP,
+ sizeof(struct pf_state_export), M_PF,
M_WAITOK | M_ZERO);
goto DIOCGETSTATESV2_retry;
}
@@ -4201,13 +4205,15 @@ DIOCGETSTATESV2_retry:
PF_HASHROW_UNLOCK(ih);
error = copyout(pstore, out,
sizeof(struct pf_state_export) * count);
- if (error)
+ if (error) {
+ free(pstore, M_PF);
goto fail;
+ }
out = ps->ps_states + nr;
}
DIOCGETSTATESV2_full:
ps->ps_len = nr * sizeof(struct pf_state_export);
- free(pstore, M_TEMP);
+ free(pstore, M_PF);
break;
}
@@ -4737,17 +4743,17 @@ DIOCCHANGEADDR_error:
totlen = io->pfrio_size * sizeof(struct pfr_table);
pfrts = mallocarray(io->pfrio_size, sizeof(struct pfr_table),
- M_TEMP, M_WAITOK);
+ M_PF, M_WAITOK);
error = copyin(io->pfrio_buffer, pfrts, totlen);
if (error) {
- free(pfrts, M_TEMP);
+ free(pfrts, M_PF);
goto fail;
}
PF_RULES_WLOCK();
error = pfr_add_tables(pfrts, io->pfrio_size,
&io->pfrio_nadd, io->pfrio_flags | PFR_FLAG_USERIOCTL);
PF_RULES_WUNLOCK();
- free(pfrts, M_TEMP);
+ free(pfrts, M_PF);
break;
}
@@ -4769,17 +4775,17 @@ DIOCCHANGEADDR_error:
totlen = io->pfrio_size * sizeof(struct pfr_table);
pfrts = mallocarray(io->pfrio_size, sizeof(struct pfr_table),
- M_TEMP, M_WAITOK);
+ M_PF, M_WAITOK);
error = copyin(io->pfrio_buffer, pfrts, totlen);
if (error) {
- free(pfrts, M_TEMP);
+ free(pfrts, M_PF);
goto fail;
}
PF_RULES_WLOCK();
error = pfr_del_tables(pfrts, io->pfrio_size,
&io->pfrio_ndel, io->pfrio_flags | PFR_FLAG_USERIOCTL);
PF_RULES_WUNLOCK();
- free(pfrts, M_TEMP);
+ free(pfrts, M_PF);
break;
}
@@ -4805,7 +4811,7 @@ DIOCCHANGEADDR_error:
totlen = io->pfrio_size * sizeof(struct pfr_table);
pfrts = mallocarray(io->pfrio_size, sizeof(struct pfr_table),
- M_TEMP, M_NOWAIT | M_ZERO);
+ M_PF, M_NOWAIT | M_ZERO);
if (pfrts == NULL) {
error = ENOMEM;
PF_RULES_RUNLOCK();
@@ -4816,7 +4822,7 @@ DIOCCHANGEADDR_error:
PF_RULES_RUNLOCK();
if (error == 0)
error = copyout(pfrts, io->pfrio_buffer, totlen);
- free(pfrts, M_TEMP);
+ free(pfrts, M_PF);
break;
}
@@ -4843,7 +4849,7 @@ DIOCCHANGEADDR_error:
totlen = io->pfrio_size * sizeof(struct pfr_tstats);
pfrtstats = mallocarray(io->pfrio_size,
- sizeof(struct pfr_tstats), M_TEMP, M_NOWAIT | M_ZERO);
+ sizeof(struct pfr_tstats), M_PF, M_NOWAIT | M_ZERO);
if (pfrtstats == NULL) {
error = ENOMEM;
PF_RULES_RUNLOCK();
@@ -4856,7 +4862,7 @@ DIOCCHANGEADDR_error:
PF_TABLE_STATS_UNLOCK();
if (error == 0)
error = copyout(pfrtstats, io->pfrio_buffer, totlen);
- free(pfrtstats, M_TEMP);
+ free(pfrtstats, M_PF);
break;
}
@@ -4881,10 +4887,10 @@ DIOCCHANGEADDR_error:
totlen = io->pfrio_size * sizeof(struct pfr_table);
pfrts = mallocarray(io->pfrio_size, sizeof(struct pfr_table),
- M_TEMP, M_WAITOK);
+ M_PF, M_WAITOK);
error = copyin(io->pfrio_buffer, pfrts, totlen);
if (error) {
- free(pfrts, M_TEMP);
+ free(pfrts, M_PF);
goto fail;
}
@@ -4894,7 +4900,7 @@ DIOCCHANGEADDR_error:
&io->pfrio_nzero, io->pfrio_flags | PFR_FLAG_USERIOCTL);
PF_RULES_RUNLOCK();
PF_TABLE_STATS_UNLOCK();
- free(pfrts, M_TEMP);
+ free(pfrts, M_PF);
break;
}
@@ -4922,10 +4928,10 @@ DIOCCHANGEADDR_error:
totlen = io->pfrio_size * sizeof(struct pfr_table);
pfrts = mallocarray(io->pfrio_size, sizeof(struct pfr_table),
- M_TEMP, M_WAITOK);
+ M_PF, M_WAITOK);
error = copyin(io->pfrio_buffer, pfrts, totlen);
if (error) {
- free(pfrts, M_TEMP);
+ free(pfrts, M_PF);
goto fail;
}
PF_RULES_WLOCK();
@@ -4933,7 +4939,7 @@ DIOCCHANGEADDR_error:
io->pfrio_setflag, io->pfrio_clrflag, &io->pfrio_nchange,
&io->pfrio_ndel, io->pfrio_flags | PFR_FLAG_USERIOCTL);
PF_RULES_WUNLOCK();
- free(pfrts, M_TEMP);
+ free(pfrts, M_PF);
break;
}
@@ -4968,10 +4974,10 @@ DIOCCHANGEADDR_error:
}
totlen = io->pfrio_size * sizeof(struct pfr_addr);
pfras = mallocarray(io->pfrio_size, sizeof(struct pfr_addr),
- M_TEMP, M_WAITOK);
+ M_PF, M_WAITOK);
error = copyin(io->pfrio_buffer, pfras, totlen);
if (error) {
- free(pfras, M_TEMP);
+ free(pfras, M_PF);
goto fail;
}
PF_RULES_WLOCK();
@@ -4982,7 +4988,7 @@ DIOCCHANGEADDR_error:
PF_RULES_WUNLOCK();
if (error == 0 && io->pfrio_flags & PFR_FLAG_FEEDBACK)
error = copyout(pfras, io->pfrio_buffer, totlen);
- free(pfras, M_TEMP);
+ free(pfras, M_PF);
break;
}
@@ -5003,10 +5009,10 @@ DIOCCHANGEADDR_error:
}
totlen = io->pfrio_size * sizeof(struct pfr_addr);
pfras = mallocarray(io->pfrio_size, sizeof(struct pfr_addr),
- M_TEMP, M_WAITOK);
+ M_PF, M_WAITOK);
error = copyin(io->pfrio_buffer, pfras, totlen);
if (error) {
- free(pfras, M_TEMP);
+ free(pfras, M_PF);
goto fail;
}
PF_RULES_WLOCK();
@@ -5016,7 +5022,7 @@ DIOCCHANGEADDR_error:
PF_RULES_WUNLOCK();
if (error == 0 && io->pfrio_flags & PFR_FLAG_FEEDBACK)
error = copyout(pfras, io->pfrio_buffer, totlen);
- free(pfras, M_TEMP);
+ free(pfras, M_PF);
break;
}
@@ -5040,11 +5046,11 @@ DIOCCHANGEADDR_error:
goto fail;
}
totlen = count * sizeof(struct pfr_addr);
- pfras = mallocarray(count, sizeof(struct pfr_addr), M_TEMP,
+ pfras = mallocarray(count, sizeof(struct pfr_addr), M_PF,
M_WAITOK);
error = copyin(io->pfrio_buffer, pfras, totlen);
if (error) {
- free(pfras, M_TEMP);
+ free(pfras, M_PF);
goto fail;
}
PF_RULES_WLOCK();
@@ -5055,7 +5061,7 @@ DIOCCHANGEADDR_error:
PF_RULES_WUNLOCK();
if (error == 0 && io->pfrio_flags & PFR_FLAG_FEEDBACK)
error = copyout(pfras, io->pfrio_buffer, totlen);
- free(pfras, M_TEMP);
+ free(pfras, M_PF);
break;
}
@@ -5076,14 +5082,14 @@ DIOCCHANGEADDR_error:
}
totlen = io->pfrio_size * sizeof(struct pfr_addr);
pfras = mallocarray(io->pfrio_size, sizeof(struct pfr_addr),
- M_TEMP, M_WAITOK | M_ZERO);
+ M_PF, M_WAITOK | M_ZERO);
PF_RULES_RLOCK();
error = pfr_get_addrs(&io->pfrio_table, pfras,
&io->pfrio_size, io->pfrio_flags | PFR_FLAG_USERIOCTL);
PF_RULES_RUNLOCK();
if (error == 0)
error = copyout(pfras, io->pfrio_buffer, totlen);
- free(pfras, M_TEMP);
+ free(pfras, M_PF);
break;
}
@@ -5104,14 +5110,14 @@ DIOCCHANGEADDR_error:
}
totlen = io->pfrio_size * sizeof(struct pfr_astats);
pfrastats = mallocarray(io->pfrio_size,
- sizeof(struct pfr_astats), M_TEMP, M_WAITOK | M_ZERO);
+ sizeof(struct pfr_astats), M_PF, M_WAITOK | M_ZERO);
PF_RULES_RLOCK();
error = pfr_get_astats(&io->pfrio_table, pfrastats,
&io->pfrio_size, io->pfrio_flags | PFR_FLAG_USERIOCTL);
PF_RULES_RUNLOCK();
if (error == 0)
error = copyout(pfrastats, io->pfrio_buffer, totlen);
- free(pfrastats, M_TEMP);
+ free(pfrastats, M_PF);
break;
}
@@ -5132,10 +5138,10 @@ DIOCCHANGEADDR_error:
}
totlen = io->pfrio_size * sizeof(struct pfr_addr);
pfras = mallocarray(io->pfrio_size, sizeof(struct pfr_addr),
- M_TEMP, M_WAITOK);
+ M_PF, M_WAITOK);
error = copyin(io->pfrio_buffer, pfras, totlen);
if (error) {
- free(pfras, M_TEMP);
+ free(pfras, M_PF);
goto fail;
}
PF_RULES_WLOCK();
@@ -5145,7 +5151,7 @@ DIOCCHANGEADDR_error:
PF_RULES_WUNLOCK();
if (error == 0 && io->pfrio_flags & PFR_FLAG_FEEDBACK)
error = copyout(pfras, io->pfrio_buffer, totlen);
- free(pfras, M_TEMP);
+ free(pfras, M_PF);
break;
}
@@ -5166,10 +5172,10 @@ DIOCCHANGEADDR_error:
}
totlen = io->pfrio_size * sizeof(struct pfr_addr);
pfras = mallocarray(io->pfrio_size, sizeof(struct pfr_addr),
- M_TEMP, M_WAITOK);
+ M_PF, M_WAITOK);
error = copyin(io->pfrio_buffer, pfras, totlen);
if (error) {
- free(pfras, M_TEMP);
+ free(pfras, M_PF);
goto fail;
}
PF_RULES_RLOCK();
@@ -5179,7 +5185,7 @@ DIOCCHANGEADDR_error:
PF_RULES_RUNLOCK();
if (error == 0)
error = copyout(pfras, io->pfrio_buffer, totlen);
- free(pfras, M_TEMP);
+ free(pfras, M_PF);
break;
}
@@ -5200,10 +5206,10 @@ DIOCCHANGEADDR_error:
}
totlen = io->pfrio_size * sizeof(struct pfr_addr);
pfras = mallocarray(io->pfrio_size, sizeof(struct pfr_addr),
- M_TEMP, M_WAITOK);
+ M_PF, M_WAITOK);
error = copyin(io->pfrio_buffer, pfras, totlen);
if (error) {
- free(pfras, M_TEMP);
+ free(pfras, M_PF);
goto fail;
}
PF_RULES_WLOCK();
@@ -5211,7 +5217,7 @@ DIOCCHANGEADDR_error:
io->pfrio_size, &io->pfrio_nadd, &io->pfrio_naddr,
io->pfrio_ticket, io->pfrio_flags | PFR_FLAG_USERIOCTL);
PF_RULES_WUNLOCK();
- free(pfras, M_TEMP);
+ free(pfras, M_PF);
break;
}
@@ -5249,10 +5255,10 @@ DIOCCHANGEADDR_error:
}
totlen = sizeof(struct pfioc_trans_e) * io->size;
ioes = mallocarray(io->size, sizeof(struct pfioc_trans_e),
- M_TEMP, M_WAITOK);
+ M_PF, M_WAITOK);
error = copyin(io->array, ioes, totlen);
if (error) {
- free(ioes, M_TEMP);
+ free(ioes, M_PF);
goto fail;
}
PF_RULES_WLOCK();
@@ -5262,7 +5268,7 @@ DIOCCHANGEADDR_error:
case PF_RULESET_ETH:
if ((error = pf_begin_eth(&ioe->ticket, ioe->anchor))) {
PF_RULES_WUNLOCK();
- free(ioes, M_TEMP);
+ free(ioes, M_PF);
goto fail;
}
break;
@@ -5270,13 +5276,13 @@ DIOCCHANGEADDR_error:
case PF_RULESET_ALTQ:
if (ioe->anchor[0]) {
PF_RULES_WUNLOCK();
- free(ioes, M_TEMP);
+ free(ioes, M_PF);
error = EINVAL;
goto fail;
}
if ((error = pf_begin_altq(&ioe->ticket))) {
PF_RULES_WUNLOCK();
- free(ioes, M_TEMP);
+ free(ioes, M_PF);
goto fail;
}
break;
@@ -5291,7 +5297,7 @@ DIOCCHANGEADDR_error:
if ((error = pfr_ina_begin(&table,
&ioe->ticket, NULL, 0))) {
PF_RULES_WUNLOCK();
- free(ioes, M_TEMP);
+ free(ioes, M_PF);
goto fail;
}
break;
@@ -5300,7 +5306,7 @@ DIOCCHANGEADDR_error:
if ((error = pf_begin_rules(&ioe->ticket,
ioe->rs_num, ioe->anchor))) {
PF_RULES_WUNLOCK();
- free(ioes, M_TEMP);
+ free(ioes, M_PF);
goto fail;
}
break;
@@ -5308,7 +5314,7 @@ DIOCCHANGEADDR_error:
}
PF_RULES_WUNLOCK();
error = copyout(ioes, io->array, totlen);
- free(ioes, M_TEMP);
+ free(ioes, M_PF);
break;
}
@@ -5330,10 +5336,10 @@ DIOCCHANGEADDR_error:
}
totlen = sizeof(struct pfioc_trans_e) * io->size;
ioes = mallocarray(io->size, sizeof(struct pfioc_trans_e),
- M_TEMP, M_WAITOK);
+ M_PF, M_WAITOK);
error = copyin(io->array, ioes, totlen);
if (error) {
- free(ioes, M_TEMP);
+ free(ioes, M_PF);
goto fail;
}
PF_RULES_WLOCK();
@@ -5344,7 +5350,7 @@ DIOCCHANGEADDR_error:
if ((error = pf_rollback_eth(ioe->ticket,
ioe->anchor))) {
PF_RULES_WUNLOCK();
- free(ioes, M_TEMP);
+ free(ioes, M_PF);
goto fail; /* really bad */
}
break;
@@ -5352,13 +5358,13 @@ DIOCCHANGEADDR_error:
case PF_RULESET_ALTQ:
if (ioe->anchor[0]) {
PF_RULES_WUNLOCK();
- free(ioes, M_TEMP);
+ free(ioes, M_PF);
error = EINVAL;
goto fail;
}
if ((error = pf_rollback_altq(ioe->ticket))) {
PF_RULES_WUNLOCK();
- free(ioes, M_TEMP);
+ free(ioes, M_PF);
goto fail; /* really bad */
}
break;
@@ -5373,7 +5379,7 @@ DIOCCHANGEADDR_error:
if ((error = pfr_ina_rollback(&table,
ioe->ticket, NULL, 0))) {
PF_RULES_WUNLOCK();
- free(ioes, M_TEMP);
+ free(ioes, M_PF);
goto fail; /* really bad */
}
break;
@@ -5382,14 +5388,14 @@ DIOCCHANGEADDR_error:
if ((error = pf_rollback_rules(ioe->ticket,
ioe->rs_num, ioe->anchor))) {
PF_RULES_WUNLOCK();
- free(ioes, M_TEMP);
+ free(ioes, M_PF);
goto fail; /* really bad */
}
break;
}
}
PF_RULES_WUNLOCK();
- free(ioes, M_TEMP);
+ free(ioes, M_PF);
break;
}
@@ -5415,10 +5421,10 @@ DIOCCHANGEADDR_error:
totlen = sizeof(struct pfioc_trans_e) * io->size;
ioes = mallocarray(io->size, sizeof(struct pfioc_trans_e),
- M_TEMP, M_WAITOK);
+ M_PF, M_WAITOK);
error = copyin(io->array, ioes, totlen);
if (error) {
- free(ioes, M_TEMP);
+ free(ioes, M_PF);
goto fail;
}
PF_RULES_WLOCK();
@@ -5431,7 +5437,7 @@ DIOCCHANGEADDR_error:
if (ers == NULL || ioe->ticket == 0 ||
ioe->ticket != ers->inactive.ticket) {
PF_RULES_WUNLOCK();
- free(ioes, M_TEMP);
+ free(ioes, M_PF);
error = EINVAL;
goto fail;
}
@@ -5440,14 +5446,14 @@ DIOCCHANGEADDR_error:
case PF_RULESET_ALTQ:
if (ioe->anchor[0]) {
PF_RULES_WUNLOCK();
- free(ioes, M_TEMP);
+ free(ioes, M_PF);
error = EINVAL;
goto fail;
}
if (!V_altqs_inactive_open || ioe->ticket !=
V_ticket_altqs_inactive) {
PF_RULES_WUNLOCK();
- free(ioes, M_TEMP);
+ free(ioes, M_PF);
error = EBUSY;
goto fail;
}
@@ -5458,7 +5464,7 @@ DIOCCHANGEADDR_error:
if (rs == NULL || !rs->topen || ioe->ticket !=
rs->tticket) {
PF_RULES_WUNLOCK();
- free(ioes, M_TEMP);
+ free(ioes, M_PF);
error = EBUSY;
goto fail;
}
@@ -5467,7 +5473,7 @@ DIOCCHANGEADDR_error:
if (ioe->rs_num < 0 || ioe->rs_num >=
PF_RULESET_MAX) {
PF_RULES_WUNLOCK();
- free(ioes, M_TEMP);
+ free(ioes, M_PF);
error = EINVAL;
goto fail;
}
@@ -5477,7 +5483,7 @@ DIOCCHANGEADDR_error:
rs->rules[ioe->rs_num].inactive.ticket !=
ioe->ticket) {
PF_RULES_WUNLOCK();
- free(ioes, M_TEMP);
+ free(ioes, M_PF);
error = EBUSY;
goto fail;
}
@@ -5490,7 +5496,7 @@ DIOCCHANGEADDR_error:
case PF_RULESET_ETH:
if ((error = pf_commit_eth(ioe->ticket, ioe->anchor))) {
PF_RULES_WUNLOCK();
- free(ioes, M_TEMP);
+ free(ioes, M_PF);
goto fail; /* really bad */
}
break;
@@ -5498,7 +5504,7 @@ DIOCCHANGEADDR_error:
case PF_RULESET_ALTQ:
if ((error = pf_commit_altq(ioe->ticket))) {
PF_RULES_WUNLOCK();
- free(ioes, M_TEMP);
+ free(ioes, M_PF);
goto fail; /* really bad */
}
break;
@@ -5513,7 +5519,7 @@ DIOCCHANGEADDR_error:
if ((error = pfr_ina_commit(&table,
ioe->ticket, NULL, NULL, 0))) {
PF_RULES_WUNLOCK();
- free(ioes, M_TEMP);
+ free(ioes, M_PF);
goto fail; /* really bad */
}
break;
@@ -5522,7 +5528,7 @@ DIOCCHANGEADDR_error:
if ((error = pf_commit_rules(ioe->ticket,
ioe->rs_num, ioe->anchor))) {
PF_RULES_WUNLOCK();
- free(ioes, M_TEMP);
+ free(ioes, M_PF);
goto fail; /* really bad */
}
break;
@@ -5536,7 +5542,7 @@ DIOCCHANGEADDR_error:
else
dehook_pf_eth();
- free(ioes, M_TEMP);
+ free(ioes, M_PF);
break;
}
@@ -5565,7 +5571,7 @@ DIOCCHANGEADDR_error:
nr = 0;
- p = pstore = malloc(psn->psn_len, M_TEMP, M_WAITOK | M_ZERO);
+ p = pstore = malloc(psn->psn_len, M_PF, M_WAITOK | M_ZERO);
for (i = 0, sh = V_pf_srchash; i <= V_pf_srchashmask;
i++, sh++) {
PF_HASHROW_LOCK(sh);
@@ -5584,11 +5590,11 @@ DIOCCHANGEADDR_error:
error = copyout(pstore, psn->psn_src_nodes,
sizeof(struct pf_src_node) * nr);
if (error) {
- free(pstore, M_TEMP);
+ free(pstore, M_PF);
goto fail;
}
psn->psn_len = sizeof(struct pf_src_node) * nr;
- free(pstore, M_TEMP);
+ free(pstore, M_PF);
break;
}
@@ -5655,13 +5661,13 @@ DIOCCHANGEADDR_error:
bufsiz = io->pfiio_size * sizeof(struct pfi_kif);
ifstore = mallocarray(io->pfiio_size, sizeof(struct pfi_kif),
- M_TEMP, M_WAITOK | M_ZERO);
+ M_PF, M_WAITOK | M_ZERO);
PF_RULES_RLOCK();
pfi_get_ifaces(io->pfiio_name, ifstore, &io->pfiio_size);
PF_RULES_RUNLOCK();
error = copyout(ifstore, io->pfiio_buffer, bufsiz);
- free(ifstore, M_TEMP);
+ free(ifstore, M_PF);
break;
}
diff --git a/sys/netpfil/pf/pf_lb.c b/sys/netpfil/pf/pf_lb.c
index bc9e1dc72902..b8b5157c9b15 100644
--- a/sys/netpfil/pf/pf_lb.c
+++ b/sys/netpfil/pf/pf_lb.c
@@ -545,11 +545,18 @@ pf_map_addr(sa_family_t saf, struct pf_krule *r, struct pf_addr *saddr,
uint64_t hashidx;
int cnt;
sa_family_t wanted_af;
+ u_int8_t pool_type;
+ bool prefer_ipv6_nexthop = rpool->opts & PF_POOL_IPV6NH;
KASSERT(saf != 0, ("%s: saf == 0", __func__));
KASSERT(naf != NULL, ("%s: naf = NULL", __func__));
KASSERT((*naf) != 0, ("%s: *naf = 0", __func__));
+ /*
+ * Given (*naf) is a hint about AF of the forwarded packet.
+ * It might be changed if prefer_ipv6_nexthop is enabled and
+ * the combination of nexthop AF and packet AF allows for it.
+ */
wanted_af = (*naf);
mtx_lock(&rpool->mtx);
@@ -594,19 +601,38 @@ pf_map_addr(sa_family_t saf, struct pf_krule *r, struct pf_addr *saddr,
} else {
raddr = &rpool->cur->addr.v.a.addr;
rmask = &rpool->cur->addr.v.a.mask;
- /*
- * For single addresses check their address family. Unless they
- * have none, which happens when addresses are added with
- * the old ioctl mechanism. In such case trust that the address
- * has the proper AF.
- */
- if (rpool->cur->af && rpool->cur->af != wanted_af) {
- reason = PFRES_MAPFAILED;
- goto done_pool_mtx;
+ }
+
+ /*
+ * For pools with a single host with the prefer-ipv6-nexthop option
+ * we can return pool address of any AF, unless the forwarded packet
+ * is IPv6, then we can return only if pool address is IPv6.
+ * For non-prefer-ipv6-nexthop we can return pool address only
+ * of wanted AF, unless the pool address'es AF is unknown, which
+ * happens in case old ioctls have been used to set up the pool.
+ *
+ * Round-robin pools have their own logic for retrying next addresses.
+ */
+ pool_type = rpool->opts & PF_POOL_TYPEMASK;
+ if (pool_type == PF_POOL_NONE || pool_type == PF_POOL_BITMASK ||
+ ((pool_type == PF_POOL_RANDOM || pool_type == PF_POOL_SRCHASH) &&
+ rpool->cur->addr.type != PF_ADDR_TABLE &&
+ rpool->cur->addr.type != PF_ADDR_DYNIFTL)) {
+ if (prefer_ipv6_nexthop) {
+ if (rpool->cur->af == AF_INET && (*naf) == AF_INET6) {
+ reason = PFRES_MAPFAILED;
+ goto done_pool_mtx;
+ }
+ wanted_af = rpool->cur->af;
+ } else {
+ if (rpool->cur->af != 0 && rpool->cur->af != (*naf)) {
+ reason = PFRES_MAPFAILED;
+ goto done_pool_mtx;
+ }
}
}
- switch (rpool->opts & PF_POOL_TYPEMASK) {
+ switch (pool_type) {
case PF_POOL_NONE:
pf_addrcpy(naddr, raddr, wanted_af);
break;
@@ -631,10 +657,22 @@ pf_map_addr(sa_family_t saf, struct pf_krule *r, struct pf_addr *saddr,
else
rpool->tblidx = (int)arc4random_uniform(cnt);
memset(&rpool->counter, 0, sizeof(rpool->counter));
+ if (prefer_ipv6_nexthop)
+ wanted_af = AF_INET6;
+ retry_other_af_random:
if (pfr_pool_get(kt, &rpool->tblidx, &rpool->counter,
wanted_af, pf_islinklocal, false)) {
- reason = PFRES_MAPFAILED;
- goto done_pool_mtx; /* unsupported */
+ /* Retry with IPv4 nexthop for IPv4 traffic */
+ if (prefer_ipv6_nexthop &&
+ wanted_af == AF_INET6 &&
+ (*naf) == AF_INET) {
+ wanted_af = AF_INET;
+ goto retry_other_af_random;
+ } else {
+ /* no hosts in wanted AF */
+ reason = PFRES_MAPFAILED;
+ goto done_pool_mtx;
+ }
}
pf_addrcpy(naddr, &rpool->counter, wanted_af);
} else if (init_addr != NULL && PF_AZERO(init_addr,
@@ -702,10 +740,22 @@ pf_map_addr(sa_family_t saf, struct pf_krule *r, struct pf_addr *saddr,
else
rpool->tblidx = (int)(hashidx % cnt);
memset(&rpool->counter, 0, sizeof(rpool->counter));
+ if (prefer_ipv6_nexthop)
+ wanted_af = AF_INET6;
+ retry_other_af_srchash:
if (pfr_pool_get(kt, &rpool->tblidx, &rpool->counter,
wanted_af, pf_islinklocal, false)) {
- reason = PFRES_MAPFAILED;
- goto done_pool_mtx; /* unsupported */
+ /* Retry with IPv4 nexthop for IPv4 traffic */
+ if (prefer_ipv6_nexthop &&
+ wanted_af == AF_INET6 &&
+ (*naf) == AF_INET) {
+ wanted_af = AF_INET;
+ goto retry_other_af_srchash;
+ } else {
+ /* no hosts in wanted AF */
+ reason = PFRES_MAPFAILED;
+ goto done_pool_mtx;
+ }
}
pf_addrcpy(naddr, &rpool->counter, wanted_af);
} else {
@@ -718,6 +768,9 @@ pf_map_addr(sa_family_t saf, struct pf_krule *r, struct pf_addr *saddr,
{
struct pf_kpooladdr *acur = rpool->cur;
+ retry_other_af_rr:
+ if (prefer_ipv6_nexthop)
+ wanted_af = rpool->ipv6_nexthop_af;
if (rpool->cur->addr.type == PF_ADDR_TABLE) {
if (!pfr_pool_get(rpool->cur->addr.p.tbl,
&rpool->tblidx, &rpool->counter, wanted_af,
@@ -728,46 +781,55 @@ pf_map_addr(sa_family_t saf, struct pf_krule *r, struct pf_addr *saddr,
&rpool->tblidx, &rpool->counter, wanted_af,
pf_islinklocal, true))
goto get_addr;
- } else if (pf_match_addr(0, raddr, rmask, &rpool->counter,
- wanted_af))
+ } else if (rpool->cur->af == wanted_af &&
+ pf_match_addr(0, raddr, rmask, &rpool->counter, wanted_af))
goto get_addr;
-
+ if (prefer_ipv6_nexthop &&
+ (*naf) == AF_INET && wanted_af == AF_INET6) {
+ /* Reset table index when changing wanted AF. */
+ rpool->tblidx = -1;
+ rpool->ipv6_nexthop_af = AF_INET;
+ goto retry_other_af_rr;
+ }
try_next:
+ /* Reset prefer-ipv6-nexthop search to IPv6 when iterating pools. */
+ rpool->ipv6_nexthop_af = AF_INET6;
if (TAILQ_NEXT(rpool->cur, entries) == NULL)
rpool->cur = TAILQ_FIRST(&rpool->list);
else
rpool->cur = TAILQ_NEXT(rpool->cur, entries);
+ try_next_ipv6_nexthop_rr:
+ /* Reset table index when iterating pools or changing wanted AF. */
rpool->tblidx = -1;
+ if (prefer_ipv6_nexthop)
+ wanted_af = rpool->ipv6_nexthop_af;
if (rpool->cur->addr.type == PF_ADDR_TABLE) {
- if (pfr_pool_get(rpool->cur->addr.p.tbl,
+ if (!pfr_pool_get(rpool->cur->addr.p.tbl,
&rpool->tblidx, &rpool->counter, wanted_af, NULL,
- true)) {
- /* table contains no address of type 'wanted_af' */
- if (rpool->cur != acur)
- goto try_next;
- reason = PFRES_MAPFAILED;
- goto done_pool_mtx;
- }
+ true))
+ goto get_addr;
} else if (rpool->cur->addr.type == PF_ADDR_DYNIFTL) {
- if (pfr_pool_get(rpool->cur->addr.p.dyn->pfid_kt,
- &rpool->tblidx, &rpool->counter, wanted_af,
- pf_islinklocal, true)) {
- /* interface has no address of type 'wanted_af' */
- if (rpool->cur != acur)
- goto try_next;
- reason = PFRES_MAPFAILED;
- goto done_pool_mtx;
- }
+ if (!pfr_pool_get(rpool->cur->addr.p.dyn->pfid_kt,
+ &rpool->tblidx, &rpool->counter, wanted_af, pf_islinklocal,
+ true))
+ goto get_addr;
} else {
- raddr = &rpool->cur->addr.v.a.addr;
- rmask = &rpool->cur->addr.v.a.mask;
- if (rpool->cur->af && rpool->cur->af != wanted_af) {
- reason = PFRES_MAPFAILED;
- goto done_pool_mtx;
+ if (rpool->cur->af == wanted_af) {
+ raddr = &rpool->cur->addr.v.a.addr;
+ rmask = &rpool->cur->addr.v.a.mask;
+ pf_addrcpy(&rpool->counter, raddr, wanted_af);
+ goto get_addr;
}
- pf_addrcpy(&rpool->counter, raddr, wanted_af);
}
-
+ if (prefer_ipv6_nexthop &&
+ (*naf) == AF_INET && wanted_af == AF_INET6) {
+ rpool->ipv6_nexthop_af = AF_INET;
+ goto try_next_ipv6_nexthop_rr;
+ }
+ if (rpool->cur != acur)
+ goto try_next;
+ reason = PFRES_MAPFAILED;
+ goto done_pool_mtx;
get_addr:
pf_addrcpy(naddr, &rpool->counter, wanted_af);
if (init_addr != NULL && PF_AZERO(init_addr, wanted_af))
@@ -777,9 +839,16 @@ pf_map_addr(sa_family_t saf, struct pf_krule *r, struct pf_addr *saddr,
}
}
+ if (wanted_af == 0) {
+ reason = PFRES_MAPFAILED;
+ goto done_pool_mtx;
+ }
+
if (nkif)
*nkif = rpool->cur->kif;
+ (*naf) = wanted_af;
+
done_pool_mtx:
mtx_unlock(&rpool->mtx);
diff --git a/sys/netpfil/pf/pf_nl.c b/sys/netpfil/pf/pf_nl.c
index 45b5b8dd5fef..73f018db0266 100644
--- a/sys/netpfil/pf/pf_nl.c
+++ b/sys/netpfil/pf/pf_nl.c
@@ -763,6 +763,8 @@ static const struct nlattr_parser nla_p_rule[] = {
{ .type = PF_RT_RCV_IFNOT, .off = _OUT(rcvifnot), .cb = nlattr_get_bool },
{ .type = PF_RT_PKTRATE, .off = _OUT(pktrate), .arg = &threshold_parser, .cb = nlattr_get_nested },
{ .type = PF_RT_MAX_PKT_SIZE, .off = _OUT(max_pkt_size), .cb = nlattr_get_uint16 },
+ { .type = PF_RT_TYPE_2, .off = _OUT(type), .cb = nlattr_get_uint16 },
+ { .type = PF_RT_CODE_2, .off = _OUT(code), .cb = nlattr_get_uint16 },
};
NL_DECLARE_ATTR_PARSER(rule_parser, nla_p_rule);
#undef _OUT
@@ -984,8 +986,12 @@ pf_handle_getrule(struct nlmsghdr *hdr, struct nl_pstate *npt)
nlattr_add_u8(nw, PF_RT_AF, rule->af);
nlattr_add_u8(nw, PF_RT_NAF, rule->naf);
nlattr_add_u8(nw, PF_RT_PROTO, rule->proto);
+
nlattr_add_u8(nw, PF_RT_TYPE, rule->type);
nlattr_add_u8(nw, PF_RT_CODE, rule->code);
+ nlattr_add_u16(nw, PF_RT_TYPE_2, rule->type);
+ nlattr_add_u16(nw, PF_RT_CODE_2, rule->code);
+
nlattr_add_u8(nw, PF_RT_FLAGS, rule->flags);
nlattr_add_u8(nw, PF_RT_FLAGSET, rule->flagset);
nlattr_add_u8(nw, PF_RT_MIN_TTL, rule->min_ttl);
@@ -1945,7 +1951,7 @@ pf_handle_get_tstats(struct nlmsghdr *hdr, struct nl_pstate *npt)
n = pfr_table_count(&attrs.pfrio_table, attrs.pfrio_flags);
pfrtstats = mallocarray(n,
- sizeof(struct pfr_tstats), M_TEMP, M_NOWAIT | M_ZERO);
+ sizeof(struct pfr_tstats), M_PF, M_NOWAIT | M_ZERO);
error = pfr_get_tstats(&attrs.pfrio_table, pfrtstats,
&n, attrs.pfrio_flags | PFR_FLAG_USERIOCTL);
@@ -1997,7 +2003,7 @@ pf_handle_get_tstats(struct nlmsghdr *hdr, struct nl_pstate *npt)
}
}
}
- free(pfrtstats, M_TEMP);
+ free(pfrtstats, M_PF);
if (!nlmsg_end_dump(npt->nw, error, hdr)) {
NL_LOG(LOG_DEBUG, "Unable to finalize the dump");
diff --git a/sys/netpfil/pf/pf_nl.h b/sys/netpfil/pf/pf_nl.h
index 87daac393821..b60d3d4797c6 100644
--- a/sys/netpfil/pf/pf_nl.h
+++ b/sys/netpfil/pf/pf_nl.h
@@ -283,6 +283,8 @@ enum pf_rule_type_t {
PF_RT_SRC_NODES_ROUTE = 81, /* u64 */
PF_RT_PKTRATE = 82, /* nested, pf_threshold_type_t */
PF_RT_MAX_PKT_SIZE = 83, /* u16 */
+ PF_RT_TYPE_2 = 84, /* u16 */
+ PF_RT_CODE_2 = 85, /* u16 */
};
enum pf_addrule_type_t {
diff --git a/sys/netpfil/pf/pf_nv.c b/sys/netpfil/pf/pf_nv.c
index 89486928e6e1..2f484e2dabc6 100644
--- a/sys/netpfil/pf/pf_nv.c
+++ b/sys/netpfil/pf/pf_nv.c
@@ -505,6 +505,7 @@ int
pf_nvrule_to_krule(const nvlist_t *nvl, struct pf_krule *rule)
{
int error = 0;
+ uint8_t tmp;
#define ERROUT(x) ERROUT_FUNCTION(errout, x)
@@ -610,8 +611,10 @@ pf_nvrule_to_krule(const nvlist_t *nvl, struct pf_krule *rule)
PFNV_CHK(pf_nvuint8(nvl, "keep_state", &rule->keep_state));
PFNV_CHK(pf_nvuint8(nvl, "af", &rule->af));
PFNV_CHK(pf_nvuint8(nvl, "proto", &rule->proto));
- PFNV_CHK(pf_nvuint8(nvl, "type", &rule->type));
- PFNV_CHK(pf_nvuint8(nvl, "code", &rule->code));
+ PFNV_CHK(pf_nvuint8(nvl, "type", &tmp));
+ rule->type = tmp;
+ PFNV_CHK(pf_nvuint8(nvl, "code", &tmp));
+ rule->code = tmp;
PFNV_CHK(pf_nvuint8(nvl, "flags", &rule->flags));
PFNV_CHK(pf_nvuint8(nvl, "flagset", &rule->flagset));
PFNV_CHK(pf_nvuint8(nvl, "min_ttl", &rule->min_ttl));
diff --git a/sys/netpfil/pf/pf_ruleset.c b/sys/netpfil/pf/pf_ruleset.c
index 039908a53126..1711e690f6bb 100644
--- a/sys/netpfil/pf/pf_ruleset.c
+++ b/sys/netpfil/pf/pf_ruleset.c
@@ -59,8 +59,8 @@
#error "Kernel only file. Please use sbin/pfctl/pf_ruleset.c instead."
#endif
-#define rs_malloc(x) malloc(x, M_TEMP, M_NOWAIT|M_ZERO)
-#define rs_free(x) free(x, M_TEMP)
+#define rs_malloc(x) malloc(x, M_PF, M_NOWAIT|M_ZERO)
+#define rs_free(x) free(x, M_PF)
VNET_DEFINE(struct pf_kanchor_global, pf_anchors);
VNET_DEFINE(struct pf_kanchor, pf_main_anchor);
@@ -336,6 +336,12 @@ pf_remove_if_empty_kruleset(struct pf_kruleset *ruleset)
int i;
while (ruleset != NULL) {
+ for (int i = 0; i < PF_RULESET_MAX; i++) {
+ pf_rule_tree_free(ruleset->rules[i].active.tree);
+ ruleset->rules[i].active.tree = NULL;
+ pf_rule_tree_free(ruleset->rules[i].inactive.tree);
+ ruleset->rules[i].inactive.tree = NULL;
+ }
if (ruleset == &pf_main_ruleset ||
!RB_EMPTY(&ruleset->anchor->children) ||
ruleset->anchor->refcnt > 0 || ruleset->tables > 0 ||
diff --git a/sys/sys/event.h b/sys/sys/event.h
index 1b30e4292de8..f161d2c938c1 100644
--- a/sys/sys/event.h
+++ b/sys/sys/event.h
@@ -45,7 +45,8 @@
#define EVFILT_USER (-11) /* User events */
#define EVFILT_SENDFILE (-12) /* attached to sendfile requests */
#define EVFILT_EMPTY (-13) /* empty send socket buf */
-#define EVFILT_SYSCOUNT 13
+#define EVFILT_JAIL (-14) /* attached to struct prison */
+#define EVFILT_SYSCOUNT 14
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
#define EV_SET(kevp_, a, b, c, d, e, f) do { \
@@ -204,10 +205,19 @@ struct freebsd11_kevent32 {
#define NOTE_PCTRLMASK 0xf0000000 /* mask for hint bits */
#define NOTE_PDATAMASK 0x000fffff /* mask for pid */
-/* additional flags for EVFILT_PROC */
-#define NOTE_TRACK 0x00000001 /* follow across forks */
+/* data/hint flags for EVFILT_JAIL */
+#define NOTE_JAIL_SET 0x80000000 /* jail was modified */
+#define NOTE_JAIL_CHILD 0x40000000 /* child jail was created */
+#define NOTE_JAIL_ATTACH 0x20000000 /* jail was attached to */
+#define NOTE_JAIL_REMOVE 0x10000000 /* jail was removed */
+#define NOTE_JAIL_ATTACH_MULTI 0x08000000 /* multiple procs attached */
+#define NOTE_JAIL_CTRLMASK 0xf0000000 /* mask for hint bits */
+#define NOTE_JAIL_DATAMASK 0x000fffff /* mask for pid */
+
+/* additional flags for EVFILT_PROC and EVFILT_JAIL */
+#define NOTE_TRACK 0x00000001 /* follow across fork/create */
#define NOTE_TRACKERR 0x00000002 /* could not track child */
-#define NOTE_CHILD 0x00000004 /* am a child process */
+#define NOTE_CHILD 0x00000004 /* am a child process/jail */
/* additional flags for EVFILT_TIMER */
#define NOTE_SECONDS 0x00000001 /* data is seconds */
@@ -309,6 +319,7 @@ struct knote {
struct proc *p_proc; /* proc pointer */
struct kaiocb *p_aio; /* AIO job pointer */
struct aioliojob *p_lio; /* LIO job pointer */
+ struct prison *p_prison; /* prison pointer */
void *p_v; /* generic other pointer */
} kn_ptr;
const struct filterops *kn_fop;
diff --git a/sys/sys/exterrvar.h b/sys/sys/exterrvar.h
index 7bf1d264ff5e..6783a0d2d84f 100644
--- a/sys/sys/exterrvar.h
+++ b/sys/sys/exterrvar.h
@@ -31,7 +31,7 @@
#error "Specify error category before including sys/exterrvar.h"
#endif
-#ifdef BLOAT_KERNEL_WITH_EXTERR
+#ifdef EXTERR_STRINGS
#define SET_ERROR_MSG(mmsg) (mmsg)
#else
#define SET_ERROR_MSG(mmsg) NULL
diff --git a/sys/sys/file.h b/sys/sys/file.h
index 63313926c4f0..cc3c733580fd 100644
--- a/sys/sys/file.h
+++ b/sys/sys/file.h
@@ -72,6 +72,7 @@ struct nameidata;
#define DTYPE_EVENTFD 13 /* eventfd */
#define DTYPE_TIMERFD 14 /* timerfd */
#define DTYPE_INOTIFY 15 /* inotify descriptor */
+#define DTYPE_JAILDESC 16 /* jail descriptor */
#ifdef _KERNEL
diff --git a/sys/sys/jail.h b/sys/sys/jail.h
index d2655c52e832..e12e8c3178c9 100644
--- a/sys/sys/jail.h
+++ b/sys/sys/jail.h
@@ -99,8 +99,12 @@ enum prison_state {
#define JAIL_UPDATE 0x02 /* Update parameters of existing jail */
#define JAIL_ATTACH 0x04 /* Attach to jail upon creation */
#define JAIL_DYING 0x08 /* Allow getting a dying jail */
-#define JAIL_SET_MASK 0x0f /* JAIL_DYING is deprecated/ignored here */
-#define JAIL_GET_MASK 0x08
+#define JAIL_USE_DESC 0x10 /* Get/set jail in descriptor */
+#define JAIL_AT_DESC 0x20 /* Find/add jail under descriptor */
+#define JAIL_GET_DESC 0x40 /* Return a new jail descriptor */
+#define JAIL_OWN_DESC 0x80 /* Return a new owning jail descriptor */
+#define JAIL_SET_MASK 0xff /* JAIL_DYING is deprecated/ignored here */
+#define JAIL_GET_MASK 0xf8
#define JAIL_SYS_DISABLE 0
#define JAIL_SYS_NEW 1
@@ -115,7 +119,9 @@ int jail(struct jail *);
int jail_set(struct iovec *, unsigned int, int);
int jail_get(struct iovec *, unsigned int, int);
int jail_attach(int);
+int jail_attach_jd(int);
int jail_remove(int);
+int jail_remove_jd(int);
__END_DECLS
#else /* _KERNEL */
@@ -144,6 +150,8 @@ MALLOC_DECLARE(M_PRISON);
#define JAIL_META_PRIVATE "meta"
#define JAIL_META_SHARED "env"
+struct jaildesc;
+struct knlist;
struct racct;
struct prison_racct;
@@ -189,7 +197,9 @@ struct prison {
struct vnode *pr_root; /* (c) vnode to rdir */
struct prison_ip *pr_addrs[PR_FAMILY_MAX]; /* (p,n) IPs of jail */
struct prison_racct *pr_prison_racct; /* (c) racct jail proxy */
- void *pr_sparep[3];
+ struct knlist *pr_klist; /* (m) attached knotes */
+ LIST_HEAD(, jaildesc) pr_descs; /* (a) attached descriptors */
+ void *pr_sparep;
int pr_childcount; /* (a) number of child jails */
int pr_childmax; /* (p) maximum child jails */
unsigned pr_allow; /* (p) PR_ALLOW_* flags */
@@ -425,10 +435,11 @@ SYSCTL_DECL(_security_jail_param);
/*
* Kernel support functions for jail().
*/
-struct ucred;
+struct knote;
struct mount;
struct sockaddr;
struct statfs;
+struct ucred;
struct vfsconf;
/*
@@ -463,6 +474,7 @@ void prison_proc_free(struct prison *);
void prison_proc_link(struct prison *, struct proc *);
void prison_proc_unlink(struct prison *, struct proc *);
void prison_proc_iterate(struct prison *, void (*)(struct proc *, void *), void *);
+void prison_remove(struct prison *);
void prison_set_allow(struct ucred *cred, unsigned flag, int enable);
bool prison_ischild(struct prison *, struct prison *);
bool prison_isalive(const struct prison *);
diff --git a/sys/sys/jaildesc.h b/sys/sys/jaildesc.h
new file mode 100644
index 000000000000..4bed1ab3b88a
--- /dev/null
+++ b/sys/sys/jaildesc.h
@@ -0,0 +1,85 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2025 James Gritton.
+ * All rights reserved.
+ *
+ * This software was developed at the University of Cambridge Computer
+ * Laboratory with support from a grant from Google, 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.
+ *
+ * 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.
+ */
+
+#ifndef _SYS_JAILDESC_H_
+#define _SYS_JAILDESC_H_
+
+#ifdef _KERNEL
+
+#include <sys/queue.h>
+#include <sys/_lock.h>
+#include <sys/_mutex.h>
+#include <sys/_types.h>
+
+struct prison;
+
+/*-
+ * struct jaildesc describes a jail descriptor, which points to a struct
+ * prison. struct prison in turn has a linked list of struct jaildesc.
+ *
+ * Locking key:
+ * (c) set on creation, remains unchanged
+ * (d) jd_lock
+ * (p) jd_prison->pr_mtx
+ */
+struct jaildesc {
+ LIST_ENTRY(jaildesc) jd_list; /* (d,p) this prison's descs */
+ struct prison *jd_prison; /* (d) the prison */
+ struct mtx jd_lock;
+ uid_t jd_uid; /* (d) nominal file owner */
+ gid_t jd_gid; /* (d) nominal file group */
+ mode_t jd_mode; /* (d) descriptor permissions */
+ unsigned jd_flags; /* (d) JDF_* flags */
+};
+
+/*
+ * Locking macros for the jaildesc.
+ */
+#define JAILDESC_LOCK_DESTROY(jd) mtx_destroy(&(jd)->jd_lock)
+#define JAILDESC_LOCK_INIT(jd) mtx_init(&(jd)->jd_lock, "jaildesc", \
+ NULL, MTX_DEF)
+#define JAILDESC_LOCK(jd) mtx_lock(&(jd)->jd_lock)
+#define JAILDESC_UNLOCK(jd) mtx_unlock(&(jd)->jd_lock)
+
+/*
+ * Flags for the jd_flags field
+ */
+#define JDF_REMOVED 0x00000002 /* jail was removed */
+
+int jaildesc_find(struct thread *td, int fd, struct jaildesc **jdp,
+ struct prison **prp, struct ucred **ucredp);
+int jaildesc_alloc(struct thread *td, struct file **fpp, int *fdp, int owning);
+void jaildesc_set_prison(struct file *jd, struct prison *pr);
+void jaildesc_prison_cleanup(struct prison *pr);
+
+#endif /* _KERNEL */
+
+#endif /* !_SYS_JAILDESC_H_ */
diff --git a/sys/sys/param.h b/sys/sys/param.h
index fc2a78883f1e..ce91430909ce 100644
--- a/sys/sys/param.h
+++ b/sys/sys/param.h
@@ -74,7 +74,7 @@
* cannot include sys/param.h and should only be updated here.
*/
#undef __FreeBSD_version
-#define __FreeBSD_version 1500063
+#define __FreeBSD_version 1600000
/*
* __FreeBSD_kernel__ indicates that this system uses the kernel of FreeBSD,
diff --git a/sys/sys/pciio.h b/sys/sys/pciio.h
index 6467e82b1b3d..64c0b32cb8e2 100644
--- a/sys/sys/pciio.h
+++ b/sys/sys/pciio.h
@@ -77,6 +77,9 @@ struct pci_conf {
u_int8_t pc_revid; /* chip revision ID */
char pd_name[PCI_MAXNAMELEN + 1]; /* device name */
u_long pd_unit; /* device unit number */
+ int pd_numa_domain; /* device NUMA domain */
+ size_t pc_reported_len;/* length of PCI data reported */
+ char pc_spare[64]; /* space for future fields */
};
struct pci_match_conf {
@@ -165,7 +168,6 @@ struct pci_bar_ioreq {
#define PCIIO_BAR_MMAP_RW 0x04
#define PCIIO_BAR_MMAP_ACTIVATE 0x08
-#define PCIOCGETCONF _IOWR('p', 5, struct pci_conf_io)
#define PCIOCREAD _IOWR('p', 2, struct pci_io)
#define PCIOCWRITE _IOWR('p', 3, struct pci_io)
#define PCIOCATTACHED _IOWR('p', 4, struct pci_io)
@@ -173,5 +175,6 @@ struct pci_bar_ioreq {
#define PCIOCLISTVPD _IOWR('p', 7, struct pci_list_vpd_io)
#define PCIOCBARMMAP _IOWR('p', 8, struct pci_bar_mmap)
#define PCIOCBARIO _IOWR('p', 9, struct pci_bar_ioreq)
+#define PCIOCGETCONF _IOWR('p', 10, struct pci_conf_io)
#endif /* !_SYS_PCIIO_H_ */
diff --git a/sys/sys/syscall.h b/sys/sys/syscall.h
index 2d6903967e15..cff27b8be316 100644
--- a/sys/sys/syscall.h
+++ b/sys/sys/syscall.h
@@ -535,4 +535,6 @@
#define SYS_inotify_rm_watch 594
#define SYS_getgroups 595
#define SYS_setgroups 596
-#define SYS_MAXSYSCALL 597
+#define SYS_jail_attach_jd 597
+#define SYS_jail_remove_jd 598
+#define SYS_MAXSYSCALL 599
diff --git a/sys/sys/syscall.mk b/sys/sys/syscall.mk
index d1172c2dc7bf..443dbadcfbff 100644
--- a/sys/sys/syscall.mk
+++ b/sys/sys/syscall.mk
@@ -438,4 +438,6 @@ MIASM = \
inotify_add_watch_at.o \
inotify_rm_watch.o \
getgroups.o \
- setgroups.o
+ setgroups.o \
+ jail_attach_jd.o \
+ jail_remove_jd.o
diff --git a/sys/sys/sysproto.h b/sys/sys/sysproto.h
index 98311a6dbf94..8dda4b4533ea 100644
--- a/sys/sys/sysproto.h
+++ b/sys/sys/sysproto.h
@@ -1901,6 +1901,12 @@ struct setgroups_args {
char gidsetsize_l_[PADL_(int)]; int gidsetsize; char gidsetsize_r_[PADR_(int)];
char gidset_l_[PADL_(const gid_t *)]; const gid_t * gidset; char gidset_r_[PADR_(const gid_t *)];
};
+struct jail_attach_jd_args {
+ char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)];
+};
+struct jail_remove_jd_args {
+ char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)];
+};
int sys__exit(struct thread *, struct _exit_args *);
int sys_fork(struct thread *, struct fork_args *);
int sys_read(struct thread *, struct read_args *);
@@ -2305,6 +2311,8 @@ int sys_inotify_add_watch_at(struct thread *, struct inotify_add_watch_at_args *
int sys_inotify_rm_watch(struct thread *, struct inotify_rm_watch_args *);
int sys_getgroups(struct thread *, struct getgroups_args *);
int sys_setgroups(struct thread *, struct setgroups_args *);
+int sys_jail_attach_jd(struct thread *, struct jail_attach_jd_args *);
+int sys_jail_remove_jd(struct thread *, struct jail_remove_jd_args *);
#ifdef COMPAT_43
@@ -3301,6 +3309,8 @@ int freebsd14_setgroups(struct thread *, struct freebsd14_setgroups_args *);
#define SYS_AUE_inotify_rm_watch AUE_INOTIFY
#define SYS_AUE_getgroups AUE_GETGROUPS
#define SYS_AUE_setgroups AUE_SETGROUPS
+#define SYS_AUE_jail_attach_jd AUE_JAIL_ATTACH
+#define SYS_AUE_jail_remove_jd AUE_JAIL_REMOVE
#undef PAD_
#undef PADL_
diff --git a/sys/sys/ttycom.h b/sys/sys/ttycom.h
index d7ddc66b09fb..43e8b98a5bc4 100644
--- a/sys/sys/ttycom.h
+++ b/sys/sys/ttycom.h
@@ -69,8 +69,8 @@
/* 89-91 conflicts: tun and tap */
#define TIOCTIMESTAMP _IOR('t', 89, struct timeval) /* enable/get timestamp
* of last input event */
-#define TIOCMGDTRWAIT _IOR('t', 90, int) /* modem: get wait on close */
-#define TIOCMSDTRWAIT _IOW('t', 91, int) /* modem: set wait on close */
+/* TIOCMGDTRWAIT _IOR('t', 90, int) * was modem: get wait on close */
+/* TIOCMSDTRWAIT _IOW('t', 91, int) * was modem: set wait on close */
/* 92-93 tun and tap */
/* 94-97 conflicts: tun and tap */
#define TIOCDRAIN _IO('t', 94) /* wait till output drained */
diff --git a/sys/sys/user.h b/sys/sys/user.h
index 103236b6ed1b..3183f0792256 100644
--- a/sys/sys/user.h
+++ b/sys/sys/user.h
@@ -266,6 +266,7 @@ struct user {
#define KF_TYPE_EVENTFD 13
#define KF_TYPE_TIMERFD 14
#define KF_TYPE_INOTIFY 15
+#define KF_TYPE_JAILDESC 16
#define KF_TYPE_UNKNOWN 255
#define KF_VTYPE_VNON 0
@@ -453,6 +454,9 @@ struct kinfo_file {
uint64_t kf_timerfd_addr;
} kf_timerfd;
struct {
+ int32_t kf_jid;
+ } kf_jail;
+ struct {
uint64_t kf_kqueue_addr;
int32_t kf_kqueue_count;
int32_t kf_kqueue_state;
diff --git a/sys/vm/vm_extern.h b/sys/vm/vm_extern.h
index 2b15a01206a2..1fd6518cf4ed 100644
--- a/sys/vm/vm_extern.h
+++ b/sys/vm/vm_extern.h
@@ -91,7 +91,7 @@ void vm_fault_copy_entry(vm_map_t, vm_map_t, vm_map_entry_t, vm_map_entry_t,
vm_ooffset_t *);
int vm_fault_disable_pagefaults(void);
void vm_fault_enable_pagefaults(int save);
-int vm_fault_hold_pages_e(vm_map_t map, vm_offset_t addr, vm_size_t len,
+int vm_fault_hold_pages(vm_map_t map, vm_offset_t addr, vm_size_t len,
vm_prot_t prot, vm_page_t *ma, int max_count, int *ppages_count);
int vm_fault_quick_hold_pages(vm_map_t map, vm_offset_t addr, vm_size_t len,
vm_prot_t prot, vm_page_t *ma, int max_count);
diff --git a/sys/vm/vm_fault.c b/sys/vm/vm_fault.c
index 2a27f3e674a4..58f8ac16fa0c 100644
--- a/sys/vm/vm_fault.c
+++ b/sys/vm/vm_fault.c
@@ -2012,7 +2012,7 @@ vm_fault_prefault(const struct faultstate *fs, vm_offset_t addra,
* (more detailed result from vm_fault() is lost)
*/
int
-vm_fault_hold_pages_e(vm_map_t map, vm_offset_t addr, vm_size_t len,
+vm_fault_hold_pages(vm_map_t map, vm_offset_t addr, vm_size_t len,
vm_prot_t prot, vm_page_t *ma, int max_count, int *ppages_count)
{
vm_offset_t end, va;
@@ -2108,7 +2108,7 @@ vm_fault_quick_hold_pages(vm_map_t map, vm_offset_t addr, vm_size_t len,
{
int error, pages_count;
- error = vm_fault_hold_pages_e(map, addr, len, prot, ma,
+ error = vm_fault_hold_pages(map, addr, len, prot, ma,
max_count, &pages_count);
if (error != 0) {
if (error == EINVAL)
diff --git a/tests/atf_python/sys/net/vnet.py b/tests/atf_python/sys/net/vnet.py
index 7afb5c721bf3..c96eb5d671fc 100644
--- a/tests/atf_python/sys/net/vnet.py
+++ b/tests/atf_python/sys/net/vnet.py
@@ -103,6 +103,7 @@ class VnetInterface(object):
if1 = cls(alias_name, name)
ret = [if1]
if name.startswith("epair"):
+ run_cmd("/sbin/ifconfig {} -txcsum -txcsum6".format(name))
if2 = cls(alias_name, name[:-1] + "b")
if1.epairb = if2
ret.append(if2);
diff --git a/tests/sys/common/vnet.subr b/tests/sys/common/vnet.subr
index bd98b02da33f..0a32e6caf813 100644
--- a/tests/sys/common/vnet.subr
+++ b/tests/sys/common/vnet.subr
@@ -42,6 +42,11 @@ vnet_init()
vnet_mkepair()
{
ifname=$(ifconfig epair create)
+ # When transmit checksum offloading is enabled, if_epair does not
+ # compute checksums, it just marks packets that this computation still
+ # needs to be done. However, some test cases verify the checksum.
+ # Therefore disable this for IPv4 and IPv6.
+ ifconfig ${ifname} -txcsum -txcsum6
list_interface $ifname
list_interface ${ifname%a}b
echo ${ifname%a}
diff --git a/tests/sys/kern/unix_stream.c b/tests/sys/kern/unix_stream.c
index bb811f78f620..49d621dc5b0a 100644
--- a/tests/sys/kern/unix_stream.c
+++ b/tests/sys/kern/unix_stream.c
@@ -467,6 +467,29 @@ ATF_TC_BODY(peershutdown_wakeup_kevent, tc)
});
}
+ATF_TC_WITHOUT_HEAD(ourshutdown_kevent);
+ATF_TC_BODY(ourshutdown_kevent, tc)
+{
+ struct kevent kev;
+ int sv[2], kq;
+
+ do_socketpair(sv);
+ ATF_REQUIRE(kq = kqueue());
+
+ EV_SET(&kev, sv[1], EVFILT_WRITE, EV_ADD, 0, 0, NULL);
+ ATF_REQUIRE(kevent(kq, &kev, 1, NULL, 0, NULL) == 0);
+
+ ATF_REQUIRE(shutdown(sv[1], SHUT_WR) == 0);
+
+ ATF_REQUIRE(kevent(kq, NULL, 0, &kev, 1, NULL) == 1);
+ ATF_REQUIRE(kev.ident == (uintptr_t)sv[1] &&
+ kev.filter == EVFILT_WRITE &&
+ kev.flags == EV_EOF);
+
+ close(sv[0]);
+ close(sv[1]);
+}
+
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, getpeereid);
@@ -482,6 +505,7 @@ ATF_TP_ADD_TCS(tp)
ATF_TP_ADD_TC(tp, peershutdown_wakeup_select);
ATF_TP_ADD_TC(tp, peershutdown_wakeup_poll);
ATF_TP_ADD_TC(tp, peershutdown_wakeup_kevent);
+ ATF_TP_ADD_TC(tp, ourshutdown_kevent);
return atf_no_error();
}
diff --git a/tests/sys/net/if_bridge_test.sh b/tests/sys/net/if_bridge_test.sh
index 0c19903714b1..b3405fd978c8 100755
--- a/tests/sys/net/if_bridge_test.sh
+++ b/tests/sys/net/if_bridge_test.sh
@@ -586,6 +586,25 @@ gif_body()
jexec one ping -c 1 -s 1200 198.51.100.2
atf_check -s exit:0 -o ignore \
jexec one ping -c 1 -s 2000 198.51.100.2
+
+ # Assigning IP addresses on the gif tunneling interfaces
+ jexec one sysctl net.link.bridge.member_ifaddrs=1
+ atf_check -s exit:0 -o ignore \
+ jexec one ifconfig ${gif_one} 192.168.0.224/24 192.168.169.254
+ atf_check -s exit:0 -o ignore \
+ jexec one ifconfig ${gif_one} inet6 no_dad 2001:db8::1/64
+ jexec one ifconfig ${bridge_one} deletem ${gif_one}
+ atf_check -s exit:0 -o ignore \
+ jexec one ifconfig ${bridge_one} addm ${gif_one}
+
+ jexec two sysctl net.link.bridge.member_ifaddrs=0
+ atf_check -s exit:0 -o ignore \
+ jexec two ifconfig ${gif_two} 192.168.169.254/24 192.168.0.224
+ atf_check -s exit:0 -o ignore \
+ jexec two ifconfig ${gif_two} inet6 no_dad 2001:db8::2/64
+ jexec two ifconfig ${bridge_two} deletem ${gif_two}
+ atf_check -s exit:0 -o ignore \
+ jexec two ifconfig ${bridge_two} addm ${gif_two}
}
gif_cleanup()
diff --git a/tests/sys/net/if_ovpn/if_ovpn.sh b/tests/sys/net/if_ovpn/if_ovpn.sh
index 0281e7fc273d..9dafce2242d8 100644
--- a/tests/sys/net/if_ovpn/if_ovpn.sh
+++ b/tests/sys/net/if_ovpn/if_ovpn.sh
@@ -510,6 +510,7 @@ linklocal_head()
linklocal_body()
{
ovpn_init
+ ovpn_check_version 2.7.0
l=$(vnet_mkepair)
@@ -1399,6 +1400,7 @@ float_head()
float_body()
{
ovpn_init
+ ovpn_check_version 2.7.0
l=$(vnet_mkepair)
diff --git a/tests/sys/net/if_ovpn/utils.subr b/tests/sys/net/if_ovpn/utils.subr
index 0da35119b2bf..fbe7dc98630a 100644
--- a/tests/sys/net/if_ovpn/utils.subr
+++ b/tests/sys/net/if_ovpn/utils.subr
@@ -40,6 +40,25 @@ ovpn_init()
fi
}
+ovpn_check_version()
+{
+ expected=$1
+
+ expected_minor=$(echo $expected |
+ awk '{ split($1, ver, "\."); print(ver[2]); }')
+ actual_minor=$(openvpn --version 2>&1 |
+ awk 'NR == 1 \
+ { \
+ split($2, ver, "\."); \
+ split(ver[2], minor, "_"); \
+ print(minor[1]); \
+ }')
+
+ if [ ${actual_minor} -lt ${expected_minor} ]; then
+ atf_skip "OpenVPN version < ${expected}"
+ fi
+}
+
ovpn_cleanup()
{
for jail in `cat ovpn_jails.lst | sort -u`
diff --git a/tests/sys/netpfil/pf/igmp.py b/tests/sys/netpfil/pf/igmp.py
index b339a2825082..5d72a1c093a7 100644
--- a/tests/sys/netpfil/pf/igmp.py
+++ b/tests/sys/netpfil/pf/igmp.py
@@ -93,3 +93,9 @@ class TestIGMP(VnetTestTemplate):
options=[sp.IPOption_Router_Alert()]) \
/ sc.igmp.IGMP(type=0x11, mrcode=1)
assert not self.find_igmp_reply(pkt, ifname)
+
+ # Or with the wrong destination address
+ pkt = sp.IP(dst="224.0.0.2%%%s" % ifname, ttl=2,
+ options=[sp.IPOption_Router_Alert()]) \
+ / sc.igmp.IGMP(type=0x11, mrcode=1)
+ assert not self.find_igmp_reply(pkt, ifname)
diff --git a/tests/sys/netpfil/pf/route_to.sh b/tests/sys/netpfil/pf/route_to.sh
index 765403dcb79c..872de0dcbb91 100644
--- a/tests/sys/netpfil/pf/route_to.sh
+++ b/tests/sys/netpfil/pf/route_to.sh
@@ -28,6 +28,75 @@
common_dir=$(atf_get_srcdir)/../common
+# We need to somehow test if the random algorithm of pf_map_addr() is working.
+# The table or prefix contains multiple IP next-hop addresses, for each one try
+# to establish up to 10 connections. Fail the test if with this many attempts
+# the "good" target has not been chosen. However this choice is random,
+# the check might still ocasionally fail.
+check_random() {
+ if [ "$1" = "IPv4" ]; then
+ ping_from="${net_clients_4}.1"
+ ping_to="${host_server_4}"
+ else
+ ping_from="${net_clients_6}::1"
+ ping_to="${host_server_6}"
+ fi
+ good_targets="$2"
+ bad_targets="$3"
+
+ port=42000
+ states=$(mktemp) || exit 1
+ for good_target in $good_targets; do
+ found="no"
+ for attempt in $(seq 1 10); do
+ port=$(( port + 1 ))
+ jexec router pfctl -Fs
+ atf_check -s exit:0 ${common_dir}/pft_ping.py \
+ --sendif ${epair_tester}a --replyif ${epair_tester}a \
+ --fromaddr ${ping_from} --to ${ping_to} \
+ --ping-type=tcp3way --send-sport=${port}
+ jexec router pfctl -qvvss | normalize_pfctl_s > $states
+ cat $states
+ if [ -n "${bad_targets}" ]; then
+ for bad_target in $bad_targets; do
+ if grep -qE "route-to: ${bad_target}@" $states; then
+ atf_fail "Bad target ${bad_target} selected!"
+ fi
+ done
+ fi;
+ if grep -qE "route-to: ${good_target}@" $states; then
+ found=yes
+ break
+ fi
+ done
+ if [ "${found}" = "no" ]; then
+ atf_fail "Target ${good_target} not selected after ${attempt} attempts!"
+ fi
+ done
+}
+
+pf_map_addr_common()
+{
+ setup_router_server_nat64
+
+ # Clients will connect from another network behind the router.
+ # This allows for using multiple source addresses.
+ jexec router route add -6 ${net_clients_6}::/${net_clients_6_mask} ${net_tester_6_host_tester}
+ jexec router route add ${net_clients_4}.0/${net_clients_4_mask} ${net_tester_4_host_tester}
+
+ # The servers are reachable over additional IP addresses for
+ # testing of tables and subnets. The addresses are noncontinougnus
+ # for pf_map_addr() counter tests.
+ for i in 0 1 4 5; do
+ a1=$((24 + i))
+ jexec server1 ifconfig ${epair_server1}b inet ${net_server1_4}.${a1}/32 alias
+ jexec server1 ifconfig ${epair_server1}b inet6 ${net_server1_6}::42:${i}/128 alias
+ a2=$((40 + i))
+ jexec server2 ifconfig ${epair_server2}b inet ${net_server2_4}.${a2}/32 alias
+ jexec server2 ifconfig ${epair_server2}b inet6 ${net_server2_6}::42:${i}/128 alias
+ done
+}
+
atf_test_case "v4" "cleanup"
v4_head()
{
@@ -893,36 +962,17 @@ empty_pool_cleanup()
pft_cleanup
}
-
atf_test_case "table_loop" "cleanup"
table_loop_head()
{
atf_set descr 'Check that iterating over tables poperly loops'
atf_set require.user root
- atf_set require.progs python3 scapy
}
table_loop_body()
{
- setup_router_server_nat64
-
- # Clients will connect from another network behind the router.
- # This allows for using multiple source addresses.
- jexec router route add -6 ${net_clients_6}::/${net_clients_6_mask} ${net_tester_6_host_tester}
- jexec router route add ${net_clients_4}.0/${net_clients_4_mask} ${net_tester_4_host_tester}
-
- # The servers are reachable over additional IP addresses for
- # testing of tables and subnets. The addresses are noncontinougnus
- # for pf_map_addr() counter tests.
- for i in 0 1 4 5; do
- a1=$((24 + i))
- jexec server1 ifconfig ${epair_server1}b inet ${net_server1_4}.${a1}/32 alias
- jexec server1 ifconfig ${epair_server1}b inet6 ${net_server1_6}::42:${i}/128 alias
- a2=$((40 + i))
- jexec server2 ifconfig ${epair_server2}b inet ${net_server2_4}.${a2}/32 alias
- jexec server2 ifconfig ${epair_server2}b inet6 ${net_server2_6}::42:${i}/128 alias
- done
+ pf_map_addr_common
jexec router pfctl -e
pft_set_rules router \
@@ -976,6 +1026,612 @@ table_loop_cleanup()
}
+atf_test_case "roundrobin" "cleanup"
+
+roundrobin_head()
+{
+ atf_set descr 'multiple gateways of mixed AF, including prefixes and tables, for IPv6 packets'
+ atf_set require.user root
+}
+
+roundrobin_body()
+{
+ pf_map_addr_common
+
+ # The rule is defined as "inet6 proto tcp" so directly given IPv4 hosts
+ # will be removed from the pool by pfctl. Tables will still be loaded
+ # and pf_map_addr() will only use IPv6 addresses from them. It will
+ # iterate over members of the pool and inside of tables and prefixes.
+
+ jexec router pfctl -e
+ pft_set_rules router \
+ "set debug loud" \
+ "set reassemble yes" \
+ "set state-policy if-bound" \
+ "table <rt_targets> { ${net_server2_4}.40/31 ${net_server2_4}.44 ${net_server2_6}::42:0/127 ${net_server2_6}::42:4 }" \
+ "pass in on ${epair_tester}b \
+ route-to { \
+ (${epair_server1}a ${net_server1_4_host_server}) \
+ (${epair_server2}a <rt_targets_empty>) \
+ (${epair_server1}a ${net_server1_6}::42:0/127) \
+ (${epair_server2}a <rt_targets_empty>) \
+ (${epair_server2}a <rt_targets>) \
+ } \
+ inet6 proto tcp \
+ keep state"
+
+ for port in $(seq 1 6); do
+ port=$((4200 + port))
+ atf_check -s exit:0 ${common_dir}/pft_ping.py \
+ --sendif ${epair_tester}a --replyif ${epair_tester}a \
+ --fromaddr ${net_clients_6}::1 --to ${host_server_6} \
+ --ping-type=tcp3way --send-sport=${port}
+ done
+
+ states=$(mktemp) || exit 1
+ jexec router pfctl -qvvss | normalize_pfctl_s > $states
+
+ for state_regexp in \
+ "${epair_tester}b tcp ${host_server_6}\[9\] <- ${net_clients_6}::1\[4201\] .* route-to: ${net_server1_6}::42:0@${epair_server1}a" \
+ "${epair_tester}b tcp ${host_server_6}\[9\] <- ${net_clients_6}::1\[4202\] .* route-to: ${net_server1_6}::42:1@${epair_server1}a" \
+ "${epair_tester}b tcp ${host_server_6}\[9\] <- ${net_clients_6}::1\[4203\] .* route-to: ${net_server2_6}::42:0@${epair_server2}a" \
+ "${epair_tester}b tcp ${host_server_6}\[9\] <- ${net_clients_6}::1\[4204\] .* route-to: ${net_server2_6}::42:1@${epair_server2}a" \
+ "${epair_tester}b tcp ${host_server_6}\[9\] <- ${net_clients_6}::1\[4205\] .* route-to: ${net_server2_6}::42:4@${epair_server2}a" \
+ "${epair_tester}b tcp ${host_server_6}\[9\] <- ${net_clients_6}::1\[4206\] .* route-to: ${net_server1_6}::42:0@${epair_server1}a" \
+ ; do
+ grep -qE "${state_regexp}" $states || atf_fail "State not found for '${state_regexp}'"
+ done
+}
+
+roundrobin_cleanup()
+{
+ pft_cleanup
+}
+
+atf_test_case "random_table" "cleanup"
+
+random_table_head()
+{
+ atf_set descr 'Pool with random flag and a table for IPv6'
+ atf_set require.user root
+}
+
+random_table_body()
+{
+ pf_map_addr_common
+
+ # The "random" flag will pick random hosts from the table but will
+ # not dive into prefixes, always choosing the 0th address.
+ # Proper address family will be choosen.
+
+ jexec router pfctl -e
+ pft_set_rules router \
+ "set debug loud" \
+ "set reassemble yes" \
+ "set state-policy if-bound" \
+ "table <rt_targets> { ${net_server2_4}.40/31 ${net_server2_4}.44 ${net_server2_6}::42:0/127 ${net_server2_6}::42:4 }" \
+ "pass in on ${epair_tester}b \
+ route-to { (${epair_server2}a <rt_targets>) } random \
+ inet6 proto tcp \
+ keep state"
+
+ good_targets="${net_server2_6}::42:0 ${net_server2_6}::42:4"
+ bad_targets="${net_server2_6}::42:1"
+ check_random IPv6 "${good_targets}" "${bad_targets}"
+}
+
+random_table_cleanup()
+{
+ pft_cleanup
+}
+
+atf_test_case "random_prefix" "cleanup"
+
+random_prefix_head()
+{
+ atf_set descr 'Pool with random flag and a table for IPv4'
+ atf_set require.user root
+}
+
+random_prefix_body()
+{
+ pf_map_addr_common
+
+ # The "random" flag will pick random hosts from given prefix.
+ # The choice being random makes testing it non-trivial. We do 10
+ # attempts to have each target chosen. Hopefully this is enough to have
+ # this test pass often enough.
+
+ jexec router pfctl -e
+ pft_set_rules router \
+ "set debug loud" \
+ "set reassemble yes" \
+ "set state-policy if-bound" \
+ "pass in on ${epair_tester}b \
+ route-to { (${epair_server2}a ${net_server2_6}::42:0/127) } random \
+ inet6 proto tcp \
+ keep state"
+
+ good_targets="${net_server2_6}::42:0 ${net_server2_6}::42:1"
+ check_random IPv6 "${good_targets}"
+}
+
+random_prefix_cleanup()
+{
+ pft_cleanup
+}
+
+atf_test_case "prefer_ipv6_nexthop_single_ipv4" "cleanup"
+
+prefer_ipv6_nexthop_single_ipv4_head()
+{
+ atf_set descr 'prefer-ipv6-nexthop option for a single IPv4 gateway'
+ atf_set require.user root
+}
+
+prefer_ipv6_nexthop_single_ipv4_body()
+{
+ pf_map_addr_common
+
+ # Basic forwarding test for prefer-ipv6-nexthop pool option.
+ # A single IPv4 gateway will work only for IPv4 traffic.
+
+ jexec router pfctl -e
+ pft_set_rules router \
+ "set reassemble yes" \
+ "set state-policy if-bound" \
+ "pass in on ${epair_tester}b \
+ route-to (${epair_server1}a ${net_server1_4_host_server}) prefer-ipv6-nexthop \
+ proto tcp \
+ keep state"
+
+ atf_check -s exit:0 ${common_dir}/pft_ping.py \
+ --sendif ${epair_tester}a --replyif ${epair_tester}a \
+ --fromaddr ${net_clients_4}.1 --to ${host_server_4} \
+ --ping-type=tcp3way --send-sport=4201 \
+
+ atf_check -s exit:1 ${common_dir}/pft_ping.py \
+ --sendif ${epair_tester}a --replyif ${epair_tester}a \
+ --fromaddr ${net_clients_6}::1 --to ${host_server_6} \
+ --ping-type=tcp3way --send-sport=4202
+
+ states=$(mktemp) || exit 1
+ jexec router pfctl -qvvss | normalize_pfctl_s > $states
+
+ for state_regexp in \
+ "${epair_tester}b tcp ${host_server_4}:9 <- ${net_clients_4}.1:4201 .* route-to: ${net_server1_4_host_server}@${epair_server1}a" \
+ ; do
+ grep -qE "${state_regexp}" $states || atf_fail "State not found for '${state_regexp}'"
+ done
+
+ # The IPv6 packet could not have been routed over IPv4 gateway.
+ atf_check -o "match:map-failed +1 +" -x "jexec router pfctl -qvvsi 2> /dev/null"
+}
+
+prefer_ipv6_nexthop_single_ipv4_cleanup()
+{
+ pft_cleanup
+}
+
+atf_test_case "prefer_ipv6_nexthop_single_ipv6" "cleanup"
+
+prefer_ipv6_nexthop_single_ipv6_head()
+{
+ atf_set descr 'prefer-ipv6-nexthop option for a single IPv6 gateway'
+ atf_set require.user root
+}
+
+prefer_ipv6_nexthop_single_ipv6_body()
+{
+ pf_map_addr_common
+
+ # Basic forwarding test for prefer-ipv6-nexthop pool option.
+ # A single IPve gateway will work both for IPv4 and IPv6 traffic.
+
+ jexec router pfctl -e
+ pft_set_rules router \
+ "set reassemble yes" \
+ "set state-policy if-bound" \
+ "pass in on ${epair_tester}b \
+ route-to (${epair_server1}a ${net_server1_6_host_server}) prefer-ipv6-nexthop \
+ proto tcp \
+ keep state"
+
+ atf_check -s exit:0 ${common_dir}/pft_ping.py \
+ --sendif ${epair_tester}a --replyif ${epair_tester}a \
+ --fromaddr ${net_clients_4}.1 --to ${host_server_4} \
+ --ping-type=tcp3way --send-sport=4201 \
+
+ atf_check -s exit:0 ${common_dir}/pft_ping.py \
+ --sendif ${epair_tester}a --replyif ${epair_tester}a \
+ --fromaddr ${net_clients_6}::1 --to ${host_server_6} \
+ --ping-type=tcp3way --send-sport=4202
+
+ states=$(mktemp) || exit 1
+ jexec router pfctl -qvvss | normalize_pfctl_s > $states
+
+ for state_regexp in \
+ "${epair_tester}b tcp ${host_server_4}:9 <- ${net_clients_4}.1:4201 .* route-to: ${net_server1_6_host_server}@${epair_server1}a" \
+ "${epair_tester}b tcp ${host_server_6}\[9\] <- ${net_clients_6}::1\[4202\] .* route-to: ${net_server1_6_host_server}@${epair_server1}a" \
+ ; do
+ grep -qE "${state_regexp}" $states || atf_fail "State not found for '${state_regexp}'"
+ done
+}
+
+prefer_ipv6_nexthop_single_ipv6_cleanup()
+{
+ pft_cleanup
+}
+
+atf_test_case "prefer_ipv6_nexthop_mixed_af_roundrobin_ipv4" "cleanup"
+
+prefer_ipv6_nexthop_mixed_af_roundrobin_ipv4_head()
+{
+ atf_set descr 'prefer-ipv6-nexthop option for multiple gateways of mixed AF with prefixes and tables, round robin selection, for IPv4 packets'
+ atf_set require.user root
+}
+
+prefer_ipv6_nexthop_mixed_af_roundrobin_ipv4_body()
+{
+ pf_map_addr_common
+
+ # pf_map_addr() starts iterating over hosts of the pool from the 2nd
+ # host. This behaviour was here before adding prefer-ipv6-nexthop
+ # support, we test for it. Some targets are hosts and some are tables.
+ # Those are iterated too. Finally the iteration loops back
+ # to the beginning of the pool. Send out IPv4 probes. They will use all
+ # IPv4 and IPv6 addresses from the pool.
+
+ jexec router pfctl -e
+ pft_set_rules router \
+ "set reassemble yes" \
+ "set state-policy if-bound" \
+ "table <rt_targets> { ${net_server2_4}.40/31 ${net_server2_4}.44 ${net_server2_6}::42:4/127 }" \
+ "pass in on ${epair_tester}b \
+ route-to { \
+ (${epair_server1}a ${net_server1_6_host_server}) \
+ (${epair_server1}a ${net_server1_6}::42:0/127) \
+ (${epair_server2}a ${net_server2_4_host_server}) \
+ (${epair_server2}a <rt_targets_empty>) \
+ (${epair_server1}a ${net_server1_4}.24/31) \
+ (${epair_server2}a <rt_targets>) \
+ } prefer-ipv6-nexthop \
+ proto tcp \
+ keep state"
+
+ for port in $(seq 1 12); do
+ port=$((4200 + port))
+ atf_check -s exit:0 ${common_dir}/pft_ping.py \
+ --sendif ${epair_tester}a --replyif ${epair_tester}a \
+ --fromaddr ${net_clients_4}.1 --to ${host_server_4} \
+ --ping-type=tcp3way --send-sport=${port}
+ done
+
+ states=$(mktemp) || exit 1
+ jexec router pfctl -qvvss | normalize_pfctl_s > $states
+
+ for state_regexp in \
+ "${epair_tester}b tcp ${host_server_4}:9 <- ${net_clients_4}.1:4201 .* route-to: ${net_server1_6}::42:0@${epair_server1}a" \
+ "${epair_tester}b tcp ${host_server_4}:9 <- ${net_clients_4}.1:4202 .* route-to: ${net_server1_6}::42:1@${epair_server1}a" \
+ "${epair_tester}b tcp ${host_server_4}:9 <- ${net_clients_4}.1:4203 .* route-to: ${net_server2_4_host_server}@${epair_server2}a" \
+ "${epair_tester}b tcp ${host_server_4}:9 <- ${net_clients_4}.1:4204 .* route-to: ${net_server1_4}.24@${epair_server1}a" \
+ "${epair_tester}b tcp ${host_server_4}:9 <- ${net_clients_4}.1:4205 .* route-to: ${net_server1_4}.25@${epair_server1}a" \
+ "${epair_tester}b tcp ${host_server_4}:9 <- ${net_clients_4}.1:4206 .* route-to: ${net_server2_6}::42:4@${epair_server2}a" \
+ "${epair_tester}b tcp ${host_server_4}:9 <- ${net_clients_4}.1:4207 .* route-to: ${net_server2_6}::42:5@${epair_server2}a" \
+ "${epair_tester}b tcp ${host_server_4}:9 <- ${net_clients_4}.1:4208 .* route-to: ${net_server2_4}.40@${epair_server2}a" \
+ "${epair_tester}b tcp ${host_server_4}:9 <- ${net_clients_4}.1:4209 .* route-to: ${net_server2_4}.41@${epair_server2}a" \
+ "${epair_tester}b tcp ${host_server_4}:9 <- ${net_clients_4}.1:4210 .* route-to: ${net_server2_4}.44@${epair_server2}a" \
+ "${epair_tester}b tcp ${host_server_4}:9 <- ${net_clients_4}.1:4211 .* route-to: ${net_server1_6_host_server}@${epair_server1}a" \
+ "${epair_tester}b tcp ${host_server_4}:9 <- ${net_clients_4}.1:4212 .* route-to: ${net_server1_6}::42:0@${epair_server1}a" \
+ ; do
+ grep -qE "${state_regexp}" $states || atf_fail "State not found for '${state_regexp}'"
+ done
+}
+
+prefer_ipv6_nexthop_mixed_af_roundrobin_ipv4_cleanup()
+{
+ pft_cleanup
+}
+
+prefer_ipv6_nexthop_mixed_af_roundrobin_ipv6_head()
+{
+ atf_set descr 'prefer-ipv6-nexthop option for multiple gateways of mixed AF with prefixes and tables, round-robin selection, for IPv6 packets'
+ atf_set require.user root
+}
+
+prefer_ipv6_nexthop_mixed_af_roundrobin_ipv6_body()
+{
+ pf_map_addr_common
+
+ # The "random" flag will pick random hosts from the table but will
+ # not dive into prefixes, always choosing the 0th address.
+ # Proper address family will be choosen. The choice being random makes
+ # testing it non-trivial. We do 10 attempts to have each target chosen.
+ # Hopefully this is enough to have this test pass often enough.
+
+ # pf_map_addr() starts iterating over hosts of the pool from the 2nd
+ # host. This behaviour was here before adding prefer-ipv6-nexthop
+ # support, we test for it. Some targets are hosts and some are tables.
+ # Those are iterated too. Finally the iteration loops back
+ # to the beginning of the pool. Send out IPv6 probes. They will use only
+ # IPv6 addresses from the pool.
+
+ jexec router pfctl -e
+ pft_set_rules router \
+ "set reassemble yes" \
+ "set state-policy if-bound" \
+ "table <rt_targets> { ${net_server2_4}.40/31 ${net_server2_4}.44 ${net_server2_6}::42:4/127 }" \
+ "pass in on ${epair_tester}b \
+ route-to { \
+ (${epair_server1}a ${net_server1_6_host_server}) \
+ (${epair_server1}a ${net_server1_6}::42:0/127) \
+ (${epair_server2}a ${net_server2_4_host_server}) \
+ (${epair_server2}a <rt_targets_empty>) \
+ (${epair_server1}a ${net_server1_4}.24/31) \
+ (${epair_server2}a <rt_targets>) \
+ } prefer-ipv6-nexthop \
+ proto tcp \
+ keep state"
+
+ for port in $(seq 1 6); do
+ port=$((4200 + port))
+ atf_check -s exit:0 ${common_dir}/pft_ping.py \
+ --sendif ${epair_tester}a --replyif ${epair_tester}a \
+ --fromaddr ${net_clients_6}::1 --to ${host_server_6} \
+ --ping-type=tcp3way --send-sport=${port}
+ done
+
+ states=$(mktemp) || exit 1
+ jexec router pfctl -qvvss | normalize_pfctl_s > $states
+
+ for state_regexp in \
+ "${epair_tester}b tcp ${host_server_6}\[9\] <- ${net_clients_6}::1\[4201\] .* route-to: ${net_server1_6}::42:0@${epair_server1}a" \
+ "${epair_tester}b tcp ${host_server_6}\[9\] <- ${net_clients_6}::1\[4202\] .* route-to: ${net_server1_6}::42:1@${epair_server1}a" \
+ "${epair_tester}b tcp ${host_server_6}\[9\] <- ${net_clients_6}::1\[4203\] .* route-to: ${net_server2_6}::42:4@${epair_server2}a" \
+ "${epair_tester}b tcp ${host_server_6}\[9\] <- ${net_clients_6}::1\[4204\] .* route-to: ${net_server2_6}::42:5@${epair_server2}a" \
+ "${epair_tester}b tcp ${host_server_6}\[9\] <- ${net_clients_6}::1\[4205\] .* route-to: ${net_server1_6_host_server}@${epair_server1}a" \
+ "${epair_tester}b tcp ${host_server_6}\[9\] <- ${net_clients_6}::1\[4206\] .* route-to: ${net_server1_6}::42:0@${epair_server1}a" \
+ ; do
+ grep -qE "${state_regexp}" $states || atf_fail "State not found for '${state_regexp}'"
+ done
+}
+
+prefer_ipv6_nexthop_mixed_af_roundrobin_ipv6_cleanup()
+{
+ pft_cleanup
+}
+
+atf_test_case "prefer_ipv6_nexthop_mixed_af_random_ipv4" "cleanup"
+
+prefer_ipv6_nexthop_mixed_af_random_table_ipv4_head()
+{
+ atf_set descr 'prefer-ipv6-nexthop option for a mixed-af table with random selection for IPv4 packets'
+ atf_set require.user root
+}
+
+prefer_ipv6_nexthop_mixed_af_random_table_ipv4_body()
+{
+ pf_map_addr_common
+
+ # Similarly to the test "random_table" the algorithm will choose
+ # IP addresses from the table not diving into prefixes.
+ # *prefer*-ipv6-nexthop means that IPv6 nexthops are preferred,
+ # so IPv4 ones will not be chosen as long as there are IPv6 ones
+ # available. With this tested there is no need for a test for IPv6-only
+ # next-hops table.
+
+ jexec router pfctl -e
+ pft_set_rules router \
+ "set reassemble yes" \
+ "set state-policy if-bound" \
+ "table <rt_targets> { ${net_server2_4}.40/31 ${net_server2_4}.44 ${net_server2_6}::42:0/127 ${net_server2_6}::42:4 }" \
+ "pass in on ${epair_tester}b \
+ route-to { (${epair_server2}a <rt_targets>) } random prefer-ipv6-nexthop \
+ proto tcp \
+ keep state"
+
+ good_targets="${net_server2_6}::42:0 ${net_server2_6}::42:4"
+ bad_targets="${net_server2_4}.40 ${net_server2_4}.41 ${net_server2_4}.44 ${net_server2_6}::42:1"
+ check_random IPv4 "${good_targets}" "${bad_targets}"
+}
+
+prefer_ipv6_nexthop_mixed_af_random_table_ipv4_cleanup()
+{
+ pft_cleanup
+}
+
+prefer_ipv6_nexthop_ipv4_random_table_ipv4_head()
+{
+ atf_set descr 'prefer-ipv6-nexthop option for an IPv4-only table with random selection for IPv4 packets'
+ atf_set require.user root
+}
+
+prefer_ipv6_nexthop_ipv4_random_table_ipv4_body()
+{
+ pf_map_addr_common
+
+ # Similarly to the test pf_map_addr:random_table the algorithm will
+ # choose IP addresses from the table not diving into prefixes.
+ # There are no IPv6 nexthops in the table, so the algorithm will
+ # fall back to IPv4.
+
+ jexec router pfctl -e
+ pft_set_rules router \
+ "set reassemble yes" \
+ "set state-policy if-bound" \
+ "table <rt_targets> { ${net_server2_4}.40/31 ${net_server2_4}.44 }" \
+ "pass in on ${epair_tester}b \
+ route-to { (${epair_server2}a <rt_targets>) } random prefer-ipv6-nexthop \
+ proto tcp \
+ keep state"
+
+ good_targets="${net_server2_4}.40 ${net_server2_4}.44"
+ bad_targets="${net_server2_4}.41"
+ check_random IPv4 "${good_targets}" "${bad_targets}"
+}
+
+prefer_ipv6_nexthop_ipv4_random_table_ipv4_cleanup()
+{
+ pft_cleanup
+}
+
+prefer_ipv6_nexthop_ipv4_random_table_ipv6_head()
+{
+ atf_set descr 'prefer-ipv6-nexthop option for an IPv4-only table with random selection for IPv6 packets'
+ atf_set require.user root
+}
+
+prefer_ipv6_nexthop_ipv4_random_table_ipv6_body()
+{
+ pf_map_addr_common
+
+ # IPv6 packets can't be forwarded over IPv4 next-hops.
+ # The failure happens in pf_map_addr() and increases the respective
+ # error counter.
+
+ jexec router pfctl -e
+ pft_set_rules router \
+ "set reassemble yes" \
+ "set state-policy if-bound" \
+ "table <rt_targets> { ${net_server2_4}.40/31 ${net_server2_4}.44 }" \
+ "pass in on ${epair_tester}b \
+ route-to { (${epair_server2}a <rt_targets>) } random prefer-ipv6-nexthop \
+ proto tcp \
+ keep state"
+
+ atf_check -s exit:1 ${common_dir}/pft_ping.py \
+ --sendif ${epair_tester}a --replyif ${epair_tester}a \
+ --fromaddr ${net_clients_6}::1 --to ${host_server_6} \
+ --ping-type=tcp3way --send-sport=4201
+
+ atf_check -o "match:map-failed +1 +" -x "jexec router pfctl -qvvsi 2> /dev/null"
+}
+
+prefer_ipv6_nexthop_ipv4_random_table_ipv6_cleanup()
+{
+ pft_cleanup
+}
+
+prefer_ipv6_nexthop_ipv6_random_prefix_ipv4_head()
+{
+ atf_set descr 'prefer-ipv6-nexthop option for an IPv6 prefix with random selection for IPv4 packets'
+ atf_set require.user root
+}
+
+prefer_ipv6_nexthop_ipv6_random_prefix_ipv4_body()
+{
+ pf_map_addr_common
+
+ jexec router pfctl -e
+ pft_set_rules router \
+ "set reassemble yes" \
+ "set state-policy if-bound" \
+ "pass in on ${epair_tester}b \
+ route-to { (${epair_server2}a ${net_server2_6}::42:0/127) } random prefer-ipv6-nexthop \
+ proto tcp \
+ keep state"
+
+ good_targets="${net_server2_6}::42:0 ${net_server2_6}::42:1"
+ check_random IPv4 "${good_targets}"
+}
+
+prefer_ipv6_nexthop_ipv6_random_prefix_ipv4_cleanup()
+{
+ pft_cleanup
+}
+
+prefer_ipv6_nexthop_ipv6_random_prefix_ipv6_head()
+{
+ atf_set descr 'prefer-ipv6-nexthop option for an IPv6 prefix with random selection for IPv6 packets'
+ atf_set require.user root
+}
+
+prefer_ipv6_nexthop_ipv6_random_prefix_ipv6_body()
+{
+ pf_map_addr_common
+
+ jexec router pfctl -e
+ pft_set_rules router \
+ "set reassemble yes" \
+ "set state-policy if-bound" \
+ "pass in on ${epair_tester}b \
+ route-to { (${epair_server2}a ${net_server2_6}::42:0/127) } random prefer-ipv6-nexthop \
+ proto tcp \
+ keep state"
+
+ good_targets="${net_server2_6}::42:0 ${net_server2_6}::42:1"
+ check_random IPv6 "${good_targets}"
+}
+
+prefer_ipv6_nexthop_ipv6_random_prefix_ipv6_cleanup()
+{
+ pft_cleanup
+}
+
+prefer_ipv6_nexthop_ipv4_random_prefix_ipv4_head()
+{
+ atf_set descr 'prefer-ipv6-nexthop option for an IPv4 prefix with random selection for IPv4 packets'
+ atf_set require.user root
+}
+
+prefer_ipv6_nexthop_ipv4_random_prefix_ipv4_body()
+{
+ pf_map_addr_common
+
+ jexec router pfctl -e
+ pft_set_rules router \
+ "set reassemble yes" \
+ "set state-policy if-bound" \
+ "pass in on ${epair_tester}b \
+ route-to { (${epair_server2}a ${net_server2_4}.40/31) } random prefer-ipv6-nexthop \
+ proto tcp \
+ keep state"
+
+ good_targets="${net_server2_4}.40 ${net_server2_4}.41"
+ check_random IPv4 "${good_targets}"
+}
+
+prefer_ipv6_nexthop_ipv4_random_prefix_ipv4_cleanup()
+{
+ pft_cleanup
+}
+
+prefer_ipv6_nexthop_ipv4_random_prefix_ipv6_head()
+{
+ atf_set descr 'prefer-ipv6-nexthop option for an IPv4 prefix with random selection for IPv6 packets'
+ atf_set require.user root
+}
+
+prefer_ipv6_nexthop_ipv4_random_prefix_ipv6_body()
+{
+ pf_map_addr_common
+
+ # IPv6 packets can't be forwarded over IPv4 next-hops.
+ # The failure happens in pf_map_addr() and increases the respective
+ # error counter.
+
+ jexec router pfctl -e
+ pft_set_rules router \
+ "set reassemble yes" \
+ "set state-policy if-bound" \
+ "pass in on ${epair_tester}b \
+ route-to { (${epair_server2}a ${net_server2_4}.40/31) } random prefer-ipv6-nexthop \
+ proto tcp \
+ keep state"
+
+ atf_check -s exit:1 ${common_dir}/pft_ping.py \
+ --sendif ${epair_tester}a --replyif ${epair_tester}a \
+ --fromaddr ${net_clients_6}::1 --to ${host_server_6} \
+ --ping-type=tcp3way --send-sport=4201
+
+ atf_check -o "match:map-failed +1 +" -x "jexec router pfctl -qvvsi 2> /dev/null"
+}
+
+prefer_ipv6_nexthop_ipv4_random_prefix_ipv6_cleanup()
+{
+ pft_cleanup
+}
+
atf_init_test_cases()
{
atf_add_test_case "v4"
@@ -995,5 +1651,25 @@ atf_init_test_cases()
atf_add_test_case "sticky"
atf_add_test_case "ttl"
atf_add_test_case "empty_pool"
+ # Tests for pf_map_addr() without prefer-ipv6-nexthop
atf_add_test_case "table_loop"
+ atf_add_test_case "roundrobin"
+ atf_add_test_case "random_table"
+ atf_add_test_case "random_prefix"
+ # Tests for pf_map_addr() without prefer-ipv6-nexthop
+ # Next hop is a Single IP address
+ atf_add_test_case "prefer_ipv6_nexthop_single_ipv4"
+ atf_add_test_case "prefer_ipv6_nexthop_single_ipv6"
+ # Next hop is tables and prefixes, accessed by the round-robin algorithm
+ atf_add_test_case "prefer_ipv6_nexthop_mixed_af_roundrobin_ipv4"
+ atf_add_test_case "prefer_ipv6_nexthop_mixed_af_roundrobin_ipv6"
+ # Next hop is a table, accessed by the random algorithm
+ atf_add_test_case "prefer_ipv6_nexthop_mixed_af_random_table_ipv4"
+ atf_add_test_case "prefer_ipv6_nexthop_ipv4_random_table_ipv4"
+ atf_add_test_case "prefer_ipv6_nexthop_ipv4_random_table_ipv6"
+ # Next hop is a prefix, accessed by the random algorithm
+ atf_add_test_case "prefer_ipv6_nexthop_ipv6_random_prefix_ipv4"
+ atf_add_test_case "prefer_ipv6_nexthop_ipv6_random_prefix_ipv6"
+ atf_add_test_case "prefer_ipv6_nexthop_ipv4_random_prefix_ipv4"
+ atf_add_test_case "prefer_ipv6_nexthop_ipv4_random_prefix_ipv6"
}
diff --git a/tests/sys/netpfil/pf/sctp.sh b/tests/sys/netpfil/pf/sctp.sh
index 57dcdad1d866..78055f5a9dd2 100644
--- a/tests/sys/netpfil/pf/sctp.sh
+++ b/tests/sys/netpfil/pf/sctp.sh
@@ -673,6 +673,9 @@ pfsync_body()
atf_fail "Initial SCTP connection failed"
fi
+ # Give pfsync some time to do its thing
+ sleep 1
+
# Verify that two has the connection too
state=$(jexec ${j}two pfctl -ss | grep sctp)
if [ -z "${state}" ];
diff --git a/tests/sys/netpfil/pf/src_track.sh b/tests/sys/netpfil/pf/src_track.sh
index ae60a5df809b..e12d0464ee8c 100755
--- a/tests/sys/netpfil/pf/src_track.sh
+++ b/tests/sys/netpfil/pf/src_track.sh
@@ -526,10 +526,12 @@ mixed_af_body()
"block" \
"pass inet6 proto icmp6 icmp6-type { neighbrsol, neighbradv }" \
"pass in on ${epair_tester}b \
- route-to { (${epair_server1}a ${net_server1_4_host_server}) \
- } sticky-address \
- inet6 proto tcp from any to 64:ff9b::/96 \
- af-to inet from ${net_clients_4}.0/${net_clients_4_mask} round-robin sticky-address"
+ route-to { \
+ (${epair_server1}a ${net_server1_4_host_server}) \
+ (${epair_server2}a ${net_server2_6_host_server}) \
+ } prefer-ipv6-nexthop sticky-address \
+ inet6 proto tcp from any to 64:ff9b::/96 \
+ af-to inet from ${net_clients_4}.0/${net_clients_4_mask} round-robin sticky-address"
atf_check -s exit:0 ${common_dir}/pft_ping.py \
--sendif ${epair_tester}a \
@@ -538,6 +540,20 @@ mixed_af_body()
--to 64:ff9b::192.0.2.100 \
--ping-type=tcp3way \
--send-sport=4201
+ atf_check -s exit:0 ${common_dir}/pft_ping.py \
+ --sendif ${epair_tester}a \
+ --replyif ${epair_tester}a \
+ --fromaddr 2001:db8:44::1 \
+ --to 64:ff9b::192.0.2.100 \
+ --ping-type=tcp3way \
+ --send-sport=4202
+ atf_check -s exit:0 ${common_dir}/pft_ping.py \
+ --sendif ${epair_tester}a \
+ --replyif ${epair_tester}a \
+ --fromaddr 2001:db8:44::2 \
+ --to 64:ff9b::192.0.2.100 \
+ --ping-type=tcp3way \
+ --send-sport=4203
states=$(mktemp) || exit 1
jexec router pfctl -qvvss | normalize_pfctl_s > $states
@@ -546,16 +562,22 @@ mixed_af_body()
# States are checked for proper route-to information.
# The route-to gateway is IPv4.
+ # FIXME: Sticky-address is broken for af-to pools!
+ # The SN is created but apparently not used, as seen in states.
for state_regexp in \
- "${epair_tester}b tcp 203.0.113.0:4201 \(2001:db8:44::1\[4201\]\) -> 192.0.2.100:9 \(64:ff9b::c000:264\[9\]\) .* route-to: 198.51.100.18@${epair_server1}a" \
+ "${epair_tester}b tcp 203.0.113.0:4201 \(2001:db8:44::1\[4201\]\) -> 192.0.2.100:9 \(64:ff9b::c000:264\[9\]\) .* route-to: 2001:db8:4202::2@${epair_server2}a" \
+ "${epair_tester}b tcp 203.0.113.1:4202 \(2001:db8:44::1\[4202\]\) -> 192.0.2.100:9 \(64:ff9b::c000:264\[9\]\) .* route-to: 2001:db8:4202::2@${epair_server2}a" \
+ "${epair_tester}b tcp 203.0.113.2:4203 \(2001:db8:44::2\[4203\]\) -> 192.0.2.100:9 \(64:ff9b::c000:264\[9\]\) .* route-to: 198.51.100.18@${epair_server1}a" \
; do
grep -qE "${state_regexp}" $states || atf_fail "State not found for '${state_regexp}'"
done
# Source nodes map IPv6 source address onto IPv4 gateway and IPv4 SNAT address.
for node_regexp in \
- '2001:db8:44::1 -> 203.0.113.0 .* states 1, .* NAT/RDR sticky-address' \
- '2001:db8:44::1 -> 198.51.100.18 .* states 1, .* route sticky-address' \
+ '2001:db8:44::2 -> 203.0.113.2 .* states 1, .* NAT/RDR sticky-address' \
+ '2001:db8:44::2 -> 198.51.100.18 .* states 1, .* route sticky-address' \
+ '2001:db8:44::1 -> 203.0.113.0 .* states 2, .* NAT/RDR sticky-address' \
+ '2001:db8:44::1 -> 2001:db8:4202::2 .* states 2, .* route sticky-address' \
; do
grep -qE "${node_regexp}" $nodes || atf_fail "Source node not found for '${node_regexp}'"
done
diff --git a/tests/sys/netpfil/pf/utils.subr b/tests/sys/netpfil/pf/utils.subr
index 3f8d437920f9..a48f26653f8c 100644
--- a/tests/sys/netpfil/pf/utils.subr
+++ b/tests/sys/netpfil/pf/utils.subr
@@ -274,8 +274,8 @@ setup_router_server_ipv6()
jexec server inetd -p ${PWD}/inetd.pid $inetd_conf
}
-# Create a router and 2 server jails for nat64 and rfc5549 test cases.
-# The router is connected to servers, both are dual-stack, and to the
+# Create a router and 2 server jails for nat64 and prefer-ipv6-nexthop test
+# cases. The router is connected to servers, both are dual-stack, and to the
# tester jail. All links are dual stack.
setup_router_server_nat64()
{
diff --git a/tools/build/mk/OptionalObsoleteFiles.inc b/tools/build/mk/OptionalObsoleteFiles.inc
index 5eea402c4526..a2fb28f1a186 100644
--- a/tools/build/mk/OptionalObsoleteFiles.inc
+++ b/tools/build/mk/OptionalObsoleteFiles.inc
@@ -3793,11 +3793,14 @@ OLD_FILES+=usr/share/man/man1/host.1.gz
.endif
.if ${MK_LEGACY_CONSOLE} == no
+OLD_FILES+=etc/moused.conf
OLD_FILES+=etc/rc.d/moused
+OLD_FILES+=etc/rc.d/msconvd
OLD_FILES+=etc/rc.d/syscons
OLD_FILES+=usr/sbin/kbdcontrol
OLD_FILES+=usr/sbin/kbdmap
OLD_FILES+=usr/sbin/moused
+OLD_FILES+=usr/sbin/msconvd
OLD_FILES+=usr/sbin/vidcontrol
OLD_FILES+=usr/sbin/vidfont
OLD_FILES+=usr/share/man/man1/kbdcontrol.1.gz
@@ -3806,7 +3809,11 @@ OLD_FILES+=usr/share/man/man1/vidcontrol.1.gz
OLD_FILES+=usr/share/man/man1/vidfont.1.gz
OLD_FILES+=usr/share/man/man5/kbdmap.5.gz
OLD_FILES+=usr/share/man/man5/keymap.5.gz
+OLD_FILES+=usr/share/man/man5/moused.conf.5.gz
OLD_FILES+=usr/share/man/man8/moused.8.gz
+OLD_FILES+=usr/share/man/man8/msconvd.8.gz
+OLD_FILES+=usr/share/moused/5-generic-touchpad.quirks
+OLD_DIRS+=usr/share/moused
.endif
.for LIBCOMPAT libcompat in ${_ALL_LIBCOMPATS_libcompats}
diff --git a/tools/coccinelle/pseudofs-create.cocci b/tools/coccinelle/pseudofs-create.cocci
new file mode 100644
index 000000000000..ba5870f38732
--- /dev/null
+++ b/tools/coccinelle/pseudofs-create.cocci
@@ -0,0 +1,35 @@
+@ pfs_create_dir_ret_ident @
+ expression _pfn, E1, E2, E3, E4, E5, E6;
+@@
+-_pfn = pfs_create_dir(E1, E2, E3, E4, E5, E6);
++pfs_create_dir(E1, &_pfn, E2, E3, E4, E5, E6);
+
+@ pfs_create_file_ret @
+ expression _pfn, E1, E2, E3, E4, E5, E6, E7;
+@@
+-_pfn = pfs_create_file(E1, E2, E3, E4, E5, E6, E7);
++pfs_create_file(E1, &_pfn, E2, E3, E4, E5, E6, E7);
+
+@ pfs_create_link_ret @
+ expression _pfn, E1, E2, E3, E4, E5, E6, E7;
+@@
+-_pfn = pfs_create_link(E1, E2, E3, E4, E5, E6, E7);
++pfs_create_link(E1, &_pfn, E2, E3, E4, E5, E6, E7);
+
+@ pfs_create_dir_noret @
+ expression E1, E2, E3, E4, E5, E6;
+@@
+-pfs_create_dir(E1, E2, E3, E4, E5, E6);
++pfs_create_dir(E1, NULL, E2, E3, E4, E5, E6);
+
+@ pfs_create_file_noret @
+ expression E1, E2, E3, E4, E5, E6, E7;
+@@
+-pfs_create_file(E1, E2, E3, E4, E5, E6, E7);
++pfs_create_file(E1, NULL, E2, E3, E4, E5, E6, E7);
+
+@ pfs_create_link_noret @
+ expression E1, E2, E3, E4, E5, E6, E7;
+@@
+-pfs_create_link(E1, E2, E3, E4, E5, E6, E7);
++pfs_create_link(E1, NULL, E2, E3, E4, E5, E6, E7);
diff --git a/usr.bin/awk/awk.1 b/usr.bin/awk/awk.1
index 65c91738966b..612669629a02 100644
--- a/usr.bin/awk/awk.1
+++ b/usr.bin/awk/awk.1
@@ -21,7 +21,7 @@
.\" IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
.\" ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
.\" THIS SOFTWARE.
-.Dd July 30, 2021
+.Dd September 3, 2025
.Dt AWK 1
.Os
.Sh NAME
@@ -32,7 +32,7 @@
.Op Fl safe
.Op Fl version
.Op Fl d Ns Op Ar n
-.Op Fl F Ar fs
+.Op Fl F Ar fs | Fl -csv
.Op Fl v Ar var Ns = Ns Ar value
.Op Ar prog | Fl f Ar progfile
.Ar
@@ -42,9 +42,11 @@ scans each input
.Ar file
for lines that match any of a set of patterns specified literally in
.Ar prog
-or in one or more files specified as
+or in one or more files
+specified as
.Fl f Ar progfile .
-With each pattern there can be an associated action that will be performed
+With each pattern
+there can be an associated action that will be performed
when a line of a
.Ar file
matches the pattern.
@@ -76,6 +78,11 @@ to dump core on fatal errors.
.It Fl F Ar fs
Define the input field separator to be the regular expression
.Ar fs .
+.It Fl -csv
+causes
+.Nm
+to process records using (more or less) standard comma-separated values
+(CSV) format.
.It Fl f Ar progfile
Read program code from the specified file
.Ar progfile
@@ -178,7 +185,7 @@ as the field separator, use the
option with a value of
.Sq [t] .
.Pp
-A pattern-action statement has the form
+A pattern-action statement has the form:
.Pp
.D1 Ar pattern Ic \&{ Ar action Ic \&}
.Pp
@@ -347,7 +354,7 @@ in a pattern.
A pattern may consist of two patterns separated by a comma;
in this case, the action is performed for all lines
from an occurrence of the first pattern
-through an occurrence of the second.
+through an occurrence of the second, inclusive.
.Pp
A relational expression is one of the following:
.Pp
@@ -363,7 +370,8 @@ A relational expression is one of the following:
.Pp
where a
.Ar relop
-is any of the six relational operators in C, and a
+is any of the six relational operators in C,
+and a
.Ar matchop
is either
.Ic ~
@@ -386,6 +394,9 @@ and after the last.
and
.Ic END
do not combine with other patterns.
+They may appear multiple times in a program and execute
+in the order they are read by
+.Nm
.Pp
Variable names with special meanings:
.Pp
@@ -428,6 +439,11 @@ The length of the string matched by the
function.
.It Va RS
Input record separator (default newline).
+If empty, blank lines separate records.
+If more than one character long,
+.Va RS
+is treated as a regular expression, and records are
+separated by text matching the expression.
.It Va RSTART
The starting position of the string matched by the
.Fn match
@@ -515,7 +531,8 @@ occurs, or 0 if it does not.
The length of
.Fa s
taken as a string,
-or of
+number of elements in an array for an array argument,
+or length of
.Va $0
if no argument is given.
.It Fn match s r
@@ -696,10 +713,44 @@ records from
.Ar file
remains open until explicitly closed with a call to
.Fn close .
+.It Fn systime
+returns the current date and time as a standard
+.Dq seconds since the epoch
+value.
+.It Fn strftime fmt timestamp
+formats
+.Fa timestamp
+(a value in seconds since the epoch)
+according to
+Fa fmt ,
+which is a format string as supported by
+.Xr strftime 3 .
+Both
+.Fa timestamp
+and
+.Fa fmt
+may be omitted; if no
+.Fa timestamp ,
+the current time of day is used, and if no
+.Fa fmt ,
+a default format of
+.Dq %a %b %e %H:%M:%S %Z %Y
+is used.
.It Fn system cmd
Executes
.Fa cmd
and returns its exit status.
+This will be -1 upon error,
+.Fa cmd 's
+exit status upon a normal exit,
+256 +
+.Va sig
+upon death-by-signal, where
+.Va sig
+is the number of the murdering signal,
+or 512 +
+.Va sig
+if there was a core dump.
.El
.Ss Bit-Operation Functions
.Bl -tag -width "lshift(a, b)"
@@ -725,6 +776,16 @@ Returns integer argument x shifted by n bits to the right.
But note that the
.Ic exit
expression can modify the exit status.
+.Sh ENVIRONMENT VARIABLES
+If
+.Va POSIXLY_CORRECT
+is set in the environment, then
+.Nm
+follows the POSIX rules for
+.Fn sub
+and
+.Fn gsub
+with respect to consecutive backslashes and ampersands.
.Sh EXAMPLES
Print lines longer than 72 characters:
.Pp
@@ -734,7 +795,7 @@ Print first two fields in opposite order:
.Pp
.Dl { print $2, $1 }
.Pp
-Same, with input fields separated by comma and/or blanks and tabs:
+Same, with input fields separated by comma and/or spaces and tabs:
.Bd -literal -offset indent
BEGIN { FS = ",[ \et]*|[ \et]+" }
{ print $2, $1 }
@@ -810,6 +871,63 @@ to it.
.Pp
The scope rules for variables in functions are a botch;
the syntax is worse.
+.Pp
+Input is expected to be UTF-8 encoded.
+Other multibyte character sets are not handled.
+However, in eight-bit locales,
+.Nm
+treats each input byte as a separate character.
+.Sh UNUSUAL FLOATING-POINT VALUES
+.Nm
+was designed before IEEE 754 arithmetic defined Not-A-Number (NaN)
+and Infinity values, which are supported by all modern floating-point
+hardware.
+.Pp
+Because
+.Nm
+uses
+.Xr strtod 3
+and
+.Xr atof 3
+to convert string values to double-precision floating-point values,
+modern C libraries also convert strings starting with
+.Va inf
+and
+.Va nan
+into infinity and NaN values respectively.
+This led to strange results,
+with something like this:
+.Bd -literal -offset indent
+echo nancy | awk '{ print $1 + 0 }'
+.Ed
+.Pp
+printing
+.Dq nan
+instead of zero.
+.Pp
+.Nm
+now follows GNU AWK, and prefilters string values before attempting
+to convert them to numbers, as follows:
+.Bl -tag -width "Hexadecimal values"
+.It Hexadecimal values
+Hexadecimal values (allowed since C99) convert to zero, as they did
+prior to C99.
+.It NaN values
+The two strings
+.Dq +nan
+and
+.Dq -nan
+(case independent) convert to NaN.
+No others do.
+(NaNs can have signs.)
+.It Infinity values
+The two strings
+.Dq +inf
+and
+.Dq -inf
+(case independent) convert to positive and negative infinity, respectively.
+No others do.
+.El
.Sh DEPRECATED BEHAVIOR
One True Awk has accepted
.Fl F Ar t
diff --git a/usr.bin/mandoc/Makefile b/usr.bin/mandoc/Makefile
index c5255b1468fd..0d04aad4e558 100644
--- a/usr.bin/mandoc/Makefile
+++ b/usr.bin/mandoc/Makefile
@@ -4,7 +4,7 @@ MANDOCDIR= ${SRCTOP}/contrib/mandoc
.PATH: ${MANDOCDIR}
PROG= mandoc
-MAN= mandoc.1 eqn.7 mandoc_char.7 tbl.7 man.7 mdoc.7 roff.7
+MAN= mandoc.1 mandoc.db.5 eqn.7 mandoc_char.7 tbl.7 man.7 mdoc.7 roff.7
MLINKS= mandoc.1 mdocml.1
.if ${MK_MAN_UTILS} != no
MAN+= apropos.1 makewhatis.8
diff --git a/usr.bin/netstat/inet.c b/usr.bin/netstat/inet.c
index 7014f02032c2..5f36b1599cad 100644
--- a/usr.bin/netstat/inet.c
+++ b/usr.bin/netstat/inet.c
@@ -767,15 +767,20 @@ tcp_stats(u_long off, const char *name, int af1 __unused, int proto __unused)
p1a(tcps_sc_badack, "\t\t{:bad-ack/%ju} {N:/badack}\n");
p1a(tcps_sc_unreach, "\t\t{:unreachable/%ju} {N:/unreach}\n");
p(tcps_sc_zonefail, "\t\t{:zone-failures/%ju} {N:/zone failure%s}\n");
+
+ xo_close_container("syncache");
+
+ xo_open_container("syncookies");
+
p(tcps_sc_sendcookie, "\t{:sent-cookies/%ju} {N:/cookie%s sent}\n");
- p(tcps_sc_recvcookie, "\t{:received-cookies/%ju} "
+ p(tcps_sc_recvcookie, "\t\t{:received-cookies/%ju} "
"{N:/cookie%s received}\n");
- p(tcps_sc_spurcookie, "\t{:spurious-cookies/%ju} "
+ p(tcps_sc_spurcookie, "\t\t{:spurious-cookies/%ju} "
"{N:/spurious cookie%s rejected}\n");
- p(tcps_sc_failcookie, "\t{:failed-cookies/%ju} "
+ p(tcps_sc_failcookie, "\t\t{:failed-cookies/%ju} "
"{N:/failed cookie%s rejected}\n");
- xo_close_container("syncache");
+ xo_close_container("syncookies");
xo_open_container("hostcache");
diff --git a/usr.bin/patch/tests/unified_patch_test.sh b/usr.bin/patch/tests/unified_patch_test.sh
index 7d4b74182c41..a91332908773 100755
--- a/usr.bin/patch/tests/unified_patch_test.sh
+++ b/usr.bin/patch/tests/unified_patch_test.sh
@@ -141,6 +141,23 @@ file_removal_body()
atf_check -o inline:"y\n" cat foo
}
+atf_test_case namespace
+namespace_head()
+{
+ atf_set "descr" "Test that patch(1) handles files with spaces in the name"
+}
+namespace_body()
+{
+ echo "ABC" > "with spaces.orig"
+ echo "ZYX" > "with spaces"
+
+ atf_check -s not-exit:0 -o save:spaces.diff \
+ diff -u "with spaces.orig" "with spaces"
+
+ atf_check mv "with spaces.orig" "with spaces"
+ atf_check -o not-empty patch < spaces.diff
+}
+
atf_test_case plinelen
plinelen_body()
{
@@ -166,5 +183,6 @@ atf_init_test_cases()
atf_add_test_case file_creation
atf_add_test_case file_nodupe
atf_add_test_case file_removal
+ atf_add_test_case namespace
atf_add_test_case plinelen
}
diff --git a/usr.bin/w/pr_time.c b/usr.bin/w/pr_time.c
index aef8b5dfaa87..445431fe3ec5 100644
--- a/usr.bin/w/pr_time.c
+++ b/usr.bin/w/pr_time.c
@@ -79,8 +79,13 @@ pr_attime(time_t *started, time_t *now)
(void)wcsftime(buf, sizeof(buf), fmt, &tp);
len = wcslen(buf);
width = wcswidth(buf, len);
- xo_attr("since", "%lu", (unsigned long) *started);
- xo_attr("delta", "%lu", (unsigned long) diff);
+ if (xo_get_style(NULL) == XO_STYLE_XML) {
+ xo_attr("since", "%lu", (unsigned long)*started);
+ xo_attr("delta", "%lu", (unsigned long)diff);
+ } else {
+ xo_emit("{e:login-time-since/%lu}{e:login-time-delta/%lu}",
+ (unsigned long)*started, (unsigned long)diff);
+ }
if (len == width)
xo_emit("{:login-time/%-7.7ls/%ls}", buf);
else if (width < 7)
@@ -100,10 +105,16 @@ pr_attime(time_t *started, time_t *now)
int
pr_idle(time_t idle)
{
+ /* In encoded formats, emit the raw data as well */
+ if (xo_get_style(NULL) == XO_STYLE_XML)
+ xo_attr("seconds", "%lu", (unsigned long) idle);
+ else
+ xo_emit("{e:idle-seconds/%lu}", (unsigned long) idle);
+
/* If idle more than 36 hours, print as a number of days. */
if (idle >= 36 * 3600) {
int days = idle / 86400;
- xo_emit(" {:idle/%dday%s} ", days, days > 1 ? "s" : " " );
+ xo_emit(" {q:idle/%dday%s} ", days, days > 1 ? "s" : " " );
if (days >= 100)
return (2);
if (days >= 10)
@@ -111,16 +122,17 @@ pr_idle(time_t idle)
}
/* If idle more than an hour, print as HH:MM. */
- else if (idle >= 3600)
- xo_emit(" {:idle/%2d:%02d/} ",
+ else if (idle >= 3600) {
+ xo_emit(" {q:idle/%2d:%02d} ",
(int)(idle / 3600), (int)((idle % 3600) / 60));
+ }
else if (idle / 60 == 0)
- xo_emit(" - ");
+ xo_emit(" - {q:idle//0}");
/* Else print the minutes idle. */
else
- xo_emit(" {:idle/%2d} ", (int)(idle / 60));
+ xo_emit(" {q:idle/%2d} ", (int)(idle / 60));
return (0); /* not idle longer than 9 days */
}
diff --git a/usr.sbin/bhyve/rfb.c b/usr.sbin/bhyve/rfb.c
index 6af374a83bbe..716e191e2fc0 100644
--- a/usr.sbin/bhyve/rfb.c
+++ b/usr.sbin/bhyve/rfb.c
@@ -63,6 +63,7 @@
#include "bhyvegc.h"
#include "debug.h"
#include "console.h"
+#include "config.h"
#include "rfb.h"
#include "sockstream.h"
@@ -152,6 +153,8 @@ struct rfb_softc {
struct pixfmt pixfmt; /* owned by the write thread */
struct pixfmt new_pixfmt; /* managed with pixfmt_mtx */
uint32_t *pixrow;
+ char *fbname;
+ int fbnamelen;
};
struct rfb_pixfmt {
@@ -262,7 +265,7 @@ struct rfb_cuttext_msg {
};
static void
-rfb_send_server_init_msg(int cfd)
+rfb_send_server_init_msg(struct rfb_softc *rc, int cfd)
{
struct bhyvegc_image *gc_image;
struct rfb_srvr_info sinfo;
@@ -284,9 +287,9 @@ rfb_send_server_init_msg(int cfd)
sinfo.pixfmt.pad[0] = 0;
sinfo.pixfmt.pad[1] = 0;
sinfo.pixfmt.pad[2] = 0;
- sinfo.namelen = htonl(strlen("bhyve"));
+ sinfo.namelen = htonl(rc->fbnamelen);
(void)stream_write(cfd, &sinfo, sizeof(sinfo));
- (void)stream_write(cfd, "bhyve", strlen("bhyve"));
+ (void)stream_write(cfd, rc->fbname, rc->fbnamelen);
}
static void
@@ -1144,7 +1147,7 @@ report_and_done:
len = stream_read(cfd, buf, 1);
/* 4a. Write server-init info */
- rfb_send_server_init_msg(cfd);
+ rfb_send_server_init_msg(rc, cfd);
if (!rc->zbuf) {
rc->zbuf = malloc(RFB_ZLIB_BUFSZ + 16);
@@ -1276,6 +1279,13 @@ rfb_init(const char *hostname, int port, int wait, const char *password)
rc->password = password;
+ rc->fbnamelen = asprintf(&rc->fbname, "bhyve:%s",
+ get_config_value("name"));
+ if (rc->fbnamelen < 0) {
+ EPRINTLN("rfb: failed to allocate memory for VNC title");
+ goto error;
+ }
+
rc->pixrow = malloc(RFB_MAX_WIDTH * sizeof(uint32_t));
if (rc->pixrow == NULL) {
EPRINTLN("rfb: failed to allocate memory for pixrow buffer");
@@ -1358,6 +1368,7 @@ rfb_init(const char *hostname, int port, int wait, const char *password)
free(rc->crc);
free(rc->crc_tmp);
free(rc->pixrow);
+ free(rc->fbname);
free(rc);
return (-1);
}
diff --git a/usr.sbin/ctld/ctld.hh b/usr.sbin/ctld/ctld.hh
index bfe4507bb3e6..cc88e6eb590e 100644
--- a/usr.sbin/ctld/ctld.hh
+++ b/usr.sbin/ctld/ctld.hh
@@ -425,7 +425,7 @@ protected:
virtual struct portal_group *default_portal_group() = 0;
struct conf *t_conf;
- std::array<struct lun *, MAX_LUNS> t_luns;
+ std::array<struct lun *, MAX_LUNS> t_luns = {};
auth_group_sp t_auth_group;
std::list<port *> t_ports;
std::string t_name;
@@ -434,7 +434,7 @@ protected:
std::string t_redirection;
/* Name of this target's physical port, if any, i.e. "isp0" */
std::string t_pport;
- bool t_private_auth;
+ bool t_private_auth = false;
};
using target_up = std::unique_ptr<target>;
@@ -575,7 +575,7 @@ struct pport {
private:
std::string pp_name;
uint32_t pp_ctl_port;
- bool pp_linked;
+ bool pp_linked = false;
};
struct kports {
diff --git a/usr.sbin/ctld/iscsi.hh b/usr.sbin/ctld/iscsi.hh
index d510e8c6731b..66bfecd62692 100644
--- a/usr.sbin/ctld/iscsi.hh
+++ b/usr.sbin/ctld/iscsi.hh
@@ -66,7 +66,7 @@ private:
std::string conn_initiator_name;
std::string conn_initiator_addr;
std::string conn_initiator_alias;
- uint8_t conn_initiator_isid[6];
+ uint8_t conn_initiator_isid[6] = {};
const struct sockaddr *conn_initiator_sa = nullptr;
int conn_max_recv_data_segment_limit = 0;
int conn_max_send_data_segment_limit = 0;
diff --git a/usr.sbin/devinfo/devinfo.8 b/usr.sbin/devinfo/devinfo.8
index f782b919056c..c34713d367ff 100644
--- a/usr.sbin/devinfo/devinfo.8
+++ b/usr.sbin/devinfo/devinfo.8
@@ -1,4 +1,5 @@
-.\" -*- nroff -*-
+.\"
+.\" SPDX-License-Identifer: BSD-2-Clause
.\"
.\" Copyright (c) 2002 Hiten Pandya
.\" Copyright (c) 2002 Robert N. M. Watson
@@ -25,7 +26,7 @@
.\" (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 January 29, 2025
+.Dd August 28, 2025
.Dt DEVINFO 8
.Os
.Sh NAME
@@ -33,11 +34,14 @@
.Nd print information about system device configuration
.Sh SYNOPSIS
.Nm
+.Op Fl -libxo
.Op Fl rv
.Nm
-.Fl u Op Fl v
-.Nm
+.Op Fl -libxo
.Fl p Ar dev Op Fl v
+.Nm
+.Op Fl -libxo
+.Fl u Op Fl v
.Sh DESCRIPTION
The
.Nm
@@ -46,11 +50,23 @@ in the system, starting from the
.Dq nexus
device.
.Pp
-The following options are accepted.
-.Bl -tag -width indent
+The following options are accepted:
+.Bl -tag -width "--libxo"
+.It Fl -libxo
+Generate output via
+.Xr libxo 3
+in a selection of different human and machine readable formats.
+See
+.Xr xo_options 7
+for details on command line arguments.
+.It Fl p Ar dev
+Display the path of
+.Ar dev
+back to the root of the device tree.
.It Fl r
-Causes hardware resource information (such as IRQ, I/O ports, I/O memory
-addresses) to be also listed, under each device that has reserved those resources.
+Causes hardware resource information
+.Pq such as IRQ, I/O ports, I/O memory addresses
+to be also listed, under each device that has reserved those resources.
.It Fl u
Displays the same information as with
.Fl r
@@ -63,19 +79,22 @@ Display all devices in the driver tree, not just those that are attached or
busy.
Without this flag, only those devices that have attached are reported.
This flag also displays verbose information about each device.
-.It Fl p Ar dev
-Display the path of
-.Ar dev
-back to the root of the device tree.
.El
.Sh SEE ALSO
.Xr systat 1 ,
.Xr devinfo 3 ,
+.Xr libxo 3 ,
+.Xr xo_options 7 ,
.Xr devctl 8 ,
.Xr iostat 8 ,
.Xr pciconf 8 ,
.Xr vmstat 8 ,
.Xr devclass 9 ,
.Xr device 9
+.Sh HISTORY
+The
+.Nm
+utility appeared in
+.Fx 5.0 .
.Sh AUTHORS
.An Mike Smith Aq Mt msmith@FreeBSD.org
diff --git a/usr.sbin/fwget/pci/pci b/usr.sbin/fwget/pci/pci
index fbdfa0001c5c..de8b7c8bb2b3 100644
--- a/usr.sbin/fwget/pci/pci
+++ b/usr.sbin/fwget/pci/pci
@@ -27,7 +27,7 @@
pci_get_class()
{
- local hexclass=$(echo $1 | sed 's/.*class=\(0x[0-9a-z]\{2\}\).*/\1/')
+ local hexclass=$(echo $1 | sed 's/.*class=\(0x[0-9a-f]\{2\}\).*/\1/')
case "${hexclass}" in
0x00) echo "old" ;; # built before class codes were finalized
0x02) echo "network" ;;
@@ -38,7 +38,7 @@ pci_get_class()
pci_get_vendor()
{
- local hexvendor=$(echo $1 | sed 's/.*\ vendor=\(0x[0-9a-z]*\).*/\1/')
+ local hexvendor=$(echo $1 | sed 's/.*\ vendor=\(0x[0-9a-f]*\).*/\1/')
case "${hexvendor}" in
0x1002) echo "amd" ;;
@@ -52,7 +52,7 @@ pci_get_vendor()
pci_get_device()
{
- local hexdevice=$(echo $1 | sed 's/.*\ device=\(0x[0-9a-z]*\).*/\1/')
+ local hexdevice=$(echo $1 | sed 's/.*\ device=\(0x[0-9a-f]*\).*/\1/')
echo ${hexdevice}
}
diff --git a/usr.sbin/fwget/pci/pci_video_amd b/usr.sbin/fwget/pci/pci_video_amd
index 5017789b9f28..7e50454d3944 100644
--- a/usr.sbin/fwget/pci/pci_video_amd
+++ b/usr.sbin/fwget/pci/pci_video_amd
@@ -48,7 +48,7 @@ pci_video_amd()
0x13*)
addpkg "gpu-firmware-amd-kmod-kaveri"
;;
- 0x664*|0x664*)
+ 0x664*|0x665*)
addpkg "gpu-firmware-amd-kmod-bonaire"
;;
0x67a*|0x67b*)
@@ -72,7 +72,7 @@ pci_video_amd()
0x987*)
addpkg "gpu-firmware-amd-kmod-carrizo"
;;
- 0x98e4*)
+ 0x98e4)
addpkg "gpu-firmware-amd-kmod-stoney"
;;
0x67e*|0x67ff)
@@ -111,7 +111,10 @@ pci_video_amd()
0x734*)
addpkg "gpu-firmware-amd-kmod-navi14"
;;
- 0x15e7|0x1636|0x1638|0x164c)
+ 0x15e7|0x1638)
+ addpkg "gpu-firmware-amd-kmod-renoir gpu-firmware-amd-kmod-green-sardine"
+ ;;
+ 0x1636|0x164c)
addpkg "gpu-firmware-amd-kmod-renoir"
;;
0x736*)
@@ -135,7 +138,7 @@ pci_video_amd()
0x740*|0x741*)
addpkg "gpu-firmware-amd-kmod-aldebaran"
;;
- 0x13fe)
+ 0x13fe|0x143f)
addpkg "gpu-firmware-amd-kmod-cyan-skillfish2"
;;
0x742*|0x743*)
diff --git a/usr.sbin/moused/Makefile b/usr.sbin/moused/Makefile
index 2a7aa0484542..b6319b6fef20 100644
--- a/usr.sbin/moused/Makefile
+++ b/usr.sbin/moused/Makefile
@@ -1,10 +1,4 @@
-PACKAGE= console-tools
-PROG= moused
-MAN= moused.8
+SUBDIR+=moused
+SUBDIR+=msconvd
-LIBADD= m util
-
-#BINMODE=4555
-#PRECIOUSPROG=
-
-.include <bsd.prog.mk>
+.include <bsd.subdir.mk>
diff --git a/usr.sbin/moused/Makefile.depend b/usr.sbin/moused/Makefile.depend
deleted file mode 100644
index af3b7054df7a..000000000000
--- a/usr.sbin/moused/Makefile.depend
+++ /dev/null
@@ -1,17 +0,0 @@
-# Autogenerated - do NOT edit!
-
-DIRDEPS = \
- include \
- include/xlocale \
- lib/${CSU_DIR} \
- lib/libc \
- lib/libcompiler_rt \
- lib/libutil \
- lib/msun \
-
-
-.include <dirdeps.mk>
-
-.if ${DEP_RELDIR} == ${_DEP_RELDIR}
-# local dependencies - needed for -jN in clean tree
-.endif
diff --git a/usr.sbin/moused/moused/Makefile b/usr.sbin/moused/moused/Makefile
new file mode 100644
index 000000000000..8479764b710b
--- /dev/null
+++ b/usr.sbin/moused/moused/Makefile
@@ -0,0 +1,28 @@
+PACKAGE= console-tools
+PROG= moused
+
+SRCS= moused.c \
+ event-names.h \
+ quirks.c \
+ quirks.h \
+ util.c \
+ util.h \
+ util-evdev.c \
+ util-evdev.h \
+ util-list.c \
+ util-list.h
+MAN= moused.8 \
+ moused.conf.5
+CONFS= moused.conf
+QUIRKS= 5-generic-touchpad.quirks
+
+CWARNFLAGS.quirks.c+= -Wno-cast-align -Wno-shadow -Wno-cast-qual \
+ -Wno-unused-variable -Wno-unused-parameter
+CWARNFLAGS.util.c+= -Wno-shadow
+LIBADD= m util
+BINDIR= /usr/sbin
+
+FILES= ${QUIRKS:S|^|quirks/|}
+FILESDIR= /usr/share/${PROG}
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/moused/moused/event-names.h b/usr.sbin/moused/moused/event-names.h
new file mode 100644
index 000000000000..05093a1d0db3
--- /dev/null
+++ b/usr.sbin/moused/moused/event-names.h
@@ -0,0 +1,1656 @@
+/* THIS FILE IS GENERATED, DO NOT EDIT */
+
+#ifndef EVENT_NAMES_H
+#define EVENT_NAMES_H
+
+static const char * const ev_map[EV_MAX + 1] = {
+ [EV_SYN] = "EV_SYN",
+ [EV_KEY] = "EV_KEY",
+ [EV_REL] = "EV_REL",
+ [EV_ABS] = "EV_ABS",
+ [EV_MSC] = "EV_MSC",
+ [EV_SW] = "EV_SW",
+ [EV_LED] = "EV_LED",
+ [EV_SND] = "EV_SND",
+ [EV_REP] = "EV_REP",
+ [EV_FF] = "EV_FF",
+ [EV_PWR] = "EV_PWR",
+ [EV_FF_STATUS] = "EV_FF_STATUS",
+ [EV_MAX] = "EV_MAX",
+};
+
+static const char * const rel_map[REL_MAX + 1] = {
+ [REL_X] = "REL_X",
+ [REL_Y] = "REL_Y",
+ [REL_Z] = "REL_Z",
+ [REL_RX] = "REL_RX",
+ [REL_RY] = "REL_RY",
+ [REL_RZ] = "REL_RZ",
+ [REL_HWHEEL] = "REL_HWHEEL",
+ [REL_DIAL] = "REL_DIAL",
+ [REL_WHEEL] = "REL_WHEEL",
+ [REL_MISC] = "REL_MISC",
+ [REL_RESERVED] = "REL_RESERVED",
+ [REL_WHEEL_HI_RES] = "REL_WHEEL_HI_RES",
+ [REL_HWHEEL_HI_RES] = "REL_HWHEEL_HI_RES",
+ [REL_MAX] = "REL_MAX",
+};
+
+static const char * const abs_map[ABS_MAX + 1] = {
+ [ABS_X] = "ABS_X",
+ [ABS_Y] = "ABS_Y",
+ [ABS_Z] = "ABS_Z",
+ [ABS_RX] = "ABS_RX",
+ [ABS_RY] = "ABS_RY",
+ [ABS_RZ] = "ABS_RZ",
+ [ABS_THROTTLE] = "ABS_THROTTLE",
+ [ABS_RUDDER] = "ABS_RUDDER",
+ [ABS_WHEEL] = "ABS_WHEEL",
+ [ABS_GAS] = "ABS_GAS",
+ [ABS_BRAKE] = "ABS_BRAKE",
+ [ABS_HAT0X] = "ABS_HAT0X",
+ [ABS_HAT0Y] = "ABS_HAT0Y",
+ [ABS_HAT1X] = "ABS_HAT1X",
+ [ABS_HAT1Y] = "ABS_HAT1Y",
+ [ABS_HAT2X] = "ABS_HAT2X",
+ [ABS_HAT2Y] = "ABS_HAT2Y",
+ [ABS_HAT3X] = "ABS_HAT3X",
+ [ABS_HAT3Y] = "ABS_HAT3Y",
+ [ABS_PRESSURE] = "ABS_PRESSURE",
+ [ABS_DISTANCE] = "ABS_DISTANCE",
+ [ABS_TILT_X] = "ABS_TILT_X",
+ [ABS_TILT_Y] = "ABS_TILT_Y",
+ [ABS_TOOL_WIDTH] = "ABS_TOOL_WIDTH",
+ [ABS_VOLUME] = "ABS_VOLUME",
+ // [ABS_PROFILE] = "ABS_PROFILE",
+ [ABS_MISC] = "ABS_MISC",
+ [ABS_RESERVED] = "ABS_RESERVED",
+ [ABS_MT_SLOT] = "ABS_MT_SLOT",
+ [ABS_MT_TOUCH_MAJOR] = "ABS_MT_TOUCH_MAJOR",
+ [ABS_MT_TOUCH_MINOR] = "ABS_MT_TOUCH_MINOR",
+ [ABS_MT_WIDTH_MAJOR] = "ABS_MT_WIDTH_MAJOR",
+ [ABS_MT_WIDTH_MINOR] = "ABS_MT_WIDTH_MINOR",
+ [ABS_MT_ORIENTATION] = "ABS_MT_ORIENTATION",
+ [ABS_MT_POSITION_X] = "ABS_MT_POSITION_X",
+ [ABS_MT_POSITION_Y] = "ABS_MT_POSITION_Y",
+ [ABS_MT_TOOL_TYPE] = "ABS_MT_TOOL_TYPE",
+ [ABS_MT_BLOB_ID] = "ABS_MT_BLOB_ID",
+ [ABS_MT_TRACKING_ID] = "ABS_MT_TRACKING_ID",
+ [ABS_MT_PRESSURE] = "ABS_MT_PRESSURE",
+ [ABS_MT_DISTANCE] = "ABS_MT_DISTANCE",
+ [ABS_MT_TOOL_X] = "ABS_MT_TOOL_X",
+ [ABS_MT_TOOL_Y] = "ABS_MT_TOOL_Y",
+ [ABS_MAX] = "ABS_MAX",
+};
+
+static const char * const key_map[KEY_MAX + 1] = {
+ [KEY_RESERVED] = "KEY_RESERVED",
+ [KEY_ESC] = "KEY_ESC",
+ [KEY_1] = "KEY_1",
+ [KEY_2] = "KEY_2",
+ [KEY_3] = "KEY_3",
+ [KEY_4] = "KEY_4",
+ [KEY_5] = "KEY_5",
+ [KEY_6] = "KEY_6",
+ [KEY_7] = "KEY_7",
+ [KEY_8] = "KEY_8",
+ [KEY_9] = "KEY_9",
+ [KEY_0] = "KEY_0",
+ [KEY_MINUS] = "KEY_MINUS",
+ [KEY_EQUAL] = "KEY_EQUAL",
+ [KEY_BACKSPACE] = "KEY_BACKSPACE",
+ [KEY_TAB] = "KEY_TAB",
+ [KEY_Q] = "KEY_Q",
+ [KEY_W] = "KEY_W",
+ [KEY_E] = "KEY_E",
+ [KEY_R] = "KEY_R",
+ [KEY_T] = "KEY_T",
+ [KEY_Y] = "KEY_Y",
+ [KEY_U] = "KEY_U",
+ [KEY_I] = "KEY_I",
+ [KEY_O] = "KEY_O",
+ [KEY_P] = "KEY_P",
+ [KEY_LEFTBRACE] = "KEY_LEFTBRACE",
+ [KEY_RIGHTBRACE] = "KEY_RIGHTBRACE",
+ [KEY_ENTER] = "KEY_ENTER",
+ [KEY_LEFTCTRL] = "KEY_LEFTCTRL",
+ [KEY_A] = "KEY_A",
+ [KEY_S] = "KEY_S",
+ [KEY_D] = "KEY_D",
+ [KEY_F] = "KEY_F",
+ [KEY_G] = "KEY_G",
+ [KEY_H] = "KEY_H",
+ [KEY_J] = "KEY_J",
+ [KEY_K] = "KEY_K",
+ [KEY_L] = "KEY_L",
+ [KEY_SEMICOLON] = "KEY_SEMICOLON",
+ [KEY_APOSTROPHE] = "KEY_APOSTROPHE",
+ [KEY_GRAVE] = "KEY_GRAVE",
+ [KEY_LEFTSHIFT] = "KEY_LEFTSHIFT",
+ [KEY_BACKSLASH] = "KEY_BACKSLASH",
+ [KEY_Z] = "KEY_Z",
+ [KEY_X] = "KEY_X",
+ [KEY_C] = "KEY_C",
+ [KEY_V] = "KEY_V",
+ [KEY_B] = "KEY_B",
+ [KEY_N] = "KEY_N",
+ [KEY_M] = "KEY_M",
+ [KEY_COMMA] = "KEY_COMMA",
+ [KEY_DOT] = "KEY_DOT",
+ [KEY_SLASH] = "KEY_SLASH",
+ [KEY_RIGHTSHIFT] = "KEY_RIGHTSHIFT",
+ [KEY_KPASTERISK] = "KEY_KPASTERISK",
+ [KEY_LEFTALT] = "KEY_LEFTALT",
+ [KEY_SPACE] = "KEY_SPACE",
+ [KEY_CAPSLOCK] = "KEY_CAPSLOCK",
+ [KEY_F1] = "KEY_F1",
+ [KEY_F2] = "KEY_F2",
+ [KEY_F3] = "KEY_F3",
+ [KEY_F4] = "KEY_F4",
+ [KEY_F5] = "KEY_F5",
+ [KEY_F6] = "KEY_F6",
+ [KEY_F7] = "KEY_F7",
+ [KEY_F8] = "KEY_F8",
+ [KEY_F9] = "KEY_F9",
+ [KEY_F10] = "KEY_F10",
+ [KEY_NUMLOCK] = "KEY_NUMLOCK",
+ [KEY_SCROLLLOCK] = "KEY_SCROLLLOCK",
+ [KEY_KP7] = "KEY_KP7",
+ [KEY_KP8] = "KEY_KP8",
+ [KEY_KP9] = "KEY_KP9",
+ [KEY_KPMINUS] = "KEY_KPMINUS",
+ [KEY_KP4] = "KEY_KP4",
+ [KEY_KP5] = "KEY_KP5",
+ [KEY_KP6] = "KEY_KP6",
+ [KEY_KPPLUS] = "KEY_KPPLUS",
+ [KEY_KP1] = "KEY_KP1",
+ [KEY_KP2] = "KEY_KP2",
+ [KEY_KP3] = "KEY_KP3",
+ [KEY_KP0] = "KEY_KP0",
+ [KEY_KPDOT] = "KEY_KPDOT",
+ [KEY_ZENKAKUHANKAKU] = "KEY_ZENKAKUHANKAKU",
+ [KEY_102ND] = "KEY_102ND",
+ [KEY_F11] = "KEY_F11",
+ [KEY_F12] = "KEY_F12",
+ [KEY_RO] = "KEY_RO",
+ [KEY_KATAKANA] = "KEY_KATAKANA",
+ [KEY_HIRAGANA] = "KEY_HIRAGANA",
+ [KEY_HENKAN] = "KEY_HENKAN",
+ [KEY_KATAKANAHIRAGANA] = "KEY_KATAKANAHIRAGANA",
+ [KEY_MUHENKAN] = "KEY_MUHENKAN",
+ [KEY_KPJPCOMMA] = "KEY_KPJPCOMMA",
+ [KEY_KPENTER] = "KEY_KPENTER",
+ [KEY_RIGHTCTRL] = "KEY_RIGHTCTRL",
+ [KEY_KPSLASH] = "KEY_KPSLASH",
+ [KEY_SYSRQ] = "KEY_SYSRQ",
+ [KEY_RIGHTALT] = "KEY_RIGHTALT",
+ [KEY_LINEFEED] = "KEY_LINEFEED",
+ [KEY_HOME] = "KEY_HOME",
+ [KEY_UP] = "KEY_UP",
+ [KEY_PAGEUP] = "KEY_PAGEUP",
+ [KEY_LEFT] = "KEY_LEFT",
+ [KEY_RIGHT] = "KEY_RIGHT",
+ [KEY_END] = "KEY_END",
+ [KEY_DOWN] = "KEY_DOWN",
+ [KEY_PAGEDOWN] = "KEY_PAGEDOWN",
+ [KEY_INSERT] = "KEY_INSERT",
+ [KEY_DELETE] = "KEY_DELETE",
+ [KEY_MACRO] = "KEY_MACRO",
+ [KEY_MUTE] = "KEY_MUTE",
+ [KEY_VOLUMEDOWN] = "KEY_VOLUMEDOWN",
+ [KEY_VOLUMEUP] = "KEY_VOLUMEUP",
+ [KEY_POWER] = "KEY_POWER",
+ [KEY_KPEQUAL] = "KEY_KPEQUAL",
+ [KEY_KPPLUSMINUS] = "KEY_KPPLUSMINUS",
+ [KEY_PAUSE] = "KEY_PAUSE",
+ [KEY_SCALE] = "KEY_SCALE",
+ [KEY_KPCOMMA] = "KEY_KPCOMMA",
+ [KEY_HANGEUL] = "KEY_HANGEUL",
+ [KEY_HANJA] = "KEY_HANJA",
+ [KEY_YEN] = "KEY_YEN",
+ [KEY_LEFTMETA] = "KEY_LEFTMETA",
+ [KEY_RIGHTMETA] = "KEY_RIGHTMETA",
+ [KEY_COMPOSE] = "KEY_COMPOSE",
+ [KEY_STOP] = "KEY_STOP",
+ [KEY_AGAIN] = "KEY_AGAIN",
+ [KEY_PROPS] = "KEY_PROPS",
+ [KEY_UNDO] = "KEY_UNDO",
+ [KEY_FRONT] = "KEY_FRONT",
+ [KEY_COPY] = "KEY_COPY",
+ [KEY_OPEN] = "KEY_OPEN",
+ [KEY_PASTE] = "KEY_PASTE",
+ [KEY_FIND] = "KEY_FIND",
+ [KEY_CUT] = "KEY_CUT",
+ [KEY_HELP] = "KEY_HELP",
+ [KEY_MENU] = "KEY_MENU",
+ [KEY_CALC] = "KEY_CALC",
+ [KEY_SETUP] = "KEY_SETUP",
+ [KEY_SLEEP] = "KEY_SLEEP",
+ [KEY_WAKEUP] = "KEY_WAKEUP",
+ [KEY_FILE] = "KEY_FILE",
+ [KEY_SENDFILE] = "KEY_SENDFILE",
+ [KEY_DELETEFILE] = "KEY_DELETEFILE",
+ [KEY_XFER] = "KEY_XFER",
+ [KEY_PROG1] = "KEY_PROG1",
+ [KEY_PROG2] = "KEY_PROG2",
+ [KEY_WWW] = "KEY_WWW",
+ [KEY_MSDOS] = "KEY_MSDOS",
+ [KEY_COFFEE] = "KEY_COFFEE",
+ [KEY_ROTATE_DISPLAY] = "KEY_ROTATE_DISPLAY",
+ [KEY_CYCLEWINDOWS] = "KEY_CYCLEWINDOWS",
+ [KEY_MAIL] = "KEY_MAIL",
+ [KEY_BOOKMARKS] = "KEY_BOOKMARKS",
+ [KEY_COMPUTER] = "KEY_COMPUTER",
+ [KEY_BACK] = "KEY_BACK",
+ [KEY_FORWARD] = "KEY_FORWARD",
+ [KEY_CLOSECD] = "KEY_CLOSECD",
+ [KEY_EJECTCD] = "KEY_EJECTCD",
+ [KEY_EJECTCLOSECD] = "KEY_EJECTCLOSECD",
+ [KEY_NEXTSONG] = "KEY_NEXTSONG",
+ [KEY_PLAYPAUSE] = "KEY_PLAYPAUSE",
+ [KEY_PREVIOUSSONG] = "KEY_PREVIOUSSONG",
+ [KEY_STOPCD] = "KEY_STOPCD",
+ [KEY_RECORD] = "KEY_RECORD",
+ [KEY_REWIND] = "KEY_REWIND",
+ [KEY_PHONE] = "KEY_PHONE",
+ [KEY_ISO] = "KEY_ISO",
+ [KEY_CONFIG] = "KEY_CONFIG",
+ [KEY_HOMEPAGE] = "KEY_HOMEPAGE",
+ [KEY_REFRESH] = "KEY_REFRESH",
+ [KEY_EXIT] = "KEY_EXIT",
+ [KEY_MOVE] = "KEY_MOVE",
+ [KEY_EDIT] = "KEY_EDIT",
+ [KEY_SCROLLUP] = "KEY_SCROLLUP",
+ [KEY_SCROLLDOWN] = "KEY_SCROLLDOWN",
+ [KEY_KPLEFTPAREN] = "KEY_KPLEFTPAREN",
+ [KEY_KPRIGHTPAREN] = "KEY_KPRIGHTPAREN",
+ [KEY_NEW] = "KEY_NEW",
+ [KEY_REDO] = "KEY_REDO",
+ [KEY_F13] = "KEY_F13",
+ [KEY_F14] = "KEY_F14",
+ [KEY_F15] = "KEY_F15",
+ [KEY_F16] = "KEY_F16",
+ [KEY_F17] = "KEY_F17",
+ [KEY_F18] = "KEY_F18",
+ [KEY_F19] = "KEY_F19",
+ [KEY_F20] = "KEY_F20",
+ [KEY_F21] = "KEY_F21",
+ [KEY_F22] = "KEY_F22",
+ [KEY_F23] = "KEY_F23",
+ [KEY_F24] = "KEY_F24",
+ [KEY_PLAYCD] = "KEY_PLAYCD",
+ [KEY_PAUSECD] = "KEY_PAUSECD",
+ [KEY_PROG3] = "KEY_PROG3",
+ [KEY_PROG4] = "KEY_PROG4",
+ // [KEY_ALL_APPLICATIONS] = "KEY_ALL_APPLICATIONS",
+ [KEY_SUSPEND] = "KEY_SUSPEND",
+ [KEY_CLOSE] = "KEY_CLOSE",
+ [KEY_PLAY] = "KEY_PLAY",
+ [KEY_FASTFORWARD] = "KEY_FASTFORWARD",
+ [KEY_BASSBOOST] = "KEY_BASSBOOST",
+ [KEY_PRINT] = "KEY_PRINT",
+ [KEY_HP] = "KEY_HP",
+ [KEY_CAMERA] = "KEY_CAMERA",
+ [KEY_SOUND] = "KEY_SOUND",
+ [KEY_QUESTION] = "KEY_QUESTION",
+ [KEY_EMAIL] = "KEY_EMAIL",
+ [KEY_CHAT] = "KEY_CHAT",
+ [KEY_SEARCH] = "KEY_SEARCH",
+ [KEY_CONNECT] = "KEY_CONNECT",
+ [KEY_FINANCE] = "KEY_FINANCE",
+ [KEY_SPORT] = "KEY_SPORT",
+ [KEY_SHOP] = "KEY_SHOP",
+ [KEY_ALTERASE] = "KEY_ALTERASE",
+ [KEY_CANCEL] = "KEY_CANCEL",
+ [KEY_BRIGHTNESSDOWN] = "KEY_BRIGHTNESSDOWN",
+ [KEY_BRIGHTNESSUP] = "KEY_BRIGHTNESSUP",
+ [KEY_MEDIA] = "KEY_MEDIA",
+ [KEY_SWITCHVIDEOMODE] = "KEY_SWITCHVIDEOMODE",
+ [KEY_KBDILLUMTOGGLE] = "KEY_KBDILLUMTOGGLE",
+ [KEY_KBDILLUMDOWN] = "KEY_KBDILLUMDOWN",
+ [KEY_KBDILLUMUP] = "KEY_KBDILLUMUP",
+ [KEY_SEND] = "KEY_SEND",
+ [KEY_REPLY] = "KEY_REPLY",
+ [KEY_FORWARDMAIL] = "KEY_FORWARDMAIL",
+ [KEY_SAVE] = "KEY_SAVE",
+ [KEY_DOCUMENTS] = "KEY_DOCUMENTS",
+ [KEY_BATTERY] = "KEY_BATTERY",
+ [KEY_BLUETOOTH] = "KEY_BLUETOOTH",
+ [KEY_WLAN] = "KEY_WLAN",
+ [KEY_UWB] = "KEY_UWB",
+ [KEY_UNKNOWN] = "KEY_UNKNOWN",
+ [KEY_VIDEO_NEXT] = "KEY_VIDEO_NEXT",
+ [KEY_VIDEO_PREV] = "KEY_VIDEO_PREV",
+ [KEY_BRIGHTNESS_CYCLE] = "KEY_BRIGHTNESS_CYCLE",
+ [KEY_BRIGHTNESS_AUTO] = "KEY_BRIGHTNESS_AUTO",
+ [KEY_DISPLAY_OFF] = "KEY_DISPLAY_OFF",
+ [KEY_WWAN] = "KEY_WWAN",
+ [KEY_RFKILL] = "KEY_RFKILL",
+ [KEY_MICMUTE] = "KEY_MICMUTE",
+ [KEY_OK] = "KEY_OK",
+ [KEY_SELECT] = "KEY_SELECT",
+ [KEY_GOTO] = "KEY_GOTO",
+ [KEY_CLEAR] = "KEY_CLEAR",
+ [KEY_POWER2] = "KEY_POWER2",
+ [KEY_OPTION] = "KEY_OPTION",
+ [KEY_INFO] = "KEY_INFO",
+ [KEY_TIME] = "KEY_TIME",
+ [KEY_VENDOR] = "KEY_VENDOR",
+ [KEY_ARCHIVE] = "KEY_ARCHIVE",
+ [KEY_PROGRAM] = "KEY_PROGRAM",
+ [KEY_CHANNEL] = "KEY_CHANNEL",
+ [KEY_FAVORITES] = "KEY_FAVORITES",
+ [KEY_EPG] = "KEY_EPG",
+ [KEY_PVR] = "KEY_PVR",
+ [KEY_MHP] = "KEY_MHP",
+ [KEY_LANGUAGE] = "KEY_LANGUAGE",
+ [KEY_TITLE] = "KEY_TITLE",
+ [KEY_SUBTITLE] = "KEY_SUBTITLE",
+ [KEY_ANGLE] = "KEY_ANGLE",
+ [KEY_FULL_SCREEN] = "KEY_FULL_SCREEN",
+ [KEY_MODE] = "KEY_MODE",
+ [KEY_KEYBOARD] = "KEY_KEYBOARD",
+ [KEY_ASPECT_RATIO] = "KEY_ASPECT_RATIO",
+ [KEY_PC] = "KEY_PC",
+ [KEY_TV] = "KEY_TV",
+ [KEY_TV2] = "KEY_TV2",
+ [KEY_VCR] = "KEY_VCR",
+ [KEY_VCR2] = "KEY_VCR2",
+ [KEY_SAT] = "KEY_SAT",
+ [KEY_SAT2] = "KEY_SAT2",
+ [KEY_CD] = "KEY_CD",
+ [KEY_TAPE] = "KEY_TAPE",
+ [KEY_RADIO] = "KEY_RADIO",
+ [KEY_TUNER] = "KEY_TUNER",
+ [KEY_PLAYER] = "KEY_PLAYER",
+ [KEY_TEXT] = "KEY_TEXT",
+ [KEY_DVD] = "KEY_DVD",
+ [KEY_AUX] = "KEY_AUX",
+ [KEY_MP3] = "KEY_MP3",
+ [KEY_AUDIO] = "KEY_AUDIO",
+ [KEY_VIDEO] = "KEY_VIDEO",
+ [KEY_DIRECTORY] = "KEY_DIRECTORY",
+ [KEY_LIST] = "KEY_LIST",
+ [KEY_MEMO] = "KEY_MEMO",
+ [KEY_CALENDAR] = "KEY_CALENDAR",
+ [KEY_RED] = "KEY_RED",
+ [KEY_GREEN] = "KEY_GREEN",
+ [KEY_YELLOW] = "KEY_YELLOW",
+ [KEY_BLUE] = "KEY_BLUE",
+ [KEY_CHANNELUP] = "KEY_CHANNELUP",
+ [KEY_CHANNELDOWN] = "KEY_CHANNELDOWN",
+ [KEY_FIRST] = "KEY_FIRST",
+ [KEY_LAST] = "KEY_LAST",
+ [KEY_AB] = "KEY_AB",
+ [KEY_NEXT] = "KEY_NEXT",
+ [KEY_RESTART] = "KEY_RESTART",
+ [KEY_SLOW] = "KEY_SLOW",
+ [KEY_SHUFFLE] = "KEY_SHUFFLE",
+ [KEY_BREAK] = "KEY_BREAK",
+ [KEY_PREVIOUS] = "KEY_PREVIOUS",
+ [KEY_DIGITS] = "KEY_DIGITS",
+ [KEY_TEEN] = "KEY_TEEN",
+ [KEY_TWEN] = "KEY_TWEN",
+ [KEY_VIDEOPHONE] = "KEY_VIDEOPHONE",
+ [KEY_GAMES] = "KEY_GAMES",
+ [KEY_ZOOMIN] = "KEY_ZOOMIN",
+ [KEY_ZOOMOUT] = "KEY_ZOOMOUT",
+ [KEY_ZOOMRESET] = "KEY_ZOOMRESET",
+ [KEY_WORDPROCESSOR] = "KEY_WORDPROCESSOR",
+ [KEY_EDITOR] = "KEY_EDITOR",
+ [KEY_SPREADSHEET] = "KEY_SPREADSHEET",
+ [KEY_GRAPHICSEDITOR] = "KEY_GRAPHICSEDITOR",
+ [KEY_PRESENTATION] = "KEY_PRESENTATION",
+ [KEY_DATABASE] = "KEY_DATABASE",
+ [KEY_NEWS] = "KEY_NEWS",
+ [KEY_VOICEMAIL] = "KEY_VOICEMAIL",
+ [KEY_ADDRESSBOOK] = "KEY_ADDRESSBOOK",
+ [KEY_MESSENGER] = "KEY_MESSENGER",
+ [KEY_DISPLAYTOGGLE] = "KEY_DISPLAYTOGGLE",
+ [KEY_SPELLCHECK] = "KEY_SPELLCHECK",
+ [KEY_LOGOFF] = "KEY_LOGOFF",
+ [KEY_DOLLAR] = "KEY_DOLLAR",
+ [KEY_EURO] = "KEY_EURO",
+ [KEY_FRAMEBACK] = "KEY_FRAMEBACK",
+ [KEY_FRAMEFORWARD] = "KEY_FRAMEFORWARD",
+ [KEY_CONTEXT_MENU] = "KEY_CONTEXT_MENU",
+ [KEY_MEDIA_REPEAT] = "KEY_MEDIA_REPEAT",
+ [KEY_10CHANNELSUP] = "KEY_10CHANNELSUP",
+ [KEY_10CHANNELSDOWN] = "KEY_10CHANNELSDOWN",
+ [KEY_IMAGES] = "KEY_IMAGES",
+ // [KEY_NOTIFICATION_CENTER] = "KEY_NOTIFICATION_CENTER",
+ // [KEY_PICKUP_PHONE] = "KEY_PICKUP_PHONE",
+ // [KEY_HANGUP_PHONE] = "KEY_HANGUP_PHONE",
+ [KEY_DEL_EOL] = "KEY_DEL_EOL",
+ [KEY_DEL_EOS] = "KEY_DEL_EOS",
+ [KEY_INS_LINE] = "KEY_INS_LINE",
+ [KEY_DEL_LINE] = "KEY_DEL_LINE",
+ [KEY_FN] = "KEY_FN",
+ [KEY_FN_ESC] = "KEY_FN_ESC",
+ [KEY_FN_F1] = "KEY_FN_F1",
+ [KEY_FN_F2] = "KEY_FN_F2",
+ [KEY_FN_F3] = "KEY_FN_F3",
+ [KEY_FN_F4] = "KEY_FN_F4",
+ [KEY_FN_F5] = "KEY_FN_F5",
+ [KEY_FN_F6] = "KEY_FN_F6",
+ [KEY_FN_F7] = "KEY_FN_F7",
+ [KEY_FN_F8] = "KEY_FN_F8",
+ [KEY_FN_F9] = "KEY_FN_F9",
+ [KEY_FN_F10] = "KEY_FN_F10",
+ [KEY_FN_F11] = "KEY_FN_F11",
+ [KEY_FN_F12] = "KEY_FN_F12",
+ [KEY_FN_1] = "KEY_FN_1",
+ [KEY_FN_2] = "KEY_FN_2",
+ [KEY_FN_D] = "KEY_FN_D",
+ [KEY_FN_E] = "KEY_FN_E",
+ [KEY_FN_F] = "KEY_FN_F",
+ [KEY_FN_S] = "KEY_FN_S",
+ [KEY_FN_B] = "KEY_FN_B",
+ // [KEY_FN_RIGHT_SHIFT] = "KEY_FN_RIGHT_SHIFT",
+ [KEY_BRL_DOT1] = "KEY_BRL_DOT1",
+ [KEY_BRL_DOT2] = "KEY_BRL_DOT2",
+ [KEY_BRL_DOT3] = "KEY_BRL_DOT3",
+ [KEY_BRL_DOT4] = "KEY_BRL_DOT4",
+ [KEY_BRL_DOT5] = "KEY_BRL_DOT5",
+ [KEY_BRL_DOT6] = "KEY_BRL_DOT6",
+ [KEY_BRL_DOT7] = "KEY_BRL_DOT7",
+ [KEY_BRL_DOT8] = "KEY_BRL_DOT8",
+ [KEY_BRL_DOT9] = "KEY_BRL_DOT9",
+ [KEY_BRL_DOT10] = "KEY_BRL_DOT10",
+ [KEY_NUMERIC_0] = "KEY_NUMERIC_0",
+ [KEY_NUMERIC_1] = "KEY_NUMERIC_1",
+ [KEY_NUMERIC_2] = "KEY_NUMERIC_2",
+ [KEY_NUMERIC_3] = "KEY_NUMERIC_3",
+ [KEY_NUMERIC_4] = "KEY_NUMERIC_4",
+ [KEY_NUMERIC_5] = "KEY_NUMERIC_5",
+ [KEY_NUMERIC_6] = "KEY_NUMERIC_6",
+ [KEY_NUMERIC_7] = "KEY_NUMERIC_7",
+ [KEY_NUMERIC_8] = "KEY_NUMERIC_8",
+ [KEY_NUMERIC_9] = "KEY_NUMERIC_9",
+ [KEY_NUMERIC_STAR] = "KEY_NUMERIC_STAR",
+ [KEY_NUMERIC_POUND] = "KEY_NUMERIC_POUND",
+ [KEY_NUMERIC_A] = "KEY_NUMERIC_A",
+ [KEY_NUMERIC_B] = "KEY_NUMERIC_B",
+ [KEY_NUMERIC_C] = "KEY_NUMERIC_C",
+ [KEY_NUMERIC_D] = "KEY_NUMERIC_D",
+ [KEY_CAMERA_FOCUS] = "KEY_CAMERA_FOCUS",
+ [KEY_WPS_BUTTON] = "KEY_WPS_BUTTON",
+ [KEY_TOUCHPAD_TOGGLE] = "KEY_TOUCHPAD_TOGGLE",
+ [KEY_TOUCHPAD_ON] = "KEY_TOUCHPAD_ON",
+ [KEY_TOUCHPAD_OFF] = "KEY_TOUCHPAD_OFF",
+ [KEY_CAMERA_ZOOMIN] = "KEY_CAMERA_ZOOMIN",
+ [KEY_CAMERA_ZOOMOUT] = "KEY_CAMERA_ZOOMOUT",
+ [KEY_CAMERA_UP] = "KEY_CAMERA_UP",
+ [KEY_CAMERA_DOWN] = "KEY_CAMERA_DOWN",
+ [KEY_CAMERA_LEFT] = "KEY_CAMERA_LEFT",
+ [KEY_CAMERA_RIGHT] = "KEY_CAMERA_RIGHT",
+ [KEY_ATTENDANT_ON] = "KEY_ATTENDANT_ON",
+ [KEY_ATTENDANT_OFF] = "KEY_ATTENDANT_OFF",
+ [KEY_ATTENDANT_TOGGLE] = "KEY_ATTENDANT_TOGGLE",
+ [KEY_LIGHTS_TOGGLE] = "KEY_LIGHTS_TOGGLE",
+ [KEY_ALS_TOGGLE] = "KEY_ALS_TOGGLE",
+ [KEY_ROTATE_LOCK_TOGGLE] = "KEY_ROTATE_LOCK_TOGGLE",
+ [KEY_BUTTONCONFIG] = "KEY_BUTTONCONFIG",
+ [KEY_TASKMANAGER] = "KEY_TASKMANAGER",
+ [KEY_JOURNAL] = "KEY_JOURNAL",
+ [KEY_CONTROLPANEL] = "KEY_CONTROLPANEL",
+ [KEY_APPSELECT] = "KEY_APPSELECT",
+ [KEY_SCREENSAVER] = "KEY_SCREENSAVER",
+ [KEY_VOICECOMMAND] = "KEY_VOICECOMMAND",
+ [KEY_ASSISTANT] = "KEY_ASSISTANT",
+ [KEY_KBD_LAYOUT_NEXT] = "KEY_KBD_LAYOUT_NEXT",
+ // [KEY_EMOJI_PICKER] = "KEY_EMOJI_PICKER",
+ //[KEY_DICTATE] = "KEY_DICTATE",
+ //[KEY_CAMERA_ACCESS_ENABLE] = "KEY_CAMERA_ACCESS_ENABLE",
+ //[KEY_CAMERA_ACCESS_DISABLE] = "KEY_CAMERA_ACCESS_DISABLE",
+ //[KEY_CAMERA_ACCESS_TOGGLE] = "KEY_CAMERA_ACCESS_TOGGLE",
+ [KEY_BRIGHTNESS_MIN] = "KEY_BRIGHTNESS_MIN",
+ [KEY_BRIGHTNESS_MAX] = "KEY_BRIGHTNESS_MAX",
+ [KEY_KBDINPUTASSIST_PREV] = "KEY_KBDINPUTASSIST_PREV",
+ [KEY_KBDINPUTASSIST_NEXT] = "KEY_KBDINPUTASSIST_NEXT",
+ [KEY_KBDINPUTASSIST_PREVGROUP] = "KEY_KBDINPUTASSIST_PREVGROUP",
+ [KEY_KBDINPUTASSIST_NEXTGROUP] = "KEY_KBDINPUTASSIST_NEXTGROUP",
+ [KEY_KBDINPUTASSIST_ACCEPT] = "KEY_KBDINPUTASSIST_ACCEPT",
+ [KEY_KBDINPUTASSIST_CANCEL] = "KEY_KBDINPUTASSIST_CANCEL",
+ [KEY_RIGHT_UP] = "KEY_RIGHT_UP",
+ [KEY_RIGHT_DOWN] = "KEY_RIGHT_DOWN",
+ [KEY_LEFT_UP] = "KEY_LEFT_UP",
+ [KEY_LEFT_DOWN] = "KEY_LEFT_DOWN",
+ [KEY_ROOT_MENU] = "KEY_ROOT_MENU",
+ [KEY_MEDIA_TOP_MENU] = "KEY_MEDIA_TOP_MENU",
+ [KEY_NUMERIC_11] = "KEY_NUMERIC_11",
+ [KEY_NUMERIC_12] = "KEY_NUMERIC_12",
+ [KEY_AUDIO_DESC] = "KEY_AUDIO_DESC",
+ [KEY_3D_MODE] = "KEY_3D_MODE",
+ [KEY_NEXT_FAVORITE] = "KEY_NEXT_FAVORITE",
+ [KEY_STOP_RECORD] = "KEY_STOP_RECORD",
+ [KEY_PAUSE_RECORD] = "KEY_PAUSE_RECORD",
+ [KEY_VOD] = "KEY_VOD",
+ [KEY_UNMUTE] = "KEY_UNMUTE",
+ [KEY_FASTREVERSE] = "KEY_FASTREVERSE",
+ [KEY_SLOWREVERSE] = "KEY_SLOWREVERSE",
+ [KEY_DATA] = "KEY_DATA",
+ [KEY_ONSCREEN_KEYBOARD] = "KEY_ONSCREEN_KEYBOARD",
+ [KEY_PRIVACY_SCREEN_TOGGLE] = "KEY_PRIVACY_SCREEN_TOGGLE",
+ [KEY_SELECTIVE_SCREENSHOT] = "KEY_SELECTIVE_SCREENSHOT",
+ // [KEY_NEXT_ELEMENT] = "KEY_NEXT_ELEMENT",
+ // [KEY_PREVIOUS_ELEMENT] = "KEY_PREVIOUS_ELEMENT",
+ // [KEY_AUTOPILOT_ENGAGE_TOGGLE] = "KEY_AUTOPILOT_ENGAGE_TOGGLE",
+ // [KEY_MARK_WAYPOINT] = "KEY_MARK_WAYPOINT",
+ // [KEY_SOS] = "KEY_SOS",
+ // [KEY_NAV_CHART] = "KEY_NAV_CHART",
+ // [KEY_FISHING_CHART] = "KEY_FISHING_CHART",
+ // [KEY_SINGLE_RANGE_RADAR] = "KEY_SINGLE_RANGE_RADAR",
+ // [KEY_DUAL_RANGE_RADAR] = "KEY_DUAL_RANGE_RADAR",
+ // [KEY_RADAR_OVERLAY] = "KEY_RADAR_OVERLAY",
+ // [KEY_TRADITIONAL_SONAR] = "KEY_TRADITIONAL_SONAR",
+ // [KEY_CLEARVU_SONAR] = "KEY_CLEARVU_SONAR",
+ // [KEY_SIDEVU_SONAR] = "KEY_SIDEVU_SONAR",
+ // [KEY_NAV_INFO] = "KEY_NAV_INFO",
+ // [KEY_BRIGHTNESS_MENU] = "KEY_BRIGHTNESS_MENU",
+ [KEY_MACRO1] = "KEY_MACRO1",
+ [KEY_MACRO2] = "KEY_MACRO2",
+ [KEY_MACRO3] = "KEY_MACRO3",
+ [KEY_MACRO4] = "KEY_MACRO4",
+ [KEY_MACRO5] = "KEY_MACRO5",
+ [KEY_MACRO6] = "KEY_MACRO6",
+ [KEY_MACRO7] = "KEY_MACRO7",
+ [KEY_MACRO8] = "KEY_MACRO8",
+ [KEY_MACRO9] = "KEY_MACRO9",
+ [KEY_MACRO10] = "KEY_MACRO10",
+ [KEY_MACRO11] = "KEY_MACRO11",
+ [KEY_MACRO12] = "KEY_MACRO12",
+ [KEY_MACRO13] = "KEY_MACRO13",
+ [KEY_MACRO14] = "KEY_MACRO14",
+ [KEY_MACRO15] = "KEY_MACRO15",
+ [KEY_MACRO16] = "KEY_MACRO16",
+ [KEY_MACRO17] = "KEY_MACRO17",
+ [KEY_MACRO18] = "KEY_MACRO18",
+ [KEY_MACRO19] = "KEY_MACRO19",
+ [KEY_MACRO20] = "KEY_MACRO20",
+ [KEY_MACRO21] = "KEY_MACRO21",
+ [KEY_MACRO22] = "KEY_MACRO22",
+ [KEY_MACRO23] = "KEY_MACRO23",
+ [KEY_MACRO24] = "KEY_MACRO24",
+ [KEY_MACRO25] = "KEY_MACRO25",
+ [KEY_MACRO26] = "KEY_MACRO26",
+ [KEY_MACRO27] = "KEY_MACRO27",
+ [KEY_MACRO28] = "KEY_MACRO28",
+ [KEY_MACRO29] = "KEY_MACRO29",
+ [KEY_MACRO30] = "KEY_MACRO30",
+ [KEY_MACRO_RECORD_START] = "KEY_MACRO_RECORD_START",
+ [KEY_MACRO_RECORD_STOP] = "KEY_MACRO_RECORD_STOP",
+ [KEY_MACRO_PRESET_CYCLE] = "KEY_MACRO_PRESET_CYCLE",
+ [KEY_MACRO_PRESET1] = "KEY_MACRO_PRESET1",
+ [KEY_MACRO_PRESET2] = "KEY_MACRO_PRESET2",
+ [KEY_MACRO_PRESET3] = "KEY_MACRO_PRESET3",
+ [KEY_KBD_LCD_MENU1] = "KEY_KBD_LCD_MENU1",
+ [KEY_KBD_LCD_MENU2] = "KEY_KBD_LCD_MENU2",
+ [KEY_KBD_LCD_MENU3] = "KEY_KBD_LCD_MENU3",
+ [KEY_KBD_LCD_MENU4] = "KEY_KBD_LCD_MENU4",
+ [KEY_KBD_LCD_MENU5] = "KEY_KBD_LCD_MENU5",
+ [KEY_MAX] = "KEY_MAX",
+ [BTN_0] = "BTN_0",
+ [BTN_1] = "BTN_1",
+ [BTN_2] = "BTN_2",
+ [BTN_3] = "BTN_3",
+ [BTN_4] = "BTN_4",
+ [BTN_5] = "BTN_5",
+ [BTN_6] = "BTN_6",
+ [BTN_7] = "BTN_7",
+ [BTN_8] = "BTN_8",
+ [BTN_9] = "BTN_9",
+ [BTN_LEFT] = "BTN_LEFT",
+ [BTN_RIGHT] = "BTN_RIGHT",
+ [BTN_MIDDLE] = "BTN_MIDDLE",
+ [BTN_SIDE] = "BTN_SIDE",
+ [BTN_EXTRA] = "BTN_EXTRA",
+ [BTN_FORWARD] = "BTN_FORWARD",
+ [BTN_BACK] = "BTN_BACK",
+ [BTN_TASK] = "BTN_TASK",
+ [BTN_TRIGGER] = "BTN_TRIGGER",
+ [BTN_THUMB] = "BTN_THUMB",
+ [BTN_THUMB2] = "BTN_THUMB2",
+ [BTN_TOP] = "BTN_TOP",
+ [BTN_TOP2] = "BTN_TOP2",
+ [BTN_PINKIE] = "BTN_PINKIE",
+ [BTN_BASE] = "BTN_BASE",
+ [BTN_BASE2] = "BTN_BASE2",
+ [BTN_BASE3] = "BTN_BASE3",
+ [BTN_BASE4] = "BTN_BASE4",
+ [BTN_BASE5] = "BTN_BASE5",
+ [BTN_BASE6] = "BTN_BASE6",
+ [BTN_DEAD] = "BTN_DEAD",
+ [BTN_SOUTH] = "BTN_SOUTH",
+ [BTN_EAST] = "BTN_EAST",
+ [BTN_C] = "BTN_C",
+ [BTN_NORTH] = "BTN_NORTH",
+ [BTN_WEST] = "BTN_WEST",
+ [BTN_Z] = "BTN_Z",
+ [BTN_TL] = "BTN_TL",
+ [BTN_TR] = "BTN_TR",
+ [BTN_TL2] = "BTN_TL2",
+ [BTN_TR2] = "BTN_TR2",
+ [BTN_SELECT] = "BTN_SELECT",
+ [BTN_START] = "BTN_START",
+ [BTN_MODE] = "BTN_MODE",
+ [BTN_THUMBL] = "BTN_THUMBL",
+ [BTN_THUMBR] = "BTN_THUMBR",
+ [BTN_TOOL_PEN] = "BTN_TOOL_PEN",
+ [BTN_TOOL_RUBBER] = "BTN_TOOL_RUBBER",
+ [BTN_TOOL_BRUSH] = "BTN_TOOL_BRUSH",
+ [BTN_TOOL_PENCIL] = "BTN_TOOL_PENCIL",
+ [BTN_TOOL_AIRBRUSH] = "BTN_TOOL_AIRBRUSH",
+ [BTN_TOOL_FINGER] = "BTN_TOOL_FINGER",
+ [BTN_TOOL_MOUSE] = "BTN_TOOL_MOUSE",
+ [BTN_TOOL_LENS] = "BTN_TOOL_LENS",
+ [BTN_TOOL_QUINTTAP] = "BTN_TOOL_QUINTTAP",
+ [BTN_STYLUS3] = "BTN_STYLUS3",
+ [BTN_TOUCH] = "BTN_TOUCH",
+ [BTN_STYLUS] = "BTN_STYLUS",
+ [BTN_STYLUS2] = "BTN_STYLUS2",
+ [BTN_TOOL_DOUBLETAP] = "BTN_TOOL_DOUBLETAP",
+ [BTN_TOOL_TRIPLETAP] = "BTN_TOOL_TRIPLETAP",
+ [BTN_TOOL_QUADTAP] = "BTN_TOOL_QUADTAP",
+ [BTN_GEAR_DOWN] = "BTN_GEAR_DOWN",
+ [BTN_GEAR_UP] = "BTN_GEAR_UP",
+ [BTN_DPAD_UP] = "BTN_DPAD_UP",
+ [BTN_DPAD_DOWN] = "BTN_DPAD_DOWN",
+ [BTN_DPAD_LEFT] = "BTN_DPAD_LEFT",
+ [BTN_DPAD_RIGHT] = "BTN_DPAD_RIGHT",
+ [BTN_TRIGGER_HAPPY1] = "BTN_TRIGGER_HAPPY1",
+ [BTN_TRIGGER_HAPPY2] = "BTN_TRIGGER_HAPPY2",
+ [BTN_TRIGGER_HAPPY3] = "BTN_TRIGGER_HAPPY3",
+ [BTN_TRIGGER_HAPPY4] = "BTN_TRIGGER_HAPPY4",
+ [BTN_TRIGGER_HAPPY5] = "BTN_TRIGGER_HAPPY5",
+ [BTN_TRIGGER_HAPPY6] = "BTN_TRIGGER_HAPPY6",
+ [BTN_TRIGGER_HAPPY7] = "BTN_TRIGGER_HAPPY7",
+ [BTN_TRIGGER_HAPPY8] = "BTN_TRIGGER_HAPPY8",
+ [BTN_TRIGGER_HAPPY9] = "BTN_TRIGGER_HAPPY9",
+ [BTN_TRIGGER_HAPPY10] = "BTN_TRIGGER_HAPPY10",
+ [BTN_TRIGGER_HAPPY11] = "BTN_TRIGGER_HAPPY11",
+ [BTN_TRIGGER_HAPPY12] = "BTN_TRIGGER_HAPPY12",
+ [BTN_TRIGGER_HAPPY13] = "BTN_TRIGGER_HAPPY13",
+ [BTN_TRIGGER_HAPPY14] = "BTN_TRIGGER_HAPPY14",
+ [BTN_TRIGGER_HAPPY15] = "BTN_TRIGGER_HAPPY15",
+ [BTN_TRIGGER_HAPPY16] = "BTN_TRIGGER_HAPPY16",
+ [BTN_TRIGGER_HAPPY17] = "BTN_TRIGGER_HAPPY17",
+ [BTN_TRIGGER_HAPPY18] = "BTN_TRIGGER_HAPPY18",
+ [BTN_TRIGGER_HAPPY19] = "BTN_TRIGGER_HAPPY19",
+ [BTN_TRIGGER_HAPPY20] = "BTN_TRIGGER_HAPPY20",
+ [BTN_TRIGGER_HAPPY21] = "BTN_TRIGGER_HAPPY21",
+ [BTN_TRIGGER_HAPPY22] = "BTN_TRIGGER_HAPPY22",
+ [BTN_TRIGGER_HAPPY23] = "BTN_TRIGGER_HAPPY23",
+ [BTN_TRIGGER_HAPPY24] = "BTN_TRIGGER_HAPPY24",
+ [BTN_TRIGGER_HAPPY25] = "BTN_TRIGGER_HAPPY25",
+ [BTN_TRIGGER_HAPPY26] = "BTN_TRIGGER_HAPPY26",
+ [BTN_TRIGGER_HAPPY27] = "BTN_TRIGGER_HAPPY27",
+ [BTN_TRIGGER_HAPPY28] = "BTN_TRIGGER_HAPPY28",
+ [BTN_TRIGGER_HAPPY29] = "BTN_TRIGGER_HAPPY29",
+ [BTN_TRIGGER_HAPPY30] = "BTN_TRIGGER_HAPPY30",
+ [BTN_TRIGGER_HAPPY31] = "BTN_TRIGGER_HAPPY31",
+ [BTN_TRIGGER_HAPPY32] = "BTN_TRIGGER_HAPPY32",
+ [BTN_TRIGGER_HAPPY33] = "BTN_TRIGGER_HAPPY33",
+ [BTN_TRIGGER_HAPPY34] = "BTN_TRIGGER_HAPPY34",
+ [BTN_TRIGGER_HAPPY35] = "BTN_TRIGGER_HAPPY35",
+ [BTN_TRIGGER_HAPPY36] = "BTN_TRIGGER_HAPPY36",
+ [BTN_TRIGGER_HAPPY37] = "BTN_TRIGGER_HAPPY37",
+ [BTN_TRIGGER_HAPPY38] = "BTN_TRIGGER_HAPPY38",
+ [BTN_TRIGGER_HAPPY39] = "BTN_TRIGGER_HAPPY39",
+ [BTN_TRIGGER_HAPPY40] = "BTN_TRIGGER_HAPPY40",
+};
+
+static const char * const led_map[LED_MAX + 1] = {
+ [LED_NUML] = "LED_NUML",
+ [LED_CAPSL] = "LED_CAPSL",
+ [LED_SCROLLL] = "LED_SCROLLL",
+ [LED_COMPOSE] = "LED_COMPOSE",
+ [LED_KANA] = "LED_KANA",
+ [LED_SLEEP] = "LED_SLEEP",
+ [LED_SUSPEND] = "LED_SUSPEND",
+ [LED_MUTE] = "LED_MUTE",
+ [LED_MISC] = "LED_MISC",
+ [LED_MAIL] = "LED_MAIL",
+ [LED_CHARGING] = "LED_CHARGING",
+ [LED_MAX] = "LED_MAX",
+};
+
+static const char * const snd_map[SND_MAX + 1] = {
+ [SND_CLICK] = "SND_CLICK",
+ [SND_BELL] = "SND_BELL",
+ [SND_TONE] = "SND_TONE",
+ [SND_MAX] = "SND_MAX",
+};
+
+static const char * const msc_map[MSC_MAX + 1] = {
+ [MSC_SERIAL] = "MSC_SERIAL",
+ [MSC_PULSELED] = "MSC_PULSELED",
+ [MSC_GESTURE] = "MSC_GESTURE",
+ [MSC_RAW] = "MSC_RAW",
+ [MSC_SCAN] = "MSC_SCAN",
+ [MSC_TIMESTAMP] = "MSC_TIMESTAMP",
+ [MSC_MAX] = "MSC_MAX",
+};
+
+static const char * const sw_map[SW_MAX + 1] = {
+ [SW_LID] = "SW_LID",
+ [SW_TABLET_MODE] = "SW_TABLET_MODE",
+ [SW_HEADPHONE_INSERT] = "SW_HEADPHONE_INSERT",
+ [SW_RFKILL_ALL] = "SW_RFKILL_ALL",
+ [SW_MICROPHONE_INSERT] = "SW_MICROPHONE_INSERT",
+ [SW_DOCK] = "SW_DOCK",
+ [SW_LINEOUT_INSERT] = "SW_LINEOUT_INSERT",
+ [SW_JACK_PHYSICAL_INSERT] = "SW_JACK_PHYSICAL_INSERT",
+ [SW_VIDEOOUT_INSERT] = "SW_VIDEOOUT_INSERT",
+ [SW_CAMERA_LENS_COVER] = "SW_CAMERA_LENS_COVER",
+ [SW_KEYPAD_SLIDE] = "SW_KEYPAD_SLIDE",
+ [SW_FRONT_PROXIMITY] = "SW_FRONT_PROXIMITY",
+ [SW_ROTATE_LOCK] = "SW_ROTATE_LOCK",
+ [SW_LINEIN_INSERT] = "SW_LINEIN_INSERT",
+ [SW_MUTE_DEVICE] = "SW_MUTE_DEVICE",
+ [SW_PEN_INSERTED] = "SW_PEN_INSERTED",
+ [SW_MACHINE_COVER] = "SW_MACHINE_COVER",
+};
+
+static const char * const ff_map[FF_MAX + 1] = {
+ [FF_STATUS_STOPPED] = "FF_STATUS_STOPPED",
+ [FF_STATUS_MAX] = "FF_STATUS_MAX",
+ [FF_RUMBLE] = "FF_RUMBLE",
+ [FF_PERIODIC] = "FF_PERIODIC",
+ [FF_CONSTANT] = "FF_CONSTANT",
+ [FF_SPRING] = "FF_SPRING",
+ [FF_FRICTION] = "FF_FRICTION",
+ [FF_DAMPER] = "FF_DAMPER",
+ [FF_INERTIA] = "FF_INERTIA",
+ [FF_RAMP] = "FF_RAMP",
+ [FF_SQUARE] = "FF_SQUARE",
+ [FF_TRIANGLE] = "FF_TRIANGLE",
+ [FF_SINE] = "FF_SINE",
+ [FF_SAW_UP] = "FF_SAW_UP",
+ [FF_SAW_DOWN] = "FF_SAW_DOWN",
+ [FF_CUSTOM] = "FF_CUSTOM",
+ [FF_GAIN] = "FF_GAIN",
+ [FF_AUTOCENTER] = "FF_AUTOCENTER",
+ [FF_MAX] = "FF_MAX",
+};
+
+static const char * const syn_map[SYN_MAX + 1] = {
+ [SYN_REPORT] = "SYN_REPORT",
+ [SYN_CONFIG] = "SYN_CONFIG",
+ [SYN_MT_REPORT] = "SYN_MT_REPORT",
+ [SYN_DROPPED] = "SYN_DROPPED",
+ [SYN_MAX] = "SYN_MAX",
+};
+
+static const char * const rep_map[REP_MAX + 1] = {
+ [REP_DELAY] = "REP_DELAY",
+ [REP_PERIOD] = "REP_PERIOD",
+};
+
+static const char * const input_prop_map[INPUT_PROP_MAX + 1] = {
+ [INPUT_PROP_POINTER] = "INPUT_PROP_POINTER",
+ [INPUT_PROP_DIRECT] = "INPUT_PROP_DIRECT",
+ [INPUT_PROP_BUTTONPAD] = "INPUT_PROP_BUTTONPAD",
+ [INPUT_PROP_SEMI_MT] = "INPUT_PROP_SEMI_MT",
+ [INPUT_PROP_TOPBUTTONPAD] = "INPUT_PROP_TOPBUTTONPAD",
+ [INPUT_PROP_POINTING_STICK] = "INPUT_PROP_POINTING_STICK",
+ [INPUT_PROP_ACCELEROMETER] = "INPUT_PROP_ACCELEROMETER",
+ [INPUT_PROP_MAX] = "INPUT_PROP_MAX",
+};
+
+static const char * const mt_tool_map[MT_TOOL_MAX + 1] = {
+ [MT_TOOL_FINGER] = "MT_TOOL_FINGER",
+ [MT_TOOL_PEN] = "MT_TOOL_PEN",
+ [MT_TOOL_PALM] = "MT_TOOL_PALM",
+ [MT_TOOL_DIAL] = "MT_TOOL_DIAL",
+ [MT_TOOL_MAX] = "MT_TOOL_MAX",
+};
+
+static const char * const * const event_type_map[EV_MAX + 1] = {
+ [EV_REL] = rel_map,
+ [EV_ABS] = abs_map,
+ [EV_KEY] = key_map,
+ [EV_LED] = led_map,
+ [EV_SND] = snd_map,
+ [EV_MSC] = msc_map,
+ [EV_SW] = sw_map,
+ [EV_FF] = ff_map,
+ [EV_SYN] = syn_map,
+ [EV_REP] = rep_map,
+};
+
+#if __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Winitializer-overrides"
+#elif __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Woverride-init"
+#endif
+static const int ev_max[EV_MAX + 1] = {
+ SYN_MAX,
+ KEY_MAX,
+ REL_MAX,
+ ABS_MAX,
+ MSC_MAX,
+ SW_MAX,
+ -1,
+ -1,
+ -1,
+ -1,
+ -1,
+ -1,
+ -1,
+ -1,
+ -1,
+ -1,
+ -1,
+ LED_MAX,
+ SND_MAX,
+ -1,
+ REP_MAX,
+ FF_MAX,
+ -1,
+ -1,
+ -1,
+ -1,
+ -1,
+ -1,
+ -1,
+ -1,
+ -1,
+ -1,
+};
+#if __clang__
+#pragma clang diagnostic pop /* "-Winitializer-overrides" */
+#elif __GNUC__
+#pragma GCC diagnostic pop /* "-Woverride-init" */
+#endif
+
+struct name_entry {
+ const char *name;
+ unsigned int value;
+};
+
+static const struct name_entry tool_type_names[] = {
+ { .name = "MT_TOOL_DIAL", .value = MT_TOOL_DIAL },
+ { .name = "MT_TOOL_FINGER", .value = MT_TOOL_FINGER },
+ { .name = "MT_TOOL_MAX", .value = MT_TOOL_MAX },
+ { .name = "MT_TOOL_PALM", .value = MT_TOOL_PALM },
+ { .name = "MT_TOOL_PEN", .value = MT_TOOL_PEN },
+};
+
+static const struct name_entry ev_names[] = {
+ { .name = "EV_ABS", .value = EV_ABS },
+ { .name = "EV_FF", .value = EV_FF },
+ { .name = "EV_FF_STATUS", .value = EV_FF_STATUS },
+ { .name = "EV_KEY", .value = EV_KEY },
+ { .name = "EV_LED", .value = EV_LED },
+ { .name = "EV_MAX", .value = EV_MAX },
+ { .name = "EV_MSC", .value = EV_MSC },
+ { .name = "EV_PWR", .value = EV_PWR },
+ { .name = "EV_REL", .value = EV_REL },
+ { .name = "EV_REP", .value = EV_REP },
+ { .name = "EV_SND", .value = EV_SND },
+ { .name = "EV_SW", .value = EV_SW },
+ { .name = "EV_SYN", .value = EV_SYN },
+};
+
+static const struct name_entry code_names[] = {
+ { .name = "ABS_BRAKE", .value = ABS_BRAKE },
+ { .name = "ABS_DISTANCE", .value = ABS_DISTANCE },
+ { .name = "ABS_GAS", .value = ABS_GAS },
+ { .name = "ABS_HAT0X", .value = ABS_HAT0X },
+ { .name = "ABS_HAT0Y", .value = ABS_HAT0Y },
+ { .name = "ABS_HAT1X", .value = ABS_HAT1X },
+ { .name = "ABS_HAT1Y", .value = ABS_HAT1Y },
+ { .name = "ABS_HAT2X", .value = ABS_HAT2X },
+ { .name = "ABS_HAT2Y", .value = ABS_HAT2Y },
+ { .name = "ABS_HAT3X", .value = ABS_HAT3X },
+ { .name = "ABS_HAT3Y", .value = ABS_HAT3Y },
+ { .name = "ABS_MAX", .value = ABS_MAX },
+ { .name = "ABS_MISC", .value = ABS_MISC },
+ { .name = "ABS_MT_BLOB_ID", .value = ABS_MT_BLOB_ID },
+ { .name = "ABS_MT_DISTANCE", .value = ABS_MT_DISTANCE },
+ { .name = "ABS_MT_ORIENTATION", .value = ABS_MT_ORIENTATION },
+ { .name = "ABS_MT_POSITION_X", .value = ABS_MT_POSITION_X },
+ { .name = "ABS_MT_POSITION_Y", .value = ABS_MT_POSITION_Y },
+ { .name = "ABS_MT_PRESSURE", .value = ABS_MT_PRESSURE },
+ { .name = "ABS_MT_SLOT", .value = ABS_MT_SLOT },
+ { .name = "ABS_MT_TOOL_TYPE", .value = ABS_MT_TOOL_TYPE },
+ { .name = "ABS_MT_TOOL_X", .value = ABS_MT_TOOL_X },
+ { .name = "ABS_MT_TOOL_Y", .value = ABS_MT_TOOL_Y },
+ { .name = "ABS_MT_TOUCH_MAJOR", .value = ABS_MT_TOUCH_MAJOR },
+ { .name = "ABS_MT_TOUCH_MINOR", .value = ABS_MT_TOUCH_MINOR },
+ { .name = "ABS_MT_TRACKING_ID", .value = ABS_MT_TRACKING_ID },
+ { .name = "ABS_MT_WIDTH_MAJOR", .value = ABS_MT_WIDTH_MAJOR },
+ { .name = "ABS_MT_WIDTH_MINOR", .value = ABS_MT_WIDTH_MINOR },
+ { .name = "ABS_PRESSURE", .value = ABS_PRESSURE },
+ // { .name = "ABS_PROFILE", .value = ABS_PROFILE },
+ { .name = "ABS_RESERVED", .value = ABS_RESERVED },
+ { .name = "ABS_RUDDER", .value = ABS_RUDDER },
+ { .name = "ABS_RX", .value = ABS_RX },
+ { .name = "ABS_RY", .value = ABS_RY },
+ { .name = "ABS_RZ", .value = ABS_RZ },
+ { .name = "ABS_THROTTLE", .value = ABS_THROTTLE },
+ { .name = "ABS_TILT_X", .value = ABS_TILT_X },
+ { .name = "ABS_TILT_Y", .value = ABS_TILT_Y },
+ { .name = "ABS_TOOL_WIDTH", .value = ABS_TOOL_WIDTH },
+ { .name = "ABS_VOLUME", .value = ABS_VOLUME },
+ { .name = "ABS_WHEEL", .value = ABS_WHEEL },
+ { .name = "ABS_X", .value = ABS_X },
+ { .name = "ABS_Y", .value = ABS_Y },
+ { .name = "ABS_Z", .value = ABS_Z },
+ { .name = "BTN_0", .value = BTN_0 },
+ { .name = "BTN_1", .value = BTN_1 },
+ { .name = "BTN_2", .value = BTN_2 },
+ { .name = "BTN_3", .value = BTN_3 },
+ { .name = "BTN_4", .value = BTN_4 },
+ { .name = "BTN_5", .value = BTN_5 },
+ { .name = "BTN_6", .value = BTN_6 },
+ { .name = "BTN_7", .value = BTN_7 },
+ { .name = "BTN_8", .value = BTN_8 },
+ { .name = "BTN_9", .value = BTN_9 },
+ { .name = "BTN_A", .value = BTN_A },
+ { .name = "BTN_B", .value = BTN_B },
+ { .name = "BTN_BACK", .value = BTN_BACK },
+ { .name = "BTN_BASE", .value = BTN_BASE },
+ { .name = "BTN_BASE2", .value = BTN_BASE2 },
+ { .name = "BTN_BASE3", .value = BTN_BASE3 },
+ { .name = "BTN_BASE4", .value = BTN_BASE4 },
+ { .name = "BTN_BASE5", .value = BTN_BASE5 },
+ { .name = "BTN_BASE6", .value = BTN_BASE6 },
+ { .name = "BTN_C", .value = BTN_C },
+ { .name = "BTN_DEAD", .value = BTN_DEAD },
+ { .name = "BTN_DPAD_DOWN", .value = BTN_DPAD_DOWN },
+ { .name = "BTN_DPAD_LEFT", .value = BTN_DPAD_LEFT },
+ { .name = "BTN_DPAD_RIGHT", .value = BTN_DPAD_RIGHT },
+ { .name = "BTN_DPAD_UP", .value = BTN_DPAD_UP },
+ { .name = "BTN_EAST", .value = BTN_EAST },
+ { .name = "BTN_EXTRA", .value = BTN_EXTRA },
+ { .name = "BTN_FORWARD", .value = BTN_FORWARD },
+ { .name = "BTN_GEAR_DOWN", .value = BTN_GEAR_DOWN },
+ { .name = "BTN_GEAR_UP", .value = BTN_GEAR_UP },
+ { .name = "BTN_LEFT", .value = BTN_LEFT },
+ { .name = "BTN_MIDDLE", .value = BTN_MIDDLE },
+ { .name = "BTN_MODE", .value = BTN_MODE },
+ { .name = "BTN_NORTH", .value = BTN_NORTH },
+ { .name = "BTN_PINKIE", .value = BTN_PINKIE },
+ { .name = "BTN_RIGHT", .value = BTN_RIGHT },
+ { .name = "BTN_SELECT", .value = BTN_SELECT },
+ { .name = "BTN_SIDE", .value = BTN_SIDE },
+ { .name = "BTN_SOUTH", .value = BTN_SOUTH },
+ { .name = "BTN_START", .value = BTN_START },
+ { .name = "BTN_STYLUS", .value = BTN_STYLUS },
+ { .name = "BTN_STYLUS2", .value = BTN_STYLUS2 },
+ { .name = "BTN_STYLUS3", .value = BTN_STYLUS3 },
+ { .name = "BTN_TASK", .value = BTN_TASK },
+ { .name = "BTN_THUMB", .value = BTN_THUMB },
+ { .name = "BTN_THUMB2", .value = BTN_THUMB2 },
+ { .name = "BTN_THUMBL", .value = BTN_THUMBL },
+ { .name = "BTN_THUMBR", .value = BTN_THUMBR },
+ { .name = "BTN_TL", .value = BTN_TL },
+ { .name = "BTN_TL2", .value = BTN_TL2 },
+ { .name = "BTN_TOOL_AIRBRUSH", .value = BTN_TOOL_AIRBRUSH },
+ { .name = "BTN_TOOL_BRUSH", .value = BTN_TOOL_BRUSH },
+ { .name = "BTN_TOOL_DOUBLETAP", .value = BTN_TOOL_DOUBLETAP },
+ { .name = "BTN_TOOL_FINGER", .value = BTN_TOOL_FINGER },
+ { .name = "BTN_TOOL_LENS", .value = BTN_TOOL_LENS },
+ { .name = "BTN_TOOL_MOUSE", .value = BTN_TOOL_MOUSE },
+ { .name = "BTN_TOOL_PEN", .value = BTN_TOOL_PEN },
+ { .name = "BTN_TOOL_PENCIL", .value = BTN_TOOL_PENCIL },
+ { .name = "BTN_TOOL_QUADTAP", .value = BTN_TOOL_QUADTAP },
+ { .name = "BTN_TOOL_QUINTTAP", .value = BTN_TOOL_QUINTTAP },
+ { .name = "BTN_TOOL_RUBBER", .value = BTN_TOOL_RUBBER },
+ { .name = "BTN_TOOL_TRIPLETAP", .value = BTN_TOOL_TRIPLETAP },
+ { .name = "BTN_TOP", .value = BTN_TOP },
+ { .name = "BTN_TOP2", .value = BTN_TOP2 },
+ { .name = "BTN_TOUCH", .value = BTN_TOUCH },
+ { .name = "BTN_TR", .value = BTN_TR },
+ { .name = "BTN_TR2", .value = BTN_TR2 },
+ { .name = "BTN_TRIGGER", .value = BTN_TRIGGER },
+ { .name = "BTN_TRIGGER_HAPPY1", .value = BTN_TRIGGER_HAPPY1 },
+ { .name = "BTN_TRIGGER_HAPPY10", .value = BTN_TRIGGER_HAPPY10 },
+ { .name = "BTN_TRIGGER_HAPPY11", .value = BTN_TRIGGER_HAPPY11 },
+ { .name = "BTN_TRIGGER_HAPPY12", .value = BTN_TRIGGER_HAPPY12 },
+ { .name = "BTN_TRIGGER_HAPPY13", .value = BTN_TRIGGER_HAPPY13 },
+ { .name = "BTN_TRIGGER_HAPPY14", .value = BTN_TRIGGER_HAPPY14 },
+ { .name = "BTN_TRIGGER_HAPPY15", .value = BTN_TRIGGER_HAPPY15 },
+ { .name = "BTN_TRIGGER_HAPPY16", .value = BTN_TRIGGER_HAPPY16 },
+ { .name = "BTN_TRIGGER_HAPPY17", .value = BTN_TRIGGER_HAPPY17 },
+ { .name = "BTN_TRIGGER_HAPPY18", .value = BTN_TRIGGER_HAPPY18 },
+ { .name = "BTN_TRIGGER_HAPPY19", .value = BTN_TRIGGER_HAPPY19 },
+ { .name = "BTN_TRIGGER_HAPPY2", .value = BTN_TRIGGER_HAPPY2 },
+ { .name = "BTN_TRIGGER_HAPPY20", .value = BTN_TRIGGER_HAPPY20 },
+ { .name = "BTN_TRIGGER_HAPPY21", .value = BTN_TRIGGER_HAPPY21 },
+ { .name = "BTN_TRIGGER_HAPPY22", .value = BTN_TRIGGER_HAPPY22 },
+ { .name = "BTN_TRIGGER_HAPPY23", .value = BTN_TRIGGER_HAPPY23 },
+ { .name = "BTN_TRIGGER_HAPPY24", .value = BTN_TRIGGER_HAPPY24 },
+ { .name = "BTN_TRIGGER_HAPPY25", .value = BTN_TRIGGER_HAPPY25 },
+ { .name = "BTN_TRIGGER_HAPPY26", .value = BTN_TRIGGER_HAPPY26 },
+ { .name = "BTN_TRIGGER_HAPPY27", .value = BTN_TRIGGER_HAPPY27 },
+ { .name = "BTN_TRIGGER_HAPPY28", .value = BTN_TRIGGER_HAPPY28 },
+ { .name = "BTN_TRIGGER_HAPPY29", .value = BTN_TRIGGER_HAPPY29 },
+ { .name = "BTN_TRIGGER_HAPPY3", .value = BTN_TRIGGER_HAPPY3 },
+ { .name = "BTN_TRIGGER_HAPPY30", .value = BTN_TRIGGER_HAPPY30 },
+ { .name = "BTN_TRIGGER_HAPPY31", .value = BTN_TRIGGER_HAPPY31 },
+ { .name = "BTN_TRIGGER_HAPPY32", .value = BTN_TRIGGER_HAPPY32 },
+ { .name = "BTN_TRIGGER_HAPPY33", .value = BTN_TRIGGER_HAPPY33 },
+ { .name = "BTN_TRIGGER_HAPPY34", .value = BTN_TRIGGER_HAPPY34 },
+ { .name = "BTN_TRIGGER_HAPPY35", .value = BTN_TRIGGER_HAPPY35 },
+ { .name = "BTN_TRIGGER_HAPPY36", .value = BTN_TRIGGER_HAPPY36 },
+ { .name = "BTN_TRIGGER_HAPPY37", .value = BTN_TRIGGER_HAPPY37 },
+ { .name = "BTN_TRIGGER_HAPPY38", .value = BTN_TRIGGER_HAPPY38 },
+ { .name = "BTN_TRIGGER_HAPPY39", .value = BTN_TRIGGER_HAPPY39 },
+ { .name = "BTN_TRIGGER_HAPPY4", .value = BTN_TRIGGER_HAPPY4 },
+ { .name = "BTN_TRIGGER_HAPPY40", .value = BTN_TRIGGER_HAPPY40 },
+ { .name = "BTN_TRIGGER_HAPPY5", .value = BTN_TRIGGER_HAPPY5 },
+ { .name = "BTN_TRIGGER_HAPPY6", .value = BTN_TRIGGER_HAPPY6 },
+ { .name = "BTN_TRIGGER_HAPPY7", .value = BTN_TRIGGER_HAPPY7 },
+ { .name = "BTN_TRIGGER_HAPPY8", .value = BTN_TRIGGER_HAPPY8 },
+ { .name = "BTN_TRIGGER_HAPPY9", .value = BTN_TRIGGER_HAPPY9 },
+ { .name = "BTN_WEST", .value = BTN_WEST },
+ { .name = "BTN_X", .value = BTN_X },
+ { .name = "BTN_Y", .value = BTN_Y },
+ { .name = "BTN_Z", .value = BTN_Z },
+ { .name = "FF_AUTOCENTER", .value = FF_AUTOCENTER },
+ { .name = "FF_CONSTANT", .value = FF_CONSTANT },
+ { .name = "FF_CUSTOM", .value = FF_CUSTOM },
+ { .name = "FF_DAMPER", .value = FF_DAMPER },
+ { .name = "FF_FRICTION", .value = FF_FRICTION },
+ { .name = "FF_GAIN", .value = FF_GAIN },
+ { .name = "FF_INERTIA", .value = FF_INERTIA },
+ { .name = "FF_MAX", .value = FF_MAX },
+ { .name = "FF_PERIODIC", .value = FF_PERIODIC },
+ { .name = "FF_RAMP", .value = FF_RAMP },
+ { .name = "FF_RUMBLE", .value = FF_RUMBLE },
+ { .name = "FF_SAW_DOWN", .value = FF_SAW_DOWN },
+ { .name = "FF_SAW_UP", .value = FF_SAW_UP },
+ { .name = "FF_SINE", .value = FF_SINE },
+ { .name = "FF_SPRING", .value = FF_SPRING },
+ { .name = "FF_SQUARE", .value = FF_SQUARE },
+ { .name = "FF_STATUS_MAX", .value = FF_STATUS_MAX },
+ { .name = "FF_STATUS_STOPPED", .value = FF_STATUS_STOPPED },
+ { .name = "FF_TRIANGLE", .value = FF_TRIANGLE },
+ { .name = "KEY_0", .value = KEY_0 },
+ { .name = "KEY_1", .value = KEY_1 },
+ { .name = "KEY_102ND", .value = KEY_102ND },
+ { .name = "KEY_10CHANNELSDOWN", .value = KEY_10CHANNELSDOWN },
+ { .name = "KEY_10CHANNELSUP", .value = KEY_10CHANNELSUP },
+ { .name = "KEY_2", .value = KEY_2 },
+ { .name = "KEY_3", .value = KEY_3 },
+ { .name = "KEY_3D_MODE", .value = KEY_3D_MODE },
+ { .name = "KEY_4", .value = KEY_4 },
+ { .name = "KEY_5", .value = KEY_5 },
+ { .name = "KEY_6", .value = KEY_6 },
+ { .name = "KEY_7", .value = KEY_7 },
+ { .name = "KEY_8", .value = KEY_8 },
+ { .name = "KEY_9", .value = KEY_9 },
+ { .name = "KEY_A", .value = KEY_A },
+ { .name = "KEY_AB", .value = KEY_AB },
+ { .name = "KEY_ADDRESSBOOK", .value = KEY_ADDRESSBOOK },
+ { .name = "KEY_AGAIN", .value = KEY_AGAIN },
+ // { .name = "KEY_ALL_APPLICATIONS", .value = KEY_ALL_APPLICATIONS },
+ { .name = "KEY_ALS_TOGGLE", .value = KEY_ALS_TOGGLE },
+ { .name = "KEY_ALTERASE", .value = KEY_ALTERASE },
+ { .name = "KEY_ANGLE", .value = KEY_ANGLE },
+ { .name = "KEY_APOSTROPHE", .value = KEY_APOSTROPHE },
+ { .name = "KEY_APPSELECT", .value = KEY_APPSELECT },
+ { .name = "KEY_ARCHIVE", .value = KEY_ARCHIVE },
+ { .name = "KEY_ASPECT_RATIO", .value = KEY_ASPECT_RATIO },
+ { .name = "KEY_ASSISTANT", .value = KEY_ASSISTANT },
+ { .name = "KEY_ATTENDANT_OFF", .value = KEY_ATTENDANT_OFF },
+ { .name = "KEY_ATTENDANT_ON", .value = KEY_ATTENDANT_ON },
+ { .name = "KEY_ATTENDANT_TOGGLE", .value = KEY_ATTENDANT_TOGGLE },
+ { .name = "KEY_AUDIO", .value = KEY_AUDIO },
+ { .name = "KEY_AUDIO_DESC", .value = KEY_AUDIO_DESC },
+ // { .name = "KEY_AUTOPILOT_ENGAGE_TOGGLE", .value = KEY_AUTOPILOT_ENGAGE_TOGGLE },
+ { .name = "KEY_AUX", .value = KEY_AUX },
+ { .name = "KEY_B", .value = KEY_B },
+ { .name = "KEY_BACK", .value = KEY_BACK },
+ { .name = "KEY_BACKSLASH", .value = KEY_BACKSLASH },
+ { .name = "KEY_BACKSPACE", .value = KEY_BACKSPACE },
+ { .name = "KEY_BASSBOOST", .value = KEY_BASSBOOST },
+ { .name = "KEY_BATTERY", .value = KEY_BATTERY },
+ { .name = "KEY_BLUE", .value = KEY_BLUE },
+ { .name = "KEY_BLUETOOTH", .value = KEY_BLUETOOTH },
+ { .name = "KEY_BOOKMARKS", .value = KEY_BOOKMARKS },
+ { .name = "KEY_BREAK", .value = KEY_BREAK },
+ { .name = "KEY_BRIGHTNESSDOWN", .value = KEY_BRIGHTNESSDOWN },
+ { .name = "KEY_BRIGHTNESSUP", .value = KEY_BRIGHTNESSUP },
+ { .name = "KEY_BRIGHTNESS_AUTO", .value = KEY_BRIGHTNESS_AUTO },
+ { .name = "KEY_BRIGHTNESS_CYCLE", .value = KEY_BRIGHTNESS_CYCLE },
+ { .name = "KEY_BRIGHTNESS_MAX", .value = KEY_BRIGHTNESS_MAX },
+ // { .name = "KEY_BRIGHTNESS_MENU", .value = KEY_BRIGHTNESS_MENU },
+ { .name = "KEY_BRIGHTNESS_MIN", .value = KEY_BRIGHTNESS_MIN },
+ { .name = "KEY_BRL_DOT1", .value = KEY_BRL_DOT1 },
+ { .name = "KEY_BRL_DOT10", .value = KEY_BRL_DOT10 },
+ { .name = "KEY_BRL_DOT2", .value = KEY_BRL_DOT2 },
+ { .name = "KEY_BRL_DOT3", .value = KEY_BRL_DOT3 },
+ { .name = "KEY_BRL_DOT4", .value = KEY_BRL_DOT4 },
+ { .name = "KEY_BRL_DOT5", .value = KEY_BRL_DOT5 },
+ { .name = "KEY_BRL_DOT6", .value = KEY_BRL_DOT6 },
+ { .name = "KEY_BRL_DOT7", .value = KEY_BRL_DOT7 },
+ { .name = "KEY_BRL_DOT8", .value = KEY_BRL_DOT8 },
+ { .name = "KEY_BRL_DOT9", .value = KEY_BRL_DOT9 },
+ { .name = "KEY_BUTTONCONFIG", .value = KEY_BUTTONCONFIG },
+ { .name = "KEY_C", .value = KEY_C },
+ { .name = "KEY_CALC", .value = KEY_CALC },
+ { .name = "KEY_CALENDAR", .value = KEY_CALENDAR },
+ { .name = "KEY_CAMERA", .value = KEY_CAMERA },
+ // { .name = "KEY_CAMERA_ACCESS_DISABLE", .value = KEY_CAMERA_ACCESS_DISABLE },
+ // { .name = "KEY_CAMERA_ACCESS_ENABLE", .value = KEY_CAMERA_ACCESS_ENABLE },
+ // { .name = "KEY_CAMERA_ACCESS_TOGGLE", .value = KEY_CAMERA_ACCESS_TOGGLE },
+ { .name = "KEY_CAMERA_DOWN", .value = KEY_CAMERA_DOWN },
+ { .name = "KEY_CAMERA_FOCUS", .value = KEY_CAMERA_FOCUS },
+ { .name = "KEY_CAMERA_LEFT", .value = KEY_CAMERA_LEFT },
+ { .name = "KEY_CAMERA_RIGHT", .value = KEY_CAMERA_RIGHT },
+ { .name = "KEY_CAMERA_UP", .value = KEY_CAMERA_UP },
+ { .name = "KEY_CAMERA_ZOOMIN", .value = KEY_CAMERA_ZOOMIN },
+ { .name = "KEY_CAMERA_ZOOMOUT", .value = KEY_CAMERA_ZOOMOUT },
+ { .name = "KEY_CANCEL", .value = KEY_CANCEL },
+ { .name = "KEY_CAPSLOCK", .value = KEY_CAPSLOCK },
+ { .name = "KEY_CD", .value = KEY_CD },
+ { .name = "KEY_CHANNEL", .value = KEY_CHANNEL },
+ { .name = "KEY_CHANNELDOWN", .value = KEY_CHANNELDOWN },
+ { .name = "KEY_CHANNELUP", .value = KEY_CHANNELUP },
+ { .name = "KEY_CHAT", .value = KEY_CHAT },
+ { .name = "KEY_CLEAR", .value = KEY_CLEAR },
+ // { .name = "KEY_CLEARVU_SONAR", .value = KEY_CLEARVU_SONAR },
+ { .name = "KEY_CLOSE", .value = KEY_CLOSE },
+ { .name = "KEY_CLOSECD", .value = KEY_CLOSECD },
+ { .name = "KEY_COFFEE", .value = KEY_COFFEE },
+ { .name = "KEY_COMMA", .value = KEY_COMMA },
+ { .name = "KEY_COMPOSE", .value = KEY_COMPOSE },
+ { .name = "KEY_COMPUTER", .value = KEY_COMPUTER },
+ { .name = "KEY_CONFIG", .value = KEY_CONFIG },
+ { .name = "KEY_CONNECT", .value = KEY_CONNECT },
+ { .name = "KEY_CONTEXT_MENU", .value = KEY_CONTEXT_MENU },
+ { .name = "KEY_CONTROLPANEL", .value = KEY_CONTROLPANEL },
+ { .name = "KEY_COPY", .value = KEY_COPY },
+ { .name = "KEY_CUT", .value = KEY_CUT },
+ { .name = "KEY_CYCLEWINDOWS", .value = KEY_CYCLEWINDOWS },
+ { .name = "KEY_D", .value = KEY_D },
+ { .name = "KEY_DATA", .value = KEY_DATA },
+ { .name = "KEY_DATABASE", .value = KEY_DATABASE },
+ { .name = "KEY_DELETE", .value = KEY_DELETE },
+ { .name = "KEY_DELETEFILE", .value = KEY_DELETEFILE },
+ { .name = "KEY_DEL_EOL", .value = KEY_DEL_EOL },
+ { .name = "KEY_DEL_EOS", .value = KEY_DEL_EOS },
+ { .name = "KEY_DEL_LINE", .value = KEY_DEL_LINE },
+ // { .name = "KEY_DICTATE", .value = KEY_DICTATE },
+ { .name = "KEY_DIGITS", .value = KEY_DIGITS },
+ { .name = "KEY_DIRECTORY", .value = KEY_DIRECTORY },
+ { .name = "KEY_DISPLAYTOGGLE", .value = KEY_DISPLAYTOGGLE },
+ { .name = "KEY_DISPLAY_OFF", .value = KEY_DISPLAY_OFF },
+ { .name = "KEY_DOCUMENTS", .value = KEY_DOCUMENTS },
+ { .name = "KEY_DOLLAR", .value = KEY_DOLLAR },
+ { .name = "KEY_DOT", .value = KEY_DOT },
+ { .name = "KEY_DOWN", .value = KEY_DOWN },
+ // { .name = "KEY_DUAL_RANGE_RADAR", .value = KEY_DUAL_RANGE_RADAR },
+ { .name = "KEY_DVD", .value = KEY_DVD },
+ { .name = "KEY_E", .value = KEY_E },
+ { .name = "KEY_EDIT", .value = KEY_EDIT },
+ { .name = "KEY_EDITOR", .value = KEY_EDITOR },
+ { .name = "KEY_EJECTCD", .value = KEY_EJECTCD },
+ { .name = "KEY_EJECTCLOSECD", .value = KEY_EJECTCLOSECD },
+ { .name = "KEY_EMAIL", .value = KEY_EMAIL },
+ // { .name = "KEY_EMOJI_PICKER", .value = KEY_EMOJI_PICKER },
+ { .name = "KEY_END", .value = KEY_END },
+ { .name = "KEY_ENTER", .value = KEY_ENTER },
+ { .name = "KEY_EPG", .value = KEY_EPG },
+ { .name = "KEY_EQUAL", .value = KEY_EQUAL },
+ { .name = "KEY_ESC", .value = KEY_ESC },
+ { .name = "KEY_EURO", .value = KEY_EURO },
+ { .name = "KEY_EXIT", .value = KEY_EXIT },
+ { .name = "KEY_F", .value = KEY_F },
+ { .name = "KEY_F1", .value = KEY_F1 },
+ { .name = "KEY_F10", .value = KEY_F10 },
+ { .name = "KEY_F11", .value = KEY_F11 },
+ { .name = "KEY_F12", .value = KEY_F12 },
+ { .name = "KEY_F13", .value = KEY_F13 },
+ { .name = "KEY_F14", .value = KEY_F14 },
+ { .name = "KEY_F15", .value = KEY_F15 },
+ { .name = "KEY_F16", .value = KEY_F16 },
+ { .name = "KEY_F17", .value = KEY_F17 },
+ { .name = "KEY_F18", .value = KEY_F18 },
+ { .name = "KEY_F19", .value = KEY_F19 },
+ { .name = "KEY_F2", .value = KEY_F2 },
+ { .name = "KEY_F20", .value = KEY_F20 },
+ { .name = "KEY_F21", .value = KEY_F21 },
+ { .name = "KEY_F22", .value = KEY_F22 },
+ { .name = "KEY_F23", .value = KEY_F23 },
+ { .name = "KEY_F24", .value = KEY_F24 },
+ { .name = "KEY_F3", .value = KEY_F3 },
+ { .name = "KEY_F4", .value = KEY_F4 },
+ { .name = "KEY_F5", .value = KEY_F5 },
+ { .name = "KEY_F6", .value = KEY_F6 },
+ { .name = "KEY_F7", .value = KEY_F7 },
+ { .name = "KEY_F8", .value = KEY_F8 },
+ { .name = "KEY_F9", .value = KEY_F9 },
+ { .name = "KEY_FASTFORWARD", .value = KEY_FASTFORWARD },
+ { .name = "KEY_FASTREVERSE", .value = KEY_FASTREVERSE },
+ { .name = "KEY_FAVORITES", .value = KEY_FAVORITES },
+ { .name = "KEY_FILE", .value = KEY_FILE },
+ { .name = "KEY_FINANCE", .value = KEY_FINANCE },
+ { .name = "KEY_FIND", .value = KEY_FIND },
+ { .name = "KEY_FIRST", .value = KEY_FIRST },
+ // { .name = "KEY_FISHING_CHART", .value = KEY_FISHING_CHART },
+ { .name = "KEY_FN", .value = KEY_FN },
+ { .name = "KEY_FN_1", .value = KEY_FN_1 },
+ { .name = "KEY_FN_2", .value = KEY_FN_2 },
+ { .name = "KEY_FN_B", .value = KEY_FN_B },
+ { .name = "KEY_FN_D", .value = KEY_FN_D },
+ { .name = "KEY_FN_E", .value = KEY_FN_E },
+ { .name = "KEY_FN_ESC", .value = KEY_FN_ESC },
+ { .name = "KEY_FN_F", .value = KEY_FN_F },
+ { .name = "KEY_FN_F1", .value = KEY_FN_F1 },
+ { .name = "KEY_FN_F10", .value = KEY_FN_F10 },
+ { .name = "KEY_FN_F11", .value = KEY_FN_F11 },
+ { .name = "KEY_FN_F12", .value = KEY_FN_F12 },
+ { .name = "KEY_FN_F2", .value = KEY_FN_F2 },
+ { .name = "KEY_FN_F3", .value = KEY_FN_F3 },
+ { .name = "KEY_FN_F4", .value = KEY_FN_F4 },
+ { .name = "KEY_FN_F5", .value = KEY_FN_F5 },
+ { .name = "KEY_FN_F6", .value = KEY_FN_F6 },
+ { .name = "KEY_FN_F7", .value = KEY_FN_F7 },
+ { .name = "KEY_FN_F8", .value = KEY_FN_F8 },
+ { .name = "KEY_FN_F9", .value = KEY_FN_F9 },
+ // { .name = "KEY_FN_RIGHT_SHIFT", .value = KEY_FN_RIGHT_SHIFT },
+ { .name = "KEY_FN_S", .value = KEY_FN_S },
+ { .name = "KEY_FORWARD", .value = KEY_FORWARD },
+ { .name = "KEY_FORWARDMAIL", .value = KEY_FORWARDMAIL },
+ { .name = "KEY_FRAMEBACK", .value = KEY_FRAMEBACK },
+ { .name = "KEY_FRAMEFORWARD", .value = KEY_FRAMEFORWARD },
+ { .name = "KEY_FRONT", .value = KEY_FRONT },
+ { .name = "KEY_FULL_SCREEN", .value = KEY_FULL_SCREEN },
+ { .name = "KEY_G", .value = KEY_G },
+ { .name = "KEY_GAMES", .value = KEY_GAMES },
+ { .name = "KEY_GOTO", .value = KEY_GOTO },
+ { .name = "KEY_GRAPHICSEDITOR", .value = KEY_GRAPHICSEDITOR },
+ { .name = "KEY_GRAVE", .value = KEY_GRAVE },
+ { .name = "KEY_GREEN", .value = KEY_GREEN },
+ { .name = "KEY_H", .value = KEY_H },
+ { .name = "KEY_HANGEUL", .value = KEY_HANGEUL },
+ // { .name = "KEY_HANGUP_PHONE", .value = KEY_HANGUP_PHONE },
+ { .name = "KEY_HANJA", .value = KEY_HANJA },
+ { .name = "KEY_HELP", .value = KEY_HELP },
+ { .name = "KEY_HENKAN", .value = KEY_HENKAN },
+ { .name = "KEY_HIRAGANA", .value = KEY_HIRAGANA },
+ { .name = "KEY_HOME", .value = KEY_HOME },
+ { .name = "KEY_HOMEPAGE", .value = KEY_HOMEPAGE },
+ { .name = "KEY_HP", .value = KEY_HP },
+ { .name = "KEY_I", .value = KEY_I },
+ { .name = "KEY_IMAGES", .value = KEY_IMAGES },
+ { .name = "KEY_INFO", .value = KEY_INFO },
+ { .name = "KEY_INSERT", .value = KEY_INSERT },
+ { .name = "KEY_INS_LINE", .value = KEY_INS_LINE },
+ { .name = "KEY_ISO", .value = KEY_ISO },
+ { .name = "KEY_J", .value = KEY_J },
+ { .name = "KEY_JOURNAL", .value = KEY_JOURNAL },
+ { .name = "KEY_K", .value = KEY_K },
+ { .name = "KEY_KATAKANA", .value = KEY_KATAKANA },
+ { .name = "KEY_KATAKANAHIRAGANA", .value = KEY_KATAKANAHIRAGANA },
+ { .name = "KEY_KBDILLUMDOWN", .value = KEY_KBDILLUMDOWN },
+ { .name = "KEY_KBDILLUMTOGGLE", .value = KEY_KBDILLUMTOGGLE },
+ { .name = "KEY_KBDILLUMUP", .value = KEY_KBDILLUMUP },
+ { .name = "KEY_KBDINPUTASSIST_ACCEPT", .value = KEY_KBDINPUTASSIST_ACCEPT },
+ { .name = "KEY_KBDINPUTASSIST_CANCEL", .value = KEY_KBDINPUTASSIST_CANCEL },
+ { .name = "KEY_KBDINPUTASSIST_NEXT", .value = KEY_KBDINPUTASSIST_NEXT },
+ { .name = "KEY_KBDINPUTASSIST_NEXTGROUP", .value = KEY_KBDINPUTASSIST_NEXTGROUP },
+ { .name = "KEY_KBDINPUTASSIST_PREV", .value = KEY_KBDINPUTASSIST_PREV },
+ { .name = "KEY_KBDINPUTASSIST_PREVGROUP", .value = KEY_KBDINPUTASSIST_PREVGROUP },
+ { .name = "KEY_KBD_LAYOUT_NEXT", .value = KEY_KBD_LAYOUT_NEXT },
+ { .name = "KEY_KBD_LCD_MENU1", .value = KEY_KBD_LCD_MENU1 },
+ { .name = "KEY_KBD_LCD_MENU2", .value = KEY_KBD_LCD_MENU2 },
+ { .name = "KEY_KBD_LCD_MENU3", .value = KEY_KBD_LCD_MENU3 },
+ { .name = "KEY_KBD_LCD_MENU4", .value = KEY_KBD_LCD_MENU4 },
+ { .name = "KEY_KBD_LCD_MENU5", .value = KEY_KBD_LCD_MENU5 },
+ { .name = "KEY_KEYBOARD", .value = KEY_KEYBOARD },
+ { .name = "KEY_KP0", .value = KEY_KP0 },
+ { .name = "KEY_KP1", .value = KEY_KP1 },
+ { .name = "KEY_KP2", .value = KEY_KP2 },
+ { .name = "KEY_KP3", .value = KEY_KP3 },
+ { .name = "KEY_KP4", .value = KEY_KP4 },
+ { .name = "KEY_KP5", .value = KEY_KP5 },
+ { .name = "KEY_KP6", .value = KEY_KP6 },
+ { .name = "KEY_KP7", .value = KEY_KP7 },
+ { .name = "KEY_KP8", .value = KEY_KP8 },
+ { .name = "KEY_KP9", .value = KEY_KP9 },
+ { .name = "KEY_KPASTERISK", .value = KEY_KPASTERISK },
+ { .name = "KEY_KPCOMMA", .value = KEY_KPCOMMA },
+ { .name = "KEY_KPDOT", .value = KEY_KPDOT },
+ { .name = "KEY_KPENTER", .value = KEY_KPENTER },
+ { .name = "KEY_KPEQUAL", .value = KEY_KPEQUAL },
+ { .name = "KEY_KPJPCOMMA", .value = KEY_KPJPCOMMA },
+ { .name = "KEY_KPLEFTPAREN", .value = KEY_KPLEFTPAREN },
+ { .name = "KEY_KPMINUS", .value = KEY_KPMINUS },
+ { .name = "KEY_KPPLUS", .value = KEY_KPPLUS },
+ { .name = "KEY_KPPLUSMINUS", .value = KEY_KPPLUSMINUS },
+ { .name = "KEY_KPRIGHTPAREN", .value = KEY_KPRIGHTPAREN },
+ { .name = "KEY_KPSLASH", .value = KEY_KPSLASH },
+ { .name = "KEY_L", .value = KEY_L },
+ { .name = "KEY_LANGUAGE", .value = KEY_LANGUAGE },
+ { .name = "KEY_LAST", .value = KEY_LAST },
+ { .name = "KEY_LEFT", .value = KEY_LEFT },
+ { .name = "KEY_LEFTALT", .value = KEY_LEFTALT },
+ { .name = "KEY_LEFTBRACE", .value = KEY_LEFTBRACE },
+ { .name = "KEY_LEFTCTRL", .value = KEY_LEFTCTRL },
+ { .name = "KEY_LEFTMETA", .value = KEY_LEFTMETA },
+ { .name = "KEY_LEFTSHIFT", .value = KEY_LEFTSHIFT },
+ { .name = "KEY_LEFT_DOWN", .value = KEY_LEFT_DOWN },
+ { .name = "KEY_LEFT_UP", .value = KEY_LEFT_UP },
+ { .name = "KEY_LIGHTS_TOGGLE", .value = KEY_LIGHTS_TOGGLE },
+ { .name = "KEY_LINEFEED", .value = KEY_LINEFEED },
+ { .name = "KEY_LIST", .value = KEY_LIST },
+ { .name = "KEY_LOGOFF", .value = KEY_LOGOFF },
+ { .name = "KEY_M", .value = KEY_M },
+ { .name = "KEY_MACRO", .value = KEY_MACRO },
+ { .name = "KEY_MACRO1", .value = KEY_MACRO1 },
+ { .name = "KEY_MACRO10", .value = KEY_MACRO10 },
+ { .name = "KEY_MACRO11", .value = KEY_MACRO11 },
+ { .name = "KEY_MACRO12", .value = KEY_MACRO12 },
+ { .name = "KEY_MACRO13", .value = KEY_MACRO13 },
+ { .name = "KEY_MACRO14", .value = KEY_MACRO14 },
+ { .name = "KEY_MACRO15", .value = KEY_MACRO15 },
+ { .name = "KEY_MACRO16", .value = KEY_MACRO16 },
+ { .name = "KEY_MACRO17", .value = KEY_MACRO17 },
+ { .name = "KEY_MACRO18", .value = KEY_MACRO18 },
+ { .name = "KEY_MACRO19", .value = KEY_MACRO19 },
+ { .name = "KEY_MACRO2", .value = KEY_MACRO2 },
+ { .name = "KEY_MACRO20", .value = KEY_MACRO20 },
+ { .name = "KEY_MACRO21", .value = KEY_MACRO21 },
+ { .name = "KEY_MACRO22", .value = KEY_MACRO22 },
+ { .name = "KEY_MACRO23", .value = KEY_MACRO23 },
+ { .name = "KEY_MACRO24", .value = KEY_MACRO24 },
+ { .name = "KEY_MACRO25", .value = KEY_MACRO25 },
+ { .name = "KEY_MACRO26", .value = KEY_MACRO26 },
+ { .name = "KEY_MACRO27", .value = KEY_MACRO27 },
+ { .name = "KEY_MACRO28", .value = KEY_MACRO28 },
+ { .name = "KEY_MACRO29", .value = KEY_MACRO29 },
+ { .name = "KEY_MACRO3", .value = KEY_MACRO3 },
+ { .name = "KEY_MACRO30", .value = KEY_MACRO30 },
+ { .name = "KEY_MACRO4", .value = KEY_MACRO4 },
+ { .name = "KEY_MACRO5", .value = KEY_MACRO5 },
+ { .name = "KEY_MACRO6", .value = KEY_MACRO6 },
+ { .name = "KEY_MACRO7", .value = KEY_MACRO7 },
+ { .name = "KEY_MACRO8", .value = KEY_MACRO8 },
+ { .name = "KEY_MACRO9", .value = KEY_MACRO9 },
+ { .name = "KEY_MACRO_PRESET1", .value = KEY_MACRO_PRESET1 },
+ { .name = "KEY_MACRO_PRESET2", .value = KEY_MACRO_PRESET2 },
+ { .name = "KEY_MACRO_PRESET3", .value = KEY_MACRO_PRESET3 },
+ { .name = "KEY_MACRO_PRESET_CYCLE", .value = KEY_MACRO_PRESET_CYCLE },
+ { .name = "KEY_MACRO_RECORD_START", .value = KEY_MACRO_RECORD_START },
+ { .name = "KEY_MACRO_RECORD_STOP", .value = KEY_MACRO_RECORD_STOP },
+ { .name = "KEY_MAIL", .value = KEY_MAIL },
+ // { .name = "KEY_MARK_WAYPOINT", .value = KEY_MARK_WAYPOINT },
+ { .name = "KEY_MAX", .value = KEY_MAX },
+ { .name = "KEY_MEDIA", .value = KEY_MEDIA },
+ { .name = "KEY_MEDIA_REPEAT", .value = KEY_MEDIA_REPEAT },
+ { .name = "KEY_MEDIA_TOP_MENU", .value = KEY_MEDIA_TOP_MENU },
+ { .name = "KEY_MEMO", .value = KEY_MEMO },
+ { .name = "KEY_MENU", .value = KEY_MENU },
+ { .name = "KEY_MESSENGER", .value = KEY_MESSENGER },
+ { .name = "KEY_MHP", .value = KEY_MHP },
+ { .name = "KEY_MICMUTE", .value = KEY_MICMUTE },
+ { .name = "KEY_MINUS", .value = KEY_MINUS },
+ { .name = "KEY_MODE", .value = KEY_MODE },
+ { .name = "KEY_MOVE", .value = KEY_MOVE },
+ { .name = "KEY_MP3", .value = KEY_MP3 },
+ { .name = "KEY_MSDOS", .value = KEY_MSDOS },
+ { .name = "KEY_MUHENKAN", .value = KEY_MUHENKAN },
+ { .name = "KEY_MUTE", .value = KEY_MUTE },
+ { .name = "KEY_N", .value = KEY_N },
+ // { .name = "KEY_NAV_CHART", .value = KEY_NAV_CHART },
+ // { .name = "KEY_NAV_INFO", .value = KEY_NAV_INFO },
+ { .name = "KEY_NEW", .value = KEY_NEW },
+ { .name = "KEY_NEWS", .value = KEY_NEWS },
+ { .name = "KEY_NEXT", .value = KEY_NEXT },
+ { .name = "KEY_NEXTSONG", .value = KEY_NEXTSONG },
+ // { .name = "KEY_NEXT_ELEMENT", .value = KEY_NEXT_ELEMENT },
+ { .name = "KEY_NEXT_FAVORITE", .value = KEY_NEXT_FAVORITE },
+ // { .name = "KEY_NOTIFICATION_CENTER", .value = KEY_NOTIFICATION_CENTER },
+ { .name = "KEY_NUMERIC_0", .value = KEY_NUMERIC_0 },
+ { .name = "KEY_NUMERIC_1", .value = KEY_NUMERIC_1 },
+ { .name = "KEY_NUMERIC_11", .value = KEY_NUMERIC_11 },
+ { .name = "KEY_NUMERIC_12", .value = KEY_NUMERIC_12 },
+ { .name = "KEY_NUMERIC_2", .value = KEY_NUMERIC_2 },
+ { .name = "KEY_NUMERIC_3", .value = KEY_NUMERIC_3 },
+ { .name = "KEY_NUMERIC_4", .value = KEY_NUMERIC_4 },
+ { .name = "KEY_NUMERIC_5", .value = KEY_NUMERIC_5 },
+ { .name = "KEY_NUMERIC_6", .value = KEY_NUMERIC_6 },
+ { .name = "KEY_NUMERIC_7", .value = KEY_NUMERIC_7 },
+ { .name = "KEY_NUMERIC_8", .value = KEY_NUMERIC_8 },
+ { .name = "KEY_NUMERIC_9", .value = KEY_NUMERIC_9 },
+ { .name = "KEY_NUMERIC_A", .value = KEY_NUMERIC_A },
+ { .name = "KEY_NUMERIC_B", .value = KEY_NUMERIC_B },
+ { .name = "KEY_NUMERIC_C", .value = KEY_NUMERIC_C },
+ { .name = "KEY_NUMERIC_D", .value = KEY_NUMERIC_D },
+ { .name = "KEY_NUMERIC_POUND", .value = KEY_NUMERIC_POUND },
+ { .name = "KEY_NUMERIC_STAR", .value = KEY_NUMERIC_STAR },
+ { .name = "KEY_NUMLOCK", .value = KEY_NUMLOCK },
+ { .name = "KEY_O", .value = KEY_O },
+ { .name = "KEY_OK", .value = KEY_OK },
+ { .name = "KEY_ONSCREEN_KEYBOARD", .value = KEY_ONSCREEN_KEYBOARD },
+ { .name = "KEY_OPEN", .value = KEY_OPEN },
+ { .name = "KEY_OPTION", .value = KEY_OPTION },
+ { .name = "KEY_P", .value = KEY_P },
+ { .name = "KEY_PAGEDOWN", .value = KEY_PAGEDOWN },
+ { .name = "KEY_PAGEUP", .value = KEY_PAGEUP },
+ { .name = "KEY_PASTE", .value = KEY_PASTE },
+ { .name = "KEY_PAUSE", .value = KEY_PAUSE },
+ { .name = "KEY_PAUSECD", .value = KEY_PAUSECD },
+ { .name = "KEY_PAUSE_RECORD", .value = KEY_PAUSE_RECORD },
+ { .name = "KEY_PC", .value = KEY_PC },
+ { .name = "KEY_PHONE", .value = KEY_PHONE },
+ // { .name = "KEY_PICKUP_PHONE", .value = KEY_PICKUP_PHONE },
+ { .name = "KEY_PLAY", .value = KEY_PLAY },
+ { .name = "KEY_PLAYCD", .value = KEY_PLAYCD },
+ { .name = "KEY_PLAYER", .value = KEY_PLAYER },
+ { .name = "KEY_PLAYPAUSE", .value = KEY_PLAYPAUSE },
+ { .name = "KEY_POWER", .value = KEY_POWER },
+ { .name = "KEY_POWER2", .value = KEY_POWER2 },
+ { .name = "KEY_PRESENTATION", .value = KEY_PRESENTATION },
+ { .name = "KEY_PREVIOUS", .value = KEY_PREVIOUS },
+ { .name = "KEY_PREVIOUSSONG", .value = KEY_PREVIOUSSONG },
+ // { .name = "KEY_PREVIOUS_ELEMENT", .value = KEY_PREVIOUS_ELEMENT },
+ { .name = "KEY_PRINT", .value = KEY_PRINT },
+ { .name = "KEY_PRIVACY_SCREEN_TOGGLE", .value = KEY_PRIVACY_SCREEN_TOGGLE },
+ { .name = "KEY_PROG1", .value = KEY_PROG1 },
+ { .name = "KEY_PROG2", .value = KEY_PROG2 },
+ { .name = "KEY_PROG3", .value = KEY_PROG3 },
+ { .name = "KEY_PROG4", .value = KEY_PROG4 },
+ { .name = "KEY_PROGRAM", .value = KEY_PROGRAM },
+ { .name = "KEY_PROPS", .value = KEY_PROPS },
+ { .name = "KEY_PVR", .value = KEY_PVR },
+ { .name = "KEY_Q", .value = KEY_Q },
+ { .name = "KEY_QUESTION", .value = KEY_QUESTION },
+ { .name = "KEY_R", .value = KEY_R },
+ // { .name = "KEY_RADAR_OVERLAY", .value = KEY_RADAR_OVERLAY },
+ { .name = "KEY_RADIO", .value = KEY_RADIO },
+ { .name = "KEY_RECORD", .value = KEY_RECORD },
+ { .name = "KEY_RED", .value = KEY_RED },
+ { .name = "KEY_REDO", .value = KEY_REDO },
+ { .name = "KEY_REFRESH", .value = KEY_REFRESH },
+ { .name = "KEY_REPLY", .value = KEY_REPLY },
+ { .name = "KEY_RESERVED", .value = KEY_RESERVED },
+ { .name = "KEY_RESTART", .value = KEY_RESTART },
+ { .name = "KEY_REWIND", .value = KEY_REWIND },
+ { .name = "KEY_RFKILL", .value = KEY_RFKILL },
+ { .name = "KEY_RIGHT", .value = KEY_RIGHT },
+ { .name = "KEY_RIGHTALT", .value = KEY_RIGHTALT },
+ { .name = "KEY_RIGHTBRACE", .value = KEY_RIGHTBRACE },
+ { .name = "KEY_RIGHTCTRL", .value = KEY_RIGHTCTRL },
+ { .name = "KEY_RIGHTMETA", .value = KEY_RIGHTMETA },
+ { .name = "KEY_RIGHTSHIFT", .value = KEY_RIGHTSHIFT },
+ { .name = "KEY_RIGHT_DOWN", .value = KEY_RIGHT_DOWN },
+ { .name = "KEY_RIGHT_UP", .value = KEY_RIGHT_UP },
+ { .name = "KEY_RO", .value = KEY_RO },
+ { .name = "KEY_ROOT_MENU", .value = KEY_ROOT_MENU },
+ { .name = "KEY_ROTATE_DISPLAY", .value = KEY_ROTATE_DISPLAY },
+ { .name = "KEY_ROTATE_LOCK_TOGGLE", .value = KEY_ROTATE_LOCK_TOGGLE },
+ { .name = "KEY_S", .value = KEY_S },
+ { .name = "KEY_SAT", .value = KEY_SAT },
+ { .name = "KEY_SAT2", .value = KEY_SAT2 },
+ { .name = "KEY_SAVE", .value = KEY_SAVE },
+ { .name = "KEY_SCALE", .value = KEY_SCALE },
+ { .name = "KEY_SCREENSAVER", .value = KEY_SCREENSAVER },
+ { .name = "KEY_SCROLLDOWN", .value = KEY_SCROLLDOWN },
+ { .name = "KEY_SCROLLLOCK", .value = KEY_SCROLLLOCK },
+ { .name = "KEY_SCROLLUP", .value = KEY_SCROLLUP },
+ { .name = "KEY_SEARCH", .value = KEY_SEARCH },
+ { .name = "KEY_SELECT", .value = KEY_SELECT },
+ { .name = "KEY_SELECTIVE_SCREENSHOT", .value = KEY_SELECTIVE_SCREENSHOT },
+ { .name = "KEY_SEMICOLON", .value = KEY_SEMICOLON },
+ { .name = "KEY_SEND", .value = KEY_SEND },
+ { .name = "KEY_SENDFILE", .value = KEY_SENDFILE },
+ { .name = "KEY_SETUP", .value = KEY_SETUP },
+ { .name = "KEY_SHOP", .value = KEY_SHOP },
+ { .name = "KEY_SHUFFLE", .value = KEY_SHUFFLE },
+ // { .name = "KEY_SIDEVU_SONAR", .value = KEY_SIDEVU_SONAR },
+ // { .name = "KEY_SINGLE_RANGE_RADAR", .value = KEY_SINGLE_RANGE_RADAR },
+ { .name = "KEY_SLASH", .value = KEY_SLASH },
+ { .name = "KEY_SLEEP", .value = KEY_SLEEP },
+ { .name = "KEY_SLOW", .value = KEY_SLOW },
+ { .name = "KEY_SLOWREVERSE", .value = KEY_SLOWREVERSE },
+ // { .name = "KEY_SOS", .value = KEY_SOS },
+ { .name = "KEY_SOUND", .value = KEY_SOUND },
+ { .name = "KEY_SPACE", .value = KEY_SPACE },
+ { .name = "KEY_SPELLCHECK", .value = KEY_SPELLCHECK },
+ { .name = "KEY_SPORT", .value = KEY_SPORT },
+ { .name = "KEY_SPREADSHEET", .value = KEY_SPREADSHEET },
+ { .name = "KEY_STOP", .value = KEY_STOP },
+ { .name = "KEY_STOPCD", .value = KEY_STOPCD },
+ { .name = "KEY_STOP_RECORD", .value = KEY_STOP_RECORD },
+ { .name = "KEY_SUBTITLE", .value = KEY_SUBTITLE },
+ { .name = "KEY_SUSPEND", .value = KEY_SUSPEND },
+ { .name = "KEY_SWITCHVIDEOMODE", .value = KEY_SWITCHVIDEOMODE },
+ { .name = "KEY_SYSRQ", .value = KEY_SYSRQ },
+ { .name = "KEY_T", .value = KEY_T },
+ { .name = "KEY_TAB", .value = KEY_TAB },
+ { .name = "KEY_TAPE", .value = KEY_TAPE },
+ { .name = "KEY_TASKMANAGER", .value = KEY_TASKMANAGER },
+ { .name = "KEY_TEEN", .value = KEY_TEEN },
+ { .name = "KEY_TEXT", .value = KEY_TEXT },
+ { .name = "KEY_TIME", .value = KEY_TIME },
+ { .name = "KEY_TITLE", .value = KEY_TITLE },
+ { .name = "KEY_TOUCHPAD_OFF", .value = KEY_TOUCHPAD_OFF },
+ { .name = "KEY_TOUCHPAD_ON", .value = KEY_TOUCHPAD_ON },
+ { .name = "KEY_TOUCHPAD_TOGGLE", .value = KEY_TOUCHPAD_TOGGLE },
+ // { .name = "KEY_TRADITIONAL_SONAR", .value = KEY_TRADITIONAL_SONAR },
+ { .name = "KEY_TUNER", .value = KEY_TUNER },
+ { .name = "KEY_TV", .value = KEY_TV },
+ { .name = "KEY_TV2", .value = KEY_TV2 },
+ { .name = "KEY_TWEN", .value = KEY_TWEN },
+ { .name = "KEY_U", .value = KEY_U },
+ { .name = "KEY_UNDO", .value = KEY_UNDO },
+ { .name = "KEY_UNKNOWN", .value = KEY_UNKNOWN },
+ { .name = "KEY_UNMUTE", .value = KEY_UNMUTE },
+ { .name = "KEY_UP", .value = KEY_UP },
+ { .name = "KEY_UWB", .value = KEY_UWB },
+ { .name = "KEY_V", .value = KEY_V },
+ { .name = "KEY_VCR", .value = KEY_VCR },
+ { .name = "KEY_VCR2", .value = KEY_VCR2 },
+ { .name = "KEY_VENDOR", .value = KEY_VENDOR },
+ { .name = "KEY_VIDEO", .value = KEY_VIDEO },
+ { .name = "KEY_VIDEOPHONE", .value = KEY_VIDEOPHONE },
+ { .name = "KEY_VIDEO_NEXT", .value = KEY_VIDEO_NEXT },
+ { .name = "KEY_VIDEO_PREV", .value = KEY_VIDEO_PREV },
+ { .name = "KEY_VOD", .value = KEY_VOD },
+ { .name = "KEY_VOICECOMMAND", .value = KEY_VOICECOMMAND },
+ { .name = "KEY_VOICEMAIL", .value = KEY_VOICEMAIL },
+ { .name = "KEY_VOLUMEDOWN", .value = KEY_VOLUMEDOWN },
+ { .name = "KEY_VOLUMEUP", .value = KEY_VOLUMEUP },
+ { .name = "KEY_W", .value = KEY_W },
+ { .name = "KEY_WAKEUP", .value = KEY_WAKEUP },
+ { .name = "KEY_WLAN", .value = KEY_WLAN },
+ { .name = "KEY_WORDPROCESSOR", .value = KEY_WORDPROCESSOR },
+ { .name = "KEY_WPS_BUTTON", .value = KEY_WPS_BUTTON },
+ { .name = "KEY_WWAN", .value = KEY_WWAN },
+ { .name = "KEY_WWW", .value = KEY_WWW },
+ { .name = "KEY_X", .value = KEY_X },
+ { .name = "KEY_XFER", .value = KEY_XFER },
+ { .name = "KEY_Y", .value = KEY_Y },
+ { .name = "KEY_YELLOW", .value = KEY_YELLOW },
+ { .name = "KEY_YEN", .value = KEY_YEN },
+ { .name = "KEY_Z", .value = KEY_Z },
+ { .name = "KEY_ZENKAKUHANKAKU", .value = KEY_ZENKAKUHANKAKU },
+ { .name = "KEY_ZOOMIN", .value = KEY_ZOOMIN },
+ { .name = "KEY_ZOOMOUT", .value = KEY_ZOOMOUT },
+ { .name = "KEY_ZOOMRESET", .value = KEY_ZOOMRESET },
+ { .name = "LED_CAPSL", .value = LED_CAPSL },
+ { .name = "LED_CHARGING", .value = LED_CHARGING },
+ { .name = "LED_COMPOSE", .value = LED_COMPOSE },
+ { .name = "LED_KANA", .value = LED_KANA },
+ { .name = "LED_MAIL", .value = LED_MAIL },
+ { .name = "LED_MAX", .value = LED_MAX },
+ { .name = "LED_MISC", .value = LED_MISC },
+ { .name = "LED_MUTE", .value = LED_MUTE },
+ { .name = "LED_NUML", .value = LED_NUML },
+ { .name = "LED_SCROLLL", .value = LED_SCROLLL },
+ { .name = "LED_SLEEP", .value = LED_SLEEP },
+ { .name = "LED_SUSPEND", .value = LED_SUSPEND },
+ { .name = "MSC_GESTURE", .value = MSC_GESTURE },
+ { .name = "MSC_MAX", .value = MSC_MAX },
+ { .name = "MSC_PULSELED", .value = MSC_PULSELED },
+ { .name = "MSC_RAW", .value = MSC_RAW },
+ { .name = "MSC_SCAN", .value = MSC_SCAN },
+ { .name = "MSC_SERIAL", .value = MSC_SERIAL },
+ { .name = "MSC_TIMESTAMP", .value = MSC_TIMESTAMP },
+ { .name = "REL_DIAL", .value = REL_DIAL },
+ { .name = "REL_HWHEEL", .value = REL_HWHEEL },
+ { .name = "REL_HWHEEL_HI_RES", .value = REL_HWHEEL_HI_RES },
+ { .name = "REL_MAX", .value = REL_MAX },
+ { .name = "REL_MISC", .value = REL_MISC },
+ { .name = "REL_RESERVED", .value = REL_RESERVED },
+ { .name = "REL_RX", .value = REL_RX },
+ { .name = "REL_RY", .value = REL_RY },
+ { .name = "REL_RZ", .value = REL_RZ },
+ { .name = "REL_WHEEL", .value = REL_WHEEL },
+ { .name = "REL_WHEEL_HI_RES", .value = REL_WHEEL_HI_RES },
+ { .name = "REL_X", .value = REL_X },
+ { .name = "REL_Y", .value = REL_Y },
+ { .name = "REL_Z", .value = REL_Z },
+ { .name = "REP_DELAY", .value = REP_DELAY },
+ { .name = "REP_MAX", .value = REP_MAX },
+ { .name = "REP_PERIOD", .value = REP_PERIOD },
+ { .name = "SND_BELL", .value = SND_BELL },
+ { .name = "SND_CLICK", .value = SND_CLICK },
+ { .name = "SND_MAX", .value = SND_MAX },
+ { .name = "SND_TONE", .value = SND_TONE },
+ { .name = "SW_CAMERA_LENS_COVER", .value = SW_CAMERA_LENS_COVER },
+ { .name = "SW_DOCK", .value = SW_DOCK },
+ { .name = "SW_FRONT_PROXIMITY", .value = SW_FRONT_PROXIMITY },
+ { .name = "SW_HEADPHONE_INSERT", .value = SW_HEADPHONE_INSERT },
+ { .name = "SW_JACK_PHYSICAL_INSERT", .value = SW_JACK_PHYSICAL_INSERT },
+ { .name = "SW_KEYPAD_SLIDE", .value = SW_KEYPAD_SLIDE },
+ { .name = "SW_LID", .value = SW_LID },
+ { .name = "SW_LINEIN_INSERT", .value = SW_LINEIN_INSERT },
+ { .name = "SW_LINEOUT_INSERT", .value = SW_LINEOUT_INSERT },
+ { .name = "SW_MACHINE_COVER", .value = SW_MACHINE_COVER },
+ { .name = "SW_MAX", .value = SW_MAX },
+ { .name = "SW_MICROPHONE_INSERT", .value = SW_MICROPHONE_INSERT },
+ { .name = "SW_MUTE_DEVICE", .value = SW_MUTE_DEVICE },
+ { .name = "SW_PEN_INSERTED", .value = SW_PEN_INSERTED },
+ { .name = "SW_RFKILL_ALL", .value = SW_RFKILL_ALL },
+ { .name = "SW_ROTATE_LOCK", .value = SW_ROTATE_LOCK },
+ { .name = "SW_TABLET_MODE", .value = SW_TABLET_MODE },
+ { .name = "SW_VIDEOOUT_INSERT", .value = SW_VIDEOOUT_INSERT },
+ { .name = "SYN_CONFIG", .value = SYN_CONFIG },
+ { .name = "SYN_DROPPED", .value = SYN_DROPPED },
+ { .name = "SYN_MAX", .value = SYN_MAX },
+ { .name = "SYN_MT_REPORT", .value = SYN_MT_REPORT },
+ { .name = "SYN_REPORT", .value = SYN_REPORT },
+};
+
+static const struct name_entry prop_names[] = {
+ { .name = "INPUT_PROP_ACCELEROMETER", .value = INPUT_PROP_ACCELEROMETER },
+ { .name = "INPUT_PROP_BUTTONPAD", .value = INPUT_PROP_BUTTONPAD },
+ { .name = "INPUT_PROP_DIRECT", .value = INPUT_PROP_DIRECT },
+ { .name = "INPUT_PROP_MAX", .value = INPUT_PROP_MAX },
+ { .name = "INPUT_PROP_POINTER", .value = INPUT_PROP_POINTER },
+ { .name = "INPUT_PROP_POINTING_STICK", .value = INPUT_PROP_POINTING_STICK },
+ { .name = "INPUT_PROP_SEMI_MT", .value = INPUT_PROP_SEMI_MT },
+ { .name = "INPUT_PROP_TOPBUTTONPAD", .value = INPUT_PROP_TOPBUTTONPAD },
+};
+
+#endif /* EVENT_NAMES_H */
diff --git a/usr.sbin/moused/moused/moused.8 b/usr.sbin/moused/moused/moused.8
new file mode 100644
index 000000000000..96feeda336c9
--- /dev/null
+++ b/usr.sbin/moused/moused/moused.8
@@ -0,0 +1,538 @@
+.\" SPDX-License-Identifier: BSD-4-Clause
+.\"
+.\" Copyright (c) 1996 Mike Pritchard <mpp@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.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by Mike Pritchard.
+.\" 4. Neither the name of the author 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 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.
+.\"
+.Dd June 14, 2025
+.Dt MOUSED 8
+.Os
+.Sh NAME
+.Nm moused
+.Nd pass mouse data to the console driver
+.Sh SYNOPSIS
+.Nm
+.Op Fl dfg
+.Op Fl I Ar file
+.Op Fl F Ar rate
+.Op Fl r Ar resolution
+.Op Fl VH Op Fl U Ar distance Fl L Ar distance
+.Op Fl A Ar exp Ns Op , Ns Ar offset
+.Op Fl a Ar X Ns Op , Ns Ar Y
+.Op Fl C Ar threshold
+.Op Fl m Ar N=M
+.Op Fl w Ar N
+.Op Fl z Ar target
+.Op Fl t Ar mousetype
+.Op Fl l Ar level
+.Op Fl 3 Op Fl E Ar timeout
+.Op Fl T Ar distance Ns Op , Ns Ar time Ns Op , Ns Ar after
+.Fl p Ar port
+.Pp
+.Nm
+.Op Fl d
+.Fl p Ar port
+.Fl i Ar info
+.Sh DESCRIPTION
+The
+.Nm
+utility and the console driver work together to support
+mouse operation in the text console and user programs.
+They virtualize the mouse and provide user programs with mouse data
+in the standard format
+(see
+.Xr sysmouse 4 ) .
+.Pp
+The mouse daemon listens to the specified port for mouse data,
+interprets and then passes it via ioctls to the console driver.
+Supported data interfaces are
+.Qq input event device
+AKA evdev and
+.Xr sysmouse 4
+level 1.
+The mouse daemon
+reports translation movement, button press/release
+events and movement of the roller or the wheel if available.
+The roller/wheel movement is reported as
+.Dq Z
+axis movement.
+.Pp
+The console driver will display the mouse pointer on the screen
+and provide cut and paste functions if the mouse pointer is enabled
+in the virtual console via
+.Xr vidcontrol 1 .
+If
+.Xr sysmouse 4
+is opened by the user program, the console driver also passes the mouse
+data to the device so that the user program will see it.
+.Pp
+If the mouse daemon receives the signal
+.Dv SIGHUP ,
+it will reopen the mouse port and reinitialize itself.
+Useful if
+the mouse is attached/detached while the system is suspended.
+.Pp
+If the mouse daemon receives the signal
+.Dv SIGUSR1 ,
+it will stop passing mouse events.
+Sending the signal
+.Dv SIGUSR1
+again will resume passing mouse events.
+Useful if your typing on a laptop is
+interrupted by accidentally touching the mouse pad.
+.Pp
+The following options are available:
+.Bl -tag -width indent
+.It Fl 3
+Emulate the third (middle) button for 2-button mice.
+It is emulated
+by pressing the left and right physical buttons simultaneously.
+.It Fl C Ar threshold
+Set double click speed as the maximum interval in msec between button clicks.
+Without this option, the default value of 500 msec will be assumed.
+This option will have effect only on the cut and paste operations
+in the text mode console.
+The user program which is reading mouse data
+via
+.Xr sysmouse 4
+will not be affected.
+.It Fl E Ar timeout
+When the third button emulation is enabled
+(see above),
+the
+.Nm
+utility waits
+.Ar timeout
+msec at most before deciding whether two buttons are being pressed
+simultaneously.
+The default timeout is 100 msec.
+.It Fl F Ar rate
+Only for
+.Xr sysmouse 4
+interface.
+Set the report rate (reports/sec) of the device if supported.
+.It Fl L Ar distance
+When
+.Dq Virtual Scrolling
+is enabled, the
+.Fl L
+option can be used to set the
+.Ar distance
+(in pixels) that the mouse must move before a scroll event
+is generated. This effectively controls the scrolling speed.
+The default
+.Ar distance
+is 2 pixels.
+.It Fl H
+Enable
+.Dq Horizontal Virtual Scrolling .
+With this option set, holding the middle mouse
+button down will cause motion to be interpreted as
+horizontal scrolling.
+Use the
+.Fl U
+option to set the distance the mouse must move before the scrolling mode is
+activated and the
+.Fl L
+option to set the scrolling speed.
+This option may be used with or without the
+.Fl V
+option.
+.It Fl I Ar file
+Write the process id of the
+.Nm
+utility in the specified file.
+Without this option, the process id will be stored in
+.Pa /var/run/moused.pid .
+.It Fl T Ar distance Ns Op , Ns Ar time Ns Op , Ns Ar after
+Terminate drift.
+Use this option if mouse pointer slowly wanders when mouse is not moved.
+Movements up to
+.Ar distance
+(for example 4) pixels (X+Y) in
+.Ar time
+msec (default 500) are ignored, except during
+.Ar after
+msec (default 4000) since last real mouse movement.
+.It Fl V
+Enable
+.Dq Virtual Scrolling .
+With this option set, holding the middle mouse
+button down will cause motion to be interpreted as scrolling.
+Use the
+.Fl U
+option to set the distance the mouse must move before the scrolling mode is
+activated and the
+.Fl L
+option to set the scrolling speed.
+.It Fl U Ar distance
+When
+.Dq Virtual Scrolling
+is enabled, the
+.Fl U
+option can be used to set the
+.Ar distance
+(in pixels) that the mouse must move before the scrolling
+mode is activated.
+The default
+.Ar distance
+is 3 pixels.
+.It Fl A Ar exp Ns Op , Ns Ar offset
+Apply exponential (dynamic) acceleration to mouse movements:
+the faster you move the mouse, the more it will be accelerated.
+That means that small mouse movements are not accelerated,
+so they are still very accurate, while a faster movement will
+drive the pointer quickly across the screen.
+.Pp
+The
+.Ar exp
+value specifies the exponent, which is basically
+the amount of acceleration. Useful values are in the
+range 1.1 to 2.0, but it depends on your mouse hardware
+and your personal preference. A value of 1.0 means no
+exponential acceleration. A value of 2.0 means squared
+acceleration (i.e. if you move the mouse twice as fast,
+the pointer will move four times as fast on the screen).
+Values beyond 2.0 are possible but not recommended.
+A good value to start is probably 1.5.
+.Pp
+The optional
+.Ar offset
+value specifies the distance at which the acceleration
+begins. The default is 1.0, which means that the
+acceleration is applied to movements larger than one unit.
+If you specify a larger value, it takes more speed for
+the acceleration to kick in, i.e. the speed range for
+small and accurate movements is wider.
+Usually the default should be sufficient, but if you're
+not satisfied with the behaviour, try a value of 2.0.
+.Pp
+Note that the
+.Fl A
+option interacts badly with the X server's own acceleration,
+which doesn't work very well anyway. Therefore it is
+recommended to switch it off if necessary:
+.Dq xset m 1 .
+.It Fl a Ar X Ns Op , Ns Ar Y
+Accelerate or decelerate the mouse input.
+This is a linear acceleration only.
+Values less than 1.0 slow down movement, values greater than 1.0 speed it
+up.
+Specifying only one value sets the acceleration for both axes.
+.Pp
+You can use the
+.Fl a
+and
+.Fl A
+options at the same time to have the combined effect
+of linear and exponential acceleration.
+.It Fl d
+Enable debugging messages.
+.It Fl f
+Do not become a daemon and instead run as a foreground process.
+Useful for testing and debugging.
+.It Fl g
+Only for evdev interface.
+Become the sole recipient of all incoming input events.
+This prevents other processes from getting input events on the device.
+.It Fl i Ar info
+Print specified information and quit.
+Available pieces of
+information are:
+.Pp
+.Bl -tag -compact -width modelxxx
+.It Ar port
+Port (device file) name, i.e.\&
+.Pa /dev/input/event0 ,
+.Pa /dev/ums0
+and
+.Pa /dev/psm0 .
+.It Ar if
+Interface type:
+.Dq evdev
+or
+.Dq sysmouse .
+.It Ar type
+Device type:
+.Dq mouse
+or
+.Dq touchpad .
+.It Ar model
+Mouse model.
+.It Ar all
+All of the above items.
+Print port, type and model in this order
+in one line.
+.El
+.Pp
+If the
+.Nm
+utility cannot determine the requested information, it prints
+.Dq Li unknown
+or
+.Dq Li generic .
+.It Fl l Ar level
+Ignored.
+Used for compatibiliy with legacy
+.Nm .
+.It Fl m Ar N=M
+Assign the physical button
+.Ar M
+to the logical button
+.Ar N .
+You may specify as many instances of this option as you like.
+More than one physical button may be assigned to a logical button at the
+same time.
+In this case the logical button will be down,
+if either of the assigned physical buttons is held down.
+Do not put space around
+.Ql = .
+.It Fl p Ar port
+Use
+.Ar port
+to communicate with the mouse.
+.It Fl r Ar resolution
+Only for
+.Xr sysmouse 4
+interface.
+Set the resolution of the device; in Dots Per Inch, or
+.Ar low ,
+.Ar medium-low ,
+.Ar medium-high
+or
+.Ar high .
+This option may not be supported by all the device.
+.It Fl t Ar type
+Ignored.
+Used for compatibiliy with legacy
+.Nm .
+.It Fl q Ar config
+Path to configuration file.
+.It Fl Q Ar quirks
+Path to quirks directory.
+.It Fl w Ar N
+Make the physical button
+.Ar N
+act as the wheel mode button.
+While this button is pressed, X and Y axis movement is reported to be zero
+and the Y axis movement is mapped to Z axis.
+You may further map the Z axis movement to virtual buttons by the
+.Fl z
+option below.
+.It Fl z Ar target
+Map Z axis (roller/wheel) movement to another axis or to virtual buttons.
+Valid
+.Ar target
+maybe:
+.Bl -tag -compact -width x__
+.It Ar x
+.It Ar y
+X or Y axis movement will be reported when the Z axis movement is detected.
+.It Ar N
+Report down events for the virtual buttons
+.Ar N
+and
+.Ar N+1
+respectively when negative and positive Z axis movement
+is detected.
+There do not need to be physical buttons
+.Ar N
+and
+.Ar N+1 .
+Note that mapping to logical buttons is carried out after mapping
+from the Z axis movement to the virtual buttons is done.
+.It Ar N1 N2
+Report down events for the virtual buttons
+.Ar N1
+and
+.Ar N2
+respectively when negative and positive Z axis movement
+is detected.
+.It Ar N1 N2 N3 N4
+This is useful for the mouse with two wheels of which
+the second wheel is used to generate horizontal scroll action,
+and for the mouse which has a knob or a stick which can detect
+the horizontal force applied by the user.
+.Pp
+The motion of the second wheel will be mapped to the buttons
+.Ar N3 ,
+for the negative direction, and
+.Ar N4 ,
+for the positive direction.
+If the buttons
+.Ar N3
+and
+.Ar N4
+actually exist in this mouse, their actions will not be detected.
+.Pp
+Note that horizontal movement or second roller/wheel movement may not
+always be detected,
+because there appears to be no accepted standard as to how it is encoded.
+.Pp
+Note also that some mice think left is the negative horizontal direction;
+others may think otherwise.
+Moreover, there are some mice whose two wheels are both mounted vertically,
+and the direction of the second vertical wheel does not match the
+first one.
+.El
+.Ss Multiple Mice
+The
+.Nm
+utility may operate in 2 different modes depending on the value of
+.Fl p
+option.
+When started with
+.Fl p Ar auto
+option specified the
+.Nm
+handles all recognized pointing devices in a single instance.
+Device hotplug is supported through
+.Xr devd 8 .
+Only evdev interface is available in this mode.
+When started with
+.Fl p Ar <selected_port>
+option specified the
+.Nm
+handles single device located at
+.Ar <selected_port> .
+Both evdev and
+.Xr sysmouse 4
+level 1 interfaces are available in this mode.
+Multiple
+.Nm
+instances may be run simultaneously.
+.Sh FILES
+.Bl -tag -width /var/run/moused.pid -compact
+.It Pa /dev/consolectl
+device to control the console
+.It Pa /dev/input/event%d
+Input event device
+.It Pa /dev/psm%d
+PS/2 mouse driver
+.It Pa /dev/sysmouse
+virtualized mouse driver
+.It Pa /dev/ums%d
+USB mouse driver
+.It Pa /var/run/moused.pid
+process id of the currently running
+.Nm
+utility
+.El
+.Sh EXAMPLES
+.Bd -literal -offset indent
+moused -p auto
+vidcontrol -m on
+.Ed
+.Pp
+Start
+.Nm
+utility to handle all evdev pointing devices automatically with hotplug
+support.
+And enable the mouse pointer in the text console after than.
+The daemon can be started without the
+.Fl p
+option as well.
+.Pp
+.Dl "moused -f -d -g -p /dev/input/event0"
+.Ed
+.Pp
+Start the mouse daemon on the
+.Pa /dev/input/event0
+in the exclusive foreground debug mode.
+Exclusive mode may disable mouse in Xorg session.
+.Pp
+.Dl "moused -p /dev/input/event0 -m 1=3 -m 3=1"
+.Pp
+Assign the physical button 3 (right button) to the logical button 1
+(logical left) and the physical button 1 (left) to the logical
+button 3 (logical right).
+This will effectively swap the left and right buttons.
+.Pp
+.Dl "moused -p /dev/input/event0 -z 4"
+.Pp
+Report negative Z axis movement (i.e., mouse wheel) as the button 4 pressed
+and positive Z axis movement (i.e., mouse wheel) as the button 5 pressed.
+.Pp
+If you add
+.Pp
+.Dl "ALL ALL = NOPASSWD: /usr/bin/killall -USR1 moused"
+.Pp
+to your
+.Pa /usr/local/etc/sudoers
+file, and bind
+.Pp
+.Dl "killall -USR1 moused"
+.Pp
+to a key in your window manager, you can suspend mouse events on your laptop if
+you keep brushing over the mouse pad while typing.
+.Sh SEE ALSO
+.Xr moused.conf 5 ,
+.Xr kill 1 ,
+.Xr vidcontrol 1 ,
+.Xr xset 1 ,
+.Xr keyboard 4 ,
+.Xr psm 4 ,
+.Xr sysmouse 4 ,
+.Xr ums 4 ,
+.Xr devd 8
+.Sh HISTORY
+The
+.Nm
+utility first appeared in
+.Fx 2.2 .
+It was rewriten to support multiple input event devices in
+.Fx 15.0 .
+.Sh AUTHORS
+.An -nosplit
+The
+.Nm
+utility was originally written by
+.An Michael Smith Aq Mt msmith@FreeBSD.org .
+This manual page was written by
+.An Mike Pritchard Aq Mt mpp@FreeBSD.org .
+The command and manual page have since been updated by
+.An Kazutaka Yokota Aq Mt yokota@FreeBSD.org .
+Multiple input event devices support was added by
+.An Vladimir Kondratyev Aq Mt wulf@FreeBSD.org .
+.Sh CAVEATS
+Cut and paste functions in the virtual console assume that there
+are three buttons on the mouse.
+The logical button 1 (logical left) selects a region of text in the
+console and copies it to the cut buffer.
+The logical button 3 (logical right) extends the selected region.
+The logical button 2 (logical middle) pastes the selected text
+at the text cursor position.
+If the mouse has only two buttons, the middle, `paste' button
+is not available.
+To obtain the paste function, use the
+.Fl 3
+option to emulate the middle button, or use the
+.Fl m
+option to assign the physical right button to the logical middle button:
+.Dq Fl m Li 2=3 .
diff --git a/usr.sbin/moused/moused/moused.c b/usr.sbin/moused/moused/moused.c
new file mode 100644
index 000000000000..33bcf359a1a0
--- /dev/null
+++ b/usr.sbin/moused/moused/moused.c
@@ -0,0 +1,3205 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 1997-2000 Kazutaka YOKOTA <yokota@FreeBSD.org>
+ * Copyright (c) 2004-2008 Philip Paeps <philip@FreeBSD.org>
+ * Copyright (c) 2008 Jean-Sebastien Pedron <dumbbell@FreeBSD.org>
+ * Copyright (c) 2021,2024 Vladimir Kondratyev <wulf@FreeBSD.org>
+ *
+ * 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.
+ */
+
+/*
+ * MOUSED.C
+ *
+ * Mouse daemon : listens to a evdev device node for mouse data stream,
+ * interprets data and passes ioctls off to the console driver.
+ *
+ */
+
+#include <sys/param.h>
+#include <sys/consio.h>
+#include <sys/event.h>
+#include <sys/mouse.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/un.h>
+
+#include <dev/evdev/input.h>
+
+#include <bitstring.h>
+#include <ctype.h>
+#include <dirent.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <fnmatch.h>
+#include <libutil.h>
+#include <math.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#include "util.h"
+#include "quirks.h"
+
+/*
+ * bitstr_t implementation must be identical to one found in EVIOCG*
+ * libevdev ioctls. Our bitstring(3) API is compatible since r299090.
+ */
+_Static_assert(sizeof(bitstr_t) == sizeof(unsigned long),
+ "bitstr_t size mismatch");
+
+#define MAX_CLICKTHRESHOLD 2000 /* 2 seconds */
+#define MAX_BUTTON2TIMEOUT 2000 /* 2 seconds */
+#define DFLT_CLICKTHRESHOLD 500 /* 0.5 second */
+#define DFLT_BUTTON2TIMEOUT 100 /* 0.1 second */
+#define DFLT_SCROLLTHRESHOLD 3 /* 3 pixels */
+#define DFLT_SCROLLSPEED 2 /* 2 pixels */
+#define DFLT_MOUSE_RESOLUTION 8 /* dpmm, == 200dpi */
+#define DFLT_TPAD_RESOLUTION 40 /* dpmm, typical X res for Synaptics */
+#define DFLT_LINEHEIGHT 10 /* pixels per line */
+
+/* Abort 3-button emulation delay after this many movement events. */
+#define BUTTON2_MAXMOVE 3
+
+#define MOUSE_XAXIS (-1)
+#define MOUSE_YAXIS (-2)
+
+#define ZMAP_MAXBUTTON 4 /* Number of zmap items */
+#define MAX_FINGERS 10
+
+#define ID_NONE 0
+#define ID_PORT 1
+#define ID_IF 2
+#define ID_TYPE 4
+#define ID_MODEL 8
+#define ID_ALL (ID_PORT | ID_IF | ID_TYPE | ID_MODEL)
+
+/* Operations on timespecs */
+#define tsclr(tvp) timespecclear(tvp)
+#define tscmp(tvp, uvp, cmp) timespeccmp(tvp, uvp, cmp)
+#define tssub(tvp, uvp, vvp) timespecsub(tvp, uvp, vvp)
+#define msec2ts(msec) (struct timespec) { \
+ .tv_sec = (msec) / 1000, \
+ .tv_nsec = (msec) % 1000 * 1000000, \
+}
+static inline struct timespec
+tsaddms(struct timespec* tsp, u_int ms)
+{
+ struct timespec ret;
+
+ ret = msec2ts(ms);
+ timespecadd(tsp, &ret, &ret);
+
+ return (ret);
+};
+
+static inline struct timespec
+tssubms(struct timespec* tsp, u_int ms)
+{
+ struct timespec ret;
+
+ ret = msec2ts(ms);
+ timespecsub(tsp, &ret, &ret);
+
+ return (ret);
+};
+
+#define debug(...) do { \
+ if (debug && nodaemon) \
+ warnx(__VA_ARGS__); \
+} while (0)
+
+#define logerr(e, ...) do { \
+ log_or_warn(LOG_DAEMON | LOG_ERR, errno, __VA_ARGS__); \
+ exit(e); \
+} while (0)
+
+#define logerrx(e, ...) do { \
+ log_or_warn(LOG_DAEMON | LOG_ERR, 0, __VA_ARGS__); \
+ exit(e); \
+} while (0)
+
+#define logwarn(...) \
+ log_or_warn(LOG_DAEMON | LOG_WARNING, errno, __VA_ARGS__)
+
+#define logwarnx(...) \
+ log_or_warn(LOG_DAEMON | LOG_WARNING, 0, __VA_ARGS__)
+
+/* structures */
+
+enum gesture {
+ GEST_IGNORE,
+ GEST_ACCUMULATE,
+ GEST_MOVE,
+ GEST_VSCROLL,
+ GEST_HSCROLL,
+};
+
+/* interfaces (the table must be ordered by DEVICE_IF_XXX in util.h) */
+static const struct {
+ const char *name;
+ size_t p_size;
+} rifs[] = {
+ [DEVICE_IF_EVDEV] = { "evdev", sizeof(struct input_event) },
+ [DEVICE_IF_SYSMOUSE] = { "sysmouse", MOUSE_SYS_PACKETSIZE },
+};
+
+/* types (the table must be ordered by DEVICE_TYPE_XXX in util.h) */
+static const char *rnames[] = {
+ [DEVICE_TYPE_MOUSE] = "mouse",
+ [DEVICE_TYPE_POINTINGSTICK] = "pointing stick",
+ [DEVICE_TYPE_TOUCHPAD] = "touchpad",
+ [DEVICE_TYPE_TOUCHSCREEN] = "touchscreen",
+ [DEVICE_TYPE_TABLET] = "tablet",
+ [DEVICE_TYPE_TABLET_PAD] = "tablet pad",
+ [DEVICE_TYPE_KEYBOARD] = "keyboard",
+ [DEVICE_TYPE_JOYSTICK] = "joystick",
+};
+
+/* Default phisical to logical button mapping */
+static const u_int default_p2l[MOUSE_MAXBUTTON] = {
+ MOUSE_BUTTON1DOWN, MOUSE_BUTTON2DOWN, MOUSE_BUTTON3DOWN, MOUSE_BUTTON4DOWN,
+ MOUSE_BUTTON5DOWN, MOUSE_BUTTON6DOWN, MOUSE_BUTTON7DOWN, MOUSE_BUTTON8DOWN,
+ 0x00000100, 0x00000200, 0x00000400, 0x00000800,
+ 0x00001000, 0x00002000, 0x00004000, 0x00008000,
+ 0x00010000, 0x00020000, 0x00040000, 0x00080000,
+ 0x00100000, 0x00200000, 0x00400000, 0x00800000,
+ 0x01000000, 0x02000000, 0x04000000, 0x08000000,
+ 0x10000000, 0x20000000, 0x40000000,
+};
+
+struct tpcaps {
+ bool is_clickpad;
+ bool is_topbuttonpad;
+ bool is_mt;
+ bool cap_touch;
+ bool cap_pressure;
+ bool cap_width;
+ int min_x;
+ int max_x;
+ int min_y;
+ int max_y;
+ int res_x; /* dots per mm */
+ int res_y; /* dots per mm */
+ int min_p;
+ int max_p;
+};
+
+struct tpinfo {
+ bool two_finger_scroll; /* Enable two finger scrolling */
+ bool natural_scroll; /* Enable natural scrolling */
+ bool three_finger_drag; /* Enable dragging with three fingers */
+ u_int min_pressure_hi; /* Min pressure to start an action */
+ u_int min_pressure_lo; /* Min pressure to continue an action */
+ u_int max_pressure; /* Maximum pressure to detect palm */
+ u_int max_width; /* Max finger width to detect palm */
+ int margin_top; /* Top margin */
+ int margin_right; /* Right margin */
+ int margin_bottom; /* Bottom margin */
+ int margin_left; /* Left margin */
+ u_int tap_timeout; /* */
+ u_int tap_threshold; /* Minimum pressure to detect a tap */
+ double tap_max_delta; /* Length of segments above which a tap is ignored */
+ u_int taphold_timeout; /* Maximum elapsed time between two taps to consider a tap-hold action */
+ double vscroll_ver_area; /* Area reserved for vertical virtual scrolling */
+ double vscroll_hor_area; /* Area reserved for horizontal virtual scrolling */
+ double vscroll_min_delta; /* Minimum movement to consider virtual scrolling */
+ int softbuttons_y; /* Vertical size of softbuttons area */
+ int softbutton2_x; /* Horizontal offset of 2-nd softbutton left edge */
+ int softbutton3_x; /* Horizontal offset of 3-rd softbutton left edge */
+};
+
+struct tpstate {
+ int start_x;
+ int start_y;
+ int prev_x;
+ int prev_y;
+ int prev_nfingers;
+ int fingers_nb;
+ int tap_button;
+ bool fingerdown;
+ bool in_taphold;
+ int in_vscroll;
+ u_int zmax; /* maximum pressure value */
+ struct timespec taptimeout; /* tap timeout for touchpads */
+ int idletimeout;
+ bool timer_armed;
+};
+
+struct tpad {
+ struct tpcaps hw; /* touchpad capabilities */
+ struct tpinfo info; /* touchpad gesture parameters */
+ struct tpstate gest; /* touchpad gesture state */
+};
+
+struct finger {
+ int x;
+ int y;
+ int p;
+ int w;
+ int id; /* id=0 - no touch, id>1 - touch id */
+};
+
+struct evstate {
+ int buttons;
+ /* Relative */
+ int dx;
+ int dy;
+ int dz;
+ int dw;
+ int acc_dx;
+ int acc_dy;
+ /* Absolute single-touch */
+ int nfingers;
+ struct finger st;
+ /* Absolute multi-touch */
+ int slot;
+ struct finger mt[MAX_FINGERS];
+ bitstr_t bit_decl(key_ignore, KEY_CNT);
+ bitstr_t bit_decl(rel_ignore, REL_CNT);
+ bitstr_t bit_decl(abs_ignore, ABS_CNT);
+ bitstr_t bit_decl(prop_ignore, INPUT_PROP_CNT);
+};
+
+/* button status */
+struct button_state {
+ int count; /* 0: up, 1: single click, 2: double click,... */
+ struct timespec ts; /* timestamp on the last button event */
+};
+
+struct btstate {
+ u_int wmode; /* wheel mode button number */
+ u_int clickthreshold; /* double click speed in msec */
+ struct button_state bstate[MOUSE_MAXBUTTON]; /* button state */
+ struct button_state *mstate[MOUSE_MAXBUTTON];/* mapped button st.*/
+ u_int p2l[MOUSE_MAXBUTTON];/* phisical to logical button mapping */
+ int zmap[ZMAP_MAXBUTTON];/* MOUSE_{X|Y}AXIS or a button number */
+ struct button_state zstate[ZMAP_MAXBUTTON]; /* Z/W axis state */
+};
+
+/* state machine for 3 button emulation */
+
+enum bt3_emul_state {
+ S0, /* start */
+ S1, /* button 1 delayed down */
+ S2, /* button 3 delayed down */
+ S3, /* both buttons down -> button 2 down */
+ S4, /* button 1 delayed up */
+ S5, /* button 1 down */
+ S6, /* button 3 down */
+ S7, /* both buttons down */
+ S8, /* button 3 delayed up */
+ S9, /* button 1 or 3 up after S3 */
+};
+
+#define A(b1, b3) (((b1) ? 2 : 0) | ((b3) ? 1 : 0))
+#define A_TIMEOUT 4
+#define S_DELAYED(st) (states[st].s[A_TIMEOUT] != (st))
+
+static const struct {
+ enum bt3_emul_state s[A_TIMEOUT + 1];
+ int buttons;
+ int mask;
+ bool timeout;
+} states[10] = {
+ /* S0 */
+ { { S0, S2, S1, S3, S0 }, 0, ~(MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN), false },
+ /* S1 */
+ { { S4, S2, S1, S3, S5 }, 0, ~MOUSE_BUTTON1DOWN, false },
+ /* S2 */
+ { { S8, S2, S1, S3, S6 }, 0, ~MOUSE_BUTTON3DOWN, false },
+ /* S3 */
+ { { S0, S9, S9, S3, S3 }, MOUSE_BUTTON2DOWN, ~0, false },
+ /* S4 */
+ { { S0, S2, S1, S3, S0 }, MOUSE_BUTTON1DOWN, ~0, true },
+ /* S5 */
+ { { S0, S2, S5, S7, S5 }, MOUSE_BUTTON1DOWN, ~0, false },
+ /* S6 */
+ { { S0, S6, S1, S7, S6 }, MOUSE_BUTTON3DOWN, ~0, false },
+ /* S7 */
+ { { S0, S6, S5, S7, S7 }, MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN, ~0, false },
+ /* S8 */
+ { { S0, S2, S1, S3, S0 }, MOUSE_BUTTON3DOWN, ~0, true },
+ /* S9 */
+ { { S0, S9, S9, S3, S9 }, 0, ~(MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN), false },
+};
+
+struct e3bstate {
+ bool enabled;
+ u_int button2timeout; /* 3 button emulation timeout */
+ enum bt3_emul_state mouse_button_state;
+ struct timespec mouse_button_state_ts;
+ int mouse_move_delayed;
+ bool timer_armed;
+};
+
+enum scroll_state {
+ SCROLL_NOTSCROLLING,
+ SCROLL_PREPARE,
+ SCROLL_SCROLLING,
+};
+
+struct scroll {
+ bool enable_vert;
+ bool enable_hor;
+ u_int threshold; /* Movement distance before virtual scrolling */
+ u_int speed; /* Movement distance to rate of scrolling */
+ enum scroll_state state;
+ int movement;
+ int hmovement;
+};
+
+struct drift_xy {
+ int x;
+ int y;
+};
+struct drift {
+ u_int distance; /* max steps X+Y */
+ u_int time; /* ms */
+ struct timespec time_ts;
+ struct timespec twotime_ts; /* 2*drift_time */
+ u_int after; /* ms */
+ struct timespec after_ts;
+ bool terminate;
+ struct timespec current_ts;
+ struct timespec last_activity;
+ struct timespec since;
+ struct drift_xy last; /* steps in last drift_time */
+ struct drift_xy previous; /* steps in prev. drift_time */
+};
+
+struct accel {
+ bool is_exponential; /* Exponential acceleration is enabled */
+ double accelx; /* Acceleration in the X axis */
+ double accely; /* Acceleration in the Y axis */
+ double accelz; /* Acceleration in the wheel axis */
+ double expoaccel; /* Exponential acceleration */
+ double expoffset; /* Movement offset for exponential accel. */
+ double remainx; /* Remainder on X, Y and wheel axis, ... */
+ double remainy; /* ... respectively to compensate */
+ double remainz; /* ... for rounding errors. */
+ double lastlength[3];
+};
+
+struct rodent {
+ struct device dev; /* Device */
+ int mfd; /* mouse file descriptor */
+ struct btstate btstate; /* button status */
+ struct e3bstate e3b; /* 3 button emulation state */
+ struct drift drift;
+ struct accel accel; /* cursor acceleration state */
+ struct scroll scroll; /* virtual scroll state */
+ struct tpad tp; /* touchpad info and gesture state */
+ struct evstate ev; /* event device state */
+ SLIST_ENTRY(rodent) next;
+};
+
+/* global variables */
+
+static SLIST_HEAD(rodent_list, rodent) rodents = SLIST_HEAD_INITIALIZER();
+
+static int debug = 0;
+static bool nodaemon = false;
+static bool background = false;
+static bool paused = false;
+static bool opt_grab = false;
+static int identify = ID_NONE;
+static int cfd = -1; /* /dev/consolectl file descriptor */
+static int kfd = -1; /* kqueue file descriptor */
+static int dfd = -1; /* devd socket descriptor */
+static const char *portname = NULL;
+static const char *pidfile = "/var/run/moused.pid";
+static struct pidfh *pfh;
+#ifndef CONFDIR
+#define CONFDIR "/etc"
+#endif
+static const char *config_file = CONFDIR "/moused.conf";
+#ifndef QUIRKSDIR
+#define QUIRKSDIR "/usr/share/moused"
+#endif
+static const char *quirks_path = QUIRKSDIR;
+static struct quirks_context *quirks;
+
+static int opt_rate = 0;
+static int opt_resolution = MOUSE_RES_UNKNOWN;
+
+static u_int opt_wmode = 0;
+static int opt_clickthreshold = -1;
+static bool opt_e3b_enabled = false;
+static int opt_e3b_button2timeout = -1;
+static struct btstate opt_btstate;
+
+static bool opt_drift_terminate = false;
+static u_int opt_drift_distance = 4; /* max steps X+Y */
+static u_int opt_drift_time = 500; /* ms */
+static u_int opt_drift_after = 4000; /* ms */
+
+static double opt_accelx = 1.0;
+static double opt_accely = 1.0;
+static bool opt_exp_accel = false;
+static double opt_expoaccel = 1.0;
+static double opt_expoffset = 1.0;
+
+static bool opt_virtual_scroll = false;
+static bool opt_hvirtual_scroll = false;
+static int opt_scroll_speed = -1;
+static int opt_scroll_threshold = -1;
+
+static jmp_buf env;
+
+/* function prototypes */
+
+static moused_log_handler log_or_warn_va;
+
+static void linacc(struct accel *, int, int, int, int*, int*, int*);
+static void expoacc(struct accel *, int, int, int, int*, int*, int*);
+static void moused(void);
+static void reset(int sig);
+static void pause_mouse(int sig);
+static int connect_devd(void);
+static void fetch_and_parse_devd(void);
+static void usage(void);
+static void log_or_warn(int log_pri, int errnum, const char *fmt, ...)
+ __printflike(3, 4);
+
+static int r_daemon(void);
+static enum device_if r_identify_if(int fd);
+static enum device_type r_identify_evdev(int fd);
+static enum device_type r_identify_sysmouse(int fd);
+static const char *r_if(enum device_if type);
+static const char *r_name(enum device_type type);
+static struct rodent *r_init(const char *path);
+static void r_init_all(void);
+static void r_deinit(struct rodent *r);
+static void r_deinit_all(void);
+static int r_protocol_evdev(enum device_type type, struct tpad *tp,
+ struct evstate *ev, struct input_event *ie,
+ mousestatus_t *act);
+static int r_protocol_sysmouse(uint8_t *pBuf, mousestatus_t *act);
+static void r_vscroll_detect(struct rodent *r, struct scroll *sc,
+ mousestatus_t *act);
+static void r_vscroll(struct scroll *sc, mousestatus_t *act);
+static int r_statetrans(struct rodent *r, mousestatus_t *a1,
+ mousestatus_t *a2, int trans);
+static bool r_installmap(char *arg, struct btstate *bt);
+static char * r_installzmap(char **argv, int argc, int* idx, struct btstate *bt);
+static void r_map(mousestatus_t *act1, mousestatus_t *act2,
+ struct btstate *bt);
+static void r_timestamp(mousestatus_t *act, struct btstate *bt,
+ struct e3bstate *e3b, struct drift *drift);
+static bool r_timeout(struct e3bstate *e3b);
+static void r_move(mousestatus_t *act, struct accel *acc);
+static void r_click(mousestatus_t *act, struct btstate *bt);
+static bool r_drift(struct drift *, mousestatus_t *);
+static enum gesture r_gestures(struct tpad *tp, int x0, int y0, u_int z, int w,
+ int nfingers, struct timespec *time, mousestatus_t *ms);
+
+int
+main(int argc, char *argv[])
+{
+ struct rodent *r;
+ pid_t mpid;
+ int c;
+ int i;
+ u_long ul;
+ char *errstr;
+
+ while ((c = getopt(argc, argv, "3A:C:E:F:HI:L:T:VU:a:dfghi:l:m:p:r:t:q:w:z:")) != -1) {
+ switch(c) {
+
+ case '3':
+ opt_e3b_enabled = true;
+ break;
+
+ case 'E':
+ errno = 0;
+ ul = strtoul(optarg, NULL, 10);
+ if ((ul == 0 && errno != 0) ||
+ ul > MAX_BUTTON2TIMEOUT) {
+ warnx("invalid argument `%s'", optarg);
+ usage();
+ }
+ opt_e3b_button2timeout = ul;
+ break;
+
+ case 'a':
+ i = sscanf(optarg, "%lf,%lf", &opt_accelx, &opt_accely);
+ if (i == 0) {
+ warnx("invalid linear acceleration argument "
+ "'%s'", optarg);
+ usage();
+ }
+ if (i == 1)
+ opt_accely = opt_accelx;
+ break;
+
+ case 'A':
+ opt_exp_accel = true;
+ i = sscanf(optarg, "%lf,%lf", &opt_expoaccel,
+ &opt_expoffset);
+ if (i == 0) {
+ warnx("invalid exponential acceleration "
+ "argument '%s'", optarg);
+ usage();
+ }
+ if (i == 1)
+ opt_expoffset = 1.0;
+ break;
+
+ case 'd':
+ ++debug;
+ break;
+
+ case 'f':
+ nodaemon = true;
+ break;
+
+ case 'g':
+ opt_grab = true;
+ break;
+
+ case 'i':
+ if (strcmp(optarg, "all") == 0)
+ identify = ID_ALL;
+ else if (strcmp(optarg, "port") == 0)
+ identify = ID_PORT;
+ else if (strcmp(optarg, "if") == 0)
+ identify = ID_IF;
+ else if (strcmp(optarg, "type") == 0)
+ identify = ID_TYPE;
+ else if (strcmp(optarg, "model") == 0)
+ identify = ID_MODEL;
+ else {
+ warnx("invalid argument `%s'", optarg);
+ usage();
+ }
+ nodaemon = true;
+ break;
+
+ case 'l':
+ ul = strtoul(optarg, NULL, 10);
+ if (ul != 1)
+ warnx("ignore mouse level `%s'", optarg);
+ break;
+
+ case 'm':
+ if (!r_installmap(optarg, &opt_btstate)) {
+ warnx("invalid argument `%s'", optarg);
+ usage();
+ }
+ break;
+
+ case 'p':
+ /* "auto" is an alias to no portname */
+ if (strcmp(optarg, "auto") != 0)
+ portname = optarg;
+ break;
+
+ case 'r':
+ if (strcmp(optarg, "high") == 0)
+ opt_resolution = MOUSE_RES_HIGH;
+ else if (strcmp(optarg, "medium-high") == 0)
+ opt_resolution = MOUSE_RES_HIGH;
+ else if (strcmp(optarg, "medium-low") == 0)
+ opt_resolution = MOUSE_RES_MEDIUMLOW;
+ else if (strcmp(optarg, "low") == 0)
+ opt_resolution = MOUSE_RES_LOW;
+ else if (strcmp(optarg, "default") == 0)
+ opt_resolution = MOUSE_RES_DEFAULT;
+ else {
+ ul= strtoul(optarg, NULL, 10);
+ if (ul == 0) {
+ warnx("invalid argument `%s'", optarg);
+ usage();
+ }
+ opt_resolution = ul;
+ }
+ break;
+
+ case 't':
+ if (strcmp(optarg, "auto") != 0)
+ warnx("ignore mouse type `%s'", optarg);
+ break;
+
+ case 'w':
+ ul = strtoul(optarg, NULL, 10);
+ if (ul == 0 || ul > MOUSE_MAXBUTTON) {
+ warnx("invalid argument `%s'", optarg);
+ usage();
+ }
+ opt_wmode = ul;
+ break;
+
+ case 'z':
+ --optind;
+ errstr = r_installzmap(argv, argc, &optind, &opt_btstate);
+ if (errstr != NULL) {
+ warnx("%s", errstr);
+ free(errstr);
+ usage();
+ }
+ break;
+
+ case 'C':
+ ul = strtoul(optarg, NULL, 10);
+ if (ul > MAX_CLICKTHRESHOLD) {
+ warnx("invalid argument `%s'", optarg);
+ usage();
+ }
+ opt_clickthreshold = ul;
+ break;
+
+ case 'F':
+ ul = strtoul(optarg, NULL, 10);
+ if (ul == 0) {
+ warnx("invalid argument `%s'", optarg);
+ usage();
+ }
+ opt_rate = ul;
+ break;
+
+ case 'H':
+ opt_hvirtual_scroll = true;
+ break;
+
+ case 'I':
+ pidfile = optarg;
+ break;
+
+ case 'L':
+ errno = 0;
+ ul = strtoul(optarg, NULL, 10);
+ if ((ul == 0 && errno != 0) || ul > INT_MAX) {
+ warnx("invalid argument `%s'", optarg);
+ usage();
+ }
+ opt_scroll_speed = ul;
+ break;
+
+ case 'q':
+ config_file = optarg;
+ break;
+
+ case 'Q':
+ quirks_path = optarg;
+ break;
+
+ case 'T':
+ opt_drift_terminate = true;
+ sscanf(optarg, "%u,%u,%u", &opt_drift_distance,
+ &opt_drift_time, &opt_drift_after);
+ if (opt_drift_distance == 0 ||
+ opt_drift_time == 0 ||
+ opt_drift_after == 0) {
+ warnx("invalid argument `%s'", optarg);
+ usage();
+ }
+ break;
+
+ case 'V':
+ opt_virtual_scroll = true;
+ break;
+
+ case 'U':
+ errno = 0;
+ ul = strtoul(optarg, NULL, 10);
+ if ((ul == 0 && errno != 0) || ul > INT_MAX) {
+ warnx("invalid argument `%s'", optarg);
+ usage();
+ }
+ opt_scroll_threshold = ul;
+ break;
+
+ case 'h':
+ case '?':
+ default:
+ usage();
+ }
+ }
+
+ if ((cfd = open("/dev/consolectl", O_RDWR, 0)) == -1)
+ logerr(1, "cannot open /dev/consolectl");
+ if ((kfd = kqueue()) == -1)
+ logerr(1, "cannot create kqueue");
+ if (portname == NULL && (dfd = connect_devd()) == -1)
+ logwarnx("cannot open devd socket");
+
+ switch (setjmp(env)) {
+ case SIGHUP:
+ quirks_context_unref(quirks);
+ r_deinit_all();
+ /* FALLTHROUGH */
+ case 0:
+ break;
+ case SIGINT:
+ case SIGQUIT:
+ case SIGTERM:
+ exit(0);
+ /* NOT REACHED */
+ default:
+ goto out;
+ }
+
+ signal(SIGHUP , reset);
+ signal(SIGINT , reset);
+ signal(SIGQUIT, reset);
+ signal(SIGTERM, reset);
+ signal(SIGUSR1, pause_mouse);
+
+ quirks = quirks_init_subsystem(quirks_path, config_file,
+ log_or_warn_va,
+ background ? QLOG_MOUSED_LOGGING : QLOG_CUSTOM_LOG_PRIORITIES);
+ if (quirks == NULL)
+ logwarnx("cannot open configuration file %s", config_file);
+
+ if (portname == NULL) {
+ r_init_all();
+ } else {
+ if ((r = r_init(portname)) == NULL)
+ logerrx(1, "Can not initialize device");
+ }
+
+ /* print some information */
+ if (identify != ID_NONE) {
+ SLIST_FOREACH(r, &rodents, next) {
+ if (identify == ID_ALL)
+ printf("%s %s %s %s\n",
+ r->dev.path, r_if(r->dev.iftype),
+ r_name(r->dev.type), r->dev.name);
+ else if (identify & ID_PORT)
+ printf("%s\n", r->dev.path);
+ else if (identify & ID_IF)
+ printf("%s\n", r_if(r->dev.iftype));
+ else if (identify & ID_TYPE)
+ printf("%s\n", r_name(r->dev.type));
+ else if (identify & ID_MODEL)
+ printf("%s\n", r->dev.name);
+ }
+ exit(0);
+ }
+
+ if (!nodaemon && !background) {
+ pfh = pidfile_open(pidfile, 0600, &mpid);
+ if (pfh == NULL) {
+ if (errno == EEXIST)
+ logerrx(1, "moused already running, pid: %d", mpid);
+ logwarn("cannot open pid file");
+ }
+ if (r_daemon()) {
+ int saved_errno = errno;
+ pidfile_remove(pfh);
+ errno = saved_errno;
+ logerr(1, "failed to become a daemon");
+ } else {
+ background = true;
+ pidfile_write(pfh);
+ }
+ }
+
+ moused();
+
+out:
+ quirks_context_unref(quirks);
+
+ r_deinit_all();
+ if (dfd != -1)
+ close(dfd);
+ if (kfd != -1)
+ close(kfd);
+ if (cfd != -1)
+ close(cfd);
+
+ exit(0);
+}
+
+/*
+ * Function to calculate linear acceleration.
+ *
+ * If there are any rounding errors, the remainder
+ * is stored in the remainx and remainy variables
+ * and taken into account upon the next movement.
+ */
+
+static void
+linacc(struct accel *acc, int dx, int dy, int dz,
+ int *movex, int *movey, int *movez)
+{
+ double fdx, fdy, fdz;
+
+ if (dx == 0 && dy == 0 && dz == 0) {
+ *movex = *movey = *movez = 0;
+ return;
+ }
+ fdx = dx * acc->accelx + acc->remainx;
+ fdy = dy * acc->accely + acc->remainy;
+ fdz = dz * acc->accelz + acc->remainz;
+ *movex = lround(fdx);
+ *movey = lround(fdy);
+ *movez = lround(fdz);
+ acc->remainx = fdx - *movex;
+ acc->remainy = fdy - *movey;
+ acc->remainz = fdz - *movez;
+}
+
+/*
+ * Function to calculate exponential acceleration.
+ * (Also includes linear acceleration if enabled.)
+ *
+ * In order to give a smoother behaviour, we record the four
+ * most recent non-zero movements and use their average value
+ * to calculate the acceleration.
+ */
+
+static void
+expoacc(struct accel *acc, int dx, int dy, int dz,
+ int *movex, int *movey, int *movez)
+{
+ double fdx, fdy, fdz, length, lbase, accel;
+
+ if (dx == 0 && dy == 0 && dz == 0) {
+ *movex = *movey = *movez = 0;
+ return;
+ }
+ fdx = dx * acc->accelx;
+ fdy = dy * acc->accely;
+ fdz = dz * acc->accelz;
+ length = sqrt((fdx * fdx) + (fdy * fdy)); /* Pythagoras */
+ length = (length + acc->lastlength[0] + acc->lastlength[1] +
+ acc->lastlength[2]) / 4;
+ lbase = length / acc->expoffset;
+ accel = pow(lbase, acc->expoaccel) / lbase;
+ fdx = fdx * accel + acc->remainx;
+ fdy = fdy * accel + acc->remainy;
+ *movex = lround(fdx);
+ *movey = lround(fdy);
+ *movez = lround(fdz);
+ acc->remainx = fdx - *movex;
+ acc->remainy = fdy - *movey;
+ acc->remainz = fdz - *movez;
+ acc->lastlength[2] = acc->lastlength[1];
+ acc->lastlength[1] = acc->lastlength[0];
+ /* Insert new average, not original length! */
+ acc->lastlength[0] = length;
+}
+
+static void
+moused(void)
+{
+ struct rodent *r = NULL;
+ mousestatus_t action0; /* original mouse action */
+ mousestatus_t action; /* interim buffer */
+ mousestatus_t action2; /* mapped action */
+ struct kevent ke[3];
+ int nchanges;
+ union {
+ struct input_event ie;
+ uint8_t se[MOUSE_SYS_PACKETSIZE];
+ } b;
+ size_t b_size;
+ ssize_t r_size;
+ int flags;
+ int c;
+
+ /* clear mouse data */
+ bzero(&action0, sizeof(action0));
+ bzero(&action, sizeof(action));
+ bzero(&action2, sizeof(action2));
+ /* process mouse data */
+ for (;;) {
+
+ if (dfd == -1 && portname == NULL)
+ dfd = connect_devd();
+ nchanges = 0;
+ if (r != NULL && r->e3b.enabled &&
+ S_DELAYED(r->e3b.mouse_button_state)) {
+ EV_SET(ke + nchanges, r->mfd << 1, EVFILT_TIMER,
+ EV_ADD | EV_ENABLE | EV_DISPATCH, 0, 20, r);
+ nchanges++;
+ r->e3b.timer_armed = true;
+ }
+ if (r != NULL && r->tp.gest.idletimeout > 0) {
+ EV_SET(ke + nchanges, r->mfd << 1 | 1, EVFILT_TIMER,
+ EV_ADD | EV_ENABLE | EV_DISPATCH,
+ 0, r->tp.gest.idletimeout, r);
+ nchanges++;
+ r->tp.gest.timer_armed = true;
+ }
+ if (dfd == -1 && nchanges == 0 && portname == NULL) {
+ EV_SET(ke + nchanges, UINTPTR_MAX, EVFILT_TIMER,
+ EV_ADD | EV_ENABLE | EV_ONESHOT, 0, 1000, NULL);
+ nchanges++;
+ }
+
+ if (!(r != NULL && r->tp.gest.idletimeout == 0)) {
+ c = kevent(kfd, ke, nchanges, ke, 1, NULL);
+ if (c <= 0) { /* error */
+ logwarn("failed to read from mouse");
+ continue;
+ }
+ } else
+ c = 0;
+ /* Devd event */
+ if (c > 0 && ke[0].udata == NULL) {
+ if (ke[0].filter == EVFILT_READ) {
+ if ((ke[0].flags & EV_EOF) != 0) {
+ logwarn("devd connection is closed");
+ close(dfd);
+ dfd = -1;
+ } else
+ fetch_and_parse_devd();
+ } else if (ke[0].filter == EVFILT_TIMER) {
+ /* DO NOTHING */
+ }
+ continue;
+ }
+ if (c > 0)
+ r = ke[0].udata;
+ /* E3B timeout */
+ if (c > 0 && ke[0].filter == EVFILT_TIMER &&
+ (ke[0].ident & 1) == 0) {
+ /* assert(rodent.flags & Emulate3Button) */
+ action0.button = action0.obutton;
+ action0.dx = action0.dy = action0.dz = 0;
+ action0.flags = flags = 0;
+ r->e3b.timer_armed = false;
+ if (r_timeout(&r->e3b) &&
+ r_statetrans(r, &action0, &action, A_TIMEOUT)) {
+ if (debug > 2)
+ debug("flags:%08x buttons:%08x obuttons:%08x",
+ action.flags, action.button, action.obutton);
+ } else {
+ action0.obutton = action0.button;
+ continue;
+ }
+ } else {
+ /* mouse movement */
+ if (c > 0 && ke[0].filter == EVFILT_READ) {
+ b_size = rifs[r->dev.iftype].p_size;
+ r_size = read(r->mfd, &b, b_size);
+ if (r_size == -1) {
+ if (errno == EWOULDBLOCK)
+ continue;
+ else if (portname == NULL) {
+ r_deinit(r);
+ r = NULL;
+ continue;
+ } else
+ return;
+ }
+ if (r_size != (ssize_t)b_size) {
+ logwarn("Short read from mouse: "
+ "%zd bytes", r_size);
+ continue;
+ }
+ /* Disarm nonexpired timers */
+ nchanges = 0;
+ if (r->e3b.timer_armed) {
+ EV_SET(ke + nchanges, r->mfd << 1,
+ EVFILT_TIMER, EV_DISABLE, 0, 0, r);
+ nchanges++;
+ r->e3b.timer_armed = false;
+ }
+ if (r->tp.gest.timer_armed) {
+ EV_SET(ke + nchanges, r->mfd << 1 | 1,
+ EVFILT_TIMER, EV_DISABLE, 0, 0, r);
+ nchanges++;
+ r->tp.gest.timer_armed = false;
+ }
+ if (nchanges != 0)
+ kevent(kfd, ke, nchanges, NULL, 0, NULL);
+ } else {
+ /*
+ * Gesture timeout expired.
+ * Notify r_gestures by empty packet.
+ */
+#ifdef DONE_RIGHT
+ struct timespec ts;
+ clock_gettime(CLOCK_REALTIME, &ts);
+ b.ie.time.tv_sec = ts.tv_sec;
+ b.ie.time.tv_usec = ts.tv_nsec / 1000;
+#else
+ /* Hacky but cheap */
+ b.ie.time.tv_sec =
+ r->tp.gest.idletimeout == 0 ? 0 : LONG_MAX;
+ b.ie.time.tv_usec = 0;
+#endif
+ b.ie.type = EV_SYN;
+ b.ie.code = SYN_REPORT;
+ b.ie.value = 1;
+ if (c > 0)
+ r->tp.gest.timer_armed = false;
+ }
+ r->tp.gest.idletimeout = -1;
+ flags = r->dev.iftype == DEVICE_IF_EVDEV ?
+ r_protocol_evdev(r->dev.type,
+ &r->tp, &r->ev, &b.ie, &action0) :
+ r_protocol_sysmouse(b.se, &action0);
+ if (flags == 0)
+ continue;
+
+ if (r->scroll.enable_vert || r->scroll.enable_hor) {
+ if (action0.button == MOUSE_BUTTON2DOWN) {
+ debug("[BUTTON2] flags:%08x buttons:%08x obuttons:%08x",
+ action.flags, action.button, action.obutton);
+ } else {
+ debug("[NOTBUTTON2] flags:%08x buttons:%08x obuttons:%08x",
+ action.flags, action.button, action.obutton);
+ }
+ r_vscroll_detect(r, &r->scroll, &action0);
+ }
+
+ r_timestamp(&action0, &r->btstate, &r->e3b, &r->drift);
+ r_statetrans(r, &action0, &action,
+ A(action0.button & MOUSE_BUTTON1DOWN,
+ action0.button & MOUSE_BUTTON3DOWN));
+ debug("flags:%08x buttons:%08x obuttons:%08x", action.flags,
+ action.button, action.obutton);
+ }
+ action0.obutton = action0.button;
+ flags &= MOUSE_POSCHANGED;
+ flags |= action.obutton ^ action.button;
+ action.flags = flags;
+
+ if (flags == 0)
+ continue;
+
+ /* handler detected action */
+ r_map(&action, &action2, &r->btstate);
+ debug("activity : buttons 0x%08x dx %d dy %d dz %d",
+ action2.button, action2.dx, action2.dy, action2.dz);
+
+ if (r->scroll.enable_vert || r->scroll.enable_hor) {
+ /*
+ * If *only* the middle button is pressed AND we are moving
+ * the stick/trackpoint/nipple, scroll!
+ */
+ r_vscroll(&r->scroll, &action2);
+ }
+
+ if (r->drift.terminate) {
+ if ((flags & MOUSE_POSCHANGED) == 0 ||
+ action.dz || action2.dz)
+ r->drift.last_activity = r->drift.current_ts;
+ else {
+ if (r_drift (&r->drift, &action2))
+ continue;
+ }
+ }
+
+ /* Defer clicks until we aren't VirtualScroll'ing. */
+ if (r->scroll.state == SCROLL_NOTSCROLLING)
+ r_click(&action2, &r->btstate);
+
+ if (action2.flags & MOUSE_POSCHANGED)
+ r_move(&action2, &r->accel);
+
+ /*
+ * If the Z axis movement is mapped to an imaginary physical
+ * button, we need to cook up a corresponding button `up' event
+ * after sending a button `down' event.
+ */
+ if ((r->btstate.zmap[0] > 0) && (action.dz != 0)) {
+ action.obutton = action.button;
+ action.dx = action.dy = action.dz = 0;
+ r_map(&action, &action2, &r->btstate);
+ debug("activity : buttons 0x%08x dx %d dy %d dz %d",
+ action2.button, action2.dx, action2.dy, action2.dz);
+
+ r_click(&action2, &r->btstate);
+ }
+ }
+ /* NOT REACHED */
+}
+
+static void
+reset(int sig)
+{
+ longjmp(env, sig);
+}
+
+static void
+pause_mouse(__unused int sig)
+{
+ paused = !paused;
+}
+
+static int
+connect_devd(void)
+{
+ const static struct sockaddr_un sa = {
+ .sun_family = AF_UNIX,
+ .sun_path = "/var/run/devd.seqpacket.pipe",
+ };
+ struct kevent kev;
+ int fd;
+
+ fd = socket(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0);
+ if (fd < 0)
+ return (-1);
+ if (connect(fd, (const struct sockaddr *) &sa, sizeof(sa)) < 0) {
+ close(fd);
+ return (-1);
+ }
+ EV_SET(&kev, fd, EVFILT_READ, EV_ADD, 0, 0, 0);
+ if (kevent(kfd, &kev, 1, NULL, 0, NULL) < 0) {
+ close(fd);
+ return (-1);
+ }
+
+ return (fd);
+}
+
+static void
+fetch_and_parse_devd(void)
+{
+ char ev[1024];
+ char path[22] = "/dev/";
+ char *cdev, *cr;
+ ssize_t len;
+
+ if ((len = recv(dfd, ev, sizeof(ev), MSG_WAITALL)) <= 0) {
+ close(dfd);
+ dfd = -1;
+ return;
+ }
+
+ if (ev[0] != '!')
+ return;
+ if (strnstr(ev, "system=DEVFS", len) == NULL)
+ return;
+ if (strnstr(ev, "subsystem=CDEV", len) == NULL)
+ return;
+ if (strnstr(ev, "type=CREATE", len) == NULL)
+ return;
+ if ((cdev = strnstr(ev, "cdev=input/event", len)) == NULL)
+ return;
+ cr = strchr(cdev, '\n');
+ if (cr != NULL)
+ *cr = '\0';
+ cr = strchr(cdev, ' ');
+ if (cr != NULL)
+ *cr = '\0';
+ strncpy(path + 5, cdev + 5, 17);
+ (void)r_init(path);
+ return;
+}
+
+/*
+ * usage
+ *
+ * Complain, and free the CPU for more worthy tasks
+ */
+static void
+usage(void)
+{
+ fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n",
+ "usage: moused [-dfg] [-I file] [-F rate] [-r resolution]",
+ " [-VH [-U threshold]] [-a X[,Y]] [-C threshold] [-m N=M] [-w N]",
+ " [-z N] [-t <mousetype>] [-l level] [-3 [-E timeout]]",
+ " [-T distance[,time[,after]]] -p <port> [-q config] [-Q quirks]",
+ " moused [-d] -i <port|if|type|model|all> -p <port>");
+ exit(1);
+}
+
+/*
+ * Output an error message to syslog or stderr as appropriate. If
+ * `errnum' is non-zero, append its string form to the message.
+ */
+static void
+log_or_warn_va(int log_pri, int errnum, const char *fmt, va_list ap)
+{
+ char buf[256];
+ size_t len;
+
+ if (debug == 0 && log_pri > LOG_ERR)
+ return;
+
+ vsnprintf(buf, sizeof(buf), fmt, ap);
+
+ /* Strip trailing line-feed appended by quirk subsystem */
+ len = strlen(buf);
+ if (len != 0 && buf[len - 1] == '\n')
+ buf[len - 1] = '\0';
+
+ if (errnum) {
+ strlcat(buf, ": ", sizeof(buf));
+ strlcat(buf, strerror(errnum), sizeof(buf));
+ }
+
+ if (background)
+ syslog(log_pri, "%s", buf);
+ else
+ warnx("%s", buf);
+}
+
+static void
+log_or_warn(int log_pri, int errnum, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ log_or_warn_va(log_pri, errnum, fmt, ap);
+ va_end(ap);
+}
+
+static int
+r_daemon(void)
+{
+ struct sigaction osa, sa;
+ pid_t newgrp;
+ int oerrno;
+ int osa_ok;
+ int nullfd;
+
+ /* A SIGHUP may be thrown when the parent exits below. */
+ sigemptyset(&sa.sa_mask);
+ sa.sa_handler = SIG_IGN;
+ sa.sa_flags = 0;
+ osa_ok = sigaction(SIGHUP, &sa, &osa);
+
+ /* Keep kqueue fd alive */
+ switch (rfork(RFPROC)) {
+ case -1:
+ return (-1);
+ case 0:
+ break;
+ default:
+ /*
+ * A fine point: _exit(0), not exit(0), to avoid triggering
+ * atexit(3) processing
+ */
+ _exit(0);
+ }
+
+ newgrp = setsid();
+ oerrno = errno;
+ if (osa_ok != -1)
+ sigaction(SIGHUP, &osa, NULL);
+
+ if (newgrp == -1) {
+ errno = oerrno;
+ return (-1);
+ }
+
+ (void)chdir("/");
+
+ nullfd = open("/dev/null", O_RDWR, 0);
+ if (nullfd != -1) {
+ (void)dup2(nullfd, STDIN_FILENO);
+ (void)dup2(nullfd, STDOUT_FILENO);
+ (void)dup2(nullfd, STDERR_FILENO);
+ }
+ if (nullfd > 2)
+ close(nullfd);
+
+ return (0);
+}
+
+static inline int
+bit_find(bitstr_t *array, int start, int stop)
+{
+ int res;
+
+ bit_ffs_at(array, start, stop + 1, &res);
+ return (res != -1);
+}
+
+static enum device_if
+r_identify_if(int fd)
+{
+ int dummy;
+
+ if (ioctl(fd, EVIOCGVERSION, &dummy) >= 0)
+ return (DEVICE_IF_EVDEV);
+ if (ioctl(fd, MOUSE_GETLEVEL, &dummy) >= 0)
+ return (DEVICE_IF_SYSMOUSE);
+ return (DEVICE_IF_UNKNOWN);
+}
+
+/* Derived from EvdevProbe() function of xf86-input-evdev driver */
+static enum device_type
+r_identify_evdev(int fd)
+{
+ enum device_type type;
+ bitstr_t bit_decl(key_bits, KEY_CNT); /* */
+ bitstr_t bit_decl(rel_bits, REL_CNT); /* Evdev capabilities */
+ bitstr_t bit_decl(abs_bits, ABS_CNT); /* */
+ bitstr_t bit_decl(prop_bits, INPUT_PROP_CNT);
+ bool has_keys, has_buttons, has_lmr, has_rel_axes, has_abs_axes;
+ bool has_mt;
+
+ /* maybe this is a evdev mouse... */
+ if (ioctl(fd, EVIOCGBIT(EV_REL, sizeof(rel_bits)), rel_bits) < 0 ||
+ ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(abs_bits)), abs_bits) < 0 ||
+ ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(key_bits)), key_bits) < 0 ||
+ ioctl(fd, EVIOCGPROP(sizeof(prop_bits)), prop_bits) < 0) {
+ return (DEVICE_TYPE_UNKNOWN);
+ }
+
+ has_keys = bit_find(key_bits, 0, BTN_MISC - 1);
+ has_buttons = bit_find(key_bits, BTN_MISC, BTN_JOYSTICK - 1);
+ has_lmr = bit_find(key_bits, BTN_LEFT, BTN_MIDDLE);
+ has_rel_axes = bit_find(rel_bits, 0, REL_MAX);
+ has_abs_axes = bit_find(abs_bits, 0, ABS_MAX);
+ has_mt = bit_find(abs_bits, ABS_MT_SLOT, ABS_MAX);
+ type = DEVICE_TYPE_UNKNOWN;
+
+ if (has_abs_axes) {
+ if (has_mt && !has_buttons) {
+ /* TBD:Improve joystick detection */
+ if (bit_test(key_bits, BTN_JOYSTICK)) {
+ return (DEVICE_TYPE_JOYSTICK);
+ } else {
+ has_buttons = true;
+ }
+ }
+
+ if (bit_test(abs_bits, ABS_X) &&
+ bit_test(abs_bits, ABS_Y)) {
+ if (bit_test(key_bits, BTN_TOOL_PEN) ||
+ bit_test(key_bits, BTN_STYLUS) ||
+ bit_test(key_bits, BTN_STYLUS2)) {
+ type = DEVICE_TYPE_TABLET;
+ } else if (bit_test(abs_bits, ABS_PRESSURE) ||
+ bit_test(key_bits, BTN_TOUCH)) {
+ if (has_lmr ||
+ bit_test(key_bits, BTN_TOOL_FINGER)) {
+ type = DEVICE_TYPE_TOUCHPAD;
+ } else {
+ type = DEVICE_TYPE_TOUCHSCREEN;
+ }
+ /* some touchscreens use BTN_LEFT rather than BTN_TOUCH */
+ } else if (!(bit_test(rel_bits, REL_X) &&
+ bit_test(rel_bits, REL_Y)) &&
+ has_lmr) {
+ type = DEVICE_TYPE_TOUCHSCREEN;
+ }
+ }
+ }
+
+ if (type == DEVICE_TYPE_UNKNOWN) {
+ if (has_keys)
+ type = DEVICE_TYPE_KEYBOARD;
+ else if (has_rel_axes || has_buttons)
+ type = DEVICE_TYPE_MOUSE;
+ }
+
+ return (type);
+}
+
+static enum device_type
+r_identify_sysmouse(int fd __unused)
+{
+ /* All sysmouse devices act like mices */
+ return (DEVICE_TYPE_MOUSE);
+}
+
+static const char *
+r_if(enum device_if type)
+{
+ const char *unknown = "unknown";
+
+ return (type == DEVICE_IF_UNKNOWN || type >= (int)nitems(rifs) ?
+ unknown : rifs[type].name);
+}
+
+static const char *
+r_name(enum device_type type)
+{
+ const char *unknown = "unknown";
+
+ return (type == DEVICE_TYPE_UNKNOWN || type >= (int)nitems(rnames) ?
+ unknown : rnames[type]);
+}
+
+static int
+r_init_dev_evdev(int fd, struct device *dev)
+{
+ if (ioctl(fd, EVIOCGNAME(sizeof(dev->name) - 1), dev->name) < 0) {
+ logwarnx("unable to get device %s name", dev->path);
+ return (errno);
+ }
+ /* Do not loop events */
+ if (strncmp(dev->name, "System mouse", sizeof(dev->name)) == 0) {
+ return (ENOTSUP);
+ }
+ if (ioctl(fd, EVIOCGID, &dev->id) < 0) {
+ logwarnx("unable to get device %s ID", dev->path);
+ return (errno);
+ }
+ (void)ioctl(fd, EVIOCGUNIQ(sizeof(dev->uniq) - 1), dev->uniq);
+
+ return (0);
+}
+
+static int
+r_init_dev_sysmouse(int fd, struct device *dev)
+{
+ mousemode_t *mode = &dev->mode;
+ int level;
+
+ level = 1;
+ if (ioctl(fd, MOUSE_SETLEVEL, &level) < 0) {
+ logwarnx("unable to MOUSE_SETLEVEL for device %s", dev->path);
+ return (errno);
+ }
+ if (ioctl(fd, MOUSE_GETLEVEL, &level) < 0) {
+ logwarnx("unable to MOUSE_GETLEVEL for device %s", dev->path);
+ return (errno);
+ }
+ if (level != 1) {
+ logwarnx("unable to set level to 1 for device %s", dev->path);
+ return (ENOTSUP);
+ }
+ memset(mode, 0, sizeof(*mode));
+ if (ioctl(fd, MOUSE_GETMODE, mode) < 0) {
+ logwarnx("unable to MOUSE_GETMODE for device %s", dev->path);
+ return (errno);
+ }
+ if (mode->protocol != MOUSE_PROTO_SYSMOUSE) {
+ logwarnx("unable to set sysmouse protocol for device %s",
+ dev->path);
+ return (ENOTSUP);
+ }
+ if (mode->packetsize != MOUSE_SYS_PACKETSIZE) {
+ logwarnx("unable to set sysmouse packet size for device %s",
+ dev->path);
+ return (ENOTSUP);
+ }
+
+ /* TODO: Fill name, id and uniq from dev.* sysctls */
+ strlcpy(dev->name, dev->path, sizeof(dev->name));
+
+ return (0);
+}
+
+static void
+r_init_evstate(struct quirks *q, struct evstate *ev)
+{
+ const struct quirk_tuples *t;
+ bitstr_t *bitstr;
+ int maxbit;
+
+ if (quirks_get_tuples(q, QUIRK_ATTR_EVENT_CODE, &t)) {
+ for (size_t i = 0; i < t->ntuples; i++) {
+ int type = t->tuples[i].first;
+ int code = t->tuples[i].second;
+ bool enable = t->tuples[i].third;
+
+ switch (type) {
+ case EV_KEY:
+ bitstr = (bitstr_t *)&ev->key_ignore;
+ maxbit = KEY_MAX;
+ break;
+ case EV_REL:
+ bitstr = (bitstr_t *)&ev->rel_ignore;
+ maxbit = REL_MAX;
+ break;
+ case EV_ABS:
+ bitstr = (bitstr_t *)&ev->abs_ignore;
+ maxbit = ABS_MAX;
+ break;
+ default:
+ continue;
+ }
+
+ if (code == EVENT_CODE_UNDEFINED) {
+ if (enable)
+ bit_nclear(bitstr, 0, maxbit);
+ else
+ bit_nset(bitstr, 0, maxbit);
+ } else {
+ if (code > maxbit)
+ continue;
+ if (enable)
+ bit_clear(bitstr, code);
+ else
+ bit_set(bitstr, code);
+ }
+ }
+ }
+
+ if (quirks_get_tuples(q, QUIRK_ATTR_INPUT_PROP, &t)) {
+ for (size_t idx = 0; idx < t->ntuples; idx++) {
+ unsigned int p = t->tuples[idx].first;
+ bool enable = t->tuples[idx].second;
+
+ if (p > INPUT_PROP_MAX)
+ continue;
+ if (enable)
+ bit_clear(ev->prop_ignore, p);
+ else
+ bit_set(ev->prop_ignore, p);
+ }
+ }
+}
+
+static void
+r_init_buttons(struct quirks *q, struct btstate *bt, struct e3bstate *e3b)
+{
+ struct timespec ts;
+ int i, j;
+
+ *bt = (struct btstate) {
+ .clickthreshold = DFLT_CLICKTHRESHOLD,
+ .zmap = { 0, 0, 0, 0 },
+ };
+
+ memcpy(bt->p2l, default_p2l, sizeof(bt->p2l));
+ for (i = 0; i < MOUSE_MAXBUTTON; ++i) {
+ j = i;
+ if (opt_btstate.p2l[i] != 0)
+ bt->p2l[i] = opt_btstate.p2l[i];
+ if (opt_btstate.mstate[i] != NULL)
+ j = opt_btstate.mstate[i] - opt_btstate.bstate;
+ bt->mstate[i] = bt->bstate + j;
+ }
+
+ if (opt_btstate.zmap[0] != 0)
+ memcpy(bt->zmap, opt_btstate.zmap, sizeof(bt->zmap));
+ if (opt_clickthreshold >= 0)
+ bt->clickthreshold = opt_clickthreshold;
+ else
+ quirks_get_uint32(q, MOUSED_CLICK_THRESHOLD, &bt->clickthreshold);
+ if (opt_wmode != 0)
+ bt->wmode = opt_wmode;
+ else
+ quirks_get_uint32(q, MOUSED_WMODE, &bt->wmode);
+ if (bt->wmode != 0)
+ bt->wmode = 1 << (bt->wmode - 1);
+
+ /* fix Z axis mapping */
+ for (i = 0; i < ZMAP_MAXBUTTON; ++i) {
+ if (bt->zmap[i] <= 0)
+ continue;
+ for (j = 0; j < MOUSE_MAXBUTTON; ++j) {
+ if (bt->mstate[j] == &bt->bstate[bt->zmap[i] - 1])
+ bt->mstate[j] = &bt->zstate[i];
+ }
+ bt->zmap[i] = 1 << (bt->zmap[i] - 1);
+ }
+
+ clock_gettime(CLOCK_MONOTONIC_FAST, &ts);
+
+ *e3b = (struct e3bstate) {
+ .enabled = false,
+ .button2timeout = DFLT_BUTTON2TIMEOUT,
+ };
+ e3b->enabled = opt_e3b_enabled;
+ if (!e3b->enabled)
+ quirks_get_bool(q, MOUSED_EMULATE_THIRD_BUTTON, &e3b->enabled);
+ if (opt_e3b_button2timeout >= 0)
+ e3b->button2timeout = opt_e3b_button2timeout;
+ else
+ quirks_get_uint32(q, MOUSED_EMULATE_THIRD_BUTTON_TIMEOUT,
+ &e3b->button2timeout);
+ e3b->mouse_button_state = S0;
+ e3b->mouse_button_state_ts = ts;
+ e3b->mouse_move_delayed = 0;
+
+ for (i = 0; i < MOUSE_MAXBUTTON; ++i) {
+ bt->bstate[i].count = 0;
+ bt->bstate[i].ts = ts;
+ }
+ for (i = 0; i < ZMAP_MAXBUTTON; ++i) {
+ bt->zstate[i].count = 0;
+ bt->zstate[i].ts = ts;
+ }
+}
+
+static void
+r_init_touchpad_hw(int fd, struct quirks *q, struct tpcaps *tphw,
+ struct evstate *ev)
+{
+ struct input_absinfo ai;
+ bitstr_t bit_decl(key_bits, KEY_CNT);
+ bitstr_t bit_decl(abs_bits, ABS_CNT);
+ bitstr_t bit_decl(prop_bits, INPUT_PROP_CNT);
+ struct quirk_range r;
+ struct quirk_dimensions dim;
+ u_int u;
+
+ ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(abs_bits)), abs_bits);
+ ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(key_bits)), key_bits);
+
+ if (!bit_test(ev->abs_ignore, ABS_X) &&
+ ioctl(fd, EVIOCGABS(ABS_X), &ai) >= 0) {
+ tphw->min_x = (ai.maximum > ai.minimum) ? ai.minimum : INT_MIN;
+ tphw->max_x = (ai.maximum > ai.minimum) ? ai.maximum : INT_MAX;
+ tphw->res_x = ai.resolution == 0 ?
+ DFLT_TPAD_RESOLUTION : ai.resolution;
+ }
+ if (!bit_test(ev->abs_ignore, ABS_Y) &&
+ ioctl(fd, EVIOCGABS(ABS_Y), &ai) >= 0) {
+ tphw->min_y = (ai.maximum > ai.minimum) ? ai.minimum : INT_MIN;
+ tphw->max_y = (ai.maximum > ai.minimum) ? ai.maximum : INT_MAX;
+ tphw->res_y = ai.resolution == 0 ?
+ DFLT_TPAD_RESOLUTION : ai.resolution;
+ }
+ if (quirks_get_dimensions(q, QUIRK_ATTR_RESOLUTION_HINT, &dim)) {
+ tphw->res_x = dim.x;
+ tphw->res_y = dim.y;
+ } else if (tphw->max_x != INT_MAX && tphw->max_y != INT_MAX &&
+ quirks_get_dimensions(q, QUIRK_ATTR_SIZE_HINT, &dim)) {
+ tphw->res_x = (tphw->max_x - tphw->min_x) / dim.x;
+ tphw->res_y = (tphw->max_y - tphw->min_y) / dim.y;
+ }
+ if (!bit_test(ev->key_ignore, BTN_TOUCH) &&
+ bit_test(key_bits, BTN_TOUCH))
+ tphw->cap_touch = true;
+ /* XXX: libinput uses ABS_MT_PRESSURE where available */
+ if (!bit_test(ev->abs_ignore, ABS_PRESSURE) &&
+ bit_test(abs_bits, ABS_PRESSURE) &&
+ ioctl(fd, EVIOCGABS(ABS_PRESSURE), &ai) >= 0) {
+ tphw->cap_pressure = true;
+ tphw->min_p = ai.minimum;
+ tphw->max_p = ai.maximum;
+ }
+ if (tphw->cap_pressure &&
+ quirks_get_range(q, QUIRK_ATTR_PRESSURE_RANGE, &r)) {
+ if (r.upper == 0 && r.lower == 0) {
+ debug("pressure-based touch detection disabled");
+ tphw->cap_pressure = false;
+ } else if (r.upper > tphw->max_p || r.upper < tphw->min_p ||
+ r.lower > tphw->max_p || r.lower < tphw->min_p) {
+ debug("discarding out-of-bounds pressure range %d:%d",
+ r.lower, r.upper);
+ tphw->cap_pressure = false;
+ }
+ }
+ /* XXX: libinput uses ABS_MT_TOUCH_MAJOR where available */
+ if (!bit_test(ev->abs_ignore, ABS_TOOL_WIDTH) &&
+ bit_test(abs_bits, ABS_TOOL_WIDTH) &&
+ quirks_get_uint32(q, QUIRK_ATTR_PALM_SIZE_THRESHOLD, &u) &&
+ u != 0)
+ tphw->cap_width = true;
+ if (!bit_test(ev->abs_ignore, ABS_MT_SLOT) &&
+ bit_test(abs_bits, ABS_MT_SLOT) &&
+ !bit_test(ev->abs_ignore, ABS_MT_TRACKING_ID) &&
+ bit_test(abs_bits, ABS_MT_TRACKING_ID) &&
+ !bit_test(ev->abs_ignore, ABS_MT_POSITION_X) &&
+ bit_test(abs_bits, ABS_MT_POSITION_X) &&
+ !bit_test(ev->abs_ignore, ABS_MT_POSITION_Y) &&
+ bit_test(abs_bits, ABS_MT_POSITION_Y))
+ tphw->is_mt = true;
+ if ( ioctl(fd, EVIOCGPROP(sizeof(prop_bits)), prop_bits) >= 0 &&
+ !bit_test(ev->prop_ignore, INPUT_PROP_BUTTONPAD) &&
+ bit_test(prop_bits, INPUT_PROP_BUTTONPAD))
+ tphw->is_clickpad = true;
+ if ( tphw->is_clickpad &&
+ !bit_test(ev->prop_ignore, INPUT_PROP_TOPBUTTONPAD) &&
+ bit_test(prop_bits, INPUT_PROP_TOPBUTTONPAD))
+ tphw->is_topbuttonpad = true;
+}
+
+static void
+r_init_touchpad_info(struct quirks *q, struct tpcaps *tphw,
+ struct tpinfo *tpinfo)
+{
+ struct quirk_range r;
+ int i;
+ u_int u;
+ int sz_x, sz_y;
+
+ *tpinfo = (struct tpinfo) {
+ .two_finger_scroll = true,
+ .natural_scroll = false,
+ .three_finger_drag = false,
+ .min_pressure_hi = 1,
+ .min_pressure_lo = 1,
+ .max_pressure = 130,
+ .max_width = 16,
+ .tap_timeout = 180, /* ms */
+ .tap_threshold = 0,
+ .tap_max_delta = 1.3, /* mm */
+ .taphold_timeout = 300, /* ms */
+ .vscroll_min_delta = 1.25, /* mm */
+ .vscroll_hor_area = 0.0, /* mm */
+ .vscroll_ver_area = -15.0, /* mm */
+ };
+
+ quirks_get_bool(q, MOUSED_TWO_FINGER_SCROLL, &tpinfo->two_finger_scroll);
+ quirks_get_bool(q, MOUSED_NATURAL_SCROLL, &tpinfo->natural_scroll);
+ quirks_get_bool(q, MOUSED_THREE_FINGER_DRAG, &tpinfo->three_finger_drag);
+ quirks_get_uint32(q, MOUSED_TAP_TIMEOUT, &tpinfo->tap_timeout);
+ quirks_get_double(q, MOUSED_TAP_MAX_DELTA, &tpinfo->tap_max_delta);
+ quirks_get_uint32(q, MOUSED_TAPHOLD_TIMEOUT, &tpinfo->taphold_timeout);
+ quirks_get_double(q, MOUSED_VSCROLL_MIN_DELTA, &tpinfo->vscroll_min_delta);
+ quirks_get_double(q, MOUSED_VSCROLL_HOR_AREA, &tpinfo->vscroll_hor_area);
+ quirks_get_double(q, MOUSED_VSCROLL_VER_AREA, &tpinfo->vscroll_ver_area);
+
+ if (tphw->cap_pressure &&
+ quirks_get_range(q, QUIRK_ATTR_PRESSURE_RANGE, &r)) {
+ tpinfo->min_pressure_lo = r.lower;
+ tpinfo->min_pressure_hi = r.upper;
+ quirks_get_uint32(q, QUIRK_ATTR_PALM_PRESSURE_THRESHOLD,
+ &tpinfo->max_pressure);
+ quirks_get_uint32(q, MOUSED_TAP_PRESSURE_THRESHOLD,
+ &tpinfo->tap_threshold);
+ }
+ if (tphw->cap_width)
+ quirks_get_uint32(q, QUIRK_ATTR_PALM_SIZE_THRESHOLD,
+ &tpinfo->max_width);
+ /* Set bottom quarter as 42% - 16% - 42% sized softbuttons */
+ if (tphw->is_clickpad) {
+ sz_x = tphw->max_x - tphw->min_x;
+ sz_y = tphw->max_y - tphw->min_y;
+ i = 25;
+ if (tphw->is_topbuttonpad)
+ i = -i;
+ quirks_get_int32(q, MOUSED_SOFTBUTTONS_Y, &i);
+ tpinfo->softbuttons_y = sz_y * i / 100;
+ u = 42;
+ quirks_get_uint32(q, MOUSED_SOFTBUTTON2_X, &u);
+ tpinfo->softbutton2_x = sz_x * u / 100;
+ u = 58;
+ quirks_get_uint32(q, MOUSED_SOFTBUTTON3_X, &u);
+ tpinfo->softbutton3_x = sz_x * u / 100;
+ }
+}
+
+static void
+r_init_touchpad_accel(struct tpcaps *tphw, struct accel *accel)
+{
+ /* Normalize pointer movement to match 200dpi mouse */
+ accel->accelx *= DFLT_MOUSE_RESOLUTION;
+ accel->accelx /= tphw->res_x;
+ accel->accely *= DFLT_MOUSE_RESOLUTION;
+ accel->accely /= tphw->res_y;
+ accel->accelz *= DFLT_MOUSE_RESOLUTION;
+ accel->accelz /= (tphw->res_x * DFLT_LINEHEIGHT);
+}
+
+static void
+r_init_touchpad_gesture(struct tpstate *gest)
+{
+ gest->idletimeout = -1;
+}
+
+static void
+r_init_drift(struct quirks *q, struct drift *d)
+{
+ if (opt_drift_terminate) {
+ d->terminate = true;
+ d->distance = opt_drift_distance;
+ d->time = opt_drift_time;
+ d->after = opt_drift_after;
+ } else if (quirks_get_bool(q, MOUSED_DRIFT_TERMINATE, &d->terminate) &&
+ d->terminate) {
+ quirks_get_uint32(q, MOUSED_DRIFT_DISTANCE, &d->distance);
+ quirks_get_uint32(q, MOUSED_DRIFT_TIME, &d->time);
+ quirks_get_uint32(q, MOUSED_DRIFT_AFTER, &d->after);
+ } else
+ return;
+
+ if (d->distance == 0 || d->time == 0 || d->after == 0) {
+ warnx("invalid drift parameter");
+ exit(1);
+ }
+
+ debug("terminate drift: distance %d, time %d, after %d",
+ d->distance, d->time, d->after);
+
+ d->time_ts = msec2ts(d->time);
+ d->twotime_ts = msec2ts(d->time * 2);
+ d->after_ts = msec2ts(d->after);
+}
+
+static void
+r_init_accel(struct quirks *q, struct accel *acc)
+{
+ bool r1, r2;
+
+ acc->accelx = opt_accelx;
+ if (opt_accelx == 1.0)
+ quirks_get_double(q, MOUSED_LINEAR_ACCEL_X, &acc->accelx);
+ acc->accely = opt_accely;
+ if (opt_accely == 1.0)
+ quirks_get_double(q, MOUSED_LINEAR_ACCEL_Y, &acc->accely);
+ if (!quirks_get_double(q, MOUSED_LINEAR_ACCEL_Z, &acc->accelz))
+ acc->accelz = 1.0;
+ acc->lastlength[0] = acc->lastlength[1] = acc->lastlength[2] = 0.0;
+ if (opt_exp_accel) {
+ acc->is_exponential = true;
+ acc->expoaccel = opt_expoaccel;
+ acc->expoffset = opt_expoffset;
+ return;
+ }
+ acc->expoaccel = acc->expoffset = 1.0;
+ r1 = quirks_get_double(q, MOUSED_EXPONENTIAL_ACCEL, &acc->expoaccel);
+ r2 = quirks_get_double(q, MOUSED_EXPONENTIAL_OFFSET, &acc->expoffset);
+ if (r1 || r2)
+ acc->is_exponential = true;
+}
+
+static void
+r_init_scroll(struct quirks *q, struct scroll *scroll)
+{
+ *scroll = (struct scroll) {
+ .threshold = DFLT_SCROLLTHRESHOLD,
+ .speed = DFLT_SCROLLSPEED,
+ .state = SCROLL_NOTSCROLLING,
+ };
+ scroll->enable_vert = opt_virtual_scroll;
+ if (!opt_virtual_scroll)
+ quirks_get_bool(q, MOUSED_VIRTUAL_SCROLL_ENABLE, &scroll->enable_vert);
+ scroll->enable_hor = opt_hvirtual_scroll;
+ if (!opt_hvirtual_scroll)
+ quirks_get_bool(q, MOUSED_HOR_VIRTUAL_SCROLL_ENABLE, &scroll->enable_hor);
+ if (opt_scroll_speed >= 0)
+ scroll->speed = opt_scroll_speed;
+ else
+ quirks_get_uint32(q, MOUSED_VIRTUAL_SCROLL_SPEED, &scroll->speed);
+ if (opt_scroll_threshold >= 0)
+ scroll->threshold = opt_scroll_threshold;
+ else
+ quirks_get_uint32(q, MOUSED_VIRTUAL_SCROLL_THRESHOLD, &scroll->threshold);
+}
+
+static struct rodent *
+r_init(const char *path)
+{
+ struct rodent *r;
+ struct device dev;
+ struct quirks *q;
+ struct kevent kev;
+ enum device_if iftype;
+ enum device_type type;
+ int fd, err;
+ bool grab;
+ bool ignore;
+ bool qvalid;
+
+ fd = open(path, O_RDWR | O_NONBLOCK);
+ if (fd == -1) {
+ logwarnx("unable to open %s", path);
+ return (NULL);
+ }
+
+ iftype = r_identify_if(fd);
+ switch (iftype) {
+ case DEVICE_IF_UNKNOWN:
+ debug("cannot determine interface type on %s", path);
+ close(fd);
+ errno = ENOTSUP;
+ return (NULL);
+ case DEVICE_IF_EVDEV:
+ type = r_identify_evdev(fd);
+ break;
+ case DEVICE_IF_SYSMOUSE:
+ type = r_identify_sysmouse(fd);
+ break;
+ default:
+ debug("unsupported interface type: %s on %s",
+ r_if(iftype), path);
+ close(fd);
+ errno = ENXIO;
+ return (NULL);
+ }
+
+ switch (type) {
+ case DEVICE_TYPE_UNKNOWN:
+ debug("cannot determine device type on %s", path);
+ close(fd);
+ errno = ENOTSUP;
+ return (NULL);
+ case DEVICE_TYPE_MOUSE:
+ case DEVICE_TYPE_TOUCHPAD:
+ break;
+ default:
+ debug("unsupported device type: %s on %s",
+ r_name(type), path);
+ close(fd);
+ errno = ENXIO;
+ return (NULL);
+ }
+
+ memset(&dev, 0, sizeof(struct device));
+ strlcpy(dev.path, path, sizeof(dev.path));
+ dev.iftype = iftype;
+ dev.type = type;
+ switch (iftype) {
+ case DEVICE_IF_EVDEV:
+ err = r_init_dev_evdev(fd, &dev);
+ break;
+ case DEVICE_IF_SYSMOUSE:
+ err = r_init_dev_sysmouse(fd, &dev);
+ break;
+ default:
+ debug("unsupported interface type: %s on %s",
+ r_if(iftype), path);
+ err = ENXIO;
+ }
+ if (err != 0) {
+ debug("failed to initialize device: %s %s on %s",
+ r_if(iftype), r_name(type), path);
+ close(fd);
+ errno = err;
+ return (NULL);
+ }
+
+ debug("port: %s interface: %s type: %s model: %s",
+ path, r_if(iftype), r_name(type), dev.name);
+
+ q = quirks_fetch_for_device(quirks, &dev);
+
+ qvalid = quirks_get_bool(q, MOUSED_IGNORE_DEVICE, &ignore);
+ if (qvalid && ignore) {
+ debug("%s: device ignored", path);
+ close(fd);
+ quirks_unref(q);
+ errno = EPERM;
+ return (NULL);
+ }
+
+ switch (iftype) {
+ case DEVICE_IF_EVDEV:
+ grab = opt_grab;
+ if (!grab)
+ qvalid = quirks_get_bool(q, MOUSED_GRAB_DEVICE, &grab);
+ if (qvalid && grab && ioctl(fd, EVIOCGRAB, 1) == -1) {
+ logwarnx("failed to grab %s", path);
+ err = errno;
+ }
+ break;
+ case DEVICE_IF_SYSMOUSE:
+ if (opt_resolution == MOUSE_RES_UNKNOWN && opt_rate == 0)
+ break;
+ if (opt_resolution != MOUSE_RES_UNKNOWN)
+ dev.mode.resolution = opt_resolution;
+ if (opt_resolution != 0)
+ dev.mode.rate = opt_rate;
+ if (ioctl(fd, MOUSE_SETMODE, &dev.mode) < 0)
+ debug("failed to MOUSE_SETMODE for device %s", path);
+ break;
+ default:
+ debug("unsupported interface type: %s on %s",
+ r_if(iftype), path);
+ err = ENXIO;
+ }
+ if (err != 0) {
+ debug("failed to initialize device: %s %s on %s",
+ r_if(iftype), r_name(type), path);
+ close(fd);
+ quirks_unref(q);
+ errno = err;
+ return (NULL);
+ }
+
+ r = calloc(1, sizeof(struct rodent));
+ memcpy(&r->dev, &dev, sizeof(struct device));
+ r->mfd = fd;
+
+ EV_SET(&kev, fd, EVFILT_READ, EV_ADD, 0, 0, r);
+ err = kevent(kfd, &kev, 1, NULL, 0, NULL);
+ if (err == -1) {
+ logwarnx("failed to register kevent on %s", path);
+ close(fd);
+ free(r);
+ quirks_unref(q);
+ return (NULL);
+ }
+
+ if (iftype == DEVICE_IF_EVDEV)
+ r_init_evstate(q, &r->ev);
+ r_init_buttons(q, &r->btstate, &r->e3b);
+ r_init_scroll(q, &r->scroll);
+ r_init_accel(q, &r->accel);
+ switch (type) {
+ case DEVICE_TYPE_TOUCHPAD:
+ r_init_touchpad_hw(fd, q, &r->tp.hw, &r->ev);
+ r_init_touchpad_info(q, &r->tp.hw, &r->tp.info);
+ r_init_touchpad_accel(&r->tp.hw, &r->accel);
+ r_init_touchpad_gesture(&r->tp.gest);
+ break;
+
+ case DEVICE_TYPE_MOUSE:
+ r_init_drift(q, &r->drift);
+ break;
+
+ default:
+ debug("unsupported device type: %s", r_name(type));
+ break;
+ }
+
+ quirks_unref(q);
+
+ SLIST_INSERT_HEAD(&rodents, r, next);
+
+ return (r);
+}
+
+static void
+r_init_all(void)
+{
+ char path[22] = "/dev/input/";
+ DIR *dirp;
+ struct dirent *dp;
+
+ dirp = opendir("/dev/input");
+ if (dirp == NULL)
+ logerr(1, "Failed to open /dev/input");
+
+ while ((dp = readdir(dirp)) != NULL) {
+ if (fnmatch("event[0-9]*", dp->d_name, 0) == 0) {
+ strncpy(path + 11, dp->d_name, 10);
+ (void)r_init(path);
+ }
+ }
+ (void)closedir(dirp);
+
+ return;
+}
+
+static void
+r_deinit(struct rodent *r)
+{
+ struct kevent ke[3];
+
+ if (r == NULL)
+ return;
+ if (r->mfd != -1) {
+ EV_SET(ke, r->mfd, EVFILT_READ, EV_DELETE, 0, 0, r);
+ EV_SET(ke + 1, r->mfd << 1, EVFILT_TIMER, EV_DELETE, 0, 0, r);
+ EV_SET(ke + 2, r->mfd << 1 | 1,
+ EVFILT_TIMER, EV_DELETE, 0, 0, r);
+ kevent(kfd, ke, nitems(ke), NULL, 0, NULL);
+ close(r->mfd);
+ }
+ SLIST_REMOVE(&rodents, r, rodent, next);
+ debug("destroy device: port: %s model: %s", r->dev.path, r->dev.name);
+ free(r);
+}
+
+static void
+r_deinit_all(void)
+{
+ while (!SLIST_EMPTY(&rodents))
+ r_deinit(SLIST_FIRST(&rodents));
+}
+
+static int
+r_protocol_evdev(enum device_type type, struct tpad *tp, struct evstate *ev,
+ struct input_event *ie, mousestatus_t *act)
+{
+ const struct tpcaps *tphw = &tp->hw;
+ const struct tpinfo *tpinfo = &tp->info;
+
+ static int butmapev[8] = { /* evdev */
+ 0,
+ MOUSE_BUTTON1DOWN,
+ MOUSE_BUTTON3DOWN,
+ MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN,
+ MOUSE_BUTTON2DOWN,
+ MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN,
+ MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN,
+ MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN
+ };
+ struct timespec ietime;
+
+ /* Drop ignored codes */
+ switch (ie->type) {
+ case EV_REL:
+ if (bit_test(ev->rel_ignore, ie->code))
+ return (0);
+ case EV_ABS:
+ if (bit_test(ev->abs_ignore, ie->code))
+ return (0);
+ case EV_KEY:
+ if (bit_test(ev->key_ignore, ie->code))
+ return (0);
+ }
+
+ if (debug > 1)
+ debug("received event 0x%02x, 0x%04x, %d",
+ ie->type, ie->code, ie->value);
+
+ switch (ie->type) {
+ case EV_REL:
+ switch (ie->code) {
+ case REL_X:
+ ev->dx += ie->value;
+ break;
+ case REL_Y:
+ ev->dy += ie->value;
+ break;
+ case REL_WHEEL:
+ ev->dz += ie->value;
+ break;
+ case REL_HWHEEL:
+ ev->dw += ie->value;
+ break;
+ }
+ break;
+ case EV_ABS:
+ switch (ie->code) {
+ case ABS_X:
+ if (!tphw->is_mt)
+ ev->dx += ie->value - ev->st.x;
+ ev->st.x = ie->value;
+ break;
+ case ABS_Y:
+ if (!tphw->is_mt)
+ ev->dy += ie->value - ev->st.y;
+ ev->st.y = ie->value;
+ break;
+ case ABS_PRESSURE:
+ ev->st.p = ie->value;
+ break;
+ case ABS_TOOL_WIDTH:
+ ev->st.w = ie->value;
+ break;
+ case ABS_MT_SLOT:
+ if (tphw->is_mt)
+ ev->slot = ie->value;
+ break;
+ case ABS_MT_TRACKING_ID:
+ if (tphw->is_mt &&
+ ev->slot >= 0 && ev->slot < MAX_FINGERS) {
+ if (ie->value != -1 && ev->mt[ev->slot].id > 0 &&
+ ie->value + 1 != ev->mt[ev->slot].id) {
+ debug("tracking id changed %d->%d",
+ ie->value, ev->mt[ev->slot].id - 1);
+ ev->mt[ev->slot].id = 0;
+ } else
+ ev->mt[ev->slot].id = ie->value + 1;
+ }
+ break;
+ case ABS_MT_POSITION_X:
+ if (tphw->is_mt &&
+ ev->slot >= 0 && ev->slot < MAX_FINGERS) {
+ /* Find fastest finger */
+ int dx = ie->value - ev->mt[ev->slot].x;
+ if (abs(dx) > abs(ev->dx))
+ ev->dx = dx;
+ ev->mt[ev->slot].x = ie->value;
+ }
+ break;
+ case ABS_MT_POSITION_Y:
+ if (tphw->is_mt &&
+ ev->slot >= 0 && ev->slot < MAX_FINGERS) {
+ /* Find fastest finger */
+ int dy = ie->value - ev->mt[ev->slot].y;
+ if (abs(dy) > abs(ev->dy))
+ ev->dy = dy;
+ ev->mt[ev->slot].y = ie->value;
+ }
+ break;
+ }
+ break;
+ case EV_KEY:
+ switch (ie->code) {
+ case BTN_TOUCH:
+ ev->st.id = ie->value != 0 ? 1 : 0;
+ break;
+ case BTN_TOOL_FINGER:
+ ev->nfingers = ie->value != 0 ? 1 : ev->nfingers;
+ break;
+ case BTN_TOOL_DOUBLETAP:
+ ev->nfingers = ie->value != 0 ? 2 : ev->nfingers;
+ break;
+ case BTN_TOOL_TRIPLETAP:
+ ev->nfingers = ie->value != 0 ? 3 : ev->nfingers;
+ break;
+ case BTN_TOOL_QUADTAP:
+ ev->nfingers = ie->value != 0 ? 4 : ev->nfingers;
+ break;
+ case BTN_TOOL_QUINTTAP:
+ ev->nfingers = ie->value != 0 ? 5 : ev->nfingers;
+ break;
+ case BTN_LEFT ... BTN_LEFT + 7:
+ ev->buttons &= ~(1 << (ie->code - BTN_LEFT));
+ ev->buttons |= ((!!ie->value) << (ie->code - BTN_LEFT));
+ break;
+ }
+ break;
+ }
+
+ if ( ie->type != EV_SYN ||
+ (ie->code != SYN_REPORT && ie->code != SYN_DROPPED))
+ return (0);
+
+ /*
+ * assembly full package
+ */
+
+ ietime.tv_sec = ie->time.tv_sec;
+ ietime.tv_nsec = ie->time.tv_usec * 1000;
+
+ if (!tphw->cap_pressure && ev->st.id != 0)
+ ev->st.p = MAX(tpinfo->min_pressure_hi, tpinfo->tap_threshold);
+ if (tphw->cap_touch && ev->st.id == 0)
+ ev->st.p = 0;
+
+ act->obutton = act->button;
+ act->button = butmapev[ev->buttons & MOUSE_SYS_STDBUTTONS];
+ act->button |= (ev->buttons & ~MOUSE_SYS_STDBUTTONS);
+
+ if (type == DEVICE_TYPE_TOUCHPAD) {
+ if (debug > 1)
+ debug("absolute data %d,%d,%d,%d", ev->st.x, ev->st.y,
+ ev->st.p, ev->st.w);
+ switch (r_gestures(tp, ev->st.x, ev->st.y, ev->st.p, ev->st.w,
+ ev->nfingers, &ietime, act)) {
+ case GEST_IGNORE:
+ ev->dx = 0;
+ ev->dy = 0;
+ ev->dz = 0;
+ ev->acc_dx = ev->acc_dy = 0;
+ debug("gesture IGNORE");
+ break;
+ case GEST_ACCUMULATE: /* Revertable pointer movement. */
+ ev->acc_dx += ev->dx;
+ ev->acc_dy += ev->dy;
+ debug("gesture ACCUMULATE %d,%d", ev->dx, ev->dy);
+ ev->dx = 0;
+ ev->dy = 0;
+ break;
+ case GEST_MOVE: /* Pointer movement. */
+ ev->dx += ev->acc_dx;
+ ev->dy += ev->acc_dy;
+ ev->acc_dx = ev->acc_dy = 0;
+ debug("gesture MOVE %d,%d", ev->dx, ev->dy);
+ break;
+ case GEST_VSCROLL: /* Vertical scrolling. */
+ if (tpinfo->natural_scroll)
+ ev->dz = -ev->dy;
+ else
+ ev->dz = ev->dy;
+ ev->dx = -ev->acc_dx;
+ ev->dy = -ev->acc_dy;
+ ev->acc_dx = ev->acc_dy = 0;
+ debug("gesture VSCROLL %d", ev->dz);
+ break;
+ case GEST_HSCROLL: /* Horizontal scrolling. */
+/*
+ if (ev.dx != 0) {
+ if (tpinfo->natural_scroll)
+ act->button |= (ev.dx > 0)
+ ? MOUSE_BUTTON6DOWN
+ : MOUSE_BUTTON7DOWN;
+ else
+ act->button |= (ev.dx > 0)
+ ? MOUSE_BUTTON7DOWN
+ : MOUSE_BUTTON6DOWN;
+ }
+*/
+ ev->dx = -ev->acc_dx;
+ ev->dy = -ev->acc_dy;
+ ev->acc_dx = ev->acc_dy = 0;
+ debug("gesture HSCROLL %d", ev->dw);
+ break;
+ }
+ }
+
+ debug("assembled full packet %d,%d,%d", ev->dx, ev->dy, ev->dz);
+ act->dx = ev->dx;
+ act->dy = ev->dy;
+ act->dz = ev->dz;
+ ev->dx = ev->dy = ev->dz = ev->dw = 0;
+
+ /* has something changed? */
+ act->flags = ((act->dx || act->dy || act->dz) ? MOUSE_POSCHANGED : 0)
+ | (act->obutton ^ act->button);
+
+ return (act->flags);
+}
+
+static int
+r_protocol_sysmouse(uint8_t *pBuf, mousestatus_t *act)
+{
+ static int butmapmsc[8] = { /* sysmouse */
+ 0,
+ MOUSE_BUTTON3DOWN,
+ MOUSE_BUTTON2DOWN,
+ MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN,
+ MOUSE_BUTTON1DOWN,
+ MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN,
+ MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN,
+ MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN
+ };
+
+ debug("%02x %02x %02x %02x %02x %02x %02x %02x", pBuf[0], pBuf[1],
+ pBuf[2], pBuf[3], pBuf[4], pBuf[5], pBuf[6], pBuf[7]);
+
+ if ((pBuf[0] & MOUSE_SYS_SYNCMASK) != MOUSE_SYS_SYNC)
+ return (0);
+
+ act->button = butmapmsc[(~pBuf[0]) & MOUSE_SYS_STDBUTTONS];
+ act->dx = (signed char)(pBuf[1]) + (signed char)(pBuf[3]);
+ act->dy = - ((signed char)(pBuf[2]) + (signed char)(pBuf[4]));
+ act->dz = ((signed char)(pBuf[5] << 1) + (signed char)(pBuf[6] << 1)) >> 1;
+ act->button |= ((~pBuf[7] & MOUSE_SYS_EXTBUTTONS) << 3);
+
+ /* has something changed? */
+ act->flags = ((act->dx || act->dy || act->dz) ? MOUSE_POSCHANGED : 0)
+ | (act->obutton ^ act->button);
+
+ return (act->flags);
+}
+
+static void
+r_vscroll_detect(struct rodent *r, struct scroll *sc, mousestatus_t *act)
+{
+ mousestatus_t newaction;
+
+ /* Allow middle button drags to scroll up and down */
+ if (act->button == MOUSE_BUTTON2DOWN) {
+ if (sc->state == SCROLL_NOTSCROLLING) {
+ sc->state = SCROLL_PREPARE;
+ sc->movement = sc->hmovement = 0;
+ debug("PREPARING TO SCROLL");
+ }
+ return;
+ }
+
+ /* This isn't a middle button down... move along... */
+ switch (sc->state) {
+ case SCROLL_SCROLLING:
+ /*
+ * We were scrolling, someone let go of button 2.
+ * Now turn autoscroll off.
+ */
+ sc->state = SCROLL_NOTSCROLLING;
+ debug("DONE WITH SCROLLING / %d", sc->state);
+ break;
+ case SCROLL_PREPARE:
+ newaction = *act;
+
+ /* We were preparing to scroll, but we never moved... */
+ r_timestamp(act, &r->btstate, &r->e3b, &r->drift);
+ r_statetrans(r, act, &newaction,
+ A(newaction.button & MOUSE_BUTTON1DOWN,
+ act->button & MOUSE_BUTTON3DOWN));
+
+ /* Send middle down */
+ newaction.button = MOUSE_BUTTON2DOWN;
+ r_click(&newaction, &r->btstate);
+
+ /* Send middle up */
+ r_timestamp(&newaction, &r->btstate, &r->e3b, &r->drift);
+ newaction.obutton = newaction.button;
+ newaction.button = act->button;
+ r_click(&newaction, &r->btstate);
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+r_vscroll(struct scroll *sc, mousestatus_t *act)
+{
+ switch (sc->state) {
+ case SCROLL_PREPARE:
+ /* Middle button down, waiting for movement threshold */
+ if (act->dy == 0 && act->dx == 0)
+ break;
+ if (sc->enable_vert) {
+ sc->movement += act->dy;
+ if ((u_int)abs(sc->movement) > sc->threshold)
+ sc->state = SCROLL_SCROLLING;
+ }
+ if (sc->enable_hor) {
+ sc->hmovement += act->dx;
+ if ((u_int)abs(sc->hmovement) > sc->threshold)
+ sc->state = SCROLL_SCROLLING;
+ }
+ if (sc->state == SCROLL_SCROLLING)
+ sc->movement = sc->hmovement = 0;
+ break;
+ case SCROLL_SCROLLING:
+ if (sc->enable_vert) {
+ sc->movement += act->dy;
+ debug("SCROLL: %d", sc->movement);
+ if (sc->movement < -(int)sc->speed) {
+ /* Scroll down */
+ act->dz = -1;
+ sc->movement = 0;
+ }
+ else if (sc->movement > (int)sc->speed) {
+ /* Scroll up */
+ act->dz = 1;
+ sc->movement = 0;
+ }
+ }
+ if (sc->enable_hor) {
+ sc->hmovement += act->dx;
+ debug("HORIZONTAL SCROLL: %d", sc->hmovement);
+
+ if (sc->hmovement < -(int)sc->speed) {
+ act->dz = -2;
+ sc->hmovement = 0;
+ }
+ else if (sc->hmovement > (int)sc->speed) {
+ act->dz = 2;
+ sc->hmovement = 0;
+ }
+ }
+
+ /* Don't move while scrolling */
+ act->dx = act->dy = 0;
+ break;
+ default:
+ break;
+ }
+}
+
+static bool
+r_drift (struct drift *drift, mousestatus_t *act)
+{
+ struct timespec tmp;
+
+ /* X or/and Y movement only - possibly drift */
+ tssub(&drift->current_ts, &drift->last_activity, &tmp);
+ if (tscmp(&tmp, &drift->after_ts, >)) {
+ tssub(&drift->current_ts, &drift->since, &tmp);
+ if (tscmp(&tmp, &drift->time_ts, <)) {
+ drift->last.x += act->dx;
+ drift->last.y += act->dy;
+ } else {
+ /* discard old accumulated steps (drift) */
+ if (tscmp(&tmp, &drift->twotime_ts, >))
+ drift->previous.x = drift->previous.y = 0;
+ else
+ drift->previous = drift->last;
+ drift->last.x = act->dx;
+ drift->last.y = act->dy;
+ drift->since = drift->current_ts;
+ }
+ if ((u_int)abs(drift->last.x) + abs(drift->last.y) > drift->distance) {
+ /* real movement, pass all accumulated steps */
+ act->dx = drift->previous.x + drift->last.x;
+ act->dy = drift->previous.y + drift->last.y;
+ /* and reset accumulators */
+ tsclr(&drift->since);
+ drift->last.x = drift->last.y = 0;
+ /* drift_previous will be cleared at next movement*/
+ drift->last_activity = drift->current_ts;
+ } else {
+ return (true); /* don't pass current movement to
+ * console driver */
+ }
+ }
+ return (false);
+}
+
+static int
+r_statetrans(struct rodent *r, mousestatus_t *a1, mousestatus_t *a2, int trans)
+{
+ struct e3bstate *e3b = &r->e3b;
+ bool changed;
+ int flags;
+
+ a2->dx = a1->dx;
+ a2->dy = a1->dy;
+ a2->dz = a1->dz;
+ a2->obutton = a2->button;
+ a2->button = a1->button;
+ a2->flags = a1->flags;
+ changed = false;
+
+ if (!e3b->enabled)
+ return (false);
+
+ if (debug > 2)
+ debug("state:%d, trans:%d -> state:%d",
+ e3b->mouse_button_state, trans,
+ states[e3b->mouse_button_state].s[trans]);
+ /*
+ * Avoid re-ordering button and movement events. While a button
+ * event is deferred, throw away up to BUTTON2_MAXMOVE movement
+ * events to allow for mouse jitter. If more movement events
+ * occur, then complete the deferred button events immediately.
+ */
+ if ((a2->dx != 0 || a2->dy != 0) &&
+ S_DELAYED(states[e3b->mouse_button_state].s[trans])) {
+ if (++e3b->mouse_move_delayed > BUTTON2_MAXMOVE) {
+ e3b->mouse_move_delayed = 0;
+ e3b->mouse_button_state =
+ states[e3b->mouse_button_state].s[A_TIMEOUT];
+ changed = true;
+ } else
+ a2->dx = a2->dy = 0;
+ } else
+ e3b->mouse_move_delayed = 0;
+ if (e3b->mouse_button_state != states[e3b->mouse_button_state].s[trans])
+ changed = true;
+ if (changed)
+ clock_gettime(CLOCK_MONOTONIC_FAST,
+ &e3b->mouse_button_state_ts);
+ e3b->mouse_button_state = states[e3b->mouse_button_state].s[trans];
+ a2->button &= ~(MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN |
+ MOUSE_BUTTON3DOWN);
+ a2->button &= states[e3b->mouse_button_state].mask;
+ a2->button |= states[e3b->mouse_button_state].buttons;
+ flags = a2->flags & MOUSE_POSCHANGED;
+ flags |= a2->obutton ^ a2->button;
+ if (flags & MOUSE_BUTTON2DOWN) {
+ a2->flags = flags & MOUSE_BUTTON2DOWN;
+ r_timestamp(a2, &r->btstate, e3b, &r->drift);
+ }
+ a2->flags = flags;
+
+ return (changed);
+}
+
+static char *
+skipspace(char *s)
+{
+ while(isspace(*s))
+ ++s;
+ return (s);
+}
+
+static bool
+r_installmap(char *arg, struct btstate *bt)
+{
+ u_long pbutton;
+ u_long lbutton;
+ char *s;
+
+ while (*arg) {
+ arg = skipspace(arg);
+ s = arg;
+ while (isdigit(*arg))
+ ++arg;
+ arg = skipspace(arg);
+ if ((arg <= s) || (*arg != '='))
+ return (false);
+ lbutton = strtoul(s, NULL, 10);
+
+ arg = skipspace(++arg);
+ s = arg;
+ while (isdigit(*arg))
+ ++arg;
+ if ((arg <= s) || (!isspace(*arg) && (*arg != '\0')))
+ return (false);
+ pbutton = strtoul(s, NULL, 10);
+
+ if (lbutton == 0 || lbutton > MOUSE_MAXBUTTON)
+ return (false);
+ if (pbutton == 0 || pbutton > MOUSE_MAXBUTTON)
+ return (false);
+ bt->p2l[pbutton - 1] = 1 << (lbutton - 1);
+ bt->mstate[lbutton - 1] = &bt->bstate[pbutton - 1];
+ }
+
+ return (true);
+}
+
+static char *
+r_installzmap(char **argv, int argc, int* idx, struct btstate *bt)
+{
+ char *arg, *errstr;
+ u_long i, j;
+
+ arg = argv[*idx];
+ ++*idx;
+ if (strcmp(arg, "x") == 0) {
+ bt->zmap[0] = MOUSE_XAXIS;
+ return (NULL);
+ }
+ if (strcmp(arg, "y") == 0) {
+ bt->zmap[0] = MOUSE_YAXIS;
+ return (NULL);
+ }
+ i = strtoul(arg, NULL, 10);
+ /*
+ * Use button i for negative Z axis movement and
+ * button (i + 1) for positive Z axis movement.
+ */
+ if (i == 0 || i >= MOUSE_MAXBUTTON) {
+ asprintf(&errstr, "invalid argument `%s'", arg);
+ return (errstr);
+ }
+ bt->zmap[0] = i;
+ bt->zmap[1] = i + 1;
+ debug("optind: %d, optarg: '%s'", *idx, arg);
+ for (j = 1; j < ZMAP_MAXBUTTON; ++j) {
+ if ((*idx >= argc) || !isdigit(*argv[*idx]))
+ break;
+ i = strtoul(argv[*idx], NULL, 10);
+ if (i == 0 || i >= MOUSE_MAXBUTTON) {
+ asprintf(&errstr, "invalid argument `%s'", argv[*idx]);
+ return (errstr);
+ }
+ bt->zmap[j] = i;
+ ++*idx;
+ }
+ if ((bt->zmap[2] != 0) && (bt->zmap[3] == 0))
+ bt->zmap[3] = bt->zmap[2] + 1;
+
+ return (NULL);
+}
+
+static void
+r_map(mousestatus_t *act1, mousestatus_t *act2, struct btstate *bt)
+{
+ int pb;
+ int pbuttons;
+ int lbuttons;
+
+ pbuttons = act1->button;
+ lbuttons = 0;
+
+ act2->obutton = act2->button;
+ if (pbuttons & bt->wmode) {
+ pbuttons &= ~bt->wmode;
+ act1->dz = act1->dy;
+ act1->dx = 0;
+ act1->dy = 0;
+ }
+ act2->dx = act1->dx;
+ act2->dy = act1->dy;
+ act2->dz = act1->dz;
+
+ switch (bt->zmap[0]) {
+ case 0: /* do nothing */
+ break;
+ case MOUSE_XAXIS:
+ if (act1->dz != 0) {
+ act2->dx = act1->dz;
+ act2->dz = 0;
+ }
+ break;
+ case MOUSE_YAXIS:
+ if (act1->dz != 0) {
+ act2->dy = act1->dz;
+ act2->dz = 0;
+ }
+ break;
+ default: /* buttons */
+ pbuttons &= ~(bt->zmap[0] | bt->zmap[1]
+ | bt->zmap[2] | bt->zmap[3]);
+ if ((act1->dz < -1) && bt->zmap[2]) {
+ pbuttons |= bt->zmap[2];
+ bt->zstate[2].count = 1;
+ } else if (act1->dz < 0) {
+ pbuttons |= bt->zmap[0];
+ bt->zstate[0].count = 1;
+ } else if ((act1->dz > 1) && bt->zmap[3]) {
+ pbuttons |= bt->zmap[3];
+ bt->zstate[3].count = 1;
+ } else if (act1->dz > 0) {
+ pbuttons |= bt->zmap[1];
+ bt->zstate[1].count = 1;
+ }
+ act2->dz = 0;
+ break;
+ }
+
+ for (pb = 0; (pb < MOUSE_MAXBUTTON) && (pbuttons != 0); ++pb) {
+ lbuttons |= (pbuttons & 1) ? bt->p2l[pb] : 0;
+ pbuttons >>= 1;
+ }
+ act2->button = lbuttons;
+
+ act2->flags =
+ ((act2->dx || act2->dy || act2->dz) ? MOUSE_POSCHANGED : 0)
+ | (act2->obutton ^ act2->button);
+}
+
+static void
+r_timestamp(mousestatus_t *act, struct btstate *bt, struct e3bstate *e3b,
+ struct drift *drift)
+{
+ struct timespec ts;
+ struct timespec ts1;
+ struct timespec ts2;
+ int button;
+ int mask;
+ int i;
+
+ mask = act->flags & MOUSE_BUTTONS;
+#if 0
+ if (mask == 0)
+ return;
+#endif
+
+ clock_gettime(CLOCK_MONOTONIC_FAST, &ts1);
+ drift->current_ts = ts1;
+
+ /* double click threshold */
+ ts = tssubms(&ts1, bt->clickthreshold);
+ debug("ts: %jd %ld", (intmax_t)ts.tv_sec, ts.tv_nsec);
+
+ /* 3 button emulation timeout */
+ ts2 = tssubms(&ts1, e3b->button2timeout);
+
+ button = MOUSE_BUTTON1DOWN;
+ for (i = 0; (i < MOUSE_MAXBUTTON) && (mask != 0); ++i) {
+ if (mask & 1) {
+ if (act->button & button) {
+ /* the button is down */
+ debug(" : %jd %ld",
+ (intmax_t)bt->bstate[i].ts.tv_sec,
+ bt->bstate[i].ts.tv_nsec);
+ if (tscmp(&ts, &bt->bstate[i].ts, >)) {
+ bt->bstate[i].count = 1;
+ } else {
+ ++bt->bstate[i].count;
+ }
+ bt->bstate[i].ts = ts1;
+ } else {
+ /* the button is up */
+ bt->bstate[i].ts = ts1;
+ }
+ } else {
+ if (act->button & button) {
+ /* the button has been down */
+ if (tscmp(&ts2, &bt->bstate[i].ts, >)) {
+ bt->bstate[i].count = 1;
+ bt->bstate[i].ts = ts1;
+ act->flags |= button;
+ debug("button %d timeout", i + 1);
+ }
+ } else {
+ /* the button has been up */
+ }
+ }
+ button <<= 1;
+ mask >>= 1;
+ }
+}
+
+static bool
+r_timeout(struct e3bstate *e3b)
+{
+ struct timespec ts;
+ struct timespec ts1;
+
+ if (states[e3b->mouse_button_state].timeout)
+ return (true);
+ clock_gettime(CLOCK_MONOTONIC_FAST, &ts1);
+ ts = tssubms(&ts1, e3b->button2timeout);
+ return (tscmp(&ts, &e3b->mouse_button_state_ts, >));
+}
+
+static void
+r_move(mousestatus_t *act, struct accel *acc)
+{
+ struct mouse_info mouse;
+
+ bzero(&mouse, sizeof(mouse));
+ if (acc->is_exponential) {
+ expoacc(acc, act->dx, act->dy, act->dz,
+ &mouse.u.data.x, &mouse.u.data.y, &mouse.u.data.z);
+ } else {
+ linacc(acc, act->dx, act->dy, act->dz,
+ &mouse.u.data.x, &mouse.u.data.y, &mouse.u.data.z);
+ }
+ mouse.operation = MOUSE_MOTION_EVENT;
+ mouse.u.data.buttons = act->button;
+ if (debug < 2 && !paused)
+ ioctl(cfd, CONS_MOUSECTL, &mouse);
+}
+
+static void
+r_click(mousestatus_t *act, struct btstate *bt)
+{
+ struct mouse_info mouse;
+ int button;
+ int mask;
+ int i;
+
+ mask = act->flags & MOUSE_BUTTONS;
+ if (mask == 0)
+ return;
+
+ button = MOUSE_BUTTON1DOWN;
+ for (i = 0; (i < MOUSE_MAXBUTTON) && (mask != 0); ++i) {
+ if (mask & 1) {
+ debug("mstate[%d]->count:%d", i, bt->mstate[i]->count);
+ if (act->button & button) {
+ /* the button is down */
+ mouse.u.event.value = bt->mstate[i]->count;
+ } else {
+ /* the button is up */
+ mouse.u.event.value = 0;
+ }
+ mouse.operation = MOUSE_BUTTON_EVENT;
+ mouse.u.event.id = button;
+ if (debug < 2 && !paused)
+ ioctl(cfd, CONS_MOUSECTL, &mouse);
+ debug("button %d count %d", i + 1,
+ mouse.u.event.value);
+ }
+ button <<= 1;
+ mask >>= 1;
+ }
+}
+
+static enum gesture
+r_gestures(struct tpad *tp, int x0, int y0, u_int z, int w, int nfingers,
+ struct timespec *time, mousestatus_t *ms)
+{
+ struct tpstate *gest = &tp->gest;
+ const struct tpcaps *tphw = &tp->hw;
+ const struct tpinfo *tpinfo = &tp->info;
+ int tap_timeout = tpinfo->tap_timeout;
+
+ /*
+ * Check pressure to detect a real wanted action on the
+ * touchpad.
+ */
+ if (z >= tpinfo->min_pressure_hi ||
+ (gest->fingerdown && z >= tpinfo->min_pressure_lo)) {
+ /* XXX Verify values? */
+ bool two_finger_scroll = tpinfo->two_finger_scroll;
+ bool three_finger_drag = tpinfo->three_finger_drag;
+ int max_width = tpinfo->max_width;
+ u_int max_pressure = tpinfo->max_pressure;
+ int margin_top = tpinfo->margin_top;
+ int margin_right = tpinfo->margin_right;
+ int margin_bottom = tpinfo->margin_bottom;
+ int margin_left = tpinfo->margin_left;
+ int vscroll_hor_area = tpinfo->vscroll_hor_area * tphw->res_x;
+ int vscroll_ver_area = tpinfo->vscroll_ver_area * tphw->res_y;;
+
+ int max_x = tphw->max_x;
+ int max_y = tphw->max_y;
+ int min_x = tphw->min_x;
+ int min_y = tphw->min_y;
+
+ int dx, dy;
+ int start_x, start_y;
+ int tap_max_delta_x, tap_max_delta_y;
+ int prev_nfingers;
+
+ /* Palm detection. */
+ if (nfingers == 1 &&
+ ((tphw->cap_width && w > max_width) ||
+ (tphw->cap_pressure && z > max_pressure))) {
+ /*
+ * We consider the packet irrelevant for the current
+ * action when:
+ * - there is a single active touch
+ * - the width isn't comprised in:
+ * [0; max_width]
+ * - the pressure isn't comprised in:
+ * [min_pressure; max_pressure]
+ *
+ * Note that this doesn't terminate the current action.
+ */
+ debug("palm detected! (%d)", z);
+ return(GEST_IGNORE);
+ }
+
+ /*
+ * Limit the coordinates to the specified margins because
+ * this area isn't very reliable.
+ */
+ if (margin_left != 0 && x0 <= min_x + margin_left)
+ x0 = min_x + margin_left;
+ else if (margin_right != 0 && x0 >= max_x - margin_right)
+ x0 = max_x - margin_right;
+ if (margin_bottom != 0 && y0 <= min_y + margin_bottom)
+ y0 = min_y + margin_bottom;
+ else if (margin_top != 0 && y0 >= max_y - margin_top)
+ y0 = max_y - margin_top;
+
+ debug("packet: [%d, %d], %d, %d", x0, y0, z, w);
+
+ /*
+ * If the action is just beginning, init the structure and
+ * compute tap timeout.
+ */
+ if (!gest->fingerdown) {
+ debug("----");
+
+ /* Reset pressure peak. */
+ gest->zmax = 0;
+
+ /* Reset fingers count. */
+ gest->fingers_nb = 0;
+
+ /* Reset virtual scrolling state. */
+ gest->in_vscroll = 0;
+
+ /* Compute tap timeout. */
+ if (tap_timeout != 0)
+ gest->taptimeout = tsaddms(time, tap_timeout);
+ else
+ tsclr(&gest->taptimeout);
+
+ gest->fingerdown = true;
+
+ gest->start_x = x0;
+ gest->start_y = y0;
+ }
+
+ prev_nfingers = gest->prev_nfingers;
+
+ gest->prev_x = x0;
+ gest->prev_y = y0;
+ gest->prev_nfingers = nfingers;
+
+ start_x = gest->start_x;
+ start_y = gest->start_y;
+
+ /* Process ClickPad softbuttons */
+ if (tphw->is_clickpad && ms->button & MOUSE_BUTTON1DOWN) {
+ int y_ok, center_bt, center_x, right_bt, right_x;
+ y_ok = tpinfo->softbuttons_y < 0
+ ? start_y < min_y - tpinfo->softbuttons_y
+ : start_y > max_y - tpinfo->softbuttons_y;
+
+ center_bt = MOUSE_BUTTON2DOWN;
+ center_x = min_x + tpinfo->softbutton2_x;
+ right_bt = MOUSE_BUTTON3DOWN;
+ right_x = min_x + tpinfo->softbutton3_x;
+
+ if (center_x > 0 && right_x > 0 && center_x > right_x) {
+ center_bt = MOUSE_BUTTON3DOWN;
+ center_x = min_x + tpinfo->softbutton3_x;
+ right_bt = MOUSE_BUTTON2DOWN;
+ right_x = min_x + tpinfo->softbutton2_x;
+ }
+
+ if (right_x > 0 && start_x > right_x && y_ok)
+ ms->button = (ms->button &
+ ~MOUSE_BUTTON1DOWN) | right_bt;
+ else if (center_x > 0 && start_x > center_x && y_ok)
+ ms->button = (ms->button &
+ ~MOUSE_BUTTON1DOWN) | center_bt;
+ }
+
+ /* If in tap-hold or three fingers, add the recorded button. */
+ if (gest->in_taphold || (nfingers == 3 && three_finger_drag))
+ ms->button |= gest->tap_button;
+
+ /*
+ * For tap, we keep the maximum number of fingers and the
+ * pressure peak.
+ */
+ gest->fingers_nb = MAX(nfingers, gest->fingers_nb);
+ gest->zmax = MAX(z, gest->zmax);
+
+ dx = abs(x0 - start_x);
+ dy = abs(y0 - start_y);
+
+ /*
+ * A scrolling action must not conflict with a tap action.
+ * Here are the conditions to consider a scrolling action:
+ * - the action in a configurable area
+ * - one of the following:
+ * . the distance between the last packet and the
+ * first should be above a configurable minimum
+ * . tap timed out
+ */
+ if (!gest->in_taphold && !ms->button &&
+ (!gest->in_vscroll || two_finger_scroll) &&
+ (tscmp(time, &gest->taptimeout, >) ||
+ ((gest->fingers_nb == 2 || !two_finger_scroll) &&
+ (dx >= tpinfo->vscroll_min_delta * tphw->res_x ||
+ dy >= tpinfo->vscroll_min_delta * tphw->res_y)))) {
+ /*
+ * Handle two finger scrolling.
+ * Note that we don't rely on fingers_nb
+ * as that keeps the maximum number of fingers.
+ */
+ if (two_finger_scroll) {
+ if (nfingers == 2) {
+ gest->in_vscroll += dy ? 2 : 0;
+ gest->in_vscroll += dx ? 1 : 0;
+ }
+ } else {
+ /* Check for horizontal scrolling. */
+ if ((vscroll_hor_area > 0 &&
+ start_y <= min_y + vscroll_hor_area) ||
+ (vscroll_hor_area < 0 &&
+ start_y >= max_y + vscroll_hor_area))
+ gest->in_vscroll += 2;
+
+ /* Check for vertical scrolling. */
+ if ((vscroll_ver_area > 0 &&
+ start_x <= min_x + vscroll_ver_area) ||
+ (vscroll_ver_area < 0 &&
+ start_x >= max_x + vscroll_ver_area))
+ gest->in_vscroll += 1;
+ }
+ /* Avoid conflicts if area overlaps. */
+ if (gest->in_vscroll >= 3)
+ gest->in_vscroll = (dx > dy) ? 2 : 1;
+ }
+ /*
+ * Reset two finger scrolling when the number of fingers
+ * is different from two or any button is pressed.
+ */
+ if (two_finger_scroll && gest->in_vscroll != 0 &&
+ (nfingers != 2 || ms->button))
+ gest->in_vscroll = 0;
+
+ debug("virtual scrolling: %s "
+ "(direction=%d, dx=%d, dy=%d, fingers=%d)",
+ gest->in_vscroll != 0 ? "YES" : "NO",
+ gest->in_vscroll, dx, dy, gest->fingers_nb);
+
+ /* Workaround cursor jump on finger set changes */
+ if (prev_nfingers != nfingers)
+ return (GEST_IGNORE);
+
+ switch (gest->in_vscroll) {
+ case 1:
+ return (GEST_VSCROLL);
+ case 2:
+ return (GEST_HSCROLL);
+ default:
+ /* NO-OP */;
+ }
+
+ /* Max delta is disabled for multi-fingers tap. */
+ if (gest->fingers_nb == 1 &&
+ tscmp(time, &gest->taptimeout, <=)) {
+ tap_max_delta_x = tpinfo->tap_max_delta * tphw->res_x;
+ tap_max_delta_y = tpinfo->tap_max_delta * tphw->res_y;
+
+ debug("dx=%d, dy=%d, deltax=%d, deltay=%d",
+ dx, dy, tap_max_delta_x, tap_max_delta_y);
+ if (dx > tap_max_delta_x || dy > tap_max_delta_y) {
+ debug("not a tap");
+ tsclr(&gest->taptimeout);
+ }
+ }
+
+ if (tscmp(time, &gest->taptimeout, <=))
+ return (gest->fingers_nb > 1 ?
+ GEST_IGNORE : GEST_ACCUMULATE);
+ else
+ return (GEST_MOVE);
+ }
+
+ /*
+ * Handle a case when clickpad pressure drops before than
+ * button up event when surface is released after click.
+ * It interferes with softbuttons.
+ */
+ if (tphw->is_clickpad && tpinfo->softbuttons_y != 0)
+ ms->button &= ~MOUSE_BUTTON1DOWN;
+
+ gest->prev_nfingers = 0;
+
+ if (gest->fingerdown) {
+ /*
+ * An action is currently taking place but the pressure
+ * dropped under the minimum, putting an end to it.
+ */
+
+ gest->fingerdown = false;
+
+ /* Check for tap. */
+ debug("zmax=%d fingers=%d", gest->zmax, gest->fingers_nb);
+ if (!gest->in_vscroll && gest->zmax >= tpinfo->tap_threshold &&
+ tscmp(time, &gest->taptimeout, <=)) {
+ /*
+ * We have a tap if:
+ * - the maximum pressure went over tap_threshold
+ * - the action ended before tap_timeout
+ *
+ * To handle tap-hold, we must delay any button push to
+ * the next action.
+ */
+ if (gest->in_taphold) {
+ /*
+ * This is the second and last tap of a
+ * double tap action, not a tap-hold.
+ */
+ gest->in_taphold = false;
+
+ /*
+ * For double-tap to work:
+ * - no button press is emitted (to
+ * simulate a button release)
+ * - PSM_FLAGS_FINGERDOWN is set to
+ * force the next packet to emit a
+ * button press)
+ */
+ debug("button RELEASE: %d", gest->tap_button);
+ gest->fingerdown = true;
+
+ /* Schedule button press on next event */
+ gest->idletimeout = 0;
+ } else {
+ /*
+ * This is the first tap: we set the
+ * tap-hold state and notify the button
+ * down event.
+ */
+ gest->in_taphold = true;
+ gest->idletimeout = tpinfo->taphold_timeout;
+ gest->taptimeout = tsaddms(time, tap_timeout);
+
+ switch (gest->fingers_nb) {
+ case 3:
+ gest->tap_button =
+ MOUSE_BUTTON2DOWN;
+ break;
+ case 2:
+ gest->tap_button =
+ MOUSE_BUTTON3DOWN;
+ break;
+ default:
+ gest->tap_button =
+ MOUSE_BUTTON1DOWN;
+ }
+ debug("button PRESS: %d", gest->tap_button);
+ ms->button |= gest->tap_button;
+ }
+ } else {
+ /*
+ * Not enough pressure or timeout: reset
+ * tap-hold state.
+ */
+ if (gest->in_taphold) {
+ debug("button RELEASE: %d", gest->tap_button);
+ gest->in_taphold = false;
+ } else {
+ debug("not a tap-hold");
+ }
+ }
+ } else if (!gest->fingerdown && gest->in_taphold) {
+ /*
+ * For a tap-hold to work, the button must remain down at
+ * least until timeout (where the in_taphold flags will be
+ * cleared) or during the next action.
+ */
+ if (tscmp(time, &gest->taptimeout, <=)) {
+ ms->button |= gest->tap_button;
+ } else {
+ debug("button RELEASE: %d", gest->tap_button);
+ gest->in_taphold = false;
+ }
+ }
+
+ return (GEST_IGNORE);
+}
diff --git a/usr.sbin/moused/moused/moused.conf b/usr.sbin/moused/moused/moused.conf
new file mode 100644
index 000000000000..04970c820c7f
--- /dev/null
+++ b/usr.sbin/moused/moused/moused.conf
@@ -0,0 +1,43 @@
+[Default]
+MatchName=*
+
+MousedGrabDevice=0 # 1/0
+MousedIgnoreDevice=0 # 1/0
+
+MousedClickThreshold=500 # ms
+MousedEmulateThirdButton=0 # 1/0
+MousedEmulateThirdButtonTimeout=100 # ms
+MousedExponentialAccel=1.3 # float
+MousedExponentialOffset=2.0 # dots
+MousedLinearAccelX=1.0 # float
+MousedLinearAccelY=1.0 # float
+MousedLinearAccelZ=1.0 # float
+#MousedMapZAxis=0
+MousedVirtualScrollEnable=0 # 1/0
+MousedHorVirtualScrollEnable=0 # 1/0
+MousedVirtualScrollSpeed=2 # dots
+MousedVirtualScrollThreshold=3 # dots
+MousedWMode=0 # button num
+
+[Mouse drift termination]
+MatchDevType=mouse # mouse/touchpad
+MousedDriftTerminate=0 # 1/0
+MousedDriftDistance=4 # dots
+MousedDriftTime=500 # ms
+MousedDriftAfter=4000 # ms
+
+[Default touchpad gesture settings]
+MatchDevType=touchpad # mouse/touchpad
+MousedTwoFingerScroll=1 # 1/0
+MousedNaturalScroll=0 # 1/0
+MousedThreeFingerDrag=0 # 1/0
+MousedSoftButton2X=42 # pct
+MousedSoftButton3X=58 # pct
+MousedSoftButtonsY=25 # pct
+MousedTapTimeout=180 # ms
+#MousedTapPressureThreshold=20
+MousedTapMaxDelta=1.3 # mm
+MousedTapholdTimeout=300 # ms
+MousedVScrollMinDelta=1.25 # mm
+MousedVScrollHorArea=0.0 # mm
+MousedVScrollVerArea=-15.0 # mm
diff --git a/usr.sbin/moused/moused/moused.conf.5 b/usr.sbin/moused/moused/moused.conf.5
new file mode 100644
index 000000000000..bc62b5d00995
--- /dev/null
+++ b/usr.sbin/moused/moused/moused.conf.5
@@ -0,0 +1,422 @@
+.\" SPDX-License-Identifier: BSD-2-Clause
+.\"
+.\" Copyright (c) 2025 Vladimir Kondratyev <wulf@FreeBSD.org>
+.\"
+.\" 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.
+.\"
+.Dd May 19, 2025
+.Dt MOUSED.CONF 5
+.Os
+.Sh NAME
+.Nm moused.conf
+.Nd mouse daemon configuration file
+.Sh DESCRIPTION
+The
+.Nm
+file specifies how the
+.Xr moused 8
+(mouse daemon) should operate. It provides ability to adjust certain
+mice parameters on per-device basis.
+.Pp
+Configuration file format is derrived from
+.Xr libinput 1
+device quirk files.
+A file may contain multiple section headers ([some identifier])
+followed by one or more MatchFoo=Bar directives, followed by at least
+one of MousedFoo=bar or AttrFoo=bar directive.
+A configuration file must contain at least one section, each section
+must have at least one
+.Sq Match
+tag and at least one of either
+.Sq Attr
+or
+.Sq Moused .
+Section names are free-form and may contain spaces.
+.Ss List of currently available matches.
+.Bl -tag -width indent
+.It MatchName, MatchUniq
+Match on the NAME or UNIQ udev property on this device. These
+properties are typically derived from the device’s kernel name or uniq.
+These matches use
+.Fn fnmatch
+globs.
+.It MatchBus
+A lower-case bus name. Currently supported are usb, bluetooth, ps2,
+rmi, i2c, and spi.
+.It MatchVendor, MatchProduct, MatchVersion
+The hexadecmial 4-digit vendor ID, product ID or driver version as
+exported, without a 0x prefix.
+.It MatchDMIModalias, MatchDeviceTree
+An
+.Fn fnmatch
+glob for the DMI modalias or the DeviceTree compatible string.
+.It MatchDevType
+One of touchpad, mouse, pointingstick, keyboard, joystick, tablet,
+tablet-pad.
+Only touchpad and mouse types are suppported.
+.El
+.Ss List of currently available Moused tags.
+.Bl -tag -width indent
+.It MousedGrabDevice
+Only for evdev interface.
+Become the sole recipient of all incoming input events.
+This prevents other processes from getting input events on the device.
+.Pp
+Use
+.Fl g
+option alternatively.
+.It MousedIgnoreDevice
+Ignore given device.
+.It MousedClickThreshold
+Set double click speed as the maximum interval in msec between button clicks.
+Without this option, the default value of 500 msec will be assumed.
+This option will have effect only on the cut and paste operations
+in the text mode console.
+The user program which is reading mouse data
+via
+.Xr sysmouse 4
+will not be affected.
+.Pp
+Use
+.Fl C
+option alternatively.
+.It MousedEmulateThirdButton
+Emulate the third (middle) button for 2-button mice.
+It is emulated
+by pressing the left and right physical buttons simultaneously.
+.Pp
+Use
+.Fl 3
+option alternatively.
+.It MousedEmulateThirdButtonTimeout
+When the third button emulation is enabled
+(see above),
+the
+.Xr moused 8
+utility waits
+.Ar MousedEmulateThirdButtonTimeout
+msec at most before deciding whether two buttons are being pressed
+simultaneously.
+The default timeout is 100 msec.
+.Pp
+Use
+.Fl E
+option alternatively.
+.It MousedLinearAccelX
+.It MousedLinearAccelY
+.It MousedLinearAccelZ
+Accelerate or decelerate the mouse input.
+This is a linear acceleration only.
+Values less than 1.0 slow down movement, values greater than 1.0 speed it
+up.
+.Pp
+You can use the
+.Ar MousedLinearAccel
+and
+.Ar MousedExponentialAccel
+options at the same time to have the combined effect
+of linear and exponential acceleration.
+.Pp
+Use
+.Fl a
+option alternatively.
+.It MousedExponentialAccel
+.It MousedExponentialOffset
+Apply exponential (dynamic) acceleration to mouse movements:
+the faster you move the mouse, the more it will be accelerated.
+That means that small mouse movements are not accelerated,
+so they are still very accurate, while a faster movement will
+drive the pointer quickly across the screen.
+.Pp
+The
+.Ar MousedExponentialAccel
+value specifies the exponent, which is basically
+the amount of acceleration. Useful values are in the
+range 1.1 to 2.0, but it depends on your mouse hardware
+and your personal preference. A value of 1.0 means no
+exponential acceleration. A value of 2.0 means squared
+acceleration (i.e. if you move the mouse twice as fast,
+the pointer will move four times as fast on the screen).
+Values beyond 2.0 are possible but not recommended.
+A good value to start is probably 1.5.
+.Pp
+The optional
+.Ar MousedExponentialOffset
+value specifies the distance at which the acceleration
+begins. The default is 1.0, which means that the
+acceleration is applied to movements larger than one unit.
+If you specify a larger value, it takes more speed for
+the acceleration to kick in, i.e. the speed range for
+small and accurate movements is wider.
+Usually the default should be sufficient, but if you're
+not satisfied with the behaviour, try a value of 2.0.
+.Pp
+Note that the
+.Fl A
+option interacts badly with the X server's own acceleration,
+which doesn't work very well anyway. Therefore it is
+recommended to switch it off if necessary:
+.Dq xset m 1 .
+.Pp
+Use
+.Fl A
+option alternatively.
+.It MousedMapZAxis
+Map Z axis (roller/wheel) movement to another axis or to virtual buttons.
+Does not supported yet.
+Use
+.Fl z
+option instead.
+.It MousedVirtualScrollEnable
+Enable
+.Dq Virtual Scrolling .
+With this option set, holding the middle mouse
+button down will cause motion to be interpreted as scrolling.
+Use the
+.Ar MousedVirtualScrollThreshold
+option to set the distance the mouse must move before the scrolling mode is
+activated and the
+.Ar MousedVirtualScrollSpeed
+option to set the scrolling speed.
+.Pp
+Use
+.Fl V
+option alternatively.
+.It MousedHorVirtualScrollEnable
+Enable
+.Dq Horizontal Virtual Scrolling .
+With this option set, holding the middle mouse
+button down will cause motion to be interpreted as
+horizontal scrolling.
+Use the
+.Ar MousedVirtualScrollThreshold
+option to set the distance the mouse must move before the scrolling mode is
+activated and the
+.Ar MousedVirtualScrollSpeed
+option to set the scrolling speed.
+This option may be used with or without the
+.Ar MousedVirtualScrollEnable
+option.
+.Pp
+Use
+.Fl H
+option alternatively.
+.It MousedVirtualScrollSpeed= Ar distance
+When
+.Dq Virtual Scrolling
+is enabled, the
+.Ar MousedVirtualScrollSpeed
+option can be used to set the
+.Ar distance
+(in pixels) that the mouse must move before a scroll event
+is generated.
+This effectively controls the scrolling speed.
+The default
+.Ar distance
+is 2 pixels.
+.Pp
+Use
+.Fl L
+option alternatively.
+.It MousedVirtualScrollThreshold= Ar distance
+When
+.Dq Virtual Scrolling
+is enabled, the
+.Ar MousedVirtualScrollThreshold
+option can be used to set the
+.Ar distance
+(in pixels) that the mouse must move before the scrolling
+mode is activated.
+The default
+.Ar distance
+is 3 pixels.
+.Pp
+Use
+.Fl U
+option alternatively.
+.It MousedWMode= Ar N
+Make the physical button
+.Ar N
+act as the wheel mode button.
+While this button is pressed, X and Y axis movement is reported to be zero
+and the Y axis movement is mapped to Z axis.
+You may further map the Z axis movement to virtual buttons by the
+.Ar MousedMapZAxis
+tag.
+.Pp
+Use
+.Fl w
+option alternatively.
+.El
+.Ss List of currently available Moused mice specific tags.
+.Bl -tag -width indent
+.It MousedDriftTerminate
+.It MousedDriftDistance
+.It MousedDriftTime
+.It MousedDriftAfter
+Terminate drift.
+Use this option if mouse pointer slowly wanders when mouse is not moved.
+Movements up to
+.Ar MousedDriftDistance
+(for example 4) pixels (X+Y) in
+.Ar MousedDriftTime
+msec (default 500) are ignored, except during
+.Ar MousedDriftAfter
+msec (default 4000) since last real mouse movement.
+.Pp
+Use
+.Fl T
+option alternatively.
+.El
+.Ss List of currently available Moused touchpad specific tags.
+.Bl -tag -width indent
+.It MousedTwoFingerScroll
+Enable two finger scrolling.
+.It MousedNaturalScroll
+Enable natural scrolling.
+.It MousedThreeFingerDrag
+Enable dragging with three fingers.
+.It MousedSoftButton2X
+Horisontal position of 2-nd softbutton left edge in percents.
+(0-disable)
+.It MousedSoftButton3X
+Horisontal position of 3-rd softbutton left edge in percents.
+(0-disable)
+.It MousedSoftButtonsY
+Vertical size of softbuttons area in percents.
+Use negative values to place softbutton area at top of touchpad.
+.It MousedTapTimeout
+Tap timeout in milliseconds
+.It MousedTapPressureThreshold
+Pressure threshold to detect tap.
+.It MousedTapMaxDelta
+Length of finger movement above which a tap is ignored measured in mm.
+.It MousedTapholdTimeout
+Maximum elapsed time between two taps to consider a tap-hold action.
+.It MousedVScrollMinDelta
+Minimum movement to consider virtual scrolling.
+.It MousedVScrollHorArea
+ Area reserved for horizontal virtual scrolling in mm.
+.It MousedVScrollVerArea
+Area reserved for vertical virtual scrolling in mm.
+.El
+.Ss List of currently available libinput-compatible tags.
+.Bl -tag -width indent
+.It AttrSizeHint
+Hints at the width x height of the device in mm.
+.It AttrTouchSizeRange
+Not supported yet.
+.It AttrPalmSizeThreshold
+Maximum finger width to detect palm in mm.
+.It AttrLidSwitchReliability
+Not supported yet.
+.It AttrKeyboardIntegration
+Not supported yet.
+.It AttrPointingStickIntegration
+Not supported yet.
+.It AttrTPKComboLayout
+Not supported yet.
+.It AttrPressureRange= Ar N : Ar M
+Specifies the touch pressure required to trigger a press
+.Ar N
+and to trigger a release
+.Ar M .
+.It AttrPalmPressureThreshold
+Maximum pressure to detect palm.
+.It AttrResolutionHint
+Hints at the resolution of the x/y axis in units/mm.
+.It AttrTrackpointMultiplier
+Not supported yet.
+.It AttrThumbPressureThreshold
+Not supported yet.
+.It AttrUseVelocityAveraging
+Not supported yet.
+.It AttrTabletSmoothing
+Not supported yet.
+.It AttrThumbSizeThreshold
+Not supported yet.
+.It AttrMscTimestamp
+Not supported yet.
+.It AttrEventCode
+Enables or disables the evdev event type/code tuples on the device.
+The prefix for each entry is either
+.Sq +
+(enable) or
+.Sq -
+(disable).
+Entries may be a named event type, or a named event code, or a named
+event type with a hexadecimal event code, separated by a single colon.
+.It AttrInputProp
+Enables or disables the evdev input property on the device.
+The prefix for each entry is either
+,Sq +
+(enable) or
+.Sq -
+(disable).
+Entries may be a named input property or the hexadecimal value of that
+property.
+.El
+.Pp
+All
+.Xr libinput 1
+.Sq Model
+quirks are currently ignored.
+.Sh FILES
+.Bl -tag -width /usr/local/etc/moused.conf -compact
+.It Pa /usr/local/etc/moused.conf
+The file
+.Nm
+resides in
+.Pa /usr/local/etc .
+.It Pa /usr/local/share/moused/*.quirks
+Predefined quirks processed before
+.Nm .
+.El
+.Sh EXAMPLES
+Set touch pressure and palm detection thesholds for PS/2 Synaptics
+touchpad:
+.Bd -literal -offset indent
+[SynPS/2 Synaptics TouchPad]
+MatchDevType=touchpad
+MatchName=SynPS/2 Synaptics TouchPad
+AttrPressureRange=35:30
+AttrPalmPressureThreshold=220
+.Ed
+.Sh SEE ALSO
+.Xr moused 8
+.Pp
+.Xr libinput 1
+device quirk format:
+.Lk https://wayland.freedesktop.org/libinput/doc/latest/device-quirks.html
+.Sh HISTORY
+The
+.Nm
+file format first appeared in
+.Fx 15.0 .
+.Sh AUTHORS
+This manual page was written by
+.An Vladimir Kondratyev Aq Mt wulf@FreeBSD.org
+based on
+. Xr moused 8
+manual page and
+.Xr libinput 1
+documentation.
diff --git a/usr.sbin/moused/moused/quirks.c b/usr.sbin/moused/moused/quirks.c
new file mode 100644
index 000000000000..3b87b34419e9
--- /dev/null
+++ b/usr.sbin/moused/moused/quirks.c
@@ -0,0 +1,2033 @@
+/*
+ * Copyright © 2018 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/* This has the hallmarks of a library to make it re-usable from the tests
+ * and from the list-quirks tool. It doesn't have all of the features from a
+ * library you'd expect though
+ */
+
+#include <sys/types.h>
+#include <dev/evdev/input.h>
+
+#undef NDEBUG /* You don't get to disable asserts here */
+#include <assert.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fnmatch.h>
+#include <kenv.h>
+#include <libgen.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "quirks.h"
+#include "util.h"
+#include "util-list.h"
+
+
+/* Custom logging so we can have detailed output for the tool but minimal
+ * logging for moused itself. */
+#define qlog_debug(ctx_, ...) quirk_log_msg((ctx_), QLOG_NOISE, __VA_ARGS__)
+#define qlog_info(ctx_, ...) quirk_log_msg((ctx_), QLOG_INFO, __VA_ARGS__)
+#define qlog_error(ctx_, ...) quirk_log_msg((ctx_), QLOG_ERROR, __VA_ARGS__)
+#define qlog_parser(ctx_, ...) quirk_log_msg((ctx_), QLOG_PARSER_ERROR, __VA_ARGS__)
+
+enum property_type {
+ PT_UINT,
+ PT_INT,
+ PT_STRING,
+ PT_BOOL,
+ PT_DIMENSION,
+ PT_RANGE,
+ PT_DOUBLE,
+ PT_TUPLES,
+ PT_UINT_ARRAY,
+};
+
+struct quirk_array {
+ union {
+ uint32_t u[32];
+ } data;
+ size_t nelements;
+};
+
+/**
+ * Generic value holder for the property types we support. The type
+ * identifies which value in the union is defined and we expect callers to
+ * already know which type yields which value.
+ */
+struct property {
+ size_t refcount;
+ struct list link; /* struct sections.properties */
+
+ enum quirk id;
+ enum property_type type;
+ union {
+ bool b;
+ uint32_t u;
+ int32_t i;
+ char *s;
+ double d;
+ struct quirk_dimensions dim;
+ struct quirk_range range;
+ struct quirk_tuples tuples;
+ struct quirk_array array;
+ } value;
+};
+
+enum match_flags {
+ M_NAME = bit(0),
+ M_BUS = bit(1),
+ M_VID = bit(2),
+ M_PID = bit(3),
+ M_DMI = bit(4),
+ M_UDEV_TYPE = bit(5),
+ M_DT = bit(6),
+ M_VERSION = bit(7),
+ M_UNIQ = bit(8),
+
+ M_LAST = M_UNIQ,
+};
+
+enum bustype {
+ BT_UNKNOWN,
+ BT_USB,
+ BT_BLUETOOTH,
+ BT_PS2,
+ BT_RMI,
+ BT_I2C,
+ BT_SPI,
+};
+
+enum udev_type {
+ UDEV_MOUSE = bit(1),
+ UDEV_POINTINGSTICK = bit(2),
+ UDEV_TOUCHPAD = bit(3),
+ UDEV_TABLET = bit(4),
+ UDEV_TABLET_PAD = bit(5),
+ UDEV_JOYSTICK = bit(6),
+ UDEV_KEYBOARD = bit(7),
+};
+
+/**
+ * Contains the combined set of matches for one section or the values for
+ * one device.
+ *
+ * bits defines which fields are set, the rest is zero.
+ */
+struct match {
+ uint32_t bits;
+
+ char *name;
+ char *uniq;
+ enum bustype bus;
+ uint32_t vendor;
+ uint32_t product[64]; /* zero-terminated */
+ uint32_t version;
+
+ char *dmi; /* dmi modalias with preceding "dmi:" */
+
+ /* We can have more than one type set, so this is a bitfield */
+ uint32_t udev_type;
+
+ char *dt; /* device tree compatible (first) string */
+};
+
+/**
+ * Represents one section in the .quirks file.
+ */
+struct section {
+ struct list link;
+
+ bool has_match; /* to check for empty sections */
+ bool has_property; /* to check for empty sections */
+
+ char *name; /* the [Section Name] */
+ struct match match;
+ struct list properties;
+};
+
+/**
+ * The struct returned to the caller. It contains the
+ * properties for a given device.
+ */
+struct quirks {
+ size_t refcount;
+ struct list link; /* struct quirks_context.quirks */
+
+ /* These are not ref'd, just a collection of pointers */
+ struct property **properties;
+ size_t nproperties;
+
+ /* Special properties for AttrEventCode and AttrInputCode, these are
+ * owned by us, not the section */
+ struct list floating_properties;
+};
+
+/**
+ * Quirk matching context, initialized once with quirks_init_subsystem()
+ */
+struct quirks_context {
+ size_t refcount;
+
+ moused_log_handler *log_handler;
+ enum quirks_log_type log_type;
+
+ char *dmi;
+ char *dt;
+
+ struct list sections;
+
+ /* list of quirks handed to moused, just for bookkeeping */
+ struct list quirks;
+};
+
+MOUSED_ATTRIBUTE_PRINTF(3, 0)
+static inline void
+quirk_log_msg_va(struct quirks_context *ctx,
+ enum quirks_log_priorities priority,
+ const char *format,
+ va_list args)
+{
+ switch (priority) {
+ /* We don't use this if we're logging through syslog */
+ default:
+ case QLOG_NOISE:
+ case QLOG_PARSER_ERROR:
+ if (ctx->log_type == QLOG_MOUSED_LOGGING)
+ return;
+ break;
+ case QLOG_DEBUG: /* These map straight to syslog priorities */
+ case QLOG_INFO:
+ case QLOG_ERROR:
+ break;
+ }
+
+ ctx->log_handler(priority,
+ 0,
+ format,
+ args);
+}
+
+MOUSED_ATTRIBUTE_PRINTF(3, 4)
+static inline void
+quirk_log_msg(struct quirks_context *ctx,
+ enum quirks_log_priorities priority,
+ const char *format,
+ ...)
+{
+ va_list args;
+
+ va_start(args, format);
+ quirk_log_msg_va(ctx, priority, format, args);
+ va_end(args);
+
+}
+
+const char *
+quirk_get_name(enum quirk q)
+{
+ switch(q) {
+ case QUIRK_MODEL_ALPS_SERIAL_TOUCHPAD: return "ModelALPSSerialTouchpad";
+ case QUIRK_MODEL_APPLE_TOUCHPAD: return "ModelAppleTouchpad";
+ case QUIRK_MODEL_APPLE_TOUCHPAD_ONEBUTTON: return "ModelAppleTouchpadOneButton";
+ case QUIRK_MODEL_BOUNCING_KEYS: return "ModelBouncingKeys";
+ case QUIRK_MODEL_CHROMEBOOK: return "ModelChromebook";
+ case QUIRK_MODEL_CLEVO_W740SU: return "ModelClevoW740SU";
+ case QUIRK_MODEL_DELL_CANVAS_TOTEM: return "ModelDellCanvasTotem";
+ case QUIRK_MODEL_HP_PAVILION_DM4_TOUCHPAD: return "ModelHPPavilionDM4Touchpad";
+ case QUIRK_MODEL_HP_ZBOOK_STUDIO_G3: return "ModelHPZBookStudioG3";
+ case QUIRK_MODEL_INVERT_HORIZONTAL_SCROLLING: return "ModelInvertHorizontalScrolling";
+ case QUIRK_MODEL_LENOVO_SCROLLPOINT: return "ModelLenovoScrollPoint";
+ case QUIRK_MODEL_LENOVO_T450_TOUCHPAD: return "ModelLenovoT450Touchpad";
+ case QUIRK_MODEL_LENOVO_X1GEN6_TOUCHPAD: return "ModelLenovoX1Gen6Touchpad";
+ case QUIRK_MODEL_LENOVO_X230: return "ModelLenovoX230";
+ case QUIRK_MODEL_SYNAPTICS_SERIAL_TOUCHPAD: return "ModelSynapticsSerialTouchpad";
+ case QUIRK_MODEL_SYSTEM76_BONOBO: return "ModelSystem76Bonobo";
+ case QUIRK_MODEL_SYSTEM76_GALAGO: return "ModelSystem76Galago";
+ case QUIRK_MODEL_SYSTEM76_KUDU: return "ModelSystem76Kudu";
+ case QUIRK_MODEL_TABLET_MODE_NO_SUSPEND: return "ModelTabletModeNoSuspend";
+ case QUIRK_MODEL_TABLET_MODE_SWITCH_UNRELIABLE: return "ModelTabletModeSwitchUnreliable";
+ case QUIRK_MODEL_TOUCHPAD_VISIBLE_MARKER: return "ModelTouchpadVisibleMarker";
+ case QUIRK_MODEL_TOUCHPAD_PHANTOM_CLICKS: return "ModelTouchpadPhantomClicks";
+ case QUIRK_MODEL_TRACKBALL: return "ModelTrackball";
+ case QUIRK_MODEL_WACOM_TOUCHPAD: return "ModelWacomTouchpad";
+ case QUIRK_MODEL_PRESSURE_PAD: return "ModelPressurePad";
+
+ case QUIRK_ATTR_SIZE_HINT: return "AttrSizeHint";
+ case QUIRK_ATTR_TOUCH_SIZE_RANGE: return "AttrTouchSizeRange";
+ case QUIRK_ATTR_PALM_SIZE_THRESHOLD: return "AttrPalmSizeThreshold";
+ case QUIRK_ATTR_LID_SWITCH_RELIABILITY: return "AttrLidSwitchReliability";
+ case QUIRK_ATTR_KEYBOARD_INTEGRATION: return "AttrKeyboardIntegration";
+ case QUIRK_ATTR_TRACKPOINT_INTEGRATION: return "AttrPointingStickIntegration";
+ case QUIRK_ATTR_TPKBCOMBO_LAYOUT: return "AttrTPKComboLayout";
+ case QUIRK_ATTR_PRESSURE_RANGE: return "AttrPressureRange";
+ case QUIRK_ATTR_PALM_PRESSURE_THRESHOLD: return "AttrPalmPressureThreshold";
+ case QUIRK_ATTR_RESOLUTION_HINT: return "AttrResolutionHint";
+ case QUIRK_ATTR_TRACKPOINT_MULTIPLIER: return "AttrTrackpointMultiplier";
+ case QUIRK_ATTR_THUMB_PRESSURE_THRESHOLD: return "AttrThumbPressureThreshold";
+ case QUIRK_ATTR_USE_VELOCITY_AVERAGING: return "AttrUseVelocityAveraging";
+ case QUIRK_ATTR_TABLET_SMOOTHING: return "AttrTabletSmoothing";
+ case QUIRK_ATTR_THUMB_SIZE_THRESHOLD: return "AttrThumbSizeThreshold";
+ case QUIRK_ATTR_MSC_TIMESTAMP: return "AttrMscTimestamp";
+ case QUIRK_ATTR_EVENT_CODE: return "AttrEventCode";
+ case QUIRK_ATTR_INPUT_PROP: return "AttrInputProp";
+
+ case MOUSED_GRAB_DEVICE: return "MousedGrabDevice";
+ case MOUSED_IGNORE_DEVICE: return "MousedIgnoreDevice";
+
+ case MOUSED_CLICK_THRESHOLD: return "MousedClickThreshold";
+ case MOUSED_DRIFT_TERMINATE: return "MousedDriftTerminate";
+ case MOUSED_DRIFT_DISTANCE: return "MousedDriftDistance";
+ case MOUSED_DRIFT_TIME: return "MousedDriftTime";
+ case MOUSED_DRIFT_AFTER: return "MousedDriftAfter";
+ case MOUSED_EMULATE_THIRD_BUTTON: return "MousedEmulateThirdButton";
+ case MOUSED_EMULATE_THIRD_BUTTON_TIMEOUT: return "MousedEmulateThirdButtonTimeout";
+ case MOUSED_EXPONENTIAL_ACCEL: return "MousedExponentialAccel";
+ case MOUSED_EXPONENTIAL_OFFSET: return "MousedExponentialOffset";
+ case MOUSED_LINEAR_ACCEL_X: return "MousedLinearAccelX";
+ case MOUSED_LINEAR_ACCEL_Y: return "MousedLinearAccelY";
+ case MOUSED_LINEAR_ACCEL_Z: return "MousedLinearAccelZ";
+ case MOUSED_MAP_Z_AXIS: return "MousedMapZAxis";
+ case MOUSED_VIRTUAL_SCROLL_ENABLE: return "MousedVirtualScrollEnable";
+ case MOUSED_HOR_VIRTUAL_SCROLL_ENABLE: return "MousedHorVirtualScrollEnable";
+ case MOUSED_VIRTUAL_SCROLL_SPEED: return "MousedVirtualScrollSpeed";
+ case MOUSED_VIRTUAL_SCROLL_THRESHOLD: return "MousedVirtualScrollThreshold";
+ case MOUSED_WMODE: return "MousedWMode";
+
+ case MOUSED_TWO_FINGER_SCROLL: return "MousedTwoFingerScroll";
+ case MOUSED_NATURAL_SCROLL: return "MousedNaturalScroll";
+ case MOUSED_THREE_FINGER_DRAG: return "MousedThreeFingerDrag";
+ case MOUSED_SOFTBUTTON2_X: return "MousedSoftButton2X";
+ case MOUSED_SOFTBUTTON3_X: return "MousedSoftButton3X";
+ case MOUSED_SOFTBUTTONS_Y: return "MousedSoftButtonsY";
+ case MOUSED_TAP_TIMEOUT: return "MousedTapTimeout";
+ case MOUSED_TAP_PRESSURE_THRESHOLD: return "MousedTapPressureThreshold";
+ case MOUSED_TAP_MAX_DELTA: return "MousedTapMaxDelta";
+ case MOUSED_TAPHOLD_TIMEOUT: return "MousedTapholdTimeout";
+ case MOUSED_VSCROLL_MIN_DELTA: return "MousedVScrollMinDelta";
+ case MOUSED_VSCROLL_HOR_AREA: return "MousedVScrollHorArea";
+ case MOUSED_VSCROLL_VER_AREA: return "MousedVScrollVerArea";
+
+
+ default:
+ abort();
+ }
+}
+
+static inline const char *
+matchflagname(enum match_flags f)
+{
+ switch(f) {
+ case M_NAME: return "MatchName"; break;
+ case M_BUS: return "MatchBus"; break;
+ case M_VID: return "MatchVendor"; break;
+ case M_PID: return "MatchProduct"; break;
+ case M_VERSION: return "MatchVersion"; break;
+ case M_DMI: return "MatchDMIModalias"; break;
+ case M_UDEV_TYPE: return "MatchDevType"; break;
+ case M_DT: return "MatchDeviceTree"; break;
+ case M_UNIQ: return "MatchUniq"; break;
+ default:
+ abort();
+ }
+}
+
+static inline struct property *
+property_new(void)
+{
+ struct property *p;
+
+ p = zalloc(sizeof *p);
+ p->refcount = 1;
+ list_init(&p->link);
+
+ return p;
+}
+
+static inline struct property *
+property_ref(struct property *p)
+{
+ assert(p->refcount > 0);
+ p->refcount++;
+ return p;
+}
+
+static inline struct property *
+property_unref(struct property *p)
+{
+ /* Note: we don't cleanup here, that is a separate call so we
+ can abort if we haven't cleaned up correctly. */
+ assert(p->refcount > 0);
+ p->refcount--;
+
+ return NULL;
+}
+
+/* Separate call so we can verify that the caller unrefs the property
+ * before shutting down the subsystem.
+ */
+static inline void
+property_cleanup(struct property *p)
+{
+ /* If we get here, the quirks must've been removed already */
+ property_unref(p);
+ assert(p->refcount == 0);
+
+ list_remove(&p->link);
+ if (p->type == PT_STRING)
+ free(p->value.s);
+ free(p);
+}
+
+/**
+ * Return the system DMI info in modalias format.
+ */
+static inline char *
+init_dmi(void)
+{
+#define LEN (KENV_MVALLEN + 1)
+ char *modalias;
+ char bios_vendor[LEN], bios_version[LEN], bios_date[LEN];
+ char sys_vendor[LEN], product_name[LEN], product_version[LEN];
+ char board_vendor[LEN], board_name[LEN], board_version[LEN];
+ char chassis_vendor[LEN], chassis_type[LEN], chassis_version[LEN];
+ int chassis_type_num = 0x2;
+
+ kenv(KENV_GET, "smbios.bios.vendor", bios_vendor, LEN);
+ kenv(KENV_GET, "smbios.bios.version", bios_version, LEN);
+ kenv(KENV_GET, "smbios.bios.reldate", bios_date, LEN);
+ kenv(KENV_GET, "smbios.system.maker", sys_vendor, LEN);
+ kenv(KENV_GET, "smbios.system.product", product_name, LEN);
+ kenv(KENV_GET, "smbios.system.version", product_version, LEN);
+ kenv(KENV_GET, "smbios.planar.maker", board_vendor, LEN);
+ kenv(KENV_GET, "smbios.planar.product", board_name, LEN);
+ kenv(KENV_GET, "smbios.planar.version", board_version, LEN);
+ kenv(KENV_GET, "smbios.chassis.vendor", chassis_vendor, LEN);
+ kenv(KENV_GET, "smbios.chassis.type", chassis_type, LEN);
+ kenv(KENV_GET, "smbios.chassis.version", chassis_version, LEN);
+#undef LEN
+
+ if (strcmp(chassis_type, "Desktop") == 0)
+ chassis_type_num = 0x3;
+ else if (strcmp(chassis_type, "Portable") == 0)
+ chassis_type_num = 0x8;
+ else if (strcmp(chassis_type, "Laptop") == 0)
+ chassis_type_num = 0x9;
+ else if (strcmp(chassis_type, "Notebook") == 0)
+ chassis_type_num = 0xA;
+ else if (strcmp(chassis_type, "Tablet") == 0)
+ chassis_type_num = 0x1E;
+ else if (strcmp(chassis_type, "Convertible") == 0)
+ chassis_type_num = 0x1F;
+ else if (strcmp(chassis_type, "Detachable") == 0)
+ chassis_type_num = 0x20;
+
+ xasprintf(&modalias,
+ "dmi:bvn%s:bvr%s:bd%s:svn%s:pn%s:pvr%s:rvn%s:rn%s:rvr%s:cvn%s:ct%d:cvr%s:",
+ bios_vendor, bios_version, bios_date, sys_vendor, product_name,
+ product_version, board_vendor, board_name, board_version, chassis_vendor,
+ chassis_type_num, chassis_version);
+
+ return modalias;
+}
+
+/**
+ * Return the dt compatible string
+ */
+static inline char *
+init_dt(void)
+{
+ char compatible[1024];
+ char *copy = NULL;
+ const char *syspath = "/sys/firmware/devicetree/base/compatible";
+ FILE *fp;
+
+ if (getenv("LIBINPUT_RUNNING_TEST_SUITE"))
+ return safe_strdup("");
+
+ fp = fopen(syspath, "r");
+ if (!fp)
+ return NULL;
+
+ /* devicetree/base/compatible has multiple null-terminated entries
+ but we only care about the first one here, so strdup is enough */
+ if (fgets(compatible, sizeof(compatible), fp)) {
+ copy = safe_strdup(compatible);
+ }
+
+ fclose(fp);
+
+ return copy;
+}
+
+static inline struct section *
+section_new(const char *path, const char *name)
+{
+ struct section *s = zalloc(sizeof(*s));
+
+ char *path_dup = safe_strdup(path);
+ xasprintf(&s->name, "%s (%s)", name, basename(path_dup));
+ free(path_dup);
+ list_init(&s->link);
+ list_init(&s->properties);
+
+ return s;
+}
+
+static inline void
+section_destroy(struct section *s)
+{
+ struct property *p;
+
+ free(s->name);
+ free(s->match.name);
+ free(s->match.uniq);
+ free(s->match.dmi);
+ free(s->match.dt);
+
+ list_for_each_safe(p, &s->properties, link)
+ property_cleanup(p);
+
+ assert(list_empty(&s->properties));
+
+ list_remove(&s->link);
+ free(s);
+}
+
+static inline bool
+parse_hex(const char *value, unsigned int *parsed)
+{
+ return strstartswith(value, "0x") &&
+ safe_atou_base(value, parsed, 16) &&
+ strspn(value, "0123456789xABCDEF") == strlen(value) &&
+ *parsed <= 0xFFFF;
+}
+
+static int
+strv_parse_hex(const char *str, size_t index, void *data)
+{
+ unsigned int *product = data;
+
+ return !parse_hex(str, &product[index]); /* 0 for success */
+}
+
+/**
+ * Parse a MatchFooBar=banana line.
+ *
+ * @param section The section struct to be filled in
+ * @param key The MatchFooBar part of the line
+ * @param value The banana part of the line.
+ *
+ * @return true on success, false otherwise.
+ */
+static bool
+parse_match(struct quirks_context *ctx,
+ struct section *s,
+ const char *key,
+ const char *value)
+{
+ int rc = false;
+
+#define check_set_bit(s_, bit_) { \
+ if ((s_)->match.bits & (bit_)) goto out; \
+ (s_)->match.bits |= (bit_); \
+ }
+
+ assert(strlen(value) >= 1);
+
+ if (streq(key, "MatchName")) {
+ check_set_bit(s, M_NAME);
+ s->match.name = safe_strdup(value);
+ } else if (streq(key, "MatchUniq")) {
+ check_set_bit(s, M_UNIQ);
+ s->match.uniq = safe_strdup(value);
+ } else if (streq(key, "MatchBus")) {
+ check_set_bit(s, M_BUS);
+ if (streq(value, "usb"))
+ s->match.bus = BT_USB;
+ else if (streq(value, "bluetooth"))
+ s->match.bus = BT_BLUETOOTH;
+ else if (streq(value, "ps2"))
+ s->match.bus = BT_PS2;
+ else if (streq(value, "rmi"))
+ s->match.bus = BT_RMI;
+ else if (streq(value, "i2c"))
+ s->match.bus = BT_I2C;
+ else if (streq(value, "spi"))
+ s->match.bus = BT_SPI;
+ else
+ goto out;
+ } else if (streq(key, "MatchVendor")) {
+ unsigned int vendor;
+
+ check_set_bit(s, M_VID);
+ if (!parse_hex(value, &vendor))
+ goto out;
+
+ s->match.vendor = vendor;
+ } else if (streq(key, "MatchProduct")) {
+ unsigned int product[ARRAY_LENGTH(s->match.product)] = {0};
+ const size_t max = ARRAY_LENGTH(s->match.product) - 1;
+
+ size_t nelems = 0;
+ char **strs = strv_from_string(value, ";", &nelems);
+ int rc = strv_for_each_n((const char**)strs, max, strv_parse_hex, product);
+ strv_free(strs);
+ if (rc != 0)
+ goto out;
+
+ check_set_bit(s, M_PID);
+ memcpy(s->match.product, product, sizeof(product));
+ } else if (streq(key, "MatchVersion")) {
+ unsigned int version;
+
+ check_set_bit(s, M_VERSION);
+ if (!parse_hex(value, &version))
+ goto out;
+
+ s->match.version = version;
+ } else if (streq(key, "MatchDMIModalias")) {
+ check_set_bit(s, M_DMI);
+ if (!strstartswith(value, "dmi:")) {
+ qlog_parser(ctx,
+ "%s: MatchDMIModalias must start with 'dmi:'\n",
+ s->name);
+ goto out;
+ }
+ s->match.dmi = safe_strdup(value);
+ } else if (streq(key, "MatchUdevType") || streq(key, "MatchDevType")) {
+ check_set_bit(s, M_UDEV_TYPE);
+ if (streq(value, "touchpad"))
+ s->match.udev_type = UDEV_TOUCHPAD;
+ else if (streq(value, "mouse"))
+ s->match.udev_type = UDEV_MOUSE;
+ else if (streq(value, "pointingstick"))
+ s->match.udev_type = UDEV_POINTINGSTICK;
+ else if (streq(value, "keyboard"))
+ s->match.udev_type = UDEV_KEYBOARD;
+ else if (streq(value, "joystick"))
+ s->match.udev_type = UDEV_JOYSTICK;
+ else if (streq(value, "tablet"))
+ s->match.udev_type = UDEV_TABLET;
+ else if (streq(value, "tablet-pad"))
+ s->match.udev_type = UDEV_TABLET_PAD;
+ else
+ goto out;
+ } else if (streq(key, "MatchDeviceTree")) {
+ check_set_bit(s, M_DT);
+ s->match.dt = safe_strdup(value);
+ } else {
+ qlog_error(ctx, "Unknown match key '%s'\n", key);
+ goto out;
+ }
+
+#undef check_set_bit
+ s->has_match = true;
+ rc = true;
+out:
+ return rc;
+}
+
+/**
+ * Parse a ModelFooBar=1 line.
+ *
+ * @param section The section struct to be filled in
+ * @param key The ModelFooBar part of the line
+ * @param value The value after the =, must be 1 or 0.
+ *
+ * @return true on success, false otherwise.
+ */
+static bool
+parse_model(struct quirks_context *ctx,
+ struct section *s,
+ const char *key,
+ const char *value)
+{
+ bool b;
+ enum quirk q = QUIRK_MODEL_ALPS_SERIAL_TOUCHPAD;
+
+ assert(strstartswith(key, "Model"));
+
+ if (!parse_boolean_property(value, &b))
+ return false;
+
+ do {
+ if (streq(key, quirk_get_name(q))) {
+ struct property *p = property_new();
+ p->id = q,
+ p->type = PT_BOOL;
+ p->value.b = b;
+ list_append(&s->properties, &p->link);
+ s->has_property = true;
+ return true;
+ }
+ } while (++q < _QUIRK_LAST_MODEL_QUIRK_);
+
+ qlog_error(ctx, "Unknown key %s in %s\n", key, s->name);
+
+ return false;
+}
+
+/**
+ * Parse a AttrFooBar=banana line.
+ *
+ * @param section The section struct to be filled in
+ * @param key The AttrFooBar part of the line
+ * @param value The banana part of the line.
+ *
+ * Value parsing depends on the attribute type.
+ *
+ * @return true on success, false otherwise.
+ */
+static inline bool
+parse_attr(struct quirks_context *ctx,
+ struct section *s,
+ const char *key,
+ const char *value)
+{
+ struct property *p = property_new();
+ bool rc = false;
+ struct quirk_dimensions dim;
+ struct quirk_range range;
+ unsigned int v;
+ bool b;
+ double d;
+
+ if (streq(key, quirk_get_name(QUIRK_ATTR_SIZE_HINT))) {
+ p->id = QUIRK_ATTR_SIZE_HINT;
+ if (!parse_dimension_property(value, &dim.x, &dim.y))
+ goto out;
+ p->type = PT_DIMENSION;
+ p->value.dim = dim;
+ rc = true;
+ } else if (streq(key, quirk_get_name(QUIRK_ATTR_TOUCH_SIZE_RANGE))) {
+ p->id = QUIRK_ATTR_TOUCH_SIZE_RANGE;
+ if (!parse_range_property(value, &range.upper, &range.lower))
+ goto out;
+ p->type = PT_RANGE;
+ p->value.range = range;
+ rc = true;
+ } else if (streq(key, quirk_get_name(QUIRK_ATTR_PALM_SIZE_THRESHOLD))) {
+ p->id = QUIRK_ATTR_PALM_SIZE_THRESHOLD;
+ if (!safe_atou(value, &v))
+ goto out;
+ p->type = PT_UINT;
+ p->value.u = v;
+ rc = true;
+ } else if (streq(key, quirk_get_name(QUIRK_ATTR_LID_SWITCH_RELIABILITY))) {
+ p->id = QUIRK_ATTR_LID_SWITCH_RELIABILITY;
+ if (!streq(value, "reliable") &&
+ !streq(value, "write_open") &&
+ !streq(value, "unreliable"))
+ goto out;
+ p->type = PT_STRING;
+ p->value.s = safe_strdup(value);
+ rc = true;
+ } else if (streq(key, quirk_get_name(QUIRK_ATTR_KEYBOARD_INTEGRATION))) {
+ p->id = QUIRK_ATTR_KEYBOARD_INTEGRATION;
+ if (!streq(value, "internal") && !streq(value, "external"))
+ goto out;
+ p->type = PT_STRING;
+ p->value.s = safe_strdup(value);
+ rc = true;
+ } else if (streq(key, quirk_get_name(QUIRK_ATTR_TRACKPOINT_INTEGRATION))) {
+ p->id = QUIRK_ATTR_TRACKPOINT_INTEGRATION;
+ if (!streq(value, "internal") && !streq(value, "external"))
+ goto out;
+ p->type = PT_STRING;
+ p->value.s = safe_strdup(value);
+ rc = true;
+ } else if (streq(key, quirk_get_name(QUIRK_ATTR_TPKBCOMBO_LAYOUT))) {
+ p->id = QUIRK_ATTR_TPKBCOMBO_LAYOUT;
+ if (!streq(value, "below"))
+ goto out;
+ p->type = PT_STRING;
+ p->value.s = safe_strdup(value);
+ rc = true;
+ } else if (streq(key, quirk_get_name(QUIRK_ATTR_PRESSURE_RANGE))) {
+ p->id = QUIRK_ATTR_PRESSURE_RANGE;
+ if (!parse_range_property(value, &range.upper, &range.lower))
+ goto out;
+ p->type = PT_RANGE;
+ p->value.range = range;
+ rc = true;
+ } else if (streq(key, quirk_get_name(QUIRK_ATTR_PALM_PRESSURE_THRESHOLD))) {
+ p->id = QUIRK_ATTR_PALM_PRESSURE_THRESHOLD;
+ if (!safe_atou(value, &v))
+ goto out;
+ p->type = PT_UINT;
+ p->value.u = v;
+ rc = true;
+ } else if (streq(key, quirk_get_name(QUIRK_ATTR_RESOLUTION_HINT))) {
+ p->id = QUIRK_ATTR_RESOLUTION_HINT;
+ if (!parse_dimension_property(value, &dim.x, &dim.y))
+ goto out;
+ p->type = PT_DIMENSION;
+ p->value.dim = dim;
+ rc = true;
+ } else if (streq(key, quirk_get_name(QUIRK_ATTR_TRACKPOINT_MULTIPLIER))) {
+ p->id = QUIRK_ATTR_TRACKPOINT_MULTIPLIER;
+ if (!safe_atod(value, &d))
+ goto out;
+ p->type = PT_DOUBLE;
+ p->value.d = d;
+ rc = true;
+ } else if (streq(key, quirk_get_name(QUIRK_ATTR_USE_VELOCITY_AVERAGING))) {
+ p->id = QUIRK_ATTR_USE_VELOCITY_AVERAGING;
+ if (!parse_boolean_property(value, &b))
+ goto out;
+ p->type = PT_BOOL;
+ p->value.b = b;
+ rc = true;
+ } else if (streq(key, quirk_get_name(QUIRK_ATTR_TABLET_SMOOTHING))) {
+ p->id = QUIRK_ATTR_TABLET_SMOOTHING;
+ if (!parse_boolean_property(value, &b))
+ goto out;
+ p->type = PT_BOOL;
+ p->value.b = b;
+ rc = true;
+ } else if (streq(key, quirk_get_name(QUIRK_ATTR_THUMB_PRESSURE_THRESHOLD))) {
+ p->id = QUIRK_ATTR_THUMB_PRESSURE_THRESHOLD;
+ if (!safe_atou(value, &v))
+ goto out;
+ p->type = PT_UINT;
+ p->value.u = v;
+ rc = true;
+ } else if (streq(key, quirk_get_name(QUIRK_ATTR_THUMB_SIZE_THRESHOLD))) {
+ p->id = QUIRK_ATTR_THUMB_SIZE_THRESHOLD;
+ if (!safe_atou(value, &v))
+ goto out;
+ p->type = PT_UINT;
+ p->value.u = v;
+ rc = true;
+ } else if (streq(key, quirk_get_name(QUIRK_ATTR_MSC_TIMESTAMP))) {
+ p->id = QUIRK_ATTR_MSC_TIMESTAMP;
+ if (!streq(value, "watch"))
+ goto out;
+ p->type = PT_STRING;
+ p->value.s = safe_strdup(value);
+ rc = true;
+ } else if (streq(key, quirk_get_name(QUIRK_ATTR_EVENT_CODE))) {
+ struct input_event events[32];
+ size_t nevents = ARRAY_LENGTH(events);
+
+ p->id = QUIRK_ATTR_EVENT_CODE;
+
+ if (!parse_evcode_property(value, events, &nevents) ||
+ nevents == 0)
+ goto out;
+
+ for (size_t i = 0; i < nevents; i++) {
+ p->value.tuples.tuples[i].first = events[i].type;
+ p->value.tuples.tuples[i].second = events[i].code;
+ p->value.tuples.tuples[i].third = events[i].value;
+ }
+ p->value.tuples.ntuples = nevents;
+ p->type = PT_TUPLES;
+
+ rc = true;
+ } else if (streq(key, quirk_get_name(QUIRK_ATTR_INPUT_PROP))) {
+ struct input_prop props[INPUT_PROP_CNT];
+ size_t nprops = ARRAY_LENGTH(props);
+
+ p->id = QUIRK_ATTR_INPUT_PROP;
+
+ if (!parse_input_prop_property(value, props, &nprops) ||
+ nprops == 0)
+ goto out;
+
+ for (size_t i = 0; i < nprops; i++) {
+ p->value.tuples.tuples[i].first = props[i].prop;
+ p->value.tuples.tuples[i].second = props[i].enabled;
+ }
+
+ rc = true;
+ } else {
+ qlog_error(ctx, "Unknown key %s in %s\n", key, s->name);
+ }
+out:
+ if (rc) {
+ list_append(&s->properties, &p->link);
+ s->has_property = true;
+ } else {
+ property_cleanup(p);
+ }
+ return rc;
+}
+
+/**
+ * Parse a MousedFooBar=banana line.
+ *
+ * @param section The section struct to be filled in
+ * @param key The MousedFooBar part of the line
+ * @param value The banana part of the line.
+ *
+ * Value parsing depends on the attribute type.
+ *
+ * @return true on success, false otherwise.
+ */
+static inline bool
+parse_moused(struct quirks_context *ctx,
+ struct section *s,
+ const char *key,
+ const char *value)
+{
+ struct property *p = property_new();
+ bool rc = false;
+ struct quirk_dimensions dim;
+ struct quirk_range range;
+ unsigned int v;
+ int i;
+ bool b;
+ double d;
+
+ if (streq(key, quirk_get_name(MOUSED_GRAB_DEVICE))) {
+ p->id = MOUSED_GRAB_DEVICE;
+ if (!parse_boolean_property(value, &b))
+ goto out;
+ p->type = PT_BOOL;
+ p->value.b = b;
+ rc = true;
+ } else if (streq(key, quirk_get_name(MOUSED_IGNORE_DEVICE))) {
+ p->id = MOUSED_IGNORE_DEVICE;
+ if (!parse_boolean_property(value, &b))
+ goto out;
+ p->type = PT_BOOL;
+ p->value.b = b;
+ rc = true;
+ } else if (streq(key, quirk_get_name(MOUSED_CLICK_THRESHOLD))) {
+ p->id = MOUSED_CLICK_THRESHOLD;
+ if (!safe_atou(value, &v))
+ goto out;
+ p->type = PT_UINT;
+ p->value.u = v;
+ rc = true;
+ } else if (streq(key, quirk_get_name(MOUSED_DRIFT_TERMINATE))) {
+ p->id = MOUSED_DRIFT_TERMINATE;
+ if (!parse_boolean_property(value, &b))
+ goto out;
+ p->type = PT_BOOL;
+ p->value.b = b;
+ rc = true;
+ } else if (streq(key, quirk_get_name(MOUSED_DRIFT_DISTANCE))) {
+ p->id = MOUSED_DRIFT_DISTANCE;
+ if (!safe_atou(value, &v))
+ goto out;
+ p->type = PT_UINT;
+ p->value.u = v;
+ rc = true;
+ } else if (streq(key, quirk_get_name(MOUSED_DRIFT_TIME))) {
+ p->id = MOUSED_DRIFT_TIME;
+ if (!safe_atou(value, &v))
+ goto out;
+ p->type = PT_UINT;
+ p->value.u = v;
+ rc = true;
+ } else if (streq(key, quirk_get_name(MOUSED_DRIFT_AFTER))) {
+ p->id = MOUSED_DRIFT_AFTER;
+ if (!safe_atou(value, &v))
+ goto out;
+ p->type = PT_UINT;
+ p->value.u = v;
+ rc = true;
+ } else if (streq(key, quirk_get_name(MOUSED_EMULATE_THIRD_BUTTON))) {
+ p->id = MOUSED_EMULATE_THIRD_BUTTON;
+ if (!parse_boolean_property(value, &b))
+ goto out;
+ p->type = PT_BOOL;
+ p->value.b = b;
+ rc = true;
+ } else if (streq(key, quirk_get_name(MOUSED_EMULATE_THIRD_BUTTON_TIMEOUT))) {
+ p->id = MOUSED_EMULATE_THIRD_BUTTON_TIMEOUT;
+ if (!safe_atou(value, &v))
+ goto out;
+ p->type = PT_UINT;
+ p->value.u = v;
+ rc = true;
+ } else if (streq(key, quirk_get_name(MOUSED_EXPONENTIAL_ACCEL))) {
+ p->id = MOUSED_EXPONENTIAL_ACCEL;
+ if (!safe_atod(value, &d))
+ goto out;
+ p->type = PT_DOUBLE;
+ p->value.d = d;
+ rc = true;
+ } else if (streq(key, quirk_get_name(MOUSED_EXPONENTIAL_OFFSET))) {
+ p->id = MOUSED_EXPONENTIAL_OFFSET;
+ if (!safe_atod(value, &d))
+ goto out;
+ p->type = PT_DOUBLE;
+ p->value.d = d;
+ rc = true;
+ } else if (streq(key, quirk_get_name(MOUSED_LINEAR_ACCEL_X))) {
+ p->id = MOUSED_LINEAR_ACCEL_X;
+ if (!safe_atod(value, &d))
+ goto out;
+ p->type = PT_DOUBLE;
+ p->value.d = d;
+ rc = true;
+ } else if (streq(key, quirk_get_name(MOUSED_LINEAR_ACCEL_Y))) {
+ p->id = MOUSED_LINEAR_ACCEL_Y;
+ if (!safe_atod(value, &d))
+ goto out;
+ p->type = PT_DOUBLE;
+ p->value.d = d;
+ rc = true;
+ } else if (streq(key, quirk_get_name(MOUSED_LINEAR_ACCEL_Z))) {
+ p->id = MOUSED_LINEAR_ACCEL_Z;
+ if (!safe_atod(value, &d))
+ goto out;
+ p->type = PT_DOUBLE;
+ p->value.d = d;
+ rc = true;
+ } else if (streq(key, quirk_get_name(MOUSED_MAP_Z_AXIS))) {
+ } else if (streq(key, quirk_get_name(MOUSED_VIRTUAL_SCROLL_ENABLE))) {
+ p->id = MOUSED_VIRTUAL_SCROLL_ENABLE;
+ if (!parse_boolean_property(value, &b))
+ goto out;
+ p->type = PT_BOOL;
+ p->value.b = b;
+ rc = true;
+ } else if (streq(key, quirk_get_name(MOUSED_HOR_VIRTUAL_SCROLL_ENABLE))) {
+ p->id = MOUSED_HOR_VIRTUAL_SCROLL_ENABLE;
+ if (!parse_boolean_property(value, &b))
+ goto out;
+ p->type = PT_BOOL;
+ p->value.b = b;
+ rc = true;
+ } else if (streq(key, quirk_get_name(MOUSED_VIRTUAL_SCROLL_SPEED))) {
+ p->id = MOUSED_VIRTUAL_SCROLL_SPEED;
+ if (!safe_atou(value, &v))
+ goto out;
+ p->type = PT_UINT;
+ p->value.u = v;
+ rc = true;
+ } else if (streq(key, quirk_get_name(MOUSED_VIRTUAL_SCROLL_THRESHOLD))) {
+ p->id = MOUSED_VIRTUAL_SCROLL_THRESHOLD;
+ if (!safe_atou(value, &v))
+ goto out;
+ p->type = PT_UINT;
+ p->value.u = v;
+ rc = true;
+ } else if (streq(key, quirk_get_name(MOUSED_WMODE))) {
+ p->id = MOUSED_WMODE;
+ if (!safe_atou(value, &v))
+ goto out;
+ p->type = PT_UINT;
+ p->value.u = v;
+ rc = true;
+ } else if (streq(key, quirk_get_name(MOUSED_TWO_FINGER_SCROLL))) {
+ p->id = MOUSED_TWO_FINGER_SCROLL;
+ if (!parse_boolean_property(value, &b))
+ goto out;
+ p->type = PT_BOOL;
+ p->value.b = b;
+ rc = true;
+ } else if (streq(key, quirk_get_name(MOUSED_NATURAL_SCROLL))) {
+ p->id = MOUSED_NATURAL_SCROLL;
+ if (!parse_boolean_property(value, &b))
+ goto out;
+ p->type = PT_BOOL;
+ p->value.b = b;
+ rc = true;
+ } else if (streq(key, quirk_get_name(MOUSED_THREE_FINGER_DRAG))) {
+ p->id = MOUSED_THREE_FINGER_DRAG;
+ if (!parse_boolean_property(value, &b))
+ goto out;
+ p->type = PT_BOOL;
+ p->value.b = b;
+ rc = true;
+ } else if (streq(key, quirk_get_name(MOUSED_SOFTBUTTON2_X))) {
+ p->id = MOUSED_SOFTBUTTON2_X;
+ if (!safe_atou(value, &v))
+ goto out;
+ p->type = PT_UINT;
+ p->value.u = v;
+ rc = true;
+ } else if (streq(key, quirk_get_name(MOUSED_SOFTBUTTON3_X))) {
+ p->id = MOUSED_SOFTBUTTON3_X;
+ if (!safe_atou(value, &v))
+ goto out;
+ p->type = PT_UINT;
+ p->value.u = v;
+ rc = true;
+ } else if (streq(key, quirk_get_name(MOUSED_SOFTBUTTONS_Y))) {
+ p->id = MOUSED_SOFTBUTTONS_Y;
+ if (!safe_atoi(value, &i))
+ goto out;
+ p->type = PT_INT;
+ p->value.i = i;
+ rc = true;
+ } else if (streq(key, quirk_get_name(MOUSED_TAP_TIMEOUT))) {
+ p->id = MOUSED_TAP_TIMEOUT;
+ if (!safe_atou(value, &v))
+ goto out;
+ p->type = PT_UINT;
+ p->value.u = v;
+ rc = true;
+ } else if (streq(key, quirk_get_name(MOUSED_TAP_PRESSURE_THRESHOLD))) {
+ p->id = MOUSED_TAP_PRESSURE_THRESHOLD;
+ if (!safe_atou(value, &v))
+ goto out;
+ p->type = PT_UINT;
+ p->value.u = v;
+ rc = true;
+ } else if (streq(key, quirk_get_name(MOUSED_TAP_MAX_DELTA))) {
+ p->id = MOUSED_TAP_MAX_DELTA;
+ if (!safe_atod(value, &d))
+ goto out;
+ p->type = PT_DOUBLE;
+ p->value.d = d;
+ rc = true;
+ } else if (streq(key, quirk_get_name(MOUSED_TAPHOLD_TIMEOUT))) {
+ p->id = MOUSED_TAPHOLD_TIMEOUT;
+ if (!safe_atou(value, &v))
+ goto out;
+ p->type = PT_UINT;
+ p->value.u = v;
+ rc = true;
+ } else if (streq(key, quirk_get_name(MOUSED_VSCROLL_MIN_DELTA))) {
+ p->id = MOUSED_VSCROLL_MIN_DELTA;
+ if (!safe_atod(value, &d))
+ goto out;
+ p->type = PT_DOUBLE;
+ p->value.d = d;
+ rc = true;
+ } else if (streq(key, quirk_get_name(MOUSED_VSCROLL_HOR_AREA))) {
+ p->id = MOUSED_VSCROLL_HOR_AREA;
+ if (!safe_atod(value, &d))
+ goto out;
+ p->type = PT_DOUBLE;
+ p->value.d = d;
+ rc = true;
+ } else if (streq(key, quirk_get_name(MOUSED_VSCROLL_VER_AREA))) {
+ p->id = MOUSED_VSCROLL_VER_AREA;
+ if (!safe_atod(value, &d))
+ goto out;
+ p->type = PT_DOUBLE;
+ p->value.d = d;
+ rc = true;
+ } else {
+ qlog_error(ctx, "Unknown key %s in %s\n", key, s->name);
+ }
+out:
+ if (rc) {
+ list_append(&s->properties, &p->link);
+ s->has_property = true;
+ } else {
+ property_cleanup(p);
+ }
+ return rc;
+}
+
+/**
+ * Parse a single line, expected to be in the format Key=value. Anything
+ * else will be rejected with a failure.
+ *
+ * Our data files can only have Match, Model and Attr, so let's check for
+ * those too.
+ */
+static bool
+parse_value_line(struct quirks_context *ctx, struct section *s, const char *line)
+{
+ bool rc = false;
+
+ size_t nelem;
+ char **strv = strv_from_string(line, "=", &nelem);
+ if (!strv || nelem != 2)
+ goto out;
+
+ const char *key = strv[0];
+ const char *value = strv[1];
+ if (strlen(key) == 0 || strlen(value) == 0)
+ goto out;
+
+ /* Whatever the value is, it's not supposed to be in quotes */
+ if (value[0] == '"' || value[0] == '\'')
+ goto out;
+
+ if (strstartswith(key, "Match"))
+ rc = parse_match(ctx, s, key, value);
+ else if (strstartswith(key, "Model"))
+ rc = parse_model(ctx, s, key, value);
+ else if (strstartswith(key, "Attr"))
+ rc = parse_attr(ctx, s, key, value);
+ else if (strstartswith(key, "Moused"))
+ rc = parse_moused(ctx, s, key, value);
+ else
+ qlog_error(ctx, "Unknown value prefix %s\n", line);
+out:
+ strv_free(strv);
+ return rc;
+}
+
+static inline bool
+parse_file(struct quirks_context *ctx, const char *path)
+{
+ enum state {
+ STATE_SECTION,
+ STATE_MATCH,
+ STATE_MATCH_OR_VALUE,
+ STATE_VALUE_OR_SECTION,
+ STATE_ANY,
+ };
+ FILE *fp;
+ char line[512];
+ bool rc = false;
+ enum state state = STATE_SECTION;
+ struct section *section = NULL;
+ int lineno = -1;
+
+ qlog_debug(ctx, "%s\n", path);
+
+ /* Not using open_restricted here, if we can't access
+ * our own data files, our installation is screwed up.
+ */
+ fp = fopen(path, "r");
+ if (!fp) {
+ /* If the file doesn't exist that's fine. Only way this can
+ * happen is for the custom override file, all others are
+ * provided by scandir so they do exist. Short of races we
+ * don't care about. */
+ if (errno == ENOENT)
+ return true;
+
+ qlog_error(ctx, "%s: failed to open file\n", path);
+ goto out;
+ }
+
+ while (fgets(line, sizeof(line), fp)) {
+ char *comment;
+
+ lineno++;
+
+ comment = strstr(line, "#");
+ if (comment) {
+ /* comment points to # but we need to remove the
+ * preceding whitespaces too */
+ comment--;
+ while (comment >= line) {
+ if (*comment != ' ' && *comment != '\t')
+ break;
+ comment--;
+ }
+ *(comment + 1) = '\0';
+ } else { /* strip the trailing newline */
+ comment = strstr(line, "\n");
+ if (comment)
+ *comment = '\0';
+ }
+ if (strlen(line) == 0)
+ continue;
+
+ /* We don't use quotes for strings, so we really don't want
+ * erroneous trailing whitespaces */
+ switch (line[strlen(line) - 1]) {
+ case ' ':
+ case '\t':
+ qlog_parser(ctx,
+ "%s:%d: Trailing whitespace '%s'\n",
+ path, lineno, line);
+ goto out;
+ }
+
+ switch (line[0]) {
+ case '\0':
+ case '\n':
+ case '#':
+ break;
+ /* white space not allowed */
+ case ' ':
+ case '\t':
+ qlog_parser(ctx, "%s:%d: Preceding whitespace '%s'\n",
+ path, lineno, line);
+ goto out;
+ /* section title */
+ case '[':
+ if (line[strlen(line) - 1] != ']') {
+ qlog_parser(ctx, "%s:%d: Closing ] missing '%s'\n",
+ path, lineno, line);
+ goto out;
+ }
+
+ if (state != STATE_SECTION &&
+ state != STATE_VALUE_OR_SECTION) {
+ qlog_parser(ctx, "%s:%d: expected section before %s\n",
+ path, lineno, line);
+ goto out;
+ }
+ if (section &&
+ (!section->has_match || !section->has_property)) {
+ qlog_parser(ctx, "%s:%d: previous section %s was empty\n",
+ path, lineno, section->name);
+ goto out; /* Previous section was empty */
+ }
+
+ state = STATE_MATCH;
+ section = section_new(path, line);
+ list_append(&ctx->sections, &section->link);
+ break;
+ default:
+ /* entries must start with A-Z */
+ if (line[0] < 'A' || line[0] > 'Z') {
+ qlog_parser(ctx, "%s:%d: Unexpected line %s\n",
+ path, lineno, line);
+ goto out;
+ }
+ switch (state) {
+ case STATE_SECTION:
+ qlog_parser(ctx, "%s:%d: expected [Section], got %s\n",
+ path, lineno, line);
+ goto out;
+ case STATE_MATCH:
+ if (!strstartswith(line, "Match")) {
+ qlog_parser(ctx, "%s:%d: expected MatchFoo=bar, have %s\n",
+ path, lineno, line);
+ goto out;
+ }
+ state = STATE_MATCH_OR_VALUE;
+ break;
+ case STATE_MATCH_OR_VALUE:
+ if (!strstartswith(line, "Match"))
+ state = STATE_VALUE_OR_SECTION;
+ break;
+ case STATE_VALUE_OR_SECTION:
+ if (strstartswith(line, "Match")) {
+ qlog_parser(ctx, "%s:%d: expected value or [Section], have %s\n",
+ path, lineno, line);
+ goto out;
+ }
+ break;
+ case STATE_ANY:
+ break;
+ }
+
+ if (!parse_value_line(ctx, section, line)) {
+ qlog_parser(ctx, "%s:%d: failed to parse %s\n",
+ path, lineno, line);
+ goto out;
+ }
+ break;
+ }
+ }
+
+ if (!section) {
+ qlog_parser(ctx, "%s: is an empty file\n", path);
+ goto out;
+ }
+
+ if ((!section->has_match || !section->has_property)) {
+ qlog_parser(ctx, "%s:%d: previous section %s was empty\n",
+ path, lineno, section->name);
+ goto out; /* Previous section was empty */
+ }
+
+ rc = true;
+out:
+ if (fp)
+ fclose(fp);
+
+ return rc;
+}
+
+static int
+is_data_file(const struct dirent *dir) {
+ return strendswith(dir->d_name, ".quirks");
+}
+
+static inline bool
+parse_files(struct quirks_context *ctx, const char *data_path)
+{
+ struct dirent **namelist;
+ int ndev = -1;
+ int idx = 0;
+
+ ndev = scandir(data_path, &namelist, is_data_file, versionsort);
+ if (ndev <= 0) {
+ qlog_error(ctx,
+ "%s: failed to find data files\n",
+ data_path);
+ return false;
+ }
+
+ for (idx = 0; idx < ndev; idx++) {
+ char path[PATH_MAX];
+
+ snprintf(path,
+ sizeof(path),
+ "%s/%s",
+ data_path,
+ namelist[idx]->d_name);
+
+ if (!parse_file(ctx, path))
+ break;
+ }
+
+ for (int i = 0; i < ndev; i++)
+ free(namelist[i]);
+ free(namelist);
+
+ return idx == ndev;
+}
+
+struct quirks_context *
+quirks_init_subsystem(const char *data_path,
+ const char *override_file,
+ moused_log_handler log_handler,
+ enum quirks_log_type log_type)
+{
+ _unref_(quirks_context) *ctx = zalloc(sizeof *ctx);
+
+ assert(data_path);
+
+ ctx->refcount = 1;
+ ctx->log_handler = log_handler;
+ ctx->log_type = log_type;
+ list_init(&ctx->quirks);
+ list_init(&ctx->sections);
+
+ qlog_debug(ctx, "%s is data root\n", data_path);
+
+ ctx->dmi = init_dmi();
+ ctx->dt = init_dt();
+ if (!ctx->dmi && !ctx->dt)
+ return NULL;
+
+ if (!parse_files(ctx, data_path))
+ return NULL;
+
+ if (override_file && !parse_file(ctx, override_file))
+ return NULL;
+
+ return steal(&ctx);
+}
+
+struct quirks_context *
+quirks_context_ref(struct quirks_context *ctx)
+{
+ assert(ctx->refcount > 0);
+ ctx->refcount++;
+
+ return ctx;
+}
+
+struct quirks_context *
+quirks_context_unref(struct quirks_context *ctx)
+{
+ struct section *s;
+
+ if (!ctx)
+ return NULL;
+
+ assert(ctx->refcount >= 1);
+ ctx->refcount--;
+
+ if (ctx->refcount > 0)
+ return NULL;
+
+ /* Caller needs to clean up before calling this */
+ assert(list_empty(&ctx->quirks));
+
+ list_for_each_safe(s, &ctx->sections, link) {
+ section_destroy(s);
+ }
+
+ free(ctx->dmi);
+ free(ctx->dt);
+ free(ctx);
+
+ return NULL;
+}
+
+static struct quirks *
+quirks_new(void)
+{
+ struct quirks *q;
+
+ q = zalloc(sizeof *q);
+ q->refcount = 1;
+ q->nproperties = 0;
+ list_init(&q->link);
+ list_init(&q->floating_properties);
+
+ return q;
+}
+
+struct quirks *
+quirks_unref(struct quirks *q)
+{
+ if (!q)
+ return NULL;
+
+ /* We don't really refcount, but might
+ * as well have the API in place */
+ assert(q->refcount == 1);
+
+ for (size_t i = 0; i < q->nproperties; i++) {
+ property_unref(q->properties[i]);
+ }
+
+ /* Floating properties are owned by our quirks context, need to be
+ * cleaned up here */
+ struct property *p;
+ list_for_each_safe(p, &q->floating_properties, link) {
+ property_cleanup(p);
+ }
+
+ list_remove(&q->link);
+ free(q->properties);
+ free(q);
+
+ return NULL;
+}
+
+static inline void
+match_fill_name(struct match *m,
+ struct device *device)
+{
+ if (device->name[0] == 0)
+ return;
+
+ m->name = safe_strdup(device->name);
+
+ m->bits |= M_NAME;
+}
+
+static inline void
+match_fill_uniq(struct match *m,
+ struct device *device)
+{
+ if (device->uniq[0] == 0)
+ return;
+
+ m->uniq = safe_strdup(device->uniq);
+
+ m->bits |= M_UNIQ;
+}
+
+static inline void
+match_fill_bus_vid_pid(struct match *m,
+ struct device *device)
+{
+ m->product[0] = device->id.product;
+ m->product[1] = 0;
+ m->vendor = device->id.vendor;
+ m->version = device->id.version;
+ m->bits |= M_PID|M_VID|M_VERSION;
+ switch (device->id.bustype) {
+ case BUS_USB:
+ m->bus = BT_USB;
+ m->bits |= M_BUS;
+ break;
+ case BUS_BLUETOOTH:
+ m->bus = BT_BLUETOOTH;
+ m->bits |= M_BUS;
+ break;
+ case BUS_I8042:
+ m->bus = BT_PS2;
+ m->bits |= M_BUS;
+ break;
+ case BUS_RMI:
+ m->bus = BT_RMI;
+ m->bits |= M_BUS;
+ break;
+ case BUS_I2C:
+ m->bus = BT_I2C;
+ m->bits |= M_BUS;
+ break;
+ case BUS_SPI:
+ m->bus = BT_SPI;
+ m->bits |= M_BUS;
+ break;
+ default:
+ break;
+ }
+}
+
+static inline void
+match_fill_udev_type(struct match *m,
+ struct device *device)
+{
+ switch (device->type) {
+ case DEVICE_TYPE_MOUSE:
+ m->udev_type |= UDEV_MOUSE;
+ break;
+ case DEVICE_TYPE_POINTINGSTICK:
+ m->udev_type |= UDEV_MOUSE | UDEV_POINTINGSTICK;
+ break;
+ case DEVICE_TYPE_TOUCHPAD:
+ m->udev_type |= UDEV_TOUCHPAD;
+ break;
+ case DEVICE_TYPE_TABLET:
+ m->udev_type |= UDEV_TABLET;
+ break;
+ case DEVICE_TYPE_TABLET_PAD:
+ m->udev_type |= UDEV_TABLET_PAD;
+ break;
+ case DEVICE_TYPE_KEYBOARD:
+ m->udev_type |= UDEV_KEYBOARD;
+ break;
+ case DEVICE_TYPE_JOYSTICK:
+ m->udev_type |= UDEV_JOYSTICK;
+ break;
+ default:
+ break;
+ }
+ m->bits |= M_UDEV_TYPE;
+}
+
+static inline void
+match_fill_dmi_dt(struct match *m, char *dmi, char *dt)
+{
+ if (dmi) {
+ m->dmi = dmi;
+ m->bits |= M_DMI;
+ }
+
+ if (dt) {
+ m->dt = dt;
+ m->bits |= M_DT;
+ }
+}
+
+static struct match *
+match_new(struct device *device,
+ char *dmi, char *dt)
+{
+ struct match *m = zalloc(sizeof *m);
+
+ match_fill_name(m, device);
+ match_fill_uniq(m, device);
+ match_fill_bus_vid_pid(m, device);
+ match_fill_dmi_dt(m, dmi, dt);
+ match_fill_udev_type(m, device);
+ return m;
+}
+
+static void
+match_free(struct match *m)
+{
+ /* dmi and dt are global */
+ free(m->name);
+ free(m->uniq);
+ free(m);
+}
+
+static void
+quirk_merge_event_codes(struct quirks_context *ctx,
+ struct quirks *q,
+ const struct property *property)
+{
+ for (size_t i = 0; i < q->nproperties; i++) {
+ struct property *p = q->properties[i];
+
+ if (p->id != property->id)
+ continue;
+
+ /* We have a duplicated property, merge in with ours */
+ size_t offset = p->value.tuples.ntuples;
+ size_t max = ARRAY_LENGTH(p->value.tuples.tuples);
+ for (size_t j = 0; j < property->value.tuples.ntuples; j++) {
+ if (offset + j >= max)
+ break;
+ p->value.tuples.tuples[offset + j] = property->value.tuples.tuples[j];
+ p->value.tuples.ntuples++;
+ }
+ return;
+ }
+
+ /* First time we add AttrEventCode: create a new property.
+ * Unlike the other properties, this one isn't part of a section, it belongs
+ * to the quirks */
+ struct property *newprop = property_new();
+ newprop->id = property->id;
+ newprop->type = property->type;
+ newprop->value.tuples = property->value.tuples;
+ /* Caller responsible for pre-allocating space */
+ q->properties[q->nproperties++] = property_ref(newprop);
+ list_append(&q->floating_properties, &newprop->link);
+}
+
+static void
+quirk_apply_section(struct quirks_context *ctx,
+ struct quirks *q,
+ const struct section *s)
+{
+ struct property *p;
+ size_t nprops = 0;
+ void *tmp;
+
+ list_for_each(p, &s->properties, link) {
+ nprops++;
+ }
+
+ nprops += q->nproperties;
+ tmp = realloc(q->properties, nprops * sizeof(p));
+ if (!tmp)
+ return;
+
+ q->properties = tmp;
+ list_for_each(p, &s->properties, link) {
+ qlog_debug(ctx, "property added: %s from %s\n",
+ quirk_get_name(p->id), s->name);
+
+ /* All quirks but AttrEventCode and AttrInputProp
+ * simply overwrite each other, so we can just append the
+ * matching property and, later when checking the quirk, pick
+ * the last one in the array.
+ *
+ * The event codes/input props are special because they're lists
+ * that may *partially* override each other, e.g. a section may
+ * enable BTN_LEFT and BTN_RIGHT but a later section may disable
+ * only BTN_RIGHT. This should result in BTN_LEFT force-enabled
+ * and BTN_RIGHT force-disabled.
+ *
+ * To hack around this, those are the only ones where only ever
+ * have one struct property in the list (not owned by a section)
+ * and we simply merge any extra sections onto that.
+ */
+ if (p->id == QUIRK_ATTR_EVENT_CODE ||
+ p->id == QUIRK_ATTR_INPUT_PROP)
+ quirk_merge_event_codes(ctx, q, p);
+ else
+ q->properties[q->nproperties++] = property_ref(p);
+ }
+}
+
+static bool
+quirk_match_section(struct quirks_context *ctx,
+ struct quirks *q,
+ struct section *s,
+ struct match *m,
+ struct device *device)
+{
+ uint32_t matched_flags = 0x0;
+
+ for (uint32_t flag = 0x1; flag <= M_LAST; flag <<= 1) {
+ uint32_t prev_matched_flags = matched_flags;
+ /* section doesn't have this bit set, continue */
+ if ((s->match.bits & flag) == 0)
+ continue;
+
+ /* Couldn't fill in this bit for the match, so we
+ * do not match on it */
+ if ((m->bits & flag) == 0) {
+ qlog_debug(ctx,
+ "%s wants %s but we don't have that\n",
+ s->name, matchflagname(flag));
+ continue;
+ }
+
+ /* now check the actual matching bit */
+ switch (flag) {
+ case M_NAME:
+ if (fnmatch(s->match.name, m->name, 0) == 0)
+ matched_flags |= flag;
+ break;
+ case M_UNIQ:
+ if (fnmatch(s->match.uniq, m->uniq, 0) == 0)
+ matched_flags |= flag;
+ break;
+ case M_BUS:
+ if (m->bus == s->match.bus)
+ matched_flags |= flag;
+ break;
+ case M_VID:
+ if (m->vendor == s->match.vendor)
+ matched_flags |= flag;
+ break;
+ case M_PID:
+ ARRAY_FOR_EACH(m->product, mi) {
+ if (*mi == 0 || matched_flags & flag)
+ break;
+
+ ARRAY_FOR_EACH(s->match.product, si) {
+ if (*si == 0)
+ break;
+ if (*mi == *si) {
+ matched_flags |= flag;
+ break;
+ }
+ }
+ }
+ break;
+ case M_VERSION:
+ if (m->version == s->match.version)
+ matched_flags |= flag;
+ break;
+ case M_DMI:
+ if (fnmatch(s->match.dmi, m->dmi, 0) == 0)
+ matched_flags |= flag;
+ break;
+ case M_DT:
+ if (fnmatch(s->match.dt, m->dt, 0) == 0)
+ matched_flags |= flag;
+ break;
+ case M_UDEV_TYPE:
+ if (s->match.udev_type & m->udev_type)
+ matched_flags |= flag;
+ break;
+ default:
+ abort();
+ }
+
+ if (prev_matched_flags != matched_flags) {
+ qlog_debug(ctx,
+ "%s matches for %s\n",
+ s->name,
+ matchflagname(flag));
+ }
+ }
+
+ if (s->match.bits == matched_flags) {
+ qlog_debug(ctx, "%s is full match\n", s->name);
+ quirk_apply_section(ctx, q, s);
+ }
+
+ return true;
+}
+
+struct quirks *
+quirks_fetch_for_device(struct quirks_context *ctx,
+ struct device *device)
+{
+ struct section *s;
+ struct match *m;
+
+ if (!ctx)
+ return NULL;
+
+ qlog_debug(ctx, "%s: fetching quirks\n", device->path);
+
+ _unref_(quirks) *q = quirks_new();
+
+ m = match_new(device, ctx->dmi, ctx->dt);
+
+ list_for_each(s, &ctx->sections, link) {
+ quirk_match_section(ctx, q, s, m, device);
+ }
+
+ match_free(m);
+
+ if (q->nproperties == 0) {
+ return NULL;
+ }
+
+ list_insert(&ctx->quirks, &q->link);
+
+ return steal(&q);
+}
+
+static inline struct property *
+quirk_find_prop(struct quirks *q, enum quirk which)
+{
+ /* Run backwards to only handle the last one assigned */
+ for (ssize_t i = q->nproperties - 1; i >= 0; i--) {
+ struct property *p = q->properties[i];
+ if (p->id == which)
+ return p;
+ }
+
+ return NULL;
+}
+
+bool
+quirks_has_quirk(struct quirks *q, enum quirk which)
+{
+ return quirk_find_prop(q, which) != NULL;
+}
+
+bool
+quirks_get_int32(struct quirks *q, enum quirk which, int32_t *val)
+{
+ struct property *p;
+
+ if (!q)
+ return false;
+
+ p = quirk_find_prop(q, which);
+ if (!p)
+ return false;
+
+ assert(p->type == PT_INT);
+ *val = p->value.i;
+
+ return true;
+}
+
+bool
+quirks_get_uint32(struct quirks *q, enum quirk which, uint32_t *val)
+{
+ struct property *p;
+
+ if (!q)
+ return false;
+
+ p = quirk_find_prop(q, which);
+ if (!p)
+ return false;
+
+ assert(p->type == PT_UINT);
+ *val = p->value.u;
+
+ return true;
+}
+
+bool
+quirks_get_double(struct quirks *q, enum quirk which, double *val)
+{
+ struct property *p;
+
+ if (!q)
+ return false;
+
+ p = quirk_find_prop(q, which);
+ if (!p)
+ return false;
+
+ assert(p->type == PT_DOUBLE);
+ *val = p->value.d;
+
+ return true;
+}
+
+bool
+quirks_get_string(struct quirks *q, enum quirk which, char **val)
+{
+ struct property *p;
+
+ if (!q)
+ return false;
+
+ p = quirk_find_prop(q, which);
+ if (!p)
+ return false;
+
+ assert(p->type == PT_STRING);
+ *val = p->value.s;
+
+ return true;
+}
+
+bool
+quirks_get_bool(struct quirks *q, enum quirk which, bool *val)
+{
+ struct property *p;
+
+ if (!q)
+ return false;
+
+ p = quirk_find_prop(q, which);
+ if (!p)
+ return false;
+
+ assert(p->type == PT_BOOL);
+ *val = p->value.b;
+
+ return true;
+}
+
+bool
+quirks_get_dimensions(struct quirks *q,
+ enum quirk which,
+ struct quirk_dimensions *val)
+{
+ struct property *p;
+
+ if (!q)
+ return false;
+
+ p = quirk_find_prop(q, which);
+ if (!p)
+ return false;
+
+ assert(p->type == PT_DIMENSION);
+ *val = p->value.dim;
+
+ return true;
+}
+
+bool
+quirks_get_range(struct quirks *q,
+ enum quirk which,
+ struct quirk_range *val)
+{
+ struct property *p;
+
+ if (!q)
+ return false;
+
+ p = quirk_find_prop(q, which);
+ if (!p)
+ return false;
+
+ assert(p->type == PT_RANGE);
+ *val = p->value.range;
+
+ return true;
+}
+
+bool
+quirks_get_tuples(struct quirks *q,
+ enum quirk which,
+ const struct quirk_tuples **tuples)
+{
+ struct property *p;
+
+ if (!q)
+ return false;
+
+ p = quirk_find_prop(q, which);
+ if (!p)
+ return false;
+
+ assert(p->type == PT_TUPLES);
+ *tuples = &p->value.tuples;
+
+ return true;
+}
+
+bool
+quirks_get_uint32_array(struct quirks *q,
+ enum quirk which,
+ const uint32_t **array,
+ size_t *nelements)
+{
+ struct property *p;
+
+ if (!q)
+ return false;
+
+ p = quirk_find_prop(q, which);
+ if (!p)
+ return false;
+
+ assert(p->type == PT_UINT_ARRAY);
+ *array = p->value.array.data.u;
+ *nelements = p->value.array.nelements;
+
+ return true;
+}
diff --git a/usr.sbin/moused/moused/quirks.h b/usr.sbin/moused/moused/quirks.h
new file mode 100644
index 000000000000..6a34d17be83c
--- /dev/null
+++ b/usr.sbin/moused/moused/quirks.h
@@ -0,0 +1,369 @@
+/*
+ * Copyright © 2018 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#pragma once
+
+#include "util.h"
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <syslog.h>
+
+/**
+ * Handle to the quirks context.
+ */
+struct quirks_context;
+
+/**
+ * Contains all quirks set for a single device.
+ */
+struct quirks;
+
+struct quirk_dimensions {
+ size_t x, y;
+};
+
+struct quirk_range {
+ int lower, upper;
+};
+
+struct quirk_tuples {
+ struct {
+ int first;
+ int second;
+ int third;
+ } tuples[32];
+ size_t ntuples;
+};
+
+/**
+ * Quirks known to libinput. Moused does not support all of them.
+ */
+enum quirk {
+ QUIRK_MODEL_ALPS_SERIAL_TOUCHPAD = 100,
+ QUIRK_MODEL_APPLE_TOUCHPAD,
+ QUIRK_MODEL_APPLE_TOUCHPAD_ONEBUTTON,
+ QUIRK_MODEL_BOUNCING_KEYS,
+ QUIRK_MODEL_CHROMEBOOK,
+ QUIRK_MODEL_CLEVO_W740SU,
+ QUIRK_MODEL_DELL_CANVAS_TOTEM,
+ QUIRK_MODEL_HP_PAVILION_DM4_TOUCHPAD,
+ QUIRK_MODEL_HP_ZBOOK_STUDIO_G3,
+ QUIRK_MODEL_INVERT_HORIZONTAL_SCROLLING,
+ QUIRK_MODEL_LENOVO_SCROLLPOINT,
+ QUIRK_MODEL_LENOVO_T450_TOUCHPAD,
+ QUIRK_MODEL_LENOVO_X1GEN6_TOUCHPAD,
+ QUIRK_MODEL_LENOVO_X230,
+ QUIRK_MODEL_SYNAPTICS_SERIAL_TOUCHPAD,
+ QUIRK_MODEL_SYSTEM76_BONOBO,
+ QUIRK_MODEL_SYSTEM76_GALAGO,
+ QUIRK_MODEL_SYSTEM76_KUDU,
+ QUIRK_MODEL_TABLET_MODE_NO_SUSPEND,
+ QUIRK_MODEL_TABLET_MODE_SWITCH_UNRELIABLE,
+ QUIRK_MODEL_TOUCHPAD_VISIBLE_MARKER,
+ QUIRK_MODEL_TRACKBALL,
+ QUIRK_MODEL_WACOM_TOUCHPAD,
+ QUIRK_MODEL_PRESSURE_PAD,
+ QUIRK_MODEL_TOUCHPAD_PHANTOM_CLICKS,
+
+ _QUIRK_LAST_MODEL_QUIRK_, /* Guard: do not modify */
+
+ QUIRK_ATTR_SIZE_HINT = 300,
+ QUIRK_ATTR_TOUCH_SIZE_RANGE,
+ QUIRK_ATTR_PALM_SIZE_THRESHOLD,
+ QUIRK_ATTR_LID_SWITCH_RELIABILITY,
+ QUIRK_ATTR_KEYBOARD_INTEGRATION,
+ QUIRK_ATTR_TRACKPOINT_INTEGRATION,
+ QUIRK_ATTR_TPKBCOMBO_LAYOUT,
+ QUIRK_ATTR_PRESSURE_RANGE,
+ QUIRK_ATTR_PALM_PRESSURE_THRESHOLD,
+ QUIRK_ATTR_RESOLUTION_HINT,
+ QUIRK_ATTR_TRACKPOINT_MULTIPLIER,
+ QUIRK_ATTR_THUMB_PRESSURE_THRESHOLD,
+ QUIRK_ATTR_USE_VELOCITY_AVERAGING,
+ QUIRK_ATTR_TABLET_SMOOTHING,
+ QUIRK_ATTR_THUMB_SIZE_THRESHOLD,
+ QUIRK_ATTR_MSC_TIMESTAMP,
+ QUIRK_ATTR_EVENT_CODE,
+ QUIRK_ATTR_INPUT_PROP,
+
+ _QUIRK_LAST_ATTR_QUIRK_, /* Guard: do not modify */
+
+
+ /* Daemon parameters */
+ MOUSED_GRAB_DEVICE = 1000,
+ MOUSED_IGNORE_DEVICE,
+
+ /* Standard moused parameters */
+ MOUSED_CLICK_THRESHOLD,
+ MOUSED_DRIFT_TERMINATE,
+ MOUSED_DRIFT_DISTANCE,
+ MOUSED_DRIFT_TIME,
+ MOUSED_DRIFT_AFTER,
+ MOUSED_EMULATE_THIRD_BUTTON,
+ MOUSED_EMULATE_THIRD_BUTTON_TIMEOUT,
+ MOUSED_EXPONENTIAL_ACCEL,
+ MOUSED_EXPONENTIAL_OFFSET,
+ MOUSED_LINEAR_ACCEL_X,
+ MOUSED_LINEAR_ACCEL_Y,
+ MOUSED_LINEAR_ACCEL_Z,
+ MOUSED_MAP_Z_AXIS,
+ MOUSED_VIRTUAL_SCROLL_ENABLE,
+ MOUSED_HOR_VIRTUAL_SCROLL_ENABLE,
+ MOUSED_VIRTUAL_SCROLL_SPEED,
+ MOUSED_VIRTUAL_SCROLL_THRESHOLD,
+ MOUSED_WMODE,
+
+ /* Touchpad parameters from psm(4) driver */
+ MOUSED_TWO_FINGER_SCROLL,
+ MOUSED_NATURAL_SCROLL,
+ MOUSED_THREE_FINGER_DRAG,
+ MOUSED_SOFTBUTTON2_X,
+ MOUSED_SOFTBUTTON3_X,
+ MOUSED_SOFTBUTTONS_Y,
+ MOUSED_TAP_TIMEOUT,
+ MOUSED_TAP_PRESSURE_THRESHOLD,
+ MOUSED_TAP_MAX_DELTA,
+ MOUSED_TAPHOLD_TIMEOUT,
+ MOUSED_VSCROLL_MIN_DELTA,
+ MOUSED_VSCROLL_HOR_AREA,
+ MOUSED_VSCROLL_VER_AREA,
+
+ _MOUSED_LAST_OPTION_ /* Guard: do not modify */
+};
+
+/**
+ * Returns a printable name for the quirk. This name is for developer
+ * tools, not user consumption. Do not display this in a GUI.
+ */
+const char*
+quirk_get_name(enum quirk q);
+
+/**
+ * Log priorities used if custom logging is enabled.
+ */
+enum quirks_log_priorities {
+ QLOG_NOISE = LOG_DEBUG + 1,
+ QLOG_DEBUG = LOG_DEBUG,
+ QLOG_INFO = LOG_INFO,
+ QLOG_ERROR = LOG_ERR,
+ QLOG_PARSER_ERROR = LOG_CRIT,
+};
+
+/**
+ * Log type to be used for logging. Use the moused logging to hook up a
+ * moused log handler. This will cause the quirks to reduce the noise and
+ * only provide useful messages.
+ *
+ * QLOG_CUSTOM_LOG_PRIORITIES enables more fine-grained and verbose logging,
+ * allowing debugging tools to be more useful.
+ */
+enum quirks_log_type {
+ QLOG_MOUSED_LOGGING,
+ QLOG_CUSTOM_LOG_PRIORITIES,
+};
+
+/**
+ * Initialize the quirks subsystem. This function must be called
+ * before anything else.
+ *
+ * If log_type is QLOG_CUSTOM_LOG_PRIORITIES, the log handler is called with
+ * the custom QLOG_* log priorities. Otherwise, the log handler only uses
+ * the moused (syslog) log priorities.
+ *
+ * @param config_file A file path to main configuration file
+ * @param quirks_path The directory containing the various quirk files
+ * @param log_handler The moused log handler called for debugging output
+ *
+ * @return an opaque handle to the context
+ */
+struct quirks_context *
+quirks_init_subsystem(const char *config_file,
+ const char *quirks_path,
+ moused_log_handler log_handler,
+ enum quirks_log_type log_type);
+
+/**
+ * Clean up after ourselves. This function must be called
+ * as the last call to the quirks subsystem.
+ *
+ * All quirks returned to the caller in quirks_fetch_for_device() must be
+ * unref'd before this call.
+ *
+ * @return Always NULL
+ */
+struct quirks_context *
+quirks_context_unref(struct quirks_context *ctx);
+
+DEFINE_UNREF_CLEANUP_FUNC(quirks_context);
+
+struct quirks_context *
+quirks_context_ref(struct quirks_context *ctx);
+
+/**
+ * Fetch the quirks for a given device. If no quirks are defined, this
+ * function returns NULL.
+ *
+ * @return A new quirks struct, use quirks_unref() to release
+ */
+struct quirks *
+quirks_fetch_for_device(struct quirks_context *ctx,
+ struct device *device);
+
+/**
+ * Reduce the refcount by one. When the refcount reaches zero, the
+ * associated struct is released.
+ *
+ * @return Always NULL
+ */
+struct quirks *
+quirks_unref(struct quirks *q);
+
+DEFINE_UNREF_CLEANUP_FUNC(quirks);
+
+/**
+ * Returns true if the given quirk applies is in this quirk list.
+ */
+bool
+quirks_has_quirk(struct quirks *q, enum quirk which);
+
+/**
+ * Get the value of the given quirk, as unsigned integer.
+ * This function will assert if the quirk type does not match the
+ * requested type. If the quirk is not set for this device, val is
+ * unchanged.
+ *
+ * @return true if the quirk value is valid, false otherwise.
+ */
+bool
+quirks_get_uint32(struct quirks *q,
+ enum quirk which,
+ uint32_t *val);
+
+/**
+ * Get the value of the given quirk, as signed integer.
+ * This function will assert if the quirk type does not match the
+ * requested type. If the quirk is not set for this device, val is
+ * unchanged.
+ *
+ * @return true if the quirk value is valid, false otherwise.
+ */
+bool
+quirks_get_int32(struct quirks *q,
+ enum quirk which,
+ int32_t *val);
+
+/**
+ * Get the value of the given quirk, as double.
+ * This function will assert if the quirk type does not match the
+ * requested type. If the quirk is not set for this device, val is
+ * unchanged.
+ *
+ * @return true if the quirk value is valid, false otherwise.
+ */
+bool
+quirks_get_double(struct quirks *q,
+ enum quirk which,
+ double *val);
+
+/**
+ * Get the value of the given quirk, as string.
+ * This function will assert if the quirk type does not match the
+ * requested type. If the quirk is not set for this device, val is
+ * unchanged.
+ *
+ * val is set to the string, do not modify or free it. The lifetime of the
+ * returned string is bound to the lifetime of the quirk.
+ *
+ * @return true if the quirk value is valid, false otherwise.
+ */
+bool
+quirks_get_string(struct quirks *q,
+ enum quirk which,
+ char **val);
+
+/**
+ * Get the value of the given quirk, as bool.
+ * This function will assert if the quirk type does not match the
+ * requested type. If the quirk is not set for this device, val is
+ * unchanged.
+ *
+ * @return true if the quirk value is valid, false otherwise.
+ */
+bool
+quirks_get_bool(struct quirks *q,
+ enum quirk which,
+ bool *val);
+
+/**
+ * Get the value of the given quirk, as dimension.
+ * This function will assert if the quirk type does not match the
+ * requested type. If the quirk is not set for this device, val is
+ * unchanged.
+ *
+ * @return true if the quirk value is valid, false otherwise.
+ */
+bool
+quirks_get_dimensions(struct quirks *q,
+ enum quirk which,
+ struct quirk_dimensions *val);
+
+/**
+ * Get the value of the given quirk, as range.
+ * This function will assert if the quirk type does not match the
+ * requested type. If the quirk is not set for this device, val is
+ * unchanged.
+ *
+ * @return true if the quirk value is valid, false otherwise.
+ */
+bool
+quirks_get_range(struct quirks *q,
+ enum quirk which,
+ struct quirk_range *val);
+
+/**
+ * Get the tuples of the given quirk.
+ * This function will assert if the quirk type does not match the
+ * requested type. If the quirk is not set for this device, tuples is
+ * unchanged.
+ *
+ * @return true if the quirk value is valid, false otherwise.
+ */
+bool
+quirks_get_tuples(struct quirks *q,
+ enum quirk which,
+ const struct quirk_tuples **tuples);
+
+/**
+ * Get the uint32 array of the given quirk.
+ * This function will assert if the quirk type does not match the
+ * requested type. If the quirk is not set for this device, tuples is
+ * unchanged.
+ *
+ * @return true if the quirk value is valid, false otherwise.
+ */
+bool
+quirks_get_uint32_array(struct quirks *q,
+ enum quirk which,
+ const uint32_t **array,
+ size_t *nelements);
diff --git a/usr.sbin/moused/moused/quirks/5-generic-touchpad.quirks b/usr.sbin/moused/moused/quirks/5-generic-touchpad.quirks
new file mode 100644
index 000000000000..c741ffc80bd6
--- /dev/null
+++ b/usr.sbin/moused/moused/quirks/5-generic-touchpad.quirks
@@ -0,0 +1,9 @@
+# Do not edit this file, it will be overwritten on update
+
+[SynPS/2 Synaptics TouchPad]
+MatchDevType=touchpad
+MatchName=SynPS/2 Synaptics TouchPad
+AttrPressureRange=35:30
+MousedTapPressureThreshold=44
+#AttrThumbPressureThreshold=45
+AttrPalmPressureThreshold=220
diff --git a/usr.sbin/moused/moused/util-evdev.c b/usr.sbin/moused/moused/util-evdev.c
new file mode 100644
index 000000000000..925979fdc02c
--- /dev/null
+++ b/usr.sbin/moused/moused/util-evdev.c
@@ -0,0 +1,173 @@
+/*
+ * Copyright © 2013 David Herrmann <dh.herrmann@gmail.com>
+ * Copyright © 2013 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <dev/evdev/input.h>
+
+#include "event-names.h"
+#include "util-evdev.h"
+
+#define ARRAY_LENGTH(a) (sizeof(a) / (sizeof((a)[0])))
+
+struct name_lookup {
+ const char *name;
+ size_t len;
+};
+
+static inline bool
+startswith(const char *str, size_t len, const char *prefix, size_t plen)
+{
+ return len >= plen && !strncmp(str, prefix, plen);
+}
+
+static int type_from_prefix(const char *name, ssize_t len)
+{
+ const char *e;
+ size_t i;
+ ssize_t l;
+
+ /* MAX_ is not allowed, even though EV_MAX exists */
+ if (startswith(name, len, "MAX_", 4))
+ return -1;
+ /* BTN_ is special as there is no EV_BTN type */
+ if (startswith(name, len, "BTN_", 4))
+ return EV_KEY;
+ /* FF_STATUS_ is special as FF_ is a prefix of it, so test it first */
+ if (startswith(name, len, "FF_STATUS_", 10))
+ return EV_FF_STATUS;
+
+ for (i = 0; i < ARRAY_LENGTH(ev_names); ++i) {
+ /* skip EV_ prefix so @e is suffix of [EV_]XYZ */
+ e = &ev_names[i].name[3];
+ l = strlen(e);
+
+ /* compare prefix and test for trailing _ */
+ if (len > l && startswith(name, len, e, l) && name[l] == '_')
+ return ev_names[i].value;
+ }
+
+ return -1;
+}
+
+static int cmp_entry(const void *vlookup, const void *ventry)
+{
+ const struct name_lookup *lookup = vlookup;
+ const struct name_entry *entry = ventry;
+ int r;
+
+ r = strncmp(lookup->name, entry->name, lookup->len);
+ if (!r) {
+ if (entry->name[lookup->len])
+ r = -1;
+ else
+ r = 0;
+ }
+
+ return r;
+}
+
+static const struct name_entry*
+lookup_name(const struct name_entry *array, size_t asize,
+ struct name_lookup *lookup)
+{
+ const struct name_entry *entry;
+
+ entry = bsearch(lookup, array, asize, sizeof(*array), cmp_entry);
+ if (!entry)
+ return NULL;
+
+ return entry;
+}
+
+int
+libevdev_event_type_get_max(unsigned int type)
+{
+ if (type > EV_MAX)
+ return -1;
+
+ return ev_max[type];
+}
+
+int
+libevdev_event_code_from_name(unsigned int type, const char *name)
+{
+ struct name_lookup lookup;
+ const struct name_entry *entry;
+ int real_type;
+ size_t len = strlen(name);
+
+ real_type = type_from_prefix(name, len);
+ if (real_type < 0 || (unsigned int)real_type != type)
+ return -1;
+
+ lookup.name = name;
+ lookup.len = len;
+
+ entry = lookup_name(code_names, ARRAY_LENGTH(code_names), &lookup);
+
+ return entry ? (int)entry->value : -1;
+}
+
+static int
+libevdev_event_type_from_name_n(const char *name, size_t len)
+{
+ struct name_lookup lookup;
+ const struct name_entry *entry;
+
+ lookup.name = name;
+ lookup.len = len;
+
+ entry = lookup_name(ev_names, ARRAY_LENGTH(ev_names), &lookup);
+
+ return entry ? (int)entry->value : -1;
+}
+
+int
+libevdev_event_type_from_name(const char *name)
+{
+ return libevdev_event_type_from_name_n(name, strlen(name));
+}
+
+static int
+libevdev_property_from_name_n(const char *name, size_t len)
+{
+ struct name_lookup lookup;
+ const struct name_entry *entry;
+
+ lookup.name = name;
+ lookup.len = len;
+
+ entry = lookup_name(prop_names, ARRAY_LENGTH(prop_names), &lookup);
+
+ return entry ? (int)entry->value : -1;
+}
+
+int
+libevdev_property_from_name(const char *name)
+{
+ return libevdev_property_from_name_n(name, strlen(name));
+}
diff --git a/usr.sbin/moused/moused/util-evdev.h b/usr.sbin/moused/moused/util-evdev.h
new file mode 100644
index 000000000000..cb2e3f1fb935
--- /dev/null
+++ b/usr.sbin/moused/moused/util-evdev.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright © 2013 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ */
+
+#ifndef UTIL_EVDEV_H
+#define UTIL_EVDEV_H
+
+#include <dev/evdev/input.h>
+
+int libevdev_event_code_from_name(unsigned int type, const char *name);
+int libevdev_event_type_get_max(unsigned int type);
+int libevdev_event_type_from_name(const char *name);
+int libevdev_property_from_name(const char *name);
+
+#endif
diff --git a/usr.sbin/moused/moused/util-list.c b/usr.sbin/moused/moused/util-list.c
new file mode 100644
index 000000000000..7f85b368076c
--- /dev/null
+++ b/usr.sbin/moused/moused/util-list.c
@@ -0,0 +1,86 @@
+/*
+ * Copyright © 2008-2011 Kristian Høgsberg
+ * Copyright © 2011 Intel Corporation
+ * Copyright © 2013-2015 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdbool.h>
+
+#include "util-list.h"
+
+void
+list_init(struct list *list)
+{
+ list->prev = list;
+ list->next = list;
+}
+
+void
+list_insert(struct list *list, struct list *elm)
+{
+ assert((list->next != NULL && list->prev != NULL) ||
+ !"list->next|prev is NULL, possibly missing list_init()");
+ assert(((elm->next == NULL && elm->prev == NULL) || list_empty(elm)) ||
+ !"elm->next|prev is not NULL, list node used twice?");
+
+ elm->prev = list;
+ elm->next = list->next;
+ list->next = elm;
+ elm->next->prev = elm;
+}
+
+void
+list_append(struct list *list, struct list *elm)
+{
+ assert((list->next != NULL && list->prev != NULL) ||
+ !"list->next|prev is NULL, possibly missing list_init()");
+ assert(((elm->next == NULL && elm->prev == NULL) || list_empty(elm)) ||
+ !"elm->next|prev is not NULL, list node used twice?");
+
+ elm->next = list;
+ elm->prev = list->prev;
+ list->prev = elm;
+ elm->prev->next = elm;
+}
+
+void
+list_remove(struct list *elm)
+{
+ assert((elm->next != NULL && elm->prev != NULL) ||
+ !"list->next|prev is NULL, possibly missing list_init()");
+
+ elm->prev->next = elm->next;
+ elm->next->prev = elm->prev;
+ elm->next = NULL;
+ elm->prev = NULL;
+}
+
+bool
+list_empty(const struct list *list)
+{
+ assert((list->next != NULL && list->prev != NULL) ||
+ !"list->next|prev is NULL, possibly missing list_init()");
+
+ return list->next == list;
+}
diff --git a/usr.sbin/moused/moused/util-list.h b/usr.sbin/moused/moused/util-list.h
new file mode 100644
index 000000000000..d7a8ce724d22
--- /dev/null
+++ b/usr.sbin/moused/moused/util-list.h
@@ -0,0 +1,194 @@
+/*
+ * Copyright © 2008-2011 Kristian Høgsberg
+ * Copyright © 2011 Intel Corporation
+ * Copyright © 2013-2015 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#pragma once
+
+#include <stdbool.h>
+#include <stddef.h>
+
+/*
+ * This list data structure is a verbatim copy from wayland-util.h from the
+ * Wayland project; except that wl_ prefix has been removed.
+ */
+
+
+/**
+ * Doubly linked list implementation. This struct is used for both the list
+ * nodes and the list head. Use like this:
+ *
+ * @code
+ *
+ * struct foo {
+ * struct list list_of_bars; // the list head
+ * };
+ *
+ * struct bar {
+ * struct list link; // links between the bars
+ * };
+ *
+ * struct foo *f = zalloc(sizeof *f);
+ * struct bar *b = make_some_bar();
+ *
+ * list_init(&f->list_of_bars);
+ * list_append(&f->list_of_bars, &b->link);
+ * list_remove(&b->link);
+ * @endcode
+ */
+struct list {
+ struct list *prev;
+ struct list *next;
+};
+
+/**
+ * Initialize a list head. This function *must* be called once for each list
+ * head. This function *must not* be called for a node to be added to a
+ * list.
+ */
+void list_init(struct list *list);
+
+/**
+ * Insert an element at the front of the list
+ */
+void list_insert(struct list *list, struct list *elm);
+/**
+ * Append an element to the back of the list
+ */
+void list_append(struct list *list, struct list *elm);
+
+/**
+ * Remove an element from list.
+ *
+ * Removing a list element is only possible once, the caller must track
+ * whether the list node has already been removed.
+ *
+ */
+void list_remove(struct list *elm);
+/**
+ * Returns true if the given list head is an empty list.
+ */
+bool list_empty(const struct list *list);
+
+/**
+ * Return the 'type' parent container struct of 'ptr' of which
+ * 'member' is our 'ptr' field. For example:
+ *
+ * @code
+ * struct foo { // the parent container struct
+ * uint32_t a;
+ * struct bar bar_member; // the member field
+ * };
+ *
+ * struct foo *f = zalloc(sizeof *f);
+ * struct bar *b = &f->bar_member;
+ * struct foo *f2 = container_of(b, struct foo, bar_member);
+ *
+ * assert(f == f2);
+ * @endcode
+ */
+#define container_of(ptr, type, member) \
+ (__typeof__(type) *)((char *)(ptr) - \
+ offsetof(__typeof__(type), member))
+
+/**
+ * Given a list 'head', return the first entry of type 'pos' that has a
+ * member 'link'.
+ *
+ * The 'pos' argument is solely used to determine the type be returned and
+ * not modified otherwise. It is common to use the same pointer that the
+ * return value of list_first_entry() is assigned to, for example:
+ *
+ * @code
+ * struct foo {
+ * struct list list_of_bars;
+ * };
+ *
+ * struct bar {
+ * struct list link;
+ * }
+ *
+ * struct foo *f = get_a_foo();
+ * struct bar *b = 0; // initialize to avoid static analysis errors
+ * b = list_first_entry(&f->list_of_bars, b, link);
+ * @endcode
+ */
+#define list_first_entry(head, pointer_of_type, member) \
+ container_of((head)->next, __typeof__(*pointer_of_type), member)
+
+/**
+ * Given a list 'head', return the first entry of type 'container_type' that
+ * has a member 'link'.
+ *
+ * @code
+ * struct foo {
+ * struct list list_of_bars;
+ * };
+ *
+ * struct bar {
+ * struct list link;
+ * }
+ *
+ * struct foo *f = get_a_foo();
+ * struct bar *b = list_first_entry(&f->list_of_bars, struct bar, link);
+ * @endcode
+ */
+#define list_first_entry_by_type(head, container_type, member) \
+ container_of((head)->next, container_type, member)
+
+/**
+ * Iterate through the list.
+ *
+ * @code
+ * struct foo *f = get_a_foo();
+ * struct bar *element;
+ * list_for_each(element, &f->list_of_bars, link) {
+ * }
+ * @endcode
+ *
+ * If a list node needs to be removed during iteration, use
+ * list_for_each_safe().
+ */
+#define list_for_each(pos, head, member) \
+ for (pos = list_first_entry_by_type(head, __typeof__(*pos), member); \
+ &pos->member != (head); \
+ pos = list_first_entry_by_type(&pos->member, __typeof__(*pos), member))
+
+/**
+ * Iterate through the list. Equivalent to list_for_each() but allows
+ * calling list_remove() on the element.
+ *
+ * @code
+ * struct foo *f = get_a_foo();
+ * struct bar *element;
+ * list_for_each(element, tmp, &f->list_of_bars, link) {
+ * list_remove(&element->link);
+ * }
+ * @endcode
+ */
+#define list_for_each_safe(pos, head, member) \
+ pos = list_first_entry_by_type(head, __typeof__(*pos), member); \
+ for (__typeof__(pos) _tmp = list_first_entry_by_type(&pos->member, __typeof__(*_tmp), member); \
+ &pos->member != (head); \
+ pos = _tmp, \
+ _tmp = list_first_entry_by_type(&pos->member, __typeof__(*_tmp), member))
diff --git a/usr.sbin/moused/moused/util.c b/usr.sbin/moused/moused/util.c
new file mode 100644
index 000000000000..09bcc42b0f19
--- /dev/null
+++ b/usr.sbin/moused/moused/util.c
@@ -0,0 +1,423 @@
+/*
+ * Copyright © 2008 Kristian Høgsberg
+ * Copyright © 2013-2019 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <dev/evdev/input.h>
+
+#include <assert.h>
+#include <ctype.h>
+#include <dirent.h>
+#include <errno.h>
+#include <limits.h>
+#include <math.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <xlocale.h>
+
+#include "util.h"
+#include "util-evdev.h"
+#include "util-list.h"
+
+/* util-strings.c */
+
+/**
+ * Return the next word in a string pointed to by state before the first
+ * separator character. Call repeatedly to tokenize a whole string.
+ *
+ * @param state Current state
+ * @param len String length of the word returned
+ * @param separators List of separator characters
+ *
+ * @return The first word in *state, NOT null-terminated
+ */
+static const char *
+next_word(const char **state, size_t *len, const char *separators)
+{
+ const char *next = *state;
+ size_t l;
+
+ if (!*next)
+ return NULL;
+
+ next += strspn(next, separators);
+ if (!*next) {
+ *state = next;
+ return NULL;
+ }
+
+ l = strcspn(next, separators);
+ *state = next + l;
+ *len = l;
+
+ return next;
+}
+
+/**
+ * Return a null-terminated string array with the tokens in the input
+ * string, e.g. "one two\tthree" with a separator list of " \t" will return
+ * an array [ "one", "two", "three", NULL ] and num elements 3.
+ *
+ * Use strv_free() to free the array.
+ *
+ * Another example:
+ * result = strv_from_string("+1-2++3--4++-+5-+-", "+-", &nelem)
+ * result == [ "1", "2", "3", "4", "5", NULL ] and nelem == 5
+ *
+ * @param in Input string
+ * @param separators List of separator characters
+ * @param num_elements Number of elements found in the input string
+ *
+ * @return A null-terminated string array or NULL on errors
+ */
+char **
+strv_from_string(const char *in, const char *separators, size_t *num_elements)
+{
+ assert(in != NULL);
+ assert(separators != NULL);
+ assert(num_elements != NULL);
+
+ const char *s = in;
+ size_t l, nelems = 0;
+ while (next_word(&s, &l, separators) != NULL)
+ nelems++;
+
+ if (nelems == 0) {
+ *num_elements = 0;
+ return NULL;
+ }
+
+ size_t strv_len = nelems + 1; /* NULL-terminated */
+ char **strv = zalloc(strv_len * sizeof *strv);
+
+ size_t idx = 0;
+ const char *word;
+ s = in;
+ while ((word = next_word(&s, &l, separators)) != NULL) {
+ char *copy = strndup(word, l);
+ if (!copy) {
+ strv_free(strv);
+ *num_elements = 0;
+ return NULL;
+ }
+
+ strv[idx++] = copy;
+ }
+
+ *num_elements = nelems;
+
+ return strv;
+}
+
+/**
+ * Iterate through strv, calling func with each string and its respective index.
+ * Iteration stops successfully after max elements or at the last element,
+ * whichever occurs first.
+ *
+ * If func returns non-zero, iteration stops and strv_for_each returns
+ * that value.
+ *
+ * @return zero on success, otherwise the error returned by the callback
+ */
+int strv_for_each_n(const char **strv, size_t max, strv_foreach_callback_t func, void *data)
+{
+ for (size_t i = 0; i < max && strv && strv[i]; i++) {
+ int ret = func(strv[i], i, data);
+ if (ret)
+ return ret;
+ }
+ return 0;
+}
+
+/* !util-strings.c */
+
+/* util-prop-parsers.c */
+
+/**
+ * Parses a simple dimension string in the form of "10x40". The two
+ * numbers must be positive integers in decimal notation.
+ * On success, the two numbers are stored in w and h. On failure, w and h
+ * are unmodified.
+ *
+ * @param prop The value of the property
+ * @param w Returns the first component of the dimension
+ * @param h Returns the second component of the dimension
+ * @return true on success, false otherwise
+ */
+bool
+parse_dimension_property(const char *prop, size_t *w, size_t *h)
+{
+ int x, y;
+
+ if (!prop)
+ return false;
+
+ if (sscanf(prop, "%dx%d", &x, &y) != 2)
+ return false;
+
+ if (x <= 0 || y <= 0)
+ return false;
+
+ *w = (size_t)x;
+ *h = (size_t)y;
+ return true;
+}
+
+/**
+ * Parses a string of the format "a:b" where both a and b must be integer
+ * numbers and a > b. Also allowed is the special string value "none" which
+ * amounts to unsetting the property.
+ *
+ * @param prop The value of the property
+ * @param hi Set to the first digit or 0 in case of 'none'
+ * @param lo Set to the second digit or 0 in case of 'none'
+ * @return true on success, false otherwise
+ */
+bool
+parse_range_property(const char *prop, int *hi, int *lo)
+{
+ int first, second;
+
+ if (!prop)
+ return false;
+
+ if (streq(prop, "none")) {
+ *hi = 0;
+ *lo = 0;
+ return true;
+ }
+
+ if (sscanf(prop, "%d:%d", &first, &second) != 2)
+ return false;
+
+ if (second >= first)
+ return false;
+
+ *hi = first;
+ *lo = second;
+
+ return true;
+}
+
+bool
+parse_boolean_property(const char *prop, bool *b)
+{
+ if (!prop)
+ return false;
+
+ if (streq(prop, "1"))
+ *b = true;
+ else if (streq(prop, "0"))
+ *b = false;
+ else
+ return false;
+
+ return true;
+}
+
+static bool
+parse_evcode_string(const char *s, int *type_out, int *code_out)
+{
+ int type, code;
+
+ if (strstartswith(s, "EV_")) {
+ type = libevdev_event_type_from_name(s);
+ if (type == -1)
+ return false;
+
+ code = EVENT_CODE_UNDEFINED;
+ } else {
+ struct map {
+ const char *str;
+ int type;
+ } map[] = {
+ { "KEY_", EV_KEY },
+ { "BTN_", EV_KEY },
+ { "ABS_", EV_ABS },
+ { "REL_", EV_REL },
+ { "SW_", EV_SW },
+ };
+ bool found = false;
+
+ ARRAY_FOR_EACH(map, m) {
+ if (!strstartswith(s, m->str))
+ continue;
+
+ type = m->type;
+ code = libevdev_event_code_from_name(type, s);
+ if (code == -1)
+ return false;
+
+ found = true;
+ break;
+ }
+ if (!found)
+ return false;
+ }
+
+ *type_out = type;
+ *code_out = code;
+
+ return true;
+}
+
+/**
+ * Parses a string of the format "+EV_ABS;+KEY_A;-BTN_TOOL_DOUBLETAP;-ABS_X;"
+ * where each element must be + or - (enable/disable) followed by a named event
+ * type OR a named event code OR a tuple in the form of EV_KEY:0x123, i.e. a
+ * named event type followed by a hex event code.
+ *
+ * events must point to an existing array of size nevents.
+ * nevents specifies the size of the array in events and returns the number
+ * of items, elements exceeding nevents are simply ignored, just make sure
+ * events is large enough for your use-case.
+ *
+ * The results are returned as input events with type and code set, all
+ * other fields undefined. Where only the event type is specified, the code
+ * is set to EVENT_CODE_UNDEFINED.
+ *
+ * On success, events contains nevents events with each event's value set to 1
+ * or 0 depending on the + or - prefix.
+ */
+bool
+parse_evcode_property(const char *prop, struct input_event *events, size_t *nevents)
+{
+ bool rc = false;
+ /* A randomly chosen max so we avoid crazy quirks */
+ struct input_event evs[32];
+
+ memset(evs, 0, sizeof evs);
+
+ size_t ncodes;
+ char **strv = strv_from_string(prop, ";", &ncodes);
+ if (!strv || ncodes == 0 || ncodes > ARRAY_LENGTH(evs))
+ goto out;
+
+ ncodes = min(*nevents, ncodes);
+ for (size_t idx = 0; strv[idx]; idx++) {
+ char *s = strv[idx];
+ bool enable;
+
+ switch (*s) {
+ case '+': enable = true; break;
+ case '-': enable = false; break;
+ default:
+ goto out;
+ }
+
+ s++;
+
+ int type, code;
+
+ if (strstr(s, ":") == NULL) {
+ if (!parse_evcode_string(s, &type, &code))
+ goto out;
+ } else {
+ int consumed;
+ char stype[13] = {0}; /* EV_FF_STATUS + '\0' */
+
+ if (sscanf(s, "%12[A-Z_]:%x%n", stype, &code, &consumed) != 2 ||
+ strlen(s) != (size_t)consumed ||
+ (type = libevdev_event_type_from_name(stype)) == -1 ||
+ code < 0 || code > libevdev_event_type_get_max(type))
+ goto out;
+ }
+
+ evs[idx].type = type;
+ evs[idx].code = code;
+ evs[idx].value = enable;
+ }
+
+ memcpy(events, evs, ncodes * sizeof *events);
+ *nevents = ncodes;
+ rc = true;
+
+out:
+ strv_free(strv);
+ return rc;
+}
+
+/**
+ * Parses a string of the format "+INPUT_PROP_BUTTONPAD;-INPUT_PROP_POINTER;+0x123;"
+ * where each element must be a named input prop OR a hexcode in the form
+ * 0x1234. The prefix for each element must be either '+' (enable) or '-' (disable).
+ *
+ * props must point to an existing array of size nprops.
+ * nprops specifies the size of the array in props and returns the number
+ * of elements, elements exceeding nprops are simply ignored, just make sure
+ * props is large enough for your use-case.
+ *
+ * On success, props contains nprops elements.
+ */
+bool
+parse_input_prop_property(const char *prop, struct input_prop *props_out, size_t *nprops)
+{
+ bool rc = false;
+ struct input_prop props[INPUT_PROP_CNT]; /* doubling up on quirks is a bug */
+
+ size_t count;
+ char **strv = strv_from_string(prop, ";", &count);
+ if (!strv || count == 0 || count > ARRAY_LENGTH(props))
+ goto out;
+
+ count = min(*nprops, count);
+ for (size_t idx = 0; strv[idx]; idx++) {
+ char *s = strv[idx];
+ unsigned int prop;
+ bool enable;
+
+ switch (*s) {
+ case '+': enable = true; break;
+ case '-': enable = false; break;
+ default:
+ goto out;
+ }
+
+ s++;
+
+ if (safe_atou_base(s, &prop, 16)) {
+ if (prop > INPUT_PROP_MAX)
+ goto out;
+ } else {
+ int val = libevdev_property_from_name(s);
+ if (val == -1)
+ goto out;
+ prop = (unsigned int)val;
+ }
+ props[idx].prop = prop;
+ props[idx].enabled = enable;
+ }
+
+ memcpy(props_out, props, count * sizeof *props);
+ *nprops = count;
+ rc = true;
+
+out:
+ strv_free(strv);
+ return rc;
+}
+
+/* !util-prop-parsers.c */
diff --git a/usr.sbin/moused/moused/util.h b/usr.sbin/moused/moused/util.h
new file mode 100644
index 000000000000..a359cbc1079a
--- /dev/null
+++ b/usr.sbin/moused/moused/util.h
@@ -0,0 +1,413 @@
+/*
+ * Copyright © 2008-2011 Kristian Høgsberg
+ * Copyright © 2011 Intel Corporation
+ * Copyright © 2013-2015 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#pragma once
+
+#include <sys/types.h>
+#include <sys/mouse.h>
+
+#include <assert.h>
+#include <ctype.h>
+#include <math.h>
+#include <xlocale.h>
+
+#define HAVE_LOCALE_H 1
+
+#define MOUSED_ATTRIBUTE_PRINTF(_format, _args) \
+ __attribute__ ((format (printf, _format, _args)))
+
+#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
+/**
+ * Iterate through the array _arr, assigning the variable elem to each
+ * element. elem only exists within the loop.
+ */
+#define ARRAY_FOR_EACH(_arr, _elem) \
+ for (__typeof__((_arr)[0]) *_elem = _arr; \
+ _elem < (_arr) + ARRAY_LENGTH(_arr); \
+ _elem++)
+
+#define versionsort(...) alphasort(__VA_ARGS__)
+#define bit(x_) (1UL << (x_))
+#define min(a, b) (((a) < (b)) ? (a) : (b))
+
+/* Supported device interfaces */
+enum device_if {
+ DEVICE_IF_UNKNOWN = -1,
+ DEVICE_IF_EVDEV = 0,
+ DEVICE_IF_SYSMOUSE,
+};
+
+/* Recognized device types */
+enum device_type {
+ DEVICE_TYPE_UNKNOWN = -1,
+ DEVICE_TYPE_MOUSE = 0,
+ DEVICE_TYPE_POINTINGSTICK,
+ DEVICE_TYPE_TOUCHPAD,
+ DEVICE_TYPE_TOUCHSCREEN,
+ DEVICE_TYPE_TABLET,
+ DEVICE_TYPE_TABLET_PAD,
+ DEVICE_TYPE_KEYBOARD,
+ DEVICE_TYPE_JOYSTICK,
+};
+
+struct device {
+ char path[80];
+ enum device_if iftype;
+ enum device_type type;
+ char name[80];
+ char uniq[80];
+ struct input_id id;
+ mousemode_t mode;
+};
+
+/**
+ * @ingroup base
+ *
+ * Log handler type for custom logging.
+ *
+ * @param priority The priority of the current message
+ * @param format Message format in printf-style
+ * @param args Message arguments
+ */
+typedef void moused_log_handler(int priority, int errnum,
+ const char *format, va_list args);
+
+/* util-mem.h */
+
+/**
+ * Use: _unref_(foo) struct foo *bar;
+ *
+ * This requires foo_unrefp() to be present, use DEFINE_UNREF_CLEANUP_FUNC.
+ */
+#define _unref_(_type) __attribute__((cleanup(_type##_unrefp))) struct _type
+
+/**
+ * Define a cleanup function for the struct type foo with a matching
+ * foo_unref(). Use:
+ * DEFINE_UNREF_CLEANUP_FUNC(foo)
+ * _unref_(foo) struct foo *bar;
+ */
+#define DEFINE_UNREF_CLEANUP_FUNC(_type) \
+ static inline void _type##_unrefp(struct _type **_p) { \
+ if (*_p) \
+ _type##_unref(*_p); \
+ } \
+ struct __useless_struct_to_allow_trailing_semicolon__
+
+static inline void*
+_steal(void *ptr) {
+ void **original = (void**)ptr;
+ void *swapped = *original;
+ *original = NULL;
+ return swapped;
+}
+
+/**
+ * Resets the pointer content and resets the data to NULL.
+ * This circumvents _cleanup_ handling for that pointer.
+ * Use:
+ * _cleanup_free_ char *data = malloc();
+ * return steal(&data);
+ *
+ */
+#define steal(ptr_) \
+ (typeof(*ptr_))_steal(ptr_)
+
+/* ! util-mem.h */
+
+/* util-strings.h */
+
+static inline bool
+streq(const char *str1, const char *str2)
+{
+ /* one NULL, one not NULL is always false */
+ if (str1 && str2)
+ return strcmp(str1, str2) == 0;
+ return str1 == str2;
+}
+
+static inline bool
+strneq(const char *str1, const char *str2, int n)
+{
+ /* one NULL, one not NULL is always false */
+ if (str1 && str2)
+ return strncmp(str1, str2, n) == 0;
+ return str1 == str2;
+}
+
+static inline void *
+zalloc(size_t size)
+{
+ void *p;
+
+ /* We never need to alloc anything more than 1,5 MB so we can assume
+ * if we ever get above that something's going wrong */
+ if (size > 1536 * 1024)
+ assert(!"bug: internal malloc size limit exceeded");
+
+ p = calloc(1, size);
+ if (!p)
+ abort();
+
+ return p;
+}
+
+/**
+ * strdup guaranteed to succeed. If the input string is NULL, the output
+ * string is NULL. If the input string is a string pointer, we strdup or
+ * abort on failure.
+ */
+static inline char*
+safe_strdup(const char *str)
+{
+ char *s;
+
+ if (!str)
+ return NULL;
+
+ s = strdup(str);
+ if (!s)
+ abort();
+ return s;
+}
+
+/**
+ * Simple wrapper for asprintf that ensures the passed in-pointer is set
+ * to NULL upon error.
+ * The standard asprintf() call does not guarantee the passed in pointer
+ * will be NULL'ed upon failure, whereas this wrapper does.
+ *
+ * @param strp pointer to set to newly allocated string.
+ * This pointer should be passed to free() to release when done.
+ * @param fmt the format string to use for printing.
+ * @return The number of bytes printed (excluding the null byte terminator)
+ * upon success or -1 upon failure. In the case of failure the pointer is set
+ * to NULL.
+ */
+__attribute__ ((format (printf, 2, 3)))
+static inline int
+xasprintf(char **strp, const char *fmt, ...)
+{
+ int rc = 0;
+ va_list args;
+
+ va_start(args, fmt);
+ rc = vasprintf(strp, fmt, args);
+ va_end(args);
+ if ((rc == -1) && strp)
+ *strp = NULL;
+
+ return rc;
+}
+
+static inline bool
+safe_atoi_base(const char *str, int *val, int base)
+{
+ assert(str != NULL);
+
+ char *endptr;
+ long v;
+
+ assert(base == 10 || base == 16 || base == 8);
+
+ errno = 0;
+ v = strtol(str, &endptr, base);
+ if (errno > 0)
+ return false;
+ if (str == endptr)
+ return false;
+ if (*str != '\0' && *endptr != '\0')
+ return false;
+
+ if (v > INT_MAX || v < INT_MIN)
+ return false;
+
+ *val = v;
+ return true;
+}
+
+static inline bool
+safe_atoi(const char *str, int *val)
+{
+ assert(str != NULL);
+ return safe_atoi_base(str, val, 10);
+}
+
+static inline bool
+safe_atou_base(const char *str, unsigned int *val, int base)
+{
+ assert(str != NULL);
+
+ char *endptr;
+ unsigned long v;
+
+ assert(base == 10 || base == 16 || base == 8);
+
+ errno = 0;
+ v = strtoul(str, &endptr, base);
+ if (errno > 0)
+ return false;
+ if (str == endptr)
+ return false;
+ if (*str != '\0' && *endptr != '\0')
+ return false;
+
+ if ((long)v < 0)
+ return false;
+
+ *val = v;
+ return true;
+}
+
+static inline bool
+safe_atou(const char *str, unsigned int *val)
+{
+ assert(str != NULL);
+ return safe_atou_base(str, val, 10);
+}
+
+static inline bool
+safe_atod(const char *str, double *val)
+{
+ assert(str != NULL);
+
+ char *endptr;
+ double v;
+ size_t slen = strlen(str);
+
+ /* We don't have a use-case where we want to accept hex for a double
+ * or any of the other values strtod can parse */
+ for (size_t i = 0; i < slen; i++) {
+ char c = str[i];
+
+ if (isdigit(c))
+ continue;
+ switch(c) {
+ case '+':
+ case '-':
+ case '.':
+ break;
+ default:
+ return false;
+ }
+ }
+
+#ifdef HAVE_LOCALE_H
+ /* Create a "C" locale to force strtod to use '.' as separator */
+ locale_t c_locale = newlocale(LC_NUMERIC_MASK, "C", (locale_t)0);
+ if (c_locale == (locale_t)0)
+ return false;
+
+ errno = 0;
+ v = strtod_l(str, &endptr, c_locale);
+ freelocale(c_locale);
+#else
+ /* No locale support in provided libc, assume it already uses '.' */
+ errno = 0;
+ v = strtod(str, &endptr);
+#endif
+ if (errno > 0)
+ return false;
+ if (str == endptr)
+ return false;
+ if (*str != '\0' && *endptr != '\0')
+ return false;
+ if (v != 0.0 && !isnormal(v))
+ return false;
+
+ *val = v;
+ return true;
+}
+
+char **strv_from_string(const char *in, const char *separator, size_t *num_elements);
+
+typedef int (*strv_foreach_callback_t)(const char *str, size_t index, void *data);
+int strv_for_each_n(const char **strv, size_t max, strv_foreach_callback_t func, void *data);
+
+static inline void
+strv_free(char **strv) {
+ char **s = strv;
+
+ if (!strv)
+ return;
+
+ while (*s != NULL) {
+ free(*s);
+ *s = (char*)0x1; /* detect use-after-free */
+ s++;
+ }
+
+ free (strv);
+}
+
+/**
+ * Return true if str ends in suffix, false otherwise. If the suffix is the
+ * empty string, strendswith() always returns false.
+ */
+static inline bool
+strendswith(const char *str, const char *suffix)
+{
+ if (str == NULL)
+ return false;
+
+ size_t slen = strlen(str);
+ size_t suffixlen = strlen(suffix);
+ size_t offset;
+
+ if (slen == 0 || suffixlen == 0 || suffixlen > slen)
+ return false;
+
+ offset = slen - suffixlen;
+ return strneq(&str[offset], suffix, suffixlen);
+}
+
+static inline bool
+strstartswith(const char *str, const char *prefix)
+{
+ if (str == NULL)
+ return false;
+
+ size_t prefixlen = strlen(prefix);
+
+ return prefixlen > 0 ? strneq(str, prefix, strlen(prefix)) : false;
+}
+
+/* !util-strings.h */
+
+/* util-prop-parsers.h */
+
+struct input_prop {
+ unsigned int prop;
+ bool enabled;
+};
+
+bool parse_dimension_property(const char *prop, size_t *w, size_t *h);
+bool parse_range_property(const char *prop, int *hi, int *lo);
+bool parse_boolean_property(const char *prop, bool *b);
+#define EVENT_CODE_UNDEFINED 0xffff
+bool parse_evcode_property(const char *prop, struct input_event *events, size_t *nevents);
+bool parse_input_prop_property(const char *prop, struct input_prop *props_out, size_t *nprops);
+
+/* !util-prop-parsers.h */
diff --git a/usr.sbin/moused/msconvd/Makefile b/usr.sbin/moused/msconvd/Makefile
new file mode 100644
index 000000000000..6ea5eee7db3b
--- /dev/null
+++ b/usr.sbin/moused/msconvd/Makefile
@@ -0,0 +1,8 @@
+PACKAGE= console-tools
+PROG= msconvd
+SRCS= ${PROG}.c
+LIBADD= util
+BINDIR= /usr/sbin
+MAN= ${PROG}.8
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/moused/moused.8 b/usr.sbin/moused/msconvd/msconvd.8
index cd5d8ddde339..17434ecb9b60 100644
--- a/usr.sbin/moused/moused.8
+++ b/usr.sbin/moused/msconvd/msconvd.8
@@ -31,30 +31,21 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd July 7, 2024
-.Dt MOUSED 8
+.Dd May 18, 2025
+.Dt MSCONVD 8
.Os
.Sh NAME
-.Nm moused
-.Nd pass mouse data to the system video console driver
+.Nm msconvd
+.Nd mouse protocol conversion daemon
.Sh SYNOPSIS
.Nm
-.Op Fl DPRacdfs
+.Op Fl DPRcdfs
.Op Fl I Ar file
.Op Fl F Ar rate
.Op Fl r Ar resolution
.Op Fl S Ar baudrate
-.Op Fl VH Op Fl U Ar distance Fl L Ar distance
-.Op Fl A Ar exp Ns Op , Ns Ar offset
-.Op Fl a Ar X Ns Op , Ns Ar Y
-.Op Fl C Ar threshold
-.Op Fl m Ar N=M
-.Op Fl w Ar N
-.Op Fl z Ar target
.Op Fl t Ar mousetype
.Op Fl l Ar level
-.Op Fl 3 Op Fl E Ar timeout
-.Op Fl T Ar distance Ns Op , Ns Ar time Ns Op , Ns Ar after
.Fl p Ar port
.Pp
.Nm
@@ -64,38 +55,41 @@
.Sh DESCRIPTION
The
.Nm
-utility and the console driver work together to support
-mouse operation in the text console and user programs.
-They virtualize the mouse and provide user programs with mouse data
-in the standard format
-(see
-.Xr sysmouse 4 ) .
-.Pp
-The mouse daemon listens to the specified port for mouse data,
-interprets and then passes it via ioctls to the console driver.
-The mouse daemon
-reports translation movement, button press/release
+utility and the
+.Xr moused 8
+driver work together to support legacy devices like COM,
+.Xr ams 4
+mices and X10 remotes as well.
+.Xr psm 4 ,
+.Xr ums 4
+and some other devices are supported too but not recomended to use with
+.Nm
+unless kernel is compiled without
+.Dq option EVDEV_SUPPORT .
+The
+.Nm
+listens to the specified port for mouse data, decodes and then passes
+it via input event device a.k.a evdev to consumer aplications like
+.Xr moused 8
+or
+.Xr libinput 1 .
+It does not display the mouse pointer on the screen or provide cut and
+paste functions.
+The msconv daemon converts translation movement, button press/release
events and movement of the roller or the wheel if available.
-The roller/wheel movement is reported as
-.Dq Z
-axis movement.
-.Pp
-The console driver will display the mouse pointer on the screen
-and provide cut and paste functions if the mouse pointer is enabled
-in the virtual console via
-.Xr vidcontrol 1 .
-If
-.Xr sysmouse 4
-is opened by the user program, the console driver also passes the mouse
-data to the device so that the user program will see it.
-.Pp
-If the mouse daemon receives the signal
+.Pp
+.Pp
+If the
+.Nm
+receives the signal
.Dv SIGHUP ,
it will reopen the mouse port and reinitialize itself.
Useful if
the mouse is attached/detached while the system is suspended.
.Pp
-If the mouse daemon receives the signal
+If the
+.Nm
+receives the signal
.Dv SIGUSR1 ,
it will stop passing mouse events.
Sending the signal
@@ -106,19 +100,6 @@ interrupted by accidentally touching the mouse pad.
.Pp
The following options are available:
.Bl -tag -width indent
-.It Fl 3
-Emulate the third (middle) button for 2-button mice.
-It is emulated
-by pressing the left and right physical buttons simultaneously.
-.It Fl C Ar threshold
-Set double click speed as the maximum interval in msec between button clicks.
-Without this option, the default value of 500 msec will be assumed.
-This option will have effect only on the cut and paste operations
-in the text mode console.
-The user program which is reading mouse data
-via
-.Xr sysmouse 4
-will not be affected.
.It Fl D
Lower DTR on the serial port.
This option is valid only if
@@ -128,46 +109,8 @@ The DTR line may need to be dropped for a 3-button mouse
to operate in the
.Ar mousesystems
mode.
-.It Fl E Ar timeout
-When the third button emulation is enabled
-(see above),
-the
-.Nm
-utility waits
-.Ar timeout
-msec at most before deciding whether two buttons are being pressed
-simultaneously.
-The default timeout is 100 msec.
.It Fl F Ar rate
Set the report rate (reports/sec) of the device if supported.
-.It Fl L Ar distance
-When
-.Dq Virtual Scrolling
-is enabled, the
-.Fl L
-option can be used to set the
-.Ar distance
-(in pixels) that the mouse must move before a scroll event
-is generated.
-This effectively controls the scrolling speed.
-The default
-.Ar distance
-is 2 pixels.
-.It Fl H
-Enable
-.Dq Horizontal Virtual Scrolling .
-With this option set, holding the middle mouse
-button down will cause motion to be interpreted as
-horizontal scrolling.
-Use the
-.Fl U
-option to set the distance the mouse must move before the scrolling mode is
-activated and the
-.Fl L
-option to set the scrolling speed.
-This option may be used with or without the
-.Fl V
-option.
.It Fl I Ar file
Write the process id of the
.Nm
@@ -199,89 +142,6 @@ mode.
.It Fl S Ar baudrate
Select the baudrate for the serial port (1200 to 9600).
Not all serial mice support this option.
-.It Fl T Ar distance Ns Op , Ns Ar time Ns Op , Ns Ar after
-Terminate drift.
-Use this option if mouse pointer slowly wanders when mouse is not moved.
-Movements up to
-.Ar distance
-(for example 4) pixels (X+Y) in
-.Ar time
-msec (default 500) are ignored, except during
-.Ar after
-msec (default 4000) since last real mouse movement.
-.It Fl V
-Enable
-.Dq Virtual Scrolling .
-With this option set, holding the middle mouse
-button down will cause motion to be interpreted as scrolling.
-Use the
-.Fl U
-option to set the distance the mouse must move before the scrolling mode is
-activated and the
-.Fl L
-option to set the scrolling speed.
-.It Fl U Ar distance
-When
-.Dq Virtual Scrolling
-is enabled, the
-.Fl U
-option can be used to set the
-.Ar distance
-(in pixels) that the mouse must move before the scrolling
-mode is activated.
-The default
-.Ar distance
-is 3 pixels.
-.It Fl A Ar exp Ns Op , Ns Ar offset
-Apply exponential (dynamic) acceleration to mouse movements:
-the faster you move the mouse, the more it will be accelerated.
-That means that small mouse movements are not accelerated,
-so they are still very accurate, while a faster movement will
-drive the pointer quickly across the screen.
-.Pp
-The
-.Ar exp
-value specifies the exponent, which is basically
-the amount of acceleration.
-Useful values are in the range 1.1 to 2.0, but it depends on
-your mouse hardware and your personal preference.
-A value of 1.0 means no exponential acceleration.
-A value of 2.0 means squared acceleration (i.e. if
-you move the mouse twice as fast, the pointer will move
-four times as fast on the screen).
-Values beyond 2.0 are possible but not recommended.
-A good value to start is probably 1.5.
-.Pp
-The optional
-.Ar offset
-value specifies the distance at which the acceleration begins.
-The default is 1.0, which means that the acceleration is applied
-to movements larger than one unit.
-If you specify a larger value, it takes more speed for
-the acceleration to kick in, i.e. the speed range for
-small and accurate movements is wider.
-Usually the default should be sufficient, but if you're
-not satisfied with the behaviour, try a value of 2.0.
-.Pp
-Note that the
-.Fl A
-option interacts badly with the X server's own acceleration,
-which doesn't work very well anyway.
-Therefore it is recommended to switch it off if necessary:
-.Dq xset m 1 .
-.It Fl a Ar X Ns Op , Ns Ar Y
-Accelerate or decelerate the mouse input.
-This is a linear acceleration only.
-Values less than 1.0 slow down movement, values greater than 1.0 speed it
-up.
-Specifying only one value sets the acceleration for both axes.
-.Pp
-You can use the
-.Fl a
-and
-.Fl A
-options at the same time to have the combined effect
-of linear and exponential acceleration.
.It Fl c
Some mice report middle button down events
as if the left and right buttons are being pressed.
@@ -339,18 +199,6 @@ Refer to
in
.Xr psm 4
for more information on this.
-.It Fl m Ar N=M
-Assign the physical button
-.Ar M
-to the logical button
-.Ar N .
-You may specify as many instances of this option as you like.
-More than one physical button may be assigned to a logical button at the
-same time.
-In this case the logical button will be down,
-if either of the assigned physical buttons is held down.
-Do not put space around
-.Ql = .
.It Fl p Ar port
Use
.Ar port
@@ -382,7 +230,7 @@ you need to use this option only if the
.Nm
utility is not able to detect the protocol automatically
(see
-.Sx "Configuring Mouse Daemon" ) .
+.Sx "Configuring Mouse Protocol Conversion Daemon" ) .
.Pp
Note that if a protocol type is specified with this option, the
.Fl P
@@ -475,73 +323,9 @@ For the USB mouse,
.Ar auto
is the only protocol type available for the USB mouse
and should be specified for any USB mice, regardless of the brand.
-.It Fl w Ar N
-Make the physical button
-.Ar N
-act as the wheel mode button.
-While this button is pressed, X and Y axis movement is reported to be zero
-and the Y axis movement is mapped to Z axis.
-You may further map the Z axis movement to virtual buttons by the
-.Fl z
-option below.
-.It Fl z Ar target
-Map Z axis (roller/wheel) movement to another axis or to virtual buttons.
-Valid
-.Ar target
-maybe:
-.Bl -tag -compact -width x__
-.It Ar x
-.It Ar y
-X or Y axis movement will be reported when the Z axis movement is detected.
-.It Ar N
-Report down events for the virtual buttons
-.Ar N
-and
-.Ar N+1
-respectively when negative and positive Z axis movement
-is detected.
-There do not need to be physical buttons
-.Ar N
-and
-.Ar N+1 .
-Note that mapping to logical buttons is carried out after mapping
-from the Z axis movement to the virtual buttons is done.
-.It Ar N1 N2
-Report down events for the virtual buttons
-.Ar N1
-and
-.Ar N2
-respectively when negative and positive Z axis movement
-is detected.
-.It Ar N1 N2 N3 N4
-This is useful for the mouse with two wheels of which
-the second wheel is used to generate horizontal scroll action,
-and for the mouse which has a knob or a stick which can detect
-the horizontal force applied by the user.
-.Pp
-The motion of the second wheel will be mapped to the buttons
-.Ar N3 ,
-for the negative direction, and
-.Ar N4 ,
-for the positive direction.
-If the buttons
-.Ar N3
-and
-.Ar N4
-actually exist in this mouse, their actions will not be detected.
-.Pp
-Note that horizontal movement or second roller/wheel movement may not
-always be detected,
-because there appears to be no accepted standard as to how it is encoded.
-.Pp
-Note also that some mice think left is the negative horizontal direction;
-others may think otherwise.
-Moreover, there are some mice whose two wheels are both mounted vertically,
-and the direction of the second vertical wheel does not match the
-first one.
.El
.El
-.Ss Configuring Mouse Daemon
+.Ss Configuring Mouse Protocol Conversion Daemon
The first thing you need to know is the interface type
of the mouse you are going to use.
It can be determined by looking at the connector of the mouse.
@@ -673,13 +457,17 @@ protocol.
.El
.Pp
To test if the selected protocol type is correct for the given mouse,
-enable the mouse pointer in the current virtual console,
+ensure the
+.Xr moused 8
+is running in auto port mode,
.Pp
-.Dl "vidcontrol -m on"
+.Dl "moused -p auto"
.Pp
-start the mouse daemon in the foreground mode,
+start the
+.Nm
+in the foreground mode,
.Pp
-.Dl "moused -f -p <selected_port> -t <selected_protocol>"
+.Dl "msconvd -f -p <selected_port> -t <selected_protocol>"
.Pp
and see if the mouse pointer travels correctly
according to the mouse movement.
@@ -688,19 +476,20 @@ clicking the left, right and middle buttons.
Type ^C to stop
the command.
.Ss Multiple Mice
-As many instances of the mouse daemon as the number of mice attached to
-the system may be run simultaneously; one
-instance for each mouse.
+As many instances of the
+.Nm
+as the number of mice attached to the system may be run simultaneously;
+one instance for each mouse.
This is useful if the user wants to use the built-in PS/2 pointing device
of a laptop computer while on the road, but wants to use a serial
mouse when s/he attaches the system to the docking station in the office.
-Run two mouse daemons and tell the application program
-(such as the
-.Tn "X\ Window System" )
-to use
-.Xr sysmouse 4 ,
-then the application program will always see mouse data from either mouse.
-When the serial mouse is not attached, the corresponding mouse daemon
+Run two
+.Nm
+and then the application program e.g.
+.Xr moused 8
+will always see mouse data from either mouse.
+When the serial mouse is not attached, the corresponding
+.Nm
will not detect any movement or button state change and the application
program will only see mouse data coming from the daemon for the
PS/2 mouse.
@@ -709,18 +498,18 @@ are moved at the same time in this configuration,
the mouse pointer will travel across the screen just as if movement of
the mice is combined all together.
.Sh FILES
-.Bl -tag -width /dev/consolectl -compact
-.It Pa /dev/consolectl
-device to control the console
+.Bl -tag -width /dev/input/event%d -compact
+.It Pa /dev/input/event%d
+input event device
.It Pa /dev/psm%d
PS/2 mouse driver
-.It Pa /dev/sysmouse
-virtualized mouse driver
+.It Pa /dev/cuau%d
+serial port
.It Pa /dev/ttyv%d
virtual consoles
.It Pa /dev/ums%d
USB mouse driver
-.It Pa /var/run/moused.pid
+.It Pa /var/run/msconvd.pid
process id of the currently running
.Nm
utility
@@ -728,7 +517,7 @@ utility
UNIX-domain stream socket for X10 MouseRemote events
.El
.Sh EXAMPLES
-.Dl "moused -p /dev/cuau0 -i type"
+.Dl "msconvd -p /dev/cuau0 -i type"
.Pp
Let the
.Nm
@@ -737,8 +526,7 @@ utility determine the protocol type of the mouse at the serial port
If successful, the command will print the type, otherwise it will say
.Dq Li unknown .
.Bd -literal -offset indent
-moused -p /dev/cuau0
-vidcontrol -m on
+msconvd -p /dev/cuau0
.Ed
.Pp
If the
@@ -746,10 +534,9 @@ If the
utility is able to identify the protocol type of the mouse at the specified
port automatically, you can start the daemon without the
.Fl t
-option and enable the mouse pointer in the text console as above.
+option.
.Bd -literal -offset indent
-moused -p /dev/mouse -t microsoft
-vidcontrol -m on
+msconvd -p /dev/mouse -t microsoft
.Ed
.Pp
Start the mouse daemon on the serial port
@@ -760,39 +547,26 @@ is explicitly specified by the
.Fl t
option.
.Pp
-.Dl "moused -p /dev/mouse -m 1=3 -m 3=1"
-.Pp
-Assign the physical button 3 (right button) to the logical button 1
-(logical left) and the physical button 1 (left) to the logical
-button 3 (logical right).
-This will effectively swap the left and right buttons.
-.Pp
-.Dl "moused -p /dev/mouse -t intellimouse -z 4"
-.Pp
-Report negative Z axis movement (i.e., mouse wheel) as the button 4 pressed
-and positive Z axis movement (i.e., mouse wheel) as the button 5 pressed.
-.Pp
If you add
.Pp
-.Dl "ALL ALL = NOPASSWD: /usr/bin/killall -USR1 moused"
+.Dl "ALL ALL = NOPASSWD: /usr/bin/killall -USR1 msconvd"
.Pp
to your
.Pa /usr/local/etc/sudoers
file, and bind
.Pp
-.Dl "killall -USR1 moused"
+.Dl "killall -USR1 msconvd"
.Pp
to a key in your window manager, you can suspend mouse events on your laptop if
you keep brushing over the mouse pad while typing.
.Sh SEE ALSO
+.Xr moused 8 ,
.Xr kill 1 ,
-.Xr vidcontrol 1 ,
.Xr xset 1 ,
-.Xr keyboard 4 ,
.Xr psm 4 ,
.Xr screen 4 ,
.Xr sysmouse 4 ,
-.Xr ums 4
+.Xr uart 4
.Sh STANDARDS
The
.Nm
@@ -809,14 +583,23 @@ for the given serial mouse.
The
.Nm
utility first appeared in
+.Fx 15.0 .
+It is a cropped-down version of
+.Fx 14.0
+.Xr moused 8
+utility originated back in
.Fx 2.2 .
.Sh AUTHORS
.An -nosplit
The
.Nm
-utility was written by
+utility is based on
+.Xr moused 8
+written by
.An Michael Smith Aq Mt msmith@FreeBSD.org .
-This manual page was written by
+This manual page is extracted from
+.Xr moused 8
+page written by
.An Mike Pritchard Aq Mt mpp@FreeBSD.org .
The command and manual page have since been updated by
.An Kazutaka Yokota Aq Mt yokota@FreeBSD.org .
@@ -830,21 +613,7 @@ treat the tapping action
as fourth button events.
Use the option
.Dq Fl m Li 1=4
+of
+.Xr moused 8
for these models
to obtain the same effect as the other pad devices.
-.Pp
-Cut and paste functions in the virtual console assume that there
-are three buttons on the mouse.
-The logical button 1 (logical left) selects a region of text in the
-console and copies it to the cut buffer.
-The logical button 3 (logical right) extends the selected region.
-The logical button 2 (logical middle) pastes the selected text
-at the text cursor position.
-If the mouse has only two buttons, the middle, `paste' button
-is not available.
-To obtain the paste function, use the
-.Fl 3
-option to emulate the middle button, or use the
-.Fl m
-option to assign the physical right button to the logical middle button:
-.Dq Fl m Li 2=3 .
diff --git a/usr.sbin/moused/moused.c b/usr.sbin/moused/msconvd/msconvd.c
index 068919f2e941..7b06d92019aa 100644
--- a/usr.sbin/moused/moused.c
+++ b/usr.sbin/moused/msconvd/msconvd.c
@@ -34,11 +34,11 @@
**/
/**
- ** MOUSED.C
+ ** MSCONVD.C
**
- ** Mouse daemon : listens to a serial port, the bus mouse interface, or
- ** the PS/2 mouse port for mouse data stream, interprets data and passes
- ** ioctls off to the console driver.
+ ** Mouse protocol conversion daemon : listens to a serial port or
+ ** the PS/2 mouse port for mouse data stream, decodes data and passes
+ ** writes off to the uinput driver.
**
** The mouse interface functions are derived closely from the mouse
** handler in the XFree86 X server. Many thanks to the XFree86 people
@@ -54,15 +54,20 @@
#include <sys/time.h>
#include <sys/un.h>
+#include <dev/evdev/input.h>
+#include <dev/evdev/uinput.h>
+
#include <ctype.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
+#include <libgen.h>
#include <libutil.h>
#include <limits.h>
#include <setjmp.h>
#include <signal.h>
#include <stdarg.h>
+#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
@@ -70,23 +75,6 @@
#include <syslog.h>
#include <termios.h>
#include <unistd.h>
-#include <math.h>
-
-#define MAX_CLICKTHRESHOLD 2000 /* 2 seconds */
-#define MAX_BUTTON2TIMEOUT 2000 /* 2 seconds */
-#define DFLT_CLICKTHRESHOLD 500 /* 0.5 second */
-#define DFLT_BUTTON2TIMEOUT 100 /* 0.1 second */
-#define DFLT_SCROLLTHRESHOLD 3 /* 3 pixels */
-#define DFLT_SCROLLSPEED 2 /* 2 pixels */
-
-/* Abort 3-button emulation delay after this many movement events. */
-#define BUTTON2_MAXMOVE 3
-
-#define TRUE 1
-#define FALSE 0
-
-#define MOUSE_XAXIS (-1)
-#define MOUSE_YAXIS (-2)
/* Logitech PS2++ protocol */
#define MOUSE_PS2PLUS_CHECKBITS(b) \
@@ -95,13 +83,9 @@
(((b[0] & 0x30) >> 2) | ((b[1] & 0x30) >> 4))
#define ChordMiddle 0x0001
-#define Emulate3Button 0x0002
#define ClearDTR 0x0004
#define ClearRTS 0x0008
#define NoPnP 0x0010
-#define VirtualScroll 0x0020
-#define HVirtualScroll 0x0040
-#define ExponentialAcc 0x0080
#define ID_NONE 0
#define ID_PORT 1
@@ -110,22 +94,6 @@
#define ID_MODEL 8
#define ID_ALL (ID_PORT | ID_IF | ID_TYPE | ID_MODEL)
-/* Operations on timespecs */
-#define tsclr(tvp) ((tvp)->tv_sec = (tvp)->tv_nsec = 0)
-#define tscmp(tvp, uvp, cmp) \
- (((tvp)->tv_sec == (uvp)->tv_sec) ? \
- ((tvp)->tv_nsec cmp (uvp)->tv_nsec) : \
- ((tvp)->tv_sec cmp (uvp)->tv_sec))
-#define tssub(tvp, uvp, vvp) \
- do { \
- (vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec; \
- (vvp)->tv_nsec = (tvp)->tv_nsec - (uvp)->tv_nsec; \
- if ((vvp)->tv_nsec < 0) { \
- (vvp)->tv_sec--; \
- (vvp)->tv_nsec += 1000000000; \
- } \
- } while (0)
-
#define debug(...) do { \
if (debug && nodaemon) \
warnx(__VA_ARGS__); \
@@ -174,30 +142,21 @@ typedef struct {
/* global variables */
static int debug = 0;
-static int nodaemon = FALSE;
-static int background = FALSE;
-static int paused = FALSE;
+static bool nodaemon = false;
+static bool background = false;
+static bool paused = false;
static int identify = ID_NONE;
-static int extioctl = FALSE;
-static const char *pidfile = "/var/run/moused.pid";
+static const char *pidfile = "/var/run/msconvd.pid";
static struct pidfh *pfh;
-#define SCROLL_NOTSCROLLING 0
-#define SCROLL_PREPARE 1
-#define SCROLL_SCROLLING 2
-
-static int scroll_state;
-static int scroll_movement;
-static int hscroll_movement;
-
/* local variables */
/* interface (the table must be ordered by MOUSE_IF_XXX in mouse.h) */
static symtab_t rifs[] = {
- { "serial", MOUSE_IF_SERIAL, 0 },
- { "ps/2", MOUSE_IF_PS2, 0 },
- { "sysmouse", MOUSE_IF_SYSMOUSE, 0 },
- { "usb", MOUSE_IF_USB, 0 },
+ { "serial", MOUSE_IF_SERIAL, BUS_RS232 },
+ { "ps/2", MOUSE_IF_PS2, BUS_I8042 },
+ { "sysmouse", MOUSE_IF_SYSMOUSE, BUS_VIRTUAL },
+ { "usb", MOUSE_IF_USB, BUS_USB },
{ NULL, MOUSE_IF_UNKNOWN, 0 },
};
@@ -381,6 +340,18 @@ static unsigned short rodentcflags[] =
(CS8 | CREAD | HUPCL ), /* GTCO Digi-Pad */
};
+/* evdev button codes */
+static const int16_t evdev_buttons[8] = {
+ BTN_LEFT,
+ BTN_MIDDLE,
+ BTN_RIGHT,
+ BTN_SIDE,
+ BTN_EXTRA,
+ BTN_FORWARD,
+ BTN_BACK,
+ BTN_TASK
+};
+
static struct rodentparam {
int flags;
const char *portname; /* /dev/XXX */
@@ -389,25 +360,13 @@ static struct rodentparam {
int baudrate;
int rate; /* report rate */
int resolution; /* MOUSE_RES_XXX or a positive number */
- int zmap[4]; /* MOUSE_{X|Y}AXIS or a button number */
- int wmode; /* wheel mode button number */
int mfd; /* mouse file descriptor */
- int cfd; /* /dev/consolectl file descriptor */
+ int ufd; /* /dev/uinput file descriptor */
int mremsfd; /* mouse remote server file descriptor */
int mremcfd; /* mouse remote client file descriptor */
int is_removable; /* set if device is removable, like USB */
- long clickthreshold; /* double click speed in msec */
- long button2timeout; /* 3 button emulation timeout */
mousehw_t hw; /* mouse device hardware information */
mousemode_t mode; /* protocol information */
- float accelx; /* Acceleration in the X axis */
- float accely; /* Acceleration in the Y axis */
- float expoaccel; /* Exponential acceleration */
- float expoffset; /* Movement offset for exponential accel. */
- float remainx; /* Remainder on X and Y axis, respectively... */
- float remainy; /* ... to compensate for rounding errors. */
- int scrollthreshold; /* Movement distance before virtual scrolling */
- int scrollspeed; /* Movement distance to rate of scrolling */
} rodent = {
.flags = 0,
.portname = NULL,
@@ -416,107 +375,18 @@ static struct rodentparam {
.baudrate = 1200,
.rate = 0,
.resolution = MOUSE_RES_UNKNOWN,
- .zmap = { 0, 0, 0, 0 },
- .wmode = 0,
.mfd = -1,
- .cfd = -1,
+ .ufd = -1,
.mremsfd = -1,
.mremcfd = -1,
.is_removable = 0,
- .clickthreshold = DFLT_CLICKTHRESHOLD,
- .button2timeout = DFLT_BUTTON2TIMEOUT,
- .accelx = 1.0,
- .accely = 1.0,
- .expoaccel = 1.0,
- .expoffset = 1.0,
- .remainx = 0.0,
- .remainy = 0.0,
- .scrollthreshold = DFLT_SCROLLTHRESHOLD,
- .scrollspeed = DFLT_SCROLLSPEED,
-};
-
-/* button status */
-struct button_state {
- int count; /* 0: up, 1: single click, 2: double click,... */
- struct timespec ts; /* timestamp on the last button event */
-};
-static struct button_state bstate[MOUSE_MAXBUTTON]; /* button state */
-static struct button_state *mstate[MOUSE_MAXBUTTON];/* mapped button st.*/
-static struct button_state zstate[4]; /* Z/W axis state */
-
-/* state machine for 3 button emulation */
-
-#define S0 0 /* start */
-#define S1 1 /* button 1 delayed down */
-#define S2 2 /* button 3 delayed down */
-#define S3 3 /* both buttons down -> button 2 down */
-#define S4 4 /* button 1 delayed up */
-#define S5 5 /* button 1 down */
-#define S6 6 /* button 3 down */
-#define S7 7 /* both buttons down */
-#define S8 8 /* button 3 delayed up */
-#define S9 9 /* button 1 or 3 up after S3 */
-
-#define A(b1, b3) (((b1) ? 2 : 0) | ((b3) ? 1 : 0))
-#define A_TIMEOUT 4
-#define S_DELAYED(st) (states[st].s[A_TIMEOUT] != (st))
-
-static struct {
- int s[A_TIMEOUT + 1];
- int buttons;
- int mask;
- int timeout;
-} states[10] = {
- /* S0 */
- { { S0, S2, S1, S3, S0 }, 0, ~(MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN), FALSE },
- /* S1 */
- { { S4, S2, S1, S3, S5 }, 0, ~MOUSE_BUTTON1DOWN, FALSE },
- /* S2 */
- { { S8, S2, S1, S3, S6 }, 0, ~MOUSE_BUTTON3DOWN, FALSE },
- /* S3 */
- { { S0, S9, S9, S3, S3 }, MOUSE_BUTTON2DOWN, ~0, FALSE },
- /* S4 */
- { { S0, S2, S1, S3, S0 }, MOUSE_BUTTON1DOWN, ~0, TRUE },
- /* S5 */
- { { S0, S2, S5, S7, S5 }, MOUSE_BUTTON1DOWN, ~0, FALSE },
- /* S6 */
- { { S0, S6, S1, S7, S6 }, MOUSE_BUTTON3DOWN, ~0, FALSE },
- /* S7 */
- { { S0, S6, S5, S7, S7 }, MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN, ~0, FALSE },
- /* S8 */
- { { S0, S2, S1, S3, S0 }, MOUSE_BUTTON3DOWN, ~0, TRUE },
- /* S9 */
- { { S0, S9, S9, S3, S9 }, 0, ~(MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN), FALSE },
};
-static int mouse_button_state;
-static struct timespec mouse_button_state_ts;
-static int mouse_move_delayed;
static jmp_buf env;
-struct drift_xy {
- int x;
- int y;
-};
-static int drift_distance = 4; /* max steps X+Y */
-static int drift_time = 500; /* in 0.5 sec */
-static struct timespec drift_time_ts;
-static struct timespec drift_2time_ts; /* 2*drift_time */
-static int drift_after = 4000; /* 4 sec */
-static struct timespec drift_after_ts;
-static int drift_terminate = FALSE;
-static struct timespec drift_current_ts;
-static struct timespec drift_tmp;
-static struct timespec drift_last_activity = {0, 0};
-static struct timespec drift_since = {0, 0};
-static struct drift_xy drift_last = {0, 0}; /* steps in last drift_time */
-static struct drift_xy drift_previous = {0, 0}; /* steps in prev. drift_time */
-
/* function prototypes */
-static void linacc(int, int, int*, int*);
-static void expoacc(int, int, int*, int*);
-static void moused(void);
+static void msconvd(void);
static void hup(int sig);
static void cleanup(int sig);
static void pause_mouse(int sig);
@@ -524,31 +394,29 @@ static void usage(void);
static void log_or_warn(int log_pri, int errnum, const char *fmt, ...)
__printflike(3, 4);
+static int r_uinput_register(void);
+static int r_uinput_report(int fd, mousestatus_t *act);
static int r_identify(void);
static const char *r_if(int type);
+static uint16_t r_bustype(int type);
static const char *r_name(int type);
static const char *r_model(int model);
static void r_init(void);
static int r_protocol(u_char b, mousestatus_t *act);
-static int r_statetrans(mousestatus_t *a1, mousestatus_t *a2, int trans);
-static int r_installmap(char *arg);
-static void r_map(mousestatus_t *act1, mousestatus_t *act2);
-static void r_timestamp(mousestatus_t *act);
-static int r_timeout(void);
-static void r_click(mousestatus_t *act);
static void setmousespeed(int old, int new, unsigned cflag);
-static int pnpwakeup1(void);
-static int pnpwakeup2(void);
+static bool pnpwakeup1(void);
+static bool pnpwakeup2(void);
static int pnpgets(char *buf);
-static int pnpparse(pnpid_t *id, char *buf, int len);
+static bool pnpparse(pnpid_t *id, char *buf, int len);
static symtab_t *pnpproto(pnpid_t *id);
static symtab_t *gettoken(symtab_t *tab, const char *s, int len);
static const char *gettokenname(symtab_t *tab, int val);
+static int gettokenval2(symtab_t *tab, int val);
static void mremote_serversetup(void);
-static void mremote_clientchg(int add);
+static void mremote_clientchg(bool add);
static int kidspad(u_char rxc, mousestatus_t *act);
static int gtco_digipad(u_char, mousestatus_t *);
@@ -558,52 +426,10 @@ main(int argc, char *argv[])
{
int c;
int i;
- int j;
- for (i = 0; i < MOUSE_MAXBUTTON; ++i)
- mstate[i] = &bstate[i];
-
- while ((c = getopt(argc, argv, "3A:C:DE:F:HI:L:PRS:T:VU:a:cdfhi:l:m:p:r:st:w:z:")) != -1)
+ while ((c = getopt(argc, argv, "DF:I:PRS:cdfhi:l:p:r:st:")) != -1)
switch(c) {
- case '3':
- rodent.flags |= Emulate3Button;
- break;
-
- case 'E':
- rodent.button2timeout = atoi(optarg);
- if ((rodent.button2timeout < 0) ||
- (rodent.button2timeout > MAX_BUTTON2TIMEOUT)) {
- warnx("invalid argument `%s'", optarg);
- usage();
- }
- break;
-
- case 'a':
- i = sscanf(optarg, "%f,%f", &rodent.accelx, &rodent.accely);
- if (i == 0) {
- warnx("invalid linear acceleration argument '%s'", optarg);
- usage();
- }
-
- if (i == 1)
- rodent.accely = rodent.accelx;
-
- break;
-
- case 'A':
- rodent.flags |= ExponentialAcc;
- i = sscanf(optarg, "%f,%f", &rodent.expoaccel, &rodent.expoffset);
- if (i == 0) {
- warnx("invalid exponential acceleration argument '%s'", optarg);
- usage();
- }
-
- if (i == 1)
- rodent.expoffset = 1.0;
-
- break;
-
case 'c':
rodent.flags |= ChordMiddle;
break;
@@ -613,7 +439,7 @@ main(int argc, char *argv[])
break;
case 'f':
- nodaemon = TRUE;
+ nodaemon = true;
break;
case 'i':
@@ -631,7 +457,7 @@ main(int argc, char *argv[])
warnx("invalid argument `%s'", optarg);
usage();
}
- nodaemon = TRUE;
+ nodaemon = true;
break;
case 'l':
@@ -642,13 +468,6 @@ main(int argc, char *argv[])
}
break;
- case 'm':
- if (!r_installmap(optarg)) {
- warnx("invalid argument `%s'", optarg);
- usage();
- }
- break;
-
case 'p':
rodent.portname = optarg;
break;
@@ -677,58 +496,6 @@ main(int argc, char *argv[])
rodent.baudrate = 9600;
break;
- case 'w':
- i = atoi(optarg);
- if ((i <= 0) || (i > MOUSE_MAXBUTTON)) {
- warnx("invalid argument `%s'", optarg);
- usage();
- }
- rodent.wmode = 1 << (i - 1);
- break;
-
- case 'z':
- if (strcmp(optarg, "x") == 0)
- rodent.zmap[0] = MOUSE_XAXIS;
- else if (strcmp(optarg, "y") == 0)
- rodent.zmap[0] = MOUSE_YAXIS;
- else {
- i = atoi(optarg);
- /*
- * Use button i for negative Z axis movement and
- * button (i + 1) for positive Z axis movement.
- */
- if ((i <= 0) || (i > MOUSE_MAXBUTTON - 1)) {
- warnx("invalid argument `%s'", optarg);
- usage();
- }
- rodent.zmap[0] = i;
- rodent.zmap[1] = i + 1;
- debug("optind: %d, optarg: '%s'", optind, optarg);
- for (j = 1; j < 4; ++j) {
- if ((optind >= argc) || !isdigit(*argv[optind]))
- break;
- i = atoi(argv[optind]);
- if ((i <= 0) || (i > MOUSE_MAXBUTTON - 1)) {
- warnx("invalid argument `%s'", argv[optind]);
- usage();
- }
- rodent.zmap[j] = i;
- ++optind;
- }
- if ((rodent.zmap[2] != 0) && (rodent.zmap[3] == 0))
- rodent.zmap[3] = rodent.zmap[2] + 1;
- }
- break;
-
- case 'C':
- rodent.clickthreshold = atoi(optarg);
- if ((rodent.clickthreshold < 0) ||
- (rodent.clickthreshold > MAX_CLICKTHRESHOLD)) {
- warnx("invalid argument `%s'", optarg);
- usage();
- }
- break;
-
case 'D':
rodent.flags |= ClearDTR;
break;
@@ -741,22 +508,10 @@ main(int argc, char *argv[])
}
break;
- case 'H':
- rodent.flags |= HVirtualScroll;
- break;
-
case 'I':
pidfile = optarg;
break;
- case 'L':
- rodent.scrollspeed = atoi(optarg);
- if (rodent.scrollspeed < 0) {
- warnx("invalid argument `%s'", optarg);
- usage();
- }
- break;
-
case 'P':
rodent.flags |= NoPnP;
break;
@@ -774,24 +529,6 @@ main(int argc, char *argv[])
debug("rodent baudrate %d", rodent.baudrate);
break;
- case 'T':
- drift_terminate = TRUE;
- sscanf(optarg, "%d,%d,%d", &drift_distance, &drift_time,
- &drift_after);
- if (drift_distance <= 0 || drift_time <= 0 || drift_after <= 0) {
- warnx("invalid argument `%s'", optarg);
- usage();
- }
- debug("terminate drift: distance %d, time %d, after %d",
- drift_distance, drift_time, drift_after);
- drift_time_ts.tv_sec = drift_time / 1000;
- drift_time_ts.tv_nsec = (drift_time % 1000) * 1000000;
- drift_2time_ts.tv_sec = (drift_time *= 2) / 1000;
- drift_2time_ts.tv_nsec = (drift_time % 1000) * 1000000;
- drift_after_ts.tv_sec = drift_after / 1000;
- drift_after_ts.tv_nsec = (drift_after % 1000) * 1000000;
- break;
-
case 't':
if (strcmp(optarg, "auto") == 0) {
rodent.rtype = MOUSE_PROTO_UNKNOWN;
@@ -812,34 +549,12 @@ main(int argc, char *argv[])
}
break;
- case 'V':
- rodent.flags |= VirtualScroll;
- break;
- case 'U':
- rodent.scrollthreshold = atoi(optarg);
- if (rodent.scrollthreshold < 0) {
- warnx("invalid argument `%s'", optarg);
- usage();
- }
- break;
-
case 'h':
case '?':
default:
usage();
}
- /* fix Z axis mapping */
- for (i = 0; i < 4; ++i) {
- if (rodent.zmap[i] > 0) {
- for (j = 0; j < MOUSE_MAXBUTTON; ++j) {
- if (mstate[j] == &bstate[rodent.zmap[i] - 1])
- mstate[j] = &zstate[i];
- }
- rodent.zmap[i] = 1 << (rodent.zmap[i] - 1);
- }
- }
-
/* the default port name */
switch(rodent.rtype) {
@@ -908,14 +623,14 @@ main(int argc, char *argv[])
}
r_init(); /* call init function */
- moused();
+ msconvd();
}
if (rodent.mfd != -1)
close(rodent.mfd);
- if (rodent.cfd != -1)
- close(rodent.cfd);
- rodent.mfd = rodent.cfd = -1;
+ if (rodent.ufd != -1)
+ close(rodent.ufd);
+ rodent.mfd = rodent.ufd = -1;
if (rodent.is_removable)
exit(0);
}
@@ -924,90 +639,24 @@ main(int argc, char *argv[])
exit(0);
}
-/*
- * Function to calculate linear acceleration.
- *
- * If there are any rounding errors, the remainder
- * is stored in the remainx and remainy variables
- * and taken into account upon the next movement.
- */
-
-static void
-linacc(int dx, int dy, int *movex, int *movey)
-{
- float fdx, fdy;
-
- if (dx == 0 && dy == 0) {
- *movex = *movey = 0;
- return;
- }
- fdx = dx * rodent.accelx + rodent.remainx;
- fdy = dy * rodent.accely + rodent.remainy;
- *movex = lround(fdx);
- *movey = lround(fdy);
- rodent.remainx = fdx - *movex;
- rodent.remainy = fdy - *movey;
-}
-
-/*
- * Function to calculate exponential acceleration.
- * (Also includes linear acceleration if enabled.)
- *
- * In order to give a smoother behaviour, we record the four
- * most recent non-zero movements and use their average value
- * to calculate the acceleration.
- */
-
-static void
-expoacc(int dx, int dy, int *movex, int *movey)
-{
- static float lastlength[3] = {0.0, 0.0, 0.0};
- float fdx, fdy, length, lbase, accel;
-
- if (dx == 0 && dy == 0) {
- *movex = *movey = 0;
- return;
- }
- fdx = dx * rodent.accelx;
- fdy = dy * rodent.accely;
- length = sqrtf((fdx * fdx) + (fdy * fdy)); /* Pythagoras */
- length = (length + lastlength[0] + lastlength[1] + lastlength[2]) / 4;
- lbase = length / rodent.expoffset;
- accel = powf(lbase, rodent.expoaccel) / lbase;
- fdx = fdx * accel + rodent.remainx;
- fdy = fdy * accel + rodent.remainy;
- *movex = lroundf(fdx);
- *movey = lroundf(fdy);
- rodent.remainx = fdx - *movex;
- rodent.remainy = fdy - *movey;
- lastlength[2] = lastlength[1];
- lastlength[1] = lastlength[0];
- lastlength[0] = length; /* Insert new average, not original length! */
-}
-
static void
-moused(void)
+msconvd(void)
{
- struct mouse_info mouse;
- mousestatus_t action0; /* original mouse action */
- mousestatus_t action; /* interim buffer */
- mousestatus_t action2; /* mapped action */
- struct timeval timeout;
+ mousestatus_t action; /* mouse action */
fd_set fds;
u_char b;
pid_t mpid;
int flags;
int c;
- int i;
- if ((rodent.cfd = open("/dev/consolectl", O_RDWR, 0)) == -1)
- logerr(1, "cannot open /dev/consolectl");
+ if ((rodent.ufd = r_uinput_register()) == -1)
+ logerr(1, "cannot register uinput device");
if (!nodaemon && !background) {
pfh = pidfile_open(pidfile, 0600, &mpid);
if (pfh == NULL) {
if (errno == EEXIST)
- logerrx(1, "moused already running, pid: %d", mpid);
+ logerrx(1, "msconvd already running, pid: %d", mpid);
logwarn("cannot open pid file");
}
if (daemon(0, 0)) {
@@ -1016,35 +665,15 @@ moused(void)
errno = saved_errno;
logerr(1, "failed to become a daemon");
} else {
- background = TRUE;
+ background = true;
pidfile_write(pfh);
}
}
/* clear mouse data */
- bzero(&action0, sizeof(action0));
bzero(&action, sizeof(action));
- bzero(&action2, sizeof(action2));
- bzero(&mouse, sizeof(mouse));
- mouse_button_state = S0;
- clock_gettime(CLOCK_MONOTONIC_FAST, &mouse_button_state_ts);
- mouse_move_delayed = 0;
- for (i = 0; i < MOUSE_MAXBUTTON; ++i) {
- bstate[i].count = 0;
- bstate[i].ts = mouse_button_state_ts;
- }
- for (i = 0; i < (int)nitems(zstate); ++i) {
- zstate[i].count = 0;
- zstate[i].ts = mouse_button_state_ts;
- }
-
- /* choose which ioctl command to use */
- mouse.operation = MOUSE_MOTION_EVENT;
- extioctl = (ioctl(rodent.cfd, CONS_MOUSECTL, &mouse) == 0);
/* process mouse data */
- timeout.tv_sec = 0;
- timeout.tv_usec = 20000; /* 20 msec */
for (;;) {
FD_ZERO(&fds);
@@ -1054,265 +683,37 @@ moused(void)
if (rodent.mremcfd >= 0)
FD_SET(rodent.mremcfd, &fds);
- c = select(FD_SETSIZE, &fds, NULL, NULL,
- ((rodent.flags & Emulate3Button) &&
- S_DELAYED(mouse_button_state)) ? &timeout : NULL);
+ c = select(FD_SETSIZE, &fds, NULL, NULL, NULL);
if (c < 0) { /* error */
logwarn("failed to read from mouse");
continue;
- } else if (c == 0) { /* timeout */
- /* assert(rodent.flags & Emulate3Button) */
- action0.button = action0.obutton;
- action0.dx = action0.dy = action0.dz = 0;
- action0.flags = flags = 0;
- if (r_timeout() && r_statetrans(&action0, &action, A_TIMEOUT)) {
- if (debug > 2)
- debug("flags:%08x buttons:%08x obuttons:%08x",
- action.flags, action.button, action.obutton);
- } else {
- action0.obutton = action0.button;
- continue;
- }
- } else {
- /* MouseRemote client connect/disconnect */
- if ((rodent.mremsfd >= 0) && FD_ISSET(rodent.mremsfd, &fds)) {
- mremote_clientchg(TRUE);
- continue;
- }
- if ((rodent.mremcfd >= 0) && FD_ISSET(rodent.mremcfd, &fds)) {
- mremote_clientchg(FALSE);
- continue;
- }
- /* mouse movement */
- if (read(rodent.mfd, &b, 1) == -1) {
- if (errno == EWOULDBLOCK)
- continue;
- else
- return;
- }
- if ((flags = r_protocol(b, &action0)) == 0)
+ }
+ /* MouseRemote client connect/disconnect */
+ if ((rodent.mremsfd >= 0) && FD_ISSET(rodent.mremsfd, &fds)) {
+ mremote_clientchg(true);
+ continue;
+ }
+ if ((rodent.mremcfd >= 0) && FD_ISSET(rodent.mremcfd, &fds)) {
+ mremote_clientchg(false);
+ continue;
+ }
+ /* mouse movement */
+ if (read(rodent.mfd, &b, 1) == -1) {
+ if (errno == EWOULDBLOCK)
continue;
-
- if ((rodent.flags & VirtualScroll) || (rodent.flags & HVirtualScroll)) {
- /* Allow middle button drags to scroll up and down */
- if (action0.button == MOUSE_BUTTON2DOWN) {
- if (scroll_state == SCROLL_NOTSCROLLING) {
- scroll_state = SCROLL_PREPARE;
- scroll_movement = hscroll_movement = 0;
- debug("PREPARING TO SCROLL");
- }
- debug("[BUTTON2] flags:%08x buttons:%08x obuttons:%08x",
- action.flags, action.button, action.obutton);
- } else {
- debug("[NOTBUTTON2] flags:%08x buttons:%08x obuttons:%08x",
- action.flags, action.button, action.obutton);
-
- /* This isn't a middle button down... move along... */
- if (scroll_state == SCROLL_SCROLLING) {
- /*
- * We were scrolling, someone let go of button 2.
- * Now turn autoscroll off.
- */
- scroll_state = SCROLL_NOTSCROLLING;
- debug("DONE WITH SCROLLING / %d", scroll_state);
- } else if (scroll_state == SCROLL_PREPARE) {
- mousestatus_t newaction = action0;
-
- /* We were preparing to scroll, but we never moved... */
- r_timestamp(&action0);
- r_statetrans(&action0, &newaction,
- A(newaction.button & MOUSE_BUTTON1DOWN,
- action0.button & MOUSE_BUTTON3DOWN));
-
- /* Send middle down */
- newaction.button = MOUSE_BUTTON2DOWN;
- r_click(&newaction);
-
- /* Send middle up */
- r_timestamp(&newaction);
- newaction.obutton = newaction.button;
- newaction.button = action0.button;
- r_click(&newaction);
- }
- }
- }
-
- r_timestamp(&action0);
- r_statetrans(&action0, &action,
- A(action0.button & MOUSE_BUTTON1DOWN,
- action0.button & MOUSE_BUTTON3DOWN));
- debug("flags:%08x buttons:%08x obuttons:%08x", action.flags,
- action.button, action.obutton);
+ else
+ return;
}
- action0.obutton = action0.button;
- flags &= MOUSE_POSCHANGED;
- flags |= action.obutton ^ action.button;
- action.flags = flags;
-
- if (flags) { /* handler detected action */
- r_map(&action, &action2);
- debug("activity : buttons 0x%08x dx %d dy %d dz %d",
- action2.button, action2.dx, action2.dy, action2.dz);
+ if ((flags = r_protocol(b, &action)) == 0)
+ continue;
- if ((rodent.flags & VirtualScroll) || (rodent.flags & HVirtualScroll)) {
- /*
- * If *only* the middle button is pressed AND we are moving
- * the stick/trackpoint/nipple, scroll!
- */
- if (scroll_state == SCROLL_PREPARE) {
- /* Middle button down, waiting for movement threshold */
- if (action2.dy || action2.dx) {
- if (rodent.flags & VirtualScroll) {
- scroll_movement += action2.dy;
- if (scroll_movement < -rodent.scrollthreshold) {
- scroll_state = SCROLL_SCROLLING;
- } else if (scroll_movement > rodent.scrollthreshold) {
- scroll_state = SCROLL_SCROLLING;
- }
- }
- if (rodent.flags & HVirtualScroll) {
- hscroll_movement += action2.dx;
- if (hscroll_movement < -rodent.scrollthreshold) {
- scroll_state = SCROLL_SCROLLING;
- } else if (hscroll_movement > rodent.scrollthreshold) {
- scroll_state = SCROLL_SCROLLING;
- }
- }
- if (scroll_state == SCROLL_SCROLLING) scroll_movement = hscroll_movement = 0;
- }
- } else if (scroll_state == SCROLL_SCROLLING) {
- if (rodent.flags & VirtualScroll) {
- scroll_movement += action2.dy;
- debug("SCROLL: %d", scroll_movement);
- if (scroll_movement < -rodent.scrollspeed) {
- /* Scroll down */
- action2.dz = -1;
- scroll_movement = 0;
- }
- else if (scroll_movement > rodent.scrollspeed) {
- /* Scroll up */
- action2.dz = 1;
- scroll_movement = 0;
- }
- }
- if (rodent.flags & HVirtualScroll) {
- hscroll_movement += action2.dx;
- debug("HORIZONTAL SCROLL: %d", hscroll_movement);
-
- if (hscroll_movement < -rodent.scrollspeed) {
- action2.dz = -2;
- hscroll_movement = 0;
- }
- else if (hscroll_movement > rodent.scrollspeed) {
- action2.dz = 2;
- hscroll_movement = 0;
- }
- }
-
- /* Don't move while scrolling */
- action2.dx = action2.dy = 0;
- }
- }
+ debug("flags:%08x buttons:%08x obuttons:%08x", action.flags,
+ action.button, action.obutton);
- if (drift_terminate) {
- if ((flags & MOUSE_POSCHANGED) == 0 || action.dz || action2.dz)
- drift_last_activity = drift_current_ts;
- else {
- /* X or/and Y movement only - possibly drift */
- tssub(&drift_current_ts, &drift_last_activity, &drift_tmp);
- if (tscmp(&drift_tmp, &drift_after_ts, >)) {
- tssub(&drift_current_ts, &drift_since, &drift_tmp);
- if (tscmp(&drift_tmp, &drift_time_ts, <)) {
- drift_last.x += action2.dx;
- drift_last.y += action2.dy;
- } else {
- /* discard old accumulated steps (drift) */
- if (tscmp(&drift_tmp, &drift_2time_ts, >))
- drift_previous.x = drift_previous.y = 0;
- else
- drift_previous = drift_last;
- drift_last.x = action2.dx;
- drift_last.y = action2.dy;
- drift_since = drift_current_ts;
- }
- if (abs(drift_last.x) + abs(drift_last.y)
- > drift_distance) {
- /* real movement, pass all accumulated steps */
- action2.dx = drift_previous.x + drift_last.x;
- action2.dy = drift_previous.y + drift_last.y;
- /* and reset accumulators */
- tsclr(&drift_since);
- drift_last.x = drift_last.y = 0;
- /* drift_previous will be cleared at next movement*/
- drift_last_activity = drift_current_ts;
- } else {
- continue; /* don't pass current movement to
- * console driver */
- }
- }
- }
- }
-
- if (extioctl) {
- /* Defer clicks until we aren't VirtualScroll'ing. */
- if (scroll_state == SCROLL_NOTSCROLLING)
- r_click(&action2);
-
- if (action2.flags & MOUSE_POSCHANGED) {
- mouse.operation = MOUSE_MOTION_EVENT;
- mouse.u.data.buttons = action2.button;
- if (rodent.flags & ExponentialAcc) {
- expoacc(action2.dx, action2.dy,
- &mouse.u.data.x, &mouse.u.data.y);
- }
- else {
- linacc(action2.dx, action2.dy,
- &mouse.u.data.x, &mouse.u.data.y);
- }
- mouse.u.data.z = action2.dz;
- if (debug < 2)
- if (!paused)
- ioctl(rodent.cfd, CONS_MOUSECTL, &mouse);
- }
- } else {
- mouse.operation = MOUSE_ACTION;
- mouse.u.data.buttons = action2.button;
- if (rodent.flags & ExponentialAcc) {
- expoacc(action2.dx, action2.dy,
- &mouse.u.data.x, &mouse.u.data.y);
- }
- else {
- linacc(action2.dx, action2.dy,
- &mouse.u.data.x, &mouse.u.data.y);
- }
- mouse.u.data.z = action2.dz;
- if (debug < 2)
- if (!paused)
- ioctl(rodent.cfd, CONS_MOUSECTL, &mouse);
- }
-
- /*
- * If the Z axis movement is mapped to an imaginary physical
- * button, we need to cook up a corresponding button `up' event
- * after sending a button `down' event.
- */
- if ((rodent.zmap[0] > 0) && (action.dz != 0)) {
- action.obutton = action.button;
- action.dx = action.dy = action.dz = 0;
- r_map(&action, &action2);
- debug("activity : buttons 0x%08x dx %d dy %d dz %d",
- action2.button, action2.dx, action2.dy, action2.dz);
-
- if (extioctl) {
- r_click(&action2);
- } else {
- mouse.operation = MOUSE_ACTION;
- mouse.u.data.buttons = action2.button;
- mouse.u.data.x = mouse.u.data.y = mouse.u.data.z = 0;
- if (debug < 2)
- if (!paused)
- ioctl(rodent.cfd, CONS_MOUSECTL, &mouse);
- }
+ if (flags) {
+ if (r_uinput_report(rodent.ufd, &action) == -1) {
+ logwarn("failed to write to uinput");
+ return;
}
}
}
@@ -1347,12 +748,10 @@ pause_mouse(__unused int sig)
static void
usage(void)
{
- fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n",
- "usage: moused [-DRcdfs] [-I file] [-F rate] [-r resolution] [-S baudrate]",
- " [-VH [-U threshold]] [-a X[,Y]] [-C threshold] [-m N=M] [-w N]",
- " [-z N] [-t <mousetype>] [-l level] [-3 [-E timeout]]",
- " [-T distance[,time[,after]]] -p <port>",
- " moused [-d] -i <port|if|type|model|all> -p <port>");
+ fprintf(stderr, "%s\n%s\n%s\n",
+ "usage: msconvd [-DPRcdfs] [-I file] [-F rate] [-r resolution] [-S baudrate]",
+ " [-t <mousetype>] [-l level] -p <port>",
+ " msconvd [-Pd] -i <port|if|type|model|all> -p <port>");
exit(1);
}
@@ -1380,6 +779,98 @@ log_or_warn(int log_pri, int errnum, const char *fmt, ...)
warnx("%s", buf);
}
+/*
+ * Setup uinput device as 8button mouse with wheel
+ */
+static int
+r_uinput_register(void)
+{
+ struct uinput_setup uisetup;
+ char *phys;
+ int fd;
+ size_t i;
+
+ fd = open("/dev/uinput", O_RDWR | O_NONBLOCK);
+ if (fd < 0)
+ return (-1);
+
+ /* Set device name and bus/vendor information */
+ memset(&uisetup, 0, sizeof(uisetup));
+ snprintf(uisetup.name, UINPUT_MAX_NAME_SIZE,
+ "%s mouse on %s", r_model(rodent.hw.model), rodent.portname);
+ uisetup.id.bustype = r_bustype(rodent.hw.iftype);
+ uisetup.id.vendor = 0;
+ uisetup.id.product = 0;
+ uisetup.id.version = 0;
+ phys = basename(__DECONST(char *, rodent.portname));
+ if (ioctl(fd, UI_SET_PHYS, phys) < 0 ||
+ ioctl(fd, UI_DEV_SETUP, &uisetup) < 0)
+ goto bail_out;
+
+ /* Advertise events and axes */
+ if (ioctl(fd, UI_SET_EVBIT, EV_SYN) < 0 ||
+ ioctl(fd, UI_SET_EVBIT, EV_KEY) < 0 ||
+ ioctl(fd, UI_SET_EVBIT, EV_REL) < 0 ||
+ ioctl(fd, UI_SET_RELBIT, REL_X) < 0 ||
+ ioctl(fd, UI_SET_RELBIT, REL_Y) < 0 ||
+ ioctl(fd, UI_SET_RELBIT, REL_WHEEL) < 0 ||
+ ioctl(fd, UI_SET_PROPBIT, INPUT_PROP_POINTER) < 0)
+ goto bail_out;
+
+ /* Advertise mouse buttons */
+ for (i = 0; i < nitems(evdev_buttons); i++)
+ if (ioctl(fd, UI_SET_KEYBIT, evdev_buttons[i]) < 0)
+ goto bail_out;
+
+ if (ioctl(fd, UI_DEV_CREATE) >= 0)
+ return (fd); /* SUCCESS */
+
+bail_out:
+ close (fd);
+ return (-1);
+}
+
+static int
+uinput_event(int fd, uint16_t type, uint16_t code, int32_t value)
+{
+ struct input_event ie;
+
+ if (debug >= 2 || paused)
+ return (0);
+
+ memset(&ie, 0, sizeof(ie));
+ ie.type = type;
+ ie.code = code;
+ ie.value = value;
+ return (write(fd, &ie, sizeof(ie)));
+}
+
+static int
+r_uinput_report(int fd, mousestatus_t *act)
+{
+ size_t i;
+ int32_t mask;
+
+ if ((act->dx != 0 && uinput_event(fd, EV_REL, REL_X, act->dx) < 0) ||
+ (act->dy != 0 && uinput_event(fd, EV_REL, REL_Y, act->dy) < 0) ||
+ (act->dz != 0 && uinput_event(fd, EV_REL, REL_WHEEL, -act->dz) < 0))
+ return (-1);
+
+ for (i = 0; i < nitems(evdev_buttons); i++) {
+ mask = 1 << i;
+ if ((act->button & mask) == (act->obutton & mask))
+ continue;
+ if (uinput_event(fd, EV_KEY, evdev_buttons[i],
+ (act->button & mask) != 0) < 0)
+ return (-1);
+ }
+
+ if (uinput_event(fd, EV_SYN, SYN_REPORT, 0) < 0)
+ return (-1);
+
+ return (0);
+}
+
/**
** Mouse interface code, courtesy of XFree86 3.1.2.
**
@@ -1559,6 +1050,12 @@ r_if(int iftype)
return (gettokenname(rifs, iftype));
}
+static uint16_t
+r_bustype(int iftype)
+{
+ return (gettokenval2(rifs, iftype));
+}
+
static const char *
r_name(int type)
{
@@ -1875,7 +1372,7 @@ r_protocol(u_char rBuf, mousestatus_t *act)
static int pBufP = 0;
static unsigned char pBuf[8];
static int prev_x, prev_y;
- static int on = FALSE;
+ static bool on = false;
int x, y;
debug("received char 0x%x",(int)rBuf);
@@ -2109,7 +1606,7 @@ r_protocol(u_char rBuf, mousestatus_t *act)
act->button |= (pBuf[0] & MOUSE_VERSA_TAP) ? MOUSE_BUTTON4DOWN : 0;
act->dx = act->dy = 0;
if (!(pBuf[0] & MOUSE_VERSA_IN_USE)) {
- on = FALSE;
+ on = false;
break;
}
x = (pBuf[2] << 6) | pBuf[1];
@@ -2122,7 +1619,7 @@ r_protocol(u_char rBuf, mousestatus_t *act)
act->dx = prev_x - x;
act->dy = prev_y - y;
} else {
- on = TRUE;
+ on = true;
}
prev_x = x;
prev_y = y;
@@ -2245,7 +1742,7 @@ r_protocol(u_char rBuf, mousestatus_t *act)
(pBuf[0] & MOUSE_PS2VERSA_TAP) ? MOUSE_BUTTON4DOWN : 0;
act->dx = act->dy = 0;
if (!(pBuf[0] & MOUSE_PS2VERSA_IN_USE)) {
- on = FALSE;
+ on = false;
break;
}
x = ((pBuf[4] << 8) & 0xf00) | pBuf[1];
@@ -2258,7 +1755,7 @@ r_protocol(u_char rBuf, mousestatus_t *act)
act->dx = prev_x - x;
act->dy = prev_y - y;
} else {
- on = TRUE;
+ on = true;
}
prev_x = x;
prev_y = y;
@@ -2324,301 +1821,6 @@ r_protocol(u_char rBuf, mousestatus_t *act)
return (act->flags);
}
-static int
-r_statetrans(mousestatus_t *a1, mousestatus_t *a2, int trans)
-{
- int changed;
- int flags;
-
- a2->dx = a1->dx;
- a2->dy = a1->dy;
- a2->dz = a1->dz;
- a2->obutton = a2->button;
- a2->button = a1->button;
- a2->flags = a1->flags;
- changed = FALSE;
-
- if (rodent.flags & Emulate3Button) {
- if (debug > 2)
- debug("state:%d, trans:%d -> state:%d",
- mouse_button_state, trans,
- states[mouse_button_state].s[trans]);
- /*
- * Avoid re-ordering button and movement events. While a button
- * event is deferred, throw away up to BUTTON2_MAXMOVE movement
- * events to allow for mouse jitter. If more movement events
- * occur, then complete the deferred button events immediately.
- */
- if ((a2->dx != 0 || a2->dy != 0) &&
- S_DELAYED(states[mouse_button_state].s[trans])) {
- if (++mouse_move_delayed > BUTTON2_MAXMOVE) {
- mouse_move_delayed = 0;
- mouse_button_state =
- states[mouse_button_state].s[A_TIMEOUT];
- changed = TRUE;
- } else
- a2->dx = a2->dy = 0;
- } else
- mouse_move_delayed = 0;
- if (mouse_button_state != states[mouse_button_state].s[trans])
- changed = TRUE;
- if (changed)
- clock_gettime(CLOCK_MONOTONIC_FAST, &mouse_button_state_ts);
- mouse_button_state = states[mouse_button_state].s[trans];
- a2->button &=
- ~(MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN);
- a2->button &= states[mouse_button_state].mask;
- a2->button |= states[mouse_button_state].buttons;
- flags = a2->flags & MOUSE_POSCHANGED;
- flags |= a2->obutton ^ a2->button;
- if (flags & MOUSE_BUTTON2DOWN) {
- a2->flags = flags & MOUSE_BUTTON2DOWN;
- r_timestamp(a2);
- }
- a2->flags = flags;
- }
- return (changed);
-}
-
-/* phisical to logical button mapping */
-static int p2l[MOUSE_MAXBUTTON] = {
- MOUSE_BUTTON1DOWN, MOUSE_BUTTON2DOWN, MOUSE_BUTTON3DOWN, MOUSE_BUTTON4DOWN,
- MOUSE_BUTTON5DOWN, MOUSE_BUTTON6DOWN, MOUSE_BUTTON7DOWN, MOUSE_BUTTON8DOWN,
- 0x00000100, 0x00000200, 0x00000400, 0x00000800,
- 0x00001000, 0x00002000, 0x00004000, 0x00008000,
- 0x00010000, 0x00020000, 0x00040000, 0x00080000,
- 0x00100000, 0x00200000, 0x00400000, 0x00800000,
- 0x01000000, 0x02000000, 0x04000000, 0x08000000,
- 0x10000000, 0x20000000, 0x40000000,
-};
-
-static char *
-skipspace(char *s)
-{
- while(isspace(*s))
- ++s;
- return (s);
-}
-
-static int
-r_installmap(char *arg)
-{
- int pbutton;
- int lbutton;
- char *s;
-
- while (*arg) {
- arg = skipspace(arg);
- s = arg;
- while (isdigit(*arg))
- ++arg;
- arg = skipspace(arg);
- if ((arg <= s) || (*arg != '='))
- return (FALSE);
- lbutton = atoi(s);
-
- arg = skipspace(++arg);
- s = arg;
- while (isdigit(*arg))
- ++arg;
- if ((arg <= s) || (!isspace(*arg) && (*arg != '\0')))
- return (FALSE);
- pbutton = atoi(s);
-
- if ((lbutton <= 0) || (lbutton > MOUSE_MAXBUTTON))
- return (FALSE);
- if ((pbutton <= 0) || (pbutton > MOUSE_MAXBUTTON))
- return (FALSE);
- p2l[pbutton - 1] = 1 << (lbutton - 1);
- mstate[lbutton - 1] = &bstate[pbutton - 1];
- }
-
- return (TRUE);
-}
-
-static void
-r_map(mousestatus_t *act1, mousestatus_t *act2)
-{
- register int pb;
- register int pbuttons;
- int lbuttons;
-
- pbuttons = act1->button;
- lbuttons = 0;
-
- act2->obutton = act2->button;
- if (pbuttons & rodent.wmode) {
- pbuttons &= ~rodent.wmode;
- act1->dz = act1->dy;
- act1->dx = 0;
- act1->dy = 0;
- }
- act2->dx = act1->dx;
- act2->dy = act1->dy;
- act2->dz = act1->dz;
-
- switch (rodent.zmap[0]) {
- case 0: /* do nothing */
- break;
- case MOUSE_XAXIS:
- if (act1->dz != 0) {
- act2->dx = act1->dz;
- act2->dz = 0;
- }
- break;
- case MOUSE_YAXIS:
- if (act1->dz != 0) {
- act2->dy = act1->dz;
- act2->dz = 0;
- }
- break;
- default: /* buttons */
- pbuttons &= ~(rodent.zmap[0] | rodent.zmap[1]
- | rodent.zmap[2] | rodent.zmap[3]);
- if ((act1->dz < -1) && rodent.zmap[2]) {
- pbuttons |= rodent.zmap[2];
- zstate[2].count = 1;
- } else if (act1->dz < 0) {
- pbuttons |= rodent.zmap[0];
- zstate[0].count = 1;
- } else if ((act1->dz > 1) && rodent.zmap[3]) {
- pbuttons |= rodent.zmap[3];
- zstate[3].count = 1;
- } else if (act1->dz > 0) {
- pbuttons |= rodent.zmap[1];
- zstate[1].count = 1;
- }
- act2->dz = 0;
- break;
- }
-
- for (pb = 0; (pb < MOUSE_MAXBUTTON) && (pbuttons != 0); ++pb) {
- lbuttons |= (pbuttons & 1) ? p2l[pb] : 0;
- pbuttons >>= 1;
- }
- act2->button = lbuttons;
-
- act2->flags = ((act2->dx || act2->dy || act2->dz) ? MOUSE_POSCHANGED : 0)
- | (act2->obutton ^ act2->button);
-}
-
-static void
-r_timestamp(mousestatus_t *act)
-{
- struct timespec ts;
- struct timespec ts1;
- struct timespec ts2;
- struct timespec ts3;
- int button;
- int mask;
- int i;
-
- mask = act->flags & MOUSE_BUTTONS;
-#if 0
- if (mask == 0)
- return;
-#endif
-
- clock_gettime(CLOCK_MONOTONIC_FAST, &ts1);
- drift_current_ts = ts1;
-
- /* double click threshold */
- ts2.tv_sec = rodent.clickthreshold / 1000;
- ts2.tv_nsec = (rodent.clickthreshold % 1000) * 1000000;
- tssub(&ts1, &ts2, &ts);
- debug("ts: %jd %ld", (intmax_t)ts.tv_sec, ts.tv_nsec);
-
- /* 3 button emulation timeout */
- ts2.tv_sec = rodent.button2timeout / 1000;
- ts2.tv_nsec = (rodent.button2timeout % 1000) * 1000000;
- tssub(&ts1, &ts2, &ts3);
-
- button = MOUSE_BUTTON1DOWN;
- for (i = 0; (i < MOUSE_MAXBUTTON) && (mask != 0); ++i) {
- if (mask & 1) {
- if (act->button & button) {
- /* the button is down */
- debug(" : %jd %ld",
- (intmax_t)bstate[i].ts.tv_sec, bstate[i].ts.tv_nsec);
- if (tscmp(&ts, &bstate[i].ts, >)) {
- bstate[i].count = 1;
- } else {
- ++bstate[i].count;
- }
- bstate[i].ts = ts1;
- } else {
- /* the button is up */
- bstate[i].ts = ts1;
- }
- } else {
- if (act->button & button) {
- /* the button has been down */
- if (tscmp(&ts3, &bstate[i].ts, >)) {
- bstate[i].count = 1;
- bstate[i].ts = ts1;
- act->flags |= button;
- debug("button %d timeout", i + 1);
- }
- } else {
- /* the button has been up */
- }
- }
- button <<= 1;
- mask >>= 1;
- }
-}
-
-static int
-r_timeout(void)
-{
- struct timespec ts;
- struct timespec ts1;
- struct timespec ts2;
-
- if (states[mouse_button_state].timeout)
- return (TRUE);
- clock_gettime(CLOCK_MONOTONIC_FAST, &ts1);
- ts2.tv_sec = rodent.button2timeout / 1000;
- ts2.tv_nsec = (rodent.button2timeout % 1000) * 1000000;
- tssub(&ts1, &ts2, &ts);
- return (tscmp(&ts, &mouse_button_state_ts, >));
-}
-
-static void
-r_click(mousestatus_t *act)
-{
- struct mouse_info mouse;
- int button;
- int mask;
- int i;
-
- mask = act->flags & MOUSE_BUTTONS;
- if (mask == 0)
- return;
-
- button = MOUSE_BUTTON1DOWN;
- for (i = 0; (i < MOUSE_MAXBUTTON) && (mask != 0); ++i) {
- if (mask & 1) {
- debug("mstate[%d]->count:%d", i, mstate[i]->count);
- if (act->button & button) {
- /* the button is down */
- mouse.u.event.value = mstate[i]->count;
- } else {
- /* the button is up */
- mouse.u.event.value = 0;
- }
- mouse.operation = MOUSE_BUTTON_EVENT;
- mouse.u.event.id = button;
- if (debug < 2)
- if (!paused)
- ioctl(rodent.cfd, CONS_MOUSECTL, &mouse);
- debug("button %d count %d", i + 1, mouse.u.event.value);
- }
- button <<= 1;
- mask >>= 1;
- }
-}
-
/* $XConsortium: posix_tty.c,v 1.3 95/01/05 20:42:55 kaleb Exp $ */
/* $XFree86: xc/programs/Xserver/hw/xfree86/os-support/shared/posix_tty.c,v 3.4 1995/01/28 17:05:03 dawes Exp $ */
/*
@@ -2745,7 +1947,7 @@ setmousespeed(int old, int new, unsigned cflag)
* The routine does not fully implement the COM Enumerator as par Section
* 2.1 of the document. In particular, we don't have idle state in which
* the driver software monitors the com port for dynamic connection or
- * removal of a device at the port, because `moused' simply quits if no
+ * removal of a device at the port, because `msconvd' simply quits if no
* device is found.
*
* In addition, as PnP COM device enumeration procedure slightly has
@@ -2753,7 +1955,7 @@ setmousespeed(int old, int new, unsigned cflag)
* revisions of the above spec. may fail to respond if the rev 1.0
* procedure is used. XXX
*/
-static int
+static bool
pnpwakeup1(void)
{
struct timeval timeout;
@@ -2783,7 +1985,7 @@ pnpwakeup1(void)
ioctl(rodent.mfd, TIOCMGET, &i);
debug("modem status 0%o", i);
if ((i & TIOCM_DSR) == 0)
- return (FALSE);
+ return (false);
/* port setup, 1st phase (2.1.3) */
setmousespeed(1200, 1200, (CS7 | CREAD | CLOCAL | HUPCL));
@@ -2807,7 +2009,7 @@ pnpwakeup1(void)
timeout.tv_usec = 240000;
if (select(FD_SETSIZE, &fds, NULL, NULL, &timeout) > 0) {
debug("pnpwakeup1(): valid response in first phase.");
- return (TRUE);
+ return (true);
}
/* port setup, 2nd phase (2.1.5) */
@@ -2828,13 +2030,13 @@ pnpwakeup1(void)
timeout.tv_usec = 240000;
if (select(FD_SETSIZE, &fds, NULL, NULL, &timeout) > 0) {
debug("pnpwakeup1(): valid response in second phase.");
- return (TRUE);
+ return (true);
}
- return (FALSE);
+ return (false);
}
-static int
+static bool
pnpwakeup2(void)
{
struct timeval timeout;
@@ -2867,10 +2069,10 @@ pnpwakeup2(void)
timeout.tv_usec = 240000;
if (select(FD_SETSIZE, &fds, NULL, NULL, &timeout) > 0) {
debug("pnpwakeup2(): valid response.");
- return (TRUE);
+ return (true);
}
- return (FALSE);
+ return (false);
}
static int
@@ -2885,7 +2087,7 @@ pnpgets(char *buf)
if (!pnpwakeup1() && !pnpwakeup2()) {
/*
* According to PnP spec, we should set DTR = 1 and RTS = 0 while
- * in idle state. But, `moused' shall set DTR = RTS = 1 and proceed,
+ * in idle state. But, `msconvd' shall set DTR = RTS = 1 and proceed,
* assuming there is something at the port even if it didn't
* respond to the PnP enumeration procedure.
*/
@@ -2942,7 +2144,7 @@ pnpgets(char *buf)
/*
* According to PnP spec, we should set DTR = 1 and RTS = 0 while
- * in idle state. But, `moused' shall leave the modem control lines
+ * in idle state. But, `msconvd' shall leave the modem control lines
* as they are. See above.
*/
connect_idle:
@@ -2951,7 +2153,7 @@ connect_idle:
return (MAX(i, 0));
}
-static int
+static bool
pnpparse(pnpid_t *id, char *buf, int len)
{
char s[3];
@@ -2975,7 +2177,7 @@ pnpparse(pnpid_t *id, char *buf, int len)
/* non-PnP mice */
switch(buf[0]) {
default:
- return (FALSE);
+ return (false);
case 'M': /* Microsoft */
id->eisaid = "PNP0F01";
break;
@@ -2987,7 +2189,7 @@ pnpparse(pnpid_t *id, char *buf, int len)
id->class = "MOUSE";
id->nclass = strlen(id->class);
debug("non-PnP mouse '%c'", buf[0]);
- return (TRUE);
+ return (true);
}
/* PnP mice */
@@ -3086,12 +2288,12 @@ pnpparse(pnpid_t *id, char *buf, int len)
* spec regarding checksum... XXX
*/
logwarnx("PnP checksum error", 0);
- return (FALSE);
+ return (false);
#endif
}
}
- return (TRUE);
+ return (true);
}
static symtab_t *
@@ -3159,6 +2361,18 @@ gettokenname(symtab_t *tab, int val)
return (unknown);
}
+static int
+gettokenval2(symtab_t *tab, int val)
+{
+ int i;
+
+ for (i = 0; tab[i].name != NULL; ++i) {
+ if (tab[i].val == val)
+ return (tab[i].val2);
+ }
+ return (0);
+}
+
/*
* code to read from the Genius Kidspad tablet.
@@ -3355,7 +2569,7 @@ mremote_serversetup(void)
}
static void
-mremote_clientchg(int add)
+mremote_clientchg(bool add)
{
struct sockaddr_un ad;
socklen_t ad_len;
diff --git a/usr.sbin/newsyslog/newsyslog.8 b/usr.sbin/newsyslog/newsyslog.8
index 6d4fc378e790..7429e3b8eb01 100644
--- a/usr.sbin/newsyslog/newsyslog.8
+++ b/usr.sbin/newsyslog/newsyslog.8
@@ -14,7 +14,7 @@
.\" the suitability of this software for any purpose. It is
.\" provided "as is" without express or implied warranty.
.\"
-.Dd December 22, 2023
+.Dd September 1, 2025
.Dt NEWSYSLOG 8
.Os
.Sh NAME
@@ -24,7 +24,6 @@
.Nm
.Op Fl CFNPnrsv
.Op Fl a Ar directory
-.Op Fl c Ar none Ns | Ns Ar legacy Ns | Ns Ar bzip2 Ns | Ns Ar gzip Ns | Ns Ar xz Ns | Ns Ar zstd
.Op Fl d Ar directory
.Op Fl f Ar config_file
.Op Fl S Ar pidfile
@@ -79,25 +78,6 @@ and mode three (above) assumes that this is so.
The following options can be used with
.Nm :
.Bl -tag -width indent
-.It Fl c Ar none Ns | Ns Ar legacy Ns | Ns Ar bzip2 Ns | Ns Ar gzip Ns | Ns Ar xz Ns | Ns Ar zstd
-Instructs
-.Nm
-to use the specified compression method when a file is flagged for compression.
-The default method is
-.Dq legacy ,
-which interprets the
-.Sy J, X, Y, Z
-flags in the configuration file according to their historical meanings.
-This default setting can be overridden by specifying
-.Fl c Ar none ,
-which causes
-.Nm
-to ignore all compression flags.
-Alternatively, specifying one of the compression methods:
-.Sy bzip2 , gzip , xz ,
-or
-.Sy zstd ,
-will apply the chosen method to all files flagged for compression.
.It Fl f Ar config_file
Instruct
.Nm
diff --git a/usr.sbin/newsyslog/newsyslog.c b/usr.sbin/newsyslog/newsyslog.c
index d07f302fd24f..7ebdd7cbc0dd 100644
--- a/usr.sbin/newsyslog/newsyslog.c
+++ b/usr.sbin/newsyslog/newsyslog.c
@@ -701,19 +701,12 @@ parse_args(int argc, char **argv)
hostname_shortlen = strcspn(hostname, ".");
/* Parse command line options. */
- while ((ch = getopt(argc, argv, "a:c:d:f:nrst:vCD:FNPR:S:")) != -1)
+ while ((ch = getopt(argc, argv, "a:d:f:nrst:vCD:FNPR:S:")) != -1)
switch (ch) {
case 'a':
archtodir++;
archdirname = optarg;
break;
- case 'c':
- if (!parse_compression_type(optarg, &compress_type_override)) {
- warnx("Unrecognized compression method '%s'.", optarg);
- usage();
- }
- compress_type_set = true;
- break;
case 'd':
destdir = optarg;
break;
@@ -858,26 +851,10 @@ parse_doption(const char *doption)
static void
usage(void)
{
- int i;
- char *alltypes = NULL, *tmp = NULL;
-
- for (i = 0; i < COMPRESS_TYPES; i++) {
- if (i == COMPRESS_NONE) {
- (void)asprintf(&tmp, "%s|legacy", compress_type[i].name);
- } else {
- (void)asprintf(&tmp, "%s|%s", alltypes, compress_type[i].name);
- }
- if (alltypes)
- free(alltypes);
- alltypes = tmp;
- tmp = NULL;
- }
fprintf(stderr,
- "usage: newsyslog [-CFNPnrsv] [-a directory] [-c %s]\n"
- " [-d directory] [-f config_file]\n"
- " [-S pidfile] [-t timefmt] [[-R tagname] file ...]\n",
- alltypes);
+ "usage: newsyslog [-CFNPnrsv] [-a directory] [-d directory] [-f config_file]\n"
+ " [-S pidfile] [-t timefmt] [[-R tagname] file ...]\n");
exit(1);
}
diff --git a/usr.sbin/newsyslog/newsyslog.conf.5 b/usr.sbin/newsyslog/newsyslog.conf.5
index 2887ecb226aa..d94c39332597 100644
--- a/usr.sbin/newsyslog/newsyslog.conf.5
+++ b/usr.sbin/newsyslog/newsyslog.conf.5
@@ -18,7 +18,7 @@
.\" the suitability of this software for any purpose. It is
.\" provided "as is" without express or implied warranty.
.\"
-.Dd November 11, 2024
+.Dd September 1, 2025
.Dt NEWSYSLOG.CONF 5
.Os
.Sh NAME
@@ -44,8 +44,7 @@ reads a configuration file,
normally
.Pa /etc/newsyslog.conf ,
to determine which logs may potentially be rotated and archived.
-Each line has five mandatory fields and four optional fields,
-separated with whitespace.
+.Pp
Blank lines or lines beginning with
.Ql #
are ignored.
@@ -63,34 +62,73 @@ in this case preceding
is removed and
.Ql #
is treated as an ordinary character.
+.Pp
+The special
+.Dq Ar <compress>
+and
+.Dq Ar <include>
+lines are defined as follows:
+.Bl -tag -width indent
+.It Ar <compress> Ns Ar none Ns | Ns Ar legacy Ns | Ns Ar bzip2 Ns | Ns Ar gzip Ns | Ns Ar xz Ns | Ns Ar zstd
+This special option sets the global compress method,
+it should be placed before all log file entries in
+.Nm
+configuration file.
+The global compress method applies to all log files flagged as
+compressible
+.Dq Sy J ,
+.Dq Sy X ,
+.Dq Sy Y ,
+.Dq Sy Z
+.Ar flags
+below.
+.Pp
+The following compression methods are available:
+.Bl -tag -width indent
+.It Cm none
+No compression is performed, even when a log file is marked as
+compressible. This is useful for filesystems that have native
+compression support.
+.It Cm legacy
+Interprets the
+.Sy J, X, Y, Z
+flags in the configuration file according to their historical meanings.
+This is the default method.
+.It Cm bzip2
+Use
+.Xr bzip2 1
+for all compressible log files.
+.It Cm gzip
+Use
+.Xr gzip 1
+for all compressible log files.
+.It Cm xz
+Use
+.Xr xz 1
+for all compressible log files.
+.It Cm zstd
+Use
+.Xr zstd 1
+for all compressible log files.
+.El
+.It Ar <include>
+The special <include> entry is used to include other configuration
+files and supports globbing.
+.El
+.Pp
+Each other line has five mandatory fields and four optional fields,
+separated with whitespace.
The fields of the configuration file are as follows:
.Bl -tag -width indent
.It Ar logfile_name
Name of the system log file to be archived,
-or one of the special strings
-.Dq Li <compress> ,
-.Dq Li <default> ,
-or
-.Dq Li <include> .
-The <compress> entry,
-which should be placed at the beginning of the
-.Nm
-configuration file,
-sets the global compress method.
-This method is applied when a log file is flagged as
-compressible,
-which has the same effect of passing a compress method to the
-.Fl c
-option on the
-.Xr newsyslog 8
-command line.
+or the special string
+.Dq Ar <default> .
The special <default> entry will only be used if a log file
name is given as a command line argument to
.Xr newsyslog 8 ,
and if that log file name is not matched by any other
line in the configuration file.
-The include entry is used to include other configuration
-files and supports globbing.
.It Ar owner : Ns Ar group
This optional field specifies the owner and group for the archive file.
The
@@ -432,7 +470,7 @@ can be the signal number, e.g., 30 for
.El
.Sh EXAMPLES
The following is an example of the
-.Dq Aq Li include
+.Dq <include>
entry:
.Dl "<include> /etc/newsyslog-local.conf"
.Sh SEE ALSO
diff --git a/usr.sbin/ngctl/Makefile b/usr.sbin/ngctl/Makefile
index 72a5ccaa96d7..997841272376 100644
--- a/usr.sbin/ngctl/Makefile
+++ b/usr.sbin/ngctl/Makefile
@@ -13,4 +13,9 @@ LIBADD= netgraph
CFLAGS+= -DEDITLINE
LIBADD+= edit pthread
+.if ${MK_JAIL} != "no"
+CFLAGS+= -DJAIL
+LIBADD+= jail
+.endif
+
.include <bsd.prog.mk>
diff --git a/usr.sbin/ngctl/main.c b/usr.sbin/ngctl/main.c
index 7c79e67d8275..b32e4f878b6e 100644
--- a/usr.sbin/ngctl/main.c
+++ b/usr.sbin/ngctl/main.c
@@ -55,6 +55,10 @@
#include <histedit.h>
#include <pthread.h>
#endif
+#ifdef JAIL
+#include <sys/jail.h>
+#include <jail.h>
+#endif
#include <netgraph.h>
@@ -137,16 +141,17 @@ int csock, dsock;
int
main(int ac, char *av[])
{
- char name[NG_NODESIZ];
- int interactive = isatty(0) && isatty(1);
- FILE *fp = NULL;
- int ch, rtn = 0;
+ char name[NG_NODESIZ];
+ int interactive = isatty(0) && isatty(1);
+ FILE *fp = NULL;
+ const char *jail_name = NULL;
+ int ch, rtn = 0;
/* Set default node name */
snprintf(name, sizeof(name), "ngctl%d", getpid());
/* Parse command line */
- while ((ch = getopt(ac, av, "df:n:")) != -1) {
+ while ((ch = getopt(ac, av, "df:j:n:")) != -1) {
switch (ch) {
case 'd':
NgSetDebug(NgSetDebug(-1) + 1);
@@ -157,6 +162,13 @@ main(int ac, char *av[])
else if ((fp = fopen(optarg, "r")) == NULL)
err(EX_NOINPUT, "%s", optarg);
break;
+ case 'j':
+#ifdef JAIL
+ jail_name = optarg;
+#else
+ errx(EX_UNAVAILABLE, "not built with jail support");
+#endif
+ break;
case 'n':
snprintf(name, sizeof(name), "%s", optarg);
break;
@@ -169,6 +181,22 @@ main(int ac, char *av[])
ac -= optind;
av += optind;
+ if (jail_name != NULL) {
+ int jid;
+
+ if (jail_name[0] == '\0')
+ Usage("invalid jail name");
+
+ jid = jail_getid(jail_name);
+
+ if (jid == -1)
+ errx((errno == EPERM) ? EX_NOPERM : EX_NOHOST,
+ "%s", jail_errmsg);
+ if (jail_attach(jid) != 0)
+ errx((errno == EPERM) ? EX_NOPERM : EX_OSERR,
+ "cannot attach to jail");
+ }
+
/* Create a new socket node */
if (NgMkSockNode(name, &csock, &dsock) < 0)
err(EX_OSERR, "can't create node");
@@ -657,6 +685,7 @@ Usage(const char *msg)
if (msg)
warnx("%s", msg);
fprintf(stderr,
- "usage: ngctl [-d] [-f file] [-n name] [command ...]\n");
+ "usage: ngctl [-j jail] [-d] [-f filename] [-n nodename] "
+ "[command [argument ...]]\n");
exit(EX_USAGE);
}
diff --git a/usr.sbin/ngctl/ngctl.8 b/usr.sbin/ngctl/ngctl.8
index 2225c836674a..63b8f58ed3df 100644
--- a/usr.sbin/ngctl/ngctl.8
+++ b/usr.sbin/ngctl/ngctl.8
@@ -31,7 +31,7 @@
.\" OF SUCH DAMAGE.
.\" $Whistle: ngctl.8,v 1.6 1999/01/20 03:19:44 archie Exp $
.\"
-.Dd January 19, 1999
+.Dd August 29, 2025
.Dt NGCTL 8
.Os
.Sh NAME
@@ -39,9 +39,11 @@
.Nd netgraph control utility
.Sh SYNOPSIS
.Nm
+.Op Fl j Ar jail
.Op Fl d
.Op Fl f Ar filename
.Op Fl n Ar nodename
+.Op Ar command Op Ns Ar argument ...
.Op Ar command ...
.Sh DESCRIPTION
The
@@ -73,12 +75,31 @@ form if the originating node supports conversion.
.Pp
The options are as follows:
.Bl -tag -width indent
-.It Fl f Ar nodeinfo
+.It Fl f Ar filename
Read commands from the named file.
A single dash represents the standard input.
Blank lines and lines starting with a
.Dq #
are ignored.
+Note that when the
+.Fl j Ar jail
+option is specified, the file will be opened before attaching to the jail and
+then be processed inside the jail.
+.It Fl j Ar jail
+Perform the actions inside the
+.Ar jail .
+.Pp
+.Nm
+will first attach to the
+.Ar jail
+(by jail id or jail name) before performing the effects.
+.Pp
+This allows netgraph nodes of
+.Ar jail
+to be created, modified, and destroyed even if the
+.Nm
+binary is not available in
+.Ar jail .
.It Fl n Ar nodename
Assign
.Em nodename
diff --git a/usr.sbin/tcpdump/Makefile.inc b/usr.sbin/tcpdump/Makefile.inc
index abbdc366c6a0..454f1869508d 100644
--- a/usr.sbin/tcpdump/Makefile.inc
+++ b/usr.sbin/tcpdump/Makefile.inc
@@ -1,3 +1,3 @@
-BINDIR?= /usr/sbin
-
WARNS?= 3
+
+.include "../Makefile.inc"
diff --git a/usr.sbin/tcpdump/tcpdump/Makefile b/usr.sbin/tcpdump/tcpdump/Makefile
index bfbe750c25be..21c5f9ac7fdf 100644
--- a/usr.sbin/tcpdump/tcpdump/Makefile
+++ b/usr.sbin/tcpdump/tcpdump/Makefile
@@ -186,9 +186,9 @@ SRCS= addrtoname.c \
print-unsupported.c \
print-vsock.c \
print-whois.c \
- print-zep.c \
- version.c
-CLEANFILES+= version.c ${MAN}
+ print-zep.c
+
+CLEANFILES+= ${MAN}
CFLAGS+= -I${.CURDIR} -I${TCPDUMP_DISTDIR}
CFLAGS+= -DHAVE_CONFIG_H
@@ -197,9 +197,6 @@ CFLAGS+= -D_U_="__attribute__((unused))"
.if ${MK_INET6_SUPPORT} != "no"
CFLAGS+= -DINET6 -DHAVE_OS_IPV6_SUPPORT
.endif
-.if ${MACHINE_CPUARCH} != "i386"
-CFLAGS+= -DLBL_ALIGN
-.endif
LIBADD= pcap
.if ${MK_CASPER} != "no"
@@ -220,11 +217,6 @@ SRCS+= print-pflog.c \
CFLAGS+= -DHAVE_NET_PFVAR_H -DHAVE_NET_IF_PFLOG_H
.endif
-version.c: ${TCPDUMP_DISTDIR}/VERSION
- rm -f version.c ; \
- sed 's/.*/char version[] = "&";/' ${TCPDUMP_DISTDIR}/VERSION \
- > version.c
-
.include <bsd.prog.mk>
.for mp in ${MAN}
diff --git a/usr.sbin/vidcontrol/vidcontrol.1 b/usr.sbin/vidcontrol/vidcontrol.1
index 09855df6b60f..91804facce8e 100644
--- a/usr.sbin/vidcontrol/vidcontrol.1
+++ b/usr.sbin/vidcontrol/vidcontrol.1
@@ -282,11 +282,17 @@ Show the current changes.
.El
.It Fl d
Print out current output screen map.
+Supported only with
+.Xr syscons 4 .
.It Fl E Ar emulator
Set the terminal emulator to
.Ar emulator .
+Supported only with
+.Xr syscons 4 .
.It Fl e
Show the active and available terminal emulators.
+Supported only with
+.Xr syscons 4 .
.It Xo
.Fl f
.Oo
@@ -358,13 +364,12 @@ Shows the possible video modes with the current video hardware.
.It Fl l Ar screen_map
Install screen output map file from
.Ar screen_map .
-See also
-.Xr syscons 4
-or
-.Xr vt 4
-(depending on which driver you use).
+Supported only with
+.Xr syscons 4 .
.It Fl L
Install default screen output map.
+Supported only with
+.Xr syscons 4 .
.It Fl M Ar char
Sets the base character used to render the mouse pointer to
.Ar char .