diff options
author | Fredrik Rinnestam <fredrik@crux.nu> | 2017-06-20 15:26:36 +0200 |
---|---|---|
committer | Fredrik Rinnestam <fredrik@crux.nu> | 2017-06-20 15:26:36 +0200 |
commit | 62eb2fedd5fe80d82aafae758c7ca9ceb67fcdb9 (patch) | |
tree | c1b5b7754ea11da30f710d7a64e42a3a4d5b7f81 /glibc-32 | |
parent | eee78a9dd5e0f9fac33f6815c396d2eaef4bc7ff (diff) | |
download | core-62eb2fedd5fe80d82aafae758c7ca9ceb67fcdb9.tar.gz core-62eb2fedd5fe80d82aafae758c7ca9ceb67fcdb9.tar.xz |
[notify] glibc-32: Synced with upstream. Contains fixes for
CVE-2017-1000366 and CVE-2015-5180.
Diffstat (limited to 'glibc-32')
-rw-r--r-- | glibc-32/.md5sum | 1 | ||||
-rw-r--r-- | glibc-32/.signature | 5 | ||||
-rw-r--r-- | glibc-32/Pkgfile | 6 | ||||
-rw-r--r-- | glibc-32/glibc-2.24-updates.patch | 15014 |
4 files changed, 15022 insertions, 4 deletions
diff --git a/glibc-32/.md5sum b/glibc-32/.md5sum index 5c1a7d4a..9d607eed 100644 --- a/glibc-32/.md5sum +++ b/glibc-32/.md5sum @@ -1,3 +1,4 @@ +655f50d41e24dcd37447fd6c63ce3f7f glibc-2.24-updates.patch 97dc5517f92016f3d70d83e3162ad318 glibc-2.24.tar.xz ac19b5dac0b160aa59a2e265998c3e91 kernel-headers-4.9.5.tar.xz a8f4549c716cd37244fbf1ed059497f8 lib32.conf diff --git a/glibc-32/.signature b/glibc-32/.signature index 66add287..c30b41d8 100644 --- a/glibc-32/.signature +++ b/glibc-32/.signature @@ -1,7 +1,8 @@ untrusted comment: verify with /etc/ports/core.pub -RWRJc1FUaeVeqgy+zDVBzaxiUtj9qjk77llpDzxL+/Kw+YhaDgV9yXeWfOgfLWa272oyoj3isViZ+xiv2s8v495U3i3LmfrkcAM= -SHA256 (Pkgfile) = c1d05d012efa069b734ef67a079721b5cab3d7c7b99c0372fa3815148badad7c +RWRJc1FUaeVeqnoY9f/WUSSU2kP4f/7u3nFnlwSRMb0MI28wvBXZ/yzOWqBPJzoeN30mfQjnKkfSkZ92JX4mMBXGN4XjPIKRmAs= +SHA256 (Pkgfile) = 70412cb73d56e5faa146698396967763dac1c80187d3813e2e426d3da36971d0 SHA256 (.footprint) = 0af47db3e8a5ea832d1f971ca56f7718a59167c0214375307a508ff46b327119 SHA256 (glibc-2.24.tar.xz) = 99d4a3e8efd144d71488e478f62587578c0f4e1fa0b4eed47ee3d4975ebeb5d3 SHA256 (kernel-headers-4.9.5.tar.xz) = 5783ad8f668ee71561fae370fbcdc477aaa6df249bd85635b87a8c204aeb4aa9 +SHA256 (glibc-2.24-updates.patch) = d74245b3a34b4bcd119ac1da145ee01af77f98c0d3c4bee763049582e8582971 SHA256 (lib32.conf) = 2f174d2bcefe1c29327690514f34d6970fffdd54398320ca23a11b5f1e3c9b2d diff --git a/glibc-32/Pkgfile b/glibc-32/Pkgfile index 6008a3c6..91f2a992 100644 --- a/glibc-32/Pkgfile +++ b/glibc-32/Pkgfile @@ -4,10 +4,10 @@ name=glibc-32 version=2.24 -release=2 +release=6 source=(http://ftpmirror.gnu.org/gnu/glibc/glibc-2.24.tar.xz \ http://crux.nu/files/distfiles/kernel-headers-4.9.5.tar.xz \ - lib32.conf) + glibc-2.24-updates.patch lib32.conf) build() { mkdir build @@ -17,6 +17,8 @@ build() { export CC="${CC:-gcc} -m32" export CFLAGS="$CFLAGS -Wno-error=parentheses" + patch -p1 -d $SRC/glibc-${version:0:4} -i $SRC/glibc-2.24-updates.patch + ../glibc-${version:0:4}/configure --prefix=/usr \ --libdir=/usr/lib32 \ --libexecdir=/usr/lib32 \ diff --git a/glibc-32/glibc-2.24-updates.patch b/glibc-32/glibc-2.24-updates.patch new file mode 100644 index 00000000..0fc9dd2c --- /dev/null +++ b/glibc-32/glibc-2.24-updates.patch @@ -0,0 +1,15014 @@ +diff --git a/ChangeLog b/ChangeLog +index c44c926094..cd6b5a92e9 100644 +--- a/ChangeLog ++++ b/ChangeLog +@@ -1,3 +1,565 @@ ++2017-06-14 Florian Weimer <fweimer@redhat.com> ++ ++ * sysdeps/i386/i686/multiarch/strcspn-c.c: Add IS_IN (libc) guard. ++ * sysdeps/i386/i686/multiarch/varshift.c: Likewise. ++ ++2017-03-07 Siddhesh Poyarekar <siddhesh@sourceware.org> ++ ++ [BZ #21209] ++ * elf/rtld.c (process_envvars): Ignore LD_HWCAP_MASK for ++ AT_SECURE processes. ++ * sysdeps/generic/unsecvars.h: Add LD_HWCAP_MASK. ++ ++2017-06-19 Florian Weimer <fweimer@redhat.com> ++ ++ * elf/rtld.c (audit_list_string): New variable. ++ (audit_list): Update comment. ++ (struct audit_list_iter): Define. ++ (audit_list_iter_init, audit_list_iter_next): New function. ++ (dl_main): Use struct audit_list_iter to process audit modules. ++ (process_dl_audit): Call dso_name_valid_for_suid. ++ (process_envvars): Set audit_list_string instead of calling ++ process_dl_audit. ++ ++2017-06-19 Florian Weimer <fweimer@redhat.com> ++ ++ * elf/rtld.c (SECURE_NAME_LIMIT, SECURE_PATH_LIMIT): Define. ++ (dso_name_valid_for_suid): New function. ++ (handle_ld_preload): Likewise. ++ (dl_main): Call it. Remove alloca. ++ ++2017-06-19 Florian Weimer <fweimer@redhat.com> ++ ++ [BZ #21624] ++ CVE-2017-1000366 ++ * elf/rtld.c (process_envvars): Ignore LD_LIBRARY_PATH for ++ __libc_enable_secure. ++ ++2017-02-01 Andreas Schwab <schwab@linux-m68k.org> ++ ++ * sysdeps/m68k/m680x0/m68020/atomic-machine.h ++ (__arch_compare_and_exchange_val_64_acq, atomic_exchange_acq) ++ (atomic_exchange_and_add, atomic_add): Add casts to 64 bit asm ++ operands. ++ ++2017-05-12 Florian Weimer <fweimer@redhat.com> ++ ++ [BZ #21386] ++ * sysdeps/nptl/fork.c (__libc_fork): Remove assertions on the ++ parent PID. The assertion in the child is incorrect with PID ++ namespaces. ++ ++2017-06-07 Arjun Shankar <arjun.is@lostca.se> ++ ++ * sysdeps/unix/sysv/linux/tst-clone2.c: Do not ++ include test-skeleton.c. ++ Include support/check.h and support/test-driver.c. ++ ++2016-11-24 Adhemerval Zanella <adhemerval.zanella@linaro.org> ++ ++ * sysdeps/nptl/fork.c (__libc_fork): Remove pid cache setting. ++ * nptl/allocatestack.c (allocate_stack): Likewise. ++ (__reclaim_stacks): Likewise. ++ (setxid_signal_thread): Obtain pid through syscall. ++ * nptl/nptl-init.c (sigcancel_handler): Likewise. ++ (sighandle_setxid): Likewise. ++ * nptl/pthread_cancel.c (pthread_cancel): Likewise. ++ * sysdeps/unix/sysv/linux/pthread_kill.c (__pthread_kill): Likewise. ++ * sysdeps/unix/sysv/linux/pthread_sigqueue.c (pthread_sigqueue): ++ Likewise. ++ * sysdeps/unix/sysv/linux/createthread.c (create_thread): Likewise. ++ * sysdeps/unix/sysv/linux/raise.c (raise): Remove old behaviour ++ comment. ++ * sysdeps/unix/sysv/linux/getpid.c: Remove file. ++ * nptl/descr.h (struct pthread): Change comment about pid value. ++ * nptl/pthread_getattr_np.c (pthread_getattr_np): Remove thread ++ pid assert. ++ * sysdeps/unix/sysv/linux/pthread-pids.h (__pthread_initialize_pids): ++ Do not set pid value. ++ * nptl_db/td_ta_thr_iter.c (iterate_thread_list): Remove thread ++ pid cache check. ++ * nptl_db/td_thr_validate.c (td_thr_validate): Likewise. ++ * sysdeps/aarch64/nptl/tcb-offsets.sym: Remove pid offset. ++ * sysdeps/alpha/nptl/tcb-offsets.sym: Likewise. ++ * sysdeps/arm/nptl/tcb-offsets.sym: Likewise. ++ * sysdeps/hppa/nptl/tcb-offsets.sym: Likewise. ++ * sysdeps/i386/nptl/tcb-offsets.sym: Likewise. ++ * sysdeps/ia64/nptl/tcb-offsets.sym: Likewise. ++ * sysdeps/m68k/nptl/tcb-offsets.sym: Likewise. ++ * sysdeps/microblaze/nptl/tcb-offsets.sym: Likewise. ++ * sysdeps/mips/nptl/tcb-offsets.sym: Likewise. ++ * sysdeps/nios2/nptl/tcb-offsets.sym: Likewise. ++ * sysdeps/powerpc/nptl/tcb-offsets.sym: Likewise. ++ * sysdeps/s390/nptl/tcb-offsets.sym: Likewise. ++ * sysdeps/sh/nptl/tcb-offsets.sym: Likewise. ++ * sysdeps/sparc/nptl/tcb-offsets.sym: Likewise. ++ * sysdeps/tile/nptl/tcb-offsets.sym: Likewise. ++ * sysdeps/x86_64/nptl/tcb-offsets.sym: Likewise. ++ * sysdeps/unix/sysv/linux/aarch64/clone.S: Remove pid and tid caching. ++ * sysdeps/unix/sysv/linux/alpha/clone.S: Likewise. ++ * sysdeps/unix/sysv/linux/arm/clone.S: Likewise. ++ * sysdeps/unix/sysv/linux/hppa/clone.S: Likewise. ++ * sysdeps/unix/sysv/linux/i386/clone.S: Likewise. ++ * sysdeps/unix/sysv/linux/ia64/clone2.S: Likewise. ++ * sysdeps/unix/sysv/linux/mips/clone.S: Likewise. ++ * sysdeps/unix/sysv/linux/nios2/clone.S: Likewise. ++ * sysdeps/unix/sysv/linux/powerpc/powerpc32/clone.S: Likewise. ++ * sysdeps/unix/sysv/linux/powerpc/powerpc64/clone.S: Likewise. ++ * sysdeps/unix/sysv/linux/s390/s390-32/clone.S: Likewise. ++ * sysdeps/unix/sysv/linux/s390/s390-64/clone.S: Likewise. ++ * sysdeps/unix/sysv/linux/sh/clone.S: Likewise. ++ * sysdeps/unix/sysv/linux/sparc/sparc32/clone.S: Likewise. ++ * sysdeps/unix/sysv/linux/sparc/sparc64/clone.S: Likewise. ++ * sysdeps/unix/sysv/linux/tile/clone.S: Likewise. ++ * sysdeps/unix/sysv/linux/x86_64/clone.S: Likewise. ++ * sysdeps/unix/sysv/linux/aarch64/vfork.S: Remove pid set and reset. ++ * sysdeps/unix/sysv/linux/alpha/vfork.S: Likewise. ++ * sysdeps/unix/sysv/linux/arm/vfork.S: Likewise. ++ * sysdeps/unix/sysv/linux/i386/vfork.S: Likewise. ++ * sysdeps/unix/sysv/linux/ia64/vfork.S: Likewise. ++ * sysdeps/unix/sysv/linux/m68k/clone.S: Likewise. ++ * sysdeps/unix/sysv/linux/m68k/vfork.S: Likewise. ++ * sysdeps/unix/sysv/linux/mips/vfork.S: Likewise. ++ * sysdeps/unix/sysv/linux/nios2/vfork.S: Likewise. ++ * sysdeps/unix/sysv/linux/powerpc/powerpc32/vfork.S: Likewise. ++ * sysdeps/unix/sysv/linux/powerpc/powerpc64/vfork.S: Likewise. ++ * sysdeps/unix/sysv/linux/s390/s390-32/vfork.S: Likewise. ++ * sysdeps/unix/sysv/linux/s390/s390-64/vfork.S: Likewise. ++ * sysdeps/unix/sysv/linux/sh/vfork.S: Likewise. ++ * sysdeps/unix/sysv/linux/sparc/sparc32/vfork.S: Likewise. ++ * sysdeps/unix/sysv/linux/sparc/sparc64/vfork.S: Likewise. ++ * sysdeps/unix/sysv/linux/tile/vfork.S: Likewise. ++ * sysdeps/unix/sysv/linux/x86_64/vfork.S: Likewise. ++ * sysdeps/unix/sysv/linux/hppa/pt-vfork.S: Likewise. ++ * sysdeps/unix/sysv/linux/tst-clone2.c (f): Remove direct pthread ++ struct access. ++ (clone_test): Remove function. ++ (do_test): Rewrite to take in consideration pid is not cached anymore. ++ ++2016-09-26 Adhemerval Zanella <adhemerval.zanella@linaro.org> ++ ++ * sysdeps/unix/sysdep.h (__INTERNAL_SYSCALL0): New macro. ++ (__INTERNAL_SYSCALL1): Likewise. ++ (__INTERNAL_SYSCALL2): Likewise. ++ (__INTERNAL_SYSCALL3): Likewise. ++ (__INTERNAL_SYSCALL4): Likewise. ++ (__INTERNAL_SYSCALL5): Likewise. ++ (__INTERNAL_SYSCALL6): Likewise. ++ (__INTERNAL_SYSCALL7): Likewise. ++ (__INTERNAL_SYSCALL_NARGS_X): Likewise. ++ (__INTERNAL_SYSCALL_NARGS): Likewise. ++ (__INTERNAL_SYSCALL_DISP): Likewise. ++ (INTERNAL_SYSCALL_CALL): Likewise. ++ (__SYSCALL0): Rename to __INLINE_SYSCALL0. ++ (__SYSCALL1): Rename to __INLINE_SYSCALL1. ++ (__SYSCALL2): Rename to __INLINE_SYSCALL2. ++ (__SYSCALL3): Rename to __INLINE_SYSCALL3. ++ (__SYSCALL4): Rename to __INLINE_SYSCALL4. ++ (__SYSCALL5): Rename to __INLINE_SYSCALL5. ++ (__SYSCALL6): Rename to __INLINE_SYSCALL6. ++ (__SYSCALL7): Rename to __INLINE_SYSCALL7. ++ (__SYSCALL_NARGS_X): Rename to __INLINE_SYSCALL_NARGS_X. ++ (__SYSCALL_NARGS): Rename to __INLINE_SYSCALL_NARGS. ++ (__SYSCALL_DISP): Rename to __INLINE_SYSCALL_DISP. ++ (__SYSCALL_CALL): Rename to INLINE_SYSCALL_CALL. ++ (SYSCALL_CANCEL): Replace __SYSCALL_CALL with INLINE_SYSCALL_CALL. ++ ++2017-04-28 H.J. Lu <hongjiu.lu@intel.com> ++ ++ [BZ #21396] ++ * sysdeps/x86/cpu-features.c (init_cpu_features): Set ++ Prefer_No_AVX512 if AVX512ER isn't available. ++ * sysdeps/x86/cpu-features.h (bit_arch_Prefer_No_AVX512): New. ++ (index_arch_Prefer_No_AVX512): Likewise. ++ * sysdeps/x86_64/multiarch/memcpy.S (__new_memcpy): Don't use ++ AVX512 version if Prefer_No_AVX512 is set. ++ * sysdeps/x86_64/multiarch/memcpy_chk.S (__memcpy_chk): ++ Likewise. ++ * sysdeps/x86_64/multiarch/memmove.S (__libc_memmove): Likewise. ++ * sysdeps/x86_64/multiarch/memmove_chk.S (__memmove_chk): ++ Likewise. ++ * sysdeps/x86_64/multiarch/mempcpy.S (__mempcpy): Likewise. ++ * sysdeps/x86_64/multiarch/mempcpy_chk.S (__mempcpy_chk): ++ Likewise. ++ * sysdeps/x86_64/multiarch/memset.S (memset): Likewise. ++ * sysdeps/x86_64/multiarch/memset_chk.S (__memset_chk): ++ Likewise. ++ ++2017-04-28 H.J. Lu <hongjiu.lu@intel.com> ++ ++ * sysdeps/x86/cpu-features.c (init_cpu_features): Set ++ Prefer_No_VZEROUPPER if AVX512ER is available. ++ * sysdeps/x86/cpu-features.h ++ (bit_cpu_AVX512PF): New. ++ (bit_cpu_AVX512ER): Likewise. ++ (bit_cpu_AVX512CD): Likewise. ++ (bit_cpu_AVX512BW): Likewise. ++ (bit_cpu_AVX512VL): Likewise. ++ (index_cpu_AVX512PF): Likewise. ++ (index_cpu_AVX512ER): Likewise. ++ (index_cpu_AVX512CD): Likewise. ++ (index_cpu_AVX512BW): Likewise. ++ (index_cpu_AVX512VL): Likewise. ++ (reg_AVX512PF): Likewise. ++ (reg_AVX512ER): Likewise. ++ (reg_AVX512CD): Likewise. ++ (reg_AVX512BW): Likewise. ++ (reg_AVX512VL): Likewise. ++ ++2017-01-05 Joseph Myers <joseph@codesourcery.com> ++ ++ [BZ #21026] ++ * sysdeps/unix/sysv/linux/mips/mips64/n64/syscalls.list ++ (readahead): New syscall entry. ++ ++2017-04-07 H.J. Lu <hongjiu.lu@intel.com> ++ ++ [BZ #21258] ++ * sysdeps/x86_64/dl-trampoline.S (_dl_runtime_resolve_opt): ++ Define only if _dl_runtime_resolve is defined to ++ _dl_runtime_resolve_sse_vex. ++ * sysdeps/x86_64/dl-trampoline.h (_dl_runtime_resolve_opt): ++ Fallthrough to _dl_runtime_resolve_sse_vex. ++ ++2017-04-03 Mike Frysinger <vapier@gentoo.org> ++ ++ [BZ #21253] ++ * sysdeps/unix/sysv/linux/spawni.c (__spawnix): Increase argv_size ++ slack space by 32KiB. ++ ++2017-03-31 Slava Barinov <v.barinov@samsung.com> ++ ++ [BZ #21289] ++ * io/fts.h (fts_set): Replace __REDIRECT with __REDIRECT_NTH. ++ ++2017-03-20 Mike Frysinger <vapier@gentoo.org> ++ ++ [BZ #21275] ++ * sysdeps/unix/sysv/linux/spawni.c [__ia64__] (CLONE): Rename ++ __stack to __stackbase. ++ (STACK): Invert _STACK_GROWS_DOWN and _STACK_GROWS_UP order of ++ checks so we can include defined(__ia64__) first. ++ ++2017-03-15 John David Anglin <danglin@gcc.gnu.org> ++ ++ * sysdeps/hppa/dl-machine.h (DL_STACK_END): Define. ++ (RTLD_START): Don't record stack end address in _dl_start_user. ++ ++2017-01-30 H.J. Lu <hongjiu.lu@intel.com> ++ ++ [BZ #21081] ++ * sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S ++ (L(stosb)): Add VZEROUPPER before ret. ++ ++2016-11-28 H.J. Lu <hongjiu.lu@intel.com> ++ ++ [BZ #20750] ++ * sysdeps/x86_64/sysdep.h (JUMPTARGET): Check SHARED instead ++ of PIC. ++ ++2016-12-31 Florian Weimer <fweimer@redhat.com> ++ ++ [BZ #18784] ++ CVE-2015-5180 ++ * include/arpa/nameser_compat.h (T_QUERY_A_AND_AAAA): Rename from ++ T_UNSPEC. Adjust value. ++ * resolv/nss_dns/dns-host.c (_nss_dns_gethostbyname4_r): Use it. ++ * resolv/res_query.c (__libc_res_nquery): Likewise. ++ * resolv/res_mkquery.c (res_nmkquery): Check for out-of-range ++ QTYPEs. ++ * resolv/tst-resolv-qtypes.c: New file. ++ * resolv/Makefile (xtests): Add tst-resolv-qtypes. ++ (tst-resolv-qtypes): Link against libresolv and libpthread. ++ ++2017-02-02 Siddhesh Poyarekar <siddhesh@sourceware.org> ++ ++ * sysdeps/generic/unsecvars.h: Add GLIBC_TUNABLES. ++ ++2017-01-23 Rajalakshmi Srinivasaraghavan <raji@linux.vnet.ibm.com> ++ Steven Munroe <sjmunroe@us.ibm.com> ++ Tulio Magno Quites Machado Filho <tuliom@linux.vnet.ibm.com> ++ ++ [BZ #20822] ++ * sysdeps/unix/sysv/linux/powerpc/elision-lock.c ++ (__lll_lock_elision): Access adapt_count via C11 atomics. ++ * sysdeps/unix/sysv/linux/powerpc/elision-trylock.c ++ (__lll_trylock_elision): Likewise. ++ * sysdeps/unix/sysv/linux/powerpc/elision-unlock.c ++ (__lll_unlock_elision): Update adapt_count variable inside the ++ critical section using C11 atomics. ++ ++2016-12-24 Carlos O'Donell <carlos@redhat.com> ++ ++ [BZ #11941] ++ * elf/dl-close.c (_dl_close): Take dl_load_lock to examine map. ++ Remove assert (map->l_init_called); if DF_1_NODELETE is set. ++ * elf/Makefile [ifeq (yes,$(build-shared))] (tests): Add ++ tst-nodelete-dlclose. ++ (modules-names): Add tst-nodelete-dlclose-dso and ++ tst-nodelete-dlclose-plugin. ++ ($(objpfx)tst-nodelete-dlclose-dso.so): Define. ++ ($(objpfx)tst-nodelete-dlclose-plugin.so): Define. ++ ($(objpfx)tst-nodelete-dlclose): Define. ++ ($(objpfx)tst-nodelete-dlclose.out): Define. ++ ++2016-08-02 Aurelien Jarno <aurelien@aurel32.net> ++ ++2016-08-02 Aurelien Jarno <aurelien@aurel32.net> ++ ++ * sysdeps/alpha/fpu/s_ceil.c (__ceil): Add argument with itself ++ when it is a NaN. ++ [_IEEE_FP_INEXACT] Remove. ++ * sysdeps/alpha/fpu/s_ceilf.c (__ceilf): Likewise. ++ * sysdeps/alpha/fpu/s_floor.c (__floor): Add argument with itself ++ when it is a NaN. ++ [_IEEE_FP_INEXACT] Remove. ++ * sysdeps/alpha/fpu/s_floorf.c (__floorf): Likewise. ++ * sysdeps/alpha/fpu/s_rint.c (__rint): Add argument with itself ++ when it is a NaN. ++ * sysdeps/alpha/fpu/s_rintf.c (__rintf): Likewise. ++ * sysdeps/alpha/fpu/s_trunc.c (__trunc): Return the input value ++ when its absolute value is greater than 0x1.0p52. ++ [_IEEE_FP_INEXACT] Remove. ++ * sysdeps/alpha/fpu/s_truncf.c (__truncf): Return the input value ++ when its absolute value is greater than 0x1.0p23. ++ [_IEEE_FP_INEXACT] Remove. ++ ++2016-11-30 H.J. Lu <hongjiu.lu@intel.com> ++ ++ [BZ #20495] ++ [BZ #20508] ++ * sysdeps/x86/cpu-features.c (init_cpu_features): For Intel ++ processors, set Use_dl_runtime_resolve_slow and set ++ Use_dl_runtime_resolve_opt if XGETBV suports ECX == 1. ++ * sysdeps/x86/cpu-features.h (bit_arch_Use_dl_runtime_resolve_opt): ++ New. ++ (bit_arch_Use_dl_runtime_resolve_slow): Likewise. ++ (index_arch_Use_dl_runtime_resolve_opt): Likewise. ++ (index_arch_Use_dl_runtime_resolve_slow): Likewise. ++ * sysdeps/x86_64/dl-machine.h (elf_machine_runtime_setup): Use ++ _dl_runtime_resolve_avx512_opt and _dl_runtime_resolve_avx_opt ++ if Use_dl_runtime_resolve_opt is set. Use ++ _dl_runtime_resolve_slow if Use_dl_runtime_resolve_slow is set. ++ * sysdeps/x86_64/dl-trampoline.S: Include <cpu-features.h>. ++ (_dl_runtime_resolve_opt): New. Defined for AVX and AVX512. ++ (_dl_runtime_resolve): Add one for _dl_runtime_resolve_sse_vex. ++ * sysdeps/x86_64/dl-trampoline.h (_dl_runtime_resolve_avx_slow): ++ New. ++ (_dl_runtime_resolve_opt): Likewise. ++ (_dl_runtime_profile): Define only if _dl_runtime_profile is ++ defined. ++ ++2016-11-24 Aurelien Jarno <aurelien@aurel32.net> ++ ++ * sysdeps/x86_64/memcpy_chk.S (__memcpy_chk): Check for SHARED ++ instead of PIC. ++ ++2016-11-23 Matthew Fortune <Matthew.Fortune@imgtec.com> ++ Maciej W. Rozycki <macro@imgtec.com> ++ ++ * sysdeps/mips/mips32/crti.S (_init): Add `.insn' pseudo-op at ++ `.Lno_weak_fn' label. ++ * sysdeps/mips/mips64/n32/crti.S (_init): Likewise. ++ * sysdeps/mips/mips64/n64/crti.S (_init): Likewise. ++ ++2016-11-22 Adhemerval Zanella <adhemerva.zanella@linaro.org> ++ ++ [BZ #20847] ++ * posix/execvpe.c (maybe_script_execute): Remove write past allocated ++ array bounds. ++ (__execvpe): Likewise. ++ ++2016-11-15 Denis Kaganovich <mahatma@eu.by> ++ Magnus Granberg <zorry@gentoo.org> ++ Mike Frysinger <vapier@gentoo.org> ++ ++ [BZ #20662] ++ * configure.ac (libc_cv_predef_stack_protector): Also check for ++ __stack_chk_fail_local symbols. ++ * configure: Regenerated. ++ ++2016-11-03 Joseph Myers <joseph@codesourcery.com> ++ ++ * conform/Makefile ($(linknamespace-header-tests)): Also depend on ++ $(linknamespace-symlists-tests). ++ ++2016-11-06 Aurelien Jarno <aurelien@aurel32.net> ++ ++ * iconv/gconv.h (__gconv_info): Define __data element using a ++ zero-length array. ++ ++2016-10-25 Joseph Myers <joseph@codesourcery.com> ++ ++ * sysdeps/powerpc/powerpc32/power6/memset.S (memset): Use cmplwi ++ instead of cmpli. ++ * sysdeps/powerpc/powerpc64/power6/memset.S (memset): Use cmpldi ++ instead of cmpli. ++ ++2016-10-24 Adhemerval Zanella <adhemerval.zanella@linaro.org> ++ ++ * sysdeps/unix/sysv/linux/pread.c (__libc_pread): Use SYSCALL_LL_PRW. ++ * sysdeps/unix/sysv/linux/pwrite.c (__libc_pwrite): Likewise. ++ * sysdeps/unix/sysv/linux/pread64.c (__libc_pread64): Use ++ SYSCALL_LL64_PRW. ++ * sysdeps/unix/sysv/linux/pwrite64.c (__libc_pwrite64): Likewise. ++ * sysdeps/unix/sysv/linux/sh/kernel-features.h: Define ++ __ASSUME_PRW_DUMMY_ARG. ++ * sysdeps/unix/sysv/linux/sh/pread.c: Remove file. ++ * sysdeps/unix/sysv/linux/sh/pread64.c: Likewise. ++ * sysdeps/unix/sysv/linux/sh/pwrite.c: Likewise. ++ * sysdeps/unix/sysv/linux/sh/pwrite64.c: Likewise. ++ * sysdeps/unix/sysv/linux/sysdep.h: Define SYSCALL_LL_PRW and ++ SYSCALL_LL_PRW64 based on __ASSUME_PRW_DUMMY_ARG. ++ ++2016-10-05 Tulio Magno Quites Machado Filho <tuliom@linux.vnet.ibm.com> ++ ++ * sysdeps/powerpc/fpu/libm-test-ulps: Regenerated. ++ ++2016-09-20 Adhemerval Zanella <adhemerval.zanella@linaro.org> ++ ++ * sysdeps/unix/sysv/linux/spawni.c (__spawnix): Correctly block and unblock ++ all signals when executing the clone vfork child. ++ (SIGALL_SET): Remove macro. ++ ++ * nptl/Makefile (tests): Add tst-exec5. ++ * nptl/tst-exec5.c: New file. ++ * sysdeps/unix/sysv/linux/spawni.c (__spawni): Correctly enable and disable ++ asynchronous cancellation. ++ ++2016-09-19 Tulio Magno Quites Machado Filho <tuliom@linux.vnet.ibm.com> ++ ++ [BZ #20615] ++ * sysdeps/powerpc/powerpc32/power9/multiarch/Implies: Replace ++ fpu directory by non-fpu. ++ * sysdeps/powerpc/powerpc64/power9/fpu/Implies: Remove dependency ++ on non-fpu directory from a fpu directory. ++ ++2016-09-02 Roland McGrath <roland@hack.frob.com> ++ ++ * sysdeps/arm/nacl/libc.abilist: Add GLIBC_2.24 A. ++ ++ * sysdeps/nacl/dup.c: Add libc_hidden_def. ++ ++2016-09-02 Roland McGrath <roland@hack.frob.com> ++ ++ * sysdeps/posix/wait3.c: Don't treat STAT_LOC as a union, since it's ++ not any more. ++ ++2016-09-02 Roland McGrath <roland@hack.frob.com> ++ ++ * sysdeps/nacl/clock.c (clock): nacl_abi_clock_t -> nacl_irt_clock_t ++ ++2016-08-17 Florian Weimer <fweimer@redhat.com> ++ ++ Reduce time to expected nptl/tst-once5 failure. ++ * nptl/tst-once5.cc (TIMEOUT): Define. ++ ++2016-08-18 Florian Weimer <fweimer@redhat.com> ++ ++ [BZ #16907] ++ * argp/argp.h: Switch to __BEGIN_DECLS and __END_DECLS. ++ (__THROW, __NTH, __attribute__, __restrict): Remove definitions. ++ * argp/argp-fmtstream.h: Add __BEGIN_DECLS and __END_DECLS. ++ (__attribute__): Remove definition. ++ ++2016-08-15 Andreas Schwab <schwab@suse.de> ++ ++ [BZ #20435] ++ * sysdeps/unix/sysv/linux/arm/setcontext.S (__startcontext): Mark ++ as .cantunwind. ++ ++2016-08-17 Florian Weimer <fweimer@redhat.com> ++ ++ [BZ #20452] ++ Avoid additional copies of objects in libc.a in static libraries. ++ * sysdeps/ia64/nptl/Makefile (libpthread-shared-only-routines): ++ Add ptw-sysdep, ptw-sigblock, ptw-sigprocmask. ++ * sysdeps/mips/Makefile (librt-shared-only-routines): Add ++ rt-sysdep. ++ * sysdeps/mips/nptl/Makefile (libpthread-shared-only-routines): ++ Add nptl-sysdep. ++ * sysdeps/s390/nptl/Makefile (libpthread-shared-only-routines): ++ Add ptw-sysdep. ++ * sysdeps/unix/alpha/Makefile (librt-shared-only-routines): Add ++ rt-sysdep. ++ * sysdeps/unix/sysv/linux/alpha/Makefile ++ (libpthread-shared-only-routines): Add ptw-sysdep, ++ ptw-sigprocmask, ptw-rt_sigaction. ++ * sysdeps/unix/sysv/linux/ia64/Makefile ++ (librt-shared-only-routines): Add rt-sysdep. ++ * sysdeps/unix/sysv/linux/i386/Makefile ++ (libpthread-shared-only-routines): Add libc-do-syscall. ++ * sysdeps/unix/sysv/linux/microblaze/Makefile ++ (libpthread-shared-only-routines): Add sysdep. ++ * sysdeps/unix/sysv/linux/powerpc/Makefile ++ (librt-shared-only-routines): Add rt-sysdep. ++ (libpthread-shared-only-routines): Add sysdep. ++ * sysdeps/unix/sysv/linux/s390/Makefile ++ (librt-shared-only-routines): Add rt-sysdep. ++ * sysdeps/unix/sysv/linux/sparc/Makefile ++ (librt-shared-only-routines): Add rt-sysdep. ++ (libpthread-shared-only-routines): Add sysdep. ++ * sysdeps/unix/sysv/linux/tile/Makefile ++ (libpthread-shared-only-routines): Likewise. ++ ++2016-08-05 Aurelien Jarno <aurelien@aurel32.net> ++ ++ * sysdeps/sparc/sparc32/sparcv9/fpu/multiarch/Makefile ++ [$(subdir) = math && $(have-as-vis3) = yes] (libm-sysdep_routines): ++ Remove s_fdimf-vis3, s_fdim-vis3. ++ * sysdeps/sparc/sparc32/fpu/s_fdim.S: Delete file. ++ * sysdeps/sparc/sparc32/fpu/s_fdimf.S: Likewise. ++ * sysdeps/sparc/sparc32/sparcv9/fpu/multiarch/s_fdim-vis3.S: Likewise. ++ * sysdeps/sparc/sparc32/sparcv9/fpu/multiarch/s_fdim.S: Likewise. ++ * sysdeps/sparc/sparc32/sparcv9/fpu/multiarch/s_fdimf-vis3.S: Likewise. ++ * sysdeps/sparc/sparc32/sparcv9/fpu/multiarch/s_fdimf.S: Likewise. ++ * sysdeps/sparc/sparc32/sparcv9/fpu/s_fdim.S: Likewise. ++ * sysdeps/sparc/sparc32/sparcv9/fpu/s_fdimf.S: Likewise. ++ * sysdeps/sparc/sparc64/fpu/s_fdim.S: Likewise. ++ * sysdeps/sparc/sparc64/fpu/s_fdimf.S: Likewise. ++ ++2016-08-02 David S. Miller <davem@davemloft.net> ++ ++ * sysdeps/sparc/sparc32/sparcv9/fpu/multiarch/s_nearbyint-vis3.S ++ (__nearbyint_vis3): Don't check for sNaN before float register is ++ loaded with the incoming argument. ++ * sysdeps/sparc/sparc32/sparcv9/fpu/multiarch/s_nearbyintf-vis3.S ++ (__nearbyintf_vis3): Likewise. ++ * sysdeps/sparc/sparc32/sparcv9/fpu/s_nearbyint.S (__nearbyint): ++ Likewise. ++ * sysdeps/sparc/sparc32/sparcv9/fpu/s_nearbyintf.S (__nearbyintf): ++ Likewise. ++ ++2016-08-03 Aurelien Jarno <aurelien@aurel32.net> ++ ++ * sysdeps/powerpc/ifunc-sel.h (ifunc_sel): Replace beqlr instructions ++ by beq instructions jumping to the end of the function. ++ * sysdeps/powerpc/ifunc-sel.h (ifunc_sel): Add "11", "12", "cr0" to the ++ clobber list. Use "i" constraint instead of "X". ++ (ifunc_one): Add "12" to the clobber list. Use "i" constraint instead ++ of "X". ++ ++2016-08-04 Carlos O'Donell <carlos@redhat.com> ++ ++ * po/de.po: Update from Translation Project. ++ * po/fi.po: Likewise. ++ * po/sv.po: Likewise. ++ ++2016-08-02 Florian Weimer <fweimer@redhat.com> ++ ++ [BZ #20370] ++ * malloc/arena.c (get_free_list): Update comment. Assert that ++ arenas on the free list have no attached threads. ++ (remove_from_free_list): New function. ++ (reused_arena): Call it. ++ ++2016-08-04 Florian Weimer <fweimer@redhat.com> ++ ++ Use sysdep.o from libc.a in static libraries. ++ * sysdeps/unix/sysv/linux/i386/Makefile ++ (libpthread-shared-only-routines): Add sysdep. ++ (librt-shared-only-routines): Likewise. ++ + 2016-08-01 Carlos O'Donell <carlos@redhat.com> + + * version.h (RELEASE): Set to "stable" +diff --git a/Makeconfig b/Makeconfig +index 03fd89c13e..ee379f5852 100644 +--- a/Makeconfig ++++ b/Makeconfig +@@ -394,6 +394,9 @@ ifndef after-link + after-link = + endif + ++# Additional libraries to link into every test. ++link-extra-libs-tests = $(libsupport) ++ + # Command for linking PIE programs with the C library. + ifndef +link-pie + +link-pie-before-libc = $(CC) -pie -Wl,-O1 -nostdlib -nostartfiles -o $@ \ +@@ -503,7 +506,7 @@ link-libc = $(link-libc-rpath-link) $(link-libc-before-gnulib) $(gnulib) + link-libc-tests = $(link-libc-tests-rpath-link) \ + $(link-libc-before-gnulib) $(gnulib-tests) + # This is how to find at build-time things that will be installed there. +-rpath-dirs = math elf dlfcn nss nis rt resolv crypt mathvec ++rpath-dirs = math elf dlfcn nss nis rt resolv crypt mathvec support + rpath-link = \ + $(common-objdir):$(subst $(empty) ,:,$(patsubst ../$(subdir),.,$(rpath-dirs:%=$(common-objpfx)%))) + else +@@ -850,7 +853,7 @@ libio-include = -I$(..)libio + # List of non-library modules that we build. + built-modules = iconvprogs iconvdata ldconfig lddlibc4 libmemusage \ + libSegFault libpcprofile librpcsvc locale-programs \ +- memusagestat nonlib nscd extramodules libnldbl ++ memusagestat nonlib nscd extramodules libnldbl libsupport + + in-module = $(subst -,_,$(firstword $(libof-$(basename $(@F))) \ + $(libof-$(<F)) \ +@@ -1089,6 +1092,12 @@ libm = $(common-objpfx)math/libm.a + libmvec = $(common-objpfx)mathvec/libmvec.a + endif + ++ifeq ($(build-shared),yes) ++libsupport = $(common-objpfx)support/libsupport_nonshared.a ++else ++libsupport = $(common-objpfx)support/libsupport.a ++endif ++ + # These are the subdirectories containing the library source. The order + # is more or less arbitrary. The sorting step will take care of the + # dependencies. +@@ -1096,7 +1105,7 @@ all-subdirs = csu assert ctype locale intl catgets math setjmp signal \ + stdlib stdio-common libio malloc string wcsmbs time dirent \ + grp pwd posix io termios resource misc socket sysvipc gmon \ + gnulib iconv iconvdata wctype manual shadow gshadow po argp \ +- crypt localedata timezone rt conform debug mathvec \ ++ crypt localedata timezone rt conform debug mathvec support \ + $(add-on-subdirs) dlfcn elf + + ifndef avoid-generated +diff --git a/NEWS b/NEWS +index b0447e7169..c4c082b415 100644 +--- a/NEWS ++++ b/NEWS +@@ -5,6 +5,29 @@ See the end for copying conditions. + Please send GNU C library bug reports via <http://sourceware.org/bugzilla/> + using `glibc' in the "product" field. + ++Version 2.24.1 ++ ++Security related changes: ++ ++* On ARM EABI (32-bit), generating a backtrace for execution contexts which ++ have been created with makecontext could fail to terminate due to a ++ missing .cantunwind annotation. This has been observed to lead to a hang ++ (denial of service) in some Go applications compiled with gccgo. Reported ++ by Andreas Schwab. (CVE-2016-6323) ++ ++* The DNS stub resolver functions would crash due to a NULL pointer ++ dereference when processing a query with a valid DNS question type which ++ was used internally in the implementation. The stub resolver now uses a ++ question type which is outside the range of valid question type values. ++ (CVE-2015-5180) ++ ++The following bugs are resolved with this release: ++ ++ [21209] Ignore and remove LD_HWCAP_MASK for AT_SECURE programs ++ [21289] Fix symbol redirect for fts_set ++ [21386] Assertion in fork for distinct parent PID is incorrect ++ [21624] Unsafe alloca allows local attackers to alias stack and heap (CVE-2017-1000366) ++ + Version 2.24 + + * The minimum Linux kernel version that this version of the GNU C Library +diff --git a/Rules b/Rules +index 8306d36a07..a981965d2b 100644 +--- a/Rules ++++ b/Rules +@@ -149,6 +149,7 @@ endif + + ifneq "$(strip $(binaries-shared-tests))" "" + $(addprefix $(objpfx),$(binaries-shared-tests)): %: %.o \ ++ $(link-extra-libs-tests) \ + $(sort $(filter $(common-objpfx)lib%,$(link-libc))) \ + $(addprefix $(csu-objpfx),start.o) $(+preinit) $(+postinit) + $(+link-tests) +@@ -156,6 +157,7 @@ endif + + ifneq "$(strip $(binaries-pie-tests))" "" + $(addprefix $(objpfx),$(binaries-pie-tests)): %: %.o \ ++ $(link-extra-libs-tests) \ + $(sort $(filter $(common-objpfx)lib%,$(link-libc))) \ + $(addprefix $(csu-objpfx),start.o) $(+preinit) $(+postinit) + $(+link-pie-tests) +@@ -177,6 +179,7 @@ endif + + ifneq "$(strip $(binaries-static-tests))" "" + $(addprefix $(objpfx),$(binaries-static-tests)): %: %.o \ ++ $(link-extra-libs-tests) \ + $(sort $(filter $(common-objpfx)lib%,$(link-libc-static-tests))) \ + $(addprefix $(csu-objpfx),start.o) $(+preinit) $(+postinit) + $(+link-static-tests) +diff --git a/argp/argp-fmtstream.h b/argp/argp-fmtstream.h +index bdeaa54dc2..e8c5797f38 100644 +--- a/argp/argp-fmtstream.h ++++ b/argp/argp-fmtstream.h +@@ -29,21 +29,6 @@ + #include <string.h> + #include <unistd.h> + +-#ifndef __attribute__ +-/* This feature is available in gcc versions 2.5 and later. */ +-# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 5) || \ +- defined __STRICT_ANSI__ +-# define __attribute__(Spec) /* empty */ +-# endif +-/* The __-protected variants of `format' and `printf' attributes +- are accepted by gcc versions 2.6.4 (effectively 2.7) and later. */ +-# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 7) || \ +- defined __STRICT_ANSI__ +-# define __format__ format +-# define __printf__ printf +-# endif +-#endif +- + #if defined (__GNU_LIBRARY__) && defined (HAVE_LINEWRAP_H) + /* line_wrap_stream is available, so use that. */ + #define ARGP_FMTSTREAM_USE_LINEWRAP +@@ -111,6 +96,8 @@ struct argp_fmtstream + + typedef struct argp_fmtstream *argp_fmtstream_t; + ++__BEGIN_DECLS ++ + /* Return an argp_fmtstream that outputs to STREAM, and which prefixes lines + written on it with LMARGIN spaces and limits them to RMARGIN columns + total. If WMARGIN >= 0, words that extend past RMARGIN are wrapped by +@@ -297,6 +284,8 @@ __argp_fmtstream_point (argp_fmtstream_t __fs) + + #endif /* __OPTIMIZE__ */ + ++__END_DECLS ++ + #endif /* ARGP_FMTSTREAM_USE_LINEWRAP */ + + #endif /* argp-fmtstream.h */ +diff --git a/argp/argp.h b/argp/argp.h +index e67bbef739..7cb5a69f08 100644 +--- a/argp/argp.h ++++ b/argp/argp.h +@@ -28,48 +28,12 @@ + #define __need_error_t + #include <errno.h> + +-#ifndef __THROW +-# define __THROW +-#endif +-#ifndef __NTH +-# define __NTH(fct) fct __THROW +-#endif +- +-#ifndef __attribute__ +-/* This feature is available in gcc versions 2.5 and later. */ +-# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 5) || \ +- defined __STRICT_ANSI__ +-# define __attribute__(Spec) /* empty */ +-# endif +-/* The __-protected variants of `format' and `printf' attributes +- are accepted by gcc versions 2.6.4 (effectively 2.7) and later. */ +-# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 7) || \ +- defined __STRICT_ANSI__ +-# define __format__ format +-# define __printf__ printf +-# endif +-#endif +- +-/* GCC 2.95 and later have "__restrict"; C99 compilers have +- "restrict", and "configure" may have defined "restrict". */ +-#ifndef __restrict +-# if ! (2 < __GNUC__ || (2 == __GNUC__ && 95 <= __GNUC_MINOR__)) +-# if defined restrict || 199901L <= __STDC_VERSION__ +-# define __restrict restrict +-# else +-# define __restrict +-# endif +-# endif +-#endif +- + #ifndef __error_t_defined + typedef int error_t; + # define __error_t_defined + #endif + +-#ifdef __cplusplus +-extern "C" { +-#endif ++__BEGIN_DECLS + + /* A description of a particular option. A pointer to an array of + these is passed in the OPTIONS field of an argp structure. Each option +@@ -590,8 +554,6 @@ __NTH (__option_is_end (const struct argp_option *__opt)) + # endif + #endif /* Use extern inlines. */ + +-#ifdef __cplusplus +-} +-#endif ++__END_DECLS + + #endif /* argp.h */ +diff --git a/configure b/configure +index 17625e1041..9b5a486048 100755 +--- a/configure ++++ b/configure +@@ -6289,12 +6289,14 @@ echo >&5 "libc_undefs='$libc_undefs'" + # symbols (resolved by the linker), so filter out unknown symbols. + # This will fail to produce the correct result if the compiler + # defaults to -fstack-protector but this produces an undefined symbol +-# other than __stack_chk_fail. However, compilers like that have not +-# been encountered in practice. +-libc_undefs=`echo "$libc_undefs" | egrep '^(foobar|__stack_chk_fail)$'` ++# other than __stack_chk_fail or __stack_chk_fail_local. However, ++# compilers like that have not been encountered in practice. ++libc_undefs=`echo "$libc_undefs" | \ ++ egrep '^(foobar|__stack_chk_fail|__stack_chk_fail_local)$'` + case "$libc_undefs" in + foobar) libc_cv_predef_stack_protector=no ;; + '__stack_chk_fail ++foobar'|'__stack_chk_fail_local + foobar') libc_cv_predef_stack_protector=yes ;; + *) as_fn_error $? "unexpected symbols in test: $libc_undefs" "$LINENO" 5 ;; + esac +diff --git a/configure.ac b/configure.ac +index 33bcd62180..8277d9f727 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -1626,12 +1626,14 @@ echo >&AS_MESSAGE_LOG_FD "libc_undefs='$libc_undefs'" + # symbols (resolved by the linker), so filter out unknown symbols. + # This will fail to produce the correct result if the compiler + # defaults to -fstack-protector but this produces an undefined symbol +-# other than __stack_chk_fail. However, compilers like that have not +-# been encountered in practice. +-libc_undefs=`echo "$libc_undefs" | egrep '^(foobar|__stack_chk_fail)$'` ++# other than __stack_chk_fail or __stack_chk_fail_local. However, ++# compilers like that have not been encountered in practice. ++libc_undefs=`echo "$libc_undefs" | \ ++ egrep '^(foobar|__stack_chk_fail|__stack_chk_fail_local)$'` + case "$libc_undefs" in + foobar) libc_cv_predef_stack_protector=no ;; + '__stack_chk_fail ++foobar'|'__stack_chk_fail_local + foobar') libc_cv_predef_stack_protector=yes ;; + *) AC_MSG_ERROR([unexpected symbols in test: $libc_undefs]) ;; + esac], +diff --git a/conform/Makefile b/conform/Makefile +index 32a0937b06..762aac98fc 100644 +--- a/conform/Makefile ++++ b/conform/Makefile +@@ -229,6 +229,7 @@ $(linknamespace-symlist-stdlibs-tests): $(objpfx)symlist-stdlibs-%: \ + + $(linknamespace-header-tests): $(objpfx)%/linknamespace.out: \ + linknamespace.pl \ ++ $(linknamespace-symlists-tests) \ + $(linknamespace-symlist-stdlibs-tests) + (set -e; std_hdr=$*; std=$${std_hdr%%/*}; hdr=$${std_hdr#*/}; \ + mkdir -p $(@D)/scratch; \ +diff --git a/elf/Makefile b/elf/Makefile +index 593403c640..847a012f84 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -149,7 +149,8 @@ tests += loadtest restest1 preloadtest loadfail multiload origtest resolvfail \ + tst-nodelete) \ + tst-initorder tst-initorder2 tst-relsort1 tst-null-argv \ + tst-ptrguard1 tst-tlsalign tst-tlsalign-extern tst-nodelete-opened \ +- tst-nodelete2 tst-audit11 tst-audit12 tst-dlsym-error ++ tst-nodelete2 tst-audit11 tst-audit12 tst-dlsym-error \ ++ tst-nodelete-dlclose + # reldep9 + ifeq ($(build-hardcoded-path-in-tests),yes) + tests += tst-dlopen-aout +@@ -223,7 +224,8 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \ + tst-array5dep tst-null-argv-lib \ + tst-tlsalign-lib tst-nodelete-opened-lib tst-nodelete2mod \ + tst-audit11mod1 tst-audit11mod2 tst-auditmod11 \ +- tst-audit12mod1 tst-audit12mod2 tst-audit12mod3 tst-auditmod12 ++ tst-audit12mod1 tst-audit12mod2 tst-audit12mod3 tst-auditmod12 \ ++ tst-nodelete-dlclose-dso tst-nodelete-dlclose-plugin + ifeq (yes,$(have-mtls-dialect-gnu2)) + tests += tst-gnu2-tls1 + modules-names += tst-gnu2-tls1mod +@@ -1267,3 +1269,12 @@ $(objpfx)tst-ldconfig-X.out : tst-ldconfig-X.sh $(objpfx)ldconfig + $(evaluate-test) + + $(objpfx)tst-dlsym-error: $(libdl) ++ ++# The application depends on the DSO, and the DSO loads the plugin. ++# The plugin also depends on the DSO. This creates the circular ++# dependency via dlopen that we're testing to make sure works. ++$(objpfx)tst-nodelete-dlclose-dso.so: $(libdl) ++$(objpfx)tst-nodelete-dlclose-plugin.so: $(objpfx)tst-nodelete-dlclose-dso.so ++$(objpfx)tst-nodelete-dlclose: $(objpfx)tst-nodelete-dlclose-dso.so ++$(objpfx)tst-nodelete-dlclose.out: $(objpfx)tst-nodelete-dlclose-dso.so \ ++ $(objpfx)tst-nodelete-dlclose-plugin.so +diff --git a/elf/dl-close.c b/elf/dl-close.c +index 687d7de874..9f93ab7628 100644 +--- a/elf/dl-close.c ++++ b/elf/dl-close.c +@@ -805,19 +805,37 @@ _dl_close (void *_map) + { + struct link_map *map = _map; + +- /* First see whether we can remove the object at all. */ ++ /* We must take the lock to examine the contents of map and avoid ++ concurrent dlopens. */ ++ __rtld_lock_lock_recursive (GL(dl_load_lock)); ++ ++ /* At this point we are guaranteed nobody else is touching the list of ++ loaded maps, but a concurrent dlclose might have freed our map ++ before we took the lock. There is no way to detect this (see below) ++ so we proceed assuming this isn't the case. First see whether we ++ can remove the object at all. */ + if (__glibc_unlikely (map->l_flags_1 & DF_1_NODELETE)) + { +- assert (map->l_init_called); + /* Nope. Do nothing. */ ++ __rtld_lock_unlock_recursive (GL(dl_load_lock)); + return; + } + ++ /* At present this is an unreliable check except in the case where the ++ caller has recursively called dlclose and we are sure the link map ++ has not been freed. In a non-recursive dlclose the map itself ++ might have been freed and this access is potentially a data race ++ with whatever other use this memory might have now, or worse we ++ might silently corrupt memory if it looks enough like a link map. ++ POSIX has language in dlclose that appears to guarantee that this ++ should be a detectable case and given that dlclose should be threadsafe ++ we need this to be a reliable detection. ++ This is bug 20990. */ + if (__builtin_expect (map->l_direct_opencount, 1) == 0) +- GLRO(dl_signal_error) (0, map->l_name, NULL, N_("shared object not open")); +- +- /* Acquire the lock. */ +- __rtld_lock_lock_recursive (GL(dl_load_lock)); ++ { ++ __rtld_lock_unlock_recursive (GL(dl_load_lock)); ++ _dl_signal_error (0, map->l_name, NULL, N_("shared object not open")); ++ } + + _dl_close_worker (map, false); + +diff --git a/elf/rtld.c b/elf/rtld.c +index 647661ca45..8f56d6edd3 100644 +--- a/elf/rtld.c ++++ b/elf/rtld.c +@@ -99,14 +99,121 @@ uintptr_t __pointer_chk_guard_local + strong_alias (__pointer_chk_guard_local, __pointer_chk_guard) + #endif + ++/* Length limits for names and paths, to protect the dynamic linker, ++ particularly when __libc_enable_secure is active. */ ++#ifdef NAME_MAX ++# define SECURE_NAME_LIMIT NAME_MAX ++#else ++# define SECURE_NAME_LIMIT 255 ++#endif ++#ifdef PATH_MAX ++# define SECURE_PATH_LIMIT PATH_MAX ++#else ++# define SECURE_PATH_LIMIT 1024 ++#endif ++ ++/* Check that AT_SECURE=0, or that the passed name does not contain ++ directories and is not overly long. Reject empty names ++ unconditionally. */ ++static bool ++dso_name_valid_for_suid (const char *p) ++{ ++ if (__glibc_unlikely (__libc_enable_secure)) ++ { ++ /* Ignore pathnames with directories for AT_SECURE=1 ++ programs, and also skip overlong names. */ ++ size_t len = strlen (p); ++ if (len >= SECURE_NAME_LIMIT || memchr (p, '/', len) != NULL) ++ return false; ++ } ++ return *p != '\0'; ++} + +-/* List of auditing DSOs. */ ++/* LD_AUDIT variable contents. Must be processed before the ++ audit_list below. */ ++const char *audit_list_string; ++ ++/* Cyclic list of auditing DSOs. audit_list->next is the first ++ element. */ + static struct audit_list + { + const char *name; + struct audit_list *next; + } *audit_list; + ++/* Iterator for audit_list_string followed by audit_list. */ ++struct audit_list_iter ++{ ++ /* Tail of audit_list_string still needing processing, or NULL. */ ++ const char *audit_list_tail; ++ ++ /* The list element returned in the previous iteration. NULL before ++ the first element. */ ++ struct audit_list *previous; ++ ++ /* Scratch buffer for returning a name which is part of ++ audit_list_string. */ ++ char fname[SECURE_NAME_LIMIT]; ++}; ++ ++/* Initialize an audit list iterator. */ ++static void ++audit_list_iter_init (struct audit_list_iter *iter) ++{ ++ iter->audit_list_tail = audit_list_string; ++ iter->previous = NULL; ++} ++ ++/* Iterate through both audit_list_string and audit_list. */ ++static const char * ++audit_list_iter_next (struct audit_list_iter *iter) ++{ ++ if (iter->audit_list_tail != NULL) ++ { ++ /* First iterate over audit_list_string. */ ++ while (*iter->audit_list_tail != '\0') ++ { ++ /* Split audit list at colon. */ ++ size_t len = strcspn (iter->audit_list_tail, ":"); ++ if (len > 0 && len < sizeof (iter->fname)) ++ { ++ memcpy (iter->fname, iter->audit_list_tail, len); ++ iter->fname[len] = '\0'; ++ } ++ else ++ /* Do not return this name to the caller. */ ++ iter->fname[0] = '\0'; ++ ++ /* Skip over the substring and the following delimiter. */ ++ iter->audit_list_tail += len; ++ if (*iter->audit_list_tail == ':') ++ ++iter->audit_list_tail; ++ ++ /* If the name is valid, return it. */ ++ if (dso_name_valid_for_suid (iter->fname)) ++ return iter->fname; ++ /* Otherwise, wrap around and try the next name. */ ++ } ++ /* Fall through to the procesing of audit_list. */ ++ } ++ ++ if (iter->previous == NULL) ++ { ++ if (audit_list == NULL) ++ /* No pre-parsed audit list. */ ++ return NULL; ++ /* Start of audit list. The first list element is at ++ audit_list->next (cyclic list). */ ++ iter->previous = audit_list->next; ++ return iter->previous->name; ++ } ++ if (iter->previous == audit_list) ++ /* Cyclic list wrap-around. */ ++ return NULL; ++ iter->previous = iter->previous->next; ++ return iter->previous->name; ++} ++ + #ifndef HAVE_INLINED_SYSCALLS + /* Set nonzero during loading and initialization of executable and + libraries, cleared before the executable's entry point runs. This +@@ -730,6 +837,42 @@ static const char *preloadlist attribute_relro; + /* Nonzero if information about versions has to be printed. */ + static int version_info attribute_relro; + ++/* The LD_PRELOAD environment variable gives list of libraries ++ separated by white space or colons that are loaded before the ++ executable's dependencies and prepended to the global scope list. ++ (If the binary is running setuid all elements containing a '/' are ++ ignored since it is insecure.) Return the number of preloads ++ performed. */ ++unsigned int ++handle_ld_preload (const char *preloadlist, struct link_map *main_map) ++{ ++ unsigned int npreloads = 0; ++ const char *p = preloadlist; ++ char fname[SECURE_PATH_LIMIT]; ++ ++ while (*p != '\0') ++ { ++ /* Split preload list at space/colon. */ ++ size_t len = strcspn (p, " :"); ++ if (len > 0 && len < sizeof (fname)) ++ { ++ memcpy (fname, p, len); ++ fname[len] = '\0'; ++ } ++ else ++ fname[0] = '\0'; ++ ++ /* Skip over the substring and the following delimiter. */ ++ p += len; ++ if (*p != '\0') ++ ++p; ++ ++ if (dso_name_valid_for_suid (fname)) ++ npreloads += do_preload (fname, main_map, "LD_PRELOAD"); ++ } ++ return npreloads; ++} ++ + static void + dl_main (const ElfW(Phdr) *phdr, + ElfW(Word) phnum, +@@ -1257,11 +1400,13 @@ of this helper program; chances are you did not intend to run this program.\n\ + GL(dl_rtld_map).l_tls_modid = _dl_next_tls_modid (); + + /* If we have auditing DSOs to load, do it now. */ +- if (__glibc_unlikely (audit_list != NULL)) ++ bool need_security_init = true; ++ if (__glibc_unlikely (audit_list != NULL) ++ || __glibc_unlikely (audit_list_string != NULL)) + { +- /* Iterate over all entries in the list. The order is important. */ + struct audit_ifaces *last_audit = NULL; +- struct audit_list *al = audit_list->next; ++ struct audit_list_iter al_iter; ++ audit_list_iter_init (&al_iter); + + /* Since we start using the auditing DSOs right away we need to + initialize the data structures now. */ +@@ -1272,9 +1417,14 @@ of this helper program; chances are you did not intend to run this program.\n\ + use different values (especially the pointer guard) and will + fail later on. */ + security_init (); ++ need_security_init = false; + +- do ++ while (true) + { ++ const char *name = audit_list_iter_next (&al_iter); ++ if (name == NULL) ++ break; ++ + int tls_idx = GL(dl_tls_max_dtv_idx); + + /* Now it is time to determine the layout of the static TLS +@@ -1283,7 +1433,7 @@ of this helper program; chances are you did not intend to run this program.\n\ + no DF_STATIC_TLS bit is set. The reason is that we know + glibc will use the static model. */ + struct dlmopen_args dlmargs; +- dlmargs.fname = al->name; ++ dlmargs.fname = name; + dlmargs.map = NULL; + + const char *objname; +@@ -1296,7 +1446,7 @@ of this helper program; chances are you did not intend to run this program.\n\ + not_loaded: + _dl_error_printf ("\ + ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n", +- al->name, err_str); ++ name, err_str); + if (malloced) + free ((char *) err_str); + } +@@ -1400,10 +1550,7 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n", + goto not_loaded; + } + } +- +- al = al->next; + } +- while (al != audit_list->next); + + /* If we have any auditing modules, announce that we already + have two objects loaded. */ +@@ -1481,23 +1628,8 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n", + + if (__glibc_unlikely (preloadlist != NULL)) + { +- /* The LD_PRELOAD environment variable gives list of libraries +- separated by white space or colons that are loaded before the +- executable's dependencies and prepended to the global scope +- list. If the binary is running setuid all elements +- containing a '/' are ignored since it is insecure. */ +- char *list = strdupa (preloadlist); +- char *p; +- + HP_TIMING_NOW (start); +- +- /* Prevent optimizing strsep. Speed is not important here. */ +- while ((p = (strsep) (&list, " :")) != NULL) +- if (p[0] != '\0' +- && (__builtin_expect (! __libc_enable_secure, 1) +- || strchr (p, '/') == NULL)) +- npreloads += do_preload (p, main_map, "LD_PRELOAD"); +- ++ npreloads += handle_ld_preload (preloadlist, main_map); + HP_TIMING_NOW (stop); + HP_TIMING_DIFF (diff, start, stop); + HP_TIMING_ACCUM_NT (load_time, diff); +@@ -1682,7 +1814,7 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n", + if (tcbp == NULL) + tcbp = init_tls (); + +- if (__glibc_likely (audit_list == NULL)) ++ if (__glibc_likely (need_security_init)) + /* Initialize security features. But only if we have not done it + earlier. */ + security_init (); +@@ -2313,9 +2445,7 @@ process_dl_audit (char *str) + char *p; + + while ((p = (strsep) (&str, ":")) != NULL) +- if (p[0] != '\0' +- && (__builtin_expect (! __libc_enable_secure, 1) +- || strchr (p, '/') == NULL)) ++ if (dso_name_valid_for_suid (p)) + { + /* This is using the local malloc, not the system malloc. The + memory can never be freed. */ +@@ -2379,7 +2509,7 @@ process_envvars (enum mode *modep) + break; + } + if (memcmp (envline, "AUDIT", 5) == 0) +- process_dl_audit (&envline[6]); ++ audit_list_string = &envline[6]; + break; + + case 7: +@@ -2423,7 +2553,8 @@ process_envvars (enum mode *modep) + + case 10: + /* Mask for the important hardware capabilities. */ +- if (memcmp (envline, "HWCAP_MASK", 10) == 0) ++ if (!__libc_enable_secure ++ && memcmp (envline, "HWCAP_MASK", 10) == 0) + GLRO(dl_hwcap_mask) = __strtoul_internal (&envline[11], NULL, + 0, 0); + break; +@@ -2437,7 +2568,8 @@ process_envvars (enum mode *modep) + + case 12: + /* The library search path. */ +- if (memcmp (envline, "LIBRARY_PATH", 12) == 0) ++ if (!__libc_enable_secure ++ && memcmp (envline, "LIBRARY_PATH", 12) == 0) + { + library_path = &envline[13]; + break; +diff --git a/elf/tst-nodelete-dlclose-dso.c b/elf/tst-nodelete-dlclose-dso.c +new file mode 100644 +index 0000000000..dd930f99cc +--- /dev/null ++++ b/elf/tst-nodelete-dlclose-dso.c +@@ -0,0 +1,90 @@ ++/* Bug 11941: Improper assert map->l_init_called in dlclose. ++ Copyright (C) 2016 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++/* This is the primary DSO that is loaded by the appliation. This DSO ++ then loads a plugin with RTLD_NODELETE. This plugin depends on this ++ DSO. This dependency chain means that at application shutdown the ++ plugin will be destructed first. Thus by the time this DSO is ++ destructed we will be calling dlclose on an object that has already ++ been destructed. It is allowed to call dlclose in this way and ++ should not assert. */ ++#include <stdio.h> ++#include <stdlib.h> ++#include <dlfcn.h> ++ ++/* Plugin to load. */ ++static void *plugin_lib = NULL; ++/* Plugin function. */ ++static void (*plugin_func) (void); ++#define LIB_PLUGIN "tst-nodelete-dlclose-plugin.so" ++ ++/* This function is never called but the plugin references it. ++ We do this to avoid any future --as-needed from removing the ++ plugin's DT_NEEDED on this DSO (required for the test). */ ++void ++primary_reference (void) ++{ ++ printf ("INFO: Called primary_reference function.\n"); ++} ++ ++void ++primary (void) ++{ ++ char *error; ++ ++ plugin_lib = dlopen (LIB_PLUGIN, RTLD_NOW | RTLD_LOCAL | RTLD_NODELETE); ++ if (plugin_lib == NULL) ++ { ++ printf ("ERROR: Unable to load plugin library.\n"); ++ exit (EXIT_FAILURE); ++ } ++ dlerror (); ++ ++ plugin_func = (void (*) (void)) dlsym (plugin_lib, "plugin_func"); ++ error = dlerror (); ++ if (error != NULL) ++ { ++ printf ("ERROR: Unable to find symbol with error \"%s\".", ++ error); ++ exit (EXIT_FAILURE); ++ } ++ ++ return; ++} ++ ++__attribute__ ((destructor)) ++static void ++primary_dtor (void) ++{ ++ int ret; ++ ++ printf ("INFO: Calling primary destructor.\n"); ++ ++ /* The destructor runs in the test driver also, which ++ hasn't called primary, in that case do nothing. */ ++ if (plugin_lib == NULL) ++ return; ++ ++ ret = dlclose (plugin_lib); ++ if (ret != 0) ++ { ++ printf ("ERROR: Calling dlclose failed with \"%s\"\n", ++ dlerror ()); ++ exit (EXIT_FAILURE); ++ } ++} +diff --git a/elf/tst-nodelete-dlclose-plugin.c b/elf/tst-nodelete-dlclose-plugin.c +new file mode 100644 +index 0000000000..8b295c1718 +--- /dev/null ++++ b/elf/tst-nodelete-dlclose-plugin.c +@@ -0,0 +1,40 @@ ++/* Bug 11941: Improper assert map->l_init_called in dlclose. ++ Copyright (C) 2016 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++/* This DSO simulates a plugin with a dependency on the ++ primary DSO loaded by the appliation. */ ++#include <stdio.h> ++ ++extern void primary_reference (void); ++ ++void ++plugin_func (void) ++{ ++ printf ("INFO: Calling plugin function.\n"); ++ /* Need a reference to the DSO to ensure that a potential --as-needed ++ doesn't remove the DT_NEEDED entry which we rely upon to ensure ++ destruction ordering. */ ++ primary_reference (); ++} ++ ++__attribute__ ((destructor)) ++static void ++plugin_dtor (void) ++{ ++ printf ("INFO: Calling plugin destructor.\n"); ++} +diff --git a/elf/tst-nodelete-dlclose.c b/elf/tst-nodelete-dlclose.c +new file mode 100644 +index 0000000000..b3d07e1849 +--- /dev/null ++++ b/elf/tst-nodelete-dlclose.c +@@ -0,0 +1,36 @@ ++/* Bug 11941: Improper assert map->l_init_called in dlclose. ++ Copyright (C) 2016 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++/* This simulates an application using the primary DSO which loads the ++ plugin DSO. */ ++#include <stdio.h> ++#include <stdlib.h> ++ ++extern void primary (void); ++ ++static int ++do_test (void) ++{ ++ printf ("INFO: Starting application.\n"); ++ primary (); ++ printf ("INFO: Exiting application.\n"); ++ return 0; ++} ++ ++#define TEST_FUNCTION do_test () ++#include "../test-skeleton.c" +diff --git a/extra-lib.mk b/extra-lib.mk +index b10748d185..2552049135 100644 +--- a/extra-lib.mk ++++ b/extra-lib.mk +@@ -5,6 +5,9 @@ + # The variable $($(lib)-routines) defines the list of modules + # to be included in that library. A sysdep Makefile can add to + # $(lib)-sysdep_routines to include additional modules. ++# ++# Libraries listed in $(extra-libs-noinstall) are built, but not ++# installed. + + lib := $(firstword $(extra-libs-left)) + extra-libs-left := $(filter-out $(lib),$(extra-libs-left)) +@@ -28,7 +31,9 @@ extra-objs := $(extra-objs) + all-$(lib)-routines := $($(lib)-routines) $($(lib)-sysdep_routines) + + # Add each flavor of library to the lists of things to build and install. ++ifeq (,$(filter $(lib), $(extra-libs-noinstall))) + install-lib += $(foreach o,$(object-suffixes-$(lib)),$(lib:lib%=$(libtype$o))) ++endif + extra-objs += $(foreach o,$(filter-out .os .oS,$(object-suffixes-$(lib))),\ + $(patsubst %,%$o,$(filter-out \ + $($(lib)-shared-only-routines),\ +diff --git a/iconv/gconv.h b/iconv/gconv.h +index 8d8ce5813b..a87028047b 100644 +--- a/iconv/gconv.h ++++ b/iconv/gconv.h +@@ -139,7 +139,7 @@ typedef struct __gconv_info + { + size_t __nsteps; + struct __gconv_step *__steps; +- __extension__ struct __gconv_step_data __data __flexarr; ++ __extension__ struct __gconv_step_data __data[0]; + } *__gconv_t; + + /* Transliteration using the locale's data. */ +diff --git a/include/arpa/nameser_compat.h b/include/arpa/nameser_compat.h +index 2e735ede4c..7c0deed9ae 100644 +--- a/include/arpa/nameser_compat.h ++++ b/include/arpa/nameser_compat.h +@@ -1,8 +1,8 @@ + #ifndef _ARPA_NAMESER_COMPAT_ + #include <resolv/arpa/nameser_compat.h> + +-/* Picksome unused number to represent lookups of IPv4 and IPv6 (i.e., +- T_A and T_AAAA). */ +-#define T_UNSPEC 62321 ++/* The number is outside the 16-bit RR type range and is used ++ internally by the implementation. */ ++#define T_QUERY_A_AND_AAAA 439963904 + + #endif +diff --git a/io/fts.h b/io/fts.h +index 127a0d2721..b6b45206c8 100644 +--- a/io/fts.h ++++ b/io/fts.h +@@ -193,7 +193,7 @@ FTS *__REDIRECT (fts_open, (char * const *, int, + int (*)(const FTSENT **, const FTSENT **)), + fts64_open); + FTSENT *__REDIRECT (fts_read, (FTS *), fts64_read); +-int __REDIRECT (fts_set, (FTS *, FTSENT *, int), fts64_set) __THROW; ++int __REDIRECT_NTH (fts_set, (FTS *, FTSENT *, int), fts64_set); + # else + # define fts_children fts64_children + # define fts_close fts64_close +diff --git a/localedata/ChangeLog b/localedata/ChangeLog +index 4be8afc110..a7688e3df6 100644 +--- a/localedata/ChangeLog ++++ b/localedata/ChangeLog +@@ -1,3 +1,17 @@ ++2017-06-11 Santhosh Thottingal <santhosh.thottingal@gmail.com> ++ ++ [BZ #19922] ++ * locales/iso14651_t1_common: Add collation rules for U+07DA to U+07DF. ++ ++ [BZ #19919] ++ * locales/iso14651_t1_common: Correct collation of U+0D36 and U+0D37. ++ ++2016-12-30 Mike Frysinger <vapier@gentoo.org> ++ ++ [BZ #20974] ++ * localedata/bs_BA (LC_MESSAGES): Delete "*." from the end of ++ yesexpr and noexpr. ++ + 2016-07-07 Aurelien Jarno <aurelien@aurel32.net> + + * locales/de_LI (postal_fmt): Fix indentation. +diff --git a/localedata/locales/bs_BA b/localedata/locales/bs_BA +index a47f87eb37..68c2f9471a 100644 +--- a/localedata/locales/bs_BA ++++ b/localedata/locales/bs_BA +@@ -148,8 +148,8 @@ copy "en_DK" + END LC_CTYPE + + LC_MESSAGES +-yesexpr "<U005E><U005B><U002B><U0031><U0064><U0044><U0079><U0059><U005D><U002A><U002E>" +-noexpr "<U005E><U005B><U002D><U0030><U006E><U004E><U005D><U002A><U002E>" ++yesexpr "<U005E><U005B><U002B><U0031><U0064><U0044><U0079><U0059><U005D>" ++noexpr "<U005E><U005B><U002D><U0030><U006E><U004E><U005D>" + yesstr "<U0064><U0061>" + nostr "<U006E><U0065>" + END LC_MESSAGES +diff --git a/localedata/locales/iso14651_t1_common b/localedata/locales/iso14651_t1_common +index eef75ba65e..0e64f26a12 100644 +--- a/localedata/locales/iso14651_t1_common ++++ b/localedata/locales/iso14651_t1_common +@@ -1042,9 +1042,9 @@ collating-element <ml-bh> from "<U0D2D><U0D4D>" + collating-element <ml-m> from "<U0D2E><U0D4D>" + collating-element <ml-y> from "<U0D2F><U0D4D>" + collating-element <ml-v> from "<U0D35><U0D4D>" +-collating-element <ml-s> from "<U0D38><U0D4D>" + collating-element <ml-ss> from "<U0D36><U0D4D>" + collating-element <ml-sh> from "<U0D37><U0D4D>" ++collating-element <ml-s> from "<U0D38><U0D4D>" + collating-element <ml-h> from "<U0D39><U0D4D>" + collating-element <ml-zh> from "<U0D34><U0D4D>" + collating-element <ml-rr> from "<U0D31><U0D4D>" +@@ -1103,8 +1103,8 @@ collating-symbol <ml-rra> + collating-symbol <ml-la> + collating-symbol <ml-lla> + collating-symbol <ml-va> +-collating-symbol <ml-sha> + collating-symbol <ml-ssa> ++collating-symbol <ml-sha> + collating-symbol <ml-sa> + collating-symbol <ml-ha> + collating-symbol <ml-avagrah> +@@ -1126,6 +1126,12 @@ collating-symbol <mlvs-o> + collating-symbol <mlvs-au> + collating-symbol <ml-visarga> + collating-symbol <ml-virama> ++collating-symbol <ml-atomic-chillu-k> ++collating-symbol <ml-atomic-chillu-n> ++collating-symbol <ml-atomic-chillu-nn> ++collating-symbol <ml-atomic-chillu-l> ++collating-symbol <ml-atomic-chillu-ll> ++collating-symbol <ml-atomic-chillu-r> + # + # <BENGALI> + # +@@ -4552,6 +4558,12 @@ collating-symbol <TIB-subA> + <mlvs-o> + <mlvs-au> + <ml-visarga> ++<ml-atomic-chillu-k> ++<ml-atomic-chillu-n> ++<ml-atomic-chillu-nn> ++<ml-atomic-chillu-l> ++<ml-atomic-chillu-ll> ++<ml-atomic-chillu-r> + # + # <BENGALI> + # +@@ -7252,6 +7264,7 @@ order_start <MALAYALAM>;forward;forward;forward;forward,position + <U0D13> <mlvw-o>;<BAS>;<MIN>;IGNORE + <U0D14> <mlvw-au>;<BAS>;<MIN>;IGNORE + <ml-chillu-k> "<ml-ka><ml-virama>";<BAS>;<MIN>;IGNORE ++<U0D7F> "<ml-ka><ml-virama>";<ml-atomic-chillu-k>;<MIN>;IGNORE + <U0D15> "<ml-ka><ml-virama><mlvw-shorta>";<BAS>;<MIN>;IGNORE + <ml-kh> "<ml-kha><ml-virama>";<BAS>;<MIN>;IGNORE + <U0D16> "<ml-kha><ml-virama><mlvw-shorta>";<BAS>;<MIN>;IGNORE +@@ -7280,6 +7293,7 @@ order_start <MALAYALAM>;forward;forward;forward;forward,position + <ml-dh> "<ml-dha><ml-virama>";<BAS>;<MIN>;IGNORE + <U0D22> "<ml-dha><ml-virama><mlvw-shorta>";<BAS>;<MIN>;IGNORE + <ml-chillu-nn> "<ml-nna><ml-virama>";<BAS>;<MIN>;IGNORE # ണ് = ണ + ് + zwj ++<U0D7A> "<ml-nna><ml-virama>";<ml-atomic-chillu-nn>;<MIN>;IGNORE + <U0D23> "<ml-nna><ml-virama><mlvw-shorta>";<BAS>;<MIN>;IGNORE # ണ = ണ + ് + അ + <ml-th> "<ml-tha><ml-virama>";<BAS>;<MIN>;IGNORE + <U0D24> "<ml-tha><ml-virama><mlvw-shorta>";<BAS>;<MIN>;IGNORE +@@ -7290,6 +7304,7 @@ order_start <MALAYALAM>;forward;forward;forward;forward,position + <ml-ddh> "<ml-ddha><ml-virama>";<BAS>;<MIN>;IGNORE + <U0D27> "<ml-ddha><ml-virama><mlvw-shorta>";<BAS>;<MIN>;IGNORE + <ml-chillu-n> "<ml-na><ml-virama>";<BAS>;<MIN>;IGNORE # ന്= ന + ് + zwj ++<U0D7B> "<ml-na><ml-virama>";<ml-atomic-chillu-n>;<MIN>;IGNORE + <U0D28> "<ml-na><ml-virama><mlvw-shorta>";<BAS>;<MIN>;IGNORE #ന = ന + ് + അ + <ml-p> "<ml-pa><ml-virama>";<BAS>;<MIN>;IGNORE + <U0D2A> "<ml-pa><ml-virama><mlvw-shorta>";<BAS>;<MIN>;IGNORE +@@ -7305,20 +7320,23 @@ order_start <MALAYALAM>;forward;forward;forward;forward,position + <ml-y> "<ml-ya><ml-virama>";<BAS>;<MIN>;IGNORE + <U0D2F> "<ml-ya><ml-virama><mlvw-shorta>";<BAS>;<MIN>;IGNORE + <ml-chillu-r> "<ml-ra><ml-virama>";<BAS>;<MIN>;IGNORE # ര = ര + ് + zwj ++<U0D7C> "<ml-ra><ml-virama>";<ml-atomic-chillu-r>;<MIN>;IGNORE + <U0D30> "<ml-ra><ml-virama><mlvw-shorta>";<BAS>;<MIN>;IGNORE # ര = ര + ് + അ + <ml-chillu-l> <ml-la>;<BAS>;<MIN>;IGNORE # ല് = ല + ് + zwj ++<U0D7D> "<ml-la><ml-virama>";<ml-atomic-chillu-l>;<MIN>;IGNORE + <U0D32> "<ml-la><ml-virama><mlvw-shorta>";<BAS>;<MIN>;IGNORE # ല = ല + ് + അ + <ml-v> "<ml-va><ml-virama>";<BAS>;<MIN>;IGNORE + <U0D35> "<ml-va><ml-virama><mlvw-shorta>";<BAS>;<MIN>;IGNORE + <ml-ss> "<ml-ssa><ml-virama>";<BAS>;<MIN>;IGNORE +-<U0D37> "<ml-ssa><ml-virama><mlvw-shorta>";<BAS>;<MIN>;IGNORE ++<U0D36> "<ml-ssa><ml-virama><mlvw-shorta>";<BAS>;<MIN>;IGNORE + <ml-sh> "<ml-sha><ml-virama>";<BAS>;<MIN>;IGNORE +-<U0D36> "<ml-sha><ml-virama><mlvw-shorta>";<BAS>;<MIN>;IGNORE ++<U0D37> "<ml-sha><ml-virama><mlvw-shorta>";<BAS>;<MIN>;IGNORE + <ml-s> "<ml-sa><ml-virama>";<BAS>;<MIN>;IGNORE + <U0D38> "<ml-sa><ml-virama><mlvw-shorta>";<BAS>;<MIN>;IGNORE + <ml-h> "<ml-ha><ml-virama>";<BAS>;<MIN>;IGNORE + <U0D39> "<ml-ha><ml-virama><mlvw-shorta>";<BAS>;<MIN>;IGNORE + <ml-chillu-ll> "<ml-lla><ml-virama>";<BAS>;<MIN>;IGNORE # ള് = ള + ് + zwj ++<U0D7E> "<ml-lla><ml-virama>";<ml-atomic-chillu-ll>;<MIN>;IGNORE + <U0D33> "<ml-lla><ml-virama><mlvw-shorta>";<BAS>;<MIN>;IGNORE # ള = ള + ് + അ + <ml-zh> "<ml-zha><ml-virama>";<BAS>;<MIN>;IGNORE + <U0D34> "<ml-zha><ml-virama><mlvw-shorta>";<BAS>;<MIN>;IGNORE +diff --git a/malloc/arena.c b/malloc/arena.c +index 229783f3b7..4e16593d8b 100644 +--- a/malloc/arena.c ++++ b/malloc/arena.c +@@ -702,8 +702,7 @@ _int_new_arena (size_t size) + } + + +-/* Remove an arena from free_list. The arena may be in use because it +- was attached concurrently to a thread by reused_arena below. */ ++/* Remove an arena from free_list. */ + static mstate + get_free_list (void) + { +@@ -718,7 +717,8 @@ get_free_list (void) + free_list = result->next_free; + + /* The arena will be attached to this thread. */ +- ++result->attached_threads; ++ assert (result->attached_threads == 0); ++ result->attached_threads = 1; + + detach_arena (replaced_arena); + } +@@ -735,6 +735,26 @@ get_free_list (void) + return result; + } + ++/* Remove the arena from the free list (if it is present). ++ free_list_lock must have been acquired by the caller. */ ++static void ++remove_from_free_list (mstate arena) ++{ ++ mstate *previous = &free_list; ++ for (mstate p = free_list; p != NULL; p = p->next_free) ++ { ++ assert (p->attached_threads == 0); ++ if (p == arena) ++ { ++ /* Remove the requested arena from the list. */ ++ *previous = p->next_free; ++ break; ++ } ++ else ++ previous = &p->next_free; ++ } ++} ++ + /* Lock and return an arena that can be reused for memory allocation. + Avoid AVOID_ARENA as we have already failed to allocate memory in + it and it is currently locked. */ +@@ -782,14 +802,25 @@ reused_arena (mstate avoid_arena) + (void) mutex_lock (&result->mutex); + + out: +- /* Attach the arena to the current thread. Note that we may have +- selected an arena which was on free_list. */ ++ /* Attach the arena to the current thread. */ + { + /* Update the arena thread attachment counters. */ + mstate replaced_arena = thread_arena; + (void) mutex_lock (&free_list_lock); + detach_arena (replaced_arena); ++ ++ /* We may have picked up an arena on the free list. We need to ++ preserve the invariant that no arena on the free list has a ++ positive attached_threads counter (otherwise, ++ arena_thread_freeres cannot use the counter to determine if the ++ arena needs to be put on the free list). We unconditionally ++ remove the selected arena from the free list. The caller of ++ reused_arena checked the free list and observed it to be empty, ++ so the list is very short. */ ++ remove_from_free_list (result); ++ + ++result->attached_threads; ++ + (void) mutex_unlock (&free_list_lock); + } + +diff --git a/nptl/Makefile b/nptl/Makefile +index 0d8aadebed..fa925819ca 100644 +--- a/nptl/Makefile ++++ b/nptl/Makefile +@@ -268,7 +268,7 @@ tests = tst-typesizes \ + tst-flock1 tst-flock2 \ + tst-signal1 tst-signal2 tst-signal3 tst-signal4 tst-signal5 \ + tst-signal6 tst-signal7 \ +- tst-exec1 tst-exec2 tst-exec3 tst-exec4 \ ++ tst-exec1 tst-exec2 tst-exec3 tst-exec4 tst-exec5 \ + tst-exit1 tst-exit2 tst-exit3 \ + tst-stdio1 tst-stdio2 \ + tst-stack1 tst-stack2 tst-stack3 tst-stack4 tst-pthread-getattr \ +diff --git a/nptl/allocatestack.c b/nptl/allocatestack.c +index 6b42b11d5a..7365ca606b 100644 +--- a/nptl/allocatestack.c ++++ b/nptl/allocatestack.c +@@ -440,9 +440,6 @@ allocate_stack (const struct pthread_attr *attr, struct pthread **pdp, + SETUP_THREAD_SYSINFO (pd); + #endif + +- /* The process ID is also the same as that of the caller. */ +- pd->pid = THREAD_GETMEM (THREAD_SELF, pid); +- + /* Don't allow setxid until cloned. */ + pd->setxid_futex = -1; + +@@ -579,9 +576,6 @@ allocate_stack (const struct pthread_attr *attr, struct pthread **pdp, + /* Don't allow setxid until cloned. */ + pd->setxid_futex = -1; + +- /* The process ID is also the same as that of the caller. */ +- pd->pid = THREAD_GETMEM (THREAD_SELF, pid); +- + /* Allocate the DTV for this thread. */ + if (_dl_allocate_tls (TLS_TPADJ (pd)) == NULL) + { +@@ -875,9 +869,6 @@ __reclaim_stacks (void) + /* This marks the stack as free. */ + curp->tid = 0; + +- /* The PID field must be initialized for the new process. */ +- curp->pid = self->pid; +- + /* Account for the size of the stack. */ + stack_cache_actsize += curp->stackblock_size; + +@@ -903,13 +894,6 @@ __reclaim_stacks (void) + } + } + +- /* Reset the PIDs in any cached stacks. */ +- list_for_each (runp, &stack_cache) +- { +- struct pthread *curp = list_entry (runp, struct pthread, list); +- curp->pid = self->pid; +- } +- + /* Add the stack of all running threads to the cache. */ + list_splice (&stack_used, &stack_cache); + +@@ -1054,9 +1038,9 @@ setxid_signal_thread (struct xid_command *cmdp, struct pthread *t) + return 0; + + int val; ++ pid_t pid = __getpid (); + INTERNAL_SYSCALL_DECL (err); +- val = INTERNAL_SYSCALL (tgkill, err, 3, THREAD_GETMEM (THREAD_SELF, pid), +- t->tid, SIGSETXID); ++ val = INTERNAL_SYSCALL_CALL (tgkill, err, pid, t->tid, SIGSETXID); + + /* If this failed, it must have had not started yet or else exited. */ + if (!INTERNAL_SYSCALL_ERROR_P (val, err)) +diff --git a/nptl/descr.h b/nptl/descr.h +index 8e4938deb5..bc92abf010 100644 +--- a/nptl/descr.h ++++ b/nptl/descr.h +@@ -167,8 +167,8 @@ struct pthread + therefore stack) used' flag. */ + pid_t tid; + +- /* Process ID - thread group ID in kernel speak. */ +- pid_t pid; ++ /* Ununsed. */ ++ pid_t pid_ununsed; + + /* List of robust mutexes the thread is holding. */ + #ifdef __PTHREAD_MUTEX_HAVE_PREV +diff --git a/nptl/nptl-init.c b/nptl/nptl-init.c +index bdbdfedcef..48fab50c4e 100644 +--- a/nptl/nptl-init.c ++++ b/nptl/nptl-init.c +@@ -184,18 +184,12 @@ __nptl_set_robust (struct pthread *self) + static void + sigcancel_handler (int sig, siginfo_t *si, void *ctx) + { +- /* Determine the process ID. It might be negative if the thread is +- in the middle of a fork() call. */ +- pid_t pid = THREAD_GETMEM (THREAD_SELF, pid); +- if (__glibc_unlikely (pid < 0)) +- pid = -pid; +- + /* Safety check. It would be possible to call this function for + other signals and send a signal from another process. This is not + correct and might even be a security problem. Try to catch as + many incorrect invocations as possible. */ + if (sig != SIGCANCEL +- || si->si_pid != pid ++ || si->si_pid != __getpid() + || si->si_code != SI_TKILL) + return; + +@@ -243,19 +237,14 @@ struct xid_command *__xidcmd attribute_hidden; + static void + sighandler_setxid (int sig, siginfo_t *si, void *ctx) + { +- /* Determine the process ID. It might be negative if the thread is +- in the middle of a fork() call. */ +- pid_t pid = THREAD_GETMEM (THREAD_SELF, pid); + int result; +- if (__glibc_unlikely (pid < 0)) +- pid = -pid; + + /* Safety check. It would be possible to call this function for + other signals and send a signal from another process. This is not + correct and might even be a security problem. Try to catch as + many incorrect invocations as possible. */ + if (sig != SIGSETXID +- || si->si_pid != pid ++ || si->si_pid != __getpid () + || si->si_code != SI_TKILL) + return; + +diff --git a/nptl/pthread_cancel.c b/nptl/pthread_cancel.c +index 1419baf988..89d02e1741 100644 +--- a/nptl/pthread_cancel.c ++++ b/nptl/pthread_cancel.c +@@ -22,7 +22,7 @@ + #include "pthreadP.h" + #include <atomic.h> + #include <sysdep.h> +- ++#include <unistd.h> + + int + pthread_cancel (pthread_t th) +@@ -66,19 +66,11 @@ pthread_cancel (pthread_t th) + #ifdef SIGCANCEL + /* The cancellation handler will take care of marking the + thread as canceled. */ +- INTERNAL_SYSCALL_DECL (err); +- +- /* One comment: The PID field in the TCB can temporarily be +- changed (in fork). But this must not affect this code +- here. Since this function would have to be called while +- the thread is executing fork, it would have to happen in +- a signal handler. But this is no allowed, pthread_cancel +- is not guaranteed to be async-safe. */ +- int val; +- val = INTERNAL_SYSCALL (tgkill, err, 3, +- THREAD_GETMEM (THREAD_SELF, pid), pd->tid, +- SIGCANCEL); ++ pid_t pid = getpid (); + ++ INTERNAL_SYSCALL_DECL (err); ++ int val = INTERNAL_SYSCALL_CALL (tgkill, err, pid, pd->tid, ++ SIGCANCEL); + if (INTERNAL_SYSCALL_ERROR_P (val, err)) + result = INTERNAL_SYSCALL_ERRNO (val, err); + #else +diff --git a/nptl/pthread_getattr_np.c b/nptl/pthread_getattr_np.c +index fb906f0484..32d7484bf8 100644 +--- a/nptl/pthread_getattr_np.c ++++ b/nptl/pthread_getattr_np.c +@@ -68,7 +68,6 @@ pthread_getattr_np (pthread_t thread_id, pthread_attr_t *attr) + { + /* No stack information available. This must be for the initial + thread. Get the info in some magical way. */ +- assert (abs (thread->pid) == thread->tid); + + /* Stack size limit. */ + struct rlimit rl; +diff --git a/nptl/tst-exec5.c b/nptl/tst-exec5.c +new file mode 100644 +index 0000000000..4327d8d41c +--- /dev/null ++++ b/nptl/tst-exec5.c +@@ -0,0 +1,196 @@ ++/* Check if posix_spawn does not act as a cancellation entrypoint. ++ Copyright (C) 2016 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <errno.h> ++#include <paths.h> ++#include <pthread.h> ++#include <signal.h> ++#include <spawn.h> ++#include <stdbool.h> ++#include <stdio.h> ++#include <stdlib.h> ++#include <unistd.h> ++#include <sys/wait.h> ++ ++static int do_test (void); ++#define TEST_FUNCTION do_test () ++#include <test-skeleton.c> ++ ++static pthread_barrier_t b; ++ ++static pid_t pid; ++static int pipefd[2]; ++ ++static void * ++tf (void *arg) ++{ ++ int r = pthread_barrier_wait (&b); ++ if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) ++ { ++ puts ("error: pthread_barrier_wait failed"); ++ exit (1); ++ } ++ ++ posix_spawn_file_actions_t a; ++ if (posix_spawn_file_actions_init (&a) != 0) ++ { ++ puts ("error: spawn_file_actions_init failed"); ++ exit (1); ++ } ++ ++ if (posix_spawn_file_actions_adddup2 (&a, pipefd[1], STDOUT_FILENO) != 0) ++ { ++ puts ("error: spawn_file_actions_adddup2 failed"); ++ exit (1); ++ } ++ ++ if (posix_spawn_file_actions_addclose (&a, pipefd[0]) != 0) ++ { ++ puts ("error: spawn_file_actions_addclose"); ++ exit (1); ++ } ++ ++ char *argv[] = { (char *) _PATH_BSHELL, (char *) "-c", (char *) "echo $$", ++ NULL }; ++ if (posix_spawn (&pid, _PATH_BSHELL, &a, NULL, argv, NULL) != 0) ++ { ++ puts ("error: spawn failed"); ++ exit (1); ++ } ++ ++ return NULL; ++} ++ ++ ++static int ++do_test (void) ++{ ++ /* The test basically pipe a 'echo $$' created by a thread with a ++ cancellation pending. It then checks if the thread is not cancelled, ++ the process is created and if the output is the expected one. */ ++ ++ if (pipe (pipefd) != 0) ++ { ++ puts ("error: pipe failed"); ++ exit (1); ++ } ++ ++ /* Not interested in knowing when the pipe is closed. */ ++ if (sigignore (SIGPIPE) != 0) ++ { ++ puts ("error: sigignore failed"); ++ exit (1); ++ } ++ ++ /* To synchronize with the thread. */ ++ if (pthread_barrier_init (&b, NULL, 2) != 0) ++ { ++ puts ("error: pthread_barrier_init failed"); ++ exit (1); ++ } ++ ++ pthread_t th; ++ if (pthread_create (&th, NULL, &tf, NULL) != 0) ++ { ++ puts ("error: pthread_create failed"); ++ exit (1); ++ } ++ ++ if (pthread_cancel (th) != 0) ++ { ++ puts ("error: pthread_cancel failed"); ++ exit (1); ++ } ++ ++ int r = pthread_barrier_wait (&b); ++ if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) ++ { ++ puts ("error: pthread_barrier_wait"); ++ exit (1); ++ } ++ ++ void *retval; ++ if (pthread_join (th, &retval) != 0) ++ { ++ puts ("error: pthread_join failed\n"); ++ } ++ if (retval == PTHREAD_CANCELED) ++ { ++ puts ("error: thread cancelled"); ++ exit (1); ++ } ++ ++ close (pipefd[1]); ++ ++ /* The global 'pid' should be set by thread posix_spawn calling. Check ++ below if it was executed correctly and with expected output. */ ++ ++ char buf[64]; ++ ssize_t n; ++ bool seen_pid = false; ++ while (TEMP_FAILURE_RETRY ((n = read (pipefd[0], buf, sizeof (buf)))) > 0) ++ { ++ /* We only expect to read the PID. */ ++ char *endp; ++ long int rpid = strtol (buf, &endp, 10); ++ ++ if (*endp != '\n') ++ { ++ printf ("error: didn't parse whole line: \"%s\"\n", buf); ++ exit (1); ++ } ++ if (endp == buf) ++ { ++ puts ("error: read empty line"); ++ exit (1); ++ } ++ ++ if (rpid != pid) ++ { ++ printf ("error: found \"%s\", expected PID %ld\n", buf, ++ (long int) pid); ++ exit (1); ++ } ++ ++ if (seen_pid) ++ { ++ puts ("error: found more than one PID line"); ++ exit (1); ++ } ++ ++ seen_pid = true; ++ } ++ ++ close (pipefd[0]); ++ ++ int status; ++ int err = waitpid (pid, &status, 0); ++ if (err != pid) ++ { ++ puts ("errnor: waitpid failed"); ++ exit (1); ++ } ++ ++ if (!seen_pid) ++ { ++ puts ("error: didn't get PID"); ++ exit (1); ++ } ++ ++ return 0; ++} +diff --git a/nptl/tst-once5.cc b/nptl/tst-once5.cc +index 978d8271bd..513ac53f6f 100644 +--- a/nptl/tst-once5.cc ++++ b/nptl/tst-once5.cc +@@ -75,5 +75,7 @@ do_test (void) + return result; + } + ++// The test currently hangs and is XFAILed. Reduce the timeout. ++#define TIMEOUT 1 + #define TEST_FUNCTION do_test () + #include "../test-skeleton.c" +diff --git a/nptl_db/structs.def b/nptl_db/structs.def +index a9b621b126..1cb6a46391 100644 +--- a/nptl_db/structs.def ++++ b/nptl_db/structs.def +@@ -48,7 +48,6 @@ DB_STRUCT (pthread) + DB_STRUCT_FIELD (pthread, list) + DB_STRUCT_FIELD (pthread, report_events) + DB_STRUCT_FIELD (pthread, tid) +-DB_STRUCT_FIELD (pthread, pid) + DB_STRUCT_FIELD (pthread, start_routine) + DB_STRUCT_FIELD (pthread, cancelhandling) + DB_STRUCT_FIELD (pthread, schedpolicy) +diff --git a/nptl_db/td_ta_thr_iter.c b/nptl_db/td_ta_thr_iter.c +index a990fed150..9e5059956b 100644 +--- a/nptl_db/td_ta_thr_iter.c ++++ b/nptl_db/td_ta_thr_iter.c +@@ -76,48 +76,28 @@ iterate_thread_list (td_thragent_t *ta, td_thr_iter_f *callback, + if (ps_pdread (ta->ph, addr, copy, ta->ta_sizeof_pthread) != PS_OK) + return TD_ERR; + +- /* Verify that this thread's pid field matches the child PID. +- If its pid field is negative, it's about to do a fork or it +- is the sole thread in a fork child. */ +- psaddr_t pid; +- err = DB_GET_FIELD_LOCAL (pid, ta, copy, pthread, pid, 0); +- if (err == TD_OK && (pid_t) (uintptr_t) pid < 0) +- { +- if (-(pid_t) (uintptr_t) pid == match_pid) +- /* It is about to do a fork, but is really still the parent PID. */ +- pid = (psaddr_t) (uintptr_t) match_pid; +- else +- /* It must be a fork child, whose new PID is in the tid field. */ +- err = DB_GET_FIELD_LOCAL (pid, ta, copy, pthread, tid, 0); +- } ++ err = DB_GET_FIELD_LOCAL (schedpolicy, ta, copy, pthread, ++ schedpolicy, 0); + if (err != TD_OK) + break; ++ err = DB_GET_FIELD_LOCAL (schedprio, ta, copy, pthread, ++ schedparam_sched_priority, 0); ++ if (err != TD_OK) ++ break; ++ ++ /* Now test whether this thread matches the specified conditions. */ + +- if ((pid_t) (uintptr_t) pid == match_pid) ++ /* Only if the priority level is as high or higher. */ ++ int descr_pri = ((uintptr_t) schedpolicy == SCHED_OTHER ++ ? 0 : (uintptr_t) schedprio); ++ if (descr_pri >= ti_pri) + { +- err = DB_GET_FIELD_LOCAL (schedpolicy, ta, copy, pthread, +- schedpolicy, 0); +- if (err != TD_OK) +- break; +- err = DB_GET_FIELD_LOCAL (schedprio, ta, copy, pthread, +- schedparam_sched_priority, 0); +- if (err != TD_OK) +- break; +- +- /* Now test whether this thread matches the specified conditions. */ +- +- /* Only if the priority level is as high or higher. */ +- int descr_pri = ((uintptr_t) schedpolicy == SCHED_OTHER +- ? 0 : (uintptr_t) schedprio); +- if (descr_pri >= ti_pri) +- { +- /* Yep, it matches. Call the callback function. */ +- td_thrhandle_t th; +- th.th_ta_p = (td_thragent_t *) ta; +- th.th_unique = addr; +- if (callback (&th, cbdata_p) != 0) +- return TD_DBERR; +- } ++ /* Yep, it matches. Call the callback function. */ ++ td_thrhandle_t th; ++ th.th_ta_p = (td_thragent_t *) ta; ++ th.th_unique = addr; ++ if (callback (&th, cbdata_p) != 0) ++ return TD_DBERR; + } + + /* Get the pointer to the next element. */ +diff --git a/nptl_db/td_thr_validate.c b/nptl_db/td_thr_validate.c +index f3c8a7bed6..9b89fecad2 100644 +--- a/nptl_db/td_thr_validate.c ++++ b/nptl_db/td_thr_validate.c +@@ -80,28 +80,5 @@ td_thr_validate (const td_thrhandle_t *th) + err = TD_OK; + } + +- if (err == TD_OK) +- { +- /* Verify that this is not a stale element in a fork child. */ +- pid_t match_pid = ps_getpid (th->th_ta_p->ph); +- psaddr_t pid; +- err = DB_GET_FIELD (pid, th->th_ta_p, th->th_unique, pthread, pid, 0); +- if (err == TD_OK && (pid_t) (uintptr_t) pid < 0) +- { +- /* This was a thread that was about to fork, or it is the new sole +- thread in a fork child. In the latter case, its tid was stored +- via CLONE_CHILD_SETTID and so is already the proper child PID. */ +- if (-(pid_t) (uintptr_t) pid == match_pid) +- /* It is about to do a fork, but is really still the parent PID. */ +- pid = (psaddr_t) (uintptr_t) match_pid; +- else +- /* It must be a fork child, whose new PID is in the tid field. */ +- err = DB_GET_FIELD (pid, th->th_ta_p, th->th_unique, +- pthread, tid, 0); +- } +- if (err == TD_OK && (pid_t) (uintptr_t) pid != match_pid) +- err = TD_NOTHR; +- } +- + return err; + } +diff --git a/po/de.po b/po/de.po +index 1383e8c4a9..ca14c7e386 100644 +--- a/po/de.po ++++ b/po/de.po +@@ -8,7 +8,7 @@ msgid "" + msgstr "" + "Project-Id-Version: GNU libc 2.22-pre1\n" + "POT-Creation-Date: 2015-07-31 00:10-0400\n" +-"PO-Revision-Date: 2015-08-31 18:30+0200\n" ++"PO-Revision-Date: 2016-04-22 18:44+0200\n" + "Last-Translator: Jochen Hein <jochen@jochen.org>\n" + "Language-Team: German <translation-team-de@lists.sourceforge.net>\n" + "Language: de\n" +@@ -4479,13 +4479,13 @@ msgstr "" + "%15s Cache ist dauerhaft\n" + "%15s Cache wird gemeinsam verwendet\n" + "%15Zu vorgeschlagene Größe\n" +-"%15Zu Gesamtröße des Data-Pools\n" ++"%15Zu Gesamtgröße des Data-Pools\n" + "%15Zu Benutzter Speicher im Data-Pool\n" + "%15lu Time to Live für positive Einträge in Sekunden\n" + "%15lu Time to Live für negative Einträge in Sekunden\n" + "%15<PRIuMAX> Cache-Hits bei positiven Einträgen\n" + "%15<PRIuMAX> Cache-Hits bei positiven Einträgen\n" +-"%15<PRIuMAX> Cache-Misses bei positiven Einträgen\n" ++"%15<PRIuMAX> Cache-Misses bei positiven Einträgen\n" + "%15<PRIuMAX> Cache-Misses bei negativen Einträgen\n" + "%15lu%% Cache-Hit Verhältnis\n" + "%15zu aktuelle Anzahl der Werte im Cache\n" +diff --git a/po/fi.po b/po/fi.po +index 17cb3e3e1d..8a2ab8358c 100644 +--- a/po/fi.po ++++ b/po/fi.po +@@ -24,16 +24,16 @@ + # + msgid "" + msgstr "" +-"Project-Id-Version: libc 2.21-pre1\n" ++"Project-Id-Version: libc 2.22-pre1\n" + "POT-Creation-Date: 2015-07-31 00:10-0400\n" +-"PO-Revision-Date: 2015-07-28 20:29+0300\n" ++"PO-Revision-Date: 2016-05-26 21:14+0300\n" + "Last-Translator: Lauri Nurmi <lanurmi@iki.fi>\n" + "Language-Team: Finnish <translation-team-fi@lists.sourceforge.net>\n" + "Language: fi\n" + "MIME-Version: 1.0\n" + "Content-Type: text/plain; charset=UTF-8\n" + "Content-Transfer-Encoding: 8bit\n" +-"X-Generator: Poedit 1.8.3\n" ++"X-Generator: Poedit 1.8.7\n" + "Plural-Forms: nplurals=2; plural=(n != 1);\n" + + #: argp/argp-help.c:227 +@@ -126,7 +126,7 @@ msgid "%s%s%s:%u: %s%sUnexpected error: %s.\n" + msgstr "%s%s%s:%u: %s%sOdottamaton virhe: %s.\n" + + #: assert/assert.c:101 +-#, fuzzy, c-format ++#, c-format + msgid "" + "%s%s%s:%u: %s%sAssertion `%s' failed.\n" + "%n" +@@ -169,12 +169,12 @@ msgstr "" + #: malloc/memusagestat.c:563 nss/getent.c:973 nss/makedb.c:369 + #: posix/getconf.c:486 sunrpc/rpcinfo.c:691 + #: sysdeps/unix/sysv/linux/lddlibc4.c:61 +-#, fuzzy, c-format ++#, c-format + msgid "" + "For bug reporting instructions, please see:\n" + "%s.\n" + msgstr "" +-"Ohjeet ohjelmistovioista ilmoittamiseen ovat osoitteessa\n" ++"Katso ohjeet vikailmoitusten tekemiseen osoitteesta:\n" + "%s.\n" + + #: catgets/gencat.c:245 debug/pcprofiledump.c:225 debug/xtrace.sh:64 +@@ -321,9 +321,8 @@ msgstr "Käyttö: xtrace [VALITSIN]... OHJELMA [OHJELMANVALITSIN]...\\n" + + #: debug/xtrace.sh:32 elf/sotruss.sh:56 elf/sotruss.sh:67 elf/sotruss.sh:135 + #: malloc/memusage.sh:26 +-#, fuzzy + msgid "Try \\`%s --help' or \\`%s --usage' for more information.\\n" +-msgstr "Kokeile ”%s --help” tai ”%s --usage” saadaksesi lisää tietoa.\n" ++msgstr "Kokeile ”%s --help” tai ”%s --usage” saadaksesi lisää tietoa.\\n" + + #: debug/xtrace.sh:38 + #, fuzzy +@@ -594,9 +593,8 @@ msgid "cannot enable executable stack as shared object requires" + msgstr "jaettua objektikahvaa ei voi luoda" + + #: elf/dl-load.c:1339 +-#, fuzzy + msgid "cannot close file descriptor" +-msgstr "tiedostoa %s ei voi sulkea" ++msgstr "tiedostokahvaa ei voi sulkea" + + #: elf/dl-load.c:1568 + msgid "file too short" +@@ -796,9 +794,8 @@ msgid "Format to use: new, old or compat (default)" + msgstr "Käytettävä muoto: ”new”, ”old” tai ”compat” (oletus)" + + #: elf/ldconfig.c:151 +-#, fuzzy + msgid "Ignore auxiliary cache file" +-msgstr "Käytä CACHEa välimuistitiedostona" ++msgstr "Jätä huomiotta apuvälimuistitiedosto" + + #: elf/ldconfig.c:159 + msgid "Configure Dynamic Linker Run Time Bindings." +@@ -1087,9 +1084,9 @@ msgid "invalid process ID '%s'" + msgstr "virheellinen prosessi-ID ”%s”" + + #: elf/pldd.c:120 +-#, fuzzy, c-format ++#, c-format + msgid "cannot open %s" +-msgstr "laitetta %s ei voi avata" ++msgstr "tiedostoa %s ei voi avata" + + #: elf/pldd.c:152 + #, fuzzy, c-format +@@ -1102,24 +1099,24 @@ msgid "cannot prepare reading %s/task" + msgstr "ei voi avata laitetta %s lukutilaan" + + #: elf/pldd.c:168 +-#, fuzzy, c-format ++#, c-format + msgid "invalid thread ID '%s'" +-msgstr "virheellinen prosessi-ID ”%s”" ++msgstr "virheellinen säie-ID ”%s”" + + #: elf/pldd.c:179 +-#, fuzzy, c-format ++#, c-format + msgid "cannot attach to process %lu" +-msgstr "tiedostoa ”%s” ei voi avata" ++msgstr "ei voida kiinnittyä prosessiin %lu" + + #: elf/pldd.c:294 + #, c-format + msgid "cannot get information about process %lu" +-msgstr "" ++msgstr "tietojen saaminen prosessista %lu ei onnistu" + + #: elf/pldd.c:307 +-#, fuzzy, c-format ++#, c-format + msgid "process %lu is no ELF program" +-msgstr "ohjelma %lu ei ole käytettävissä\n" ++msgstr "prosessi %lu ei ole ELF-ohjelma" + + #: elf/readelflib.c:34 + #, c-format +@@ -1203,7 +1200,7 @@ msgstr "%s kohde ei saa olla hakemisto\n" + #: elf/sln.c:184 + #, c-format + msgid "%s: failed to remove the old destination\n" +-msgstr "" ++msgstr "%s: vanhan kohteen poistaminen epäonnistui\n" + + #: elf/sln.c:192 + #, c-format +@@ -1237,9 +1234,8 @@ msgid "Mandatory arguments to long options are also mandatory for any correspond + msgstr "Pakolliset argumentit pitkille valitsimille ovat pakollisia kaikille vastaaville lyhyille valitsimille.\\n" + + #: elf/sotruss.sh:55 +-#, fuzzy + msgid "%s: option requires an argument -- '%s'\\n" +-msgstr "%s: valitsin ”%s” vaatii argumentin\n" ++msgstr "%s: valitsin vaatii argumentin -- ”%c”\\n" + + #: elf/sotruss.sh:61 + msgid "%s: option is ambiguous; possibilities:" +@@ -1507,7 +1503,6 @@ msgid "unknown iconv() error %d" + msgstr "tuntematon iconv()-virhe %d" + + #: iconv/iconv_prog.c:791 +-#, fuzzy + msgid "" + "The following list contains all the coded character sets known. This does\n" + "not necessarily mean that all combinations of these names can be used for\n" +@@ -1516,9 +1511,9 @@ msgid "" + "\n" + " " + msgstr "" +-"Seuraavassa listassa ovat kaikki tunnetut koodatut merkistöt. Se ei\n" ++"Seuraavassa listassa ovat kaikki tunnetut koodatut merkistöt. Tämä ei\n" + "kuitenkaan välttämättä tarkoita sitä, että kaikkia näiden nimien\n" +-"yhdistelmiä voidaan käyttää FROM- ja TO-komentoriviparametreina. Yksi\n" ++"yhdistelmiä voisi käyttää FROM- ja TO-komentoriviparametreina. Yksi\n" + "koodattu merkistö voi olla listalla useilla eri nimillä (aliaksilla).\n" + "\n" + " " +@@ -2733,14 +2728,12 @@ msgid "locale.alias file to consult when making archive" + msgstr "Arkistoa luotaessa käytettävä locale.alias-tiedosto" + + #: locale/programs/localedef.c:150 +-#, fuzzy + msgid "Generate little-endian output" +-msgstr "Tuota little-endian-koodia" ++msgstr "Tuota little-endian-muotoa" + + #: locale/programs/localedef.c:152 +-#, fuzzy + msgid "Generate big-endian output" +-msgstr "Tuota big-endian-koodia" ++msgstr "Tuota big-endian-muotoa" + + #: locale/programs/localedef.c:157 + msgid "Compile locale specification" +@@ -4275,10 +4268,9 @@ msgid "" + msgstr "" + + #: nscd/nscd.c:635 +-#, fuzzy, c-format +-#| msgid "lstat failed" ++#, c-format + msgid "'wait' failed\n" +-msgstr "tiedoston tilan luku epäonnistui" ++msgstr "”wait” epäonnistui\n" + + #: nscd/nscd.c:642 + #, c-format +@@ -4670,9 +4662,9 @@ msgid "cannot create temporary file" + msgstr "tilapäistä tiedostoa ei voi luoda" + + #: nss/makedb.c:304 +-#, fuzzy, c-format ++#, c-format + msgid "cannot stat newly created file" +-msgstr "tiedoston ”%s” tilaa ei voi lukea: %s" ++msgstr "juuri luodun tiedoston tilaa ei voi lukea" + + #: nss/makedb.c:315 + #, c-format +@@ -4680,9 +4672,9 @@ msgid "cannot rename temporary file" + msgstr "tilapäistä tiedostoa ei voi nimetä uudelleen" + + #: nss/makedb.c:531 nss/makedb.c:554 +-#, fuzzy, c-format ++#, c-format + msgid "cannot create search tree" +-msgstr "hakupolulle ei voi luoda välimuistia" ++msgstr "hakupuuta ei voi luoda" + + #: nss/makedb.c:560 + msgid "duplicate key" +@@ -4699,9 +4691,9 @@ msgid "failed to write new database file" + msgstr "uuden tietokantatiedoston kirjoittaminen epäonnistui" + + #: nss/makedb.c:812 +-#, fuzzy, c-format ++#, c-format + msgid "cannot stat database file" +-msgstr "tiedoston ”%s” tilaa ei voi lukea: %s" ++msgstr "tietokantatiedoston tilaa ei voi lukea" + + #: nss/makedb.c:817 + #, fuzzy, c-format +@@ -4709,9 +4701,9 @@ msgid "cannot map database file" + msgstr "Karttatietokannassa ei ole enempää tietueita" + + #: nss/makedb.c:820 +-#, fuzzy, c-format ++#, c-format + msgid "file not a database file" +-msgstr "luettaessa profilointidatatiedoston tilaa" ++msgstr "tiedosto ei ole tietokantatiedosto" + + #: nss/makedb.c:871 + #, fuzzy, c-format +@@ -4726,7 +4718,7 @@ msgstr "Käyttö: %s [-v määrittely] muuttujanimi [polku]\n" + #: posix/getconf.c:403 + #, c-format + msgid " %s -a [pathname]\n" +-msgstr "" ++msgstr " %s -a [polku]\n" + + #: posix/getconf.c:479 + #, c-format +@@ -5094,11 +5086,11 @@ msgstr "Laitetta irrotettu" + + #: stdio-common/psiginfo.c:139 + msgid "Signal sent by kill()" +-msgstr "" ++msgstr "Signaalin lähetti kill()" + + #: stdio-common/psiginfo.c:142 + msgid "Signal sent by sigqueue()" +-msgstr "" ++msgstr "Signaalin lähetti sigqueue()" + + #: stdio-common/psiginfo.c:145 + msgid "Signal generated by the expiration of a timer" +@@ -5114,7 +5106,7 @@ msgstr "" + + #: stdio-common/psiginfo.c:157 + msgid "Signal sent by tkill()" +-msgstr "" ++msgstr "Signaalin lähetti tkill()" + + #: stdio-common/psiginfo.c:162 + msgid "Signal generated by the completion of an asynchronous name lookup request" +@@ -5296,9 +5288,8 @@ msgid "Failed (unspecified error)" + msgstr "Epäonnistui (määrittelemätön virhe)" + + #: sunrpc/clnt_raw.c:115 +-#, fuzzy + msgid "clnt_raw.c: fatal header serialization error" +-msgstr "clnt_raw.c: vakava otsikon serialisointivirhe" ++msgstr "clnt_raw.c: vakava otsikon sarjallistamisvirhe" + + #: sunrpc/pm_getmaps.c:77 + msgid "pmap_getmaps.c: rpc problem" +@@ -6825,9 +6816,8 @@ msgid "Interrupted by a signal" + msgstr "Signaalin keskeyttämä" + + #: sysdeps/posix/gai_strerror-strs.h:17 +-#, fuzzy + msgid "Parameter string not correctly encoded" +-msgstr "Parametrimerkkijono on väärin koodattu" ++msgstr "Parametrimerkkijono ei ole koodattu oikein" + + #: sysdeps/unix/sysv/linux/i386/readelflib.c:65 + #, c-format +diff --git a/po/sv.po b/po/sv.po +index 49d1f23904..e046577b08 100644 +--- a/po/sv.po ++++ b/po/sv.po +@@ -1,13 +1,17 @@ + # GNU libc message catalog for Swedish +-# Copyright © 1996, 1998, 2001, 2002, 2003, 2006, 2008, 2009, 2011, 2012, 2013, 2014, 2015 Free Software Foundation, Inc. ++# Copyright © 1996, 1998, 2001, 2002, 2003, 2006, 2008, 2009, 2011, 2012, 2013, 2014, 2015, 2016 Free Software Foundation, Inc. + # This file is distributed under the same license as the glibc package. +-# Jan Djärv <jan.h.d@swipnet.se>, 1996, 1998, 2001, 2002, 2003, 2006, 2007, 2008, 2009, 2011, 2012, 2013, 2014, 2015 ++# ++# Jan Djärv <jan.h.d@swipnet.se>, 1996, 1998, 2001, 2002, 2003, 2006, 2007, 2008, 2009, 2011, 2012, 2013, 2014, 2015. ++# Göran Uddeborg <goeran@uddeborg.se>, 2016. ++# ++# $Revision: 1.3 $ + msgid "" + msgstr "" +-"Project-Id-Version: libc 2.21-pre1\n" ++"Project-Id-Version: libc 2.22-pre1\n" + "POT-Creation-Date: 2015-07-31 00:10-0400\n" +-"PO-Revision-Date: 2015-01-24 10:35+0100\n" +-"Last-Translator: Jan Djärv <jan.h.d@swipnet.se>\n" ++"PO-Revision-Date: 2016-08-02 17:17+0200\n" ++"Last-Translator: Göran Uddeborg <goeran@uddeborg.se>\n" + "Language-Team: Swedish <tp-sv@listor.tp-sv.se>\n" + "Language: sv\n" + "MIME-Version: 1.0\n" +@@ -48,7 +52,7 @@ msgstr " [FLAGGA...]" + #: argp/argp-help.c:1643 + #, c-format + msgid "Try `%s --help' or `%s --usage' for more information.\n" +-msgstr "Försök med \"%s --help\" eller \"%s --usage\" för mer information\n" ++msgstr "Försök med ”%s --help” eller ”%s --usage” för mer information.\n" + + #: argp/argp-help.c:1671 + #, c-format +@@ -304,11 +308,11 @@ msgstr "Användning: xtrace [FLAGGA]... PROGRAM [PROGRAMFLAGGA}...\\n" + #: debug/xtrace.sh:32 elf/sotruss.sh:56 elf/sotruss.sh:67 elf/sotruss.sh:135 + #: malloc/memusage.sh:26 + msgid "Try \\`%s --help' or \\`%s --usage' for more information.\\n" +-msgstr "Försök med \\\"%s --help\\\" eller \\\"%s --usage\\\" för mer information\\n" ++msgstr "Försök med ”%s --help” eller ”%s --usage” för mer information\\n" + + #: debug/xtrace.sh:38 + msgid "%s: option '%s' requires an argument.\\n" +-msgstr "%s: flaggan \\\"%s\\\" kräver ett argument\\n" ++msgstr "%s: flaggan ”%s” kräver ett argument.\\n" + + #: debug/xtrace.sh:45 + msgid "" +@@ -332,19 +336,17 @@ msgstr "" + " --usage Visa en kort hjälptext\n" + " -V,--version Visa versionsinformation och avsluta\n" + "\n" +-"Obligatoriska argument för långa flaggor är obligatoriska även för\n" ++"Obligatoriska argument för långa flaggor är obligatoriska även för\n" + "motsvarande korta.\n" + + #: debug/xtrace.sh:57 elf/ldd.bash.in:55 elf/sotruss.sh:49 + #: malloc/memusage.sh:64 + msgid "For bug reporting instructions, please see:\\\\n%s.\\\\n" +-msgstr "" +-"För felrapporteringsinstruktioner, se:\\\\n%s.\\\\n\n" +-"Rapportera fel eller synpunkter på översättningen till <tp-sv@listor.tp-sv.se>.\\\\n" ++msgstr "För felrapporteringsinstruktioner, se:\\\\n%s.\\\\nRapportera fel eller synpunkter på översättningen till:\\\\n<tp-sv@listor.tp-sv.se>.\\\\n" + + #: debug/xtrace.sh:125 + msgid "xtrace: unrecognized option \\`$1'\\n" +-msgstr "xtrace: okänd flagga \"$1\"\\n" ++msgstr "xtrace: okänd flagga ”$1”\\n" + + #: debug/xtrace.sh:138 + msgid "No program name given\\n" +@@ -353,12 +355,12 @@ msgstr "Inget programnamn givet\\n" + #: debug/xtrace.sh:146 + #, sh-format + msgid "executable \\`$program' not found\\n" +-msgstr "program \"$program\" hittades inte\\n" ++msgstr "program ”$program” hittades inte\\n" + + #: debug/xtrace.sh:150 + #, sh-format + msgid "\\`$program' is no executable\\n" +-msgstr "\"$program\" är inte en körbar binär\\n" ++msgstr "”$program” är inte en körbar binär\\n" + + #: dlfcn/dlinfo.c:63 + msgid "RTLD_SELF used in code not dynamically loaded" +@@ -396,7 +398,7 @@ msgstr ", OS ABI: %s %d.%d.%d" + #: elf/cache.c:157 elf/ldconfig.c:1340 + #, c-format + msgid "Can't open cache file %s\n" +-msgstr "Kan inte öppna cache-fil \"%s\"\n" ++msgstr "Kan inte öppna cache-filen %s\n" + + #: elf/cache.c:171 + #, c-format +@@ -416,7 +418,7 @@ msgstr "%d bibliotek hittades i cache \"%s\"\n" + #: elf/cache.c:426 + #, c-format + msgid "Can't create temporary cache file %s" +-msgstr "Kan inte skapa temporär cache-fil \"%s\"" ++msgstr "Kan inte skapa en temporär cache-fil %s" + + #: elf/cache.c:434 elf/cache.c:444 elf/cache.c:448 elf/cache.c:453 + #, c-format +@@ -829,7 +831,7 @@ msgstr "Kan inte ta status (lstat) på %s" + #: elf/ldconfig.c:609 + #, c-format + msgid "Ignored file %s since it is not a regular file." +-msgstr "Ignorerar fil %s eftersom den inte är en vanlig fil" ++msgstr "Ignorerar fil %s eftersom den inte är en vanlig fil." + + #: elf/ldconfig.c:618 + #, c-format +@@ -951,7 +953,7 @@ msgstr "" + + #: elf/ldd.bash.in:80 + msgid "ldd: option \\`$1' is ambiguous" +-msgstr "ldd: flaggan \"$1\" är tvetydig" ++msgstr "ldd: flaggan ”$1” är tvetydig" + + #: elf/ldd.bash.in:87 + msgid "unrecognized option" +@@ -959,7 +961,7 @@ msgstr "okänd flagga" + + #: elf/ldd.bash.in:88 elf/ldd.bash.in:125 + msgid "Try \\`ldd --help' for more information." +-msgstr "Försök med \"ldd --help\" för mer information" ++msgstr "Försök med \"ldd --help\" för mer information." + + #: elf/ldd.bash.in:124 + msgid "missing file arguments" +@@ -1028,10 +1030,9 @@ msgid "cannot read object name" + msgstr "kan inte läsa objektnamn" + + #: elf/pldd-xx.c:219 +-#, fuzzy, c-format +-#| msgid "cannot allocate memory for program header" ++#, c-format + msgid "cannot allocate buffer for object name" +-msgstr "kan inte allokera minne för programhuvud" ++msgstr "kan inte allokera en buffert för objektnamn" + + #: elf/pldd.c:64 + msgid "List dynamic shared objects loaded into process." +@@ -1212,11 +1213,11 @@ msgstr "" + + #: elf/sotruss.sh:46 + msgid "Mandatory arguments to long options are also mandatory for any corresponding\\nshort options.\\n" +-msgstr "Obligatoriska respektive valfria argument för långa flaggor är obligatoriska respektive\\nvalfria även för korta.\\n" ++msgstr "Obligatoriska respektive valfria argument för långa flaggor är obligatoriska\\nrespektive valfria även för korta.\\n" + + #: elf/sotruss.sh:55 + msgid "%s: option requires an argument -- '%s'\\n" +-msgstr "%s: flaggan kräver ett argument -- \\\"%s\\\"\\n" ++msgstr "%s: flaggan kräver ett argument — ”%s”\\n" + + #: elf/sotruss.sh:61 + msgid "%s: option is ambiguous; possibilities:" +@@ -1240,7 +1241,7 @@ msgstr "" + + #: elf/sotruss.sh:134 + msgid "%s: unrecognized option '%c%s'\\n" +-msgstr "%s: okänd flagga \\\"%c%s\\\"\\n" ++msgstr "%s: okänd flagga ”%c%s”\\n" + + #: elf/sprof.c:77 + msgid "Output selection:" +@@ -1260,7 +1261,7 @@ msgstr "generera anropsgraf" + + #: elf/sprof.c:89 + msgid "Read and display shared object profiling data." +-msgstr "Läs och visa profildata för delat objekt" ++msgstr "Läs och visa profildata för delat objekt." + + #: elf/sprof.c:94 + msgid "SHOBJ [PROFDATA]" +@@ -1622,7 +1623,7 @@ msgstr "Fel: .netrc kan läsas av andra." + + #: inet/ruserpass.c:185 + msgid "Remove password or make file unreadable by others." +-msgstr "Ta bort lösenord eller gör filen oläsbar för andra" ++msgstr "Ta bort lösenord eller gör filen oläsbar för andra." + + #: inet/ruserpass.c:277 + #, c-format +@@ -2182,12 +2183,12 @@ msgstr "Inget namn definierat i teckenuppsättning" + #: locale/programs/ld-ctype.c:479 + #, c-format + msgid "character L'\\u%0*x' in class `%s' must be in class `%s'" +-msgstr "tecken L\"\\u%0*x\" i klass \"%s\" måste vara i klass \"%s\"" ++msgstr "tecken L'\\u%0*x' i klassen ”%s” måste vara i klassen ”%s”" + + #: locale/programs/ld-ctype.c:494 + #, c-format + msgid "character L'\\u%0*x' in class `%s' must not be in class `%s'" +-msgstr "tecken L\"\\u%0*x\" i klass \"%s\" får inte vara i klass \"%s\"" ++msgstr "tecken L'\\u%0*x' i klassen ”%s” får inte vara i klassen ”%s”" + + #: locale/programs/ld-ctype.c:508 locale/programs/ld-ctype.c:566 + #, c-format +@@ -2611,7 +2612,7 @@ msgstr "Skriv mer information" + + #: locale/programs/locale.c:85 + msgid "Get locale-specific information." +-msgstr "Hämta lokalspecifik information" ++msgstr "Hämta lokalspecifik information." + + #: locale/programs/locale.c:88 + msgid "" +@@ -3022,7 +3023,7 @@ msgstr "felaktig mcheck_status, biblioteket är felaktigt\n" + + #: malloc/memusage.sh:32 + msgid "%s: option '%s' requires an argument\\n" +-msgstr "%s: flaggan \\\"%s\\\" kräver ett argument\\n" ++msgstr "%s: flaggan ”%s” kräver ett argument\\n" + + #: malloc/memusage.sh:38 + msgid "" +@@ -3091,11 +3092,11 @@ msgstr "" + + #: malloc/memusage.sh:191 + msgid "memusage: option \\`${1##*=}' is ambiguous" +-msgstr "memusage: flaggan \"${1##*=}\" är tvetydig" ++msgstr "memusage: flaggan ”${1##*=}” är tvetydig" + + #: malloc/memusage.sh:200 + msgid "memusage: unrecognized option \\`$1'" +-msgstr "memusage: okänd flagga \"$1\"" ++msgstr "memusage: okänd flagga ”$1”" + + #: malloc/memusage.sh:213 + msgid "No program name given" +@@ -3341,7 +3342,7 @@ msgstr "Kan inte skapa process hos server" + + #: nis/nis_error.h:48 + msgid "Master server busy, full dump rescheduled." +-msgstr "Huvudserver är upptagen, full dump åter schemalagd" ++msgstr "Huvudserver är upptagen, full dump åter schemalagd." + + #: nis/nis_local_names.c:121 + #, c-format +@@ -3511,7 +3512,7 @@ msgstr "\t\tRättigheter : " + + #: nis/nis_print.c:290 + msgid "Linked Object Type : " +-msgstr "Länkad objekttyp: " ++msgstr "Länkad objekttyp : " + + #: nis/nis_print.c:292 + #, c-format +@@ -3802,15 +3803,14 @@ msgid " (first)" + msgstr " (första)" + + #: nscd/cache.c:288 +-#, fuzzy, c-format +-#| msgid "cannot stat() file `%s': %s" ++#, c-format + msgid "checking for monitored file `%s': %s" +-msgstr "kan inte ta status på fil \"%s\": %s" ++msgstr "kontrollerar den övervakade filen ”%s”: %s" + + #: nscd/cache.c:298 + #, c-format + msgid "monitored file `%s` changed (mtime)" +-msgstr "" ++msgstr "den övervakade filen ”%s” ändrades (mtime)" + + #: nscd/cache.c:341 + #, c-format +@@ -3906,34 +3906,32 @@ msgstr "kan inte få uttag (socket) att acceptera förbindelser: %s" + #: nscd/connections.c:973 + #, c-format + msgid "disabled inotify-based monitoring for file `%s': %s" +-msgstr "" ++msgstr "avaktiverade inotify-baserad övervakning för filen ”%s”: %s" + + #: nscd/connections.c:977 + #, c-format + msgid "monitoring file `%s` (%d)" +-msgstr "" ++msgstr "övervakar filen ”%s” (%d)" + + #: nscd/connections.c:990 + #, c-format + msgid "disabled inotify-based monitoring for directory `%s': %s" +-msgstr "" ++msgstr "avaktiverade inotify-baserad övervakning av katalogen ”%s”: %s" + + #: nscd/connections.c:994 +-#, fuzzy, c-format +-#| msgid "Can't open directory %s" ++#, c-format + msgid "monitoring directory `%s` (%d)" +-msgstr "Kan inte öppna katalog %s" ++msgstr "övervakar katalogen ”%s” (%d)" + + #: nscd/connections.c:1022 +-#, fuzzy, c-format +-#| msgid "register trace file %s for database %s" ++#, c-format + msgid "monitoring file %s for database %s" +-msgstr "registrera spårningsfil %s för databas %s" ++msgstr "övervakar filen %s för databas %s" + + #: nscd/connections.c:1032 + #, c-format + msgid "stat failed for file `%s'; will try again later: %s" +-msgstr "" ++msgstr "stat misslyckades för filen ”%s”; kommer försöka igen senare: %s" + + #: nscd/connections.c:1151 + #, c-format +@@ -4032,44 +4030,42 @@ msgstr "handle_request: begäran mottagen (Version = %d)" + #: nscd/connections.c:1963 + #, c-format + msgid "ignored inotify event for `%s` (file exists)" +-msgstr "" ++msgstr "ignorerade inotify-händelse för ”%s” (filen finns)" + + #: nscd/connections.c:1968 + #, c-format + msgid "monitored file `%s` was %s, removing watch" +-msgstr "" ++msgstr "den övervakade filen ”%s” var %s, tar bort vakten" + + #: nscd/connections.c:1976 nscd/connections.c:2018 + #, c-format + msgid "failed to remove file watch `%s`: %s" +-msgstr "" ++msgstr "misslyckades att ta bort filvakt ”%s”: %s" + + #: nscd/connections.c:1991 + #, c-format + msgid "monitored file `%s` was written to" +-msgstr "" ++msgstr "den övervakade filen ”%s” skrevs till" + + #: nscd/connections.c:2015 + #, c-format + msgid "monitored parent directory `%s` was %s, removing watch on `%s`" +-msgstr "" ++msgstr "den övervakade föräldrakatalogen ”%s” var %s, tar bort vakten av ”%s”" + + #: nscd/connections.c:2041 + #, c-format + msgid "monitored file `%s` was %s, adding watch" +-msgstr "" ++msgstr "den övervakade filen ”%s” var %s, lägger till vakt" + + #: nscd/connections.c:2053 +-#, fuzzy, c-format +-#| msgid "failed to load shared object `%s'" ++#, c-format + msgid "failed to add file watch `%s`: %s" +-msgstr "misslyckades med att ladda delat objekt \"%s\"" ++msgstr "misslyckades med att lägga till filvakt ”%s”: %s" + + #: nscd/connections.c:2247 nscd/connections.c:2428 +-#, fuzzy, c-format +-#| msgid "disabled inotify after read error %d" ++#, c-format + msgid "disabled inotify-based monitoring after read error %d" +-msgstr "inaktiverade inotify efter läsfel %d" ++msgstr "avaktiverade inotify-baserad övervakning efter läsfel %d" + + #: nscd/connections.c:2543 + msgid "could not initialize conditional variable" +@@ -4199,7 +4195,7 @@ msgstr "Använd separat cache för varje användare" + + #: nscd/nscd.c:122 + msgid "Name Service Cache Daemon." +-msgstr "Namntjänst cache-demon" ++msgstr "Cache-demon för namntjänsten." + + #: nscd/nscd.c:155 nss/getent.c:1007 nss/makedb.c:206 + #, c-format +@@ -4531,11 +4527,11 @@ msgstr "Access Vector Cache (AVC) startad" + + #: nscd/selinux.c:368 + msgid "Error querying policy for undefined object classes or permissions." +-msgstr "Fel när policy för odefinierade objektklasser eller rättigheter hämtades" ++msgstr "Fel när policy för odefinierade objektklasser eller rättigheter hämtades." + + #: nscd/selinux.c:375 + msgid "Error getting security class for nscd." +-msgstr "Fel när säkerhetsklass för nscd hämtades" ++msgstr "Fel när säkerhetsklass för nscd hämtades." + + #: nscd/selinux.c:380 + #, c-format +@@ -4609,7 +4605,7 @@ msgstr "inaktivera DIN-kodning" + + #: nss/getent.c:64 + msgid "Get entries from administrative database." +-msgstr "Hämta poster från den administrativa databasen" ++msgstr "Hämta poster från den administrativa databasen." + + #: nss/getent.c:148 nss/getent.c:477 nss/getent.c:522 + #, c-format +@@ -4652,7 +4648,7 @@ msgstr "Genererad rad som inte ingår i iterationen" + + #: nss/makedb.c:131 + msgid "Create simple database from textual input." +-msgstr "Skapa en enkel databas från textuell indata" ++msgstr "Skapa en enkel databas från textuell indata." + + #: nss/makedb.c:134 + msgid "" +@@ -5412,7 +5408,7 @@ msgstr "Kan inte ange netid-flaggan utan TIRPC!\n" + #: sunrpc/rpc_main.c:1374 + #, c-format + msgid "Cannot use table flags with newstyle!\n" +-msgstr "Kan inte ange tabellflaggor med ny stil\n" ++msgstr "Kan inte ange tabellflaggor med ny stil!\n" + + #: sunrpc/rpc_main.c:1393 + #, c-format +@@ -7270,18 +7266,9 @@ msgstr "tidszonsförkortning skiljer sig från POSIX-standarden" + + #: timezone/zic.c:2789 + msgid "too many, or too long, time zone abbreviations" +-msgstr "för många eller för långa tidszonförkortningar" ++msgstr "för många eller för långa tidszonsförkortningar" + + #: timezone/zic.c:2829 + #, c-format + msgid "%s: Can't create directory %s: %s\n" + msgstr "%s: Kan inte skapa katalog %s: %s\n" +- +-#~ msgid "cannot load any more object with static TLS" +-#~ msgstr "kan inte ladda fler objekt med statiskt TLS" +- +-#~ msgid "%s: no PLTREL found in object %s\n" +-#~ msgstr "%s: hittade inga PLTREL i objekt %s\n" +- +-#~ msgid "cannot create internal descriptors" +-#~ msgstr "kan inte skapa interna deskriptorer" +diff --git a/posix/execvpe.c b/posix/execvpe.c +index d933f9c92a..7cdb06a611 100644 +--- a/posix/execvpe.c ++++ b/posix/execvpe.c +@@ -48,12 +48,13 @@ maybe_script_execute (const char *file, char *const argv[], char *const envp[]) + } + } + +- /* Construct an argument list for the shell. */ ++ /* Construct an argument list for the shell. It will contain at minimum 3 ++ arguments (current shell, script, and an ending NULL. */ + char *new_argv[argc + 1]; + new_argv[0] = (char *) _PATH_BSHELL; + new_argv[1] = (char *) file; + if (argc > 1) +- memcpy (new_argv + 2, argv + 1, argc * sizeof(char *)); ++ memcpy (new_argv + 2, argv + 1, (argc - 1) * sizeof(char *)); + else + new_argv[2] = NULL; + +@@ -91,10 +92,11 @@ __execvpe (const char *file, char *const argv[], char *const envp[]) + /* Although GLIBC does not enforce NAME_MAX, we set it as the maximum + size to avoid unbounded stack allocation. Same applies for + PATH_MAX. */ +- size_t file_len = __strnlen (file, NAME_MAX + 1); ++ size_t file_len = __strnlen (file, NAME_MAX) + 1; + size_t path_len = __strnlen (path, PATH_MAX - 1) + 1; + +- if ((file_len > NAME_MAX) ++ /* NAME_MAX does not include the terminating null character. */ ++ if (((file_len-1) > NAME_MAX) + || !__libc_alloca_cutoff (path_len + file_len + 1)) + { + errno = ENAMETOOLONG; +@@ -103,6 +105,9 @@ __execvpe (const char *file, char *const argv[], char *const envp[]) + + const char *subp; + bool got_eacces = false; ++ /* The resulting string maximum size would be potentially a entry ++ in PATH plus '/' (path_len + 1) and then the the resulting file name ++ plus '\0' (file_len since it already accounts for the '\0'). */ + char buffer[path_len + file_len + 1]; + for (const char *p = path; ; p = subp) + { +@@ -123,7 +128,7 @@ __execvpe (const char *file, char *const argv[], char *const envp[]) + execute. */ + char *pend = mempcpy (buffer, p, subp - p); + *pend = '/'; +- memcpy (pend + (p < subp), file, file_len + 1); ++ memcpy (pend + (p < subp), file, file_len); + + __execve (buffer, argv, envp); + +diff --git a/resolv/Makefile b/resolv/Makefile +index 8be41d3ae1..a4c86b9762 100644 +--- a/resolv/Makefile ++++ b/resolv/Makefile +@@ -40,6 +40,9 @@ ifeq ($(have-thread-library),yes) + extra-libs += libanl + routines += gai_sigqueue + tests += tst-res_hconf_reorder ++ ++# This test sends millions of packets and is rather slow. ++xtests += tst-resolv-qtypes + endif + extra-libs-others = $(extra-libs) + libresolv-routines := gethnamaddr res_comp res_debug \ +@@ -117,3 +120,5 @@ tst-leaks2-ENV = MALLOC_TRACE=$(objpfx)tst-leaks2.mtrace + $(objpfx)mtrace-tst-leaks2.out: $(objpfx)tst-leaks2.out + $(common-objpfx)malloc/mtrace $(objpfx)tst-leaks2.mtrace > $@; \ + $(evaluate-test) ++ ++$(objpfx)tst-resolv-qtypes: $(objpfx)libresolv.so $(shared-thread-library) +diff --git a/resolv/nss_dns/dns-host.c b/resolv/nss_dns/dns-host.c +index 5f9e35701b..d16fa4b8ed 100644 +--- a/resolv/nss_dns/dns-host.c ++++ b/resolv/nss_dns/dns-host.c +@@ -323,7 +323,7 @@ _nss_dns_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat, + + int olderr = errno; + enum nss_status status; +- int n = __libc_res_nsearch (&_res, name, C_IN, T_UNSPEC, ++ int n = __libc_res_nsearch (&_res, name, C_IN, T_QUERY_A_AND_AAAA, + host_buffer.buf->buf, 2048, &host_buffer.ptr, + &ans2p, &nans2p, &resplen2, &ans2p_malloced); + if (n >= 0) +diff --git a/resolv/res_mkquery.c b/resolv/res_mkquery.c +index 12f9730199..d80b5318e5 100644 +--- a/resolv/res_mkquery.c ++++ b/resolv/res_mkquery.c +@@ -103,6 +103,10 @@ res_nmkquery(res_state statp, + int n; + u_char *dnptrs[20], **dpp, **lastdnptr; + ++ if (class < 0 || class > 65535 ++ || type < 0 || type > 65535) ++ return -1; ++ + #ifdef DEBUG + if (statp->options & RES_DEBUG) + printf(";; res_nmkquery(%s, %s, %s, %s)\n", +diff --git a/resolv/res_query.c b/resolv/res_query.c +index 944d1a90f5..07dc6f6583 100644 +--- a/resolv/res_query.c ++++ b/resolv/res_query.c +@@ -122,7 +122,7 @@ __libc_res_nquery(res_state statp, + int n, use_malloc = 0; + u_int oflags = statp->_flags; + +- size_t bufsize = (type == T_UNSPEC ? 2 : 1) * QUERYSIZE; ++ size_t bufsize = (type == T_QUERY_A_AND_AAAA ? 2 : 1) * QUERYSIZE; + u_char *buf = alloca (bufsize); + u_char *query1 = buf; + int nquery1 = -1; +@@ -137,7 +137,7 @@ __libc_res_nquery(res_state statp, + printf(";; res_query(%s, %d, %d)\n", name, class, type); + #endif + +- if (type == T_UNSPEC) ++ if (type == T_QUERY_A_AND_AAAA) + { + n = res_nmkquery(statp, QUERY, name, class, T_A, NULL, 0, NULL, + query1, bufsize); +@@ -190,7 +190,7 @@ __libc_res_nquery(res_state statp, + if (__builtin_expect (n <= 0, 0) && !use_malloc) { + /* Retry just in case res_nmkquery failed because of too + short buffer. Shouldn't happen. */ +- bufsize = (type == T_UNSPEC ? 2 : 1) * MAXPACKET; ++ bufsize = (type == T_QUERY_A_AND_AAAA ? 2 : 1) * MAXPACKET; + buf = malloc (bufsize); + if (buf != NULL) { + query1 = buf; +diff --git a/resolv/tst-resolv-qtypes.c b/resolv/tst-resolv-qtypes.c +new file mode 100644 +index 0000000000..b3e60c693b +--- /dev/null ++++ b/resolv/tst-resolv-qtypes.c +@@ -0,0 +1,185 @@ ++/* Exercise low-level query functions with different QTYPEs. ++ Copyright (C) 2016 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <resolv.h> ++#include <string.h> ++#include <support/check.h> ++#include <support/check_nss.h> ++#include <support/resolv_test.h> ++#include <support/support.h> ++#include <support/test-driver.h> ++#include <support/xmemstream.h> ++ ++/* If ture, the response function will send the actual response packet ++ over TCP instead of UDP. */ ++static volatile bool force_tcp; ++ ++/* Send back a fake resource record matching the QTYPE. */ ++static void ++response (const struct resolv_response_context *ctx, ++ struct resolv_response_builder *b, ++ const char *qname, uint16_t qclass, uint16_t qtype) ++{ ++ if (force_tcp && ctx->tcp) ++ { ++ resolv_response_init (b, (struct resolv_response_flags) { .tc = 1 }); ++ resolv_response_add_question (b, qname, qclass, qtype); ++ return; ++ } ++ ++ resolv_response_init (b, (struct resolv_response_flags) { }); ++ resolv_response_add_question (b, qname, qclass, qtype); ++ resolv_response_section (b, ns_s_an); ++ resolv_response_open_record (b, qname, qclass, qtype, 0); ++ resolv_response_add_data (b, &qtype, sizeof (qtype)); ++ resolv_response_close_record (b); ++} ++ ++static const const char *domain = "www.example.com"; ++ ++static int ++wrap_res_query (int type, unsigned char *answer, int answer_length) ++{ ++ return res_query (domain, C_IN, type, answer, answer_length); ++} ++ ++static int ++wrap_res_search (int type, unsigned char *answer, int answer_length) ++{ ++ return res_query (domain, C_IN, type, answer, answer_length); ++} ++ ++static int ++wrap_res_querydomain (int type, unsigned char *answer, int answer_length) ++{ ++ return res_querydomain ("www", "example.com", C_IN, type, ++ answer, answer_length); ++} ++ ++static int ++wrap_res_send (int type, unsigned char *answer, int answer_length) ++{ ++ unsigned char buf[512]; ++ int ret = res_mkquery (QUERY, domain, C_IN, type, ++ (const unsigned char *) "", 0, NULL, ++ buf, sizeof (buf)); ++ if (type < 0 || type >= 65536) ++ { ++ /* res_mkquery fails for out-of-range record types. */ ++ TEST_VERIFY_EXIT (ret == -1); ++ return -1; ++ } ++ TEST_VERIFY_EXIT (ret > 12); /* DNS header length. */ ++ return res_send (buf, ret, answer, answer_length); ++} ++ ++static int ++wrap_res_nquery (int type, unsigned char *answer, int answer_length) ++{ ++ return res_nquery (&_res, domain, C_IN, type, answer, answer_length); ++} ++ ++static int ++wrap_res_nsearch (int type, unsigned char *answer, int answer_length) ++{ ++ return res_nquery (&_res, domain, C_IN, type, answer, answer_length); ++} ++ ++static int ++wrap_res_nquerydomain (int type, unsigned char *answer, int answer_length) ++{ ++ return res_nquerydomain (&_res, "www", "example.com", C_IN, type, ++ answer, answer_length); ++} ++ ++static int ++wrap_res_nsend (int type, unsigned char *answer, int answer_length) ++{ ++ unsigned char buf[512]; ++ int ret = res_nmkquery (&_res, QUERY, domain, C_IN, type, ++ (const unsigned char *) "", 0, NULL, ++ buf, sizeof (buf)); ++ if (type < 0 || type >= 65536) ++ { ++ /* res_mkquery fails for out-of-range record types. */ ++ TEST_VERIFY_EXIT (ret == -1); ++ return -1; ++ } ++ TEST_VERIFY_EXIT (ret > 12); /* DNS header length. */ ++ return res_nsend (&_res, buf, ret, answer, answer_length); ++} ++ ++static void ++test_function (const char *fname, ++ int (*func) (int type, ++ unsigned char *answer, int answer_length)) ++{ ++ unsigned char buf[512]; ++ for (int tcp = 0; tcp < 2; ++tcp) ++ { ++ force_tcp = tcp; ++ for (unsigned int type = 1; type <= 65535; ++type) ++ { ++ if (test_verbose) ++ printf ("info: sending QTYPE %d with %s (tcp=%d)\n", ++ type, fname, tcp); ++ int ret = func (type, buf, sizeof (buf)); ++ if (ret != 47) ++ FAIL_EXIT1 ("%s tcp=%d qtype=%d return value %d", ++ fname,tcp, type, ret); ++ /* One question, one answer record. */ ++ TEST_VERIFY (memcmp (buf + 4, "\0\1\0\1\0\0\0\0", 8) == 0); ++ /* Question section. */ ++ static const char qname[] = "\3www\7example\3com"; ++ size_t qname_length = sizeof (qname); ++ TEST_VERIFY (memcmp (buf + 12, qname, qname_length) == 0); ++ /* RDATA part of answer. */ ++ uint16_t type16 = type; ++ TEST_VERIFY (memcmp (buf + ret - 2, &type16, sizeof (type16)) == 0); ++ } ++ } ++ ++ TEST_VERIFY (func (-1, buf, sizeof (buf) == -1)); ++ TEST_VERIFY (func (65536, buf, sizeof (buf) == -1)); ++} ++ ++static int ++do_test (void) ++{ ++ struct resolv_redirect_config config = ++ { ++ .response_callback = response, ++ }; ++ struct resolv_test *obj = resolv_test_start (config); ++ ++ test_function ("res_query", &wrap_res_query); ++ test_function ("res_search", &wrap_res_search); ++ test_function ("res_querydomain", &wrap_res_querydomain); ++ test_function ("res_send", &wrap_res_send); ++ ++ test_function ("res_nquery", &wrap_res_nquery); ++ test_function ("res_nsearch", &wrap_res_nsearch); ++ test_function ("res_nquerydomain", &wrap_res_nquerydomain); ++ test_function ("res_nsend", &wrap_res_nsend); ++ ++ resolv_test_end (obj); ++ return 0; ++} ++ ++#define TIMEOUT 300 ++#include <support/test-driver.c> +diff --git a/scripts/backport-support.sh b/scripts/backport-support.sh +new file mode 100644 +index 0000000000..2ece7ce575 +--- /dev/null ++++ b/scripts/backport-support.sh +@@ -0,0 +1,110 @@ ++#!/bin/bash ++# Create a patch which backports the support/ subdirectory. ++# Copyright (C) 2017 Free Software Foundation, Inc. ++# This file is part of the GNU C Library. ++ ++# The GNU C Library is free software; you can redistribute it and/or ++# modify it under the terms of the GNU Lesser General Public ++# License as published by the Free Software Foundation; either ++# version 2.1 of the License, or (at your option) any later version. ++ ++# The GNU C Library 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 ++# Lesser General Public License for more details. ++ ++# You should have received a copy of the GNU Lesser General Public ++# License along with the GNU C Library; if not, see ++# <http://www.gnu.org/licenses/>. ++ ++# This script does not backport the Makefile tweaks outside the ++# support/ directory (which need to be backported separately), or the ++# changes to test-skeleton.c (which should not be backported). ++ ++set -e ++ ++export LC_ALL=C ++export GIT_CONFIG=/dev/null ++export GTT_CONFIG_NOSYSTEM=0 ++export GIT_PAGER= ++ ++usage () { ++ cat >&2 <<EOF ++usage: $0 {patch|commit} ++EOF ++ exit 1 ++} ++ ++if test $# -ne 1 ; then ++ usage ++fi ++ ++command="$1" ++ ++case "$command" in ++ patch|commit) ++ ;; ++ *) ++ usage ++ ;; ++esac ++ ++# The upstream branch to work on. ++branch=origin/master ++ ++# The commit which added the support/ directory. ++initial_commit=c23de0aacbeaa7a091609b35764bed931475a16d ++ ++# We backport the support directory and this script. Directories need ++# to end in a /. ++patch_targets="support/ scripts/backport-support.sh" ++ ++latest_commit="$(git log --max-count=1 --pretty=format:%H "$branch" -- \ ++ $patch_targets)" ++ ++# Simplify the branch name somewhat for reporting. ++branch_name="$(echo "$branch" | sed s,^origin/,,)" ++ ++command_patch () { ++ cat <<EOF ++This patch creates the contents of the support/ directory up to this ++upstream commit on the $branch_name branch: ++ ++EOF ++ git log --max-count=1 "$latest_commit" ++ echo ++ git diff "$initial_commit"^.."$latest_commit" $patch_targets ++ echo "# Before applying the patch, run this command:" >&2 ++ echo "# rm -rf $patch_targets" >&2 ++} ++ ++command_commit () { ++ git status --porcelain | while read line ; do ++ echo "error: working copy is not clean, cannot commit" >&2 ++ exit 1 ++ done ++ for path in $patch_targets; do ++ echo "# Processing $path" >&2 ++ case "$path" in ++ [a-zA-Z0-9]*/) ++ # Directory. ++ git rm --cached --ignore-unmatch -r "$path" ++ rm -rf "$path" ++ git read-tree --prefix="$path" "$latest_commit":"$path" ++ git checkout "$path" ++ ;; ++ *) ++ # File. ++ git show "$latest_commit":"$path" > "$path" ++ git add "$path" ++ esac ++ done ++ git commit -m "Synchronize support/ infrastructure with $branch_name ++ ++This commit updates the support/ subdirectory to ++commit $latest_commit ++on the $branch_name branch. ++" ++} ++ ++command_$command +diff --git a/support/Makefile b/support/Makefile +new file mode 100644 +index 0000000000..20b0343ade +--- /dev/null ++++ b/support/Makefile +@@ -0,0 +1,146 @@ ++# Makefile for support library, used only at build and test time ++# Copyright (C) 2016-2017 Free Software Foundation, Inc. ++# This file is part of the GNU C Library. ++ ++# The GNU C Library is free software; you can redistribute it and/or ++# modify it under the terms of the GNU Lesser General Public ++# License as published by the Free Software Foundation; either ++# version 2.1 of the License, or (at your option) any later version. ++ ++# The GNU C Library 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 ++# Lesser General Public License for more details. ++ ++# You should have received a copy of the GNU Lesser General Public ++# License along with the GNU C Library; if not, see ++# <http://www.gnu.org/licenses/>. ++ ++subdir := support ++ ++include ../Makeconfig ++ ++extra-libs := libsupport ++extra-libs-others = $(extra-libs) ++extra-libs-noinstall := $(extra-libs) ++ ++libsupport-routines = \ ++ check \ ++ check_addrinfo \ ++ check_dns_packet \ ++ check_hostent \ ++ check_netent \ ++ delayed_exit \ ++ ignore_stderr \ ++ oom_error \ ++ resolv_test \ ++ set_fortify_handler \ ++ support-xstat \ ++ support_become_root \ ++ support_can_chroot \ ++ support_capture_subprocess \ ++ support_capture_subprocess_check \ ++ support_enter_network_namespace \ ++ support_format_address_family \ ++ support_format_addrinfo \ ++ support_format_dns_packet \ ++ support_format_herrno \ ++ support_format_hostent \ ++ support_format_netent \ ++ support_isolate_in_subprocess \ ++ support_record_failure \ ++ support_run_diff \ ++ support_shared_allocate \ ++ support_write_file_string \ ++ support_test_main \ ++ support_test_verify_impl \ ++ temp_file \ ++ write_message \ ++ xaccept \ ++ xaccept4 \ ++ xasprintf \ ++ xbind \ ++ xcalloc \ ++ xchroot \ ++ xclose \ ++ xconnect \ ++ xdup2 \ ++ xfclose \ ++ xfopen \ ++ xfork \ ++ xgetsockname \ ++ xlisten \ ++ xmalloc \ ++ xmemstream \ ++ xmkdir \ ++ xmmap \ ++ xmunmap \ ++ xopen \ ++ xpipe \ ++ xpoll \ ++ xpthread_attr_destroy \ ++ xpthread_attr_init \ ++ xpthread_attr_setdetachstate \ ++ xpthread_attr_setstacksize \ ++ xpthread_barrier_destroy \ ++ xpthread_barrier_init \ ++ xpthread_barrier_wait \ ++ xpthread_cancel \ ++ xpthread_check_return \ ++ xpthread_cond_wait \ ++ xpthread_create \ ++ xpthread_detach \ ++ xpthread_join \ ++ xpthread_mutex_consistent \ ++ xpthread_mutex_destroy \ ++ xpthread_mutex_init \ ++ xpthread_mutex_lock \ ++ xpthread_mutex_unlock \ ++ xpthread_mutexattr_destroy \ ++ xpthread_mutexattr_init \ ++ xpthread_mutexattr_setprotocol \ ++ xpthread_mutexattr_setpshared \ ++ xpthread_mutexattr_setrobust \ ++ xpthread_mutexattr_settype \ ++ xpthread_once \ ++ xpthread_sigmask \ ++ xpthread_spin_lock \ ++ xpthread_spin_unlock \ ++ xrealloc \ ++ xrecvfrom \ ++ xsendto \ ++ xsetsockopt \ ++ xsocket \ ++ xstrdup \ ++ xwaitpid \ ++ xwrite \ ++ ++libsupport-static-only-routines := $(libsupport-routines) ++# Only build one variant of the library. ++libsupport-inhibit-o := .os ++ifeq ($(build-shared),yes) ++libsupport-inhibit-o += .o ++endif ++ ++tests = \ ++ README-testing \ ++ tst-support-namespace \ ++ tst-support_capture_subprocess \ ++ tst-support_format_dns_packet \ ++ tst-support_record_failure \ ++ ++ifeq ($(run-built-tests),yes) ++tests-special = \ ++ $(objpfx)tst-support_record_failure-2.out ++ ++$(objpfx)tst-support_record_failure-2.out: tst-support_record_failure-2.sh \ ++ $(objpfx)tst-support_record_failure ++ $(SHELL) $< $(common-objpfx) '$(test-program-prefix-before-env)' \ ++ '$(run-program-env)' '$(test-program-prefix-after-env)' \ ++ > $@; \ ++ $(evaluate-test) ++endif ++ ++$(objpfx)tst-support_format_dns_packet: $(common-objpfx)resolv/libresolv.so ++ ++include ../Rules +diff --git a/support/README b/support/README +new file mode 100644 +index 0000000000..476cfcda59 +--- /dev/null ++++ b/support/README +@@ -0,0 +1,29 @@ ++This subdirectory contains infrastructure which is not put into ++installed libraries, but may be linked into programs (installed or ++not) and tests. ++ ++# Error-checking wrappers ++ ++These wrappers test for error return codes an terminate the process on ++error. They are declared in these header files: ++ ++* support.h ++* xsignal.h ++* xthread.h ++ ++In general, new wrappers should be added to support.h if possible. ++However, support.h must remain fully compatible with C90 and therefore ++cannot include headers which use identifers not reserved in C90. If ++the wrappers need additional types, additional headers such as ++signal.h need to be introduced. ++ ++# Test framework ++ ++The test framework provides a main program for tests, including a ++timeout for hanging tests. See README-testing.c for a minimal ++example, and test-driver.c for details how to use it. The following ++header files provide related declarations: ++ ++* check.h ++* temp_file.h ++* test-driver.h +diff --git a/support/README-testing.c b/support/README-testing.c +new file mode 100644 +index 0000000000..9d289c3020 +--- /dev/null ++++ b/support/README-testing.c +@@ -0,0 +1,19 @@ ++/* This file contains an example test case which shows minimal use of ++ the test framework. Additional testing hooks are described in ++ <support/test-driver.c>. */ ++ ++/* This function will be called from the test driver. */ ++static int ++do_test (void) ++{ ++ if (3 == 5) ++ /* Indicate failure. */ ++ return 1; ++ else ++ /* Indicate success. */ ++ return 0; ++} ++ ++/* This file references do_test above and contains the definition of ++ the main function. */ ++#include <support/test-driver.c> +diff --git a/support/capture_subprocess.h b/support/capture_subprocess.h +new file mode 100644 +index 0000000000..43caf9bce4 +--- /dev/null ++++ b/support/capture_subprocess.h +@@ -0,0 +1,61 @@ ++/* Capture output from a subprocess. ++ Copyright (C) 2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#ifndef SUPPORT_CAPTURE_SUBPROCESS_H ++#define SUPPORT_CAPTURE_SUBPROCESS_H ++ ++#include <support/xmemstream.h> ++ ++struct support_capture_subprocess ++{ ++ struct xmemstream out; ++ struct xmemstream err; ++ int status; ++}; ++ ++/* Invoke CALLBACK (CLOSURE) in a subprocess and capture standard ++ output, standard error, and the exit status. The out.buffer and ++ err.buffer members in the result are null-terminated strings which ++ can be examined by the caller (out.out and err.out are NULL). */ ++struct support_capture_subprocess support_capture_subprocess ++ (void (*callback) (void *), void *closure); ++ ++/* Deallocate the subprocess data captured by ++ support_capture_subprocess. */ ++void support_capture_subprocess_free (struct support_capture_subprocess *); ++ ++enum support_capture_allow ++{ ++ /* No output is allowed. */ ++ sc_allow_none = 0x01, ++ /* Output to stdout is permitted. */ ++ sc_allow_stdout = 0x02, ++ /* Output to standard error is permitted. */ ++ sc_allow_stderr = 0x04, ++}; ++ ++/* Check that the subprocess exited with STATUS and that only the ++ allowed outputs happened. ALLOWED is a combination of ++ support_capture_allow flags. Report errors under the CONTEXT ++ message. */ ++void support_capture_subprocess_check (struct support_capture_subprocess *, ++ const char *context, int status, ++ int allowed) ++ __attribute__ ((nonnull (1, 2))); ++ ++#endif /* SUPPORT_CAPTURE_SUBPROCESS_H */ +diff --git a/support/check.c b/support/check.c +new file mode 100644 +index 0000000000..592f2bc856 +--- /dev/null ++++ b/support/check.c +@@ -0,0 +1,57 @@ ++/* Support code for reporting test results. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <support/check.h> ++ ++#include <stdarg.h> ++#include <stdio.h> ++#include <stdlib.h> ++#include <support/test-driver.h> ++ ++static void ++print_failure (const char *file, int line, const char *format, va_list ap) ++{ ++ printf ("error: %s:%d: ", file, line); ++ vprintf (format, ap); ++ puts (""); ++} ++ ++int ++support_print_failure_impl (const char *file, int line, ++ const char *format, ...) ++{ ++ support_record_failure (); ++ va_list ap; ++ va_start (ap, format); ++ print_failure (file, line, format, ap); ++ va_end (ap); ++ return 1; ++} ++ ++void ++support_exit_failure_impl (int status, const char *file, int line, ++ const char *format, ...) ++{ ++ if (status != EXIT_SUCCESS && status != EXIT_UNSUPPORTED) ++ support_record_failure (); ++ va_list ap; ++ va_start (ap, format); ++ print_failure (file, line, format, ap); ++ va_end (ap); ++ exit (status); ++} +diff --git a/support/check.h b/support/check.h +new file mode 100644 +index 0000000000..1d244a3557 +--- /dev/null ++++ b/support/check.h +@@ -0,0 +1,94 @@ ++/* Functionality for reporting test results. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#ifndef SUPPORT_CHECK_H ++#define SUPPORT_CHECK_H ++ ++#include <sys/cdefs.h> ++ ++__BEGIN_DECLS ++ ++/* Record a test failure, print the failure message to standard output ++ and return 1. */ ++#define FAIL_RET(...) \ ++ return support_print_failure_impl (__FILE__, __LINE__, __VA_ARGS__) ++ ++/* Print the failure message and terminate the process with STATUS. ++ Record a the process as failed if STATUS is neither EXIT_SUCCESS ++ nor EXIT_UNSUPPORTED. */ ++#define FAIL_EXIT(status, ...) \ ++ support_exit_failure_impl (status, __FILE__, __LINE__, __VA_ARGS__) ++ ++/* Record a test failure, print the failure message and terminate with ++ exit status 1. */ ++#define FAIL_EXIT1(...) \ ++ support_exit_failure_impl (1, __FILE__, __LINE__, __VA_ARGS__) ++ ++/* Print failure message and terminate with as unsupported test (exit ++ status of 77). */ ++#define FAIL_UNSUPPORTED(...) \ ++ support_exit_failure_impl (77, __FILE__, __LINE__, __VA_ARGS__) ++ ++/* Record a test failure (but continue executing) if EXPR evaluates to ++ false. */ ++#define TEST_VERIFY(expr) \ ++ ({ \ ++ if (expr) \ ++ ; \ ++ else \ ++ support_test_verify_impl (-1, __FILE__, __LINE__, #expr); \ ++ }) ++ ++/* Record a test failure and exit if EXPR evaluates to false. */ ++#define TEST_VERIFY_EXIT(expr) \ ++ ({ \ ++ if (expr) \ ++ ; \ ++ else \ ++ support_test_verify_impl (1, __FILE__, __LINE__, #expr); \ ++ }) ++ ++int support_print_failure_impl (const char *file, int line, ++ const char *format, ...) ++ __attribute__ ((nonnull (1), format (printf, 3, 4))); ++void support_exit_failure_impl (int exit_status, ++ const char *file, int line, ++ const char *format, ...) ++ __attribute__ ((noreturn, nonnull (2), format (printf, 4, 5))); ++void support_test_verify_impl (int status, const char *file, int line, ++ const char *expr); ++ ++/* Record a test failure. This function returns and does not ++ terminate the process. The failure counter is stored in a shared ++ memory mapping, so that failures reported in child processes are ++ visible to the parent process and test driver. This function ++ depends on initialization by an ELF constructor, so it can only be ++ invoked after the test driver has run. Note that this function ++ does not support reporting failures from a DSO. */ ++void support_record_failure (void); ++ ++/* Internal function called by the test driver. */ ++int support_report_failure (int status) ++ __attribute__ ((weak, warn_unused_result)); ++ ++/* Internal function used to test the failure recording framework. */ ++void support_record_failure_reset (void); ++ ++__END_DECLS ++ ++#endif /* SUPPORT_CHECK_H */ +diff --git a/support/check_addrinfo.c b/support/check_addrinfo.c +new file mode 100644 +index 0000000000..55895ace3c +--- /dev/null ++++ b/support/check_addrinfo.c +@@ -0,0 +1,42 @@ ++/* Compare struct addrinfo values against a formatted string. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <support/check_nss.h> ++ ++#include <stdio.h> ++#include <stdlib.h> ++#include <support/check.h> ++#include <support/format_nss.h> ++#include <support/run_diff.h> ++ ++void ++check_addrinfo (const char *query_description, struct addrinfo *ai, int ret, ++ const char *expected) ++{ ++ char *formatted = support_format_addrinfo (ai, ret); ++ if (strcmp (formatted, expected) != 0) ++ { ++ support_record_failure (); ++ printf ("error: addrinfo comparison failure\n"); ++ if (query_description != NULL) ++ printf ("query: %s\n", query_description); ++ support_run_diff ("expected", expected, ++ "actual", formatted); ++ } ++ free (formatted); ++} +diff --git a/support/check_dns_packet.c b/support/check_dns_packet.c +new file mode 100644 +index 0000000000..d2a31bed7b +--- /dev/null ++++ b/support/check_dns_packet.c +@@ -0,0 +1,42 @@ ++/* Check that a DNS packet buffer has the expected contents. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <support/check_nss.h> ++ ++#include <stdio.h> ++#include <stdlib.h> ++#include <support/check.h> ++#include <support/format_nss.h> ++#include <support/run_diff.h> ++ ++void ++check_dns_packet (const char *query_description, ++ const unsigned char *buffer, size_t length, ++ const char *expected) ++{ ++ char *formatted = support_format_dns_packet (buffer, length); ++ if (strcmp (formatted, expected) != 0) ++ { ++ support_record_failure (); ++ printf ("error: packet comparison failure\n"); ++ if (query_description != NULL) ++ printf ("query: %s\n", query_description); ++ support_run_diff ("expected", expected, "actual", formatted); ++ } ++ free (formatted); ++} +diff --git a/support/check_hostent.c b/support/check_hostent.c +new file mode 100644 +index 0000000000..890d672d50 +--- /dev/null ++++ b/support/check_hostent.c +@@ -0,0 +1,42 @@ ++/* Compare struct hostent values against a formatted string. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <support/check_nss.h> ++ ++#include <stdio.h> ++#include <stdlib.h> ++#include <support/check.h> ++#include <support/format_nss.h> ++#include <support/run_diff.h> ++ ++void ++check_hostent (const char *query_description, struct hostent *h, ++ const char *expected) ++{ ++ char *formatted = support_format_hostent (h); ++ if (strcmp (formatted, expected) != 0) ++ { ++ support_record_failure (); ++ printf ("error: hostent comparison failure\n"); ++ if (query_description != NULL) ++ printf ("query: %s\n", query_description); ++ support_run_diff ("expected", expected, ++ "actual", formatted); ++ } ++ free (formatted); ++} +diff --git a/support/check_netent.c b/support/check_netent.c +new file mode 100644 +index 0000000000..daa3083fd1 +--- /dev/null ++++ b/support/check_netent.c +@@ -0,0 +1,42 @@ ++/* Compare struct netent values against a formatted string. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <support/check_nss.h> ++ ++#include <stdio.h> ++#include <stdlib.h> ++#include <support/check.h> ++#include <support/format_nss.h> ++#include <support/run_diff.h> ++ ++void ++check_netent (const char *query_description, struct netent *e, ++ const char *expected) ++{ ++ char *formatted = support_format_netent (e); ++ if (strcmp (formatted, expected) != 0) ++ { ++ support_record_failure (); ++ printf ("error: netent comparison failure\n"); ++ if (query_description != NULL) ++ printf ("query: %s\n", query_description); ++ support_run_diff ("expected", expected, ++ "actual", formatted); ++ } ++ free (formatted); ++} +diff --git a/support/check_nss.h b/support/check_nss.h +new file mode 100644 +index 0000000000..2893f2c295 +--- /dev/null ++++ b/support/check_nss.h +@@ -0,0 +1,42 @@ ++/* Test verification functions for NSS- and DNS-related data. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#ifndef SUPPORT_CHECK_NSS_H ++#define SUPPORT_CHECK_NSS_H ++ ++#include <netdb.h> ++#include <sys/cdefs.h> ++ ++__BEGIN_DECLS ++ ++/* Compare the data structures against the expected values (which have ++ to be formatted according to the support_format_* functions in ++ <support/format_nss.h>). If there is a difference, a delayed test ++ failure is recorded, and a diff is written to standard output. */ ++void check_addrinfo (const char *query_description, ++ struct addrinfo *, int ret, const char *expected); ++void check_dns_packet (const char *query_description, ++ const unsigned char *, size_t, const char *expected); ++void check_hostent (const char *query_description, ++ struct hostent *, const char *expected); ++void check_netent (const char *query_description, ++ struct netent *, const char *expected); ++ ++__END_DECLS ++ ++#endif /* SUPPORT_CHECK_NSS_H */ +diff --git a/support/delayed_exit.c b/support/delayed_exit.c +new file mode 100644 +index 0000000000..67442f95df +--- /dev/null ++++ b/support/delayed_exit.c +@@ -0,0 +1,55 @@ ++/* Time-triggered process termination. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <support/xthread.h> ++#include <support/xsignal.h> ++ ++#include <stdint.h> ++#include <stdio.h> ++#include <stdlib.h> ++#include <support/check.h> ++#include <time.h> ++ ++static void * ++delayed_exit_thread (void *seconds_as_ptr) ++{ ++ int seconds = (uintptr_t) seconds_as_ptr; ++ struct timespec delay = { seconds, 0 }; ++ struct timespec remaining = { 0 }; ++ if (nanosleep (&delay, &remaining) != 0) ++ FAIL_EXIT1 ("nanosleep: %m"); ++ /* Exit the process sucessfully. */ ++ exit (0); ++ return NULL; ++} ++ ++void ++delayed_exit (int seconds) ++{ ++ /* Create the new thread with all signals blocked. */ ++ sigset_t all_blocked; ++ sigfillset (&all_blocked); ++ sigset_t old_set; ++ xpthread_sigmask (SIG_SETMASK, &all_blocked, &old_set); ++ /* Create a detached thread. */ ++ pthread_t thr = xpthread_create ++ (NULL, delayed_exit_thread, (void *) (uintptr_t) seconds); ++ xpthread_detach (thr); ++ /* Restore the original signal mask. */ ++ xpthread_sigmask (SIG_SETMASK, &old_set, NULL); ++} +diff --git a/support/format_nss.h b/support/format_nss.h +new file mode 100644 +index 0000000000..fb4597c238 +--- /dev/null ++++ b/support/format_nss.h +@@ -0,0 +1,41 @@ ++/* String formatting functions for NSS- and DNS-related data. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#ifndef SUPPORT_FORMAT_NSS_H ++#define SUPPORT_FORMAT_NSS_H ++ ++#include <netdb.h> ++#include <sys/cdefs.h> ++ ++__BEGIN_DECLS ++ ++/* The following functions format their arguments as human-readable ++ strings (which can span multiple lines). The caller must free the ++ returned buffer. For NULL pointers or failure status arguments, ++ error variables such as h_errno and errno are included in the ++ result. */ ++char *support_format_address_family (int); ++char *support_format_addrinfo (struct addrinfo *, int ret); ++char *support_format_dns_packet (const unsigned char *buffer, size_t length); ++char *support_format_herrno (int); ++char *support_format_hostent (struct hostent *); ++char *support_format_netent (struct netent *); ++ ++__END_DECLS ++ ++#endif /* SUPPORT_FORMAT_NSS_H */ +diff --git a/support/ignore_stderr.c b/support/ignore_stderr.c +new file mode 100644 +index 0000000000..7b77a2cd56 +--- /dev/null ++++ b/support/ignore_stderr.c +@@ -0,0 +1,38 @@ ++/* Avoid all the buffer overflow messages on stderr. ++ Copyright (C) 2015-2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <support/support.h> ++ ++#include <fcntl.h> ++#include <paths.h> ++#include <stdlib.h> ++#include <unistd.h> ++ ++void ++ignore_stderr (void) ++{ ++ int fd = open (_PATH_DEVNULL, O_WRONLY); ++ if (fd == -1) ++ close (STDERR_FILENO); ++ else ++ { ++ dup2 (fd, STDERR_FILENO); ++ close (fd); ++ } ++ setenv ("LIBC_FATAL_STDERR_", "1", 1); ++} +diff --git a/support/namespace.h b/support/namespace.h +new file mode 100644 +index 0000000000..e1ccaa1ef0 +--- /dev/null ++++ b/support/namespace.h +@@ -0,0 +1,65 @@ ++/* Entering namespaces for test case isolation. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#ifndef SUPPORT_NAMESPACE_H ++#define SUPPORT_NAMESPACE_H ++ ++#include <stdbool.h> ++#include <sys/cdefs.h> ++ ++__BEGIN_DECLS ++ ++/* Attempts to become root (or acquire root-like privileges), possibly ++ with the help of user namespaces. Return true if (restricted) root ++ privileges could be attained in some way. Print diagnostics to ++ standard output. ++ ++ Note that this function generally has to be called before a process ++ becomes multi-threaded, otherwise it may fail with insufficient ++ privileges on systems which would support this operation for ++ single-threaded processes. */ ++bool support_become_root (void); ++ ++/* Return true if this process can perform a chroot operation. In ++ general, this is only possible if support_become_root has been ++ called. Note that the actual test is performed in a subprocess, ++ after fork, so that the file system root of the original process is ++ not changed. */ ++bool support_can_chroot (void); ++ ++/* Enter a network namespace (and a UTS namespace if possible) and ++ configure the loopback interface. Return true if a network ++ namespace could be created. Print diagnostics to standard output. ++ If a network namespace could be created, but networking in it could ++ not be configured, terminate the process. It is recommended to ++ call support_become_root before this function so that the process ++ has sufficient privileges. */ ++bool support_enter_network_namespace (void); ++ ++/* Return true if support_enter_network_namespace managed to enter a ++ UTS namespace. */ ++bool support_in_uts_namespace (void); ++ ++/* Invoke CALLBACK (CLOSURE) in a subprocess created using fork. ++ Terminate the calling process if the subprocess exits with a ++ non-zero exit status. */ ++void support_isolate_in_subprocess (void (*callback) (void *), void *closure); ++ ++__END_DECLS ++ ++#endif +diff --git a/sysdeps/sparc/sparc64/fpu/s_fdimf.S b/support/oom_error.c +similarity index 69% +rename from sysdeps/sparc/sparc64/fpu/s_fdimf.S +rename to support/oom_error.c +index 356c23c4e3..7816978273 100644 +--- a/sysdeps/sparc/sparc64/fpu/s_fdimf.S ++++ b/support/oom_error.c +@@ -1,7 +1,6 @@ +-/* Compute positive difference, sparc 64-bit. +- Copyright (C) 2013-2016 Free Software Foundation, Inc. ++/* Reporting out-of-memory errors. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. +- Contributed by David S. Miller <davem@davemloft.net>. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public +@@ -17,15 +16,14 @@ + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +-#include <sysdep.h> ++#include <support/support.h> + +-ENTRY(__fdimf) +- fcmps %f1, %f3 +- fbug 1f +- nop +- fzeros %f1 +- fnegs %f1, %f3 +-1: retl +- fsubs %f1, %f3, %f0 +-END(__fdimf) +-weak_alias (__fdimf, fdimf) ++#include <stdio.h> ++#include <stdlib.h> ++ ++void ++oom_error (const char *function, size_t size) ++{ ++ printf ("%s: unable to allocate %zu bytes: %m\n", function, size); ++ exit (1); ++} +diff --git a/support/resolv_test.c b/support/resolv_test.c +new file mode 100644 +index 0000000000..050cd7154b +--- /dev/null ++++ b/support/resolv_test.c +@@ -0,0 +1,1202 @@ ++/* DNS test framework and libresolv redirection. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <support/resolv_test.h> ++ ++#include <arpa/inet.h> ++#include <errno.h> ++#include <fcntl.h> ++#include <nss.h> ++#include <resolv.h> ++#include <search.h> ++#include <stdlib.h> ++#include <string.h> ++#include <support/check.h> ++#include <support/namespace.h> ++#include <support/support.h> ++#include <support/test-driver.h> ++#include <support/xsocket.h> ++#include <support/xthread.h> ++#include <support/xunistd.h> ++#include <sys/uio.h> ++#include <unistd.h> ++ ++/* Response builder. */ ++ ++enum ++ { ++ max_response_length = 65536 ++ }; ++ ++/* List of pointers to be freed. The hash table implementation ++ (struct hsearch_data) does not provide a way to deallocate all ++ objects, so this approach is used to avoid memory leaks. */ ++struct to_be_freed ++{ ++ struct to_be_freed *next; ++ void *ptr; ++}; ++ ++struct resolv_response_builder ++{ ++ const unsigned char *query_buffer; ++ size_t query_length; ++ ++ size_t offset; /* Bytes written so far in buffer. */ ++ ns_sect section; /* Current section in the DNS packet. */ ++ unsigned int truncate_bytes; /* Bytes to remove at end of response. */ ++ bool drop; /* Discard generated response. */ ++ bool close; /* Close TCP client connection. */ ++ ++ /* Offset of the two-byte RDATA length field in the currently ++ written RDATA sub-structure. 0 if no RDATA is being written. */ ++ size_t current_rdata_offset; ++ ++ /* Hash table for locating targets for label compression. */ ++ struct hsearch_data compression_offsets; ++ /* List of pointers which need to be freed. Used for domain names ++ involved in label compression. */ ++ struct to_be_freed *to_be_freed; ++ ++ /* Must be last. Not zeroed for performance reasons. */ ++ unsigned char buffer[max_response_length]; ++}; ++ ++/* Response builder. */ ++ ++/* Add a pointer to the list of pointers to be freed when B is ++ deallocated. */ ++static void ++response_push_pointer_to_free (struct resolv_response_builder *b, void *ptr) ++{ ++ if (ptr == NULL) ++ return; ++ struct to_be_freed *e = xmalloc (sizeof (*e)); ++ *e = (struct to_be_freed) {b->to_be_freed, ptr}; ++ b->to_be_freed = e; ++} ++ ++void ++resolv_response_init (struct resolv_response_builder *b, ++ struct resolv_response_flags flags) ++{ ++ if (b->offset > 0) ++ FAIL_EXIT1 ("response_init: called at offset %zu", b->offset); ++ if (b->query_length < 12) ++ FAIL_EXIT1 ("response_init called for a query of size %zu", ++ b->query_length); ++ if (flags.rcode > 15) ++ FAIL_EXIT1 ("response_init: invalid RCODE %u", flags.rcode); ++ ++ /* Copy the transaction ID. */ ++ b->buffer[0] = b->query_buffer[0]; ++ b->buffer[1] = b->query_buffer[1]; ++ ++ /* Initialize the flags. */ ++ b->buffer[2] = 0x80; /* Mark as response. */ ++ b->buffer[2] |= b->query_buffer[2] & 0x01; /* Copy the RD bit. */ ++ if (flags.tc) ++ b->buffer[2] |= 0x02; ++ b->buffer[3] = 0x80 | flags.rcode; /* Always set RA. */ ++ ++ /* Fill in the initial section count values. */ ++ b->buffer[4] = flags.qdcount >> 8; ++ b->buffer[5] = flags.qdcount; ++ b->buffer[6] = flags.ancount >> 8; ++ b->buffer[7] = flags.ancount; ++ b->buffer[8] = flags.nscount >> 8; ++ b->buffer[9] = flags.nscount; ++ b->buffer[10] = flags.adcount >> 8; ++ b->buffer[11] = flags.adcount; ++ ++ b->offset = 12; ++} ++ ++void ++resolv_response_section (struct resolv_response_builder *b, ns_sect section) ++{ ++ if (b->offset == 0) ++ FAIL_EXIT1 ("resolv_response_section: response_init not called before"); ++ if (section < b->section) ++ FAIL_EXIT1 ("resolv_response_section: cannot go back to previous section"); ++ b->section = section; ++} ++ ++/* Add a single byte to B. */ ++static inline void ++response_add_byte (struct resolv_response_builder *b, unsigned char ch) ++{ ++ if (b->offset == max_response_length) ++ FAIL_EXIT1 ("DNS response exceeds 64 KiB limit"); ++ b->buffer[b->offset] = ch; ++ ++b->offset; ++} ++ ++/* Add a 16-bit word VAL to B, in big-endian format. */ ++static void ++response_add_16 (struct resolv_response_builder *b, uint16_t val) ++{ ++ response_add_byte (b, val >> 8); ++ response_add_byte (b, val); ++} ++ ++/* Increment the pers-section record counter in the packet header. */ ++static void ++response_count_increment (struct resolv_response_builder *b) ++{ ++ unsigned int offset = b->section; ++ offset = 4 + 2 * offset; ++ ++b->buffer[offset + 1]; ++ if (b->buffer[offset + 1] == 0) ++ { ++ /* Carry. */ ++ ++b->buffer[offset]; ++ if (b->buffer[offset] == 0) ++ /* Overflow. */ ++ FAIL_EXIT1 ("too many records in section"); ++ } ++} ++ ++void ++resolv_response_add_question (struct resolv_response_builder *b, ++ const char *name, uint16_t class, uint16_t type) ++{ ++ if (b->offset == 0) ++ FAIL_EXIT1 ("resolv_response_add_question: " ++ "resolv_response_init not called"); ++ if (b->section != ns_s_qd) ++ FAIL_EXIT1 ("resolv_response_add_question: " ++ "must be called in the question section"); ++ ++ resolv_response_add_name (b, name); ++ response_add_16 (b, type); ++ response_add_16 (b, class); ++ ++ response_count_increment (b); ++} ++ ++void ++resolv_response_add_name (struct resolv_response_builder *b, ++ const char *const origname) ++{ ++ /* Normalized name. */ ++ char *name; ++ /* Normalized name with case preserved. */ ++ char *name_case; ++ { ++ size_t namelen = strlen (origname); ++ /* Remove trailing dots. FIXME: Handle trailing quoted dots. */ ++ while (namelen > 0 && origname[namelen - 1] == '.') ++ --namelen; ++ name = xmalloc (namelen + 1); ++ name_case = xmalloc (namelen + 1); ++ /* Copy and convert to lowercase. FIXME: This needs to normalize ++ escaping as well. */ ++ for (size_t i = 0; i < namelen; ++i) ++ { ++ char ch = origname[i]; ++ name_case[i] = ch; ++ if ('A' <= ch && ch <= 'Z') ++ ch = ch - 'A' + 'a'; ++ name[i] = ch; ++ } ++ name[namelen] = 0; ++ name_case[namelen] = 0; ++ } ++ char *name_start = name; ++ char *name_case_start = name_case; ++ ++ bool compression = false; ++ while (*name) ++ { ++ /* Search for a previous name we can reference. */ ++ ENTRY new_entry = ++ { ++ .key = name, ++ .data = (void *) (uintptr_t) b->offset, ++ }; ++ ++ /* If the label can be a compression target because it is at a ++ reachable offset, add it to the hash table. */ ++ ACTION action; ++ if (b->offset < (1 << 12)) ++ action = ENTER; ++ else ++ action = FIND; ++ ++ /* Search for known compression offsets in the hash table. */ ++ ENTRY *e; ++ if (hsearch_r (new_entry, action, &e, &b->compression_offsets) == 0) ++ { ++ if (action == FIND && errno == ESRCH) ++ /* Fall through. */ ++ e = NULL; ++ else ++ FAIL_EXIT1 ("hsearch_r failure in name compression: %m"); ++ } ++ ++ /* The name is known. Reference the previous location. */ ++ if (e != NULL && e->data != new_entry.data) ++ { ++ size_t old_offset = (uintptr_t) e->data; ++ response_add_byte (b, 0xC0 | (old_offset >> 8)); ++ response_add_byte (b, old_offset); ++ compression = true; ++ break; ++ } ++ ++ /* The name does not exist yet. Write one label. First, add ++ room for the label length. */ ++ size_t buffer_label_offset = b->offset; ++ response_add_byte (b, 0); ++ ++ /* Copy the label. */ ++ while (true) ++ { ++ char ch = *name_case; ++ if (ch == '\0') ++ break; ++ ++name; ++ ++name_case; ++ if (ch == '.') ++ break; ++ /* FIXME: Handle escaping. */ ++ response_add_byte (b, ch); ++ } ++ ++ /* Patch in the label length. */ ++ size_t label_length = b->offset - buffer_label_offset - 1; ++ if (label_length == 0) ++ FAIL_EXIT1 ("empty label in name compression: %s", origname); ++ if (label_length > 63) ++ FAIL_EXIT1 ("label too long in name compression: %s", origname); ++ b->buffer[buffer_label_offset] = label_length; ++ ++ /* Continue with the tail of the name and the next label. */ ++ } ++ ++ if (compression) ++ { ++ /* If we found an immediate match for the name, we have not put ++ it into the hash table, and can free it immediately. */ ++ if (name == name_start) ++ free (name_start); ++ else ++ response_push_pointer_to_free (b, name_start); ++ } ++ else ++ { ++ /* Terminate the sequence of labels. With compression, this is ++ implicit in the compression reference. */ ++ response_add_byte (b, 0); ++ response_push_pointer_to_free (b, name_start); ++ } ++ ++ free (name_case_start); ++} ++ ++void ++resolv_response_open_record (struct resolv_response_builder *b, ++ const char *name, ++ uint16_t class, uint16_t type, uint32_t ttl) ++{ ++ if (b->section == ns_s_qd) ++ FAIL_EXIT1 ("resolv_response_open_record called in question section"); ++ if (b->current_rdata_offset != 0) ++ FAIL_EXIT1 ("resolv_response_open_record called with open record"); ++ ++ resolv_response_add_name (b, name); ++ response_add_16 (b, type); ++ response_add_16 (b, class); ++ response_add_16 (b, ttl >> 16); ++ response_add_16 (b, ttl); ++ ++ b->current_rdata_offset = b->offset; ++ /* Add room for the RDATA length. */ ++ response_add_16 (b, 0); ++} ++ ++ ++void ++resolv_response_close_record (struct resolv_response_builder *b) ++{ ++ size_t rdata_offset = b->current_rdata_offset; ++ if (rdata_offset == 0) ++ FAIL_EXIT1 ("response_close_record called without open record"); ++ size_t rdata_length = b->offset - rdata_offset - 2; ++ if (rdata_length > 65535) ++ FAIL_EXIT1 ("RDATA length %zu exceeds limit", rdata_length); ++ b->buffer[rdata_offset] = rdata_length >> 8; ++ b->buffer[rdata_offset + 1] = rdata_length; ++ response_count_increment (b); ++ b->current_rdata_offset = 0; ++} ++ ++void ++resolv_response_add_data (struct resolv_response_builder *b, ++ const void *data, size_t length) ++{ ++ size_t remaining = max_response_length - b->offset; ++ if (remaining < length) ++ FAIL_EXIT1 ("resolv_response_add_data: not enough room for %zu bytes", ++ length); ++ memcpy (b->buffer + b->offset, data, length); ++ b->offset += length; ++} ++ ++void ++resolv_response_drop (struct resolv_response_builder *b) ++{ ++ b->drop = true; ++} ++ ++void ++resolv_response_close (struct resolv_response_builder *b) ++{ ++ b->close = true; ++} ++ ++void ++resolv_response_truncate_data (struct resolv_response_builder *b, size_t count) ++{ ++ if (count > 65535) ++ FAIL_EXIT1 ("resolv_response_truncate_data: argument too large: %zu", ++ count); ++ b->truncate_bytes = count; ++} ++ ++ ++size_t ++resolv_response_length (const struct resolv_response_builder *b) ++{ ++ return b->offset; ++} ++ ++unsigned char * ++resolv_response_buffer (const struct resolv_response_builder *b) ++{ ++ unsigned char *result = xmalloc (b->offset); ++ memcpy (result, b->buffer, b->offset); ++ return result; ++} ++ ++static struct resolv_response_builder * ++response_builder_allocate ++ (const unsigned char *query_buffer, size_t query_length) ++{ ++ struct resolv_response_builder *b = xmalloc (sizeof (*b)); ++ memset (b, 0, offsetof (struct resolv_response_builder, buffer)); ++ b->query_buffer = query_buffer; ++ b->query_length = query_length; ++ TEST_VERIFY_EXIT (hcreate_r (10000, &b->compression_offsets) != 0); ++ return b; ++} ++ ++static void ++response_builder_free (struct resolv_response_builder *b) ++{ ++ struct to_be_freed *current = b->to_be_freed; ++ while (current != NULL) ++ { ++ struct to_be_freed *next = current->next; ++ free (current->ptr); ++ free (current); ++ current = next; ++ } ++ hdestroy_r (&b->compression_offsets); ++ free (b); ++} ++ ++/* DNS query processing. */ ++ ++/* Data extracted from the question section of a DNS packet. */ ++struct query_info ++{ ++ char qname[MAXDNAME]; ++ uint16_t qclass; ++ uint16_t qtype; ++ struct resolv_edns_info edns; ++}; ++ ++/* Update *INFO from the specified DNS packet. */ ++static void ++parse_query (struct query_info *info, ++ const unsigned char *buffer, size_t length) ++{ ++ HEADER hd; ++ _Static_assert (sizeof (hd) == 12, "DNS header size"); ++ if (length < sizeof (hd)) ++ FAIL_EXIT1 ("malformed DNS query: too short: %zu bytes", length); ++ memcpy (&hd, buffer, sizeof (hd)); ++ ++ if (ntohs (hd.qdcount) != 1) ++ FAIL_EXIT1 ("malformed DNS query: wrong question count: %d", ++ (int) ntohs (hd.qdcount)); ++ if (ntohs (hd.ancount) != 0) ++ FAIL_EXIT1 ("malformed DNS query: wrong answer count: %d", ++ (int) ntohs (hd.ancount)); ++ if (ntohs (hd.nscount) != 0) ++ FAIL_EXIT1 ("malformed DNS query: wrong authority count: %d", ++ (int) ntohs (hd.nscount)); ++ if (ntohs (hd.arcount) > 1) ++ FAIL_EXIT1 ("malformed DNS query: wrong additional count: %d", ++ (int) ntohs (hd.arcount)); ++ ++ int ret = dn_expand (buffer, buffer + length, buffer + sizeof (hd), ++ info->qname, sizeof (info->qname)); ++ if (ret < 0) ++ FAIL_EXIT1 ("malformed DNS query: cannot uncompress QNAME"); ++ ++ /* Obtain QTYPE and QCLASS. */ ++ size_t remaining = length - (12 + ret); ++ struct ++ { ++ uint16_t qtype; ++ uint16_t qclass; ++ } qtype_qclass; ++ if (remaining < sizeof (qtype_qclass)) ++ FAIL_EXIT1 ("malformed DNS query: " ++ "query lacks QCLASS/QTYPE, QNAME: %s", info->qname); ++ memcpy (&qtype_qclass, buffer + 12 + ret, sizeof (qtype_qclass)); ++ info->qclass = ntohs (qtype_qclass.qclass); ++ info->qtype = ntohs (qtype_qclass.qtype); ++ ++ memset (&info->edns, 0, sizeof (info->edns)); ++ if (ntohs (hd.arcount) > 0) ++ { ++ /* Parse EDNS record. */ ++ struct __attribute__ ((packed, aligned (1))) ++ { ++ uint8_t root; ++ uint16_t rtype; ++ uint16_t payload; ++ uint8_t edns_extended_rcode; ++ uint8_t edns_version; ++ uint16_t flags; ++ uint16_t rdatalen; ++ } rr; ++ _Static_assert (sizeof (rr) == 11, "EDNS record size"); ++ ++ if (remaining < 4 + sizeof (rr)) ++ FAIL_EXIT1 ("mailformed DNS query: no room for EDNS record"); ++ memcpy (&rr, buffer + 12 + ret + 4, sizeof (rr)); ++ if (rr.root != 0) ++ FAIL_EXIT1 ("malformed DNS query: invalid OPT RNAME: %d\n", rr.root); ++ if (rr.rtype != htons (41)) ++ FAIL_EXIT1 ("malformed DNS query: invalid OPT type: %d\n", ++ ntohs (rr.rtype)); ++ info->edns.active = true; ++ info->edns.extended_rcode = rr.edns_extended_rcode; ++ info->edns.version = rr.edns_version; ++ info->edns.flags = ntohs (rr.flags); ++ info->edns.payload_size = ntohs (rr.payload); ++ } ++} ++ ++ ++/* Main testing framework. */ ++ ++/* Per-server information. One struct is allocated for each test ++ server. */ ++struct resolv_test_server ++{ ++ /* Local address of the server. UDP and TCP use the same port. */ ++ struct sockaddr_in address; ++ ++ /* File descriptor of the UDP server, or -1 if this server is ++ disabled. */ ++ int socket_udp; ++ ++ /* File descriptor of the TCP server, or -1 if this server is ++ disabled. */ ++ int socket_tcp; ++ ++ /* Counter of the number of responses processed so far. */ ++ size_t response_number; ++ ++ /* Thread handles for the server threads (if not disabled in the ++ configuration). */ ++ pthread_t thread_udp; ++ pthread_t thread_tcp; ++}; ++ ++/* Main struct for keeping track of libresolv redirection and ++ testing. */ ++struct resolv_test ++{ ++ /* After initialization, any access to the struct must be performed ++ while this lock is acquired. */ ++ pthread_mutex_t lock; ++ ++ /* Data for each test server. */ ++ struct resolv_test_server servers[resolv_max_test_servers]; ++ ++ /* Used if config.single_thread_udp is true. */ ++ pthread_t thread_udp_single; ++ ++ struct resolv_redirect_config config; ++ bool termination_requested; ++}; ++ ++/* Function implementing a server thread. */ ++typedef void (*thread_callback) (struct resolv_test *, int server_index); ++ ++/* Storage for thread-specific data, for passing to the ++ thread_callback function. */ ++struct thread_closure ++{ ++ struct resolv_test *obj; /* Current test object. */ ++ thread_callback callback; /* Function to call. */ ++ int server_index; /* Index of the implemented server. */ ++}; ++ ++/* Wrap response_callback as a function which can be passed to ++ pthread_create. */ ++static void * ++thread_callback_wrapper (void *arg) ++{ ++ struct thread_closure *closure = arg; ++ closure->callback (closure->obj, closure->server_index); ++ free (closure); ++ return NULL; ++} ++ ++/* Start a server thread for the specified SERVER_INDEX, implemented ++ by CALLBACK. */ ++static pthread_t ++start_server_thread (struct resolv_test *obj, int server_index, ++ thread_callback callback) ++{ ++ struct thread_closure *closure = xmalloc (sizeof (*closure)); ++ *closure = (struct thread_closure) ++ { ++ .obj = obj, ++ .callback = callback, ++ .server_index = server_index, ++ }; ++ return xpthread_create (NULL, thread_callback_wrapper, closure); ++} ++ ++/* Process one UDP query. Return false if a termination requested has ++ been detected. */ ++static bool ++server_thread_udp_process_one (struct resolv_test *obj, int server_index) ++{ ++ unsigned char query[512]; ++ struct sockaddr_storage peer; ++ socklen_t peerlen = sizeof (peer); ++ size_t length = xrecvfrom (obj->servers[server_index].socket_udp, ++ query, sizeof (query), 0, ++ (struct sockaddr *) &peer, &peerlen); ++ /* Check for termination. */ ++ { ++ bool termination_requested; ++ xpthread_mutex_lock (&obj->lock); ++ termination_requested = obj->termination_requested; ++ xpthread_mutex_unlock (&obj->lock); ++ if (termination_requested) ++ return false; ++ } ++ ++ ++ struct query_info qinfo; ++ parse_query (&qinfo, query, length); ++ if (test_verbose > 0) ++ { ++ if (test_verbose > 1) ++ printf ("info: UDP server %d: incoming query:" ++ " %zd bytes, %s/%u/%u, tnxid=0x%02x%02x\n", ++ server_index, length, qinfo.qname, qinfo.qclass, qinfo.qtype, ++ query[0], query[1]); ++ else ++ printf ("info: UDP server %d: incoming query:" ++ " %zd bytes, %s/%u/%u\n", ++ server_index, length, qinfo.qname, qinfo.qclass, qinfo.qtype); ++ } ++ ++ struct resolv_response_context ctx = ++ { ++ .query_buffer = query, ++ .query_length = length, ++ .server_index = server_index, ++ .tcp = false, ++ .edns = qinfo.edns, ++ }; ++ struct resolv_response_builder *b = response_builder_allocate (query, length); ++ obj->config.response_callback ++ (&ctx, b, qinfo.qname, qinfo.qclass, qinfo.qtype); ++ ++ if (b->drop) ++ { ++ if (test_verbose) ++ printf ("info: UDP server %d: dropping response to %s/%u/%u\n", ++ server_index, qinfo.qname, qinfo.qclass, qinfo.qtype); ++ } ++ else ++ { ++ if (test_verbose) ++ { ++ if (b->offset >= 12) ++ printf ("info: UDP server %d: sending response:" ++ " %zu bytes, RCODE %d (for %s/%u/%u)\n", ++ server_index, b->offset, b->buffer[3] & 0x0f, ++ qinfo.qname, qinfo.qclass, qinfo.qtype); ++ else ++ printf ("info: UDP server %d: sending response: %zu bytes" ++ " (for %s/%u/%u)\n", ++ server_index, b->offset, ++ qinfo.qname, qinfo.qclass, qinfo.qtype); ++ if (b->truncate_bytes > 0) ++ printf ("info: truncated by %u bytes\n", b->truncate_bytes); ++ } ++ size_t to_send = b->offset; ++ if (to_send < b->truncate_bytes) ++ to_send = 0; ++ else ++ to_send -= b->truncate_bytes; ++ ++ /* Ignore most errors here because the other end may have closed ++ the socket. */ ++ if (sendto (obj->servers[server_index].socket_udp, ++ b->buffer, to_send, 0, ++ (struct sockaddr *) &peer, peerlen) < 0) ++ TEST_VERIFY_EXIT (errno != EBADF); ++ } ++ response_builder_free (b); ++ return true; ++} ++ ++/* UDP thread_callback function. Variant for one thread per ++ server. */ ++static void ++server_thread_udp (struct resolv_test *obj, int server_index) ++{ ++ while (server_thread_udp_process_one (obj, server_index)) ++ ; ++} ++ ++/* Single-threaded UDP processing function, for the single_thread_udp ++ case. */ ++static void * ++server_thread_udp_single (void *closure) ++{ ++ struct resolv_test *obj = closure; ++ ++ struct pollfd fds[resolv_max_test_servers]; ++ for (int server_index = 0; server_index < resolv_max_test_servers; ++ ++server_index) ++ if (obj->config.servers[server_index].disable_udp) ++ fds[server_index] = (struct pollfd) {.fd = -1}; ++ else ++ { ++ fds[server_index] = (struct pollfd) ++ { ++ .fd = obj->servers[server_index].socket_udp, ++ .events = POLLIN ++ }; ++ ++ /* Make the socket non-blocking. */ ++ int flags = fcntl (obj->servers[server_index].socket_udp, F_GETFL, 0); ++ if (flags < 0) ++ FAIL_EXIT1 ("fcntl (F_GETFL): %m"); ++ flags |= O_NONBLOCK; ++ if (fcntl (obj->servers[server_index].socket_udp, F_SETFL, flags) < 0) ++ FAIL_EXIT1 ("fcntl (F_SETFL): %m"); ++ } ++ ++ while (true) ++ { ++ xpoll (fds, resolv_max_test_servers, -1); ++ for (int server_index = 0; server_index < resolv_max_test_servers; ++ ++server_index) ++ if (fds[server_index].revents != 0) ++ { ++ if (!server_thread_udp_process_one (obj, server_index)) ++ goto out; ++ fds[server_index].revents = 0; ++ } ++ } ++ ++ out: ++ return NULL; ++} ++ ++/* Start the single UDP handler thread (for the single_thread_udp ++ case). */ ++static void ++start_server_thread_udp_single (struct resolv_test *obj) ++{ ++ obj->thread_udp_single ++ = xpthread_create (NULL, server_thread_udp_single, obj); ++} ++ ++/* Data describing a TCP client connect. */ ++struct tcp_thread_closure ++{ ++ struct resolv_test *obj; ++ int server_index; ++ int client_socket; ++}; ++ ++/* Read a complete DNS query packet. If EOF_OK, an immediate ++ end-of-file condition is acceptable. */ ++static bool ++read_fully (int fd, void *buf, size_t len, bool eof_ok) ++{ ++ const void *const end = buf + len; ++ while (buf < end) ++ { ++ ssize_t ret = read (fd, buf, end - buf); ++ if (ret == 0) ++ { ++ if (!eof_ok) ++ { ++ support_record_failure (); ++ printf ("error: unexpected EOF on TCP connection\n"); ++ } ++ return false; ++ } ++ else if (ret < 0) ++ { ++ if (!eof_ok || errno != ECONNRESET) ++ { ++ support_record_failure (); ++ printf ("error: TCP read: %m\n"); ++ } ++ return false; ++ } ++ buf += ret; ++ eof_ok = false; ++ } ++ return true; ++} ++ ++/* Write an array of iovecs. Terminate the process on failure. */ ++static void ++writev_fully (int fd, struct iovec *buffers, size_t count) ++{ ++ while (count > 0) ++ { ++ /* Skip zero-length write requests. */ ++ if (buffers->iov_len == 0) ++ { ++ ++buffers; ++ --count; ++ continue; ++ } ++ /* Try to rewrite the remaing buffers. */ ++ ssize_t ret = writev (fd, buffers, count); ++ if (ret < 0) ++ FAIL_EXIT1 ("writev: %m"); ++ if (ret == 0) ++ FAIL_EXIT1 ("writev: invalid return value zero"); ++ /* Find the buffers that were successfully written. */ ++ while (ret > 0) ++ { ++ if (count == 0) ++ FAIL_EXIT1 ("internal writev consistency failure"); ++ /* Current buffer was partially written. */ ++ if (buffers->iov_len > (size_t) ret) ++ { ++ buffers->iov_base += ret; ++ buffers->iov_len -= ret; ++ ret = 0; ++ } ++ else ++ { ++ ret -= buffers->iov_len; ++ buffers->iov_len = 0; ++ ++buffers; ++ --count; ++ } ++ } ++ } ++} ++ ++/* Thread callback for handling a single established TCP connection to ++ a client. */ ++static void * ++server_thread_tcp_client (void *arg) ++{ ++ struct tcp_thread_closure *closure = arg; ++ ++ while (true) ++ { ++ /* Read packet length. */ ++ uint16_t query_length; ++ if (!read_fully (closure->client_socket, ++ &query_length, sizeof (query_length), true)) ++ break; ++ query_length = ntohs (query_length); ++ ++ /* Read the packet. */ ++ unsigned char *query_buffer = xmalloc (query_length); ++ read_fully (closure->client_socket, query_buffer, query_length, false); ++ ++ struct query_info qinfo; ++ parse_query (&qinfo, query_buffer, query_length); ++ if (test_verbose > 0) ++ { ++ if (test_verbose > 1) ++ printf ("info: UDP server %d: incoming query:" ++ " %d bytes, %s/%u/%u, tnxid=0x%02x%02x\n", ++ closure->server_index, query_length, ++ qinfo.qname, qinfo.qclass, qinfo.qtype, ++ query_buffer[0], query_buffer[1]); ++ else ++ printf ("info: TCP server %d: incoming query:" ++ " %u bytes, %s/%u/%u\n", ++ closure->server_index, query_length, ++ qinfo.qname, qinfo.qclass, qinfo.qtype); ++ } ++ ++ struct resolv_response_context ctx = ++ { ++ .query_buffer = query_buffer, ++ .query_length = query_length, ++ .server_index = closure->server_index, ++ .tcp = true, ++ .edns = qinfo.edns, ++ }; ++ struct resolv_response_builder *b = response_builder_allocate ++ (query_buffer, query_length); ++ closure->obj->config.response_callback ++ (&ctx, b, qinfo.qname, qinfo.qclass, qinfo.qtype); ++ ++ if (b->drop) ++ { ++ if (test_verbose) ++ printf ("info: TCP server %d: dropping response to %s/%u/%u\n", ++ closure->server_index, ++ qinfo.qname, qinfo.qclass, qinfo.qtype); ++ } ++ else ++ { ++ if (test_verbose) ++ printf ("info: TCP server %d: sending response: %zu bytes" ++ " (for %s/%u/%u)\n", ++ closure->server_index, b->offset, ++ qinfo.qname, qinfo.qclass, qinfo.qtype); ++ uint16_t length = htons (b->offset); ++ size_t to_send = b->offset; ++ if (to_send < b->truncate_bytes) ++ to_send = 0; ++ else ++ to_send -= b->truncate_bytes; ++ struct iovec buffers[2] = ++ { ++ {&length, sizeof (length)}, ++ {b->buffer, to_send} ++ }; ++ writev_fully (closure->client_socket, buffers, 2); ++ } ++ bool close_flag = b->close; ++ response_builder_free (b); ++ free (query_buffer); ++ if (close_flag) ++ break; ++ } ++ ++ xclose (closure->client_socket); ++ free (closure); ++ return NULL; ++} ++ ++/* thread_callback for the TCP case. Accept connections and create a ++ new thread for each client. */ ++static void ++server_thread_tcp (struct resolv_test *obj, int server_index) ++{ ++ while (true) ++ { ++ /* Get the client conenction. */ ++ int client_socket = xaccept ++ (obj->servers[server_index].socket_tcp, NULL, NULL); ++ ++ /* Check for termination. */ ++ xpthread_mutex_lock (&obj->lock); ++ if (obj->termination_requested) ++ { ++ xpthread_mutex_unlock (&obj->lock); ++ xclose (client_socket); ++ break; ++ } ++ xpthread_mutex_unlock (&obj->lock); ++ ++ /* Spawn a new thread for handling this connection. */ ++ struct tcp_thread_closure *closure = xmalloc (sizeof (*closure)); ++ *closure = (struct tcp_thread_closure) ++ { ++ .obj = obj, ++ .server_index = server_index, ++ .client_socket = client_socket, ++ }; ++ ++ pthread_t thr ++ = xpthread_create (NULL, server_thread_tcp_client, closure); ++ /* TODO: We should keep track of this thread so that we can ++ block in resolv_test_end until it has exited. */ ++ xpthread_detach (thr); ++ } ++} ++ ++/* Create UDP and TCP server sockets. */ ++static void ++make_server_sockets (struct resolv_test_server *server) ++{ ++ while (true) ++ { ++ server->socket_udp = xsocket (AF_INET, SOCK_DGRAM, IPPROTO_UDP); ++ server->socket_tcp = xsocket (AF_INET, SOCK_STREAM, IPPROTO_TCP); ++ ++ /* Pick the address for the UDP socket. */ ++ server->address = (struct sockaddr_in) ++ { ++ .sin_family = AF_INET, ++ .sin_addr = {.s_addr = htonl (INADDR_LOOPBACK)} ++ }; ++ xbind (server->socket_udp, ++ (struct sockaddr *)&server->address, sizeof (server->address)); ++ ++ /* Retrieve the address. */ ++ socklen_t addrlen = sizeof (server->address); ++ xgetsockname (server->socket_udp, ++ (struct sockaddr *)&server->address, &addrlen); ++ ++ /* Bind the TCP socket to the same address. */ ++ { ++ int on = 1; ++ xsetsockopt (server->socket_tcp, SOL_SOCKET, SO_REUSEADDR, ++ &on, sizeof (on)); ++ } ++ if (bind (server->socket_tcp, ++ (struct sockaddr *)&server->address, ++ sizeof (server->address)) != 0) ++ { ++ /* Port collision. The UDP bind succeeded, but the TCP BIND ++ failed. We assume here that the kernel will pick the ++ next local UDP address randomly. */ ++ if (errno == EADDRINUSE) ++ { ++ xclose (server->socket_udp); ++ xclose (server->socket_tcp); ++ continue; ++ } ++ FAIL_EXIT1 ("TCP bind: %m"); ++ } ++ xlisten (server->socket_tcp, 5); ++ break; ++ } ++} ++ ++/* One-time initialization of NSS. */ ++static void ++resolv_redirect_once (void) ++{ ++ /* Only use nss_dns. */ ++ __nss_configure_lookup ("hosts", "dns"); ++ __nss_configure_lookup ("networks", "dns"); ++ /* Enter a network namespace for isolation and firewall state ++ cleanup. The tests will still work if these steps fail, but they ++ may be less reliable. */ ++ support_become_root (); ++ support_enter_network_namespace (); ++} ++pthread_once_t resolv_redirect_once_var = PTHREAD_ONCE_INIT; ++ ++void ++resolv_test_init (void) ++{ ++ /* Perform one-time initialization of NSS. */ ++ xpthread_once (&resolv_redirect_once_var, resolv_redirect_once); ++} ++ ++/* Copy the search path from CONFIG.search to the _res object. */ ++static void ++set_search_path (struct resolv_redirect_config config) ++{ ++ memset (_res.defdname, 0, sizeof (_res.defdname)); ++ memset (_res.dnsrch, 0, sizeof (_res.dnsrch)); ++ ++ char *current = _res.defdname; ++ char *end = current + sizeof (_res.defdname); ++ ++ for (unsigned int i = 0; ++ i < sizeof (config.search) / sizeof (config.search[0]); ++i) ++ { ++ if (config.search[i] == NULL) ++ continue; ++ ++ size_t length = strlen (config.search[i]) + 1; ++ size_t remaining = end - current; ++ TEST_VERIFY_EXIT (length <= remaining); ++ memcpy (current, config.search[i], length); ++ _res.dnsrch[i] = current; ++ current += length; ++ } ++} ++ ++struct resolv_test * ++resolv_test_start (struct resolv_redirect_config config) ++{ ++ /* Apply configuration defaults. */ ++ if (config.nscount == 0) ++ config.nscount = resolv_max_test_servers; ++ ++ struct resolv_test *obj = xmalloc (sizeof (*obj)); ++ *obj = (struct resolv_test) { ++ .config = config, ++ .lock = PTHREAD_MUTEX_INITIALIZER, ++ }; ++ ++ resolv_test_init (); ++ ++ /* Create all the servers, to reserve the necessary ports. */ ++ for (int server_index = 0; server_index < config.nscount; ++server_index) ++ make_server_sockets (obj->servers + server_index); ++ ++ /* Start server threads. Disable the server ports, as ++ requested. */ ++ for (int server_index = 0; server_index < config.nscount; ++server_index) ++ { ++ struct resolv_test_server *server = obj->servers + server_index; ++ if (config.servers[server_index].disable_udp) ++ { ++ xclose (server->socket_udp); ++ server->socket_udp = -1; ++ } ++ else if (!config.single_thread_udp) ++ server->thread_udp = start_server_thread (obj, server_index, ++ server_thread_udp); ++ if (config.servers[server_index].disable_tcp) ++ { ++ xclose (server->socket_tcp); ++ server->socket_tcp = -1; ++ } ++ else ++ server->thread_tcp = start_server_thread (obj, server_index, ++ server_thread_tcp); ++ } ++ if (config.single_thread_udp) ++ start_server_thread_udp_single (obj); ++ ++ int timeout = 1; ++ ++ /* Initialize libresolv. */ ++ TEST_VERIFY_EXIT (res_init () == 0); ++ ++ /* Disable IPv6 name server addresses. The code below only ++ overrides the IPv4 addresses. */ ++ __res_iclose (&_res, true); ++ _res._u._ext.nscount = 0; ++ ++ /* Redirect queries to the server socket. */ ++ if (test_verbose) ++ { ++ printf ("info: old timeout value: %d\n", _res.retrans); ++ printf ("info: old retry attempt value: %d\n", _res.retry); ++ printf ("info: old _res.options: 0x%lx\n", _res.options); ++ printf ("info: old _res.nscount value: %d\n", _res.nscount); ++ printf ("info: old _res.ndots value: %d\n", _res.ndots); ++ } ++ _res.retrans = timeout; ++ _res.retry = 4; ++ _res.nscount = config.nscount; ++ _res.options = RES_INIT | RES_RECURSE | RES_DEFNAMES | RES_DNSRCH; ++ _res.ndots = 1; ++ if (test_verbose) ++ { ++ printf ("info: new timeout value: %d\n", _res.retrans); ++ printf ("info: new retry attempt value: %d\n", _res.retry); ++ printf ("info: new _res.options: 0x%lx\n", _res.options); ++ printf ("info: new _res.nscount value: %d\n", _res.nscount); ++ printf ("info: new _res.ndots value: %d\n", _res.ndots); ++ } ++ for (int server_index = 0; server_index < config.nscount; ++server_index) ++ { ++ _res.nsaddr_list[server_index] = obj->servers[server_index].address; ++ if (test_verbose) ++ { ++ char buf[256]; ++ TEST_VERIFY_EXIT ++ (inet_ntop (AF_INET, &obj->servers[server_index].address.sin_addr, ++ buf, sizeof (buf)) != NULL); ++ printf ("info: server %d: %s/%u\n", ++ server_index, buf, ++ htons (obj->servers[server_index].address.sin_port)); ++ } ++ } ++ ++ set_search_path (config); ++ ++ return obj; ++} ++ ++void ++resolv_test_end (struct resolv_test *obj) ++{ ++ res_close (); ++ ++ xpthread_mutex_lock (&obj->lock); ++ obj->termination_requested = true; ++ xpthread_mutex_unlock (&obj->lock); ++ ++ /* Send trigger packets to unblock the server threads. */ ++ for (int server_index = 0; server_index < obj->config.nscount; ++ ++server_index) ++ { ++ if (!obj->config.servers[server_index].disable_udp) ++ { ++ int sock = xsocket (AF_INET, SOCK_DGRAM, IPPROTO_UDP); ++ xsendto (sock, "", 1, 0, ++ (struct sockaddr *) &obj->servers[server_index].address, ++ sizeof (obj->servers[server_index].address)); ++ xclose (sock); ++ } ++ if (!obj->config.servers[server_index].disable_tcp) ++ { ++ int sock = xsocket (AF_INET, SOCK_STREAM, IPPROTO_TCP); ++ xconnect (sock, ++ (struct sockaddr *) &obj->servers[server_index].address, ++ sizeof (obj->servers[server_index].address)); ++ xclose (sock); ++ } ++ } ++ ++ if (obj->config.single_thread_udp) ++ xpthread_join (obj->thread_udp_single); ++ ++ /* Wait for the server threads to terminate. */ ++ for (int server_index = 0; server_index < obj->config.nscount; ++ ++server_index) ++ { ++ if (!obj->config.servers[server_index].disable_udp) ++ { ++ if (!obj->config.single_thread_udp) ++ xpthread_join (obj->servers[server_index].thread_udp); ++ xclose (obj->servers[server_index].socket_udp); ++ } ++ if (!obj->config.servers[server_index].disable_tcp) ++ { ++ xpthread_join (obj->servers[server_index].thread_tcp); ++ xclose (obj->servers[server_index].socket_tcp); ++ } ++ } ++ ++ free (obj); ++} +diff --git a/support/resolv_test.h b/support/resolv_test.h +new file mode 100644 +index 0000000000..6498751569 +--- /dev/null ++++ b/support/resolv_test.h +@@ -0,0 +1,180 @@ ++/* DNS test framework and libresolv redirection. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#ifndef SUPPORT_RESOLV_TEST_H ++#define SUPPORT_RESOLV_TEST_H ++ ++#include <arpa/nameser.h> ++#include <stdbool.h> ++#include <sys/cdefs.h> ++ ++__BEGIN_DECLS ++ ++/* Information about EDNS properties of a DNS query. */ ++struct resolv_edns_info ++{ ++ bool active; ++ uint8_t extended_rcode; ++ uint8_t version; ++ uint16_t flags; ++ uint16_t payload_size; ++}; ++ ++/* This struct provides context information when the response callback ++ specified in struct resolv_redirect_config is invoked. */ ++struct resolv_response_context ++{ ++ const unsigned char *query_buffer; ++ size_t query_length; ++ int server_index; ++ bool tcp; ++ struct resolv_edns_info edns; ++}; ++ ++/* This opaque struct is used to construct responses from within the ++ response callback function. */ ++struct resolv_response_builder; ++ ++/* This opaque struct collects information about the resolver testing ++ currently in progress. */ ++struct resolv_test; ++ ++enum ++ { ++ /* Maximum number of test servers supported by the framework. */ ++ resolv_max_test_servers = 3, ++ }; ++ ++/* Configuration settings specific to individual test servers. */ ++struct resolv_redirect_server_config ++{ ++ bool disable_tcp; /* If true, no TCP server is listening. */ ++ bool disable_udp; /* If true, no UDP server is listening. */ ++}; ++ ++/* Instructions for setting up the libresolv redirection. */ ++struct resolv_redirect_config ++{ ++ /* The response_callback function is called for every incoming DNS ++ packet, over UDP or TCP. It must be specified, the other ++ configuration settings are optional. */ ++ void (*response_callback) (const struct resolv_response_context *, ++ struct resolv_response_builder *, ++ const char *qname, ++ uint16_t qclass, uint16_t qtype); ++ ++ /* Per-server configuration. */ ++ struct resolv_redirect_server_config servers[resolv_max_test_servers]; ++ ++ /* Search path entries. The first entry serves as the default ++ domain name as well. */ ++ const char *search[7]; ++ ++ /* Number of servers to activate in resolv. 0 means the default, ++ resolv_max_test_servers. */ ++ int nscount; ++ ++ /* If true, use a single thread to process all UDP queries. This ++ may results in more predictable ordering of queries and ++ responses. */ ++ bool single_thread_udp; ++}; ++ ++/* Configure NSS to use, nss_dns only for aplicable databases, and try ++ to put the process into a network namespace for better isolation. ++ This may have to be called before resolv_test_start, before the ++ process creates any threads. Otherwise, initialization is ++ performed by resolv_test_start implicitly. */ ++void resolv_test_init (void); ++ ++/* Initiate resolver testing. This updates the _res variable as ++ needed. As a side effect, NSS is reconfigured to use nss_dns only ++ for aplicable databases, and the process may enter a network ++ namespace for better isolation. */ ++struct resolv_test *resolv_test_start (struct resolv_redirect_config); ++ ++/* Call this function at the end of resolver testing, to free ++ resources and report pending errors (if any). */ ++void resolv_test_end (struct resolv_test *); ++ ++/* The remaining facilities in this file are used for constructing ++ response packets from the response_callback function. */ ++ ++/* Special settings for constructing responses from the callback. */ ++struct resolv_response_flags ++{ ++ /* 4-bit response code to incorporate into the response. */ ++ unsigned char rcode; ++ ++ /* If true, the TC (truncation) flag will be set. */ ++ bool tc; ++ ++ /* Initial section count values. Can be used to artificially ++ increase the counts, for malformed packet testing.*/ ++ unsigned short qdcount; ++ unsigned short ancount; ++ unsigned short nscount; ++ unsigned short adcount; ++}; ++ ++/* Begin a new response with the requested flags. Must be called ++ first. */ ++void resolv_response_init (struct resolv_response_builder *, ++ struct resolv_response_flags); ++ ++/* Switches to the section in the response packet. Only forward ++ movement is supported. */ ++void resolv_response_section (struct resolv_response_builder *, ns_sect); ++ ++/* Add a question record to the question section. */ ++void resolv_response_add_question (struct resolv_response_builder *, ++ const char *name, uint16_t class, ++ uint16_t type); ++/* Starts a new resource record with the specified owner name, class, ++ type, and TTL. Data is supplied with resolv_response_add_data or ++ resolv_response_add_name. */ ++void resolv_response_open_record (struct resolv_response_builder *, ++ const char *name, uint16_t class, ++ uint16_t type, uint32_t ttl); ++ ++/* Add unstructed bytes to the RDATA part of a resource record. */ ++void resolv_response_add_data (struct resolv_response_builder *, ++ const void *, size_t); ++ ++/* Add a compressed domain name to the RDATA part of a resource ++ record. */ ++void resolv_response_add_name (struct resolv_response_builder *, ++ const char *name); ++ ++/* Mark the end of the constructed record. Must be called last. */ ++void resolv_response_close_record (struct resolv_response_builder *); ++ ++/* Drop this query packet (that is, do not send a response, not even ++ an empty packet). */ ++void resolv_response_drop (struct resolv_response_builder *); ++ ++/* In TCP mode, close the connection after this packet (if a response ++ is sent). */ ++void resolv_response_close (struct resolv_response_builder *); ++ ++/* The size of the response packet built so far. */ ++size_t resolv_response_length (const struct resolv_response_builder *); ++ ++__END_DECLS ++ ++#endif /* SUPPORT_RESOLV_TEST_H */ +diff --git a/support/run_diff.h b/support/run_diff.h +new file mode 100644 +index 0000000000..f65b5dd22c +--- /dev/null ++++ b/support/run_diff.h +@@ -0,0 +1,31 @@ ++/* Invoke the system diff tool to compare two strings. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#ifndef SUPPORT_RUN_DIFF_H ++#define SUPPORT_RUN_DIFF_H ++ ++/* Compare the two NUL-terminated strings LEFT and RIGHT using the ++ diff tool. Label the sides of the diff with LEFT_LABEL and ++ RIGHT_LABEL, respectively. ++ ++ This function assumes that LEFT and RIGHT are different ++ strings. */ ++void support_run_diff (const char *left_label, const char *left, ++ const char *right_label, const char *right); ++ ++#endif /* SUPPORT_RUN_DIFF_H */ +diff --git a/support/set_fortify_handler.c b/support/set_fortify_handler.c +new file mode 100644 +index 0000000000..f434a8082a +--- /dev/null ++++ b/support/set_fortify_handler.c +@@ -0,0 +1,34 @@ ++/* Set signal handler for use in fortify tests. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <support/support.h> ++ ++#include <signal.h> ++ ++void ++set_fortify_handler (void (*handler) (int sig)) ++{ ++ struct sigaction sa; ++ ++ sa.sa_handler = handler; ++ sa.sa_flags = 0; ++ sigemptyset (&sa.sa_mask); ++ ++ sigaction (SIGABRT, &sa, NULL); ++ ignore_stderr (); ++} +diff --git a/support/support-xstat.c b/support/support-xstat.c +new file mode 100644 +index 0000000000..86a81ec601 +--- /dev/null ++++ b/support/support-xstat.c +@@ -0,0 +1,30 @@ ++/* stat64 with error checking. ++ Copyright (C) 2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++/* NB: Non-standard file name to avoid sysdeps override for xstat. */ ++ ++#include <support/check.h> ++#include <support/xunistd.h> ++#include <sys/stat.h> ++ ++void ++xstat (const char *path, struct stat64 *result) ++{ ++ if (stat64 (path, result) != 0) ++ FAIL_EXIT1 ("stat64 (\"%s\"): %m", path); ++} +diff --git a/support/support.h b/support/support.h +new file mode 100644 +index 0000000000..4b5f04c2cc +--- /dev/null ++++ b/support/support.h +@@ -0,0 +1,74 @@ ++/* Common extra functions. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++/* This header file should only contain definitions compatible with ++ C90. (Using __attribute__ is fine because <features.h> provides a ++ fallback.) */ ++ ++#ifndef SUPPORT_H ++#define SUPPORT_H ++ ++#include <stddef.h> ++#include <sys/cdefs.h> ++ ++__BEGIN_DECLS ++ ++/* Write a message to standard output. Can be used in signal ++ handlers. */ ++void write_message (const char *message) __attribute__ ((nonnull (1))); ++ ++/* Avoid all the buffer overflow messages on stderr. */ ++void ignore_stderr (void); ++ ++/* Set fortification error handler. Used when tests want to verify that bad ++ code is caught by the library. */ ++void set_fortify_handler (void (*handler) (int sig)); ++ ++/* Report an out-of-memory error for the allocation of SIZE bytes in ++ FUNCTION, terminating the process. */ ++void oom_error (const char *function, size_t size) ++ __attribute__ ((nonnull (1))); ++ ++/* Return a pointer to a memory region of SIZE bytes. The memory is ++ initialized to zero and will be shared with subprocesses (across ++ fork). The returned pointer must be freed using ++ support_shared_free; it is not compatible with the malloc ++ functions. */ ++void *support_shared_allocate (size_t size); ++ ++/* Deallocate a pointer returned by support_shared_allocate. */ ++void support_shared_free (void *); ++ ++/* Write CONTENTS to the file PATH. Create or truncate the file as ++ needed. The file mode is 0666 masked by the umask. Terminate the ++ process on error. */ ++void support_write_file_string (const char *path, const char *contents); ++ ++/* Error-checking wrapper functions which terminate the process on ++ error. */ ++ ++void *xmalloc (size_t) __attribute__ ((malloc)); ++void *xcalloc (size_t n, size_t s) __attribute__ ((malloc)); ++void *xrealloc (void *p, size_t n); ++char *xasprintf (const char *format, ...) ++ __attribute__ ((format (printf, 1, 2), malloc)); ++char *xstrdup (const char *); ++ ++__END_DECLS ++ ++#endif /* SUPPORT_H */ +diff --git a/sysdeps/sparc/sparc32/sparcv9/fpu/s_fdim.S b/support/support_become_root.c +similarity index 57% +rename from sysdeps/sparc/sparc32/sparcv9/fpu/s_fdim.S +rename to support/support_become_root.c +index 37f7f44dfa..3fa0bd4ac0 100644 +--- a/sysdeps/sparc/sparc32/sparcv9/fpu/s_fdim.S ++++ b/support/support_become_root.c +@@ -1,7 +1,6 @@ +-/* Compute positive difference, sparc 32-bit+v9. +- Copyright (C) 2013-2016 Free Software Foundation, Inc. ++/* Acquire root privileges. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. +- Contributed by David S. Miller <davem@davemloft.net>. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public +@@ -17,24 +16,25 @@ + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +-#include <sysdep.h> +-#include <math_ldbl_opt.h> ++#include <support/namespace.h> + +-ENTRY(__fdim) +- std %o0, [%sp + 72] +- std %o2, [%sp + 80] +- ldd [%sp + 72], %f0 +- ldd [%sp + 80], %f2 +- fcmpd %f0, %f2 +- fbug 1f +- nop +- fzero %f0 +- fnegd %f0, %f2 +-1: retl +- fsubd %f0, %f2, %f0 +-END(__fdim) +-weak_alias (__fdim, fdim) ++#include <sched.h> ++#include <stdio.h> ++#include <unistd.h> + +-#if LONG_DOUBLE_COMPAT(libm, GLIBC_2_1) +-compat_symbol (libm, __fdim, fdiml, GLIBC_2_1); ++bool ++support_become_root (void) ++{ ++#ifdef CLONE_NEWUSER ++ if (unshare (CLONE_NEWUSER | CLONE_NEWNS) == 0) ++ /* Even if we do not have UID zero, we have extended privileges at ++ this point. */ ++ return true; + #endif ++ if (setuid (0) != 0) ++ { ++ printf ("warning: could not become root outside namespace (%m)\n"); ++ return false; ++ } ++ return true; ++} +diff --git a/support/support_can_chroot.c b/support/support_can_chroot.c +new file mode 100644 +index 0000000000..0dfd2deb54 +--- /dev/null ++++ b/support/support_can_chroot.c +@@ -0,0 +1,65 @@ ++/* Return true if the process can perform a chroot operation. ++ Copyright (C) 2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <errno.h> ++#include <stdio.h> ++#include <support/check.h> ++#include <support/namespace.h> ++#include <support/support.h> ++#include <sys/stat.h> ++#include <unistd.h> ++#include <xunistd.h> ++ ++static void ++callback (void *closure) ++{ ++ int *result = closure; ++ struct stat64 before; ++ xstat ("/dev", &before); ++ if (chroot ("/dev") != 0) ++ { ++ *result = errno; ++ return; ++ } ++ struct stat64 after; ++ xstat ("/", &after); ++ TEST_VERIFY (before.st_dev == after.st_dev); ++ TEST_VERIFY (before.st_ino == after.st_ino); ++ *result = 0; ++} ++ ++bool ++support_can_chroot (void) ++{ ++ int *result = support_shared_allocate (sizeof (*result)); ++ *result = 0; ++ support_isolate_in_subprocess (callback, result); ++ bool ok = *result == 0; ++ if (!ok) ++ { ++ static bool already_warned; ++ if (!already_warned) ++ { ++ already_warned = true; ++ errno = *result; ++ printf ("warning: this process does not support chroot: %m\n"); ++ } ++ } ++ support_shared_free (result); ++ return ok; ++} +diff --git a/support/support_capture_subprocess.c b/support/support_capture_subprocess.c +new file mode 100644 +index 0000000000..030f124252 +--- /dev/null ++++ b/support/support_capture_subprocess.c +@@ -0,0 +1,108 @@ ++/* Capture output from a subprocess. ++ Copyright (C) 2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <support/capture_subprocess.h> ++ ++#include <errno.h> ++#include <stdlib.h> ++#include <support/check.h> ++#include <support/xunistd.h> ++#include <support/xsocket.h> ++ ++static void ++transfer (const char *what, struct pollfd *pfd, struct xmemstream *stream) ++{ ++ if (pfd->revents != 0) ++ { ++ char buf[1024]; ++ ssize_t ret = TEMP_FAILURE_RETRY (read (pfd->fd, buf, sizeof (buf))); ++ if (ret < 0) ++ { ++ support_record_failure (); ++ printf ("error: reading from subprocess %s: %m", what); ++ pfd->events = 0; ++ pfd->revents = 0; ++ } ++ else if (ret == 0) ++ { ++ /* EOF reached. Stop listening. */ ++ pfd->events = 0; ++ pfd->revents = 0; ++ } ++ else ++ /* Store the data just read. */ ++ TEST_VERIFY (fwrite (buf, ret, 1, stream->out) == 1); ++ } ++} ++ ++struct support_capture_subprocess ++support_capture_subprocess (void (*callback) (void *), void *closure) ++{ ++ struct support_capture_subprocess result; ++ xopen_memstream (&result.out); ++ xopen_memstream (&result.err); ++ ++ int stdout_pipe[2]; ++ xpipe (stdout_pipe); ++ int stderr_pipe[2]; ++ xpipe (stderr_pipe); ++ ++ TEST_VERIFY (fflush (stdout) == 0); ++ TEST_VERIFY (fflush (stderr) == 0); ++ ++ pid_t pid = xfork (); ++ if (pid == 0) ++ { ++ xclose (stdout_pipe[0]); ++ xclose (stderr_pipe[0]); ++ xdup2 (stdout_pipe[1], STDOUT_FILENO); ++ xdup2 (stderr_pipe[1], STDERR_FILENO); ++ callback (closure); ++ _exit (0); ++ } ++ xclose (stdout_pipe[1]); ++ xclose (stderr_pipe[1]); ++ ++ struct pollfd fds[2] = ++ { ++ { .fd = stdout_pipe[0], .events = POLLIN }, ++ { .fd = stderr_pipe[0], .events = POLLIN }, ++ }; ++ ++ do ++ { ++ xpoll (fds, 2, -1); ++ transfer ("stdout", &fds[0], &result.out); ++ transfer ("stderr", &fds[1], &result.err); ++ } ++ while (fds[0].events != 0 || fds[1].events != 0); ++ xclose (stdout_pipe[0]); ++ xclose (stderr_pipe[0]); ++ ++ xfclose_memstream (&result.out); ++ xfclose_memstream (&result.err); ++ xwaitpid (pid, &result.status, 0); ++ return result; ++} ++ ++void ++support_capture_subprocess_free (struct support_capture_subprocess *p) ++{ ++ free (p->out.buffer); ++ free (p->err.buffer); ++} +diff --git a/support/support_capture_subprocess_check.c b/support/support_capture_subprocess_check.c +new file mode 100644 +index 0000000000..708c89f331 +--- /dev/null ++++ b/support/support_capture_subprocess_check.c +@@ -0,0 +1,67 @@ ++/* Verify capture output from a subprocess. ++ Copyright (C) 2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <stdbool.h> ++#include <stdio.h> ++#include <support/capture_subprocess.h> ++#include <support/check.h> ++ ++static void ++print_context (const char *context, bool *failed) ++{ ++ if (*failed) ++ /* Do not duplicate message. */ ++ return; ++ support_record_failure (); ++ printf ("error: subprocess failed: %s\n", context); ++} ++ ++void ++support_capture_subprocess_check (struct support_capture_subprocess *proc, ++ const char *context, int status, ++ int allowed) ++{ ++ TEST_VERIFY ((allowed & sc_allow_none) ++ || (allowed & sc_allow_stdout) ++ || (allowed & sc_allow_stderr)); ++ TEST_VERIFY (!((allowed & sc_allow_none) ++ && ((allowed & sc_allow_stdout) ++ || (allowed & sc_allow_stderr)))); ++ ++ bool failed = false; ++ if (proc->status != status) ++ { ++ print_context (context, &failed); ++ printf ("error: expected exit status: %d\n", status); ++ printf ("error: actual exit status: %d\n", status); ++ } ++ if (!(allowed & sc_allow_stdout) && proc->out.length != 0) ++ { ++ print_context (context, &failed); ++ printf ("error: unexpected output from subprocess\n"); ++ fwrite (proc->out.buffer, proc->out.length, 1, stdout); ++ puts ("\n"); ++ } ++ if (!(allowed & sc_allow_stderr) && proc->err.length != 0) ++ { ++ print_context (context, &failed); ++ printf ("error: unexpected error output from subprocess\n"); ++ fwrite (proc->err.buffer, proc->err.length, 1, stdout); ++ puts ("\n"); ++ } ++} +diff --git a/support/support_enter_network_namespace.c b/support/support_enter_network_namespace.c +new file mode 100644 +index 0000000000..28b0ee29cf +--- /dev/null ++++ b/support/support_enter_network_namespace.c +@@ -0,0 +1,75 @@ ++/* Enter a network namespace. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <support/namespace.h> ++ ++#include <net/if.h> ++#include <sched.h> ++#include <stdio.h> ++#include <string.h> ++#include <support/check.h> ++#include <support/xsocket.h> ++#include <support/xunistd.h> ++#include <sys/ioctl.h> ++#include <unistd.h> ++ ++static bool in_uts_namespace; ++ ++bool ++support_enter_network_namespace (void) ++{ ++#ifdef CLONE_NEWUTS ++ if (unshare (CLONE_NEWUTS) == 0) ++ in_uts_namespace = true; ++ else ++ printf ("warning: unshare (CLONE_NEWUTS) failed: %m\n"); ++#endif ++ ++#ifdef CLONE_NEWNET ++ if (unshare (CLONE_NEWNET) == 0) ++ { ++ /* Bring up the loopback interface. */ ++ int fd = xsocket (AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0); ++ struct ifreq req; ++ strcpy (req.ifr_name, "lo"); ++ TEST_VERIFY_EXIT (ioctl (fd, SIOCGIFFLAGS, &req) == 0); ++ bool already_up = req.ifr_flags & IFF_UP; ++ if (already_up) ++ /* This means that we likely have not achieved isolation from ++ the parent namespace. */ ++ printf ("warning: loopback interface already exists" ++ " in new network namespace\n"); ++ else ++ { ++ req.ifr_flags |= IFF_UP | IFF_RUNNING; ++ TEST_VERIFY_EXIT (ioctl (fd, SIOCSIFFLAGS, &req) == 0); ++ } ++ xclose (fd); ++ ++ return !already_up; ++ } ++#endif ++ printf ("warning: could not enter network namespace\n"); ++ return false; ++} ++ ++bool ++support_in_uts_namespace (void) ++{ ++ return in_uts_namespace; ++} +diff --git a/sysdeps/sparc/sparc32/sparcv9/fpu/s_fdimf.S b/support/support_format_address_family.c +similarity index 63% +rename from sysdeps/sparc/sparc32/sparcv9/fpu/s_fdimf.S +rename to support/support_format_address_family.c +index 9e0e3f21be..5d42c42a45 100644 +--- a/sysdeps/sparc/sparc32/sparcv9/fpu/s_fdimf.S ++++ b/support/support_format_address_family.c +@@ -1,7 +1,6 @@ +-/* Compute positive difference, sparc 32-bit+v9. +- Copyright (C) 2013-2016 Free Software Foundation, Inc. ++/* Convert an address family to a string. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. +- Contributed by David S. Miller <davem@davemloft.net>. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public +@@ -17,19 +16,20 @@ + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +-#include <sysdep.h> ++#include <support/format_nss.h> + +-ENTRY(__fdimf) +- st %o0, [%sp + 72] +- st %o1, [%sp + 76] +- ld [%sp + 72], %f0 +- ld [%sp + 76], %f1 +- fcmps %f0, %f1 +- fbug 1f +- nop +- fzeros %f0 +- fnegs %f0, %f1 +-1: retl +- fsubs %f0, %f1, %f0 +-END(__fdimf) +-weak_alias (__fdimf, fdimf) ++#include <support/support.h> ++ ++char * ++support_format_address_family (int family) ++{ ++ switch (family) ++ { ++ case AF_INET: ++ return xstrdup ("INET"); ++ case AF_INET6: ++ return xstrdup ("INET6"); ++ default: ++ return xasprintf ("<unknown address family %d>", family); ++ } ++} +diff --git a/support/support_format_addrinfo.c b/support/support_format_addrinfo.c +new file mode 100644 +index 0000000000..eedb030591 +--- /dev/null ++++ b/support/support_format_addrinfo.c +@@ -0,0 +1,239 @@ ++/* Convert struct addrinfo values to a string. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <support/format_nss.h> ++ ++#include <arpa/inet.h> ++#include <errno.h> ++#include <stdio.h> ++#include <support/support.h> ++#include <support/xmemstream.h> ++ ++static size_t ++socket_address_length (int family) ++{ ++ switch (family) ++ { ++ case AF_INET: ++ return sizeof (struct sockaddr_in); ++ case AF_INET6: ++ return sizeof (struct sockaddr_in6); ++ default: ++ return -1; ++ } ++} ++ ++static void ++format_ai_flags_1 (FILE *out, struct addrinfo *ai, int flag, const char *name, ++ int * flags_printed) ++{ ++ if ((ai->ai_flags & flag) != 0) ++ fprintf (out, " %s", name); ++ *flags_printed |= flag; ++} ++ ++static void ++format_ai_flags (FILE *out, struct addrinfo *ai) ++{ ++ if (ai == NULL) ++ return; ++ ++ if (ai->ai_flags != 0) ++ { ++ fprintf (out, "flags:"); ++ int flags_printed = 0; ++#define FLAG(flag) format_ai_flags_1 (out, ai, flag, #flag, &flags_printed) ++ FLAG (AI_PASSIVE); ++ FLAG (AI_CANONNAME); ++ FLAG (AI_NUMERICHOST); ++ FLAG (AI_V4MAPPED); ++ FLAG (AI_ALL); ++ FLAG (AI_ADDRCONFIG); ++ FLAG (AI_IDN); ++ FLAG (AI_CANONIDN); ++ FLAG (AI_IDN_ALLOW_UNASSIGNED); ++ FLAG (AI_IDN_USE_STD3_ASCII_RULES); ++ FLAG (AI_NUMERICSERV); ++#undef FLAG ++ int remaining = ai->ai_flags & ~flags_printed; ++ if (remaining != 0) ++ fprintf (out, " %08x", remaining); ++ fprintf (out, "\n"); ++ } ++ ++ /* Report flag mismatches within the list. */ ++ int flags = ai->ai_flags; ++ int index = 1; ++ ai = ai->ai_next; ++ while (ai != NULL) ++ { ++ if (ai->ai_flags != flags) ++ fprintf (out, "error: flags at %d: 0x%x expected, 0x%x actual\n", ++ index, flags, ai->ai_flags); ++ ai = ai->ai_next; ++ ++index; ++ } ++} ++ ++static void ++format_ai_canonname (FILE *out, struct addrinfo *ai) ++{ ++ if (ai == NULL) ++ return; ++ if (ai->ai_canonname != NULL) ++ fprintf (out, "canonname: %s\n", ai->ai_canonname); ++ ++ /* Report incorrectly set ai_canonname fields on subsequent list ++ entries. */ ++ int index = 1; ++ ai = ai->ai_next; ++ while (ai != NULL) ++ { ++ if (ai->ai_canonname != NULL) ++ fprintf (out, "error: canonname set at %d: %s\n", ++ index, ai->ai_canonname); ++ ai = ai->ai_next; ++ ++index; ++ } ++} ++ ++static void ++format_ai_one (FILE *out, struct addrinfo *ai) ++{ ++ { ++ char type_buf[32]; ++ const char *type_str; ++ char proto_buf[32]; ++ const char *proto_str; ++ ++ /* ai_socktype */ ++ switch (ai->ai_socktype) ++ { ++ case SOCK_RAW: ++ type_str = "RAW"; ++ break; ++ case SOCK_DGRAM: ++ type_str = "DGRAM"; ++ break; ++ case SOCK_STREAM: ++ type_str = "STREAM"; ++ break; ++ default: ++ snprintf (type_buf, sizeof (type_buf), "%d", ai->ai_socktype); ++ type_str = type_buf; ++ } ++ ++ /* ai_protocol */ ++ switch (ai->ai_protocol) ++ { ++ case IPPROTO_IP: ++ proto_str = "IP"; ++ break; ++ case IPPROTO_UDP: ++ proto_str = "UDP"; ++ break; ++ case IPPROTO_TCP: ++ proto_str = "TCP"; ++ break; ++ default: ++ snprintf (proto_buf, sizeof (proto_buf), "%d", ai->ai_protocol); ++ proto_str = proto_buf; ++ } ++ fprintf (out, "address: %s/%s", type_str, proto_str); ++ } ++ ++ /* ai_addrlen */ ++ if (ai->ai_addrlen != socket_address_length (ai->ai_family)) ++ { ++ char *family = support_format_address_family (ai->ai_family); ++ fprintf (out, "error: invalid address length %d for %s\n", ++ ai->ai_addrlen, family); ++ free (family); ++ } ++ ++ /* ai_addr */ ++ { ++ char buf[128]; ++ uint16_t port; ++ const char *ret; ++ switch (ai->ai_family) ++ { ++ case AF_INET: ++ { ++ struct sockaddr_in *sin = (struct sockaddr_in *) ai->ai_addr; ++ ret = inet_ntop (AF_INET, &sin->sin_addr, buf, sizeof (buf)); ++ port = sin->sin_port; ++ } ++ break; ++ case AF_INET6: ++ { ++ struct sockaddr_in6 *sin = (struct sockaddr_in6 *) ai->ai_addr; ++ ret = inet_ntop (AF_INET6, &sin->sin6_addr, buf, sizeof (buf)); ++ port = sin->sin6_port; ++ } ++ break; ++ default: ++ errno = EAFNOSUPPORT; ++ ret = NULL; ++ } ++ if (ret == NULL) ++ fprintf (out, "error: inet_top failed: %m\n"); ++ else ++ fprintf (out, " %s %u\n", buf, ntohs (port)); ++ } ++} ++ ++/* Format all the addresses in one address family. */ ++static void ++format_ai_family (FILE *out, struct addrinfo *ai, int family) ++{ ++ while (ai) ++ { ++ if (ai->ai_family == family) ++ format_ai_one (out, ai); ++ ai = ai->ai_next; ++ } ++} ++ ++char * ++support_format_addrinfo (struct addrinfo *ai, int ret) ++{ ++ int errno_copy = errno; ++ ++ struct xmemstream mem; ++ xopen_memstream (&mem); ++ if (ret != 0) ++ { ++ fprintf (mem.out, "error: %s\n", gai_strerror (ret)); ++ if (ret == EAI_SYSTEM) ++ { ++ errno = errno_copy; ++ fprintf (mem.out, "error: %m\n"); ++ } ++ } ++ else ++ { ++ format_ai_flags (mem.out, ai); ++ format_ai_canonname (mem.out, ai); ++ format_ai_family (mem.out, ai, AF_INET); ++ format_ai_family (mem.out, ai, AF_INET6); ++ } ++ ++ xfclose_memstream (&mem); ++ return mem.buffer; ++} +diff --git a/support/support_format_dns_packet.c b/support/support_format_dns_packet.c +new file mode 100644 +index 0000000000..2992c57971 +--- /dev/null ++++ b/support/support_format_dns_packet.c +@@ -0,0 +1,222 @@ ++/* Convert a DNS packet to a human-readable representation. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <support/format_nss.h> ++ ++#include <arpa/inet.h> ++#include <resolv.h> ++#include <support/check.h> ++#include <support/support.h> ++#include <support/xmemstream.h> ++ ++struct in_buffer ++{ ++ const unsigned char *data; ++ size_t size; ++}; ++ ++static inline bool ++extract_8 (struct in_buffer *in, unsigned char *value) ++{ ++ if (in->size == 0) ++ return false; ++ *value = in->data[0]; ++ ++in->data; ++ --in->size; ++ return true; ++} ++ ++static inline bool ++extract_16 (struct in_buffer *in, unsigned short *value) ++{ ++ if (in->size < 2) ++ return false; ++ *value = (in->data[0] << 8) | in->data[1]; ++ in->data += 2; ++ in->size -= 2; ++ return true; ++} ++ ++static inline bool ++extract_32 (struct in_buffer *in, unsigned *value) ++{ ++ if (in->size < 4) ++ return false; ++ unsigned a = in->data[0]; ++ unsigned b = in->data[1]; ++ unsigned c = in->data[2]; ++ unsigned d = in->data[3]; ++ *value = (a << 24) | (b << 16) | (c << 8) | d; ++ in->data += 4; ++ in->size -= 4; ++ return true; ++} ++ ++static inline bool ++extract_bytes (struct in_buffer *in, size_t length, struct in_buffer *value) ++{ ++ if (in->size < length) ++ return false; ++ *value = (struct in_buffer) {in->data, length}; ++ in->data += length; ++ in->size -= length; ++ return true; ++} ++ ++struct dname ++{ ++ char name[MAXDNAME + 1]; ++}; ++ ++static bool ++extract_name (struct in_buffer full, struct in_buffer *in, struct dname *value) ++{ ++ const unsigned char *full_end = full.data + full.size; ++ /* Sanity checks; these indicate buffer misuse. */ ++ TEST_VERIFY_EXIT ++ (!(in->data < full.data || in->data > full_end ++ || in->size > (size_t) (full_end - in->data))); ++ int ret = dn_expand (full.data, full_end, in->data, ++ value->name, sizeof (value->name)); ++ if (ret < 0) ++ return false; ++ in->data += ret; ++ in->size -= ret; ++ return true; ++} ++ ++char * ++support_format_dns_packet (const unsigned char *buffer, size_t length) ++{ ++ struct in_buffer full = { buffer, length }; ++ struct in_buffer in = full; ++ struct xmemstream mem; ++ xopen_memstream (&mem); ++ ++ unsigned short txnid; ++ unsigned short flags; ++ unsigned short qdcount; ++ unsigned short ancount; ++ unsigned short nscount; ++ unsigned short adcount; ++ if (!(extract_16 (&in, &txnid) ++ && extract_16 (&in, &flags) ++ && extract_16 (&in, &qdcount) ++ && extract_16 (&in, &ancount) ++ && extract_16 (&in, &nscount) ++ && extract_16 (&in, &adcount))) ++ { ++ fprintf (mem.out, "error: could not parse DNS header\n"); ++ goto out; ++ } ++ if (qdcount != 1) ++ { ++ fprintf (mem.out, "error: question count is %d, not 1\n", qdcount); ++ goto out; ++ } ++ struct dname qname; ++ if (!extract_name (full, &in, &qname)) ++ { ++ fprintf (mem.out, "error: malformed QNAME\n"); ++ goto out; ++ } ++ unsigned short qtype; ++ unsigned short qclass; ++ if (!(extract_16 (&in, &qtype) ++ && extract_16 (&in, &qclass))) ++ { ++ fprintf (mem.out, "error: malformed question\n"); ++ goto out; ++ } ++ if (qtype != T_A && qtype != T_AAAA && qtype != T_PTR) ++ { ++ fprintf (mem.out, "error: unsupported QTYPE %d\n", qtype); ++ goto out; ++ } ++ ++ fprintf (mem.out, "name: %s\n", qname.name); ++ ++ for (int i = 0; i < ancount; ++i) ++ { ++ struct dname rname; ++ if (!extract_name (full, &in, &rname)) ++ { ++ fprintf (mem.out, "error: malformed record name\n"); ++ goto out; ++ } ++ unsigned short rtype; ++ unsigned short rclass; ++ unsigned ttl; ++ unsigned short rdlen; ++ struct in_buffer rdata; ++ if (!(extract_16 (&in, &rtype) ++ && extract_16 (&in, &rclass) ++ && extract_32 (&in, &ttl) ++ && extract_16 (&in, &rdlen) ++ && extract_bytes (&in, rdlen, &rdata))) ++ { ++ fprintf (mem.out, "error: malformed record header\n"); ++ goto out; ++ } ++ /* Skip non-matching record types. */ ++ if ((rtype != qtype && rtype != T_CNAME) || rclass != qclass) ++ continue; ++ switch (rtype) ++ { ++ case T_A: ++ if (rdlen == 4) ++ fprintf (mem.out, "address: %d.%d.%d.%d\n", ++ rdata.data[0], ++ rdata.data[1], ++ rdata.data[2], ++ rdata.data[3]); ++ else ++ fprintf (mem.out, "error: A record of size %d: %s\n", ++ rdlen, rname.name); ++ break; ++ case T_AAAA: ++ { ++ if (rdlen == 16) ++ { ++ char buf[100]; ++ if (inet_ntop (AF_INET6, rdata.data, buf, sizeof (buf)) == NULL) ++ fprintf (mem.out, "error: AAAA record decoding failed: %m\n"); ++ else ++ fprintf (mem.out, "address: %s\n", buf); ++ } ++ else ++ fprintf (mem.out, "error: AAAA record of size %d: %s\n", ++ rdlen, rname.name); ++ } ++ break; ++ case T_CNAME: ++ case T_PTR: ++ { ++ struct dname name; ++ if (extract_name (full, &rdata, &name)) ++ fprintf (mem.out, "name: %s\n", name.name); ++ else ++ fprintf (mem.out, "error: malformed CNAME/PTR record\n"); ++ } ++ } ++ } ++ ++ out: ++ xfclose_memstream (&mem); ++ return mem.buffer; ++} +diff --git a/support/support_format_herrno.c b/support/support_format_herrno.c +new file mode 100644 +index 0000000000..493d6ae962 +--- /dev/null ++++ b/support/support_format_herrno.c +@@ -0,0 +1,45 @@ ++/* Convert a h_errno error code to a string. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <support/format_nss.h> ++ ++#include <support/support.h> ++ ++char * ++support_format_herrno (int code) ++{ ++ const char *errstr; ++ switch (code) ++ { ++ case HOST_NOT_FOUND: ++ errstr = "HOST_NOT_FOUND"; ++ break; ++ case NO_ADDRESS: ++ errstr = "NO_ADDRESS"; ++ break; ++ case NO_RECOVERY: ++ errstr = "NO_RECOVERY"; ++ break; ++ case TRY_AGAIN: ++ errstr = "TRY_AGAIN"; ++ break; ++ default: ++ return xasprintf ("<invalid h_errno value %d>\n", code); ++ } ++ return xstrdup (errstr); ++} +diff --git a/support/support_format_hostent.c b/support/support_format_hostent.c +new file mode 100644 +index 0000000000..5b5f26082e +--- /dev/null ++++ b/support/support_format_hostent.c +@@ -0,0 +1,75 @@ ++/* Convert a struct hostent object to a string. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <support/format_nss.h> ++ ++#include <arpa/inet.h> ++#include <stdio.h> ++#include <support/support.h> ++#include <support/xmemstream.h> ++ ++static int ++address_length (int family) ++{ ++ switch (family) ++ { ++ case AF_INET: ++ return 4; ++ case AF_INET6: ++ return 16; ++ } ++ return -1; ++} ++ ++char * ++support_format_hostent (struct hostent *h) ++{ ++ if (h == NULL) ++ { ++ char *value = support_format_herrno (h_errno); ++ char *result = xasprintf ("error: %s\n", value); ++ free (value); ++ return result; ++ } ++ ++ struct xmemstream mem; ++ xopen_memstream (&mem); ++ ++ fprintf (mem.out, "name: %s\n", h->h_name); ++ for (char **alias = h->h_aliases; *alias != NULL; ++alias) ++ fprintf (mem.out, "alias: %s\n", *alias); ++ for (unsigned i = 0; h->h_addr_list[i] != NULL; ++i) ++ { ++ char buf[128]; ++ if (inet_ntop (h->h_addrtype, h->h_addr_list[i], ++ buf, sizeof (buf)) == NULL) ++ fprintf (mem.out, "error: inet_ntop failed: %m\n"); ++ else ++ fprintf (mem.out, "address: %s\n", buf); ++ } ++ if (h->h_length != address_length (h->h_addrtype)) ++ { ++ char *family = support_format_address_family (h->h_addrtype); ++ fprintf (mem.out, "error: invalid address length %d for %s\n", ++ h->h_length, family); ++ free (family); ++ } ++ ++ xfclose_memstream (&mem); ++ return mem.buffer; ++} +diff --git a/support/support_format_netent.c b/support/support_format_netent.c +new file mode 100644 +index 0000000000..020f5720d9 +--- /dev/null ++++ b/support/support_format_netent.c +@@ -0,0 +1,52 @@ ++/* Convert a struct netent object to a string. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <support/format_nss.h> ++ ++#include <arpa/inet.h> ++#include <stdio.h> ++#include <support/support.h> ++#include <support/xmemstream.h> ++ ++char * ++support_format_netent (struct netent *e) ++{ ++ if (e == NULL) ++ { ++ char *value = support_format_herrno (h_errno); ++ char *result = xasprintf ("error: %s\n", value); ++ free (value); ++ return result; ++ } ++ ++ struct xmemstream mem; ++ xopen_memstream (&mem); ++ ++ if (e->n_name != NULL) ++ fprintf (mem.out, "name: %s\n", e->n_name); ++ for (char **ap = e->n_aliases; *ap != NULL; ++ap) ++ fprintf (mem.out, "alias: %s\n", *ap); ++ if (e->n_addrtype != AF_INET) ++ fprintf (mem.out, "addrtype: %d\n", e->n_addrtype); ++ /* On alpha, e->n_net is an unsigned long. */ ++ unsigned int n_net = e->n_net; ++ fprintf (mem.out, "net: 0x%08x\n", n_net); ++ ++ xfclose_memstream (&mem); ++ return mem.buffer; ++} +diff --git a/support/support_isolate_in_subprocess.c b/support/support_isolate_in_subprocess.c +new file mode 100644 +index 0000000000..cf48614383 +--- /dev/null ++++ b/support/support_isolate_in_subprocess.c +@@ -0,0 +1,38 @@ ++/* Run a function in a subprocess. ++ Copyright (C) 2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <support/check.h> ++#include <support/xunistd.h> ++ ++void ++support_isolate_in_subprocess (void (*callback) (void *), void *closure) ++{ ++ pid_t pid = xfork (); ++ if (pid == 0) ++ { ++ /* Child process. */ ++ callback (closure); ++ _exit (0); ++ } ++ ++ /* Parent process. */ ++ int status; ++ xwaitpid (pid, &status, 0); ++ if (status != 0) ++ FAIL_EXIT1 ("child process exited with status %d", status); ++} +diff --git a/support/support_record_failure.c b/support/support_record_failure.c +new file mode 100644 +index 0000000000..684055c746 +--- /dev/null ++++ b/support/support_record_failure.c +@@ -0,0 +1,106 @@ ++/* Global test failure counter. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <support/check.h> ++#include <support/support.h> ++#include <support/test-driver.h> ++ ++#include <stdbool.h> ++#include <stdio.h> ++#include <stdlib.h> ++#include <sys/mman.h> ++#include <unistd.h> ++ ++/* This structure keeps track of test failures. The counter is ++ incremented on each failure. The failed member is set to true if a ++ failure is detected, so that even if the counter wraps around to ++ zero, the failure of a test can be detected. ++ ++ The init constructor function below puts *state on a shared ++ annonymous mapping, so that failure reports from subprocesses ++ propagate to the parent process. */ ++struct test_failures ++{ ++ unsigned int counter; ++ unsigned int failed; ++}; ++static struct test_failures *state; ++ ++static __attribute__ ((constructor)) void ++init (void) ++{ ++ void *ptr = mmap (NULL, sizeof (*state), PROT_READ | PROT_WRITE, ++ MAP_ANONYMOUS | MAP_SHARED, -1, 0); ++ if (ptr == MAP_FAILED) ++ { ++ printf ("error: could not map %zu bytes: %m\n", sizeof (*state)); ++ exit (1); ++ } ++ /* Zero-initialization of the struct is sufficient. */ ++ state = ptr; ++} ++ ++void ++support_record_failure (void) ++{ ++ if (state == NULL) ++ { ++ write_message ++ ("error: support_record_failure called without initialization\n"); ++ _exit (1); ++ } ++ /* Relaxed MO is sufficient because we are only interested in the ++ values themselves, in isolation. */ ++ __atomic_store_n (&state->failed, 1, __ATOMIC_RELEASE); ++ __atomic_add_fetch (&state->counter, 1, __ATOMIC_RELEASE); ++} ++ ++int ++support_report_failure (int status) ++{ ++ if (state == NULL) ++ { ++ write_message ++ ("error: support_report_failure called without initialization\n"); ++ return 1; ++ } ++ ++ /* Relaxed MO is sufficient because acquire test result reporting ++ assumes that exiting from the main thread happens before the ++ error reporting via support_record_failure, which requires some ++ form of external synchronization. */ ++ bool failed = __atomic_load_n (&state->failed, __ATOMIC_RELAXED); ++ if (failed) ++ printf ("error: %u test failures\n", ++ __atomic_load_n (&state->counter, __ATOMIC_RELAXED)); ++ ++ if ((status == 0 || status == EXIT_UNSUPPORTED) && failed) ++ /* If we have a recorded failure, it overrides a non-failure ++ report from the test function. */ ++ status = 1; ++ return status; ++} ++ ++void ++support_record_failure_reset (void) ++{ ++ /* Only used for testing the test framework, with external ++ synchronization, but use release MO for consistency. */ ++ __atomic_store_n (&state->failed, 0, __ATOMIC_RELAXED); ++ __atomic_add_fetch (&state->counter, 0, __ATOMIC_RELAXED); ++} +diff --git a/support/support_run_diff.c b/support/support_run_diff.c +new file mode 100644 +index 0000000000..f5155de727 +--- /dev/null ++++ b/support/support_run_diff.c +@@ -0,0 +1,76 @@ ++/* Invoke the system diff tool to compare two strings. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <support/run_diff.h> ++ ++#include <stdio.h> ++#include <stdlib.h> ++#include <string.h> ++#include <support/check.h> ++#include <support/support.h> ++#include <support/temp_file.h> ++#include <support/xunistd.h> ++#include <sys/wait.h> ++ ++static char * ++write_to_temp_file (const char *prefix, const char *str) ++{ ++ char *template = xasprintf ("run_diff-%s", prefix); ++ char *name = NULL; ++ int fd = create_temp_file (template, &name); ++ TEST_VERIFY_EXIT (fd >= 0); ++ free (template); ++ xwrite (fd, str, strlen (str)); ++ xclose (fd); ++ return name; ++} ++ ++void ++support_run_diff (const char *left_label, const char *left, ++ const char *right_label, const char *right) ++{ ++ /* Ensure that the diff command output is ordered properly with ++ standard output. */ ++ TEST_VERIFY_EXIT (fflush (stdout) == 0); ++ ++ char *left_path = write_to_temp_file ("left-diff", left); ++ char *right_path = write_to_temp_file ("right-diff", right); ++ ++ pid_t pid = xfork (); ++ if (pid == 0) ++ { ++ execlp ("diff", "diff", "-u", ++ "--label", left_label, "--label", right_label, ++ "--", left_path, right_path, ++ NULL); ++ _exit (17); ++ } ++ else ++ { ++ int status; ++ xwaitpid (pid, &status, 0); ++ if (!WIFEXITED (status) || WEXITSTATUS (status) != 1) ++ printf ("warning: could not run diff, exit status: %d\n" ++ "*** %s ***\n%s\n" ++ "*** %s ***\n%s\n", ++ status, left_label, left, right_label, right); ++ } ++ ++ free (right_path); ++ free (left_path); ++} +diff --git a/support/support_shared_allocate.c b/support/support_shared_allocate.c +new file mode 100644 +index 0000000000..61d088e8cf +--- /dev/null ++++ b/support/support_shared_allocate.c +@@ -0,0 +1,57 @@ ++/* Allocate a memory region shared across processes. ++ Copyright (C) 2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <errno.h> ++#include <stddef.h> ++#include <support/support.h> ++#include <support/xunistd.h> ++#include <sys/mman.h> ++ ++/* Header for the allocation. It contains the size of the allocation ++ for subsequent unmapping. */ ++struct header ++{ ++ size_t total_size; ++ char data[] __attribute__ ((aligned (__alignof__ (max_align_t)))); ++}; ++ ++void * ++support_shared_allocate (size_t size) ++{ ++ size_t total_size = size + offsetof (struct header, data); ++ if (total_size < size) ++ { ++ errno = ENOMEM; ++ oom_error (__func__, size); ++ return NULL; ++ } ++ else ++ { ++ struct header *result = xmmap (NULL, total_size, PROT_READ | PROT_WRITE, ++ MAP_ANONYMOUS | MAP_SHARED, -1); ++ result->total_size = total_size; ++ return &result->data; ++ } ++} ++ ++void ++support_shared_free (void *data) ++{ ++ struct header *header = data - offsetof (struct header, data); ++ xmunmap (header, header->total_size); ++} +diff --git a/support/support_test_main.c b/support/support_test_main.c +new file mode 100644 +index 0000000000..914d64f603 +--- /dev/null ++++ b/support/support_test_main.c +@@ -0,0 +1,423 @@ ++/* Main worker function for the test driver. ++ Copyright (C) 1998-2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <support/test-driver.h> ++#include <support/check.h> ++#include <support/temp_file-internal.h> ++ ++#include <assert.h> ++#include <errno.h> ++#include <getopt.h> ++#include <malloc.h> ++#include <signal.h> ++#include <stdbool.h> ++#include <stdlib.h> ++#include <string.h> ++#include <sys/param.h> ++#include <sys/resource.h> ++#include <sys/types.h> ++#include <sys/wait.h> ++#include <time.h> ++#include <unistd.h> ++ ++static const struct option default_options[] = ++{ ++ TEST_DEFAULT_OPTIONS ++ { NULL, 0, NULL, 0 } ++}; ++ ++/* Show people how to run the program. */ ++static void ++usage (const struct option *options) ++{ ++ size_t i; ++ ++ printf ("Usage: %s [options]\n" ++ "\n" ++ "Environment Variables:\n" ++ " TIMEOUTFACTOR An integer used to scale the timeout\n" ++ " TMPDIR Where to place temporary files\n" ++ " TEST_COREDUMPS Do not disable coredumps if set\n" ++ "\n", ++ program_invocation_short_name); ++ printf ("Options:\n"); ++ for (i = 0; options[i].name; ++i) ++ { ++ int indent; ++ ++ indent = printf (" --%s", options[i].name); ++ if (options[i].has_arg == required_argument) ++ indent += printf (" <arg>"); ++ printf ("%*s", 25 - indent, ""); ++ switch (options[i].val) ++ { ++ case 'v': ++ printf ("Increase the output verbosity"); ++ break; ++ case OPT_DIRECT: ++ printf ("Run the test directly (instead of forking & monitoring)"); ++ break; ++ case OPT_TESTDIR: ++ printf ("Override the TMPDIR env var"); ++ break; ++ } ++ printf ("\n"); ++ } ++} ++ ++/* The PID of the test process. */ ++static pid_t test_pid; ++ ++/* The cleanup handler passed to test_main. */ ++static void (*cleanup_function) (void); ++ ++/* Timeout handler. We kill the child and exit with an error. */ ++static void ++__attribute__ ((noreturn)) ++signal_handler (int sig) ++{ ++ int killed; ++ int status; ++ ++ assert (test_pid > 1); ++ /* Kill the whole process group. */ ++ kill (-test_pid, SIGKILL); ++ /* In case setpgid failed in the child, kill it individually too. */ ++ kill (test_pid, SIGKILL); ++ ++ /* Wait for it to terminate. */ ++ int i; ++ for (i = 0; i < 5; ++i) ++ { ++ killed = waitpid (test_pid, &status, WNOHANG|WUNTRACED); ++ if (killed != 0) ++ break; ++ ++ /* Delay, give the system time to process the kill. If the ++ nanosleep() call return prematurely, all the better. We ++ won't restart it since this probably means the child process ++ finally died. */ ++ struct timespec ts; ++ ts.tv_sec = 0; ++ ts.tv_nsec = 100000000; ++ nanosleep (&ts, NULL); ++ } ++ if (killed != 0 && killed != test_pid) ++ { ++ printf ("Failed to kill test process: %m\n"); ++ exit (1); ++ } ++ ++ if (cleanup_function != NULL) ++ cleanup_function (); ++ ++ if (sig == SIGINT) ++ { ++ signal (sig, SIG_DFL); ++ raise (sig); ++ } ++ ++ if (killed == 0 || (WIFSIGNALED (status) && WTERMSIG (status) == SIGKILL)) ++ puts ("Timed out: killed the child process"); ++ else if (WIFSTOPPED (status)) ++ printf ("Timed out: the child process was %s\n", ++ strsignal (WSTOPSIG (status))); ++ else if (WIFSIGNALED (status)) ++ printf ("Timed out: the child process got signal %s\n", ++ strsignal (WTERMSIG (status))); ++ else ++ printf ("Timed out: killed the child process but it exited %d\n", ++ WEXITSTATUS (status)); ++ ++ /* Exit with an error. */ ++ exit (1); ++} ++ ++/* Run test_function or test_function_argv. */ ++static int ++run_test_function (int argc, char **argv, const struct test_config *config) ++{ ++ if (config->test_function != NULL) ++ return config->test_function (); ++ else if (config->test_function_argv != NULL) ++ return config->test_function_argv (argc, argv); ++ else ++ { ++ printf ("error: no test function defined\n"); ++ exit (1); ++ } ++} ++ ++static bool test_main_called; ++ ++const char *test_dir = NULL; ++unsigned int test_verbose = 0; ++ ++/* If test failure reporting has been linked in, it may contribute ++ additional test failures. */ ++static int ++adjust_exit_status (int status) ++{ ++ if (support_report_failure != NULL) ++ return support_report_failure (status); ++ return status; ++} ++ ++int ++support_test_main (int argc, char **argv, const struct test_config *config) ++{ ++ if (test_main_called) ++ { ++ printf ("error: test_main called for a second time\n"); ++ exit (1); ++ } ++ test_main_called = true; ++ const struct option *options; ++ if (config->options != NULL) ++ options = config->options; ++ else ++ options = default_options; ++ ++ cleanup_function = config->cleanup_function; ++ ++ int direct = 0; /* Directly call the test function? */ ++ int status; ++ int opt; ++ unsigned int timeoutfactor = 1; ++ pid_t termpid; ++ ++ if (!config->no_mallopt) ++ { ++ /* Make uses of freed and uninitialized memory known. Do not ++ pull in a definition for mallopt if it has not been defined ++ already. */ ++ extern __typeof__ (mallopt) mallopt __attribute__ ((weak)); ++ if (mallopt != NULL) ++ mallopt (M_PERTURB, 42); ++ } ++ ++ while ((opt = getopt_long (argc, argv, "+", options, NULL)) != -1) ++ switch (opt) ++ { ++ case '?': ++ usage (options); ++ exit (1); ++ case 'v': ++ ++test_verbose; ++ break; ++ case OPT_DIRECT: ++ direct = 1; ++ break; ++ case OPT_TESTDIR: ++ test_dir = optarg; ++ break; ++ default: ++ if (config->cmdline_function != NULL) ++ config->cmdline_function (opt); ++ } ++ ++ /* If set, read the test TIMEOUTFACTOR value from the environment. ++ This value is used to scale the default test timeout values. */ ++ char *envstr_timeoutfactor = getenv ("TIMEOUTFACTOR"); ++ if (envstr_timeoutfactor != NULL) ++ { ++ char *envstr_conv = envstr_timeoutfactor; ++ unsigned long int env_fact; ++ ++ env_fact = strtoul (envstr_timeoutfactor, &envstr_conv, 0); ++ if (*envstr_conv == '\0' && envstr_conv != envstr_timeoutfactor) ++ timeoutfactor = MAX (env_fact, 1); ++ } ++ ++ /* Set TMPDIR to specified test directory. */ ++ if (test_dir != NULL) ++ { ++ setenv ("TMPDIR", test_dir, 1); ++ ++ if (chdir (test_dir) < 0) ++ { ++ printf ("chdir: %m\n"); ++ exit (1); ++ } ++ } ++ else ++ { ++ test_dir = getenv ("TMPDIR"); ++ if (test_dir == NULL || test_dir[0] == '\0') ++ test_dir = "/tmp"; ++ } ++ if (support_set_test_dir != NULL) ++ support_set_test_dir (test_dir); ++ ++ int timeout = config->timeout; ++ if (timeout == 0) ++ timeout = DEFAULT_TIMEOUT; ++ ++ /* Make sure we see all message, even those on stdout. */ ++ setvbuf (stdout, NULL, _IONBF, 0); ++ ++ /* Make sure temporary files are deleted. */ ++ if (support_delete_temp_files != NULL) ++ atexit (support_delete_temp_files); ++ ++ /* Correct for the possible parameters. */ ++ argv[optind - 1] = argv[0]; ++ argv += optind - 1; ++ argc -= optind - 1; ++ ++ /* Call the initializing function, if one is available. */ ++ if (config->prepare_function != NULL) ++ config->prepare_function (argc, argv); ++ ++ const char *envstr_direct = getenv ("TEST_DIRECT"); ++ if (envstr_direct != NULL) ++ { ++ FILE *f = fopen (envstr_direct, "w"); ++ if (f == NULL) ++ { ++ printf ("cannot open TEST_DIRECT output file '%s': %m\n", ++ envstr_direct); ++ exit (1); ++ } ++ ++ fprintf (f, "timeout=%u\ntimeoutfactor=%u\n", ++ config->timeout, timeoutfactor); ++ if (config->expected_status != 0) ++ fprintf (f, "exit=%u\n", config->expected_status); ++ if (config->expected_signal != 0) ++ fprintf (f, "signal=%s\n", strsignal (config->expected_signal)); ++ ++ if (support_print_temp_files != NULL) ++ support_print_temp_files (f); ++ ++ fclose (f); ++ direct = 1; ++ } ++ ++ bool disable_coredumps; ++ { ++ const char *coredumps = getenv ("TEST_COREDUMPS"); ++ disable_coredumps = coredumps == NULL || coredumps[0] == '\0'; ++ } ++ ++ /* If we are not expected to fork run the function immediately. */ ++ if (direct) ++ return adjust_exit_status (run_test_function (argc, argv, config)); ++ ++ /* Set up the test environment: ++ - prevent core dumps ++ - set up the timer ++ - fork and execute the function. */ ++ ++ test_pid = fork (); ++ if (test_pid == 0) ++ { ++ /* This is the child. */ ++ if (disable_coredumps) ++ { ++ /* Try to avoid dumping core. This is necessary because we ++ run the test from the source tree, and the coredumps ++ would end up there (and not in the build tree). */ ++ struct rlimit core_limit; ++ core_limit.rlim_cur = 0; ++ core_limit.rlim_max = 0; ++ setrlimit (RLIMIT_CORE, &core_limit); ++ } ++ ++ /* We put the test process in its own pgrp so that if it bogusly ++ generates any job control signals, they won't hit the whole build. */ ++ if (setpgid (0, 0) != 0) ++ printf ("Failed to set the process group ID: %m\n"); ++ ++ /* Execute the test function and exit with the return value. */ ++ exit (run_test_function (argc, argv, config)); ++ } ++ else if (test_pid < 0) ++ { ++ printf ("Cannot fork test program: %m\n"); ++ exit (1); ++ } ++ ++ /* Set timeout. */ ++ signal (SIGALRM, signal_handler); ++ alarm (timeout * timeoutfactor); ++ ++ /* Make sure we clean up if the wrapper gets interrupted. */ ++ signal (SIGINT, signal_handler); ++ ++ /* Wait for the regular termination. */ ++ termpid = TEMP_FAILURE_RETRY (waitpid (test_pid, &status, 0)); ++ if (termpid == -1) ++ { ++ printf ("Waiting for test program failed: %m\n"); ++ exit (1); ++ } ++ if (termpid != test_pid) ++ { ++ printf ("Oops, wrong test program terminated: expected %ld, got %ld\n", ++ (long int) test_pid, (long int) termpid); ++ exit (1); ++ } ++ ++ /* Process terminated normaly without timeout etc. */ ++ if (WIFEXITED (status)) ++ { ++ if (config->expected_status == 0) ++ { ++ if (config->expected_signal == 0) ++ /* Exit with the return value of the test. */ ++ return adjust_exit_status (WEXITSTATUS (status)); ++ else ++ { ++ printf ("Expected signal '%s' from child, got none\n", ++ strsignal (config->expected_signal)); ++ exit (1); ++ } ++ } ++ else ++ { ++ /* Non-zero exit status is expected */ ++ if (WEXITSTATUS (status) != config->expected_status) ++ { ++ printf ("Expected status %d, got %d\n", ++ config->expected_status, WEXITSTATUS (status)); ++ exit (1); ++ } ++ } ++ return adjust_exit_status (0); ++ } ++ /* Process was killed by timer or other signal. */ ++ else ++ { ++ if (config->expected_signal == 0) ++ { ++ printf ("Didn't expect signal from child: got `%s'\n", ++ strsignal (WTERMSIG (status))); ++ exit (1); ++ } ++ else if (WTERMSIG (status) != config->expected_signal) ++ { ++ printf ("Incorrect signal from child: got `%s', need `%s'\n", ++ strsignal (WTERMSIG (status)), ++ strsignal (config->expected_signal)); ++ exit (1); ++ } ++ ++ return adjust_exit_status (0); ++ } ++} +diff --git a/support/support_test_verify_impl.c b/support/support_test_verify_impl.c +new file mode 100644 +index 0000000000..5bae38f8b1 +--- /dev/null ++++ b/support/support_test_verify_impl.c +@@ -0,0 +1,33 @@ ++/* Implementation of the TEST_VERIFY and TEST_VERIFY_EXIT macros. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <support/check.h> ++ ++#include <stdio.h> ++#include <stdlib.h> ++ ++void ++support_test_verify_impl (int status, const char *file, int line, ++ const char *expr) ++{ ++ support_record_failure (); ++ printf ("error: %s:%d: not true: %s\n", file, line, expr); ++ if (status >= 0) ++ exit (status); ++ ++} +diff --git a/support/support_write_file_string.c b/support/support_write_file_string.c +new file mode 100644 +index 0000000000..48e89597f3 +--- /dev/null ++++ b/support/support_write_file_string.c +@@ -0,0 +1,39 @@ ++/* Write a string to a file. ++ Copyright (C) 2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <fcntl.h> ++#include <string.h> ++#include <support/check.h> ++#include <xunistd.h> ++ ++void ++support_write_file_string (const char *path, const char *contents) ++{ ++ int fd = xopen (path, O_CREAT | O_TRUNC | O_WRONLY, 0666); ++ const char *end = contents + strlen (contents); ++ for (const char *p = contents; p < end; ) ++ { ++ ssize_t ret = write (fd, p, end - p); ++ if (ret < 0) ++ FAIL_EXIT1 ("cannot write to \"%s\": %m", path); ++ if (ret == 0) ++ FAIL_EXIT1 ("zero-length write to \"%s\"", path); ++ p += ret; ++ } ++ xclose (fd); ++} +diff --git a/support/temp_file-internal.h b/support/temp_file-internal.h +new file mode 100644 +index 0000000000..fb6cceb065 +--- /dev/null ++++ b/support/temp_file-internal.h +@@ -0,0 +1,31 @@ ++/* Internal weak declarations for temporary file handling. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#ifndef SUPPORT_TEMP_FILE_INTERNAL_H ++#define SUPPORT_TEMP_FILE_INTERNAL_H ++ ++/* These functions are called by the test driver if they are ++ defined. Tests should not call them directly. */ ++ ++#include <stdio.h> ++ ++void support_set_test_dir (const char *name) __attribute__ ((weak)); ++void support_delete_temp_files (void) __attribute__ ((weak)); ++void support_print_temp_files (FILE *) __attribute__ ((weak)); ++ ++#endif /* SUPPORT_TEMP_FILE_INTERNAL_H */ +diff --git a/support/temp_file.c b/support/temp_file.c +new file mode 100644 +index 0000000000..fdb2477ab9 +--- /dev/null ++++ b/support/temp_file.c +@@ -0,0 +1,132 @@ ++/* Temporary file handling for tests. ++ Copyright (C) 1998-2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++/* This is required to get an mkstemp which can create large files on ++ some 32-bit platforms. */ ++#define _FILE_OFFSET_BITS 64 ++ ++#include <support/temp_file.h> ++#include <support/temp_file-internal.h> ++#include <support/support.h> ++ ++#include <paths.h> ++#include <stdio.h> ++#include <stdlib.h> ++#include <string.h> ++#include <unistd.h> ++ ++/* List of temporary files. */ ++static struct temp_name_list ++{ ++ struct temp_name_list *next; ++ char *name; ++ pid_t owner; ++} *temp_name_list; ++ ++/* Location of the temporary files. Set by the test skeleton via ++ support_set_test_dir. The string is not be freed. */ ++static const char *test_dir = _PATH_TMP; ++ ++void ++add_temp_file (const char *name) ++{ ++ struct temp_name_list *newp ++ = (struct temp_name_list *) xcalloc (sizeof (*newp), 1); ++ char *newname = strdup (name); ++ if (newname != NULL) ++ { ++ newp->name = newname; ++ newp->next = temp_name_list; ++ newp->owner = getpid (); ++ temp_name_list = newp; ++ } ++ else ++ free (newp); ++} ++ ++int ++create_temp_file (const char *base, char **filename) ++{ ++ char *fname; ++ int fd; ++ ++ fname = (char *) xmalloc (strlen (test_dir) + 1 + strlen (base) ++ + sizeof ("XXXXXX")); ++ strcpy (stpcpy (stpcpy (stpcpy (fname, test_dir), "/"), base), "XXXXXX"); ++ ++ fd = mkstemp (fname); ++ if (fd == -1) ++ { ++ printf ("cannot open temporary file '%s': %m\n", fname); ++ free (fname); ++ return -1; ++ } ++ ++ add_temp_file (fname); ++ if (filename != NULL) ++ *filename = fname; ++ else ++ free (fname); ++ ++ return fd; ++} ++ ++/* Helper functions called by the test skeleton follow. */ ++ ++void ++support_set_test_dir (const char *path) ++{ ++ test_dir = path; ++} ++ ++void ++support_delete_temp_files (void) ++{ ++ pid_t pid = getpid (); ++ while (temp_name_list != NULL) ++ { ++ /* Only perform the removal if the path was registed in the same ++ process, as identified by the PID. (This assumes that the ++ parent process which registered the temporary file sticks ++ around, to prevent PID reuse.) */ ++ if (temp_name_list->owner == pid) ++ { ++ if (remove (temp_name_list->name) != 0) ++ printf ("warning: could not remove temporary file: %s: %m\n", ++ temp_name_list->name); ++ } ++ free (temp_name_list->name); ++ ++ struct temp_name_list *next = temp_name_list->next; ++ free (temp_name_list); ++ temp_name_list = next; ++ } ++} ++ ++void ++support_print_temp_files (FILE *f) ++{ ++ if (temp_name_list != NULL) ++ { ++ struct temp_name_list *n; ++ fprintf (f, "temp_files=(\n"); ++ for (n = temp_name_list; n != NULL; n = n->next) ++ fprintf (f, " '%s'\n", n->name); ++ fprintf (f, ")\n"); ++ } ++} +diff --git a/support/temp_file.h b/support/temp_file.h +new file mode 100644 +index 0000000000..6fed8df1ea +--- /dev/null ++++ b/support/temp_file.h +@@ -0,0 +1,37 @@ ++/* Declarations for temporary file handling. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#ifndef SUPPORT_TEMP_FILE_H ++#define SUPPORT_TEMP_FILE_H ++ ++#include <sys/cdefs.h> ++ ++__BEGIN_DECLS ++ ++/* Schedule a temporary file for deletion on exit. */ ++void add_temp_file (const char *name); ++ ++/* Create a temporary file. Return the opened file descriptor on ++ success, or -1 on failure. Write the file name to *FILENAME if ++ FILENAME is not NULL. In this case, the caller is expected to free ++ *FILENAME. */ ++int create_temp_file (const char *base, char **filename); ++ ++__END_DECLS ++ ++#endif /* SUPPORT_TEMP_FILE_H */ +diff --git a/support/test-driver.c b/support/test-driver.c +new file mode 100644 +index 0000000000..482066dbeb +--- /dev/null ++++ b/support/test-driver.c +@@ -0,0 +1,156 @@ ++/* Main function for test programs. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++/* This file should be included from test cases. It will define a ++ main function which provides the test wrapper. ++ ++ It assumes that the test case defines a function ++ ++ int do_test (void); ++ ++ and arranges for that function being called under the test wrapper. ++ The do_test function should return 0 to indicate a passing test, 1 ++ to indicate a failing test, or 77 to indicate an unsupported test. ++ Other result values could be used to indicate a failing test, but ++ the result of the expression is passed to exit and exit only ++ returns the lower 8 bits of its input. A non-zero return with some ++ values could cause a test to incorrectly be considered passing when ++ it really failed. For this reason, the function should always ++ return 0 (EXIT_SUCCESS), 1 (EXIT_FAILURE), or 77 ++ (EXIT_UNSUPPORTED). ++ ++ The test function may print out diagnostic or warning messages as well ++ as messages about failures. These messages should be printed to stdout ++ and not stderr so that the output is properly ordered with respect to ++ the rest of the glibc testsuite run output. ++ ++ Several preprocessors macros can be defined before including this ++ file. ++ ++ The name of the do_test function can be changed with the ++ TEST_FUNCTION macro. It must expand to the desired function name. ++ ++ If the test case needs access to command line parameters, it must ++ define the TEST_FUNCTION_ARGV macro with the name of the test ++ function. It must have the following type: ++ ++ int TEST_FUNCTION_ARGV (int argc, char **argv); ++ ++ This overrides the do_test default function and is incompatible ++ with the TEST_FUNCTION macro. ++ ++ If PREPARE is defined, it must expand to the name of a function of ++ the type ++ ++ void PREPARE (int argc, char **); ++ ++ This function will be called early, after parsing the command line, ++ but before running the test, in the parent process which acts as ++ the test supervisor. ++ ++ If CLEANUP_HANDLER is defined, it must expand to the name of a ++ function of the type ++ ++ void CLEANUP_HANDLER (void); ++ ++ This function will be called from the timeout (SIGALRM) signal ++ handler. ++ ++ If EXPECTED_SIGNAL is defined, it must expanded to a constant which ++ denotes the expected signal number. ++ ++ If EXPECTED_STATUS is defined, it must expand to the expected exit ++ status. ++ ++ If TIMEOUT is defined, it must be positive constant. It overrides ++ the default test timeout and is measured in seconds. ++ ++ If TEST_NO_MALLOPT is defined, the test wrapper will not call ++ mallopt. ++ ++ Custom command line handling can be implemented by defining the ++ CMDLINE_OPTION macro (after including the <getopt.h> header; this ++ requires _GNU_SOURCE to be defined). This macro must expand to a ++ to a comma-separated list of braced initializers for struct option ++ from <getopt.h>, with a trailing comma. CMDLINE_PROCESS can be ++ defined as the name of a function which is called to process these ++ options. The function is passed the option character/number and ++ has this type: ++ ++ void CMDLINE_PROCESS (int); ++*/ ++ ++#include <support/test-driver.h> ++ ++#include <string.h> ++ ++int ++main (int argc, char **argv) ++{ ++ struct test_config test_config; ++ memset (&test_config, 0, sizeof (test_config)); ++ ++#ifdef PREPARE ++ test_config.prepare_function = (PREPARE); ++#endif ++ ++#if defined (TEST_FUNCTION) && defined (TEST_FUNCTON_ARGV) ++# error TEST_FUNCTION and TEST_FUNCTION_ARGV cannot be defined at the same time ++#endif ++#if defined (TEST_FUNCTION) ++ test_config.test_function = TEST_FUNCTION; ++#elif defined (TEST_FUNCTION_ARGV) ++ test_config.test_function_argv = TEST_FUNCTION_ARGV; ++#else ++ test_config.test_function = do_test; ++#endif ++ ++#ifdef CLEANUP_HANDLER ++ test_config.cleanup_function = CLEANUP_HANDLER; ++#endif ++ ++#ifdef EXPECTED_SIGNAL ++ test_config.expected_signal = (EXPECTED_SIGNAL); ++#endif ++ ++#ifdef EXPECTED_STATUS ++ test_config.expected_status = (EXPECTED_STATUS); ++#endif ++ ++#ifdef TEST_NO_MALLOPT ++ test_config.no_mallopt = 1; ++#endif ++ ++#ifdef TIMEOUT ++ test_config.timeout = TIMEOUT; ++#endif ++ ++#ifdef CMDLINE_OPTIONS ++ struct option options[] = ++ { ++ CMDLINE_OPTIONS ++ TEST_DEFAULT_OPTIONS ++ }; ++ test_config.options = &options; ++#endif ++#ifdef CMDLINE_PROCESS ++ test_config.cmdline_function = CMDLINE_PROCESS; ++#endif ++ ++ return support_test_main (argc, argv, &test_config); ++} +diff --git a/support/test-driver.h b/support/test-driver.h +new file mode 100644 +index 0000000000..af1971a9ca +--- /dev/null ++++ b/support/test-driver.h +@@ -0,0 +1,74 @@ ++/* Interfaces for the test driver. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#ifndef SUPPORT_TEST_DRIVER_H ++#define SUPPORT_TEST_DRIVER_H ++ ++#include <sys/cdefs.h> ++ ++__BEGIN_DECLS ++ ++struct test_config ++{ ++ void (*prepare_function) (int argc, char **argv); ++ int (*test_function) (void); ++ int (*test_function_argv) (int argc, char **argv); ++ void (*cleanup_function) (void); ++ void (*cmdline_function) (int); ++ const void *options; /* Custom options if not NULL. */ ++ int timeout; /* Test timeout in seconds. */ ++ int expected_status; /* Expected exit status. */ ++ int expected_signal; /* If non-zero, expect termination by signal. */ ++ char no_mallopt; /* Boolean flag to disable mallopt. */ ++}; ++ ++enum ++ { ++ /* Test exit status which indicates that the feature is ++ unsupported. */ ++ EXIT_UNSUPPORTED = 77, ++ ++ /* Default timeout is twenty seconds. Tests should normally ++ complete faster than this, but if they don't, that's abnormal ++ (a bug) anyways. */ ++ DEFAULT_TIMEOUT = 20, ++ ++ /* Used for command line argument parsing. */ ++ OPT_DIRECT = 1000, ++ OPT_TESTDIR, ++ }; ++ ++/* Options provided by the test driver. */ ++#define TEST_DEFAULT_OPTIONS \ ++ { "verbose", no_argument, NULL, 'v' }, \ ++ { "direct", no_argument, NULL, OPT_DIRECT }, \ ++ { "test-dir", required_argument, NULL, OPT_TESTDIR }, \ ++ ++/* The directory the test should use for temporary files. */ ++extern const char *test_dir; ++ ++/* The number of --verbose arguments specified during program ++ invocation. This variable can be used to control the verbosity of ++ tests. */ ++extern unsigned int test_verbose; ++ ++int support_test_main (int argc, char **argv, const struct test_config *); ++ ++__END_DECLS ++ ++#endif /* SUPPORT_TEST_DRIVER_H */ +diff --git a/support/tst-support-namespace.c b/support/tst-support-namespace.c +new file mode 100644 +index 0000000000..a50b074f5e +--- /dev/null ++++ b/support/tst-support-namespace.c +@@ -0,0 +1,34 @@ ++/* Test entering namespaces. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <stdio.h> ++#include <support/namespace.h> ++ ++static int ++do_test (void) ++{ ++ if (support_become_root ()) ++ printf ("info: acquired root-like privileges\n"); ++ if (support_enter_network_namespace ()) ++ printf ("info: entered network namespace\n"); ++ if (support_in_uts_namespace ()) ++ printf ("info: also entered UTS namespace\n"); ++ return 0; ++} ++ ++#include <support/test-driver.c> +diff --git a/support/tst-support_capture_subprocess.c b/support/tst-support_capture_subprocess.c +new file mode 100644 +index 0000000000..5672fba0f7 +--- /dev/null ++++ b/support/tst-support_capture_subprocess.c +@@ -0,0 +1,188 @@ ++/* Test capturing output from a subprocess. ++ Copyright (C) 2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <stdbool.h> ++#include <stdio.h> ++#include <stdlib.h> ++#include <string.h> ++#include <support/capture_subprocess.h> ++#include <support/check.h> ++#include <support/support.h> ++#include <sys/wait.h> ++#include <unistd.h> ++ ++/* Write one byte at *P to FD and advance *P. Do nothing if *P is ++ '\0'. */ ++static void ++transfer (const unsigned char **p, int fd) ++{ ++ if (**p != '\0') ++ { ++ TEST_VERIFY (write (fd, *p, 1) == 1); ++ ++*p; ++ } ++} ++ ++/* Determine the order in which stdout and stderr are written. */ ++enum write_mode { out_first, err_first, interleave, ++ write_mode_last = interleave }; ++ ++/* Describe what to write in the subprocess. */ ++struct test ++{ ++ char *out; ++ char *err; ++ enum write_mode write_mode; ++ int signal; ++ int status; ++}; ++ ++/* For use with support_capture_subprocess. */ ++static void ++callback (void *closure) ++{ ++ const struct test *test = closure; ++ bool mode_ok = false; ++ switch (test->write_mode) ++ { ++ case out_first: ++ TEST_VERIFY (fputs (test->out, stdout) >= 0); ++ TEST_VERIFY (fflush (stdout) == 0); ++ TEST_VERIFY (fputs (test->err, stderr) >= 0); ++ TEST_VERIFY (fflush (stderr) == 0); ++ mode_ok = true; ++ break; ++ case err_first: ++ TEST_VERIFY (fputs (test->err, stderr) >= 0); ++ TEST_VERIFY (fflush (stderr) == 0); ++ TEST_VERIFY (fputs (test->out, stdout) >= 0); ++ TEST_VERIFY (fflush (stdout) == 0); ++ mode_ok = true; ++ break; ++ case interleave: ++ { ++ const unsigned char *pout = (const unsigned char *) test->out; ++ const unsigned char *perr = (const unsigned char *) test->err; ++ do ++ { ++ transfer (&pout, STDOUT_FILENO); ++ transfer (&perr, STDERR_FILENO); ++ } ++ while (*pout != '\0' || *perr != '\0'); ++ } ++ mode_ok = true; ++ break; ++ } ++ TEST_VERIFY (mode_ok); ++ ++ if (test->signal != 0) ++ raise (test->signal); ++ exit (test->status); ++} ++ ++/* Create a heap-allocated random string of letters. */ ++static char * ++random_string (size_t length) ++{ ++ char *result = xmalloc (length + 1); ++ for (size_t i = 0; i < length; ++i) ++ result[i] = 'a' + (rand () % 26); ++ result[length] = '\0'; ++ return result; ++} ++ ++/* Check that the specific stream from the captured subprocess matches ++ expectations. */ ++static void ++check_stream (const char *what, const struct xmemstream *stream, ++ const char *expected) ++{ ++ if (strcmp (stream->buffer, expected) != 0) ++ { ++ support_record_failure (); ++ printf ("error: captured %s data incorrect\n" ++ " expected: %s\n" ++ " actual: %s\n", ++ what, expected, stream->buffer); ++ } ++ if (stream->length != strlen (expected)) ++ { ++ support_record_failure (); ++ printf ("error: captured %s data length incorrect\n" ++ " expected: %zu\n" ++ " actual: %zu\n", ++ what, strlen (expected), stream->length); ++ } ++} ++ ++static int ++do_test (void) ++{ ++ const int lengths[] = {0, 1, 17, 512, 20000, -1}; ++ ++ /* Test multiple combinations of support_capture_subprocess. ++ ++ length_idx_stdout: Index into the lengths array above, ++ controls how many bytes are written by the subprocess to ++ standard output. ++ length_idx_stderr: Same for standard error. ++ write_mode: How standard output and standard error writes are ++ ordered. ++ signal: Exit with no signal if zero, with SIGTERM if one. ++ status: Process exit status: 0 if zero, 3 if one. */ ++ for (int length_idx_stdout = 0; lengths[length_idx_stdout] >= 0; ++ ++length_idx_stdout) ++ for (int length_idx_stderr = 0; lengths[length_idx_stderr] >= 0; ++ ++length_idx_stderr) ++ for (int write_mode = 0; write_mode < write_mode_last; ++write_mode) ++ for (int signal = 0; signal < 2; ++signal) ++ for (int status = 0; status < 2; ++status) ++ { ++ struct test test = ++ { ++ .out = random_string (lengths[length_idx_stdout]), ++ .err = random_string (lengths[length_idx_stderr]), ++ .write_mode = write_mode, ++ .signal = signal * SIGTERM, /* 0 or SIGTERM. */ ++ .status = status * 3, /* 0 or 3. */ ++ }; ++ TEST_VERIFY (strlen (test.out) == lengths[length_idx_stdout]); ++ TEST_VERIFY (strlen (test.err) == lengths[length_idx_stderr]); ++ ++ struct support_capture_subprocess result ++ = support_capture_subprocess (callback, &test); ++ check_stream ("stdout", &result.out, test.out); ++ check_stream ("stderr", &result.err, test.err); ++ if (test.signal != 0) ++ { ++ TEST_VERIFY (WIFSIGNALED (result.status)); ++ TEST_VERIFY (WTERMSIG (result.status) == test.signal); ++ } ++ else ++ { ++ TEST_VERIFY (WIFEXITED (result.status)); ++ TEST_VERIFY (WEXITSTATUS (result.status) == test.status); ++ } ++ support_capture_subprocess_free (&result); ++ free (test.out); ++ free (test.err); ++ } ++ return 0; ++} ++ ++#include <support/test-driver.c> +diff --git a/support/tst-support_format_dns_packet.c b/support/tst-support_format_dns_packet.c +new file mode 100644 +index 0000000000..9c8589c09c +--- /dev/null ++++ b/support/tst-support_format_dns_packet.c +@@ -0,0 +1,101 @@ ++/* Tests for the support_format_dns_packet function. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <support/check.h> ++#include <support/format_nss.h> ++#include <support/run_diff.h> ++ ++#include <stdio.h> ++#include <stdlib.h> ++#include <string.h> ++ ++static void ++check_packet (const void *buffer, size_t length, ++ const char *name, const char *expected) ++{ ++ char *actual = support_format_dns_packet (buffer, length); ++ if (strcmp (actual, expected) != 0) ++ { ++ support_record_failure (); ++ printf ("error: formatted packet does not match: %s\n", name); ++ support_run_diff ("expected", expected, ++ "actual", actual); ++ } ++ free (actual); ++} ++ ++static void ++test_aaaa_length (void) ++{ ++ static const char packet[] = ++ /* Header: Response with two records. */ ++ "\x12\x34\x80\x00\x00\x01\x00\x02\x00\x00\x00\x00" ++ /* Question section. www.example/IN/AAAA. */ ++ "\x03www\x07""example\x00\x00\x1c\x00\x01" ++ /* Answer section. www.example AAAA [corrupted]. */ ++ "\xc0\x0c" ++ "\x00\x1c\x00\x01\x00\x00\x00\x00\x00\x10" ++ "\x20\x01\x0d\xb8\x05\x06\x07\x08" ++ "\x11\x12\x13\x14\x15\x16\x17\x18" ++ /* www.example AAAA [corrupted]. */ ++ "\xc0\x0c" ++ "\x00\x1c\x00\x01\x00\x00\x00\x00\x00\x11" ++ "\x01\x02\x03\x04\x05\x06\x07\x08" ++ "\x11\x12\x13\x14\x15\x16\x17\x18" "\xff"; ++ check_packet (packet, sizeof (packet) - 1, __func__, ++ "name: www.example\n" ++ "address: 2001:db8:506:708:1112:1314:1516:1718\n" ++ "error: AAAA record of size 17: www.example\n"); ++} ++ ++static void ++test_multiple_cnames (void) ++{ ++ static const char packet[] = ++ /* Header: Response with three records. */ ++ "\x12\x34\x80\x00\x00\x01\x00\x03\x00\x00\x00\x00" ++ /* Question section. www.example/IN/A. */ ++ "\x03www\x07""example\x00\x00\x01\x00\x01" ++ /* Answer section. www.example CNAME www1.example. */ ++ "\xc0\x0c" ++ "\x00\x05\x00\x01\x00\x00\x00\x00\x00\x07" ++ "\x04www1\xc0\x10" ++ /* www1 CNAME www2. */ ++ "\x04www1\xc0\x10" ++ "\x00\x05\x00\x01\x00\x00\x00\x00\x00\x07" ++ "\x04www2\xc0\x10" ++ /* www2 A 192.0.2.1. */ ++ "\x04www2\xc0\x10" ++ "\x00\x01\x00\x01\x00\x00\x00\x00\x00\x04" ++ "\xc0\x00\x02\x01"; ++ check_packet (packet, sizeof (packet) - 1, __func__, ++ "name: www.example\n" ++ "name: www1.example\n" ++ "name: www2.example\n" ++ "address: 192.0.2.1\n"); ++} ++ ++static int ++do_test (void) ++{ ++ test_aaaa_length (); ++ test_multiple_cnames (); ++ return 0; ++} ++ ++#include <support/test-driver.c> +diff --git a/support/tst-support_record_failure-2.sh b/support/tst-support_record_failure-2.sh +new file mode 100644 +index 0000000000..2c9372cc29 +--- /dev/null ++++ b/support/tst-support_record_failure-2.sh +@@ -0,0 +1,69 @@ ++#!/bin/sh ++# Test failure recording (with and without --direct). ++# Copyright (C) 2016-2017 Free Software Foundation, Inc. ++# This file is part of the GNU C Library. ++ ++# The GNU C Library is free software; you can redistribute it and/or ++# modify it under the terms of the GNU Lesser General Public ++# License as published by the Free Software Foundation; either ++# version 2.1 of the License, or (at your option) any later version. ++# ++# The GNU C Library 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 ++# Lesser General Public License for more details. ++# ++# You should have received a copy of the GNU Lesser General Public ++# License along with the GNU C Library; if not, see ++# <http://www.gnu.org/licenses/>. */ ++ ++set -e ++ ++common_objpfx=$1; shift ++test_program_prefix_before_env=$1; shift ++run_program_env=$1; shift ++test_program_prefix_after_env=$1; shift ++ ++run_test () { ++ expected_status="$1" ++ expected_output="$2" ++ shift 2 ++ args="${common_objpfx}support/tst-support_record_failure $*" ++ echo "running: $args" ++ set +e ++ output="$(${test_program_prefix_before_env} \ ++ ${run_program} ${test_program_prefix_after_env} $args)" ++ status=$? ++ set -e ++ echo " exit status: $status" ++ if test "$output" != "$expected_output" ; then ++ echo "error: unexpected output: $output" ++ exit 1 ++ fi ++ if test "$status" -ne "$expected_status" ; then ++ echo "error: exit status $expected_status expected" ++ exit 1 ++ fi ++} ++ ++different_status () { ++ direct="$1" ++ run_test 1 "error: 1 test failures" $direct --status=0 ++ run_test 1 "error: 1 test failures" $direct --status=1 ++ run_test 2 "error: 1 test failures" $direct --status=2 ++ run_test 1 "error: 1 test failures" $direct --status=77 ++ run_test 2 "error: tst-support_record_failure.c:109: not true: false ++error: 1 test failures" $direct --test-verify ++ run_test 2 "error: tst-support_record_failure.c:109: not true: false ++info: execution passed failed TEST_VERIFY ++error: 1 test failures" $direct --test-verify --verbose ++} ++ ++different_status ++different_status --direct ++ ++run_test 1 "error: tst-support_record_failure.c:116: not true: false ++error: 1 test failures" --test-verify-exit ++# --direct does not print the summary error message if exit is called. ++run_test 1 "error: tst-support_record_failure.c:116: not true: false" \ ++ --direct --test-verify-exit +diff --git a/support/tst-support_record_failure.c b/support/tst-support_record_failure.c +new file mode 100644 +index 0000000000..e739e739c3 +--- /dev/null ++++ b/support/tst-support_record_failure.c +@@ -0,0 +1,153 @@ ++/* Test support_record_failure state sharing. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <support/check.h> ++#include <support/support.h> ++#include <support/test-driver.h> ++#include <support/xunistd.h> ++ ++#include <getopt.h> ++#include <stdbool.h> ++#include <stdlib.h> ++#include <stdio.h> ++#include <string.h> ++ ++static int exit_status_with_failure = -1; ++static bool test_verify; ++static bool test_verify_exit; ++enum ++ { ++ OPT_STATUS = 10001, ++ OPT_TEST_VERIFY, ++ OPT_TEST_VERIFY_EXIT, ++ }; ++#define CMDLINE_OPTIONS \ ++ { "status", required_argument, NULL, OPT_STATUS }, \ ++ { "test-verify", no_argument, NULL, OPT_TEST_VERIFY }, \ ++ { "test-verify-exit", no_argument, NULL, OPT_TEST_VERIFY_EXIT }, ++static void ++cmdline_process (int c) ++{ ++ switch (c) ++ { ++ case OPT_STATUS: ++ exit_status_with_failure = atoi (optarg); ++ break; ++ case OPT_TEST_VERIFY: ++ test_verify = true; ++ break; ++ case OPT_TEST_VERIFY_EXIT: ++ test_verify_exit = true; ++ break; ++ } ++} ++#define CMDLINE_PROCESS cmdline_process ++ ++static void ++check_failure_reporting (int phase, int zero, int unsupported) ++{ ++ int status = support_report_failure (0); ++ if (status != zero) ++ { ++ printf ("real-error (phase %d): support_report_failure (0) == %d\n", ++ phase, status); ++ exit (1); ++ } ++ status = support_report_failure (1); ++ if (status != 1) ++ { ++ printf ("real-error (phase %d): support_report_failure (1) == %d\n", ++ phase, status); ++ exit (1); ++ } ++ status = support_report_failure (2); ++ if (status != 2) ++ { ++ printf ("real-error (phase %d): support_report_failure (2) == %d\n", ++ phase, status); ++ exit (1); ++ } ++ status = support_report_failure (EXIT_UNSUPPORTED); ++ if (status != unsupported) ++ { ++ printf ("real-error (phase %d): " ++ "support_report_failure (EXIT_UNSUPPORTED) == %d\n", ++ phase, status); ++ exit (1); ++ } ++} ++ ++static int ++do_test (void) ++{ ++ if (exit_status_with_failure >= 0) ++ { ++ /* External invocation with requested error status. Used by ++ tst-support_report_failure-2.sh. */ ++ support_record_failure (); ++ return exit_status_with_failure; ++ } ++ TEST_VERIFY (true); ++ TEST_VERIFY_EXIT (true); ++ if (test_verify) ++ { ++ TEST_VERIFY (false); ++ if (test_verbose) ++ printf ("info: execution passed failed TEST_VERIFY\n"); ++ return 2; /* Expected exit status. */ ++ } ++ if (test_verify_exit) ++ { ++ TEST_VERIFY_EXIT (false); ++ return 3; /* Not reached. Expected exit status is 1. */ ++ } ++ ++ printf ("info: This test tests the test framework.\n" ++ "info: It reports some expected errors on stdout.\n"); ++ ++ /* Check that the status is passed through unchanged. */ ++ check_failure_reporting (1, 0, EXIT_UNSUPPORTED); ++ ++ /* Check state propagation from a subprocess. */ ++ pid_t pid = xfork (); ++ if (pid == 0) ++ { ++ support_record_failure (); ++ _exit (0); ++ } ++ int status; ++ xwaitpid (pid, &status, 0); ++ if (status != 0) ++ { ++ printf ("real-error: incorrect status from subprocess: %d\n", status); ++ return 1; ++ } ++ check_failure_reporting (2, 1, 1); ++ ++ /* Also test directly in the parent process. */ ++ support_record_failure_reset (); ++ check_failure_reporting (3, 0, EXIT_UNSUPPORTED); ++ support_record_failure (); ++ check_failure_reporting (4, 1, 1); ++ ++ /* We need to mask the failure above. */ ++ support_record_failure_reset (); ++ return 0; ++} ++ ++#include <support/test-driver.c> +diff --git a/sysdeps/unix/sysv/linux/sh/pwrite64.c b/support/write_message.c +similarity index 68% +rename from sysdeps/unix/sysv/linux/sh/pwrite64.c +rename to support/write_message.c +index 683a5d9886..f03ed931d6 100644 +--- a/sysdeps/unix/sysv/linux/sh/pwrite64.c ++++ b/support/write_message.c +@@ -1,6 +1,6 @@ +-/* Copyright (C) 1997-2016 Free Software Foundation, Inc. ++/* Write a message to standard output. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. +- Contributed by Ralf Baechle <ralf@gnu.org>, 1998. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public +@@ -16,8 +16,14 @@ + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +-/* SH4 ABI does not really require argument alignment for 64-bits, but +- the kernel interface for pread adds a dummy long argument before the +- offset. */ +-#define __ALIGNMENT_ARG +-#include <sysdeps/unix/sysv/linux/pwrite64.c> ++#include <support/support.h> ++ ++#include <string.h> ++#include <unistd.h> ++ ++void ++write_message (const char *message) ++{ ++ ssize_t unused __attribute__ ((unused)); ++ unused = write (STDOUT_FILENO, message, strlen (message)); ++} +diff --git a/support/xaccept.c b/support/xaccept.c +new file mode 100644 +index 0000000000..7b25af3b05 +--- /dev/null ++++ b/support/xaccept.c +@@ -0,0 +1,32 @@ ++/* accept with error checking. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <support/xsocket.h> ++ ++#include <stdio.h> ++#include <stdlib.h> ++#include <support/check.h> ++ ++int ++xaccept (int fd, struct sockaddr *sa, socklen_t *salen) ++{ ++ int clientfd = accept (fd, sa, salen); ++ if (clientfd < 0) ++ FAIL_EXIT1 ("accept (%d): %m", fd); ++ return clientfd; ++} +diff --git a/support/xaccept4.c b/support/xaccept4.c +new file mode 100644 +index 0000000000..67dd95e9fb +--- /dev/null ++++ b/support/xaccept4.c +@@ -0,0 +1,32 @@ ++/* accept4 with error checking. ++ Copyright (C) 2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <support/xsocket.h> ++ ++#include <stdio.h> ++#include <stdlib.h> ++#include <support/check.h> ++ ++int ++xaccept4 (int fd, struct sockaddr *sa, socklen_t *salen, int flags) ++{ ++ int clientfd = accept4 (fd, sa, salen, flags); ++ if (clientfd < 0) ++ FAIL_EXIT1 ("accept4 (%d, 0x%x): %m", fd, flags); ++ return clientfd; ++} +diff --git a/support/xasprintf.c b/support/xasprintf.c +new file mode 100644 +index 0000000000..5157680fa2 +--- /dev/null ++++ b/support/xasprintf.c +@@ -0,0 +1,36 @@ ++/* Error-checking wrapper for asprintf. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <support/support.h> ++ ++#include <stdarg.h> ++#include <stdio.h> ++#include <stdlib.h> ++#include <support/check.h> ++ ++char * ++xasprintf (const char *format, ...) ++{ ++ va_list ap; ++ va_start (ap, format); ++ char *result; ++ if (vasprintf (&result, format, ap) < 0) ++ FAIL_EXIT1 ("asprintf: %m"); ++ va_end (ap); ++ return result; ++} +diff --git a/support/xbind.c b/support/xbind.c +new file mode 100644 +index 0000000000..cfc6dd8fa8 +--- /dev/null ++++ b/support/xbind.c +@@ -0,0 +1,30 @@ ++/* bind with error checking. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <support/xsocket.h> ++ ++#include <stdio.h> ++#include <stdlib.h> ++#include <support/check.h> ++ ++void ++xbind (int fd, const struct sockaddr *sa, socklen_t sa_len) ++{ ++ if (bind (fd, sa, sa_len) != 0) ++ FAIL_EXIT1 ("bind (%d), family %d: %m", fd, sa->sa_family); ++} +diff --git a/sysdeps/unix/sysv/linux/sh/pread.c b/support/xcalloc.c +similarity index 68% +rename from sysdeps/unix/sysv/linux/sh/pread.c +rename to support/xcalloc.c +index d3f99f35db..135f42dab2 100644 +--- a/sysdeps/unix/sysv/linux/sh/pread.c ++++ b/support/xcalloc.c +@@ -1,6 +1,6 @@ +-/* Copyright (C) 1997-2016 Free Software Foundation, Inc. ++/* Error-checking wrapper for calloc. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. +- Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public +@@ -16,8 +16,19 @@ + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +-/* SH4 ABI does not really require argument alignment for 64-bits, but +- the kernel interface for pread adds a dummy long argument before the +- offset. */ +-#define __ALIGNMENT_ARG +-#include <sysdeps/unix/sysv/linux/pread.c> ++#include <support/support.h> ++ ++#include <stdarg.h> ++#include <stdio.h> ++#include <stdlib.h> ++ ++void * ++xcalloc (size_t n, size_t s) ++{ ++ void *p; ++ ++ p = calloc (n, s); ++ if (p == NULL) ++ oom_error ("calloc", n * s); ++ return p; ++} +diff --git a/sysdeps/unix/sysv/linux/sh/pread64.c b/support/xchroot.c +similarity index 67% +rename from sysdeps/unix/sysv/linux/sh/pread64.c +rename to support/xchroot.c +index b2e8a25788..abcc299e00 100644 +--- a/sysdeps/unix/sysv/linux/sh/pread64.c ++++ b/support/xchroot.c +@@ -1,6 +1,6 @@ +-/* Copyright (C) 1997-2016 Free Software Foundation, Inc. ++/* chroot with error checking. ++ Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. +- Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public +@@ -16,8 +16,13 @@ + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +-/* SH4 ABI does not really require argument alignment for 64-bits, but +- the kernel interface for pread adds a dummy long argument before the +- offset. */ +-#define __ALIGNMENT_ARG +-#include <sysdeps/unix/sysv/linux/pread64.c> ++#include <support/check.h> ++#include <support/xunistd.h> ++#include <sys/stat.h> ++ ++void ++xchroot (const char *path) ++{ ++ if (chroot (path) != 0) ++ FAIL_EXIT1 ("chroot (\"%s\"): %m", path); ++} +diff --git a/support/xclose.c b/support/xclose.c +new file mode 100644 +index 0000000000..c931e08421 +--- /dev/null ++++ b/support/xclose.c +@@ -0,0 +1,28 @@ ++/* close with error checking. ++ Copyright (C) 2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <support/xunistd.h> ++#include <support/check.h> ++#include <errno.h> ++ ++void ++xclose (int fd) ++{ ++ if (close (fd) < 0 && errno != EINTR) ++ FAIL_EXIT1 ("close of descriptor %d failed: %m", fd); ++} +diff --git a/support/xconnect.c b/support/xconnect.c +new file mode 100644 +index 0000000000..0266dbc643 +--- /dev/null ++++ b/support/xconnect.c +@@ -0,0 +1,30 @@ ++/* connect with error checking. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <support/xsocket.h> ++ ++#include <stdio.h> ++#include <stdlib.h> ++#include <support/check.h> ++ ++void ++xconnect (int fd, const struct sockaddr *sa, socklen_t sa_len) ++{ ++ if (connect (fd, sa, sa_len) != 0) ++ FAIL_EXIT1 ("connect (%d), family %d: %m", fd, sa->sa_family); ++} +diff --git a/support/xdup2.c b/support/xdup2.c +new file mode 100644 +index 0000000000..dc08c94518 +--- /dev/null ++++ b/support/xdup2.c +@@ -0,0 +1,28 @@ ++/* dup2 with error checking. ++ Copyright (C) 2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <support/xunistd.h> ++ ++#include <support/check.h> ++ ++void ++xdup2 (int from, int to) ++{ ++ if (dup2 (from, to) < 0) ++ FAIL_EXIT1 ("dup2 (%d, %d): %m", from, to); ++} +diff --git a/support/xfclose.c b/support/xfclose.c +new file mode 100644 +index 0000000000..2737f05044 +--- /dev/null ++++ b/support/xfclose.c +@@ -0,0 +1,33 @@ ++/* fclose with error checking. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <support/xstdio.h> ++ ++#include <support/check.h> ++#include <stdlib.h> ++ ++void ++xfclose (FILE *fp) ++{ ++ if (ferror (fp)) ++ FAIL_EXIT1 ("stdio stream closed with pending errors"); ++ if (fflush (fp) != 0) ++ FAIL_EXIT1 ("fflush: %m"); ++ if (fclose (fp) != 0) ++ FAIL_EXIT1 ("fclose: %m"); ++} +diff --git a/sysdeps/sparc/sparc32/sparcv9/fpu/multiarch/s_fdimf-vis3.S b/support/xfopen.c +similarity index 67% +rename from sysdeps/sparc/sparc32/sparcv9/fpu/multiarch/s_fdimf-vis3.S +rename to support/xfopen.c +index 081fc15b62..14532a09f3 100644 +--- a/sysdeps/sparc/sparc32/sparcv9/fpu/multiarch/s_fdimf-vis3.S ++++ b/support/xfopen.c +@@ -1,7 +1,6 @@ +-/* Compute positive difference, sparc 32-bit+v9+vis3. +- Copyright (C) 2013-2016 Free Software Foundation, Inc. ++/* fopen with error checking. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. +- Contributed by David S. Miller <davem@davemloft.net>. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public +@@ -17,16 +16,16 @@ + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +-#include <sysdep.h> ++#include <support/xstdio.h> + +-ENTRY(__fdimf_vis3) +- movwtos %o0, %f0 +- movwtos %o1, %f1 +- fcmps %f0, %f1 +- fbug 1f +- nop +- fzeros %f0 +- fnegs %f0, %f1 +-1: retl +- fsubs %f0, %f1, %f0 +-END(__fdimf_vis3) ++#include <support/check.h> ++#include <stdlib.h> ++ ++FILE * ++xfopen (const char *path, const char *mode) ++{ ++ FILE *fp = fopen (path, mode); ++ if (fp == NULL) ++ FAIL_EXIT1 ("could not open %s (mode \"%s\"): %m", path, mode); ++ return fp; ++} +diff --git a/support/xfork.c b/support/xfork.c +new file mode 100644 +index 0000000000..aa52ba62c5 +--- /dev/null ++++ b/support/xfork.c +@@ -0,0 +1,32 @@ ++/* fork with error checking. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <support/xunistd.h> ++ ++#include <stdio.h> ++#include <stdlib.h> ++#include <support/check.h> ++ ++pid_t ++xfork (void) ++{ ++ pid_t result = fork (); ++ if (result < 0) ++ FAIL_EXIT1 ("fork: %m"); ++ return result; ++} +diff --git a/support/xgetsockname.c b/support/xgetsockname.c +new file mode 100644 +index 0000000000..c3bd884f8d +--- /dev/null ++++ b/support/xgetsockname.c +@@ -0,0 +1,30 @@ ++/* getsockname with error checking. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <support/xsocket.h> ++ ++#include <stdio.h> ++#include <stdlib.h> ++#include <support/check.h> ++ ++void ++xgetsockname (int fd, struct sockaddr *sa, socklen_t *plen) ++{ ++ if (getsockname (fd, sa, plen) != 0) ++ FAIL_EXIT1 ("setsockopt (%d): %m", fd); ++} +diff --git a/support/xlisten.c b/support/xlisten.c +new file mode 100644 +index 0000000000..1953e5900a +--- /dev/null ++++ b/support/xlisten.c +@@ -0,0 +1,30 @@ ++/* listen with error checking. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <support/xsocket.h> ++ ++#include <stdio.h> ++#include <stdlib.h> ++#include <support/check.h> ++ ++void ++xlisten (int fd, int backlog) ++{ ++ if (listen (fd, backlog) != 0) ++ FAIL_EXIT1 ("listen (%d, %d): %m", fd, backlog); ++} +diff --git a/support/xmalloc.c b/support/xmalloc.c +new file mode 100644 +index 0000000000..450f699789 +--- /dev/null ++++ b/support/xmalloc.c +@@ -0,0 +1,34 @@ ++/* Error-checking wrapper for malloc. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <support/support.h> ++ ++#include <stdarg.h> ++#include <stdio.h> ++#include <stdlib.h> ++ ++void * ++xmalloc (size_t n) ++{ ++ void *p; ++ ++ p = malloc (n); ++ if (p == NULL) ++ oom_error ("malloc", n); ++ return p; ++} +diff --git a/sysdeps/sparc/sparc32/fpu/s_fdim.S b/support/xmemstream.c +similarity index 54% +rename from sysdeps/sparc/sparc32/fpu/s_fdim.S +rename to support/xmemstream.c +index e93970faae..bce6dc9170 100644 +--- a/sysdeps/sparc/sparc32/fpu/s_fdim.S ++++ b/support/xmemstream.c +@@ -1,7 +1,6 @@ +-/* Compute positive difference, sparc 32-bit. +- Copyright (C) 2013-2016 Free Software Foundation, Inc. ++/* Error-checking wrappers for memstream functions. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. +- Contributed by David S. Miller <davem@davemloft.net>. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public +@@ -17,26 +16,27 @@ + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +-#include <sysdep.h> +-#include <math_ldbl_opt.h> ++#include <support/xmemstream.h> + +-ENTRY(__fdim) +- std %o0, [%sp + 72] +- std %o2, [%sp + 80] +- ldd [%sp + 72], %f0 +- ldd [%sp + 80], %f2 +- fcmpd %f0, %f2 +- st %g0, [%sp + 72] +- fbug 1f +- st %g0, [%sp + 76] +- ldd [%sp + 72], %f0 +- fnegs %f0, %f2 +- fmovs %f1, %f3 +-1: retl +- fsubd %f0, %f2, %f0 +-END(__fdim) +-weak_alias (__fdim, fdim) ++#include <errno.h> ++#include <stdlib.h> ++#include <support/check.h> ++#include <support/xstdio.h> + +-#if LONG_DOUBLE_COMPAT(libm, GLIBC_2_1) +-compat_symbol (libm, __fdim, fdiml, GLIBC_2_1); +-#endif ++void ++xopen_memstream (struct xmemstream *stream) ++{ ++ int old_errno = errno; ++ *stream = (struct xmemstream) {}; ++ stream->out = open_memstream (&stream->buffer, &stream->length); ++ if (stream->out == NULL) ++ FAIL_EXIT1 ("open_memstream: %m"); ++ errno = old_errno; ++} ++ ++void ++xfclose_memstream (struct xmemstream *stream) ++{ ++ xfclose (stream->out); ++ stream->out = NULL; ++} +diff --git a/support/xmemstream.h b/support/xmemstream.h +new file mode 100644 +index 0000000000..e5ba231e4d +--- /dev/null ++++ b/support/xmemstream.h +@@ -0,0 +1,49 @@ ++/* Error-checking wrappers for memstream functions. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#ifndef SUPPORT_XMEMSTREAM_H ++#define SUPPORT_XMEMSTREAM_H ++ ++#include <stdio.h> ++#include <sys/cdefs.h> ++ ++__BEGIN_DECLS ++ ++/* Wrappers for other libc functions. */ ++struct xmemstream ++{ ++ FILE *out; ++ char *buffer; ++ size_t length; ++}; ++ ++/* Create a new in-memory stream. Initializes *STREAM. After this ++ function returns, STREAM->out is a file descriptor open for ++ writing. errno is preserved, so that the %m format specifier can ++ be used for writing to STREAM->out. */ ++void xopen_memstream (struct xmemstream *stream); ++ ++/* Closes STREAM->OUT. After this function returns, STREAM->buffer ++ and STREAM->length denote a memory range which contains the bytes ++ written to the output stream. The caller should free ++ STREAM->buffer. */ ++void xfclose_memstream (struct xmemstream *stream); ++ ++__END_DECLS ++ ++#endif /* SUPPORT_XMEMSTREAM_H */ +diff --git a/support/xmkdir.c b/support/xmkdir.c +new file mode 100644 +index 0000000000..ea17d49391 +--- /dev/null ++++ b/support/xmkdir.c +@@ -0,0 +1,28 @@ ++/* mkdir with error checking. ++ Copyright (C) 2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <support/check.h> ++#include <support/xunistd.h> ++#include <sys/stat.h> ++ ++void ++xmkdir (const char *path, mode_t mode) ++{ ++ if (mkdir (path, mode) != 0) ++ FAIL_EXIT1 ("mkdir (\"%s\", 0%o): %m", path, mode); ++} +diff --git a/support/xmmap.c b/support/xmmap.c +new file mode 100644 +index 0000000000..435b1eb733 +--- /dev/null ++++ b/support/xmmap.c +@@ -0,0 +1,31 @@ ++/* mmap with error checking. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <support/check.h> ++#include <support/xunistd.h> ++#include <sys/mman.h> ++ ++void * ++xmmap (void *addr, size_t length, int prot, int flags, int fd) ++{ ++ void *result = mmap (addr, length, prot, flags, fd, 0); ++ if (result == MAP_FAILED) ++ FAIL_EXIT1 ("mmap of %zu bytes, prot=0x%x, flags=0x%x: %m", ++ length, prot, flags); ++ return result; ++} +diff --git a/support/xmunmap.c b/support/xmunmap.c +new file mode 100644 +index 0000000000..6ef5a4a468 +--- /dev/null ++++ b/support/xmunmap.c +@@ -0,0 +1,28 @@ ++/* munmap with error checking. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <support/check.h> ++#include <support/xunistd.h> ++#include <sys/mman.h> ++ ++void ++xmunmap (void *addr, size_t length) ++{ ++ if (munmap (addr, length) != 0) ++ FAIL_EXIT1 ("munmap of %zu bytes: %m", length); ++} +diff --git a/support/xopen.c b/support/xopen.c +new file mode 100644 +index 0000000000..7f033a03a7 +--- /dev/null ++++ b/support/xopen.c +@@ -0,0 +1,30 @@ ++/* open64 with error checking. ++ Copyright (C) 2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <support/check.h> ++#include <support/xunistd.h> ++#include <fcntl.h> ++ ++int ++xopen (const char *path, int flags, mode_t mode) ++{ ++ int ret = open64 (path, flags, mode); ++ if (ret < 0) ++ FAIL_EXIT1 ("open64 (\"%s\", 0x%x, 0%o): %m", path, flags, mode); ++ return ret; ++} +diff --git a/support/xpipe.c b/support/xpipe.c +new file mode 100644 +index 0000000000..89a64a55c1 +--- /dev/null ++++ b/support/xpipe.c +@@ -0,0 +1,28 @@ ++/* pipe with error checking. ++ Copyright (C) 2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <support/xunistd.h> ++ ++#include <support/check.h> ++ ++void ++xpipe (int fds[2]) ++{ ++ if (pipe (fds) < 0) ++ FAIL_EXIT1 ("pipe: %m"); ++} +diff --git a/support/xpoll.c b/support/xpoll.c +new file mode 100644 +index 0000000000..bec2521ffc +--- /dev/null ++++ b/support/xpoll.c +@@ -0,0 +1,32 @@ ++/* poll with error checking. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <support/xsocket.h> ++ ++#include <stdio.h> ++#include <stdlib.h> ++#include <support/check.h> ++ ++int ++xpoll (struct pollfd *fds, nfds_t nfds, int timeout) ++{ ++ int ret = poll (fds, nfds, timeout); ++ if (ret < 0) ++ FAIL_EXIT1 ("poll: %m"); ++ return ret; ++} +diff --git a/support/xpthread_attr_destroy.c b/support/xpthread_attr_destroy.c +new file mode 100644 +index 0000000000..664c809e9f +--- /dev/null ++++ b/support/xpthread_attr_destroy.c +@@ -0,0 +1,26 @@ ++/* pthread_attr_destroy with error checking. ++ Copyright (C) 2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <support/xthread.h> ++ ++void ++xpthread_attr_destroy (pthread_attr_t *attr) ++{ ++ xpthread_check_return ("pthread_attr_destroy", ++ pthread_attr_destroy (attr)); ++} +diff --git a/support/xpthread_attr_init.c b/support/xpthread_attr_init.c +new file mode 100644 +index 0000000000..2e30ade9ab +--- /dev/null ++++ b/support/xpthread_attr_init.c +@@ -0,0 +1,25 @@ ++/* pthread_attr_init with error checking. ++ Copyright (C) 2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <support/xthread.h> ++ ++void ++xpthread_attr_init (pthread_attr_t *attr) ++{ ++ xpthread_check_return ("pthread_attr_init", pthread_attr_init (attr)); ++} +diff --git a/support/xpthread_attr_setdetachstate.c b/support/xpthread_attr_setdetachstate.c +new file mode 100644 +index 0000000000..b544dbaa42 +--- /dev/null ++++ b/support/xpthread_attr_setdetachstate.c +@@ -0,0 +1,27 @@ ++/* pthread_attr_setdetachstate with error checking. ++ Copyright (C) 2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <support/xthread.h> ++ ++void ++xpthread_attr_setdetachstate (pthread_attr_t *attr, int detachstate) ++{ ++ xpthread_check_return ("pthread_attr_setdetachstate", ++ pthread_attr_setdetachstate (attr, ++ detachstate)); ++} +diff --git a/support/xpthread_attr_setstacksize.c b/support/xpthread_attr_setstacksize.c +new file mode 100644 +index 0000000000..02d06310a9 +--- /dev/null ++++ b/support/xpthread_attr_setstacksize.c +@@ -0,0 +1,26 @@ ++/* pthread_attr_setstacksize with error checking. ++ Copyright (C) 2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <support/xthread.h> ++ ++void ++xpthread_attr_setstacksize (pthread_attr_t *attr, size_t stacksize) ++{ ++ xpthread_check_return ("pthread_attr_setstacksize", ++ pthread_attr_setstacksize (attr, stacksize)); ++} +diff --git a/support/xpthread_barrier_destroy.c b/support/xpthread_barrier_destroy.c +new file mode 100644 +index 0000000000..efc0719a63 +--- /dev/null ++++ b/support/xpthread_barrier_destroy.c +@@ -0,0 +1,26 @@ ++/* pthread_barrier_destroy with error checking. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <support/xthread.h> ++ ++void ++xpthread_barrier_destroy (pthread_barrier_t *barrier) ++{ ++ xpthread_check_return ("pthread_barrier_destroy", ++ pthread_barrier_destroy (barrier)); ++} +diff --git a/sysdeps/sparc/sparc32/sparcv9/fpu/multiarch/s_fdim-vis3.S b/support/xpthread_barrier_init.c +similarity index 65% +rename from sysdeps/sparc/sparc32/sparcv9/fpu/multiarch/s_fdim-vis3.S +rename to support/xpthread_barrier_init.c +index 4a479b1a59..b32dad1315 100644 +--- a/sysdeps/sparc/sparc32/sparcv9/fpu/multiarch/s_fdim-vis3.S ++++ b/support/xpthread_barrier_init.c +@@ -1,7 +1,6 @@ +-/* Compute positive difference, sparc 32-bit+v9+vis3. +- Copyright (C) 2013-2016 Free Software Foundation, Inc. ++/* pthread_barrier_init with error checking. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. +- Contributed by David S. Miller <davem@davemloft.net>. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public +@@ -17,18 +16,12 @@ + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +-#include <sysdep.h> ++#include <support/xthread.h> + +-ENTRY(__fdim_vis3) +- movwtos %o0, %f0 +- movwtos %o1, %f1 +- movwtos %o2, %f2 +- movwtos %o3, %f3 +- fcmpd %f0, %f2 +- fbug 1f +- nop +- fzero %f0 +- fnegd %f0, %f2 +-1: retl +- fsubd %f0, %f2, %f0 +-END(__fdim_vis3) ++void ++xpthread_barrier_init (pthread_barrier_t *barrier, ++ pthread_barrierattr_t *attr, unsigned int count) ++{ ++ xpthread_check_return ("pthread_barrier_init", ++ pthread_barrier_init (barrier, attr, count)); ++} +diff --git a/support/xpthread_barrier_wait.c b/support/xpthread_barrier_wait.c +new file mode 100644 +index 0000000000..7cee44d0a3 +--- /dev/null ++++ b/support/xpthread_barrier_wait.c +@@ -0,0 +1,28 @@ ++/* pthread_barrier_wait with error checking. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <support/xthread.h> ++ ++int ++xpthread_barrier_wait (pthread_barrier_t *barrier) ++{ ++ int ret = pthread_barrier_wait (barrier); ++ if (ret != 0 && ret != PTHREAD_BARRIER_SERIAL_THREAD) ++ xpthread_check_return ("pthread_barrier_wait", ret); ++ return ret == PTHREAD_BARRIER_SERIAL_THREAD; ++} +diff --git a/support/xpthread_cancel.c b/support/xpthread_cancel.c +new file mode 100644 +index 0000000000..3af16f9b54 +--- /dev/null ++++ b/support/xpthread_cancel.c +@@ -0,0 +1,25 @@ ++/* pthread_cancel with error checking. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <support/xthread.h> ++ ++void ++xpthread_cancel (pthread_t thr) ++{ ++ xpthread_check_return ("pthread_cancel", pthread_cancel (thr)); ++} +diff --git a/support/xpthread_check_return.c b/support/xpthread_check_return.c +new file mode 100644 +index 0000000000..3094d82e9c +--- /dev/null ++++ b/support/xpthread_check_return.c +@@ -0,0 +1,34 @@ ++/* Return value checking for pthread functions, exit variant. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <support/xthread.h> ++ ++#include <errno.h> ++#include <stdio.h> ++#include <stdlib.h> ++#include <support/check.h> ++ ++void ++xpthread_check_return (const char *function, int value) ++{ ++ if (value != 0) ++ { ++ errno = value; ++ FAIL_EXIT1 ("%s: %m", function); ++ } ++} +diff --git a/support/xpthread_cond_wait.c b/support/xpthread_cond_wait.c +new file mode 100644 +index 0000000000..b0e9b2a232 +--- /dev/null ++++ b/support/xpthread_cond_wait.c +@@ -0,0 +1,26 @@ ++/* pthread_cond_wait with error checking. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <support/xthread.h> ++ ++void ++xpthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex) ++{ ++ xpthread_check_return ++ ("pthread_cond_wait", pthread_cond_wait (cond, mutex)); ++} +diff --git a/support/xpthread_create.c b/support/xpthread_create.c +new file mode 100644 +index 0000000000..98c63e54c3 +--- /dev/null ++++ b/support/xpthread_create.c +@@ -0,0 +1,29 @@ ++/* pthread_create with error checking. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <support/xthread.h> ++ ++pthread_t ++xpthread_create (pthread_attr_t *attr, ++ void *(*thread_func) (void *), void *closure) ++{ ++ pthread_t thr; ++ xpthread_check_return ++ ("pthread_create", pthread_create (&thr, attr, thread_func, closure)); ++ return thr; ++} +diff --git a/support/xpthread_detach.c b/support/xpthread_detach.c +new file mode 100644 +index 0000000000..2088af2f57 +--- /dev/null ++++ b/support/xpthread_detach.c +@@ -0,0 +1,25 @@ ++/* pthread_detach with error checking. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <support/xthread.h> ++ ++void ++xpthread_detach (pthread_t thr) ++{ ++ xpthread_check_return ("pthread_detach", pthread_detach (thr)); ++} +diff --git a/support/xpthread_join.c b/support/xpthread_join.c +new file mode 100644 +index 0000000000..f23bb9a5ae +--- /dev/null ++++ b/support/xpthread_join.c +@@ -0,0 +1,27 @@ ++/* pthread_join with error checking. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <support/xthread.h> ++ ++void * ++xpthread_join (pthread_t thr) ++{ ++ void *result; ++ xpthread_check_return ("pthread_join", pthread_join (thr, &result)); ++ return result; ++} +diff --git a/support/xpthread_mutex_consistent.c b/support/xpthread_mutex_consistent.c +new file mode 100644 +index 0000000000..52364be365 +--- /dev/null ++++ b/support/xpthread_mutex_consistent.c +@@ -0,0 +1,26 @@ ++/* pthread_mutex_consistent with error checking. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <support/xthread.h> ++ ++void ++xpthread_mutex_consistent (pthread_mutex_t *mutex) ++{ ++ xpthread_check_return ("pthread_mutex_consistent", ++ pthread_mutex_consistent (mutex)); ++} +diff --git a/support/xpthread_mutex_destroy.c b/support/xpthread_mutex_destroy.c +new file mode 100644 +index 0000000000..f11f8f0acd +--- /dev/null ++++ b/support/xpthread_mutex_destroy.c +@@ -0,0 +1,26 @@ ++/* pthread_mutex_destroy with error checking. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <support/xthread.h> ++ ++void ++xpthread_mutex_destroy (pthread_mutex_t *mutex) ++{ ++ xpthread_check_return ("pthread_mutex_destroy", ++ pthread_mutex_destroy (mutex)); ++} +diff --git a/support/xpthread_mutex_init.c b/support/xpthread_mutex_init.c +new file mode 100644 +index 0000000000..2d16d1b9d9 +--- /dev/null ++++ b/support/xpthread_mutex_init.c +@@ -0,0 +1,26 @@ ++/* pthread_mutex_init with error checking. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <support/xthread.h> ++ ++void ++xpthread_mutex_init (pthread_mutex_t *mutex, const pthread_mutexattr_t *attr) ++{ ++ xpthread_check_return ("pthread_mutex_init", ++ pthread_mutex_init (mutex, attr)); ++} +diff --git a/support/xpthread_mutex_lock.c b/support/xpthread_mutex_lock.c +new file mode 100644 +index 0000000000..af727b45f3 +--- /dev/null ++++ b/support/xpthread_mutex_lock.c +@@ -0,0 +1,25 @@ ++/* pthread_mutex_lock with error checking. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <support/xthread.h> ++ ++void ++xpthread_mutex_lock (pthread_mutex_t *mutex) ++{ ++ xpthread_check_return ("pthread_mutex_lock", pthread_mutex_lock (mutex)); ++} +diff --git a/support/xpthread_mutex_unlock.c b/support/xpthread_mutex_unlock.c +new file mode 100644 +index 0000000000..161b41edf6 +--- /dev/null ++++ b/support/xpthread_mutex_unlock.c +@@ -0,0 +1,25 @@ ++/* pthread_mutex_unlock with error checking. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <support/xthread.h> ++ ++void ++xpthread_mutex_unlock (pthread_mutex_t *mutex) ++{ ++ xpthread_check_return ("pthread_mutex_unlock", pthread_mutex_unlock (mutex)); ++} +diff --git a/support/xpthread_mutexattr_destroy.c b/support/xpthread_mutexattr_destroy.c +new file mode 100644 +index 0000000000..c699e32b41 +--- /dev/null ++++ b/support/xpthread_mutexattr_destroy.c +@@ -0,0 +1,26 @@ ++/* pthread_mutexattr_destroy with error checking. ++ Copyright (C) 2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <support/xthread.h> ++ ++void ++xpthread_mutexattr_destroy (pthread_mutexattr_t *attr) ++{ ++ xpthread_check_return ("pthread_mutexattr_destroy", ++ pthread_mutexattr_destroy (attr)); ++} +diff --git a/support/xpthread_mutexattr_init.c b/support/xpthread_mutexattr_init.c +new file mode 100644 +index 0000000000..fa93fab178 +--- /dev/null ++++ b/support/xpthread_mutexattr_init.c +@@ -0,0 +1,25 @@ ++/* pthread_mutexattr_init with error checking. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <support/xthread.h> ++ ++void ++xpthread_mutexattr_init (pthread_mutexattr_t *attr) ++{ ++ xpthread_check_return ("pthread_mutexattr_init", pthread_mutexattr_init (attr)); ++} +diff --git a/sysdeps/sparc/sparc64/fpu/s_fdim.S b/support/xpthread_mutexattr_setprotocol.c +similarity index 67% +rename from sysdeps/sparc/sparc64/fpu/s_fdim.S +rename to support/xpthread_mutexattr_setprotocol.c +index 7fae72a251..353f75e3d7 100644 +--- a/sysdeps/sparc/sparc64/fpu/s_fdim.S ++++ b/support/xpthread_mutexattr_setprotocol.c +@@ -1,7 +1,6 @@ +-/* Compute positive difference, sparc 64-bit. +- Copyright (C) 2013-2016 Free Software Foundation, Inc. ++/* pthread_mutexattr_setprotocol with error checking. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. +- Contributed by David S. Miller <davem@davemloft.net>. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public +@@ -17,16 +16,11 @@ + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +-#include <sysdep.h> +-#include <math_ldbl_opt.h> ++#include <support/xthread.h> + +-ENTRY(__fdim) +- fcmpd %f0, %f2 +- fbug 1f +- nop +- fzero %f0 +- fnegd %f0, %f2 +-1: retl +- fsubd %f0, %f2, %f0 +-END(__fdim) +-weak_alias (__fdim, fdim) ++void ++xpthread_mutexattr_setprotocol (pthread_mutexattr_t *attr, int flag) ++{ ++ xpthread_check_return ("pthread_mutexattr_setprotocol", ++ pthread_mutexattr_setprotocol (attr, flag)); ++} +diff --git a/support/xpthread_mutexattr_setpshared.c b/support/xpthread_mutexattr_setpshared.c +new file mode 100644 +index 0000000000..242da1aeca +--- /dev/null ++++ b/support/xpthread_mutexattr_setpshared.c +@@ -0,0 +1,26 @@ ++/* pthread_mutexattr_setpshared with error checking. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <support/xthread.h> ++ ++void ++xpthread_mutexattr_setpshared (pthread_mutexattr_t *attr, int flag) ++{ ++ xpthread_check_return ("pthread_mutexattr_setpshared", ++ pthread_mutexattr_setpshared (attr, flag)); ++} +diff --git a/support/xpthread_mutexattr_setrobust.c b/support/xpthread_mutexattr_setrobust.c +new file mode 100644 +index 0000000000..d7d6fa8630 +--- /dev/null ++++ b/support/xpthread_mutexattr_setrobust.c +@@ -0,0 +1,26 @@ ++/* pthread_mutexattr_setrobust with error checking. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <support/xthread.h> ++ ++void ++xpthread_mutexattr_setrobust (pthread_mutexattr_t *attr, int flag) ++{ ++ xpthread_check_return ("pthread_mutexattr_setrobust", ++ pthread_mutexattr_setrobust (attr, flag)); ++} +diff --git a/support/xpthread_mutexattr_settype.c b/support/xpthread_mutexattr_settype.c +new file mode 100644 +index 0000000000..cf22170b56 +--- /dev/null ++++ b/support/xpthread_mutexattr_settype.c +@@ -0,0 +1,26 @@ ++/* pthread_mutexattr_settype with error checking. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <support/xthread.h> ++ ++void ++xpthread_mutexattr_settype (pthread_mutexattr_t *attr, int flag) ++{ ++ xpthread_check_return ("pthread_mutexattr_settype", ++ pthread_mutexattr_settype (attr, flag)); ++} +diff --git a/support/xpthread_once.c b/support/xpthread_once.c +new file mode 100644 +index 0000000000..70d58dbab2 +--- /dev/null ++++ b/support/xpthread_once.c +@@ -0,0 +1,25 @@ ++/* pthread_once with error checking. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <support/xthread.h> ++ ++void ++xpthread_once (pthread_once_t *guard, void (*func) (void)) ++{ ++ xpthread_check_return ("pthread_once", pthread_once (guard, func)); ++} +diff --git a/support/xpthread_sigmask.c b/support/xpthread_sigmask.c +new file mode 100644 +index 0000000000..0ba9ca02dc +--- /dev/null ++++ b/support/xpthread_sigmask.c +@@ -0,0 +1,34 @@ ++/* pthread_sigmask with error checking. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <support/xsignal.h> ++#include <support/support.h> ++ ++#include <unistd.h> ++ ++void ++xpthread_sigmask (int how, const sigset_t *set, sigset_t *oldset) ++{ ++ if (pthread_sigmask (how, set, oldset) != 0) ++ { ++ write_message ("error: pthread_setmask failed\n"); ++ /* Do not use exit because pthread_sigmask can be called from a ++ signal handler. */ ++ _exit (1); ++ } ++} +diff --git a/support/xpthread_spin_lock.c b/support/xpthread_spin_lock.c +new file mode 100644 +index 0000000000..6975215b17 +--- /dev/null ++++ b/support/xpthread_spin_lock.c +@@ -0,0 +1,25 @@ ++/* pthread_spin_lock with error checking. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <support/xthread.h> ++ ++void ++xpthread_spin_lock (pthread_spinlock_t *lock) ++{ ++ xpthread_check_return ("pthread_spin_lock", pthread_spin_lock (lock)); ++} +diff --git a/support/xpthread_spin_unlock.c b/support/xpthread_spin_unlock.c +new file mode 100644 +index 0000000000..4f19a44c48 +--- /dev/null ++++ b/support/xpthread_spin_unlock.c +@@ -0,0 +1,25 @@ ++/* pthread_spin_unlock with error checking. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <support/xthread.h> ++ ++void ++xpthread_spin_unlock (pthread_spinlock_t *lock) ++{ ++ xpthread_check_return ("pthread_spin_unlock", pthread_spin_unlock (lock)); ++} +diff --git a/support/xrealloc.c b/support/xrealloc.c +new file mode 100644 +index 0000000000..00c313880c +--- /dev/null ++++ b/support/xrealloc.c +@@ -0,0 +1,32 @@ ++/* Error-checking wrapper for realloc. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <support/support.h> ++ ++#include <stdarg.h> ++#include <stdio.h> ++#include <stdlib.h> ++ ++void * ++xrealloc (void *p, size_t n) ++{ ++ void *result = realloc (p, n); ++ if (result == NULL && (n > 0 || p == NULL)) ++ oom_error ("realloc", n); ++ return result; ++} +diff --git a/support/xrecvfrom.c b/support/xrecvfrom.c +new file mode 100644 +index 0000000000..17809c4dd2 +--- /dev/null ++++ b/support/xrecvfrom.c +@@ -0,0 +1,33 @@ ++/* recvfrom with error checking. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <support/xsocket.h> ++ ++#include <stdio.h> ++#include <stdlib.h> ++#include <support/check.h> ++ ++size_t ++xrecvfrom (int fd, void *buf, size_t buflen, int flags, ++ struct sockaddr *sa, socklen_t *salen) ++{ ++ ssize_t ret = recvfrom (fd, buf, buflen, flags, sa, salen); ++ if (ret < 0) ++ FAIL_EXIT1 ("error: recvfrom (%d), %zu bytes buffer: %m", fd, buflen); ++ return ret; ++} +diff --git a/support/xsendto.c b/support/xsendto.c +new file mode 100644 +index 0000000000..20bddf6965 +--- /dev/null ++++ b/support/xsendto.c +@@ -0,0 +1,35 @@ ++/* sendto with error checking. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <support/xsocket.h> ++ ++#include <stdio.h> ++#include <stdlib.h> ++#include <support/check.h> ++ ++void ++xsendto (int fd, const void *buf, size_t buflen, int flags, ++ const struct sockaddr *sa, socklen_t salen) ++{ ++ ssize_t ret = sendto (fd, buf, buflen, flags, sa, salen); ++ if (ret < 0) ++ FAIL_EXIT1 ("sendto (%d), %zu bytes, family %d: %m", ++ fd, buflen, sa->sa_family); ++ if (ret != buflen) ++ FAIL_EXIT1 ("sendto (%d) sent %zd bytes instead of %zu", fd, ret, buflen); ++} +diff --git a/sysdeps/sparc/sparc32/fpu/s_fdimf.S b/support/xsetsockopt.c +similarity index 62% +rename from sysdeps/sparc/sparc32/fpu/s_fdimf.S +rename to support/xsetsockopt.c +index c3fe8afa98..9931882e75 100644 +--- a/sysdeps/sparc/sparc32/fpu/s_fdimf.S ++++ b/support/xsetsockopt.c +@@ -1,7 +1,6 @@ +-/* Compute positive difference, sparc 32-bit. +- Copyright (C) 2013-2016 Free Software Foundation, Inc. ++/* setsockopt with error checking. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. +- Contributed by David S. Miller <davem@davemloft.net>. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public +@@ -17,19 +16,16 @@ + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +-#include <sysdep.h> ++#include <support/xsocket.h> + +-ENTRY(__fdimf) +- st %o0, [%sp + 72] +- st %o1, [%sp + 76] +- ld [%sp + 72], %f0 +- ld [%sp + 76], %f1 +- fcmps %f0, %f1 +- fbug 1f +- st %g0, [%sp + 72] +- ld [%sp + 72], %f0 +- fnegs %f0, %f1 +-1: retl +- fsubs %f0, %f1, %f0 +-END(__fdimf) +-weak_alias (__fdimf, fdimf) ++#include <stdio.h> ++#include <stdlib.h> ++#include <support/check.h> ++ ++void ++xsetsockopt (int fd, int level, int name, const void *val, socklen_t vallen) ++{ ++ if (setsockopt (fd, level, name, val, vallen) != 0) ++ FAIL_EXIT1 ("setsockopt (%d, %d, %d), %zu bytes: %m", ++ fd, level, name, (size_t) vallen); ++} +diff --git a/support/xsignal.h b/support/xsignal.h +new file mode 100644 +index 0000000000..3dc0d9d5ce +--- /dev/null ++++ b/support/xsignal.h +@@ -0,0 +1,34 @@ ++/* Support functionality for using signals. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#ifndef SUPPORT_SIGNAL_H ++#define SUPPORT_SIGNAL_H ++ ++#include <signal.h> ++#include <sys/cdefs.h> ++ ++__BEGIN_DECLS ++ ++/* The following functions call the corresponding libpthread functions ++ and terminate the process on error. */ ++ ++void xpthread_sigmask (int how, const sigset_t *set, sigset_t *oldset); ++ ++__END_DECLS ++ ++#endif /* SUPPORT_SIGNAL_H */ +diff --git a/support/xsocket.c b/support/xsocket.c +new file mode 100644 +index 0000000000..c1deaee924 +--- /dev/null ++++ b/support/xsocket.c +@@ -0,0 +1,32 @@ ++/* socket with error checking. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <support/xsocket.h> ++ ++#include <stdio.h> ++#include <stdlib.h> ++#include <support/check.h> ++ ++int ++xsocket (int domain, int type, int protocol) ++{ ++ int fd = socket (domain, type, protocol); ++ if (fd < 0) ++ FAIL_EXIT1 ("socket (%d, %d, %d): %m\n", domain, type, protocol); ++ return fd; ++} +diff --git a/support/xsocket.h b/support/xsocket.h +new file mode 100644 +index 0000000000..d6724948d8 +--- /dev/null ++++ b/support/xsocket.h +@@ -0,0 +1,39 @@ ++/* Error-checking wrappers for socket functions. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#ifndef SUPPORT_XSOCKET_H ++#define SUPPORT_XSOCKET_H ++ ++#include <poll.h> ++#include <sys/socket.h> ++#include <sys/types.h> ++ ++int xsocket (int, int, int); ++void xsetsockopt (int, int, int, const void *, socklen_t); ++void xgetsockname (int, struct sockaddr *, socklen_t *); ++void xconnect (int, const struct sockaddr *, socklen_t); ++void xbind (int, const struct sockaddr *, socklen_t); ++void xlisten (int, int); ++int xaccept (int, struct sockaddr *, socklen_t *); ++int xaccept4 (int, struct sockaddr *, socklen_t *, int); ++void xsendto (int, const void *, size_t, int, ++ const struct sockaddr *, socklen_t); ++size_t xrecvfrom (int, void *, size_t, int, struct sockaddr *, socklen_t *); ++int xpoll (struct pollfd *, nfds_t, int); ++ ++#endif /* SUPPORT_XSOCKET_H */ +diff --git a/support/xstdio.h b/support/xstdio.h +new file mode 100644 +index 0000000000..bcc2e863bf +--- /dev/null ++++ b/support/xstdio.h +@@ -0,0 +1,32 @@ ++/* Error-checking wrappers for stdio functions. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#ifndef SUPPORT_XSTDIO_H ++#define SUPPORT_XSTDIO_H ++ ++#include <stdio.h> ++#include <sys/cdefs.h> ++ ++__BEGIN_DECLS ++ ++FILE *xfopen (const char *path, const char *mode); ++void xfclose (FILE *); ++ ++__END_DECLS ++ ++#endif /* SUPPORT_XSTDIO_H */ +diff --git a/support/xstrdup.c b/support/xstrdup.c +new file mode 100644 +index 0000000000..d6a8c04baf +--- /dev/null ++++ b/support/xstrdup.c +@@ -0,0 +1,30 @@ ++/* strdup with error checking. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <support/support.h> ++ ++#include <string.h> ++ ++char * ++xstrdup (const char *s) ++{ ++ char *p = strdup (s); ++ if (p == NULL) ++ oom_error ("strdup", strlen (s)); ++ return p; ++} +diff --git a/support/xthread.h b/support/xthread.h +new file mode 100644 +index 0000000000..6dd7e709be +--- /dev/null ++++ b/support/xthread.h +@@ -0,0 +1,77 @@ ++/* Support functionality for using threads. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#ifndef SUPPORT_THREAD_H ++#define SUPPORT_THREAD_H ++ ++#include <pthread.h> ++#include <sys/cdefs.h> ++ ++__BEGIN_DECLS ++ ++/* Terminate the process (with exit status 0) after SECONDS have ++ elapsed, from a helper thread. The process is terminated with the ++ exit function, so atexit handlers are executed. */ ++void delayed_exit (int seconds); ++ ++/* Terminate the process (with exit status 1) if VALUE is not zero. ++ In that case, print a failure message to standard output mentioning ++ FUNCTION. The process is terminated with the exit function, so ++ atexit handlers are executed. */ ++void xpthread_check_return (const char *function, int value); ++ ++/* The following functions call the corresponding libpthread functions ++ and terminate the process on error. */ ++ ++void xpthread_barrier_init (pthread_barrier_t *barrier, ++ pthread_barrierattr_t *attr, unsigned int count); ++void xpthread_barrier_destroy (pthread_barrier_t *barrier); ++void xpthread_mutexattr_destroy (pthread_mutexattr_t *); ++void xpthread_mutexattr_init (pthread_mutexattr_t *); ++void xpthread_mutexattr_setprotocol (pthread_mutexattr_t *, int); ++void xpthread_mutexattr_setpshared (pthread_mutexattr_t *, int); ++void xpthread_mutexattr_setrobust (pthread_mutexattr_t *, int); ++void xpthread_mutexattr_settype (pthread_mutexattr_t *, int); ++void xpthread_mutex_init (pthread_mutex_t *, const pthread_mutexattr_t *); ++void xpthread_mutex_destroy (pthread_mutex_t *); ++void xpthread_mutex_lock (pthread_mutex_t *mutex); ++void xpthread_mutex_unlock (pthread_mutex_t *mutex); ++void xpthread_mutex_consistent (pthread_mutex_t *); ++void xpthread_spin_lock (pthread_spinlock_t *lock); ++void xpthread_spin_unlock (pthread_spinlock_t *lock); ++void xpthread_cond_wait (pthread_cond_t * cond, pthread_mutex_t * mutex); ++pthread_t xpthread_create (pthread_attr_t *attr, ++ void *(*thread_func) (void *), void *closure); ++void xpthread_detach (pthread_t thr); ++void xpthread_cancel (pthread_t thr); ++void *xpthread_join (pthread_t thr); ++void xpthread_once (pthread_once_t *guard, void (*func) (void)); ++void xpthread_attr_destroy (pthread_attr_t *attr); ++void xpthread_attr_init (pthread_attr_t *attr); ++void xpthread_attr_setdetachstate (pthread_attr_t *attr, ++ int detachstate); ++void xpthread_attr_setstacksize (pthread_attr_t *attr, ++ size_t stacksize); ++ ++/* This function returns non-zero if pthread_barrier_wait returned ++ PTHREAD_BARRIER_SERIAL_THREAD. */ ++int xpthread_barrier_wait (pthread_barrier_t *barrier); ++ ++__END_DECLS ++ ++#endif /* SUPPORT_THREAD_H */ +diff --git a/support/xunistd.h b/support/xunistd.h +new file mode 100644 +index 0000000000..151d743e1f +--- /dev/null ++++ b/support/xunistd.h +@@ -0,0 +1,56 @@ ++/* POSIX-specific extra functions. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++/* These wrapper functions use POSIX types and therefore cannot be ++ declared in <support/support.h>. */ ++ ++#ifndef SUPPORT_XUNISTD_H ++#define SUPPORT_XUNISTD_H ++ ++#include <sys/cdefs.h> ++#include <sys/types.h> ++#include <unistd.h> ++ ++__BEGIN_DECLS ++ ++struct stat64; ++ ++pid_t xfork (void); ++pid_t xwaitpid (pid_t, int *status, int flags); ++void xpipe (int[2]); ++void xdup2 (int, int); ++int xopen (const char *path, int flags, mode_t); ++void xstat (const char *path, struct stat64 *); ++void xmkdir (const char *path, mode_t); ++void xchroot (const char *path); ++ ++/* Close the file descriptor. Ignore EINTR errors, but terminate the ++ process on other errors. */ ++void xclose (int); ++ ++/* Write the buffer. Retry on short writes. */ ++void xwrite (int, const void *, size_t); ++ ++/* Invoke mmap with a zero file offset. */ ++void *xmmap (void *addr, size_t length, int prot, int flags, int fd); ++ ++void xmunmap (void *addr, size_t length); ++ ++__END_DECLS ++ ++#endif /* SUPPORT_XUNISTD_H */ +diff --git a/support/xwaitpid.c b/support/xwaitpid.c +new file mode 100644 +index 0000000000..204795e4c0 +--- /dev/null ++++ b/support/xwaitpid.c +@@ -0,0 +1,33 @@ ++/* waitpid with error checking. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <support/xunistd.h> ++ ++#include <stdio.h> ++#include <stdlib.h> ++#include <support/check.h> ++#include <sys/wait.h> ++ ++int ++xwaitpid (int pid, int *status, int flags) ++{ ++ pid_t result = waitpid (pid, status, flags); ++ if (result < 0) ++ FAIL_EXIT1 ("waitpid: %m\n"); ++ return result; ++} +diff --git a/support/xwrite.c b/support/xwrite.c +new file mode 100644 +index 0000000000..134e8ee4c1 +--- /dev/null ++++ b/support/xwrite.c +@@ -0,0 +1,39 @@ ++/* write with error checking and retries. ++ Copyright (C) 2016-2017 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ The GNU C Library is free software; you can redistribute it and/or ++ modify it under the terms of the GNU Lesser General Public ++ License as published by the Free Software Foundation; either ++ version 2.1 of the License, or (at your option) any later version. ++ ++ The GNU C Library 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 ++ Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public ++ License along with the GNU C Library; if not, see ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <support/xunistd.h> ++ ++#include <support/check.h> ++ ++void ++xwrite (int fd, const void *buffer, size_t length) ++{ ++ const char *p = buffer; ++ const char *end = p + length; ++ while (p < end) ++ { ++ ssize_t ret = write (fd, p, end - p); ++ if (ret < 0) ++ FAIL_EXIT1 ("write of %zu bytes failed after %td: %m", ++ length, p - (const char *) buffer); ++ if (ret == 0) ++ FAIL_EXIT1 ("write return 0 after writing %td bytes of %zu", ++ p - (const char *) buffer, length); ++ p += ret; ++ } ++} +diff --git a/sysdeps/aarch64/nptl/tcb-offsets.sym b/sysdeps/aarch64/nptl/tcb-offsets.sym +index 0677aeabff..238647dd47 100644 +--- a/sysdeps/aarch64/nptl/tcb-offsets.sym ++++ b/sysdeps/aarch64/nptl/tcb-offsets.sym +@@ -2,6 +2,5 @@ + #include <tls.h> + + PTHREAD_MULTIPLE_THREADS_OFFSET offsetof (struct pthread, header.multiple_threads) +-PTHREAD_PID_OFFSET offsetof (struct pthread, pid) + PTHREAD_TID_OFFSET offsetof (struct pthread, tid) + PTHREAD_SIZEOF sizeof (struct pthread) +diff --git a/sysdeps/alpha/fpu/s_ceil.c b/sysdeps/alpha/fpu/s_ceil.c +index c1ff864d4b..e9c350af1c 100644 +--- a/sysdeps/alpha/fpu/s_ceil.c ++++ b/sysdeps/alpha/fpu/s_ceil.c +@@ -26,17 +26,16 @@ + double + __ceil (double x) + { ++ if (isnan (x)) ++ return x + x; ++ + if (isless (fabs (x), 9007199254740992.0)) /* 1 << DBL_MANT_DIG */ + { + double tmp1, new_x; + + new_x = -x; + __asm ( +-#ifdef _IEEE_FP_INEXACT +- "cvttq/svim %2,%1\n\t" +-#else + "cvttq/svm %2,%1\n\t" +-#endif + "cvtqt/m %1,%0\n\t" + : "=f"(new_x), "=&f"(tmp1) + : "f"(new_x)); +diff --git a/sysdeps/alpha/fpu/s_ceilf.c b/sysdeps/alpha/fpu/s_ceilf.c +index 7e63a6fe94..77e01a99f7 100644 +--- a/sysdeps/alpha/fpu/s_ceilf.c ++++ b/sysdeps/alpha/fpu/s_ceilf.c +@@ -25,6 +25,9 @@ + float + __ceilf (float x) + { ++ if (isnanf (x)) ++ return x + x; ++ + if (isless (fabsf (x), 16777216.0f)) /* 1 << FLT_MANT_DIG */ + { + /* Note that Alpha S_Floating is stored in registers in a +@@ -36,11 +39,7 @@ __ceilf (float x) + + new_x = -x; + __asm ("cvtst/s %3,%2\n\t" +-#ifdef _IEEE_FP_INEXACT +- "cvttq/svim %2,%1\n\t" +-#else + "cvttq/svm %2,%1\n\t" +-#endif + "cvtqt/m %1,%0\n\t" + : "=f"(new_x), "=&f"(tmp1), "=&f"(tmp2) + : "f"(new_x)); +diff --git a/sysdeps/alpha/fpu/s_floor.c b/sysdeps/alpha/fpu/s_floor.c +index 1a6f8c4617..9930f6be42 100644 +--- a/sysdeps/alpha/fpu/s_floor.c ++++ b/sysdeps/alpha/fpu/s_floor.c +@@ -27,16 +27,15 @@ + double + __floor (double x) + { ++ if (isnan (x)) ++ return x + x; ++ + if (isless (fabs (x), 9007199254740992.0)) /* 1 << DBL_MANT_DIG */ + { + double tmp1, new_x; + + __asm ( +-#ifdef _IEEE_FP_INEXACT +- "cvttq/svim %2,%1\n\t" +-#else + "cvttq/svm %2,%1\n\t" +-#endif + "cvtqt/m %1,%0\n\t" + : "=f"(new_x), "=&f"(tmp1) + : "f"(x)); +diff --git a/sysdeps/alpha/fpu/s_floorf.c b/sysdeps/alpha/fpu/s_floorf.c +index 8cd80e2b42..015c04f40d 100644 +--- a/sysdeps/alpha/fpu/s_floorf.c ++++ b/sysdeps/alpha/fpu/s_floorf.c +@@ -26,6 +26,9 @@ + float + __floorf (float x) + { ++ if (isnanf (x)) ++ return x + x; ++ + if (isless (fabsf (x), 16777216.0f)) /* 1 << FLT_MANT_DIG */ + { + /* Note that Alpha S_Floating is stored in registers in a +@@ -36,11 +39,7 @@ __floorf (float x) + float tmp1, tmp2, new_x; + + __asm ("cvtst/s %3,%2\n\t" +-#ifdef _IEEE_FP_INEXACT +- "cvttq/svim %2,%1\n\t" +-#else + "cvttq/svm %2,%1\n\t" +-#endif + "cvtqt/m %1,%0\n\t" + : "=f"(new_x), "=&f"(tmp1), "=&f"(tmp2) + : "f"(x)); +diff --git a/sysdeps/alpha/fpu/s_rint.c b/sysdeps/alpha/fpu/s_rint.c +index f33fe72c11..259348afc0 100644 +--- a/sysdeps/alpha/fpu/s_rint.c ++++ b/sysdeps/alpha/fpu/s_rint.c +@@ -23,6 +23,9 @@ + double + __rint (double x) + { ++ if (isnan (x)) ++ return x + x; ++ + if (isless (fabs (x), 9007199254740992.0)) /* 1 << DBL_MANT_DIG */ + { + double tmp1, new_x; +diff --git a/sysdeps/alpha/fpu/s_rintf.c b/sysdeps/alpha/fpu/s_rintf.c +index 1400dfe8d7..645728ad5b 100644 +--- a/sysdeps/alpha/fpu/s_rintf.c ++++ b/sysdeps/alpha/fpu/s_rintf.c +@@ -22,6 +22,9 @@ + float + __rintf (float x) + { ++ if (isnanf (x)) ++ return x + x; ++ + if (isless (fabsf (x), 16777216.0f)) /* 1 << FLT_MANT_DIG */ + { + /* Note that Alpha S_Floating is stored in registers in a +diff --git a/sysdeps/alpha/fpu/s_trunc.c b/sysdeps/alpha/fpu/s_trunc.c +index 16cb114a72..4b986a6926 100644 +--- a/sysdeps/alpha/fpu/s_trunc.c ++++ b/sysdeps/alpha/fpu/s_trunc.c +@@ -28,12 +28,11 @@ __trunc (double x) + double two52 = copysign (0x1.0p52, x); + double r, tmp; + ++ if (isgreaterequal (fabs (x), 0x1.0p52)) ++ return x; ++ + __asm ( +-#ifdef _IEEE_FP_INEXACT +- "addt/suic %2, %3, %1\n\tsubt/suic %1, %3, %0" +-#else + "addt/suc %2, %3, %1\n\tsubt/suc %1, %3, %0" +-#endif + : "=&f"(r), "=&f"(tmp) + : "f"(x), "f"(two52)); + +diff --git a/sysdeps/alpha/fpu/s_truncf.c b/sysdeps/alpha/fpu/s_truncf.c +index 2290f28295..3e93356166 100644 +--- a/sysdeps/alpha/fpu/s_truncf.c ++++ b/sysdeps/alpha/fpu/s_truncf.c +@@ -27,12 +27,11 @@ __truncf (float x) + float two23 = copysignf (0x1.0p23, x); + float r, tmp; + ++ if (isgreaterequal (fabsf (x), 0x1.0p23)) ++ return x; ++ + __asm ( +-#ifdef _IEEE_FP_INEXACT +- "adds/suic %2, %3, %1\n\tsubs/suic %1, %3, %0" +-#else + "adds/suc %2, %3, %1\n\tsubs/suc %1, %3, %0" +-#endif + : "=&f"(r), "=&f"(tmp) + : "f"(x), "f"(two23)); + +diff --git a/sysdeps/alpha/nptl/tcb-offsets.sym b/sysdeps/alpha/nptl/tcb-offsets.sym +index c21a791040..1005621b37 100644 +--- a/sysdeps/alpha/nptl/tcb-offsets.sym ++++ b/sysdeps/alpha/nptl/tcb-offsets.sym +@@ -10,5 +10,4 @@ + #define thread_offsetof(mem) (long)(offsetof(struct pthread, mem) - sizeof(struct pthread)) + + MULTIPLE_THREADS_OFFSET thread_offsetof (header.multiple_threads) +-PID_OFFSET thread_offsetof (pid) + TID_OFFSET thread_offsetof (tid) +diff --git a/sysdeps/arm/nacl/libc.abilist b/sysdeps/arm/nacl/libc.abilist +index 2f7751d167..dfa7198306 100644 +--- a/sysdeps/arm/nacl/libc.abilist ++++ b/sysdeps/arm/nacl/libc.abilist +@@ -1840,4 +1840,5 @@ GLIBC_2.23 fts64_close F + GLIBC_2.23 fts64_open F + GLIBC_2.23 fts64_read F + GLIBC_2.23 fts64_set F ++GLIBC_2.24 GLIBC_2.24 A + GLIBC_2.24 quick_exit F +diff --git a/sysdeps/arm/nptl/tcb-offsets.sym b/sysdeps/arm/nptl/tcb-offsets.sym +index 92cc441d3d..bf9c0a1c17 100644 +--- a/sysdeps/arm/nptl/tcb-offsets.sym ++++ b/sysdeps/arm/nptl/tcb-offsets.sym +@@ -7,5 +7,4 @@ + #define thread_offsetof(mem) (long)(offsetof(struct pthread, mem) - sizeof(struct pthread)) + + MULTIPLE_THREADS_OFFSET thread_offsetof (header.multiple_threads) +-PID_OFFSET thread_offsetof (pid) + TID_OFFSET thread_offsetof (tid) +diff --git a/sysdeps/generic/unsecvars.h b/sysdeps/generic/unsecvars.h +index d5b8119c9c..ac57bd5db0 100644 +--- a/sysdeps/generic/unsecvars.h ++++ b/sysdeps/generic/unsecvars.h +@@ -4,11 +4,13 @@ + #define UNSECURE_ENVVARS \ + "GCONV_PATH\0" \ + "GETCONF_DIR\0" \ ++ "GLIBC_TUNABLES\0" \ + "HOSTALIASES\0" \ + "LD_AUDIT\0" \ + "LD_DEBUG\0" \ + "LD_DEBUG_OUTPUT\0" \ + "LD_DYNAMIC_WEAK\0" \ ++ "LD_HWCAP_MASK\0" \ + "LD_LIBRARY_PATH\0" \ + "LD_ORIGIN_PATH\0" \ + "LD_PRELOAD\0" \ +diff --git a/sysdeps/hppa/dl-machine.h b/sysdeps/hppa/dl-machine.h +index 9404211819..01bd5bf197 100644 +--- a/sysdeps/hppa/dl-machine.h ++++ b/sysdeps/hppa/dl-machine.h +@@ -302,6 +302,10 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile) + #define ARCH_LA_PLTENTER hppa_gnu_pltenter + #define ARCH_LA_PLTEXIT hppa_gnu_pltexit + ++/* Adjust DL_STACK_END to get value we want in __libc_stack_end. */ ++#define DL_STACK_END(cookie) \ ++ ((void *) (((long) (cookie)) + 0x160)) ++ + /* Initial entry point code for the dynamic linker. + The C function `_dl_start' is the real entry point; + its return value is the user program's entry point. */ +@@ -401,11 +405,6 @@ asm ( \ + /* Save the entry point in %r3. */ \ + " copy %ret0,%r3\n" \ + \ +- /* Remember the lowest stack address. */ \ +-" addil LT'__libc_stack_end,%r19\n" \ +-" ldw RT'__libc_stack_end(%r1),%r20\n" \ +-" stw %sp,0(%r20)\n" \ +- \ + /* See if we were called as a command with the executable file \ + name as an extra leading argument. */ \ + " addil LT'_dl_skip_args,%r19\n" \ +diff --git a/sysdeps/hppa/nptl/tcb-offsets.sym b/sysdeps/hppa/nptl/tcb-offsets.sym +index c2f326ee3d..6e852f35b1 100644 +--- a/sysdeps/hppa/nptl/tcb-offsets.sym ++++ b/sysdeps/hppa/nptl/tcb-offsets.sym +@@ -3,7 +3,6 @@ + + RESULT offsetof (struct pthread, result) + TID offsetof (struct pthread, tid) +-PID offsetof (struct pthread, pid) + CANCELHANDLING offsetof (struct pthread, cancelhandling) + CLEANUP_JMP_BUF offsetof (struct pthread, cleanup_jmp_buf) + MULTIPLE_THREADS_OFFSET offsetof (struct pthread, header.multiple_threads) +@@ -14,6 +13,5 @@ MUTEX_FUTEX offsetof (pthread_mutex_t, __data.__lock) + -- This way we get the offset of a member in the struct pthread that + -- preceeds the thread pointer (which points to the dtv). + #define thread_offsetof(mem) (unsigned int)(offsetof(struct pthread, mem) - sizeof(struct pthread)) +-PID_THREAD_OFFSET thread_offsetof (pid) + TID_THREAD_OFFSET thread_offsetof (tid) + MULTIPLE_THREADS_THREAD_OFFSET thread_offsetof (header.multiple_threads) +diff --git a/sysdeps/i386/i686/multiarch/strcspn-c.c b/sysdeps/i386/i686/multiarch/strcspn-c.c +index 6d61e190a8..ec230fb383 100644 +--- a/sysdeps/i386/i686/multiarch/strcspn-c.c ++++ b/sysdeps/i386/i686/multiarch/strcspn-c.c +@@ -1,2 +1,4 @@ +-#define __strcspn_sse2 __strcspn_ia32 +-#include <sysdeps/x86_64/multiarch/strcspn-c.c> ++#if IS_IN (libc) ++# define __strcspn_sse2 __strcspn_ia32 ++# include <sysdeps/x86_64/multiarch/strcspn-c.c> ++#endif +diff --git a/sysdeps/i386/i686/multiarch/varshift.c b/sysdeps/i386/i686/multiarch/varshift.c +index 7760b966e2..6742a35d41 100644 +--- a/sysdeps/i386/i686/multiarch/varshift.c ++++ b/sysdeps/i386/i686/multiarch/varshift.c +@@ -1 +1,3 @@ +-#include <sysdeps/x86_64/multiarch/varshift.c> ++#if IS_IN (libc) ++# include <sysdeps/x86_64/multiarch/varshift.c> ++#endif +diff --git a/sysdeps/i386/nptl/tcb-offsets.sym b/sysdeps/i386/nptl/tcb-offsets.sym +index 7bdf161b29..695a810386 100644 +--- a/sysdeps/i386/nptl/tcb-offsets.sym ++++ b/sysdeps/i386/nptl/tcb-offsets.sym +@@ -4,7 +4,6 @@ + + RESULT offsetof (struct pthread, result) + TID offsetof (struct pthread, tid) +-PID offsetof (struct pthread, pid) + CANCELHANDLING offsetof (struct pthread, cancelhandling) + CLEANUP_JMP_BUF offsetof (struct pthread, cleanup_jmp_buf) + MULTIPLE_THREADS_OFFSET offsetof (tcbhead_t, multiple_threads) +diff --git a/sysdeps/ia64/nptl/Makefile b/sysdeps/ia64/nptl/Makefile +index 48f1327446..1e6be8eea8 100644 +--- a/sysdeps/ia64/nptl/Makefile ++++ b/sysdeps/ia64/nptl/Makefile +@@ -21,4 +21,5 @@ endif + + ifeq ($(subdir),nptl) + libpthread-routines += ptw-sysdep ptw-sigblock ptw-sigprocmask ++libpthread-shared-only-routines += ptw-sysdep ptw-sigblock ptw-sigprocmask + endif +diff --git a/sysdeps/ia64/nptl/tcb-offsets.sym b/sysdeps/ia64/nptl/tcb-offsets.sym +index e1707ab1c8..b01f712be2 100644 +--- a/sysdeps/ia64/nptl/tcb-offsets.sym ++++ b/sysdeps/ia64/nptl/tcb-offsets.sym +@@ -1,7 +1,6 @@ + #include <sysdep.h> + #include <tls.h> + +-PID offsetof (struct pthread, pid) - TLS_PRE_TCB_SIZE + TID offsetof (struct pthread, tid) - TLS_PRE_TCB_SIZE + MULTIPLE_THREADS_OFFSET offsetof (struct pthread, header.multiple_threads) - TLS_PRE_TCB_SIZE + SYSINFO_OFFSET offsetof (tcbhead_t, __private) +diff --git a/sysdeps/m68k/m680x0/m68020/atomic-machine.h b/sysdeps/m68k/m680x0/m68020/atomic-machine.h +index 24bc5c5ef7..65965cca9e 100644 +--- a/sysdeps/m68k/m680x0/m68020/atomic-machine.h ++++ b/sysdeps/m68k/m680x0/m68020/atomic-machine.h +@@ -73,7 +73,7 @@ typedef uintmax_t uatomic_max_t; + __typeof (mem) __memp = (mem); \ + __asm __volatile ("cas2%.l %0:%R0,%1:%R1,(%2):(%3)" \ + : "=d" (__ret) \ +- : "d" (newval), "r" (__memp), \ ++ : "d" ((__typeof (*(mem))) (newval)), "r" (__memp), \ + "r" ((char *) __memp + 4), "0" (oldval) \ + : "memory"); \ + __ret; }) +@@ -101,8 +101,9 @@ typedef uintmax_t uatomic_max_t; + __asm __volatile ("1: cas2%.l %0:%R0,%1:%R1,(%2):(%3);" \ + " jbne 1b" \ + : "=d" (__result) \ +- : "d" (newvalue), "r" (__memp), \ +- "r" ((char *) __memp + 4), "0" (__result) \ ++ : "d" ((__typeof (*(mem))) (newvalue)), \ ++ "r" (__memp), "r" ((char *) __memp + 4), \ ++ "0" (__result) \ + : "memory"); \ + } \ + __result; }) +@@ -144,7 +145,7 @@ typedef uintmax_t uatomic_max_t; + " cas2%.l %0:%R0,%1:%R1,(%3):(%4);" \ + " jbne 1b" \ + : "=d" (__result), "=&d" (__temp) \ +- : "d" (value), "r" (__memp), \ ++ : "d" ((__typeof (*(mem))) (value)), "r" (__memp), \ + "r" ((char *) __memp + 4), "0" (__result) \ + : "memory"); \ + } \ +@@ -175,8 +176,9 @@ typedef uintmax_t uatomic_max_t; + " cas2%.l %0:%R0,%1:%R1,(%3):(%4);" \ + " jbne 1b" \ + : "=d" (__oldval), "=&d" (__temp) \ +- : "d" (value), "r" (__memp), \ +- "r" ((char *) __memp + 4), "0" (__oldval) \ ++ : "d" ((__typeof (*(mem))) (value)), \ ++ "r" (__memp), "r" ((char *) __memp + 4), \ ++ "0" (__oldval) \ + : "memory"); \ + } \ + }) +diff --git a/sysdeps/m68k/nptl/tcb-offsets.sym b/sysdeps/m68k/nptl/tcb-offsets.sym +index b1bba65868..241fb8b47c 100644 +--- a/sysdeps/m68k/nptl/tcb-offsets.sym ++++ b/sysdeps/m68k/nptl/tcb-offsets.sym +@@ -7,5 +7,4 @@ + #define thread_offsetof(mem) (long)(offsetof(struct pthread, mem) - TLS_TCB_OFFSET - TLS_PRE_TCB_SIZE) + + MULTIPLE_THREADS_OFFSET thread_offsetof (header.multiple_threads) +-PID_OFFSET thread_offsetof (pid) + TID_OFFSET thread_offsetof (tid) +diff --git a/sysdeps/microblaze/nptl/tcb-offsets.sym b/sysdeps/microblaze/nptl/tcb-offsets.sym +index 18afbee291..614f0dfed6 100644 +--- a/sysdeps/microblaze/nptl/tcb-offsets.sym ++++ b/sysdeps/microblaze/nptl/tcb-offsets.sym +@@ -7,5 +7,4 @@ + #define thread_offsetof(mem) (long)(offsetof (struct pthread, mem) - sizeof (struct pthread)) + + MULTIPLE_THREADS_OFFSET thread_offsetof (header.multiple_threads) +-PID_OFFSET thread_offsetof (pid) + TID_OFFSET thread_offsetof (tid) +diff --git a/sysdeps/mips/Makefile b/sysdeps/mips/Makefile +index 3d3552322b..7c1d77941e 100644 +--- a/sysdeps/mips/Makefile ++++ b/sysdeps/mips/Makefile +@@ -9,6 +9,7 @@ endif + + ifeq ($(subdir),rt) + librt-sysdep_routines += rt-sysdep ++librt-shared-only-routines += rt-sysdep + endif + + ifeq ($(subdir),debug) +diff --git a/sysdeps/mips/mips32/crti.S b/sysdeps/mips/mips32/crti.S +index 5c0ad7328a..dfbbdc4f8f 100644 +--- a/sysdeps/mips/mips32/crti.S ++++ b/sysdeps/mips/mips32/crti.S +@@ -74,6 +74,7 @@ _init: + .reloc 1f,R_MIPS_JALR,PREINIT_FUNCTION + 1: jalr $25 + .Lno_weak_fn: ++ .insn + #else + lw $25,%got(PREINIT_FUNCTION)($28) + .reloc 1f,R_MIPS_JALR,PREINIT_FUNCTION +diff --git a/sysdeps/mips/mips64/n32/crti.S b/sysdeps/mips/mips64/n32/crti.S +index 00b89f3894..afe6d8edaa 100644 +--- a/sysdeps/mips/mips64/n32/crti.S ++++ b/sysdeps/mips/mips64/n32/crti.S +@@ -74,6 +74,7 @@ _init: + .reloc 1f,R_MIPS_JALR,PREINIT_FUNCTION + 1: jalr $25 + .Lno_weak_fn: ++ .insn + #else + lw $25,%got_disp(PREINIT_FUNCTION)($28) + .reloc 1f,R_MIPS_JALR,PREINIT_FUNCTION +diff --git a/sysdeps/mips/mips64/n64/crti.S b/sysdeps/mips/mips64/n64/crti.S +index f59b20c631..4049d29290 100644 +--- a/sysdeps/mips/mips64/n64/crti.S ++++ b/sysdeps/mips/mips64/n64/crti.S +@@ -74,6 +74,7 @@ _init: + .reloc 1f,R_MIPS_JALR,PREINIT_FUNCTION + 1: jalr $25 + .Lno_weak_fn: ++ .insn + #else + ld $25,%got_disp(PREINIT_FUNCTION)($28) + .reloc 1f,R_MIPS_JALR,PREINIT_FUNCTION +diff --git a/sysdeps/mips/nptl/Makefile b/sysdeps/mips/nptl/Makefile +index 117744ffe2..dda154d842 100644 +--- a/sysdeps/mips/nptl/Makefile ++++ b/sysdeps/mips/nptl/Makefile +@@ -21,4 +21,5 @@ endif + + ifeq ($(subdir),nptl) + libpthread-sysdep_routines += nptl-sysdep ++libpthread-shared-only-routines += nptl-sysdep + endif +diff --git a/sysdeps/mips/nptl/tcb-offsets.sym b/sysdeps/mips/nptl/tcb-offsets.sym +index e0e71dc430..9ea25b94a8 100644 +--- a/sysdeps/mips/nptl/tcb-offsets.sym ++++ b/sysdeps/mips/nptl/tcb-offsets.sym +@@ -7,5 +7,4 @@ + #define thread_offsetof(mem) (long)(offsetof(struct pthread, mem) - TLS_TCB_OFFSET - TLS_PRE_TCB_SIZE) + + MULTIPLE_THREADS_OFFSET thread_offsetof (header.multiple_threads) +-PID_OFFSET thread_offsetof (pid) + TID_OFFSET thread_offsetof (tid) +diff --git a/sysdeps/nacl/clock.c b/sysdeps/nacl/clock.c +index 664ad650c3..b6fbcfd2dd 100644 +--- a/sysdeps/nacl/clock.c ++++ b/sysdeps/nacl/clock.c +@@ -24,6 +24,6 @@ + clock_t + clock (void) + { +- nacl_abi_clock_t result; ++ nacl_irt_clock_t result; + return NACL_CALL (__nacl_irt_basic.clock (&result), result); + } +diff --git a/sysdeps/nacl/dup.c b/sysdeps/nacl/dup.c +index 34a7cd46d4..cbce3f5a5a 100644 +--- a/sysdeps/nacl/dup.c ++++ b/sysdeps/nacl/dup.c +@@ -27,4 +27,5 @@ __dup (int fd) + int result; + return NACL_CALL (__nacl_irt_fdio.dup (fd, &result), result); + } ++libc_hidden_def (__dup) + weak_alias (__dup, dup) +diff --git a/sysdeps/nios2/nptl/tcb-offsets.sym b/sysdeps/nios2/nptl/tcb-offsets.sym +index d9ae952585..3cd8d984ac 100644 +--- a/sysdeps/nios2/nptl/tcb-offsets.sym ++++ b/sysdeps/nios2/nptl/tcb-offsets.sym +@@ -9,6 +9,5 @@ + # define thread_offsetof(mem) ((ptrdiff_t) THREAD_SELF + offsetof (struct pthread, mem)) + + MULTIPLE_THREADS_OFFSET thread_offsetof (header.multiple_threads) +-PID_OFFSET thread_offsetof (pid) + TID_OFFSET thread_offsetof (tid) + POINTER_GUARD (offsetof (tcbhead_t, pointer_guard) - TLS_TCB_OFFSET - sizeof (tcbhead_t)) +diff --git a/sysdeps/nptl/fork.c b/sysdeps/nptl/fork.c +index 616d897a36..a5d1e86d71 100644 +--- a/sysdeps/nptl/fork.c ++++ b/sysdeps/nptl/fork.c +@@ -131,16 +131,6 @@ __libc_fork (void) + __malloc_fork_lock_parent (); + } + +-#ifndef NDEBUG +- pid_t ppid = THREAD_GETMEM (THREAD_SELF, tid); +-#endif +- +- /* We need to prevent the getpid() code to update the PID field so +- that, if a signal arrives in the child very early and the signal +- handler uses getpid(), the value returned is correct. */ +- pid_t parentpid = THREAD_GETMEM (THREAD_SELF, pid); +- THREAD_SETMEM (THREAD_SELF, pid, -parentpid); +- + #ifdef ARCH_FORK + pid = ARCH_FORK (); + #else +@@ -153,15 +143,10 @@ __libc_fork (void) + { + struct pthread *self = THREAD_SELF; + +- assert (THREAD_GETMEM (self, tid) != ppid); +- + /* See __pthread_once. */ + if (__fork_generation_pointer != NULL) + *__fork_generation_pointer += __PTHREAD_ONCE_FORK_GEN_INCR; + +- /* Adjust the PID field for the new process. */ +- THREAD_SETMEM (self, pid, THREAD_GETMEM (self, tid)); +- + #if HP_TIMING_AVAIL + /* The CPU clock of the thread and process have to be set to zero. */ + hp_timing_t now; +@@ -231,11 +216,6 @@ __libc_fork (void) + } + else + { +- assert (THREAD_GETMEM (THREAD_SELF, tid) == ppid); +- +- /* Restore the PID value. */ +- THREAD_SETMEM (THREAD_SELF, pid, parentpid); +- + /* Release acquired locks in the multi-threaded case. */ + if (multiple_threads) + { +diff --git a/sysdeps/posix/wait3.c b/sysdeps/posix/wait3.c +index cf43d973a7..73722d2be6 100644 +--- a/sysdeps/posix/wait3.c ++++ b/sysdeps/posix/wait3.c +@@ -33,7 +33,7 @@ __wait3 (int *stat_loc, int options, struct rusage *usage) + __set_errno (ENOSYS); + return (pid_t) -1; + } +- return __waitpid (WAIT_ANY, stat_loc.__iptr, options); ++ return __waitpid (WAIT_ANY, stat_loc, options); + } + + weak_alias (__wait3, wait3) +diff --git a/sysdeps/powerpc/fpu/libm-test-ulps b/sysdeps/powerpc/fpu/libm-test-ulps +index 7f37c813d0..36b700c520 100644 +--- a/sysdeps/powerpc/fpu/libm-test-ulps ++++ b/sysdeps/powerpc/fpu/libm-test-ulps +@@ -36,8 +36,8 @@ double: 2 + float: 2 + idouble: 2 + ifloat: 2 +-ildouble: 1 +-ldouble: 1 ++ildouble: 2 ++ldouble: 2 + + Function: "acosh_downward": + double: 1 +@@ -52,8 +52,8 @@ double: 2 + float: 2 + idouble: 2 + ifloat: 2 +-ildouble: 3 +-ldouble: 3 ++ildouble: 4 ++ldouble: 4 + + Function: "acosh_upward": + double: 2 +@@ -122,8 +122,8 @@ double: 3 + float: 3 + idouble: 3 + ifloat: 3 +-ildouble: 4 +-ldouble: 4 ++ildouble: 7 ++ldouble: 7 + + Function: "atan": + double: 1 +@@ -216,8 +216,8 @@ double: 3 + float: 3 + idouble: 3 + ifloat: 3 +-ildouble: 3 +-ldouble: 3 ++ildouble: 4 ++ldouble: 4 + + Function: "cabs": + double: 1 +@@ -272,8 +272,8 @@ double: 5 + float: 3 + idouble: 5 + ifloat: 3 +-ildouble: 5 +-ldouble: 5 ++ildouble: 8 ++ldouble: 8 + + Function: Real part of "cacos_towardzero": + double: 2 +@@ -288,8 +288,8 @@ double: 5 + float: 3 + idouble: 5 + ifloat: 3 +-ildouble: 5 +-ldouble: 5 ++ildouble: 8 ++ldouble: 8 + + Function: Real part of "cacos_upward": + double: 2 +@@ -328,8 +328,8 @@ double: 5 + float: 3 + idouble: 5 + ifloat: 3 +-ildouble: 5 +-ldouble: 5 ++ildouble: 8 ++ldouble: 8 + + Function: Imaginary part of "cacosh_downward": + double: 2 +@@ -344,8 +344,8 @@ double: 5 + float: 3 + idouble: 5 + ifloat: 3 +-ildouble: 5 +-ldouble: 5 ++ildouble: 8 ++ldouble: 8 + + Function: Imaginary part of "cacosh_towardzero": + double: 2 +@@ -432,8 +432,8 @@ double: 5 + float: 3 + idouble: 5 + ifloat: 3 +-ildouble: 5 +-ldouble: 5 ++ildouble: 8 ++ldouble: 8 + + Function: Real part of "casin_towardzero": + double: 3 +@@ -448,8 +448,8 @@ double: 5 + float: 3 + idouble: 5 + ifloat: 3 +-ildouble: 5 +-ldouble: 5 ++ildouble: 8 ++ldouble: 8 + + Function: Real part of "casin_upward": + double: 2 +@@ -488,8 +488,8 @@ double: 5 + float: 3 + idouble: 5 + ifloat: 3 +-ildouble: 5 +-ldouble: 5 ++ildouble: 8 ++ldouble: 8 + + Function: Imaginary part of "casinh_downward": + double: 3 +@@ -504,8 +504,8 @@ double: 5 + float: 3 + idouble: 5 + ifloat: 3 +-ildouble: 5 +-ldouble: 5 ++ildouble: 8 ++ldouble: 8 + + Function: Imaginary part of "casinh_towardzero": + double: 3 +@@ -696,8 +696,8 @@ double: 1 + float: 1 + idouble: 1 + ifloat: 1 +-ildouble: 1 +-ldouble: 1 ++ildouble: 2 ++ldouble: 2 + + Function: Real part of "ccos_downward": + double: 1 +@@ -1132,8 +1132,8 @@ double: 1 + float: 1 + idouble: 1 + ifloat: 1 +-ildouble: 1 +-ldouble: 1 ++ildouble: 2 ++ldouble: 2 + + Function: Imaginary part of "csin": + ildouble: 1 +@@ -1198,8 +1198,8 @@ double: 1 + float: 1 + idouble: 1 + ifloat: 1 +-ildouble: 1 +-ldouble: 1 ++ildouble: 2 ++ldouble: 2 + + Function: Real part of "csinh_downward": + double: 2 +@@ -1318,8 +1318,8 @@ double: 1 + float: 1 + idouble: 1 + ifloat: 1 +-ildouble: 2 +-ldouble: 2 ++ildouble: 3 ++ldouble: 3 + + Function: Imaginary part of "ctan": + double: 2 +@@ -1390,8 +1390,8 @@ double: 2 + float: 1 + idouble: 2 + ifloat: 1 +-ildouble: 2 +-ldouble: 2 ++ildouble: 3 ++ldouble: 3 + + Function: Real part of "ctanh_downward": + double: 4 +@@ -1478,8 +1478,8 @@ double: 2 + float: 2 + idouble: 2 + ifloat: 2 +-ildouble: 2 +-ldouble: 2 ++ildouble: 3 ++ldouble: 3 + + Function: "erfc_downward": + double: 3 +@@ -1564,8 +1564,8 @@ double: 1 + float: 1 + idouble: 1 + ifloat: 1 +-ildouble: 1 +-ldouble: 1 ++ildouble: 2 ++ldouble: 2 + + Function: "exp2_upward": + double: 1 +@@ -1588,8 +1588,8 @@ ildouble: 2 + ldouble: 2 + + Function: "exp_upward": +-float: 1 + double: 1 ++float: 1 + idouble: 1 + ifloat: 1 + ildouble: 1 +@@ -1624,8 +1624,8 @@ double: 1 + float: 1 + idouble: 1 + ifloat: 1 +-ildouble: 4 +-ldouble: 4 ++ildouble: 6 ++ldouble: 6 + + Function: "fma": + ildouble: 1 +@@ -1688,8 +1688,8 @@ double: 4 + float: 5 + idouble: 4 + ifloat: 5 +-ildouble: 10 +-ldouble: 10 ++ildouble: 11 ++ldouble: 11 + + Function: "hypot": + double: 1 +@@ -1752,8 +1752,8 @@ double: 1 + float: 2 + idouble: 1 + ifloat: 2 +-ildouble: 1 +-ldouble: 1 ++ildouble: 2 ++ldouble: 2 + + Function: "j1_downward": + double: 3 +@@ -1840,8 +1840,8 @@ double: 4 + float: 5 + idouble: 4 + ifloat: 5 +-ildouble: 10 +-ldouble: 10 ++ildouble: 11 ++ldouble: 11 + + Function: "log": + float: 1 +@@ -1910,8 +1910,8 @@ double: 2 + float: 2 + idouble: 2 + ifloat: 2 +-ildouble: 2 +-ldouble: 2 ++ildouble: 3 ++ldouble: 3 + + Function: "log2": + double: 1 +@@ -2184,16 +2184,16 @@ double: 3 + float: 3 + idouble: 3 + ifloat: 3 +-ildouble: 3 +-ldouble: 3 ++ildouble: 4 ++ldouble: 4 + + Function: "tanh_towardzero": + double: 2 + float: 2 + idouble: 2 + ifloat: 2 +-ildouble: 3 +-ldouble: 3 ++ildouble: 4 ++ldouble: 4 + + Function: "tanh_upward": + double: 3 +diff --git a/sysdeps/powerpc/ifunc-sel.h b/sysdeps/powerpc/ifunc-sel.h +index 526d8ed88b..ac589bd3c0 100644 +--- a/sysdeps/powerpc/ifunc-sel.h ++++ b/sysdeps/powerpc/ifunc-sel.h +@@ -17,15 +17,17 @@ ifunc_sel (int (*f1) (void), int (*f2) (void), int (*f3) (void)) + "addis %0,11,%2-1b@ha\n\t" + "addi %0,%0,%2-1b@l\n\t" + "cmpwi 12,1\n\t" +- "beqlr\n\t" ++ "beq 2f\n\t" + "addis %0,11,%3-1b@ha\n\t" + "addi %0,%0,%3-1b@l\n\t" + "cmpwi 12,-1\n\t" +- "beqlr\n\t" ++ "beq 2f\n\t" + "addis %0,11,%4-1b@ha\n\t" +- "addi %0,%0,%4-1b@l" ++ "addi %0,%0,%4-1b@l\n\t" ++ "2:" + : "=r" (ret) +- : "X" (&global), "X" (f1), "X" (f2), "X" (f3)); ++ : "i" (&global), "i" (f1), "i" (f2), "i" (f3) ++ : "11", "12", "cr0"); + return ret; + } + +@@ -40,7 +42,8 @@ ifunc_one (int (*f1) (void)) + "addis %0,%0,%1-1b@ha\n\t" + "addi %0,%0,%1-1b@l" + : "=r" (ret) +- : "X" (f1)); ++ : "i" (f1) ++ : "12"); + return ret; + } + #endif +diff --git a/sysdeps/powerpc/nptl/tcb-offsets.sym b/sysdeps/powerpc/nptl/tcb-offsets.sym +index f580e69555..7c9fd33562 100644 +--- a/sysdeps/powerpc/nptl/tcb-offsets.sym ++++ b/sysdeps/powerpc/nptl/tcb-offsets.sym +@@ -13,7 +13,6 @@ + #if TLS_MULTIPLE_THREADS_IN_TCB + MULTIPLE_THREADS_OFFSET thread_offsetof (header.multiple_threads) + #endif +-PID thread_offsetof (pid) + TID thread_offsetof (tid) + POINTER_GUARD (offsetof (tcbhead_t, pointer_guard) - TLS_TCB_OFFSET - sizeof (tcbhead_t)) + TAR_SAVE (offsetof (tcbhead_t, tar_save) - TLS_TCB_OFFSET - sizeof (tcbhead_t)) +diff --git a/sysdeps/powerpc/powerpc32/power6/memset.S b/sysdeps/powerpc/powerpc32/power6/memset.S +index b2a222edd2..d5dbe83af2 100644 +--- a/sysdeps/powerpc/powerpc32/power6/memset.S ++++ b/sysdeps/powerpc/powerpc32/power6/memset.S +@@ -394,7 +394,7 @@ L(cacheAlignedx): + /* A simple loop for the longer (>640 bytes) lengths. This form limits + the branch miss-predicted to exactly 1 at loop exit.*/ + L(cacheAligned512): +- cmpli cr1,rLEN,128 ++ cmplwi cr1,rLEN,128 + blt cr1,L(cacheAligned1) + dcbz 0,rMEMP + addi rLEN,rLEN,-128 +diff --git a/sysdeps/powerpc/powerpc32/power9/multiarch/Implies b/sysdeps/powerpc/powerpc32/power9/multiarch/Implies +index 4393b56872..1a46ef0035 100644 +--- a/sysdeps/powerpc/powerpc32/power9/multiarch/Implies ++++ b/sysdeps/powerpc/powerpc32/power9/multiarch/Implies +@@ -1 +1 @@ +-powerpc/powerpc32/power8/fpu/multiarch ++powerpc/powerpc32/power8/multiarch +diff --git a/sysdeps/powerpc/powerpc64/power6/memset.S b/sysdeps/powerpc/powerpc64/power6/memset.S +index c2d1c4e600..d445b1e1ef 100644 +--- a/sysdeps/powerpc/powerpc64/power6/memset.S ++++ b/sysdeps/powerpc/powerpc64/power6/memset.S +@@ -251,7 +251,7 @@ L(cacheAlignedx): + /* A simple loop for the longer (>640 bytes) lengths. This form limits + the branch miss-predicted to exactly 1 at loop exit.*/ + L(cacheAligned512): +- cmpli cr1,rLEN,128 ++ cmpldi cr1,rLEN,128 + blt cr1,L(cacheAligned1) + dcbz 0,rMEMP + addi rLEN,rLEN,-128 +diff --git a/sysdeps/powerpc/powerpc64/power9/fpu/Implies b/sysdeps/powerpc/powerpc64/power9/fpu/Implies +index fad2505ab9..ae0dbaf857 100644 +--- a/sysdeps/powerpc/powerpc64/power9/fpu/Implies ++++ b/sysdeps/powerpc/powerpc64/power9/fpu/Implies +@@ -1,2 +1 @@ + powerpc/powerpc64/power8/fpu +-powerpc/powerpc64/power8 +diff --git a/sysdeps/s390/nptl/Makefile b/sysdeps/s390/nptl/Makefile +index 5734b983b0..3a391c8217 100644 +--- a/sysdeps/s390/nptl/Makefile ++++ b/sysdeps/s390/nptl/Makefile +@@ -21,4 +21,5 @@ endif + + ifeq ($(subdir),nptl) + libpthread-routines += ptw-sysdep ++libpthread-shared-only-routines += ptw-sysdep + endif +diff --git a/sysdeps/s390/nptl/tcb-offsets.sym b/sysdeps/s390/nptl/tcb-offsets.sym +index 9cfae211e0..9c1c01f353 100644 +--- a/sysdeps/s390/nptl/tcb-offsets.sym ++++ b/sysdeps/s390/nptl/tcb-offsets.sym +@@ -3,5 +3,4 @@ + + MULTIPLE_THREADS_OFFSET offsetof (tcbhead_t, multiple_threads) + STACK_GUARD offsetof (tcbhead_t, stack_guard) +-PID offsetof (struct pthread, pid) + TID offsetof (struct pthread, tid) +diff --git a/sysdeps/sh/nptl/tcb-offsets.sym b/sysdeps/sh/nptl/tcb-offsets.sym +index ac63b5b93b..4963e1506f 100644 +--- a/sysdeps/sh/nptl/tcb-offsets.sym ++++ b/sysdeps/sh/nptl/tcb-offsets.sym +@@ -4,7 +4,6 @@ + + RESULT offsetof (struct pthread, result) + TID offsetof (struct pthread, tid) +-PID offsetof (struct pthread, pid) + CANCELHANDLING offsetof (struct pthread, cancelhandling) + CLEANUP_JMP_BUF offsetof (struct pthread, cleanup_jmp_buf) + MULTIPLE_THREADS_OFFSET offsetof (struct pthread, header.multiple_threads) +diff --git a/sysdeps/sparc/nptl/tcb-offsets.sym b/sysdeps/sparc/nptl/tcb-offsets.sym +index 923af8a5b7..f75d02065e 100644 +--- a/sysdeps/sparc/nptl/tcb-offsets.sym ++++ b/sysdeps/sparc/nptl/tcb-offsets.sym +@@ -3,5 +3,4 @@ + + MULTIPLE_THREADS_OFFSET offsetof (tcbhead_t, multiple_threads) + POINTER_GUARD offsetof (tcbhead_t, pointer_guard) +-PID offsetof (struct pthread, pid) + TID offsetof (struct pthread, tid) +diff --git a/sysdeps/sparc/sparc32/sparcv9/fpu/multiarch/Makefile b/sysdeps/sparc/sparc32/sparcv9/fpu/multiarch/Makefile +index ebbe28b07f..13d3c6db51 100644 +--- a/sysdeps/sparc/sparc32/sparcv9/fpu/multiarch/Makefile ++++ b/sysdeps/sparc/sparc32/sparcv9/fpu/multiarch/Makefile +@@ -4,8 +4,8 @@ libm-sysdep_routines += m_copysignf-vis3 m_copysign-vis3 s_fabs-vis3 \ + s_fabsf-vis3 s_llrintf-vis3 s_llrint-vis3 \ + s_rintf-vis3 s_rint-vis3 w_sqrt-vis3 w_sqrtf-vis3 \ + s_fminf-vis3 s_fmin-vis3 s_fmaxf-vis3 s_fmax-vis3 \ +- s_fmaf-vis3 s_fma-vis3 s_fdimf-vis3 s_fdim-vis3 \ +- s_nearbyint-vis3 s_nearbyintf-vis3 ++ s_fmaf-vis3 s_fma-vis3 s_nearbyint-vis3 \ ++ s_nearbyintf-vis3 + sysdep_routines += s_copysignf-vis3 s_copysign-vis3 + endif + endif +diff --git a/sysdeps/sparc/sparc32/sparcv9/fpu/multiarch/s_fdim.S b/sysdeps/sparc/sparc32/sparcv9/fpu/multiarch/s_fdim.S +deleted file mode 100644 +index 4b13408244..0000000000 +--- a/sysdeps/sparc/sparc32/sparcv9/fpu/multiarch/s_fdim.S ++++ /dev/null +@@ -1,19 +0,0 @@ +-#include <sparc-ifunc.h> +-#include <math_ldbl_opt.h> +- +-SPARC_ASM_VIS3_IFUNC(fdim) +- +-weak_alias (__fdim, fdim) +- +-#if LONG_DOUBLE_COMPAT(libm, GLIBC_2_1) +-compat_symbol (libm, __fdim, fdiml, GLIBC_2_1); +-#endif +- +-# undef weak_alias +-# define weak_alias(a, b) +-# undef compat_symbol +-# define compat_symbol(a, b, c, d) +- +-#define __fdim __fdim_generic +- +-#include "../s_fdim.S" +diff --git a/sysdeps/sparc/sparc32/sparcv9/fpu/multiarch/s_fdimf.S b/sysdeps/sparc/sparc32/sparcv9/fpu/multiarch/s_fdimf.S +deleted file mode 100644 +index 30381d6a59..0000000000 +--- a/sysdeps/sparc/sparc32/sparcv9/fpu/multiarch/s_fdimf.S ++++ /dev/null +@@ -1,12 +0,0 @@ +-#include <sparc-ifunc.h> +- +-SPARC_ASM_VIS3_IFUNC(fdimf) +- +-weak_alias (__fdimf, fdimf) +- +-# undef weak_alias +-# define weak_alias(a, b) +- +-#define __fdimf __fdimf_generic +- +-#include "../s_fdimf.S" +diff --git a/sysdeps/sparc/sparc32/sparcv9/fpu/multiarch/s_nearbyint-vis3.S b/sysdeps/sparc/sparc32/sparcv9/fpu/multiarch/s_nearbyint-vis3.S +index d9ff0cc288..ff81b0da83 100644 +--- a/sysdeps/sparc/sparc32/sparcv9/fpu/multiarch/s_nearbyint-vis3.S ++++ b/sysdeps/sparc/sparc32/sparcv9/fpu/multiarch/s_nearbyint-vis3.S +@@ -36,15 +36,15 @@ + #define SIGN_BIT %f12 /* -0.0 */ + + ENTRY (__nearbyint_vis3) ++ sllx %o0, 32, %o0 ++ or %o0, %o1, %o0 ++ movxtod %o0, %f0 + fcmpd %fcc3, %f0, %f0 /* Check for sNaN */ + st %fsr, [%sp + 88] + sethi %hi(TWO_FIFTYTWO), %o2 + sethi %hi(0xf8003e0), %o5 + ld [%sp + 88], %o4 +- sllx %o0, 32, %o0 + or %o5, %lo(0xf8003e0), %o5 +- or %o0, %o1, %o0 +- movxtod %o0, %f0 + andn %o4, %o5, %o4 + fzero ZERO + st %o4, [%sp + 80] +diff --git a/sysdeps/sparc/sparc32/sparcv9/fpu/multiarch/s_nearbyintf-vis3.S b/sysdeps/sparc/sparc32/sparcv9/fpu/multiarch/s_nearbyintf-vis3.S +index 5cd1eb02db..833a0dfc24 100644 +--- a/sysdeps/sparc/sparc32/sparcv9/fpu/multiarch/s_nearbyintf-vis3.S ++++ b/sysdeps/sparc/sparc32/sparcv9/fpu/multiarch/s_nearbyintf-vis3.S +@@ -35,9 +35,9 @@ + #define SIGN_BIT %f12 /* -0.0 */ + + ENTRY (__nearbyintf_vis3) ++ movwtos %o0, %f1 + fcmps %fcc3, %f1, %f1 /* Check for sNaN */ + st %fsr, [%sp + 88] +- movwtos %o0, %f1 + sethi %hi(TWO_TWENTYTHREE), %o2 + sethi %hi(0xf8003e0), %o5 + ld [%sp + 88], %o4 +diff --git a/sysdeps/sparc/sparc32/sparcv9/fpu/s_nearbyint.S b/sysdeps/sparc/sparc32/sparcv9/fpu/s_nearbyint.S +index 84a10971a4..198440a5bc 100644 +--- a/sysdeps/sparc/sparc32/sparcv9/fpu/s_nearbyint.S ++++ b/sysdeps/sparc/sparc32/sparcv9/fpu/s_nearbyint.S +@@ -36,21 +36,21 @@ + #define SIGN_BIT %f12 /* -0.0 */ + + ENTRY (__nearbyint) ++ sllx %o0, 32, %o0 ++ or %o0, %o1, %o0 ++ stx %o0, [%sp + 72] ++ ldd [%sp + 72], %f0 + fcmpd %fcc3, %f0, %f0 /* Check for sNaN */ + st %fsr, [%sp + 88] + sethi %hi(TWO_FIFTYTWO), %o2 + sethi %hi(0xf8003e0), %o5 + ld [%sp + 88], %o4 +- sllx %o0, 32, %o0 + or %o5, %lo(0xf8003e0), %o5 +- or %o0, %o1, %o0 + andn %o4, %o5, %o4 + fzero ZERO + st %o4, [%sp + 80] +- stx %o0, [%sp + 72] + sllx %o2, 32, %o2 + fnegd ZERO, SIGN_BIT +- ldd [%sp + 72], %f0 + ld [%sp + 80], %fsr + stx %o2, [%sp + 72] + fabsd %f0, %f14 +diff --git a/sysdeps/sparc/sparc32/sparcv9/fpu/s_nearbyintf.S b/sysdeps/sparc/sparc32/sparcv9/fpu/s_nearbyintf.S +index d5cf5ce815..9be41f6c22 100644 +--- a/sysdeps/sparc/sparc32/sparcv9/fpu/s_nearbyintf.S ++++ b/sysdeps/sparc/sparc32/sparcv9/fpu/s_nearbyintf.S +@@ -35,9 +35,10 @@ + #define SIGN_BIT %f12 /* -0.0 */ + + ENTRY (__nearbyintf) ++ st %o0, [%sp + 68] ++ ld [%sp + 68], %f1 + fcmps %fcc3, %f1, %f1 /* Check for sNaN */ + st %fsr, [%sp + 88] +- st %o0, [%sp + 68] + sethi %hi(TWO_TWENTYTHREE), %o2 + sethi %hi(0xf8003e0), %o5 + ld [%sp + 88], %o4 +@@ -46,7 +47,6 @@ ENTRY (__nearbyintf) + fnegs ZERO, SIGN_BIT + andn %o4, %o5, %o4 + st %o4, [%sp + 80] +- ld [%sp + 68], %f1 + ld [%sp + 80], %fsr + st %o2, [%sp + 68] + fabss %f1, %f14 +diff --git a/sysdeps/tile/nptl/tcb-offsets.sym b/sysdeps/tile/nptl/tcb-offsets.sym +index 6740bc976f..0147ffafb7 100644 +--- a/sysdeps/tile/nptl/tcb-offsets.sym ++++ b/sysdeps/tile/nptl/tcb-offsets.sym +@@ -9,7 +9,6 @@ + #define thread_offsetof(mem) (long)(offsetof(struct pthread, mem) - TLS_TCB_OFFSET - TLS_PRE_TCB_SIZE) + + MULTIPLE_THREADS_OFFSET thread_offsetof (header.multiple_threads) +-PID_OFFSET thread_offsetof (pid) + TID_OFFSET thread_offsetof (tid) + POINTER_GUARD (offsetof (tcbhead_t, pointer_guard) - TLS_TCB_OFFSET - sizeof (tcbhead_t)) + FEEDBACK_DATA_OFFSET (offsetof (tcbhead_t, feedback_data) - TLS_TCB_OFFSET - sizeof (tcbhead_t)) +diff --git a/sysdeps/unix/alpha/Makefile b/sysdeps/unix/alpha/Makefile +index 441aa02a83..0660847f15 100644 +--- a/sysdeps/unix/alpha/Makefile ++++ b/sysdeps/unix/alpha/Makefile +@@ -1,3 +1,4 @@ + ifeq ($(subdir),rt) + librt-sysdep_routines += rt-sysdep ++librt-shared-only-routines += rt-sysdep + endif +diff --git a/sysdeps/unix/sysdep.h b/sysdeps/unix/sysdep.h +index 94a2ce0e37..38c2432002 100644 +--- a/sysdeps/unix/sysdep.h ++++ b/sysdeps/unix/sysdep.h +@@ -24,42 +24,79 @@ + #define SYSCALL__(name, args) PSEUDO (__##name, name, args) + #define SYSCALL(name, args) PSEUDO (name, name, args) + +-#define __SYSCALL0(name) \ ++#define __SYSCALL_CONCAT_X(a,b) a##b ++#define __SYSCALL_CONCAT(a,b) __SYSCALL_CONCAT_X (a, b) ++ ++ ++#define __INTERNAL_SYSCALL0(name, err) \ ++ INTERNAL_SYSCALL (name, err, 0) ++#define __INTERNAL_SYSCALL1(name, err, a1) \ ++ INTERNAL_SYSCALL (name, err, 1, a1) ++#define __INTERNAL_SYSCALL2(name, err, a1, a2) \ ++ INTERNAL_SYSCALL (name, err, 2, a1, a2) ++#define __INTERNAL_SYSCALL3(name, err, a1, a2, a3) \ ++ INTERNAL_SYSCALL (name, err, 3, a1, a2, a3) ++#define __INTERNAL_SYSCALL4(name, err, a1, a2, a3, a4) \ ++ INTERNAL_SYSCALL (name, err, 4, a1, a2, a3, a4) ++#define __INTERNAL_SYSCALL5(name, err, a1, a2, a3, a4, a5) \ ++ INTERNAL_SYSCALL (name, err, 5, a1, a2, a3, a4, a5) ++#define __INTERNAL_SYSCALL6(name, err, a1, a2, a3, a4, a5, a6) \ ++ INTERNAL_SYSCALL (name, err, 6, a1, a2, a3, a4, a5, a6) ++#define __INTERNAL_SYSCALL7(name, err, a1, a2, a3, a4, a5, a6, a7) \ ++ INTERNAL_SYSCALL (name, err, 7, a1, a2, a3, a4, a5, a6, a7) ++ ++#define __INTERNAL_SYSCALL_NARGS_X(a,b,c,d,e,f,g,h,n,o,...) o ++#define __INTERNAL_SYSCALL_NARGS(...) \ ++ __INTERNAL_SYSCALL_NARGS_X (__VA_ARGS__,7,6,5,4,3,2,1,0,) ++#define __INTERNAL_SYSCALL_DISP(b,...) \ ++ __SYSCALL_CONCAT (b,__INTERNAL_SYSCALL_NARGS(__VA_ARGS__))(__VA_ARGS__) ++ ++/* Issue a syscall defined by syscall number plus any other argument required. ++ It is similar to INTERNAL_SYSCALL macro, but without the need to pass the ++ expected argument number as second parameter. */ ++#define INTERNAL_SYSCALL_CALL(...) \ ++ __INTERNAL_SYSCALL_DISP (__INTERNAL_SYSCALL, __VA_ARGS__) ++ ++#define __INLINE_SYSCALL0(name) \ + INLINE_SYSCALL (name, 0) +-#define __SYSCALL1(name, a1) \ ++#define __INLINE_SYSCALL1(name, a1) \ + INLINE_SYSCALL (name, 1, a1) +-#define __SYSCALL2(name, a1, a2) \ ++#define __INLINE_SYSCALL2(name, a1, a2) \ + INLINE_SYSCALL (name, 2, a1, a2) +-#define __SYSCALL3(name, a1, a2, a3) \ ++#define __INLINE_SYSCALL3(name, a1, a2, a3) \ + INLINE_SYSCALL (name, 3, a1, a2, a3) +-#define __SYSCALL4(name, a1, a2, a3, a4) \ ++#define __INLINE_SYSCALL4(name, a1, a2, a3, a4) \ + INLINE_SYSCALL (name, 4, a1, a2, a3, a4) +-#define __SYSCALL5(name, a1, a2, a3, a4, a5) \ ++#define __INLINE_SYSCALL5(name, a1, a2, a3, a4, a5) \ + INLINE_SYSCALL (name, 5, a1, a2, a3, a4, a5) +-#define __SYSCALL6(name, a1, a2, a3, a4, a5, a6) \ ++#define __INLINE_SYSCALL6(name, a1, a2, a3, a4, a5, a6) \ + INLINE_SYSCALL (name, 6, a1, a2, a3, a4, a5, a6) +-#define __SYSCALL7(name, a1, a2, a3, a4, a5, a6, a7) \ ++#define __INLINE_SYSCALL7(name, a1, a2, a3, a4, a5, a6, a7) \ + INLINE_SYSCALL (name, 7, a1, a2, a3, a4, a5, a6, a7) + +-#define __SYSCALL_NARGS_X(a,b,c,d,e,f,g,h,n,...) n +-#define __SYSCALL_NARGS(...) \ +- __SYSCALL_NARGS_X (__VA_ARGS__,7,6,5,4,3,2,1,0,) +-#define __SYSCALL_CONCAT_X(a,b) a##b +-#define __SYSCALL_CONCAT(a,b) __SYSCALL_CONCAT_X (a, b) +-#define __SYSCALL_DISP(b,...) \ +- __SYSCALL_CONCAT (b,__SYSCALL_NARGS(__VA_ARGS__))(__VA_ARGS__) ++#define __INLINE_SYSCALL_NARGS_X(a,b,c,d,e,f,g,h,n,...) n ++#define __INLINE_SYSCALL_NARGS(...) \ ++ __INLINE_SYSCALL_NARGS_X (__VA_ARGS__,7,6,5,4,3,2,1,0,) ++#define __INLINE_SYSCALL_DISP(b,...) \ ++ __SYSCALL_CONCAT (b,__INLINE_SYSCALL_NARGS(__VA_ARGS__))(__VA_ARGS__) + +-#define __SYSCALL_CALL(...) __SYSCALL_DISP (__SYSCALL, __VA_ARGS__) ++/* Issue a syscall defined by syscall number plus any other argument ++ required. Any error will be handled using arch defined macros and errno ++ will be set accordingly. ++ It is similar to INLINE_SYSCALL macro, but without the need to pass the ++ expected argument number as second parameter. */ ++#define INLINE_SYSCALL_CALL(...) \ ++ __INLINE_SYSCALL_DISP (__INLINE_SYSCALL, __VA_ARGS__) + + #define SYSCALL_CANCEL(...) \ + ({ \ + long int sc_ret; \ + if (SINGLE_THREAD_P) \ +- sc_ret = __SYSCALL_CALL (__VA_ARGS__); \ ++ sc_ret = INLINE_SYSCALL_CALL (__VA_ARGS__); \ + else \ + { \ + int sc_cancel_oldtype = LIBC_CANCEL_ASYNC (); \ +- sc_ret = __SYSCALL_CALL (__VA_ARGS__); \ ++ sc_ret = INLINE_SYSCALL_CALL (__VA_ARGS__); \ + LIBC_CANCEL_RESET (sc_cancel_oldtype); \ + } \ + sc_ret; \ +diff --git a/sysdeps/unix/sysv/linux/aarch64/clone.S b/sysdeps/unix/sysv/linux/aarch64/clone.S +index 76baa7a698..96482e53c0 100644 +--- a/sysdeps/unix/sysv/linux/aarch64/clone.S ++++ b/sysdeps/unix/sysv/linux/aarch64/clone.S +@@ -72,16 +72,6 @@ thread_start: + cfi_undefined (x30) + mov x29, 0 + +- tbnz x11, #CLONE_VM_BIT, 1f +- +- mov x8, #SYS_ify(getpid) +- svc 0x0 +- mrs x1, tpidr_el0 +- sub x1, x1, #PTHREAD_SIZEOF +- str w0, [x1, #PTHREAD_PID_OFFSET] +- str w0, [x1, #PTHREAD_TID_OFFSET] +-1: +- + /* Pick the function arg and execute. */ + mov x0, x12 + blr x10 +diff --git a/sysdeps/unix/sysv/linux/aarch64/vfork.S b/sysdeps/unix/sysv/linux/aarch64/vfork.S +index 577895eeb2..aeed0b29ce 100644 +--- a/sysdeps/unix/sysv/linux/aarch64/vfork.S ++++ b/sysdeps/unix/sysv/linux/aarch64/vfork.S +@@ -27,27 +27,10 @@ + + ENTRY (__vfork) + +- /* Save the TCB-cached PID away in w3, and then negate the TCB +- field. But if it's zero, set it to 0x80000000 instead. See +- raise.c for the logic that relies on this value. */ +- mrs x2, tpidr_el0 +- sub x2, x2, #PTHREAD_SIZEOF +- ldr w3, [x2, #PTHREAD_PID_OFFSET] +- mov w1, #0x80000000 +- negs w0, w3 +- csel w0, w1, w0, eq +- str w0, [x2, #PTHREAD_PID_OFFSET] +- + mov x0, #0x4111 /* CLONE_VM | CLONE_VFORK | SIGCHLD */ + mov x1, sp + DO_CALL (clone, 2) + +- /* Restore the original value of the TCB cache of the PID, if we're +- the parent. But in the child (syscall return value equals zero), +- leave things as they are. */ +- cbz x0, 1f +- str w3, [x2, #PTHREAD_PID_OFFSET] +-1: + cmn x0, #4095 + b.cs .Lsyscall_error + RET +diff --git a/sysdeps/unix/sysv/linux/alpha/Makefile b/sysdeps/unix/sysv/linux/alpha/Makefile +index c089545e9b..3b523b70cf 100644 +--- a/sysdeps/unix/sysv/linux/alpha/Makefile ++++ b/sysdeps/unix/sysv/linux/alpha/Makefile +@@ -40,4 +40,5 @@ endif # math + ifeq ($(subdir),nptl) + # pull in __syscall_error routine, __sigprocmask, __syscall_rt_sigaction + libpthread-routines += ptw-sysdep ptw-sigprocmask ptw-rt_sigaction ++libpthread-shared-only-routines += ptw-sysdep ptw-sigprocmask ptw-rt_sigaction + endif +diff --git a/sysdeps/unix/sysv/linux/alpha/clone.S b/sysdeps/unix/sysv/linux/alpha/clone.S +index 6a3154f9a7..2757bf20c3 100644 +--- a/sysdeps/unix/sysv/linux/alpha/clone.S ++++ b/sysdeps/unix/sysv/linux/alpha/clone.S +@@ -91,13 +91,6 @@ thread_start: + cfi_def_cfa_register(fp) + cfi_undefined(ra) + +- /* Check and see if we need to reset the PID. */ +- ldq t0, 16(sp) +- lda t1, CLONE_VM +- and t0, t1, t2 +- beq t2, 2f +-1: +- + /* Load up the arguments. */ + ldq pv, 0(sp) + ldq a0, 8(sp) +@@ -120,15 +113,6 @@ thread_start: + halt + + .align 4 +-2: +- rduniq +- mov v0, s0 +- lda v0, __NR_getxpid +- callsys +-3: +- stl v0, PID_OFFSET(s0) +- stl v0, TID_OFFSET(s0) +- br 1b + cfi_endproc + .end thread_start + +diff --git a/sysdeps/unix/sysv/linux/alpha/vfork.S b/sysdeps/unix/sysv/linux/alpha/vfork.S +index 9fc199ac41..e5f7ed0661 100644 +--- a/sysdeps/unix/sysv/linux/alpha/vfork.S ++++ b/sysdeps/unix/sysv/linux/alpha/vfork.S +@@ -25,24 +25,9 @@ ENTRY(__libc_vfork) + rduniq + mov v0, a1 + +- /* Save the TCB-cached PID away in A2, and then negate the TCB +- field. But if it's zero, set it to 0x80000000 instead. See +- raise.c for the logic that relies on this value. */ +- ldl a2, PID_OFFSET(v0) +- ldah t0, -0x8000 +- negl a2, t1 +- cmovne a2, t1, t0 +- stl t0, PID_OFFSET(v0); +- + lda v0, SYS_ify(vfork) + call_pal PAL_callsys + +- /* Restore the original value of the TCB cache of the PID, if we're +- the parent. But in the child (syscall return value equals zero), +- leave things as they are. */ +- beq v0, 1f +- stl a2, PID_OFFSET(a1) +-1: + /* Normal error check and return. */ + bne a3, SYSCALL_ERROR_LABEL + ret +diff --git a/sysdeps/unix/sysv/linux/arm/clone.S b/sysdeps/unix/sysv/linux/arm/clone.S +index 7ff681804b..4c6325d088 100644 +--- a/sysdeps/unix/sysv/linux/arm/clone.S ++++ b/sysdeps/unix/sysv/linux/arm/clone.S +@@ -70,16 +70,6 @@ PSEUDO_END (__clone) + 1: + .fnstart + .cantunwind +- tst ip, #CLONE_VM +- bne 2f +- GET_TLS (lr) +- mov r1, r0 +- ldr r7, =SYS_ify(getpid) +- swi 0x0 +- NEGOFF_ADJ_BASE (r1, TID_OFFSET) +- str r0, NEGOFF_OFF1 (r1, TID_OFFSET) +- str r0, NEGOFF_OFF2 (r1, PID_OFFSET, TID_OFFSET) +-2: + @ pick the function arg and call address off the stack and execute + ldr r0, [sp, #4] + ldr ip, [sp], #8 +diff --git a/sysdeps/unix/sysv/linux/arm/setcontext.S b/sysdeps/unix/sysv/linux/arm/setcontext.S +index 603e508858..d1f168fece 100644 +--- a/sysdeps/unix/sysv/linux/arm/setcontext.S ++++ b/sysdeps/unix/sysv/linux/arm/setcontext.S +@@ -86,12 +86,19 @@ weak_alias(__setcontext, setcontext) + + /* Called when a makecontext() context returns. Start the + context in R4 or fall through to exit(). */ ++ /* Unwind descriptors are looked up based on PC - 2, so we have to ++ make sure to mark the instruction preceding the __startcontext ++ label as .cantunwind. */ ++ .fnstart ++ .cantunwind ++ nop + ENTRY(__startcontext) + movs r0, r4 + bne PLTJMP(__setcontext) + + @ New context was 0 - exit + b PLTJMP(HIDDEN_JUMPTARGET(exit)) ++ .fnend + END(__startcontext) + + #ifdef PIC +diff --git a/sysdeps/unix/sysv/linux/arm/vfork.S b/sysdeps/unix/sysv/linux/arm/vfork.S +index 500f5ca4be..794372ee12 100644 +--- a/sysdeps/unix/sysv/linux/arm/vfork.S ++++ b/sysdeps/unix/sysv/linux/arm/vfork.S +@@ -28,16 +28,6 @@ + and the process ID of the new process to the old process. */ + + ENTRY (__vfork) +- /* Save the PID value. */ +- GET_TLS (r2) +- NEGOFF_ADJ_BASE2 (r2, r0, PID_OFFSET) /* Save the TLS addr in r2. */ +- ldr r3, NEGOFF_OFF1 (r2, PID_OFFSET) /* Load the saved PID. */ +- rsbs r0, r3, #0 /* Negate it, and test for zero. */ +- /* Use 0x80000000 if it was 0. See raise.c for how this is used. */ +- it eq +- moveq r0, #0x80000000 +- str r0, NEGOFF_OFF1 (r2, PID_OFFSET) /* Store the temp PID. */ +- + /* The DO_CALL macro saves r7 on the stack, to enable generation + of ARM unwind info. Since the stack is initially shared between + parent and child of vfork, that saved value could be corrupted. +@@ -57,11 +47,6 @@ ENTRY (__vfork) + mov r7, ip + cfi_restore (r7) + +- /* Restore the old PID value in the parent. */ +- cmp r0, #0 /* If we are the parent... */ +- it ne +- strne r3, NEGOFF_OFF1 (r2, PID_OFFSET) /* restore the saved PID. */ +- + cmn a1, #4096 + it cc + RETINSTR(cc, lr) +diff --git a/sysdeps/unix/sysv/linux/createthread.c b/sysdeps/unix/sysv/linux/createthread.c +index 6d32cece48..ec86f50814 100644 +--- a/sysdeps/unix/sysv/linux/createthread.c ++++ b/sysdeps/unix/sysv/linux/createthread.c +@@ -128,10 +128,10 @@ create_thread (struct pthread *pd, const struct pthread_attr *attr, + /* The operation failed. We have to kill the thread. + We let the normal cancellation mechanism do the work. */ + ++ pid_t pid = __getpid (); + INTERNAL_SYSCALL_DECL (err2); +- (void) INTERNAL_SYSCALL (tgkill, err2, 3, +- THREAD_GETMEM (THREAD_SELF, pid), +- pd->tid, SIGCANCEL); ++ (void) INTERNAL_SYSCALL_CALL (tgkill, err2, pid, pd->tid, ++ SIGCANCEL); + + return INTERNAL_SYSCALL_ERRNO (res, err); + } +diff --git a/sysdeps/unix/sysv/linux/getpid.c b/sysdeps/unix/sysv/linux/getpid.c +deleted file mode 100644 +index 1124549326..0000000000 +--- a/sysdeps/unix/sysv/linux/getpid.c ++++ /dev/null +@@ -1,64 +0,0 @@ +-/* Copyright (C) 2003-2016 Free Software Foundation, Inc. +- This file is part of the GNU C Library. +- Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. +- +- The GNU C Library is free software; you can redistribute it and/or +- modify it under the terms of the GNU Lesser General Public +- License as published by the Free Software Foundation; either +- version 2.1 of the License, or (at your option) any later version. +- +- The GNU C Library 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 +- Lesser General Public License for more details. +- +- You should have received a copy of the GNU Lesser General Public +- License along with the GNU C Library; if not, see +- <http://www.gnu.org/licenses/>. */ +- +-#include <unistd.h> +-#include <tls.h> +-#include <sysdep.h> +- +- +-#if IS_IN (libc) +-static inline __attribute__((always_inline)) pid_t really_getpid (pid_t oldval); +- +-static inline __attribute__((always_inline)) pid_t +-really_getpid (pid_t oldval) +-{ +- if (__glibc_likely (oldval == 0)) +- { +- pid_t selftid = THREAD_GETMEM (THREAD_SELF, tid); +- if (__glibc_likely (selftid != 0)) +- return selftid; +- } +- +- INTERNAL_SYSCALL_DECL (err); +- pid_t result = INTERNAL_SYSCALL (getpid, err, 0); +- +- /* We do not set the PID field in the TID here since we might be +- called from a signal handler while the thread executes fork. */ +- if (oldval == 0) +- THREAD_SETMEM (THREAD_SELF, tid, result); +- return result; +-} +-#endif +- +-pid_t +-__getpid (void) +-{ +-#if !IS_IN (libc) +- INTERNAL_SYSCALL_DECL (err); +- pid_t result = INTERNAL_SYSCALL (getpid, err, 0); +-#else +- pid_t result = THREAD_GETMEM (THREAD_SELF, pid); +- if (__glibc_unlikely (result <= 0)) +- result = really_getpid (result); +-#endif +- return result; +-} +- +-libc_hidden_def (__getpid) +-weak_alias (__getpid, getpid) +-libc_hidden_def (getpid) +diff --git a/sysdeps/unix/sysv/linux/hppa/clone.S b/sysdeps/unix/sysv/linux/hppa/clone.S +index 3d037f1430..25fcd497f7 100644 +--- a/sysdeps/unix/sysv/linux/hppa/clone.S ++++ b/sysdeps/unix/sysv/linux/hppa/clone.S +@@ -132,18 +132,6 @@ ENTRY(__clone) + ldwm -64(%sp), %r4 + + .LthreadStart: +-# define CLONE_VM_BIT 23 /* 0x00000100 */ +- /* Load original clone flags. +- If CLONE_VM was passed, don't modify PID/TID. +- Otherwise store the result of getpid to PID/TID. */ +- ldw -56(%sp), %r26 +- bb,<,n %r26, CLONE_VM_BIT, 1f +- ble 0x100(%sr2, %r0) +- ldi __NR_getpid, %r20 +- mfctl %cr27, %r26 +- stw %ret0, PID_THREAD_OFFSET(%r26) +- stw %ret0, TID_THREAD_OFFSET(%r26) +-1: + /* Load up the arguments. */ + ldw -60(%sp), %arg0 + ldw -64(%sp), %r22 +diff --git a/sysdeps/unix/sysv/linux/hppa/pt-vfork.S b/sysdeps/unix/sysv/linux/hppa/pt-vfork.S +index df532362d2..4684048502 100644 +--- a/sysdeps/unix/sysv/linux/hppa/pt-vfork.S ++++ b/sysdeps/unix/sysv/linux/hppa/pt-vfork.S +@@ -25,26 +25,6 @@ + replaced by a call to `execve'. Return -1 for errors, 0 to the new process, + and the process ID of the new process to the old process. */ + +-/* Load the thread register. +- Load the saved PID value. +- Negate the value. +- Store the temporary PID. */ +-#define SAVE_PID \ +- mfctl %cr27, %r26 ASM_LINE_SEP \ +- ldw PID_THREAD_OFFSET(%r26),%r1 ASM_LINE_SEP \ +- sub %r0,%r1,%r1 ASM_LINE_SEP \ +- stw %r1,PID_THREAD_OFFSET(%r26) ASM_LINE_SEP +-/* If we are the parent... +- Get the thread pointer. +- Load the saved PID. +- Negate the value (got back original) +- Restore the PID. */ +-#define RESTORE_PID \ +- cmpb,=,n %r0,%ret0,.Lthread_start ASM_LINE_SEP \ +- mfctl %cr27, %r26 ASM_LINE_SEP \ +- ldw PID_THREAD_OFFSET(%r26),%r1 ASM_LINE_SEP \ +- sub %r0,%r1,%r1 ASM_LINE_SEP \ +- stw %r1,PID_THREAD_OFFSET(%r26) ASM_LINE_SEP \ + .Lthread_start: ASM_LINE_SEP + + /* r26, r25, r24, r23 are free since vfork has no arguments */ +@@ -58,16 +38,10 @@ ENTRY(__vfork) + copy %r19, %r25 /* parent */ + #endif + +- /* Save the process PID */ +- SAVE_PID +- + /* Syscall saves and restores all register states */ + ble 0x100(%sr2,%r0) + ldi __NR_vfork,%r20 + +- /* Conditionally restore the PID */ +- RESTORE_PID +- + /* Check for error */ + ldi -4096,%r1 + comclr,>>= %r1,%ret0,%r0 /* Note: unsigned compare. */ +diff --git a/sysdeps/unix/sysv/linux/i386/Makefile b/sysdeps/unix/sysv/linux/i386/Makefile +index 71ba61e9d7..6073a9fe04 100644 +--- a/sysdeps/unix/sysv/linux/i386/Makefile ++++ b/sysdeps/unix/sysv/linux/i386/Makefile +@@ -31,6 +31,7 @@ endif + # libpthread uses six-argument inline syscalls. + ifeq ($(subdir),nptl) + libpthread-sysdep_routines += libc-do-syscall ++libpthread-shared-only-routines += libc-do-syscall + endif + + ifeq ($(subdir),resource) +@@ -48,9 +49,11 @@ endif + ifeq ($(subdir),nptl) + # pull in __syscall_error routine + libpthread-routines += sysdep ++libpthread-shared-only-routines += sysdep + endif + + ifeq ($(subdir),rt) + # pull in __syscall_error routine + librt-routines += sysdep ++librt-shared-only-routines += sysdep + endif +diff --git a/sysdeps/unix/sysv/linux/i386/clone.S b/sysdeps/unix/sysv/linux/i386/clone.S +index 25f2a9c340..feae504ce6 100644 +--- a/sysdeps/unix/sysv/linux/i386/clone.S ++++ b/sysdeps/unix/sysv/linux/i386/clone.S +@@ -107,9 +107,6 @@ L(thread_start): + cfi_undefined (eip); + /* Note: %esi is zero. */ + movl %esi,%ebp /* terminate the stack frame */ +- testl $CLONE_VM, %edi +- je L(newpid) +-L(haspid): + call *%ebx + #ifdef PIC + call L(here) +@@ -121,18 +118,6 @@ L(here): + movl $SYS_ify(exit), %eax + ENTER_KERNEL + +- .subsection 2 +-L(newpid): +- movl $SYS_ify(getpid), %eax +- ENTER_KERNEL +-L(nomoregetpid): +- movl %eax, %gs:PID +- movl %eax, %gs:TID +- jmp L(haspid) +- .previous +- cfi_endproc; +- +- cfi_startproc + PSEUDO_END (__clone) + + libc_hidden_def (__clone) +diff --git a/sysdeps/unix/sysv/linux/i386/vfork.S b/sysdeps/unix/sysv/linux/i386/vfork.S +index 7a1d3373bb..a865de2201 100644 +--- a/sysdeps/unix/sysv/linux/i386/vfork.S ++++ b/sysdeps/unix/sysv/linux/i386/vfork.S +@@ -34,17 +34,6 @@ ENTRY (__vfork) + cfi_adjust_cfa_offset (-4) + cfi_register (%eip, %ecx) + +- /* Save the TCB-cached PID away in %edx, and then negate the TCB +- field. But if it's zero, set it to 0x80000000 instead. See +- raise.c for the logic that relies on this value. */ +- movl %gs:PID, %edx +- movl %edx, %eax +- negl %eax +- jne 1f +- movl $0x80000000, %eax +-1: movl %eax, %gs:PID +- +- + /* Stuff the syscall number in EAX and enter into the kernel. */ + movl $SYS_ify (vfork), %eax + int $0x80 +@@ -55,14 +44,6 @@ ENTRY (__vfork) + pushl %ecx + cfi_adjust_cfa_offset (4) + +- /* Restore the original value of the TCB cache of the PID, if we're +- the parent. But in the child (syscall return value equals zero), +- leave things as they are. */ +- testl %eax, %eax +- je 1f +- movl %edx, %gs:PID +-1: +- + cmpl $-4095, %eax + /* Branch forward if it failed. */ + jae SYSCALL_ERROR_LABEL +diff --git a/sysdeps/unix/sysv/linux/ia64/Makefile b/sysdeps/unix/sysv/linux/ia64/Makefile +index 1de62c528a..4d6766db5e 100644 +--- a/sysdeps/unix/sysv/linux/ia64/Makefile ++++ b/sysdeps/unix/sysv/linux/ia64/Makefile +@@ -19,6 +19,7 @@ endif + + ifeq ($(subdir),rt) + librt-routines += rt-sysdep ++librt-shared-only-routines += rt-sysdep + endif + + ifeq ($(subdir),nptl) +diff --git a/sysdeps/unix/sysv/linux/ia64/clone2.S b/sysdeps/unix/sysv/linux/ia64/clone2.S +index b4cfdfc959..e637b6d4a5 100644 +--- a/sysdeps/unix/sysv/linux/ia64/clone2.S ++++ b/sysdeps/unix/sysv/linux/ia64/clone2.S +@@ -67,19 +67,7 @@ ENTRY(__clone2) + (CHILD) mov loc0=gp + (PARENT) ret + ;; +- tbit.nz p6,p0=in3,8 /* CLONE_VM */ +-(p6) br.cond.dptk 1f +- ;; +- mov r15=SYS_ify (getpid) +-(p7) break __BREAK_SYSCALL +- ;; +- add r9=PID,r13 +- add r10=TID,r13 +- ;; +- st4 [r9]=r8 +- st4 [r10]=r8 +- ;; +-1: ld8 out1=[in0],8 /* Retrieve code pointer. */ ++ ld8 out1=[in0],8 /* Retrieve code pointer. */ + mov out0=in4 /* Pass proper argument to fn */ + ;; + ld8 gp=[in0] /* Load function gp. */ +diff --git a/sysdeps/unix/sysv/linux/ia64/vfork.S b/sysdeps/unix/sysv/linux/ia64/vfork.S +index 9154d7c0fd..84bfdd5d8a 100644 +--- a/sysdeps/unix/sysv/linux/ia64/vfork.S ++++ b/sysdeps/unix/sysv/linux/ia64/vfork.S +@@ -33,32 +33,12 @@ ENTRY (__libc_vfork) + .prologue // work around a GAS bug which triggers if + .body // first .prologue is not at the beginning of proc. + alloc r2=ar.pfs,0,0,2,0 +- adds r14=PID,r13 +- ;; +- ld4 r16=[r14] +- ;; +- sub r15=0,r16 +- cmp.eq p6,p0=0,r16 +- ;; +-(p6) movl r15=0x80000000 + mov out0=CLONE_VM+CLONE_VFORK+SIGCHLD + mov out1=0 /* Standard sp value. */ + ;; +- st4 [r14]=r15 + DO_CALL (SYS_ify (clone)) + cmp.eq p6,p0=0,r8 +- adds r14=PID,r13 + (p6) br.cond.dptk 1f +- ;; +- ld4 r15=[r14] +- ;; +- extr.u r16=r15,0,31 +- ;; +- cmp.eq p0,p6=0,r16 +- ;; +-(p6) sub r16=0,r15 +- ;; +- st4 [r14]=r16 + 1: + cmp.eq p6,p0=-1,r10 + (p6) br.cond.spnt.few __syscall_error +diff --git a/sysdeps/unix/sysv/linux/m68k/clone.S b/sysdeps/unix/sysv/linux/m68k/clone.S +index 3a828443dc..630a29209d 100644 +--- a/sysdeps/unix/sysv/linux/m68k/clone.S ++++ b/sysdeps/unix/sysv/linux/m68k/clone.S +@@ -98,19 +98,6 @@ ENTRY (__clone) + cfi_startproc + cfi_undefined (pc) /* Mark end of stack */ + subl %fp, %fp /* terminate the stack frame */ +- /* Check and see if we need to reset the PID. */ +- andl #CLONE_VM, %d1 +- jne 1f +- movel #SYS_ify (getpid), %d0 +- trap #0 +- movel %a0, -(%sp) +- movel %d0, -(%sp) +- bsrl __m68k_read_tp@PLTPC +- movel (%sp)+, %d0 +- movel %d0, PID_OFFSET(%a0) +- movel %d0, TID_OFFSET(%a0) +- movel (%sp)+, %a0 +-1: + jsr (%a0) + movel %d0, %d1 + movel #SYS_ify (exit), %d0 +diff --git a/sysdeps/unix/sysv/linux/m68k/vfork.S b/sysdeps/unix/sysv/linux/m68k/vfork.S +index 1625a7b7a0..e27479361b 100644 +--- a/sysdeps/unix/sysv/linux/m68k/vfork.S ++++ b/sysdeps/unix/sysv/linux/m68k/vfork.S +@@ -28,18 +28,6 @@ + + ENTRY (__vfork) + +- /* Save the TCB-cached PID away in %d1, and then negate the TCB +- field. But if it's zero, set it to 0x80000000 instead. See +- raise.c for the logic that relies on this value. */ +- jbsr __m68k_read_tp@PLTPC +- movel %a0, %a1 +- movel PID_OFFSET(%a1), %d0 +- movel %d0, %d1 +- negl %d0 +- jne 1f +- movel #0x80000000, %d0 +-1: movel %d0, PID_OFFSET(%a1) +- + /* Pop the return PC value into A0. */ + movel %sp@+, %a0 + cfi_adjust_cfa_offset (-4) +@@ -49,14 +37,6 @@ ENTRY (__vfork) + movel #SYS_ify (vfork), %d0 + trap #0 + +- /* Restore the original value of the TCB cache of the PID, if we're +- the parent. But in the child (syscall return value equals zero), +- leave things as they are. */ +- tstl %d0 +- jeq 1f +- movel %d1, PID_OFFSET(%a1) +-1: +- + tstl %d0 + jmi .Lerror /* Branch forward if it failed. */ + +diff --git a/sysdeps/unix/sysv/linux/microblaze/Makefile b/sysdeps/unix/sysv/linux/microblaze/Makefile +index 44a838fa11..d178bc6f34 100644 +--- a/sysdeps/unix/sysv/linux/microblaze/Makefile ++++ b/sysdeps/unix/sysv/linux/microblaze/Makefile +@@ -5,4 +5,5 @@ endif + ifeq ($(subdir),nptl) + # pull in __syscall_error routine + libpthread-routines += sysdep +-endif +\ No newline at end of file ++libpthread-shared-only-routines += sysdep ++endif +diff --git a/sysdeps/unix/sysv/linux/mips/clone.S b/sysdeps/unix/sysv/linux/mips/clone.S +index 39634c5cf0..7ae65ef723 100644 +--- a/sysdeps/unix/sysv/linux/mips/clone.S ++++ b/sysdeps/unix/sysv/linux/mips/clone.S +@@ -130,11 +130,6 @@ L(thread_start): + SAVE_GP (GPOFF) + /* The stackframe has been created on entry of clone(). */ + +- /* Check and see if we need to reset the PID. */ +- and a1,a0,CLONE_VM +- beqz a1,L(restore_pid) +-L(donepid): +- + /* Restore the arg for user's function. */ + PTR_L t9,0(sp) /* Function pointer. */ + PTR_L a0,PTRSIZE(sp) /* Argument pointer. */ +@@ -151,14 +146,6 @@ L(donepid): + jal _exit + #endif + +-L(restore_pid): +- li v0,__NR_getpid +- syscall +- READ_THREAD_POINTER(v1) +- INT_S v0,PID_OFFSET(v1) +- INT_S v0,TID_OFFSET(v1) +- b L(donepid) +- + END(__thread_start) + + libc_hidden_def (__clone) +diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/syscalls.list b/sysdeps/unix/sysv/linux/mips/mips64/n64/syscalls.list +index 890a74494a..26ab6d0b75 100644 +--- a/sysdeps/unix/sysv/linux/mips/mips64/n64/syscalls.list ++++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/syscalls.list +@@ -4,6 +4,8 @@ mmap - mmap b:aniiii __mmap mmap __mmap64 mmap64 + + sync_file_range - sync_file_range Ci:iiii sync_file_range + ++readahead - readahead i:iii __readahead readahead ++ + prlimit EXTRA prlimit64 i:iipp prlimit prlimit64 + + fanotify_mark EXTRA fanotify_mark i:iiiis fanotify_mark +diff --git a/sysdeps/unix/sysv/linux/mips/vfork.S b/sysdeps/unix/sysv/linux/mips/vfork.S +index 1867c8626e..0b9244b7f8 100644 +--- a/sysdeps/unix/sysv/linux/mips/vfork.S ++++ b/sysdeps/unix/sysv/linux/mips/vfork.S +@@ -60,14 +60,6 @@ NESTED(__libc_vfork,FRAMESZ,sp) + PTR_ADDU sp, FRAMESZ + cfi_adjust_cfa_offset (-FRAMESZ) + +- /* Save the PID value. */ +- READ_THREAD_POINTER(v1) /* Get the thread pointer. */ +- lw a2, PID_OFFSET(v1) /* Load the saved PID. */ +- subu a2, $0, a2 /* Negate it. */ +- bnez a2, 1f /* If it was zero... */ +- lui a2, 0x8000 /* use 0x80000000 instead. */ +-1: sw a2, PID_OFFSET(v1) /* Store the temporary PID. */ +- + li a0, 0x4112 /* CLONE_VM | CLONE_VFORK | SIGCHLD */ + move a1, sp + +@@ -75,17 +67,6 @@ NESTED(__libc_vfork,FRAMESZ,sp) + li v0,__NR_clone + syscall + +- /* Restore the old PID value in the parent. */ +- beqz v0, 1f /* If we are the parent... */ +- READ_THREAD_POINTER(v1) /* Get the thread pointer. */ +- lw a2, PID_OFFSET(v1) /* Load the saved PID. */ +- subu a2, $0, a2 /* Re-negate it. */ +- lui a0, 0x8000 /* Load 0x80000000... */ +- bne a2, a0, 2f /* ... compare against it... */ +- li a2, 0 /* ... use 0 instead. */ +-2: sw a2, PID_OFFSET(v1) /* Restore the PID. */ +-1: +- + cfi_remember_state + bnez a3,L(error) + +diff --git a/sysdeps/unix/sysv/linux/nios2/clone.S b/sysdeps/unix/sysv/linux/nios2/clone.S +index 30b6e4a6c8..c9fa00f94c 100644 +--- a/sysdeps/unix/sysv/linux/nios2/clone.S ++++ b/sysdeps/unix/sysv/linux/nios2/clone.S +@@ -68,14 +68,6 @@ thread_start: + cfi_startproc + cfi_undefined (ra) + +- /* We expect the argument registers to be preserved across system +- calls and across task cloning, so flags should be in r4 here. */ +- andi r2, r4, CLONE_VM +- bne r2, zero, 2f +- DO_CALL (getpid, 0) +- stw r2, PID_OFFSET(r23) +- stw r2, TID_OFFSET(r23) +-2: + ldw r5, 4(sp) /* Function pointer. */ + ldw r4, 0(sp) /* Argument pointer. */ + addi sp, sp, 8 +diff --git a/sysdeps/unix/sysv/linux/nios2/vfork.S b/sysdeps/unix/sysv/linux/nios2/vfork.S +index c1bb9c7134..8997269199 100644 +--- a/sysdeps/unix/sysv/linux/nios2/vfork.S ++++ b/sysdeps/unix/sysv/linux/nios2/vfork.S +@@ -21,20 +21,10 @@ + + ENTRY(__vfork) + +- ldw r6, PID_OFFSET(r23) +- sub r7, zero, r6 +- bne r7, zero, 2f +- movhi r7, %hi(0x80000000) +-2: +- stw r7, PID_OFFSET(r23) +- + movi r4, 0x4111 /* (CLONE_VM | CLONE_VFORK | SIGCHLD) */ + mov r5, zero + DO_CALL (clone, 2) + +- beq r2, zero, 1f +- stw r6, PID_OFFSET(r23) +-1: + bne r7, zero, SYSCALL_ERROR_LABEL + ret + +diff --git a/sysdeps/unix/sysv/linux/powerpc/Makefile b/sysdeps/unix/sysv/linux/powerpc/Makefile +index c89ed9ec7d..2cfb46eca3 100644 +--- a/sysdeps/unix/sysv/linux/powerpc/Makefile ++++ b/sysdeps/unix/sysv/linux/powerpc/Makefile +@@ -8,6 +8,7 @@ abi-64-v2-condition := __WORDSIZE == 64 && _CALL_ELF == 2 + + ifeq ($(subdir),rt) + librt-routines += rt-sysdep ++librt-shared-only-routines += rt-sysdep + endif + + ifeq ($(subdir),stdlib) +@@ -34,4 +35,5 @@ ifeq ($(subdir),nptl) + libpthread-routines += sysdep + libpthread-sysdep_routines += elision-lock elision-unlock elision-timed \ + elision-trylock ++libpthread-shared-only-routines += sysdep + endif +diff --git a/sysdeps/unix/sysv/linux/powerpc/elision-lock.c b/sysdeps/unix/sysv/linux/powerpc/elision-lock.c +index dd1e4c3b17..7dd3d835b6 100644 +--- a/sysdeps/unix/sysv/linux/powerpc/elision-lock.c ++++ b/sysdeps/unix/sysv/linux/powerpc/elision-lock.c +@@ -45,7 +45,9 @@ + int + __lll_lock_elision (int *lock, short *adapt_count, EXTRAARG int pshared) + { +- if (*adapt_count > 0) ++ /* adapt_count is accessed concurrently but is just a hint. Thus, ++ use atomic accesses but relaxed MO is sufficient. */ ++ if (atomic_load_relaxed (adapt_count) > 0) + { + goto use_lock; + } +@@ -67,7 +69,8 @@ __lll_lock_elision (int *lock, short *adapt_count, EXTRAARG int pshared) + if (_TEXASRU_FAILURE_PERSISTENT (__builtin_get_texasru ())) + { + if (aconf.skip_lock_internal_abort > 0) +- *adapt_count = aconf.skip_lock_internal_abort; ++ atomic_store_relaxed (adapt_count, ++ aconf.skip_lock_internal_abort); + goto use_lock; + } + } +@@ -75,7 +78,8 @@ __lll_lock_elision (int *lock, short *adapt_count, EXTRAARG int pshared) + + /* Fall back to locks for a bit if retries have been exhausted */ + if (aconf.try_tbegin > 0 && aconf.skip_lock_out_of_tbegin_retries > 0) +- *adapt_count = aconf.skip_lock_out_of_tbegin_retries; ++ atomic_store_relaxed (adapt_count, ++ aconf.skip_lock_out_of_tbegin_retries); + + use_lock: + return LLL_LOCK ((*lock), pshared); +diff --git a/sysdeps/unix/sysv/linux/powerpc/elision-trylock.c b/sysdeps/unix/sysv/linux/powerpc/elision-trylock.c +index 0807a6a432..606185670d 100644 +--- a/sysdeps/unix/sysv/linux/powerpc/elision-trylock.c ++++ b/sysdeps/unix/sysv/linux/powerpc/elision-trylock.c +@@ -34,7 +34,7 @@ __lll_trylock_elision (int *futex, short *adapt_count) + __libc_tabort (_ABORT_NESTED_TRYLOCK); + + /* Only try a transaction if it's worth it. */ +- if (*adapt_count > 0) ++ if (atomic_load_relaxed (adapt_count) > 0) + { + goto use_lock; + } +@@ -49,7 +49,7 @@ __lll_trylock_elision (int *futex, short *adapt_count) + __libc_tend (0); + + if (aconf.skip_lock_busy > 0) +- *adapt_count = aconf.skip_lock_busy; ++ atomic_store_relaxed (adapt_count, aconf.skip_lock_busy); + } + else + { +@@ -59,7 +59,8 @@ __lll_trylock_elision (int *futex, short *adapt_count) + result in another failure. Use normal locking now and + for the next couple of calls. */ + if (aconf.skip_trylock_internal_abort > 0) +- *adapt_count = aconf.skip_trylock_internal_abort; ++ atomic_store_relaxed (adapt_count, ++ aconf.skip_trylock_internal_abort); + } + } + +diff --git a/sysdeps/unix/sysv/linux/powerpc/elision-unlock.c b/sysdeps/unix/sysv/linux/powerpc/elision-unlock.c +index 43c5a67df2..51d7018e4c 100644 +--- a/sysdeps/unix/sysv/linux/powerpc/elision-unlock.c ++++ b/sysdeps/unix/sysv/linux/powerpc/elision-unlock.c +@@ -28,13 +28,16 @@ __lll_unlock_elision (int *lock, short *adapt_count, int pshared) + __libc_tend (0); + else + { +- lll_unlock ((*lock), pshared); ++ /* Update adapt_count in the critical section to prevent a ++ write-after-destroy error as mentioned in BZ 20822. The ++ following update of adapt_count has to be contained within ++ the critical region of the fall-back lock in order to not violate ++ the mutex destruction requirements. */ ++ short __tmp = atomic_load_relaxed (adapt_count); ++ if (__tmp > 0) ++ atomic_store_relaxed (adapt_count, __tmp - 1); + +- /* Update the adapt count AFTER completing the critical section. +- Doing this here prevents unneeded stalling when entering +- a critical section. Saving about 8% runtime on P8. */ +- if (*adapt_count > 0) +- (*adapt_count)--; ++ lll_unlock ((*lock), pshared); + } + return 0; + } +diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/clone.S b/sysdeps/unix/sysv/linux/powerpc/powerpc32/clone.S +index bebadbfbb9..49fe01ecde 100644 +--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/clone.S ++++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/clone.S +@@ -76,15 +76,6 @@ ENTRY (__clone) + crandc cr1*4+eq,cr1*4+eq,cr0*4+so + bne- cr1,L(parent) /* The '-' is to minimise the race. */ + +- /* If CLONE_VM is set do not update the pid/tid field. */ +- andi. r0,r28,CLONE_VM +- bne+ cr0,L(oldpid) +- +- DO_CALL(SYS_ify(getpid)) +- stw r3,TID(r2) +- stw r3,PID(r2) +-L(oldpid): +- + /* Call procedure. */ + mtctr r30 + mr r3,r31 +diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/vfork.S b/sysdeps/unix/sysv/linux/powerpc/powerpc32/vfork.S +index edbc7de1e6..0a724953a4 100644 +--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/vfork.S ++++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/vfork.S +@@ -27,34 +27,8 @@ + + ENTRY (__vfork) + +- /* Load the TCB-cached PID value and negates it. If It it is zero +- sets it to 0x800000. And then sets its value again on TCB field. +- See raise.c for the logic that relies on this value. */ +- +- lwz r0,PID(r2) +- cmpwi cr0,r0,0 +- neg r0,r0 +- bne- cr0,1f +- lis r0,0x8000 +-1: stw r0,PID(r2) +- + DO_CALL (SYS_ify (vfork)) + +- cmpwi cr1,r3,0 +- beqlr- 1 +- +- /* Restore the original value of the TCB cache of the PID, if we're +- the parent. But in the child (syscall return value equals zero), +- leave things as they are. */ +- lwz r0,PID(r2) +- /* Cannot use clrlwi. here, because cr0 needs to be preserved +- until PSEUDO_RET. */ +- clrlwi r4,r0,1 +- cmpwi cr1,r4,0 +- beq- cr1,1f +- neg r4,r0 +-1: stw r4,PID(r2) +- + PSEUDO_RET + + PSEUDO_END (__vfork) +diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/clone.S b/sysdeps/unix/sysv/linux/powerpc/powerpc64/clone.S +index 7c59b9b4e9..d8604f6731 100644 +--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/clone.S ++++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/clone.S +@@ -78,15 +78,6 @@ ENTRY (__clone) + crandc cr1*4+eq,cr1*4+eq,cr0*4+so + bne- cr1,L(parent) /* The '-' is to minimise the race. */ + +- /* If CLONE_VM is set do not update the pid/tid field. */ +- rldicl. r0,r29,56,63 /* flags & CLONE_VM. */ +- bne+ cr0,L(oldpid) +- +- DO_CALL(SYS_ify(getpid)) +- stw r3,TID(r13) +- stw r3,PID(r13) +-L(oldpid): +- + std r2,FRAME_TOC_SAVE(r1) + /* Call procedure. */ + PPC64_LOAD_FUNCPTR r30 +diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/vfork.S b/sysdeps/unix/sysv/linux/powerpc/powerpc64/vfork.S +index 3083ab7b3c..6b4cf432c1 100644 +--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/vfork.S ++++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/vfork.S +@@ -28,31 +28,8 @@ + ENTRY (__vfork) + CALL_MCOUNT 0 + +- /* Load the TCB-cached PID value and negates it. If It it is zero +- sets it to 0x800000. And then sets its value again on TCB field. +- See raise.c for the logic that relies on this value. */ +- lwz r0,PID(r13) +- cmpwi cr0,r0,0 +- neg r0,r0 +- bne- cr0,1f +- lis r0,0x8000 +-1: stw r0,PID(r13) +- + DO_CALL (SYS_ify (vfork)) + +- cmpwi cr1,r3,0 +- beqlr- 1 +- +- /* Restore the original value of the TCB cache of the PID, if we're +- the parent. But in the child (syscall return value equals zero), +- leave things as they are. */ +- lwz r0,PID(r13) +- clrlwi r4,r0,1 +- cmpwi cr1,r4,0 +- beq- cr1,1f +- neg r4,r0 +-1: stw r4,PID(r13) +- + PSEUDO_RET + + PSEUDO_END (__vfork) +diff --git a/sysdeps/unix/sysv/linux/pread.c b/sysdeps/unix/sysv/linux/pread.c +index 1bcff64781..46d974d952 100644 +--- a/sysdeps/unix/sysv/linux/pread.c ++++ b/sysdeps/unix/sysv/linux/pread.c +@@ -28,8 +28,7 @@ + ssize_t + __libc_pread (int fd, void *buf, size_t count, off_t offset) + { +- return SYSCALL_CANCEL (pread, fd, buf, count, +- __ALIGNMENT_ARG SYSCALL_LL (offset)); ++ return SYSCALL_CANCEL (pread, fd, buf, count, SYSCALL_LL_PRW (offset)); + } + + strong_alias (__libc_pread, __pread) +diff --git a/sysdeps/unix/sysv/linux/pread64.c b/sysdeps/unix/sysv/linux/pread64.c +index 58c6aeb541..f51beae77a 100644 +--- a/sysdeps/unix/sysv/linux/pread64.c ++++ b/sysdeps/unix/sysv/linux/pread64.c +@@ -26,8 +26,7 @@ + ssize_t + __libc_pread64 (int fd, void *buf, size_t count, off64_t offset) + { +- return SYSCALL_CANCEL (pread64, fd, buf, count, +- __ALIGNMENT_ARG SYSCALL_LL64 (offset)); ++ return SYSCALL_CANCEL (pread64, fd, buf, count, SYSCALL_LL64_PRW (offset)); + } + + weak_alias (__libc_pread64, __pread64) +diff --git a/sysdeps/unix/sysv/linux/pthread-pids.h b/sysdeps/unix/sysv/linux/pthread-pids.h +index d42bba03cf..618a5b1b9f 100644 +--- a/sysdeps/unix/sysv/linux/pthread-pids.h ++++ b/sysdeps/unix/sysv/linux/pthread-pids.h +@@ -26,5 +26,5 @@ static inline void + __pthread_initialize_pids (struct pthread *pd) + { + INTERNAL_SYSCALL_DECL (err); +- pd->pid = pd->tid = INTERNAL_SYSCALL (set_tid_address, err, 1, &pd->tid); ++ pd->tid = INTERNAL_SYSCALL_CALL (set_tid_address, err, &pd->tid); + } +diff --git a/sysdeps/unix/sysv/linux/pthread_kill.c b/sysdeps/unix/sysv/linux/pthread_kill.c +index bcb3009675..cc109973cc 100644 +--- a/sysdeps/unix/sysv/linux/pthread_kill.c ++++ b/sysdeps/unix/sysv/linux/pthread_kill.c +@@ -21,6 +21,7 @@ + #include <pthreadP.h> + #include <tls.h> + #include <sysdep.h> ++#include <unistd.h> + + + int +@@ -49,15 +50,9 @@ __pthread_kill (pthread_t threadid, int signo) + /* We have a special syscall to do the work. */ + INTERNAL_SYSCALL_DECL (err); + +- /* One comment: The PID field in the TCB can temporarily be changed +- (in fork). But this must not affect this code here. Since this +- function would have to be called while the thread is executing +- fork, it would have to happen in a signal handler. But this is +- no allowed, pthread_kill is not guaranteed to be async-safe. */ +- int val; +- val = INTERNAL_SYSCALL (tgkill, err, 3, THREAD_GETMEM (THREAD_SELF, pid), +- tid, signo); ++ pid_t pid = __getpid (); + ++ int val = INTERNAL_SYSCALL_CALL (tgkill, err, pid, tid, signo); + return (INTERNAL_SYSCALL_ERROR_P (val, err) + ? INTERNAL_SYSCALL_ERRNO (val, err) : 0); + } +diff --git a/sysdeps/unix/sysv/linux/pthread_sigqueue.c b/sysdeps/unix/sysv/linux/pthread_sigqueue.c +index 7694d5467c..e393e0bd73 100644 +--- a/sysdeps/unix/sysv/linux/pthread_sigqueue.c ++++ b/sysdeps/unix/sysv/linux/pthread_sigqueue.c +@@ -49,27 +49,22 @@ pthread_sigqueue (pthread_t threadid, int signo, const union sigval value) + if (signo == SIGCANCEL || signo == SIGTIMER || signo == SIGSETXID) + return EINVAL; + ++ pid_t pid = getpid (); ++ + /* Set up the siginfo_t structure. */ + siginfo_t info; + memset (&info, '\0', sizeof (siginfo_t)); + info.si_signo = signo; + info.si_code = SI_QUEUE; +- info.si_pid = THREAD_GETMEM (THREAD_SELF, pid); ++ info.si_pid = pid; + info.si_uid = getuid (); + info.si_value = value; + + /* We have a special syscall to do the work. */ + INTERNAL_SYSCALL_DECL (err); + +- /* One comment: The PID field in the TCB can temporarily be changed +- (in fork). But this must not affect this code here. Since this +- function would have to be called while the thread is executing +- fork, it would have to happen in a signal handler. But this is +- no allowed, pthread_sigqueue is not guaranteed to be async-safe. */ +- int val = INTERNAL_SYSCALL (rt_tgsigqueueinfo, err, 4, +- THREAD_GETMEM (THREAD_SELF, pid), +- tid, signo, &info); +- ++ int val = INTERNAL_SYSCALL_CALL (rt_tgsigqueueinfo, err, pid, tid, signo, ++ &info); + return (INTERNAL_SYSCALL_ERROR_P (val, err) + ? INTERNAL_SYSCALL_ERRNO (val, err) : 0); + #else +diff --git a/sysdeps/unix/sysv/linux/pwrite.c b/sysdeps/unix/sysv/linux/pwrite.c +index 9c502beac1..1371df8a60 100644 +--- a/sysdeps/unix/sysv/linux/pwrite.c ++++ b/sysdeps/unix/sysv/linux/pwrite.c +@@ -28,8 +28,7 @@ + ssize_t + __libc_pwrite (int fd, const void *buf, size_t count, off_t offset) + { +- return SYSCALL_CANCEL (pwrite, fd, buf, count, +- __ALIGNMENT_ARG SYSCALL_LL (offset)); ++ return SYSCALL_CANCEL (pwrite, fd, buf, count, SYSCALL_LL_PRW (offset)); + } + + strong_alias (__libc_pwrite, __pwrite) +diff --git a/sysdeps/unix/sysv/linux/pwrite64.c b/sysdeps/unix/sysv/linux/pwrite64.c +index b49e6bc286..22f1f05a44 100644 +--- a/sysdeps/unix/sysv/linux/pwrite64.c ++++ b/sysdeps/unix/sysv/linux/pwrite64.c +@@ -26,8 +26,7 @@ + ssize_t + __libc_pwrite64 (int fd, const void *buf, size_t count, off64_t offset) + { +- return SYSCALL_CANCEL (pwrite64, fd, buf, count, +- __ALIGNMENT_ARG SYSCALL_LL64 (offset)); ++ return SYSCALL_CANCEL (pwrite64, fd, buf, count, SYSCALL_LL64_PRW (offset)); + } + weak_alias (__libc_pwrite64, __pwrite64) + libc_hidden_weak (__pwrite64) +diff --git a/sysdeps/unix/sysv/linux/raise.c b/sysdeps/unix/sysv/linux/raise.c +index 470033e83d..49bb7cb0d4 100644 +--- a/sysdeps/unix/sysv/linux/raise.c ++++ b/sysdeps/unix/sysv/linux/raise.c +@@ -26,13 +26,6 @@ + int + raise (int sig) + { +- /* raise is an async-safe function so it could be called while the +- fork/vfork function temporarily invalidated the PID field. To avoid +- relying on cached value we block all user-defined signal handler +- (which might call fork/vfork) and issue the getpid and gettid +- syscalls directly. */ +- +- + /* rt_sigprocmask may fail if: + + 1. sigsetsize != sizeof (sigset_t) (EINVAL) +diff --git a/sysdeps/unix/sysv/linux/s390/Makefile b/sysdeps/unix/sysv/linux/s390/Makefile +index 497ffd566c..f8ed013e9e 100644 +--- a/sysdeps/unix/sysv/linux/s390/Makefile ++++ b/sysdeps/unix/sysv/linux/s390/Makefile +@@ -6,6 +6,7 @@ abi-64-condition := __WORDSIZE == 64 + + ifeq ($(subdir),rt) + librt-routines += rt-sysdep ++librt-shared-only-routines += rt-sysdep + endif + + ifeq ($(subdir),stdlib) +diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/clone.S b/sysdeps/unix/sysv/linux/s390/s390-32/clone.S +index 2f8fa0b840..b1de1480d1 100644 +--- a/sysdeps/unix/sysv/linux/s390/s390-32/clone.S ++++ b/sysdeps/unix/sysv/linux/s390/s390-32/clone.S +@@ -54,13 +54,6 @@ error: + PSEUDO_END (__clone) + + thread_start: +- tml %r3,256 /* CLONE_VM == 0x00000100 */ +- jne 1f +- svc SYS_ify(getpid) +- ear %r3,%a0 +- st %r2,PID(%r3) +- st %r2,TID(%r3) +-1: + /* fn is in gpr 1, arg in gpr 0 */ + lr %r2,%r0 /* set first parameter to void *arg */ + ahi %r15,-96 /* make room on the stack for the save area */ +diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/vfork.S b/sysdeps/unix/sysv/linux/s390/s390-32/vfork.S +index b7588ebd7c..cc60e139ba 100644 +--- a/sysdeps/unix/sysv/linux/s390/s390-32/vfork.S ++++ b/sysdeps/unix/sysv/linux/s390/s390-32/vfork.S +@@ -28,21 +28,9 @@ + and the process ID of the new process to the old process. */ + + ENTRY (__libc_vfork) +- ear %r4,%a0 +- lhi %r1,1 +- icm %r3,15,PID(%r4) +- sll %r1,31 +- je 1f +- lcr %r1,%r3 +-1: st %r1,PID(%r4) +- + /* Do vfork system call. */ + svc SYS_ify (vfork) + +- ltr %r2,%r2 +- je 1f +- st %r3,PID(%r4) +-1: + /* Check for error. */ + lhi %r4,-4095 + clr %r2,%r4 +diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/clone.S b/sysdeps/unix/sysv/linux/s390/s390-64/clone.S +index fb816922ca..29606acf03 100644 +--- a/sysdeps/unix/sysv/linux/s390/s390-64/clone.S ++++ b/sysdeps/unix/sysv/linux/s390/s390-64/clone.S +@@ -55,15 +55,6 @@ error: + PSEUDO_END (__clone) + + thread_start: +- tmll %r3,256 /* CLONE_VM == 0x00000100 */ +- jne 1f +- svc SYS_ify(getpid) +- ear %r3,%a0 +- sllg %r3,%r3,32 +- ear %r3,%a1 +- st %r2,PID(%r3) +- st %r2,TID(%r3) +-1: + /* fn is in gpr 1, arg in gpr 0 */ + lgr %r2,%r0 /* set first parameter to void *arg */ + aghi %r15,-160 /* make room on the stack for the save area */ +diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/vfork.S b/sysdeps/unix/sysv/linux/s390/s390-64/vfork.S +index 0bd2161381..b9a813f2cc 100644 +--- a/sysdeps/unix/sysv/linux/s390/s390-64/vfork.S ++++ b/sysdeps/unix/sysv/linux/s390/s390-64/vfork.S +@@ -28,22 +28,9 @@ + and the process ID of the new process to the old process. */ + + ENTRY (__libc_vfork) +- ear %r4,%a0 +- sllg %r4,%r4,32 +- ear %r4,%a1 +- icm %r3,15,PID(%r4) +- llilh %r1,32768 +- je 1f +- lcr %r1,%r3 +-1: st %r1,PID(%r4) +- + /* Do vfork system call. */ + svc SYS_ify (vfork) + +- ltgr %r2,%r2 +- je 1f +- st %r3,PID(%r4) +-1: + /* Check for error. */ + lghi %r4,-4095 + clgr %r2,%r4 +diff --git a/sysdeps/unix/sysv/linux/sh/clone.S b/sysdeps/unix/sysv/linux/sh/clone.S +index 4cd7df117c..ce7cddcb19 100644 +--- a/sysdeps/unix/sysv/linux/sh/clone.S ++++ b/sysdeps/unix/sysv/linux/sh/clone.S +@@ -66,23 +66,7 @@ ENTRY(__clone) + 2: + /* terminate the stack frame */ + mov #0, r14 +- mov r4, r0 +- shlr8 r0 +- tst #1, r0 // CLONE_VM = (1 << 8) +- bf/s 4f +- mov r4, r0 +- /* new pid */ +- mov #+SYS_ify(getpid), r3 +- trapa #0x15 +-3: +- stc gbr, r1 +- mov.w .Lpidoff, r2 +- add r1, r2 +- mov.l r0, @r2 +- mov.w .Ltidoff, r2 +- add r1, r2 +- mov.l r0, @r2 +-4: ++ + /* thread starts */ + mov.l @r15, r1 + jsr @r1 +@@ -113,10 +97,6 @@ ENTRY(__clone) + .long _GLOBAL_OFFSET_TABLE_ + .L3: + .long PLTJMP(C_SYMBOL_NAME(_exit)) +-.Lpidoff: +- .word PID - TLS_PRE_TCB_SIZE +-.Ltidoff: +- .word TID - TLS_PRE_TCB_SIZE + PSEUDO_END (__clone) + + libc_hidden_def (__clone) +diff --git a/sysdeps/unix/sysv/linux/sh/kernel-features.h b/sysdeps/unix/sysv/linux/sh/kernel-features.h +index ad05fc39e1..c5240fafbd 100644 +--- a/sysdeps/unix/sysv/linux/sh/kernel-features.h ++++ b/sysdeps/unix/sysv/linux/sh/kernel-features.h +@@ -44,3 +44,8 @@ + + /* SH does not have a 64-bit inode field. */ + #undef __ASSUME_ST_INO_64_BIT ++ ++/* SH4 ABI does not really require argument alignment for 64-bits, but ++ the kernel interface for p{read,write}64 adds a dummy long argument ++ before the offset. */ ++#define __ASSUME_PRW_DUMMY_ARG 1 +diff --git a/sysdeps/unix/sysv/linux/sh/pwrite.c b/sysdeps/unix/sysv/linux/sh/pwrite.c +deleted file mode 100644 +index 391ed5e17b..0000000000 +--- a/sysdeps/unix/sysv/linux/sh/pwrite.c ++++ /dev/null +@@ -1,23 +0,0 @@ +-/* Copyright (C) 1997-2016 Free Software Foundation, Inc. +- This file is part of the GNU C Library. +- Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997. +- +- The GNU C Library is free software; you can redistribute it and/or +- modify it under the terms of the GNU Lesser General Public +- License as published by the Free Software Foundation; either +- version 2.1 of the License, or (at your option) any later version. +- +- The GNU C Library 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 +- Lesser General Public License for more details. +- +- You should have received a copy of the GNU Lesser General Public +- License along with the GNU C Library; if not, see +- <http://www.gnu.org/licenses/>. */ +- +-/* SH4 ABI does not really require argument alignment for 64-bits, but +- the kernel interface for pwrite adds a dummy long argument before the +- offset. */ +-#define __ALIGNMENT_ARG +-#include <sysdeps/unix/sysv/linux/pwrite.c> +diff --git a/sysdeps/unix/sysv/linux/sh/vfork.S b/sysdeps/unix/sysv/linux/sh/vfork.S +index 6895bc5491..df559cb439 100644 +--- a/sysdeps/unix/sysv/linux/sh/vfork.S ++++ b/sysdeps/unix/sysv/linux/sh/vfork.S +@@ -26,30 +26,11 @@ + and the process ID of the new process to the old process. */ + + ENTRY (__libc_vfork) +- /* Save the PID value. */ +- stc gbr, r2 +- mov.w .L2, r0 +- mov.l @(r0,r2), r4 +- neg r4, r1 +- tst r1, r1 +- bf 1f +- mov #1, r1 +- rotr r1 +-1: +- mov.l r1, @(r0,r2) + + mov.w .L1, r3 + trapa #0x10 + mov r0, r1 + +- /* Restore the old PID value in the parent. */ +- tst r0, r0 +- bt.s 2f +- stc gbr, r2 +- mov.w .L2, r0 +- mov.l r4, @(r0,r2) +- mov r1, r0 +-2: + mov #-12, r2 + shad r2, r1 + not r1, r1 // r1=0 means r0 = -1 to -4095 +@@ -61,8 +42,6 @@ ENTRY (__libc_vfork) + nop + .L1: + .word __NR_vfork +-.L2: +- .word PID - TLS_PRE_TCB_SIZE + .align 2 + PSEUDO_END (__libc_vfork) + +diff --git a/sysdeps/unix/sysv/linux/sparc/Makefile b/sysdeps/unix/sysv/linux/sparc/Makefile +index e67aecf8f0..a67d199eb5 100644 +--- a/sysdeps/unix/sysv/linux/sparc/Makefile ++++ b/sysdeps/unix/sysv/linux/sparc/Makefile +@@ -6,6 +6,7 @@ abi-64-condition := __WORDSIZE == 64 + + ifeq ($(subdir),rt) + librt-routines += rt-sysdep ++librt-shared-only-routines += rt-sysdep + endif + + ifeq ($(subdir),sysvipc) +@@ -15,4 +16,5 @@ endif + ifeq ($(subdir),nptl) + # pull in __syscall_error routine + libpthread-routines += sysdep ++libpthread-shared-only-routines += sysdep + endif +diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/clone.S b/sysdeps/unix/sysv/linux/sparc/sparc32/clone.S +index d6c92f6133..0456a0d16e 100644 +--- a/sysdeps/unix/sysv/linux/sparc/sparc32/clone.S ++++ b/sysdeps/unix/sysv/linux/sparc/sparc32/clone.S +@@ -79,13 +79,6 @@ END(__clone) + + .type __thread_start,@function + __thread_start: +- andcc %g4, CLONE_VM, %g0 +- bne 1f +- set __NR_getpid,%g1 +- ta 0x10 +- st %o0,[%g7 + PID] +- st %o0,[%g7 + TID] +-1: + mov %g0, %fp /* terminate backtrace */ + call %g2 + mov %g3,%o0 +diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/vfork.S b/sysdeps/unix/sysv/linux/sparc/sparc32/vfork.S +index 0d0a3b5298..6d985034f0 100644 +--- a/sysdeps/unix/sysv/linux/sparc/sparc32/vfork.S ++++ b/sysdeps/unix/sysv/linux/sparc/sparc32/vfork.S +@@ -22,24 +22,14 @@ + .text + .globl __syscall_error + ENTRY(__libc_vfork) +- ld [%g7 + PID], %o5 +- cmp %o5, 0 +- bne 1f +- sub %g0, %o5, %o4 +- sethi %hi(0x80000000), %o4 +-1: st %o4, [%g7 + PID] +- + LOADSYSCALL(vfork) + ta 0x10 + bcc 2f + mov %o7, %g1 +- st %o5, [%g7 + PID] + call __syscall_error + mov %g1, %o7 + 2: sub %o1, 1, %o1 + andcc %o0, %o1, %o0 +- bne,a 1f +- st %o5, [%g7 + PID] + 1: retl + nop + END(__libc_vfork) +diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/clone.S b/sysdeps/unix/sysv/linux/sparc/sparc64/clone.S +index b0f62660a7..6ffead88e2 100644 +--- a/sysdeps/unix/sysv/linux/sparc/sparc64/clone.S ++++ b/sysdeps/unix/sysv/linux/sparc/sparc64/clone.S +@@ -76,13 +76,6 @@ END(__clone) + + .type __thread_start,@function + __thread_start: +- andcc %g4, CLONE_VM, %g0 +- bne,pt %icc, 1f +- set __NR_getpid,%g1 +- ta 0x6d +- st %o0,[%g7 + PID] +- st %o0,[%g7 + TID] +-1: + mov %g0, %fp /* terminate backtrace */ + call %g2 + mov %g3,%o0 +diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/vfork.S b/sysdeps/unix/sysv/linux/sparc/sparc64/vfork.S +index 0818eba02e..298dd197a9 100644 +--- a/sysdeps/unix/sysv/linux/sparc/sparc64/vfork.S ++++ b/sysdeps/unix/sysv/linux/sparc/sparc64/vfork.S +@@ -22,24 +22,14 @@ + .text + .globl __syscall_error + ENTRY(__libc_vfork) +- ld [%g7 + PID], %o5 +- sethi %hi(0x80000000), %o3 +- cmp %o5, 0 +- sub %g0, %o5, %o4 +- move %icc, %o3, %o4 +- st %o4, [%g7 + PID] +- + LOADSYSCALL(vfork) + ta 0x6d + bcc,pt %xcc, 2f + mov %o7, %g1 +- st %o5, [%g7 + PID] + call __syscall_error + mov %g1, %o7 + 2: sub %o1, 1, %o1 + andcc %o0, %o1, %o0 +- bne,a,pt %icc, 1f +- st %o5, [%g7 + PID] + 1: retl + nop + END(__libc_vfork) +diff --git a/sysdeps/unix/sysv/linux/spawni.c b/sysdeps/unix/sysv/linux/spawni.c +index bb3eecfde1..b5f20a710b 100644 +--- a/sysdeps/unix/sysv/linux/spawni.c ++++ b/sysdeps/unix/sysv/linux/spawni.c +@@ -58,22 +58,19 @@ + normal program exit with the exit code 127. */ + #define SPAWN_ERROR 127 + +-/* We need to block both SIGCANCEL and SIGSETXID. */ +-#define SIGALL_SET \ +- ((__sigset_t) { .__val = {[0 ... _SIGSET_NWORDS-1 ] = -1 } }) +- + #ifdef __ia64__ +-# define CLONE(__fn, __stack, __stacksize, __flags, __args) \ +- __clone2 (__fn, __stack, __stacksize, __flags, __args, 0, 0, 0) ++# define CLONE(__fn, __stackbase, __stacksize, __flags, __args) \ ++ __clone2 (__fn, __stackbase, __stacksize, __flags, __args, 0, 0, 0) + #else + # define CLONE(__fn, __stack, __stacksize, __flags, __args) \ + __clone (__fn, __stack, __flags, __args) + #endif + +-#if _STACK_GROWS_DOWN +-# define STACK(__stack, __stack_size) (__stack + __stack_size) +-#elif _STACK_GROWS_UP ++/* Since ia64 wants the stackbase w/clone2, re-use the grows-up macro. */ ++#if _STACK_GROWS_UP || defined (__ia64__) + # define STACK(__stack, __stack_size) (__stack) ++#elif _STACK_GROWS_DOWN ++# define STACK(__stack, __stack_size) (__stack + __stack_size) + #endif + + +@@ -329,6 +326,11 @@ __spawnix (pid_t * pid, const char *file, + + /* Add a slack area for child's stack. */ + size_t argv_size = (argc * sizeof (void *)) + 512; ++ /* We need at least a few pages in case the compiler's stack checking is ++ enabled. In some configs, it is known to use at least 24KiB. We use ++ 32KiB to be "safe" from anything the compiler might do. Besides, the ++ extra pages won't actually be allocated unless they get used. */ ++ argv_size += (32 * 1024); + size_t stack_size = ALIGN_UP (argv_size, GLRO(dl_pagesize)); + void *stack = __mmap (NULL, stack_size, prot, + MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0); +@@ -340,7 +342,9 @@ __spawnix (pid_t * pid, const char *file, + } + + /* Disable asynchronous cancellation. */ +- int cs = LIBC_CANCEL_ASYNC (); ++ int state; ++ __libc_ptf_call (__pthread_setcancelstate, ++ (PTHREAD_CANCEL_DISABLE, &state), 0); + + args.file = file; + args.exec = exec; +@@ -351,7 +355,7 @@ __spawnix (pid_t * pid, const char *file, + args.envp = envp; + args.xflags = xflags; + +- __sigprocmask (SIG_BLOCK, &SIGALL_SET, &args.oldmask); ++ __libc_signal_block_all (&args.oldmask); + + /* The clone flags used will create a new child that will run in the same + memory space (CLONE_VM) and the execution of calling thread will be +@@ -384,9 +388,9 @@ __spawnix (pid_t * pid, const char *file, + if ((ec == 0) && (pid != NULL)) + *pid = new_pid; + +- __sigprocmask (SIG_SETMASK, &args.oldmask, 0); ++ __libc_signal_restore_set (&args.oldmask); + +- LIBC_CANCEL_RESET (cs); ++ __libc_ptf_call (__pthread_setcancelstate, (state, NULL), 0); + + return ec; + } +diff --git a/sysdeps/unix/sysv/linux/syscalls.list b/sysdeps/unix/sysv/linux/syscalls.list +index 7ae2541f8f..248641b830 100644 +--- a/sysdeps/unix/sysv/linux/syscalls.list ++++ b/sysdeps/unix/sysv/linux/syscalls.list +@@ -18,6 +18,7 @@ execve - execve i:spp __execve execve + fdatasync - fdatasync Ci:i fdatasync + flock - flock i:ii __flock flock + get_kernel_syms EXTRA get_kernel_syms i:p __compat_get_kernel_syms get_kernel_syms@GLIBC_2.0:GLIBC_2.23 ++getpid - getpid Ei: __getpid getpid + getegid - getegid Ei: __getegid getegid + geteuid - geteuid Ei: __geteuid geteuid + getpgid - getpgid i:i __getpgid getpgid +diff --git a/sysdeps/unix/sysv/linux/sysdep.h b/sysdeps/unix/sysv/linux/sysdep.h +index a469f57121..e3ecd5638e 100644 +--- a/sysdeps/unix/sysv/linux/sysdep.h ++++ b/sysdeps/unix/sysv/linux/sysdep.h +@@ -48,6 +48,16 @@ + __LONG_LONG_PAIR ((long) ((val) >> 32), (long) ((val) & 0xffffffff)) + #endif + ++/* Provide a common macro to pass 64-bit value on pread and pwrite ++ syscalls. */ ++#ifdef __ASSUME_PRW_DUMMY_ARG ++# define SYSCALL_LL_PRW(val) 0, SYSCALL_LL (val) ++# define SYSCALL_LL64_PRW(val) 0, SYSCALL_LL64 (val) ++#else ++# define SYSCALL_LL_PRW(val) __ALIGNMENT_ARG SYSCALL_LL (val) ++# define SYSCALL_LL64_PRW(val) __ALIGNMENT_ARG SYSCALL_LL64 (val) ++#endif ++ + /* Provide a macro to pass the off{64}_t argument on p{readv,writev}{64}. */ + #define LO_HI_LONG(val) \ + (long) (val), \ +diff --git a/sysdeps/unix/sysv/linux/tile/Makefile b/sysdeps/unix/sysv/linux/tile/Makefile +index 1c1cfff280..43acea3633 100644 +--- a/sysdeps/unix/sysv/linux/tile/Makefile ++++ b/sysdeps/unix/sysv/linux/tile/Makefile +@@ -25,4 +25,5 @@ endif + ifeq ($(subdir),nptl) + # pull in __syscall_error routine + libpthread-routines += sysdep ++libpthread-shared-only-routines += sysdep + endif +diff --git a/sysdeps/unix/sysv/linux/tile/clone.S b/sysdeps/unix/sysv/linux/tile/clone.S +index d1d36462e7..3f9e3d56c4 100644 +--- a/sysdeps/unix/sysv/linux/tile/clone.S ++++ b/sysdeps/unix/sysv/linux/tile/clone.S +@@ -163,22 +163,6 @@ ENTRY (__clone) + .Lthread_start: + cfi_def_cfa_offset (FRAME_SIZE) + cfi_undefined (lr) +- /* Check and see if we need to reset the PID, which we do if +- CLONE_VM isn't set, i.e. it's a fork-like clone with a new +- address space. In that case we update the cached values +- from the true system pid (retrieved via __NR_getpid syscall). */ +- moveli r0, CLONE_VM +- and r0, r30, r0 +- BNEZ r0, .Lno_reset_pid /* CLONE_VM is set */ +- moveli TREG_SYSCALL_NR_NAME, __NR_getpid +- swint1 +- ADDLI_PTR r2, tp, PID_OFFSET +- { +- ST4 r2, r0 +- ADDLI_PTR r2, tp, TID_OFFSET +- } +- ST4 r2, r0 +-.Lno_reset_pid: + { + /* Invoke user function with specified argument. */ + move r0, r31 +diff --git a/sysdeps/unix/sysv/linux/tile/vfork.S b/sysdeps/unix/sysv/linux/tile/vfork.S +index d8c5ce3e24..2272777187 100644 +--- a/sysdeps/unix/sysv/linux/tile/vfork.S ++++ b/sysdeps/unix/sysv/linux/tile/vfork.S +@@ -30,18 +30,6 @@ + .text + ENTRY (__vfork) + { +- addli r11, tp, PID_OFFSET /* Point at PID. */ +- movei r13, 1 +- } +- { +- LD4U r12, r11 /* Load the saved PID. */ +- shli r13, r13, 31 /* Build 0x80000000. */ +- } +- sub r12, zero, r12 /* Negate it. */ +- CMOVEQZ r12, r12, r13 /* Replace zero pids. */ +- ST4 r11, r12 /* Store the temporary PID. */ +- +- { + moveli r0, CLONE_VFORK | CLONE_VM | SIGCHLD + move r1, zero + } +@@ -52,22 +40,6 @@ ENTRY (__vfork) + moveli TREG_SYSCALL_NR_NAME, __NR_clone + swint1 + +- BEQZ r0, 1f /* If we are the parent... */ +- { +- addli r11, tp, PID_OFFSET /* Point at PID. */ +- movei r13, 1 +- } +- { +- LD4U r12, r11 /* Load the saved PID. */ +- shli r13, r13, 31 /* Build 0x80000000. */ +- } +- { +- CMPEQ r13, r12, r12 /* Test for that value. */ +- sub r12, zero, r12 /* Re-negate it. */ +- } +- CMOVNEZ r12, r13, zero /* Replace zero pids. */ +- ST4 r11, r12 /* Restore the PID. */ +-1: + BNEZ r1, 0f + jrp lr + PSEUDO_END (__vfork) +diff --git a/sysdeps/unix/sysv/linux/tst-clone2.c b/sysdeps/unix/sysv/linux/tst-clone2.c +index 68a7e6d6e2..1472311947 100644 +--- a/sysdeps/unix/sysv/linux/tst-clone2.c ++++ b/sysdeps/unix/sysv/linux/tst-clone2.c +@@ -28,8 +28,11 @@ + #include <stdlib.h> + #include <sys/types.h> + #include <sys/wait.h> ++#include <sys/syscall.h> + +-#include <tls.h> /* for THREAD_* macros. */ ++#include <stackinfo.h> /* For _STACK_GROWS_{UP,DOWN}. */ ++ ++#include <support/check.h> + + static int sig; + static int pipefd[2]; +@@ -39,39 +42,35 @@ f (void *a) + { + close (pipefd[0]); + +- pid_t pid = THREAD_GETMEM (THREAD_SELF, pid); +- pid_t tid = THREAD_GETMEM (THREAD_SELF, tid); ++ pid_t ppid = getppid (); ++ pid_t pid = getpid (); ++ pid_t tid = syscall (__NR_gettid); + +- while (write (pipefd[1], &pid, sizeof pid) < 0) +- continue; +- while (write (pipefd[1], &tid, sizeof tid) < 0) +- continue; ++ if (write (pipefd[1], &ppid, sizeof ppid) != sizeof (ppid)) ++ FAIL_EXIT1 ("write ppid failed\n"); ++ if (write (pipefd[1], &pid, sizeof pid) != sizeof (pid)) ++ FAIL_EXIT1 ("write pid failed\n"); ++ if (write (pipefd[1], &tid, sizeof tid) != sizeof (tid)) ++ FAIL_EXIT1 ("write tid failed\n"); + + return 0; + } + + + static int +-clone_test (int clone_flags) ++do_test (void) + { + sig = SIGRTMIN; + sigset_t ss; + sigemptyset (&ss); + sigaddset (&ss, sig); + if (sigprocmask (SIG_BLOCK, &ss, NULL) != 0) +- { +- printf ("sigprocmask failed: %m\n"); +- return 1; +- } ++ FAIL_EXIT1 ("sigprocmask failed: %m"); + + if (pipe2 (pipefd, O_CLOEXEC)) +- { +- printf ("sigprocmask failed: %m\n"); +- return 1; +- } +- +- pid_t ppid = getpid (); ++ FAIL_EXIT1 ("pipe failed: %m"); + ++ int clone_flags = 0; + #ifdef __ia64__ + extern int __clone2 (int (*__fn) (void *__arg), void *__child_stack_base, + size_t __child_stack_size, int __flags, +@@ -88,61 +87,47 @@ clone_test (int clone_flags) + #error "Define either _STACK_GROWS_DOWN or _STACK_GROWS_UP" + #endif + #endif ++ + close (pipefd[1]); + + if (p == -1) ++ FAIL_EXIT1("clone failed: %m"); ++ ++ pid_t ppid, pid, tid; ++ if (read (pipefd[0], &ppid, sizeof pid) != sizeof pid) + { +- printf ("clone failed: %m\n"); +- return 1; ++ kill (p, SIGKILL); ++ FAIL_EXIT1 ("read ppid failed: %m"); + } +- +- pid_t pid, tid; + if (read (pipefd[0], &pid, sizeof pid) != sizeof pid) + { +- printf ("read pid failed: %m\n"); + kill (p, SIGKILL); +- return 1; ++ FAIL_EXIT1 ("read pid failed: %m"); + } + if (read (pipefd[0], &tid, sizeof tid) != sizeof tid) + { +- printf ("read pid failed: %m\n"); + kill (p, SIGKILL); +- return 1; ++ FAIL_EXIT1 ("read tid failed: %m"); + } + + close (pipefd[0]); + + int ret = 0; + +- /* For CLONE_VM glibc clone implementation does not change the pthread +- pid/tid field. */ +- if ((clone_flags & CLONE_VM) == CLONE_VM) +- { +- if ((ppid != pid) || (ppid != tid)) +- { +- printf ("parent pid (%i) != received pid/tid (%i/%i)\n", +- (int)ppid, (int)pid, (int)tid); +- ret = 1; +- } +- } +- /* For any other flag clone updates the new pthread pid and tid with +- the clone return value. */ +- else +- { +- if ((p != pid) || (p != tid)) +- { +- printf ("child pid (%i) != received pid/tid (%i/%i)\n", +- (int)p, (int)pid, (int)tid); +- ret = 1; +- } +- } ++ pid_t own_pid = getpid (); ++ pid_t own_tid = syscall (__NR_gettid); ++ ++ /* Some sanity checks for clone syscall: returned ppid should be current ++ pid and both returned tid/pid should be different from current one. */ ++ if ((ppid != own_pid) || (pid == own_pid) || (tid == own_tid)) ++ FAIL_RET ("ppid=%i pid=%i tid=%i | own_pid=%i own_tid=%i", ++ (int)ppid, (int)pid, (int)tid, (int)own_pid, (int)own_tid); + + int e; + if (waitpid (p, &e, __WCLONE) != p) + { +- puts ("waitpid failed"); + kill (p, SIGKILL); +- return 1; ++ FAIL_EXIT1 ("waitpid failed"); + } + if (!WIFEXITED (e)) + { +@@ -150,29 +135,12 @@ clone_test (int clone_flags) + printf ("died from signal %s\n", strsignal (WTERMSIG (e))); + else + puts ("did not terminate correctly"); +- return 1; ++ exit (EXIT_FAILURE); + } + if (WEXITSTATUS (e) != 0) +- { +- printf ("exit code %d\n", WEXITSTATUS (e)); +- return 1; +- } ++ FAIL_EXIT1 ("exit code %d", WEXITSTATUS (e)); + + return ret; + } + +-int +-do_test (void) +-{ +- /* First, check that the clone implementation, without any flag, updates +- the struct pthread to contain the new PID and TID. */ +- int ret = clone_test (0); +- /* Second, check that with CLONE_VM the struct pthread PID and TID fields +- remain unmodified after the clone. Any modifications would cause problem +- for the parent as described in bug 19957. */ +- ret += clone_test (CLONE_VM); +- return ret; +-} +- +-#define TEST_FUNCTION do_test () +-#include "../test-skeleton.c" ++#include <support/test-driver.c> +diff --git a/sysdeps/unix/sysv/linux/x86_64/clone.S b/sysdeps/unix/sysv/linux/x86_64/clone.S +index 66f4b11490..5629aed395 100644 +--- a/sysdeps/unix/sysv/linux/x86_64/clone.S ++++ b/sysdeps/unix/sysv/linux/x86_64/clone.S +@@ -91,14 +91,6 @@ L(thread_start): + the outermost frame obviously. */ + xorl %ebp, %ebp + +- andq $CLONE_VM, %rdi +- jne 1f +- movl $SYS_ify(getpid), %eax +- syscall +- movl %eax, %fs:PID +- movl %eax, %fs:TID +-1: +- + /* Set up arguments for the function call. */ + popq %rax /* Function to call. */ + popq %rdi /* Argument. */ +diff --git a/sysdeps/unix/sysv/linux/x86_64/vfork.S b/sysdeps/unix/sysv/linux/x86_64/vfork.S +index 8332ade9fb..cdd2dea32a 100644 +--- a/sysdeps/unix/sysv/linux/x86_64/vfork.S ++++ b/sysdeps/unix/sysv/linux/x86_64/vfork.S +@@ -34,16 +34,6 @@ ENTRY (__vfork) + cfi_adjust_cfa_offset(-8) + cfi_register(%rip, %rdi) + +- /* Save the TCB-cached PID away in %esi, and then negate the TCB +- field. But if it's zero, set it to 0x80000000 instead. See +- raise.c for the logic that relies on this value. */ +- movl %fs:PID, %esi +- movl $0x80000000, %ecx +- movl %esi, %edx +- negl %edx +- cmove %ecx, %edx +- movl %edx, %fs:PID +- + /* Stuff the syscall number in RAX and enter into the kernel. */ + movl $SYS_ify (vfork), %eax + syscall +@@ -52,14 +42,6 @@ ENTRY (__vfork) + pushq %rdi + cfi_adjust_cfa_offset(8) + +- /* Restore the original value of the TCB cache of the PID, if we're +- the parent. But in the child (syscall return value equals zero), +- leave things as they are. */ +- testq %rax, %rax +- je 1f +- movl %esi, %fs:PID +-1: +- + cmpl $-4095, %eax + jae SYSCALL_ERROR_LABEL /* Branch forward if it failed. */ + +diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c +index 9ce4b495a5..d1ee922290 100644 +--- a/sysdeps/x86/cpu-features.c ++++ b/sysdeps/x86/cpu-features.c +@@ -133,8 +133,6 @@ init_cpu_features (struct cpu_features *cpu_features) + + case 0x57: + /* Knights Landing. Enable Silvermont optimizations. */ +- cpu_features->feature[index_arch_Prefer_No_VZEROUPPER] +- |= bit_arch_Prefer_No_VZEROUPPER; + + case 0x5c: + case 0x5f: +@@ -205,6 +203,30 @@ init_cpu_features (struct cpu_features *cpu_features) + if (CPU_FEATURES_ARCH_P (cpu_features, AVX2_Usable)) + cpu_features->feature[index_arch_AVX_Fast_Unaligned_Load] + |= bit_arch_AVX_Fast_Unaligned_Load; ++ ++ /* Since AVX512ER is unique to Xeon Phi, set Prefer_No_VZEROUPPER ++ if AVX512ER is available. Don't use AVX512 to avoid lower CPU ++ frequency if AVX512ER isn't available. */ ++ if (CPU_FEATURES_CPU_P (cpu_features, AVX512ER)) ++ cpu_features->feature[index_arch_Prefer_No_VZEROUPPER] ++ |= bit_arch_Prefer_No_VZEROUPPER; ++ else ++ cpu_features->feature[index_arch_Prefer_No_AVX512] ++ |= bit_arch_Prefer_No_AVX512; ++ ++ /* To avoid SSE transition penalty, use _dl_runtime_resolve_slow. ++ If XGETBV suports ECX == 1, use _dl_runtime_resolve_opt. */ ++ cpu_features->feature[index_arch_Use_dl_runtime_resolve_slow] ++ |= bit_arch_Use_dl_runtime_resolve_slow; ++ if (cpu_features->max_cpuid >= 0xd) ++ { ++ unsigned int eax; ++ ++ __cpuid_count (0xd, 1, eax, ebx, ecx, edx); ++ if ((eax & (1 << 2)) != 0) ++ cpu_features->feature[index_arch_Use_dl_runtime_resolve_opt] ++ |= bit_arch_Use_dl_runtime_resolve_opt; ++ } + } + /* This spells out "AuthenticAMD". */ + else if (ebx == 0x68747541 && ecx == 0x444d4163 && edx == 0x69746e65) +diff --git a/sysdeps/x86/cpu-features.h b/sysdeps/x86/cpu-features.h +index 97ffe765f4..2609ac0999 100644 +--- a/sysdeps/x86/cpu-features.h ++++ b/sysdeps/x86/cpu-features.h +@@ -37,6 +37,9 @@ + #define bit_arch_Prefer_No_VZEROUPPER (1 << 17) + #define bit_arch_Fast_Unaligned_Copy (1 << 18) + #define bit_arch_Prefer_ERMS (1 << 19) ++#define bit_arch_Use_dl_runtime_resolve_opt (1 << 20) ++#define bit_arch_Use_dl_runtime_resolve_slow (1 << 21) ++#define bit_arch_Prefer_No_AVX512 (1 << 22) + + /* CPUID Feature flags. */ + +@@ -60,6 +63,11 @@ + #define bit_cpu_AVX2 (1 << 5) + #define bit_cpu_AVX512F (1 << 16) + #define bit_cpu_AVX512DQ (1 << 17) ++#define bit_cpu_AVX512PF (1 << 26) ++#define bit_cpu_AVX512ER (1 << 27) ++#define bit_cpu_AVX512CD (1 << 28) ++#define bit_cpu_AVX512BW (1 << 30) ++#define bit_cpu_AVX512VL (1u << 31) + + /* XCR0 Feature flags. */ + #define bit_XMM_state (1 << 1) +@@ -107,6 +115,9 @@ + # define index_arch_Prefer_No_VZEROUPPER FEATURE_INDEX_1*FEATURE_SIZE + # define index_arch_Fast_Unaligned_Copy FEATURE_INDEX_1*FEATURE_SIZE + # define index_arch_Prefer_ERMS FEATURE_INDEX_1*FEATURE_SIZE ++# define index_arch_Use_dl_runtime_resolve_opt FEATURE_INDEX_1*FEATURE_SIZE ++# define index_arch_Use_dl_runtime_resolve_slow FEATURE_INDEX_1*FEATURE_SIZE ++# define index_arch_Prefer_No_AVX512 FEATURE_INDEX_1*FEATURE_SIZE + + + # if defined (_LIBC) && !IS_IN (nonlib) +@@ -232,6 +243,11 @@ extern const struct cpu_features *__get_cpu_features (void) + # define index_cpu_AVX2 COMMON_CPUID_INDEX_7 + # define index_cpu_AVX512F COMMON_CPUID_INDEX_7 + # define index_cpu_AVX512DQ COMMON_CPUID_INDEX_7 ++# define index_cpu_AVX512PF COMMON_CPUID_INDEX_7 ++# define index_cpu_AVX512ER COMMON_CPUID_INDEX_7 ++# define index_cpu_AVX512CD COMMON_CPUID_INDEX_7 ++# define index_cpu_AVX512BW COMMON_CPUID_INDEX_7 ++# define index_cpu_AVX512VL COMMON_CPUID_INDEX_7 + # define index_cpu_ERMS COMMON_CPUID_INDEX_7 + # define index_cpu_RTM COMMON_CPUID_INDEX_7 + # define index_cpu_FMA COMMON_CPUID_INDEX_1 +@@ -250,6 +266,11 @@ extern const struct cpu_features *__get_cpu_features (void) + # define reg_AVX2 ebx + # define reg_AVX512F ebx + # define reg_AVX512DQ ebx ++# define reg_AVX512PF ebx ++# define reg_AVX512ER ebx ++# define reg_AVX512CD ebx ++# define reg_AVX512BW ebx ++# define reg_AVX512VL ebx + # define reg_ERMS ebx + # define reg_RTM ebx + # define reg_FMA ecx +@@ -277,6 +298,9 @@ extern const struct cpu_features *__get_cpu_features (void) + # define index_arch_Prefer_No_VZEROUPPER FEATURE_INDEX_1 + # define index_arch_Fast_Unaligned_Copy FEATURE_INDEX_1 + # define index_arch_Prefer_ERMS FEATURE_INDEX_1 ++# define index_arch_Use_dl_runtime_resolve_opt FEATURE_INDEX_1 ++# define index_arch_Use_dl_runtime_resolve_slow FEATURE_INDEX_1 ++# define index_arch_Prefer_No_AVX512 FEATURE_INDEX_1 + + #endif /* !__ASSEMBLER__ */ + +diff --git a/sysdeps/x86_64/dl-machine.h b/sysdeps/x86_64/dl-machine.h +index ed0c1a8efd..c0f0fa16a2 100644 +--- a/sysdeps/x86_64/dl-machine.h ++++ b/sysdeps/x86_64/dl-machine.h +@@ -68,7 +68,10 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile) + Elf64_Addr *got; + extern void _dl_runtime_resolve_sse (ElfW(Word)) attribute_hidden; + extern void _dl_runtime_resolve_avx (ElfW(Word)) attribute_hidden; ++ extern void _dl_runtime_resolve_avx_slow (ElfW(Word)) attribute_hidden; ++ extern void _dl_runtime_resolve_avx_opt (ElfW(Word)) attribute_hidden; + extern void _dl_runtime_resolve_avx512 (ElfW(Word)) attribute_hidden; ++ extern void _dl_runtime_resolve_avx512_opt (ElfW(Word)) attribute_hidden; + extern void _dl_runtime_profile_sse (ElfW(Word)) attribute_hidden; + extern void _dl_runtime_profile_avx (ElfW(Word)) attribute_hidden; + extern void _dl_runtime_profile_avx512 (ElfW(Word)) attribute_hidden; +@@ -118,9 +121,26 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile) + indicated by the offset on the stack, and then jump to + the resolved address. */ + if (HAS_ARCH_FEATURE (AVX512F_Usable)) +- *(ElfW(Addr) *) (got + 2) = (ElfW(Addr)) &_dl_runtime_resolve_avx512; ++ { ++ if (HAS_ARCH_FEATURE (Use_dl_runtime_resolve_opt)) ++ *(ElfW(Addr) *) (got + 2) ++ = (ElfW(Addr)) &_dl_runtime_resolve_avx512_opt; ++ else ++ *(ElfW(Addr) *) (got + 2) ++ = (ElfW(Addr)) &_dl_runtime_resolve_avx512; ++ } + else if (HAS_ARCH_FEATURE (AVX_Usable)) +- *(ElfW(Addr) *) (got + 2) = (ElfW(Addr)) &_dl_runtime_resolve_avx; ++ { ++ if (HAS_ARCH_FEATURE (Use_dl_runtime_resolve_opt)) ++ *(ElfW(Addr) *) (got + 2) ++ = (ElfW(Addr)) &_dl_runtime_resolve_avx_opt; ++ else if (HAS_ARCH_FEATURE (Use_dl_runtime_resolve_slow)) ++ *(ElfW(Addr) *) (got + 2) ++ = (ElfW(Addr)) &_dl_runtime_resolve_avx_slow; ++ else ++ *(ElfW(Addr) *) (got + 2) ++ = (ElfW(Addr)) &_dl_runtime_resolve_avx; ++ } + else + *(ElfW(Addr) *) (got + 2) = (ElfW(Addr)) &_dl_runtime_resolve_sse; + } +diff --git a/sysdeps/x86_64/dl-trampoline.S b/sysdeps/x86_64/dl-trampoline.S +index 12f1a5cf84..50b23633e3 100644 +--- a/sysdeps/x86_64/dl-trampoline.S ++++ b/sysdeps/x86_64/dl-trampoline.S +@@ -18,6 +18,7 @@ + + #include <config.h> + #include <sysdep.h> ++#include <cpu-features.h> + #include <link-defines.h> + + #ifndef DL_STACK_ALIGNMENT +@@ -104,9 +105,11 @@ + #endif + #define VEC(i) ymm##i + #define _dl_runtime_resolve _dl_runtime_resolve_avx ++#define _dl_runtime_resolve_opt _dl_runtime_resolve_avx_opt + #define _dl_runtime_profile _dl_runtime_profile_avx + #include "dl-trampoline.h" + #undef _dl_runtime_resolve ++#undef _dl_runtime_resolve_opt + #undef _dl_runtime_profile + #undef VEC + #undef VMOV +@@ -126,3 +129,19 @@ + #define _dl_runtime_profile _dl_runtime_profile_sse + #undef RESTORE_AVX + #include "dl-trampoline.h" ++#undef _dl_runtime_resolve ++#undef _dl_runtime_profile ++#undef VMOV ++#undef VMOVA ++ ++/* Used by _dl_runtime_resolve_avx_opt/_dl_runtime_resolve_avx512_opt ++ to preserve the full vector registers with zero upper bits. */ ++#define VMOVA vmovdqa ++#if DL_RUNTIME_RESOLVE_REALIGN_STACK || VEC_SIZE <= DL_STACK_ALIGNMENT ++# define VMOV vmovdqa ++#else ++# define VMOV vmovdqu ++#endif ++#define _dl_runtime_resolve _dl_runtime_resolve_sse_vex ++#define _dl_runtime_resolve_opt _dl_runtime_resolve_avx512_opt ++#include "dl-trampoline.h" +diff --git a/sysdeps/x86_64/dl-trampoline.h b/sysdeps/x86_64/dl-trampoline.h +index b90836ab13..32ad3af202 100644 +--- a/sysdeps/x86_64/dl-trampoline.h ++++ b/sysdeps/x86_64/dl-trampoline.h +@@ -50,6 +50,106 @@ + #endif + + .text ++#ifdef _dl_runtime_resolve_opt ++/* Use the smallest vector registers to preserve the full YMM/ZMM ++ registers to avoid SSE transition penalty. */ ++ ++# if VEC_SIZE == 32 ++/* Check if the upper 128 bits in %ymm0 - %ymm7 registers are non-zero ++ and preserve %xmm0 - %xmm7 registers with the zero upper bits. Since ++ there is no SSE transition penalty on AVX512 processors which don't ++ support XGETBV with ECX == 1, _dl_runtime_resolve_avx512_slow isn't ++ provided. */ ++ .globl _dl_runtime_resolve_avx_slow ++ .hidden _dl_runtime_resolve_avx_slow ++ .type _dl_runtime_resolve_avx_slow, @function ++ .align 16 ++_dl_runtime_resolve_avx_slow: ++ cfi_startproc ++ cfi_adjust_cfa_offset(16) # Incorporate PLT ++ vorpd %ymm0, %ymm1, %ymm8 ++ vorpd %ymm2, %ymm3, %ymm9 ++ vorpd %ymm4, %ymm5, %ymm10 ++ vorpd %ymm6, %ymm7, %ymm11 ++ vorpd %ymm8, %ymm9, %ymm9 ++ vorpd %ymm10, %ymm11, %ymm10 ++ vpcmpeqd %xmm8, %xmm8, %xmm8 ++ vorpd %ymm9, %ymm10, %ymm10 ++ vptest %ymm10, %ymm8 ++ # Preserve %ymm0 - %ymm7 registers if the upper 128 bits of any ++ # %ymm0 - %ymm7 registers aren't zero. ++ PRESERVE_BND_REGS_PREFIX ++ jnc _dl_runtime_resolve_avx ++ # Use vzeroupper to avoid SSE transition penalty. ++ vzeroupper ++ # Preserve %xmm0 - %xmm7 registers with the zero upper 128 bits ++ # when the upper 128 bits of %ymm0 - %ymm7 registers are zero. ++ PRESERVE_BND_REGS_PREFIX ++ jmp _dl_runtime_resolve_sse_vex ++ cfi_adjust_cfa_offset(-16) # Restore PLT adjustment ++ cfi_endproc ++ .size _dl_runtime_resolve_avx_slow, .-_dl_runtime_resolve_avx_slow ++# endif ++ ++/* Use XGETBV with ECX == 1 to check which bits in vector registers are ++ non-zero and only preserve the non-zero lower bits with zero upper ++ bits. */ ++ .globl _dl_runtime_resolve_opt ++ .hidden _dl_runtime_resolve_opt ++ .type _dl_runtime_resolve_opt, @function ++ .align 16 ++_dl_runtime_resolve_opt: ++ cfi_startproc ++ cfi_adjust_cfa_offset(16) # Incorporate PLT ++ pushq %rax ++ cfi_adjust_cfa_offset(8) ++ cfi_rel_offset(%rax, 0) ++ pushq %rcx ++ cfi_adjust_cfa_offset(8) ++ cfi_rel_offset(%rcx, 0) ++ pushq %rdx ++ cfi_adjust_cfa_offset(8) ++ cfi_rel_offset(%rdx, 0) ++ movl $1, %ecx ++ xgetbv ++ movl %eax, %r11d ++ popq %rdx ++ cfi_adjust_cfa_offset(-8) ++ cfi_restore (%rdx) ++ popq %rcx ++ cfi_adjust_cfa_offset(-8) ++ cfi_restore (%rcx) ++ popq %rax ++ cfi_adjust_cfa_offset(-8) ++ cfi_restore (%rax) ++# if VEC_SIZE == 32 ++ # For YMM registers, check if YMM state is in use. ++ andl $bit_YMM_state, %r11d ++ # Preserve %xmm0 - %xmm7 registers with the zero upper 128 bits if ++ # YMM state isn't in use. ++ PRESERVE_BND_REGS_PREFIX ++ jz _dl_runtime_resolve_sse_vex ++# elif VEC_SIZE == 16 ++ # For ZMM registers, check if YMM state and ZMM state are in ++ # use. ++ andl $(bit_YMM_state | bit_ZMM0_15_state), %r11d ++ cmpl $bit_YMM_state, %r11d ++ # Preserve %zmm0 - %zmm7 registers if ZMM state is in use. ++ PRESERVE_BND_REGS_PREFIX ++ jg _dl_runtime_resolve_avx512 ++ # Preserve %ymm0 - %ymm7 registers with the zero upper 256 bits if ++ # ZMM state isn't in use. ++ PRESERVE_BND_REGS_PREFIX ++ je _dl_runtime_resolve_avx ++ # Preserve %xmm0 - %xmm7 registers with the zero upper 384 bits if ++ # neither YMM state nor ZMM state are in use. ++# else ++# error Unsupported VEC_SIZE! ++# endif ++ cfi_adjust_cfa_offset(-16) # Restore PLT adjustment ++ cfi_endproc ++ .size _dl_runtime_resolve_opt, .-_dl_runtime_resolve_opt ++#endif + .globl _dl_runtime_resolve + .hidden _dl_runtime_resolve + .type _dl_runtime_resolve, @function +@@ -162,7 +262,10 @@ _dl_runtime_resolve: + .size _dl_runtime_resolve, .-_dl_runtime_resolve + + +-#ifndef PROF ++/* To preserve %xmm0 - %xmm7 registers, dl-trampoline.h is included ++ twice, for _dl_runtime_resolve_sse and _dl_runtime_resolve_sse_vex. ++ But we don't need another _dl_runtime_profile for XMM registers. */ ++#if !defined PROF && defined _dl_runtime_profile + # if (LR_VECTOR_OFFSET % VEC_SIZE) != 0 + # error LR_VECTOR_OFFSET must be multples of VEC_SIZE + # endif +diff --git a/sysdeps/x86_64/memcpy_chk.S b/sysdeps/x86_64/memcpy_chk.S +index 2296b55119..a95b3ad3cf 100644 +--- a/sysdeps/x86_64/memcpy_chk.S ++++ b/sysdeps/x86_64/memcpy_chk.S +@@ -19,7 +19,7 @@ + #include <sysdep.h> + #include "asm-syntax.h" + +-#ifndef PIC ++#ifndef SHARED + /* For libc.so this is defined in memcpy.S. + For libc.a, this is a separate source to avoid + memcpy bringing in __chk_fail and all routines +diff --git a/sysdeps/x86_64/multiarch/memcpy.S b/sysdeps/x86_64/multiarch/memcpy.S +index b8677596f9..ea4ec70d1a 100644 +--- a/sysdeps/x86_64/multiarch/memcpy.S ++++ b/sysdeps/x86_64/multiarch/memcpy.S +@@ -32,6 +32,8 @@ ENTRY(__new_memcpy) + lea __memcpy_erms(%rip), %RAX_LP + HAS_ARCH_FEATURE (Prefer_ERMS) + jnz 2f ++ HAS_ARCH_FEATURE (Prefer_No_AVX512) ++ jnz 1f + HAS_ARCH_FEATURE (AVX512F_Usable) + jz 1f + lea __memcpy_avx512_no_vzeroupper(%rip), %RAX_LP +diff --git a/sysdeps/x86_64/multiarch/memcpy_chk.S b/sysdeps/x86_64/multiarch/memcpy_chk.S +index 9d92c8a7e3..26b49de6f6 100644 +--- a/sysdeps/x86_64/multiarch/memcpy_chk.S ++++ b/sysdeps/x86_64/multiarch/memcpy_chk.S +@@ -30,6 +30,8 @@ + ENTRY(__memcpy_chk) + .type __memcpy_chk, @gnu_indirect_function + LOAD_RTLD_GLOBAL_RO_RDX ++ HAS_ARCH_FEATURE (Prefer_No_AVX512) ++ jnz 1f + HAS_ARCH_FEATURE (AVX512F_Usable) + jz 1f + lea __memcpy_chk_avx512_no_vzeroupper(%rip), %RAX_LP +diff --git a/sysdeps/x86_64/multiarch/memmove.S b/sysdeps/x86_64/multiarch/memmove.S +index ff5e041420..ef92afde5a 100644 +--- a/sysdeps/x86_64/multiarch/memmove.S ++++ b/sysdeps/x86_64/multiarch/memmove.S +@@ -30,6 +30,8 @@ ENTRY(__libc_memmove) + lea __memmove_erms(%rip), %RAX_LP + HAS_ARCH_FEATURE (Prefer_ERMS) + jnz 2f ++ HAS_ARCH_FEATURE (Prefer_No_AVX512) ++ jnz 1f + HAS_ARCH_FEATURE (AVX512F_Usable) + jz 1f + lea __memmove_avx512_no_vzeroupper(%rip), %RAX_LP +diff --git a/sysdeps/x86_64/multiarch/memmove_chk.S b/sysdeps/x86_64/multiarch/memmove_chk.S +index 7f861206df..a9129c460a 100644 +--- a/sysdeps/x86_64/multiarch/memmove_chk.S ++++ b/sysdeps/x86_64/multiarch/memmove_chk.S +@@ -29,6 +29,8 @@ + ENTRY(__memmove_chk) + .type __memmove_chk, @gnu_indirect_function + LOAD_RTLD_GLOBAL_RO_RDX ++ HAS_ARCH_FEATURE (Prefer_No_AVX512) ++ jnz 1f + HAS_ARCH_FEATURE (AVX512F_Usable) + jz 1f + lea __memmove_chk_avx512_no_vzeroupper(%rip), %RAX_LP +diff --git a/sysdeps/x86_64/multiarch/mempcpy.S b/sysdeps/x86_64/multiarch/mempcpy.S +index 51970687cf..87c8299fea 100644 +--- a/sysdeps/x86_64/multiarch/mempcpy.S ++++ b/sysdeps/x86_64/multiarch/mempcpy.S +@@ -32,6 +32,8 @@ ENTRY(__mempcpy) + lea __mempcpy_erms(%rip), %RAX_LP + HAS_ARCH_FEATURE (Prefer_ERMS) + jnz 2f ++ HAS_ARCH_FEATURE (Prefer_No_AVX512) ++ jnz 1f + HAS_ARCH_FEATURE (AVX512F_Usable) + jz 1f + lea __mempcpy_avx512_no_vzeroupper(%rip), %RAX_LP +diff --git a/sysdeps/x86_64/multiarch/mempcpy_chk.S b/sysdeps/x86_64/multiarch/mempcpy_chk.S +index 9e49f6f26e..642c67973b 100644 +--- a/sysdeps/x86_64/multiarch/mempcpy_chk.S ++++ b/sysdeps/x86_64/multiarch/mempcpy_chk.S +@@ -30,6 +30,8 @@ + ENTRY(__mempcpy_chk) + .type __mempcpy_chk, @gnu_indirect_function + LOAD_RTLD_GLOBAL_RO_RDX ++ HAS_ARCH_FEATURE (Prefer_No_AVX512) ++ jnz 1f + HAS_ARCH_FEATURE (AVX512F_Usable) + jz 1f + lea __mempcpy_chk_avx512_no_vzeroupper(%rip), %RAX_LP +diff --git a/sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S b/sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S +index 28e71fd576..acf448c9a6 100644 +--- a/sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S ++++ b/sysdeps/x86_64/multiarch/memset-vec-unaligned-erms.S +@@ -110,6 +110,8 @@ ENTRY (__memset_erms) + ENTRY (MEMSET_SYMBOL (__memset, erms)) + # endif + L(stosb): ++ /* Issue vzeroupper before rep stosb. */ ++ VZEROUPPER + movq %rdx, %rcx + movzbl %sil, %eax + movq %rdi, %rdx +diff --git a/sysdeps/x86_64/multiarch/memset.S b/sysdeps/x86_64/multiarch/memset.S +index 96e99341aa..eae39e2ecd 100644 +--- a/sysdeps/x86_64/multiarch/memset.S ++++ b/sysdeps/x86_64/multiarch/memset.S +@@ -41,6 +41,8 @@ ENTRY(memset) + jnz L(AVX512F) + lea __memset_avx2_unaligned(%rip), %RAX_LP + L(AVX512F): ++ HAS_ARCH_FEATURE (Prefer_No_AVX512) ++ jnz 2f + HAS_ARCH_FEATURE (AVX512F_Usable) + jz 2f + lea __memset_avx512_no_vzeroupper(%rip), %RAX_LP +diff --git a/sysdeps/x86_64/multiarch/memset_chk.S b/sysdeps/x86_64/multiarch/memset_chk.S +index 2efe6ed909..38d7bef6df 100644 +--- a/sysdeps/x86_64/multiarch/memset_chk.S ++++ b/sysdeps/x86_64/multiarch/memset_chk.S +@@ -38,6 +38,8 @@ ENTRY(__memset_chk) + jnz L(AVX512F) + lea __memset_chk_avx2_unaligned(%rip), %RAX_LP + L(AVX512F): ++ HAS_ARCH_FEATURE (Prefer_No_AVX512) ++ jnz 2f + HAS_ARCH_FEATURE (AVX512F_Usable) + jz 2f + lea __memset_chk_avx512_no_vzeroupper(%rip), %RAX_LP +diff --git a/sysdeps/x86_64/nptl/tcb-offsets.sym b/sysdeps/x86_64/nptl/tcb-offsets.sym +index aeb752673a..8a25c482cb 100644 +--- a/sysdeps/x86_64/nptl/tcb-offsets.sym ++++ b/sysdeps/x86_64/nptl/tcb-offsets.sym +@@ -4,7 +4,6 @@ + + RESULT offsetof (struct pthread, result) + TID offsetof (struct pthread, tid) +-PID offsetof (struct pthread, pid) + CANCELHANDLING offsetof (struct pthread, cancelhandling) + CLEANUP_JMP_BUF offsetof (struct pthread, cleanup_jmp_buf) + CLEANUP offsetof (struct pthread, cleanup) +diff --git a/sysdeps/x86_64/sysdep.h b/sysdeps/x86_64/sysdep.h +index 75ac747be8..4b67fa80c1 100644 +--- a/sysdeps/x86_64/sysdep.h ++++ b/sysdeps/x86_64/sysdep.h +@@ -89,13 +89,14 @@ lose: \ + END (name) + + #undef JUMPTARGET +-#ifdef PIC ++#ifdef SHARED + # ifdef BIND_NOW + # define JUMPTARGET(name) *name##@GOTPCREL(%rip) + # else + # define JUMPTARGET(name) name##@PLT + # endif + #else ++/* For static archives, branch to target directly. */ + # define JUMPTARGET(name) name + #endif + |