diff --git a/glibc-RHEL-106562-1.patch b/glibc-RHEL-106562-1.patch new file mode 100644 index 0000000..d9838ff --- /dev/null +++ b/glibc-RHEL-106562-1.patch @@ -0,0 +1,69 @@ +commit f942a732d37a96217ef828116ebe64a644db18d7 +Author: Joe Talbott +Date: Tue May 14 14:39:38 2024 +0000 + + math: Add GLIBC_TEST_LIBM_VERBOSE environment variable support. + + Allow the libm-test-driver based tests to have their verbosity set based + on the GLIBC_TEST_LIBM_VERBOSE environment variable. This allows the entire + testsuite to be run with a non-default verbosity. + + While here check the conversion for the verbose option as well. + + Reviewed-by: Carlos O'Donell + +diff --git a/math/libm-test-support.c b/math/libm-test-support.c +index 1d60ac783be6fb65..0cae545f86ac1352 100644 +--- a/math/libm-test-support.c ++++ b/math/libm-test-support.c +@@ -130,7 +130,7 @@ static int noTests; /* number of tests (without testing exceptions) */ + static int noExcTests; /* number of tests for exception flags */ + static int noErrnoTests;/* number of tests for errno values */ + +-static int verbose; ++static unsigned int verbose; + static int output_max_error; /* Should the maximal errors printed? */ + static int output_points; /* Should the single function results printed? */ + static int ignore_max_ulp; /* Should we ignore max_ulp? */ +@@ -1057,7 +1057,14 @@ parse_opt (int key, char *arg, struct argp_state *state) + break; + case 'v': + if (optarg) +- verbose = (unsigned int) strtoul (optarg, NULL, 0); ++ { ++ char *optstr_conv = optarg; ++ unsigned int opt_verbose; ++ ++ opt_verbose = (unsigned int) strtoul (optarg, &optstr_conv, 0); ++ if (*optstr_conv == '\0' && optstr_conv != optarg) ++ verbose = opt_verbose; ++ } + else + verbose = 3; + break; +@@ -1139,6 +1146,7 @@ libm_test_init (int argc, char **argv) + int remaining; + char *ulps_file_path; + size_t dir_len = 0; ++ char *envstr_verbose; + + verbose = 1; + output_ulps = 0; +@@ -1148,6 +1156,17 @@ libm_test_init (int argc, char **argv) + /* XXX set to 0 for releases. */ + ignore_max_ulp = 0; + ++ envstr_verbose = getenv("GLIBC_TEST_LIBM_VERBOSE"); ++ if (envstr_verbose != NULL) ++ { ++ char *envstr_conv = envstr_verbose; ++ unsigned int env_verbose; ++ ++ env_verbose = (unsigned int) strtoul (envstr_verbose, &envstr_conv, 0); ++ if (*envstr_conv == '\0' && envstr_conv != envstr_verbose) ++ verbose = env_verbose; ++ } ++ + /* Parse and process arguments. */ + argp_parse (&argp, argc, argv, 0, &remaining, NULL); + diff --git a/glibc-RHEL-106562-10.patch b/glibc-RHEL-106562-10.patch new file mode 100644 index 0000000..e3c1b91 --- /dev/null +++ b/glibc-RHEL-106562-10.patch @@ -0,0 +1,20 @@ +commit 79f44e1a47e87907fb8e97bbd098e01c4adc26a5 +Author: Florian Weimer +Date: Mon Aug 26 16:45:31 2024 +0200 + + inet: Avoid label at end of compound statement in tst-if_nameindex + + This fails to compile with GCC 8. + +diff --git a/inet/tst-if_nameindex.c b/inet/tst-if_nameindex.c +index b025cdb3a7c6b68c..5b905601245bef34 100644 +--- a/inet/tst-if_nameindex.c ++++ b/inet/tst-if_nameindex.c +@@ -105,6 +105,7 @@ do_test (void) + TEST_VERIFY (errno == ENODEV); + + not_this_one: ++ ; + } + + diff --git a/glibc-RHEL-106562-11.patch b/glibc-RHEL-106562-11.patch new file mode 100644 index 0000000..ef95c71 --- /dev/null +++ b/glibc-RHEL-106562-11.patch @@ -0,0 +1,288 @@ +commit 4945ffc88a8ad49280bae64165683ddfd12b2390 +Author: DJ Delorie +Date: Wed Aug 7 16:55:16 2024 -0400 + + fgets: more tests + + Add more tests for unusual situations fgets() might see: + + * zero size file + * zero sized buffer + * NULL buffer + * NUL data + * writable stream + * closed stream + + Reviewed-by: Florian Weimer + +diff --git a/stdio-common/Makefile b/stdio-common/Makefile +index c822434293b7e809..6b52fd3e0d818960 100644 +--- a/stdio-common/Makefile ++++ b/stdio-common/Makefile +@@ -209,6 +209,7 @@ tests := \ + tst-fdopen2 \ + tst-ferror \ + tst-fgets \ ++ tst-fgets2 \ + tst-fileno \ + tst-fmemopen \ + tst-fmemopen2 \ +diff --git a/stdio-common/tst-fgets2.c b/stdio-common/tst-fgets2.c +new file mode 100644 +index 0000000000000000..5b78447ea9aa3cbe +--- /dev/null ++++ b/stdio-common/tst-fgets2.c +@@ -0,0 +1,253 @@ ++/* Test for additional fgets error handling. ++ Copyright (C) 2024 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++/* This avoids compiler warnings about passing NULL where a valid ++ pointer is expected. */ ++static void *volatile null = NULL; ++ ++/* Implementation of our FILE stream backend. */ ++ ++static int bytes_read; ++static int cookie_valid = 0; ++struct Cookie { ++ const char *buffer; ++ int bufptr; ++ int bufsz; ++}; ++ ++#define VALIDATE_COOKIE() if (! cookie_valid) { \ ++ FAIL ("call to %s after file closed", __FUNCTION__); \ ++ return -1; \ ++ } ++ ++static ssize_t ++io_read (void *vcookie, char *buf, size_t size) ++{ ++ struct Cookie *cookie = (struct Cookie *) vcookie; ++ ++ VALIDATE_COOKIE (); ++ ++ if (size > cookie->bufsz - cookie->bufptr) ++ size = cookie->bufsz - cookie->bufptr; ++ ++ memcpy (buf, cookie->buffer + cookie->bufptr, size); ++ cookie->bufptr += size; ++ bytes_read += size; ++ return size; ++} ++ ++static ssize_t ++io_write (void *vcookie, const char *buf, size_t size) ++{ ++ VALIDATE_COOKIE (); ++ FAIL_EXIT1 ("io_write called"); ++} ++ ++static int ++io_seek (void *vcookie, off64_t *position, int whence) ++{ ++ VALIDATE_COOKIE (); ++ FAIL_EXIT1 ("io_seek called"); ++} ++ ++static int ++io_clean (void *vcookie) ++{ ++ struct Cookie *cookie = (struct Cookie *) vcookie; ++ ++ VALIDATE_COOKIE (); ++ ++ cookie->buffer = NULL; ++ cookie->bufsz = 0; ++ cookie->bufptr = 0; ++ ++ cookie_valid = 0; ++ free (cookie); ++ return 0; ++} ++ ++cookie_io_functions_t io_funcs = { ++ .read = io_read, ++ .write = io_write, ++ .seek = io_seek, ++ .close = io_clean ++}; ++ ++FILE * ++io_open (const char *buffer, int buflen, const char *mode, void **vcookie) ++{ ++ FILE *f; ++ struct Cookie *cookie; ++ ++ cookie = (struct Cookie *) xcalloc (1, sizeof (struct Cookie)); ++ *vcookie = cookie; ++ cookie_valid = 1; ++ ++ cookie->buffer = buffer; ++ cookie->bufsz = buflen; ++ bytes_read = 0; ++ ++ f = fopencookie (cookie, mode, io_funcs); ++ if (f == NULL) ++ FAIL_EXIT1 ("fopencookie failed"); ++ ++ clearerr (f); ++ return f; ++} ++ ++/* The test cases. */ ++ ++#define my_open(s,l,m) io_open (s, l, m, (void *) &cookie) ++ ++#define TEST_COMPARE_0x11(buf, len) \ ++ TEST_COMPARE_BLOB (buf + (len), sizeof (buf) - (len), \ ++ buf2, sizeof (buf) - (len)); ++ ++#define check_flags(f, expected_eof, expected_err) \ ++ { \ ++ if (expected_eof) \ ++ TEST_VERIFY (feof (f) != 0); \ ++ else \ ++ TEST_VERIFY (feof (f) == 0); \ ++ if (expected_err) \ ++ TEST_VERIFY (ferror (f) != 0); \ ++ else \ ++ TEST_VERIFY (ferror (f) == 0); \ ++ } ++ ++static int ++do_test (void) ++{ ++ FILE *f; ++ struct Cookie *cookie; ++ char buf [10]; ++ char buf2 [10]; ++ char *returned_string; ++ ++ memset (buf2, 0x11, sizeof (buf2)); ++ ++ printf ("testing base operation...\n"); ++ f = my_open ("hello\n", 6, "r"); ++ memset (buf, 0x11, sizeof (buf)); ++ returned_string = fgets (buf, sizeof (buf) - 1, f); ++ TEST_VERIFY (returned_string == buf); ++ TEST_COMPARE_BLOB (buf, bytes_read + 1, "hello\n\0", 7); ++ TEST_COMPARE_0x11 (buf, bytes_read + 1); ++ check_flags (f, 0, 0); ++ ++ fclose (f); ++ ++ printf ("testing zero size file...\n"); ++ f = my_open ("hello\n", 0, "r"); ++ memset (buf, 0x11, sizeof (buf)); ++ returned_string = fgets (buf, sizeof (buf) - 1, f); ++ TEST_VERIFY (returned_string == NULL); ++ TEST_VERIFY (bytes_read == 0); ++ check_flags (f, 1, 0); ++ fclose (f); ++ ++ printf ("testing zero size buffer...\n"); ++ f = my_open ("hello\n", 6, "r"); ++ memset (buf, 0x11, sizeof (buf)); ++ returned_string = fgets (buf, 0, f); ++ TEST_VERIFY (returned_string == NULL); ++ TEST_VERIFY (bytes_read == 0); ++ check_flags (f, 0, 0); ++ fclose (f); ++ ++ printf ("testing NULL buffer with empty stream...\n"); ++ f = my_open ("hello\n", 0, "r"); ++ memset (buf, 0x11, sizeof (buf)); ++ ++ returned_string = fgets (null, sizeof (buf), f); ++ ++ TEST_VERIFY (returned_string == NULL); ++ TEST_VERIFY (bytes_read == 0); ++ check_flags (f, 1, 0); ++ fclose (f); ++ ++ printf ("testing embedded NUL...\n"); ++ f = my_open ("hel\0lo\n", 7, "r"); ++ memset (buf, 0x11, sizeof (buf)); ++ returned_string = fgets (buf, sizeof (buf) - 1, f); ++ TEST_VERIFY (returned_string == buf); ++ TEST_COMPARE_BLOB (buf, bytes_read + 1, "hel\0lo\n\0", 8); ++ TEST_COMPARE_0x11 (buf, bytes_read + 1); ++ check_flags (f, 0, 0); ++ fclose (f); ++ ++ printf ("testing writable stream...\n"); ++ f = my_open ("hel\0lo\n", 7, "w"); ++ memset (buf, 0x11, sizeof (buf)); ++ returned_string = fgets (buf, sizeof (buf) - 1, f); ++ TEST_VERIFY (returned_string == NULL); ++ TEST_VERIFY (bytes_read == 0); ++ check_flags (f, 0, 1); ++ fclose (f); ++ ++ printf ("testing closed fd stream...\n"); ++ int fd = open ("/dev/null", O_RDONLY); ++ f = fdopen (fd, "r"); ++ close (fd); ++ memset (buf, 0x11, sizeof (buf)); ++ returned_string = fgets (buf, sizeof (buf) - 1, f); ++ TEST_VERIFY (returned_string == NULL); ++ TEST_VERIFY (bytes_read == 0); ++ check_flags (f, 0, 1); ++ fclose (f); ++ ++#ifdef IO_DEBUG ++ /* These tests only pass if glibc is built with -DIO_DEBUG, but are ++ included for reference. */ ++ ++ printf ("testing NULL descriptor...\n"); ++ memset (buf, 0x11, sizeof (buf)); ++ returned_string = fgets (buf, sizeof (buf) - 1, null); ++ TEST_VERIFY (returned_string == NULL); ++ TEST_VERIFY (bytes_read == 0); ++ ++ printf ("testing closed descriptor...\n"); ++ f = my_open ("hello\n", 7, "r"); ++ fclose (f); ++ memset (buf, 0x11, sizeof (buf)); ++ returned_string = fgets (buf, sizeof (buf) - 1, f); ++ TEST_VERIFY (returned_string == NULL); ++ TEST_VERIFY (bytes_read == 0); ++#endif ++ ++ return 0; ++} ++ ++#include diff --git a/glibc-RHEL-106562-12.patch b/glibc-RHEL-106562-12.patch new file mode 100644 index 0000000..a5d4fb5 --- /dev/null +++ b/glibc-RHEL-106562-12.patch @@ -0,0 +1,90 @@ +commit 83fd4149ffdae86c8864a6828f39dd942956636f +Author: Aaron Merey +Date: Thu Sep 19 11:11:39 2024 -0400 + + Test that errno is set to 0 at program startup + + Add new testcase elf/tst-startup-errno.c which tests that errno is set + to 0 at first ELF constructor execution and at the start of the + program's main function. + + Tested for x86_64 + + Reviewed-by: Carlos O'Donell + +diff --git a/elf/Makefile b/elf/Makefile +index a46c4f69d98553f7..92da608da1ebc175 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -457,6 +457,7 @@ tests += \ + tst-single_threaded-pthread \ + tst-sonamemove-dlopen \ + tst-sonamemove-link \ ++ tst-startup-errno \ + tst-thrlock \ + tst-tls-dlinfo \ + tst-tls-ie \ +diff --git a/elf/tst-startup-errno.c b/elf/tst-startup-errno.c +new file mode 100644 +index 0000000000000000..59a1005fb674a5c3 +--- /dev/null ++++ b/elf/tst-startup-errno.c +@@ -0,0 +1,58 @@ ++/* Test the value of errno at program startup. ++ Copyright (C) 2024 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 ++ . */ ++ ++#include ++#include ++#include ++ ++/* Verify that errno is 0 at first ELF constructor execution and at ++ the start of main. */ ++ ++static void set_ctor_errno (void) __attribute__((constructor)); ++static int ctor_errno = -1; ++ ++static void ++set_ctor_errno (void) ++{ ++ ctor_errno = errno; ++} ++ ++static int ++get_ctor_errno (void) ++{ ++ return ctor_errno; ++} ++ ++int ++main (void) ++{ ++ if (errno != 0) ++ { ++ printf ("At start of main errno set to %d != 0\n", errno); ++ exit (1); ++ } ++ ++ if (get_ctor_errno () != 0) ++ { ++ printf ("At ctor exec errno set to %d != 0\n", get_ctor_errno ()); ++ exit (1); ++ } ++ ++ return 0; ++} ++ diff --git a/glibc-RHEL-106562-13.patch b/glibc-RHEL-106562-13.patch new file mode 100644 index 0000000..84b92cf --- /dev/null +++ b/glibc-RHEL-106562-13.patch @@ -0,0 +1,301 @@ +commit cfb35f5f7f32cec8fa4e16b99e35b7d70fa13f1f +Author: DJ Delorie +Date: Tue Sep 17 22:52:37 2024 -0400 + + rt: more clock_nanosleep tests + + Test that clock_nanosleep rejects out of range time values. + + Test that clock_nanosleep actually sleeps for at least the + requested time relative to the requested clock. + + Reviewed-by: Adhemerval Zanella + +diff --git a/rt/Makefile b/rt/Makefile +index 7b50c64f7664c07f..bc5f28c6d03722a3 100644 +--- a/rt/Makefile ++++ b/rt/Makefile +@@ -77,6 +77,7 @@ tests := tst-shm tst-timer tst-timer2 \ + tst-bz28213 \ + tst-timer3 tst-timer4 tst-timer5 \ + tst-cpuclock2 tst-cputimer1 tst-cputimer2 tst-cputimer3 \ ++ tst-clock_nanosleep2 \ + tst-shm-cancel \ + tst-mqueue10 + tests-internal := tst-timer-sigmask +@@ -84,6 +85,7 @@ tests-internal := tst-timer-sigmask + tests-time64 := \ + tst-aio6-time64 \ + tst-cpuclock2-time64 \ ++ tst-clock_nanosleep2-time64 \ + tst-mqueue1-time64 \ + tst-mqueue2-time64 \ + tst-mqueue4-time64 \ +diff --git a/rt/tst-clock_nanosleep2-time64.c b/rt/tst-clock_nanosleep2-time64.c +new file mode 100644 +index 0000000000000000..8deb4201f38b094a +--- /dev/null ++++ b/rt/tst-clock_nanosleep2-time64.c +@@ -0,0 +1 @@ ++#include "tst-clock_nanosleep2.c" +diff --git a/rt/tst-clock_nanosleep2.c b/rt/tst-clock_nanosleep2.c +new file mode 100644 +index 0000000000000000..10c822fd54668531 +--- /dev/null ++++ b/rt/tst-clock_nanosleep2.c +@@ -0,0 +1,255 @@ ++/* Test program for process CPU clocks - invalid inputs, minimum time ++ Copyright (C) 2024 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 ++ . */ ++ ++/* This test has two primary goals - first, to validate that invalid ++ inputs to clock_nanosleep are caught, and second, to validate that ++ clock_nanosleep sleeps for at least the amount of time requested. ++ It is assumed that the system may sleep for an arbitrary additional ++ amount of time beyond the requested time. */ ++ ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++/* This is 1 ms per test, we have 10 tests, so this file runs in on ++ the order of 0.01 seconds. */ ++#define TEST_NSEC 1000000 ++ ++/* Nanoseconds per second. */ ++#define NSECMAX 1000000000L ++ ++static pthread_barrier_t barrier; ++ ++/* This function is intended to rack up both user and system time. */ ++static void * ++chew_cpu (void *arg) ++{ ++ pthread_barrier_wait (&barrier); ++ ++ while (1) ++ { ++ static volatile char buf[4096]; ++ for (int i = 0; i < 100; ++i) ++ for (size_t j = 0; j < sizeof buf; ++j) ++ buf[j] = 0xaa; ++ int nullfd = xopen ("/dev/null", O_WRONLY, 0); ++ for (int i = 0; i < 100; ++i) ++ for (size_t j = 0; j < sizeof buf; ++j) ++ buf[j] = 0xbb; ++ xwrite (nullfd, (char *) buf, sizeof buf); ++ close (nullfd); ++ } ++ ++ return NULL; ++} ++ ++static void ++ptime_1 (const char *n, struct timespec t) ++{ ++ /* This is only for debugging failed test cases. */ ++ printf ("%12s: %lld.%09lld\n", n, (long long int) t.tv_sec, ++ (long long int) t.tv_nsec); ++} ++#define ptime(t) ptime_1 (#t, t) ++ ++static void ++test_interval_1 (const char *n_clock, clockid_t t_clock) ++{ ++ struct timespec me_before, me_after, quantum, me_sleep, me_slept; ++ long long int slept, min_slept; ++ ++ /* Arbitrary to ensure our time period is sufficiently bigger than ++ the time step. */ ++ TEST_VERIFY (clock_getres (t_clock, &quantum) == 0); ++ printf("Clock quantum: %lld ns, test time: %lld ns\n", ++ (long long int) quantum.tv_nsec, (long long int) TEST_NSEC); ++ TEST_VERIFY (quantum.tv_nsec <= TEST_NSEC / 10); ++ ++ min_slept = TEST_NSEC; ++ ++ me_sleep = make_timespec (0, min_slept); ++ ++ printf ("test clock %s for %lld.%09lld sec relative\n", ++ n_clock, (long long int) me_sleep.tv_sec, ++ (long long int) me_sleep.tv_nsec); ++ ++ TEST_COMPARE (clock_gettime (t_clock, &me_before), 0); ++ TEST_COMPARE (clock_nanosleep (t_clock, 0, &me_sleep, NULL), 0); ++ TEST_COMPARE (clock_gettime (t_clock, &me_after), 0); ++ ++ me_slept = timespec_sub (me_after, me_before); ++ slept = support_timespec_ns (me_slept); ++ ++ ptime (me_before); ++ ptime (me_after); ++ ptime (me_sleep); ++ ptime (me_slept); ++ printf ("test slept %lld nsec >= asked for %lld ?\n", slept, min_slept); ++ ++ /* This is the important part - verify that the time slept is at ++ least as much as the time requested. */ ++ TEST_VERIFY (slept >= min_slept); ++} ++ ++static void ++test_abs_1 (const char *n_clock, clockid_t t_clock) ++{ ++ struct timespec me_before, me_after, quantum, me_sleep; ++ ++ /* Arbitrary to ensure our time period is sufficiently bigger than ++ the time step. */ ++ TEST_VERIFY (clock_getres (t_clock, &quantum) == 0); ++ printf("Clock quantum: %lld ns, test time: %lld ns\n", ++ (long long int) quantum.tv_nsec, (long long int) TEST_NSEC); ++ TEST_VERIFY (quantum.tv_nsec <= TEST_NSEC / 10); ++ ++ me_sleep = make_timespec (0, TEST_NSEC); ++ ++ printf ("test clock %s for %lld.%09lld sec absolute\n", ++ n_clock, (long long int) me_sleep.tv_sec, ++ (long long int) me_sleep.tv_nsec); ++ ++ TEST_COMPARE (clock_gettime (t_clock, &me_before), 0); ++ me_sleep = timespec_add (me_sleep, me_before); ++ TEST_COMPARE (clock_nanosleep (t_clock, TIMER_ABSTIME, &me_sleep, NULL), 0); ++ TEST_COMPARE (clock_gettime (t_clock, &me_after), 0); ++ ++ ptime (me_before); ++ ptime (me_sleep); ++ ptime (me_after); ++ ++ printf("test slept until %lld.%09lld after requested %lld.%09lld ?\n", ++ (long long int) me_after.tv_sec, (long long int) me_after.tv_nsec, ++ (long long int) me_sleep.tv_sec, (long long int) me_sleep.tv_nsec); ++ ++ /* This is the important part - verify that the time slept is at ++ least as much as the time requested. */ ++ TEST_TIMESPEC_EQUAL_OR_AFTER (me_after, me_sleep); ++} ++ ++static void ++test_invalids_1 (const char *the_clock_name, int the_clock, ++ const char *flags_name, int flags) ++{ ++ struct timespec me_before; ++ ++ /* Note: do not use make_timespec() in case that function tries to ++ normalize the fields. */ ++ ++ printf ("%s: %s: test tv 0, 0\n", the_clock_name, flags_name); ++ me_before.tv_sec = 0; ++ me_before.tv_nsec = 0; ++ TEST_COMPARE (clock_nanosleep (the_clock, 0, &me_before, NULL), 0); ++ ++ printf ("%s: %s: test tv -1, 0\n", the_clock_name, flags_name); ++ me_before.tv_sec = -1; ++ me_before.tv_nsec = 0; ++ TEST_COMPARE (clock_nanosleep (the_clock, 0, &me_before, NULL), EINVAL); ++ ++ printf ("%s: %s: test tv 0, -1\n", the_clock_name, flags_name); ++ me_before.tv_sec = 0; ++ me_before.tv_nsec = -1; ++ TEST_COMPARE (clock_nanosleep (the_clock, 0, &me_before, NULL), EINVAL); ++ ++ printf ("%s: %s: test tv -1, -1\n", the_clock_name, flags_name); ++ me_before.tv_sec = -1; ++ me_before.tv_nsec = -1; ++ TEST_COMPARE (clock_nanosleep (the_clock, 0, &me_before, NULL), EINVAL); ++ ++ printf ("%s: %s: test tv 0, MAX\n", the_clock_name, flags_name); ++ me_before.tv_sec = 0; ++ me_before.tv_nsec = NSECMAX; ++ TEST_COMPARE (clock_nanosleep (the_clock, 0, &me_before, NULL), EINVAL); ++} ++ ++static int ++do_test (void) ++{ ++ pthread_t th; ++ ++ pthread_barrier_init (&barrier, NULL, 2); ++ ++ /* Test for proper error detection. */ ++ ++#define test_invalids(c, f) test_invalids_1 (#c, c, #f, f) ++ test_invalids (CLOCK_REALTIME, 0); ++#ifdef CLOCK_TAI ++ test_invalids (CLOCK_TAI, 0); ++#endif ++ test_invalids (CLOCK_MONOTONIC, 0); ++#ifdef CLOCK_BOOTTIME ++ test_invalids (CLOCK_BOOTTIME, 0); ++#endif ++ test_invalids (CLOCK_PROCESS_CPUTIME_ID, 0); ++ test_invalids (CLOCK_REALTIME, TIMER_ABSTIME); ++#ifdef CLOCK_TAI ++ test_invalids (CLOCK_TAI, TIMER_ABSTIME); ++#endif ++ test_invalids (CLOCK_MONOTONIC, TIMER_ABSTIME); ++#ifdef CLOCK_BOOTTIME ++ test_invalids (CLOCK_BOOTTIME, TIMER_ABSTIME); ++#endif ++ test_invalids (CLOCK_PROCESS_CPUTIME_ID, TIMER_ABSTIME); ++ ++ /* Test for various clocks "working". */ ++ ++#define test_interval(c) test_interval_1 (#c, c) ++ test_interval (CLOCK_REALTIME); ++#ifdef CLOCK_TAI ++ test_interval (CLOCK_TAI); ++#endif ++ test_interval (CLOCK_MONOTONIC); ++#ifdef CLOCK_BOOTTIME ++ test_interval (CLOCK_BOOTTIME); ++#endif ++ ++ th = xpthread_create (NULL, chew_cpu, NULL); ++ xpthread_barrier_wait (&barrier); ++ test_interval (CLOCK_PROCESS_CPUTIME_ID); ++ xpthread_cancel (th); ++ ++#define test_abs(c) test_abs_1 (#c, c) ++ test_abs (CLOCK_REALTIME); ++#ifdef CLOCK_TAI ++ test_abs (CLOCK_TAI); ++#endif ++ test_abs (CLOCK_MONOTONIC); ++#ifdef CLOCK_BOOTTIME ++ test_abs (CLOCK_BOOTTIME); ++#endif ++ ++ th = xpthread_create (NULL, chew_cpu, NULL); ++ xpthread_barrier_wait (&barrier); ++ test_abs (CLOCK_PROCESS_CPUTIME_ID); ++ xpthread_cancel (th); ++ ++ return 0; ++} ++ ++#include diff --git a/glibc-RHEL-106562-14.patch b/glibc-RHEL-106562-14.patch new file mode 100644 index 0000000..813c7ff --- /dev/null +++ b/glibc-RHEL-106562-14.patch @@ -0,0 +1,18 @@ +commit 1895a35e7092713b224166d36b9bc26e8eb3371f +Author: DJ Delorie +Date: Tue Oct 8 14:30:21 2024 -0400 + + rt: more clock_nanosleep tests addendum + + Forgot to change the first-line description. + +diff --git a/rt/tst-clock_nanosleep2.c b/rt/tst-clock_nanosleep2.c +index 10c822fd54668531..e9b2a2716d6e9016 100644 +--- a/rt/tst-clock_nanosleep2.c ++++ b/rt/tst-clock_nanosleep2.c +@@ -1,4 +1,4 @@ +-/* Test program for process CPU clocks - invalid inputs, minimum time ++/* Test for clock_nanosleep parameter checks and sleep duration. + Copyright (C) 2024 Free Software Foundation, Inc. + This file is part of the GNU C Library. + diff --git a/glibc-RHEL-106562-15.patch b/glibc-RHEL-106562-15.patch new file mode 100644 index 0000000..5df1459 --- /dev/null +++ b/glibc-RHEL-106562-15.patch @@ -0,0 +1,218 @@ +commit 99671e72bb27a3cb98860bdc4c0e25961ce96b3e +Author: Joseph Myers +Date: Fri Nov 22 16:58:51 2024 +0000 + + Add multithreaded test of sem_getvalue + + Test coverage of sem_getvalue is fairly limited. Add a test that runs + it on threads on each CPU. For this purpose I adapted + tst-skeleton-thread-affinity.c; it didn't seem very suitable to use + as-is or include directly in a different test doing things per-CPU, + but did seem a suitable starting point (thus sharing + tst-skeleton-affinity.c) for such testing. + + Tested for x86_64. + +diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile +index eee91c7b64d79fe7..47bf050759bd2b4e 100644 +--- a/sysdeps/unix/sysv/linux/Makefile ++++ b/sysdeps/unix/sysv/linux/Makefile +@@ -653,6 +653,7 @@ ifeq ($(subdir),nptl) + tests += \ + tst-align-clone \ + tst-getpid1 \ ++ tst-sem_getvalue-affinity \ + # tests + + # tst-rseq-nptl is an internal test because it requires a definition of +diff --git a/sysdeps/unix/sysv/linux/tst-sem_getvalue-affinity.c b/sysdeps/unix/sysv/linux/tst-sem_getvalue-affinity.c +new file mode 100644 +index 0000000000000000..4176f67533357909 +--- /dev/null ++++ b/sysdeps/unix/sysv/linux/tst-sem_getvalue-affinity.c +@@ -0,0 +1,185 @@ ++/* Test sem_getvalue across CPUs. Based on tst-skeleton-thread-affinity.c. ++ Copyright (C) 2015-2024 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++struct conf; ++static bool early_test (struct conf *); ++ ++static int ++setaffinity (size_t size, const cpu_set_t *set) ++{ ++ int ret = pthread_setaffinity_np (pthread_self (), size, set); ++ if (ret != 0) ++ { ++ errno = ret; ++ return -1; ++ } ++ return 0; ++} ++ ++static int ++getaffinity (size_t size, cpu_set_t *set) ++{ ++ int ret = pthread_getaffinity_np (pthread_self (), size, set); ++ if (ret != 0) ++ { ++ errno = ret; ++ return -1; ++ } ++ return 0; ++} ++ ++#include "tst-skeleton-affinity.c" ++ ++static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; ++static sem_t sem; ++ ++static void * ++tf (void *arg) ++{ ++ void *ret = NULL; ++ xpthread_mutex_lock (&lock); ++ int semval; ++ if (sem_getvalue (&sem, &semval) != 0) ++ { ++ printf ("sem_getvalue failed: %m\n"); ++ ret = (void *) 1; ++ } ++ else if (semval != 12345) ++ { ++ printf ("sem_getvalue returned %d not 12345\n", semval); ++ ret = (void *) 1; ++ } ++ xpthread_mutex_unlock (&lock); ++ return ret; ++} ++ ++static int ++stop_and_join_threads (struct conf *conf, cpu_set_t *set, ++ pthread_t *pinned_first, pthread_t *pinned_last) ++{ ++ int failed = 0; ++ for (pthread_t *p = pinned_first; p < pinned_last; ++p) ++ { ++ int cpu = p - pinned_first; ++ if (!CPU_ISSET_S (cpu, CPU_ALLOC_SIZE (conf->set_size), set)) ++ continue; ++ ++ void *retval = (void *) 1; ++ int ret = pthread_join (*p, &retval); ++ if (ret != 0) ++ { ++ printf ("error: Failed to join thread %d: %s\n", cpu, strerror (ret)); ++ fflush (stdout); ++ /* Cannot shut down cleanly with threads still running. */ ++ abort (); ++ } ++ if (retval != NULL) ++ failed = 1; ++ } ++ return failed; ++} ++ ++static bool ++early_test (struct conf *conf) ++{ ++ int ret; ++ ret = sem_init (&sem, 0, 12345); ++ if (ret != 0) ++ { ++ printf ("error: sem_init failed: %m\n"); ++ return false; ++ } ++ xpthread_mutex_lock (&lock); ++ pthread_t *pinned_threads ++ = calloc (conf->last_cpu + 1, sizeof (*pinned_threads)); ++ cpu_set_t *initial_set = CPU_ALLOC (conf->set_size); ++ cpu_set_t *scratch_set = CPU_ALLOC (conf->set_size); ++ ++ if (pinned_threads == NULL || initial_set == NULL || scratch_set == NULL) ++ { ++ puts ("error: Memory allocation failure"); ++ return false; ++ } ++ if (getaffinity (CPU_ALLOC_SIZE (conf->set_size), initial_set) < 0) ++ { ++ printf ("error: pthread_getaffinity_np failed: %m\n"); ++ return false; ++ } ++ ++ pthread_attr_t attr; ++ ret = pthread_attr_init (&attr); ++ if (ret != 0) ++ { ++ printf ("error: pthread_attr_init failed: %s\n", strerror (ret)); ++ return false; ++ } ++ support_set_small_thread_stack_size (&attr); ++ ++ /* Spawn a thread pinned to each available CPU. */ ++ for (int cpu = 0; cpu <= conf->last_cpu; ++cpu) ++ { ++ if (!CPU_ISSET_S (cpu, CPU_ALLOC_SIZE (conf->set_size), initial_set)) ++ continue; ++ CPU_ZERO_S (CPU_ALLOC_SIZE (conf->set_size), scratch_set); ++ CPU_SET_S (cpu, CPU_ALLOC_SIZE (conf->set_size), scratch_set); ++ ret = pthread_attr_setaffinity_np ++ (&attr, CPU_ALLOC_SIZE (conf->set_size), scratch_set); ++ if (ret != 0) ++ { ++ printf ("error: pthread_attr_setaffinity_np for CPU %d failed: %s\n", ++ cpu, strerror (ret)); ++ stop_and_join_threads (conf, initial_set, ++ pinned_threads, pinned_threads + cpu); ++ return false; ++ } ++ ret = pthread_create (pinned_threads + cpu, &attr, ++ tf, (void *) (uintptr_t) cpu); ++ if (ret != 0) ++ { ++ printf ("error: pthread_create for CPU %d failed: %s\n", ++ cpu, strerror (ret)); ++ stop_and_join_threads (conf, initial_set, ++ pinned_threads, pinned_threads + cpu); ++ return false; ++ } ++ } ++ ++ /* Main thread. */ ++ xpthread_mutex_unlock (&lock); ++ int failed = stop_and_join_threads (conf, initial_set, ++ pinned_threads, ++ pinned_threads + conf->last_cpu + 1); ++ ++ printf ("info: Main thread ran on %d CPU(s) of %d available CPU(s)\n", ++ CPU_COUNT_S (CPU_ALLOC_SIZE (conf->set_size), scratch_set), ++ CPU_COUNT_S (CPU_ALLOC_SIZE (conf->set_size), initial_set)); ++ ++ pthread_attr_destroy (&attr); ++ CPU_FREE (scratch_set); ++ CPU_FREE (initial_set); ++ free (pinned_threads); ++ return failed == 0; ++} diff --git a/glibc-RHEL-106562-16.patch b/glibc-RHEL-106562-16.patch new file mode 100644 index 0000000..e6ee947 --- /dev/null +++ b/glibc-RHEL-106562-16.patch @@ -0,0 +1,65 @@ +commit 4b7cfcc3fbfab55a1bbb32a2da69c048060739d6 +Author: Florian Weimer +Date: Mon Nov 25 17:32:54 2024 +0100 + + debug: Wire up tst-longjmp_chk3 + + The test was added in commit ac8cc9e300a002228eb7e660df3e7b333d9a7414 + without all the required Makefile scaffolding. Tweak the test + so that it actually builds (including with dynamic SIGSTKSZ). + + Reviewed-by: Adhemerval Zanella + +diff --git a/debug/Makefile b/debug/Makefile +index 3903cc97a3706354..76c311d2845df9c1 100644 +--- a/debug/Makefile ++++ b/debug/Makefile +@@ -287,6 +287,7 @@ tests = \ + tst-fortify-wide \ + tst-longjmp_chk \ + tst-longjmp_chk2 \ ++ tst-longjmp_chk3 \ + tst-realpath-chk \ + tst-sprintf-fortify-rdonly \ + tst-sprintf-fortify-unchecked \ +diff --git a/debug/tst-longjmp_chk3.c b/debug/tst-longjmp_chk3.c +index 9ff99772075926ce..7bf1646b354fd2fe 100644 +--- a/debug/tst-longjmp_chk3.c ++++ b/debug/tst-longjmp_chk3.c +@@ -18,9 +18,12 @@ + + #include + #include ++#include + #include + +-static char buf[SIGSTKSZ * 4]; ++#include ++ ++static char *buf; + static jmp_buf jb; + + static void +@@ -49,8 +52,10 @@ do_test (void) + set_fortify_handler (handler); + + /* Create a valid signal stack and enable it. */ ++ size_t bufsize = SIGSTKSZ * 4; ++ buf = xmalloc (bufsize); + ss.ss_sp = buf; +- ss.ss_size = sizeof (buf); ++ ss.ss_size = bufsize; + ss.ss_flags = 0; + if (sigaltstack (&ss, NULL) < 0) + { +@@ -65,8 +70,8 @@ do_test (void) + + /* Shrink the signal stack so the jmpbuf is now invalid. + We adjust the start & end to handle stacks that grow up & down. */ +- ss.ss_sp = buf + sizeof (buf) / 2; +- ss.ss_size = sizeof (buf) / 4; ++ ss.ss_sp = buf + bufsize / 2; ++ ss.ss_size = bufsize / 4; + if (sigaltstack (&ss, NULL) < 0) + { + printf ("second sigaltstack failed: %m\n"); diff --git a/glibc-RHEL-106562-17.patch b/glibc-RHEL-106562-17.patch new file mode 100644 index 0000000..a6e68a1 --- /dev/null +++ b/glibc-RHEL-106562-17.patch @@ -0,0 +1,20 @@ +commit 4836a9af89f1b4d482e6c72ff67e36226d36434c +Author: Florian Weimer +Date: Tue Nov 26 19:26:13 2024 +0100 + + debug: Fix tst-longjmp_chk3 build failure on Hurd + + Explicitly include for _exit and getpid. + +diff --git a/debug/tst-longjmp_chk3.c b/debug/tst-longjmp_chk3.c +index 7bf1646b354fd2fe..9b9db3b9e9e37d54 100644 +--- a/debug/tst-longjmp_chk3.c ++++ b/debug/tst-longjmp_chk3.c +@@ -20,6 +20,7 @@ + #include + #include + #include ++#include + + #include + diff --git a/glibc-RHEL-106562-18.patch b/glibc-RHEL-106562-18.patch new file mode 100644 index 0000000..134781a --- /dev/null +++ b/glibc-RHEL-106562-18.patch @@ -0,0 +1,111 @@ +commit bde47662b74b883149c3001e2c052dea5d3cd92f +Author: Sergey Kolosov +Date: Wed Nov 6 15:24:06 2024 +0100 + + nptl: Add new test for pthread_spin_trylock + + Add a threaded test for pthread_spin_trylock attempting to lock already + acquired spin lock and checking for correct return code. + + Reviewed-by: Florian Weimer + +diff --git a/sysdeps/pthread/Makefile b/sysdeps/pthread/Makefile +index 04ea56559ef3a79b..8c80b7a606da4c94 100644 +--- a/sysdeps/pthread/Makefile ++++ b/sysdeps/pthread/Makefile +@@ -265,6 +265,7 @@ tests += \ + tst-spin2 \ + tst-spin3 \ + tst-spin4 \ ++ tst-spin5 \ + tst-stack1 \ + tst-stdio1 \ + tst-stdio2 \ +diff --git a/sysdeps/pthread/tst-spin5.c b/sysdeps/pthread/tst-spin5.c +new file mode 100644 +index 0000000000000000..5c23bd48ef27b3ce +--- /dev/null ++++ b/sysdeps/pthread/tst-spin5.c +@@ -0,0 +1,82 @@ ++/* Threaded test the pthread_spin_trylock function. ++ Copyright (C) 2024 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++pthread_spinlock_t lock; ++ ++void * ++thread (void *arg) ++{ ++ int ret; ++ int thr_id = *(int *) arg; ++ ++ ret = pthread_spin_trylock (&lock); ++ if (thr_id == 1) ++ /* thread with already acquired lock. */ ++ { ++ if (ret != EBUSY) ++ { ++ FAIL_EXIT1 ("pthread_spin_trylock should fail with EBUSY"); ++ } ++ } ++ else if (thr_id == 2) ++ /* thread with released spin lock. */ ++ { ++ if (ret != 0) ++ { ++ FAIL_EXIT1 ("pthread_spin_trylock should be able to acquire lock"); ++ } ++ } ++ return NULL; ++} ++ ++static int ++do_test (void) ++{ ++ pthread_t thr1, thr2; ++ int ret; ++ int thr1_id = 1, thr2_id = 2; ++ ++ pthread_spin_init (&lock, PTHREAD_PROCESS_PRIVATE); ++ /* lock spin in main thread. */ ++ ret = pthread_spin_trylock (&lock); ++ if (ret != 0) ++ { ++ FAIL_EXIT1 ("Main thread should be able to acquire spin lock"); ++ } ++ ++ /* create first thread to try locking already acquired spin lock. */ ++ thr1 = xpthread_create (NULL, thread, &thr1_id); ++ xpthread_join (thr1); ++ ++ /* release spin lock and create thread to acquire released spin lock. */ ++ pthread_spin_unlock (&lock); ++ thr2 = xpthread_create (NULL, thread, &thr2_id); ++ xpthread_join (thr2); ++ ++ pthread_spin_destroy (&lock); ++ return 0; ++} ++ ++#include diff --git a/glibc-RHEL-106562-19.patch b/glibc-RHEL-106562-19.patch new file mode 100644 index 0000000..0502db0 --- /dev/null +++ b/glibc-RHEL-106562-19.patch @@ -0,0 +1,575 @@ +commit 45c42b65c29422b773ac94771aa71165e245f8f8 +Author: Martin Coufal +Date: Thu Jan 23 13:04:06 2025 +0100 + + Add new tests for fopen + + Adding some basic tests for fopen, testing different modes, stream + positioning and concurrent read/write operation on files. + Reviewed-by: DJ Delorie + +diff --git a/stdio-common/Makefile b/stdio-common/Makefile +index 6b52fd3e0d818960..f44562df75cb98bc 100644 +--- a/stdio-common/Makefile ++++ b/stdio-common/Makefile +@@ -215,6 +215,7 @@ tests := \ + tst-fmemopen2 \ + tst-fmemopen3 \ + tst-fmemopen4 \ ++ tst-fopen \ + tst-fphex \ + tst-fphex-wide \ + tst-fread \ +diff --git a/stdio-common/tst-fopen.c b/stdio-common/tst-fopen.c +new file mode 100644 +index 0000000000000000..8c1fefd116f9f581 +--- /dev/null ++++ b/stdio-common/tst-fopen.c +@@ -0,0 +1,279 @@ ++/* Basic test for fopen. ++ Copyright (C) 2025 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#define APPENDED_TEXT "This is appended text. " ++#define DEFAULT_TEXT "Lorem ipsum dolor sit amet, consectetur " \ ++ "adipiscing elit, sed do eiusmod tempor incididunt ut labore et " \ ++ "dolore magna aliqua." ++#define MAX_BUFFER_SIZE 300 ++ ++ ++static int ++do_test (void) ++{ ++ char *temp_file; ++ FILE *fd_file = NULL; ++ char read_buffer[MAX_BUFFER_SIZE] = ""; ++ size_t ret; ++ ++ /* Prepare files. */ ++ int fd = create_temp_file ("tst-fopen.", &temp_file); ++ TEST_VERIFY_EXIT (fd != -1); ++ fd_file = fdopen (fd, "w"); ++ ret = fwrite (DEFAULT_TEXT, sizeof (char), strlen (DEFAULT_TEXT), fd_file); ++ TEST_COMPARE (ret, strlen (DEFAULT_TEXT)); ++ xfclose (fd_file); ++ ++ /* Test 1: This checks for fopen with mode "r". Open text file for ++ reading. The stream is positioned at the beginning of the file. */ ++ printf ("Test 1: This checks for fopen with mode \"r\".\n"); ++ fd_file = fopen (temp_file, "r"); ++ TEST_COMPARE (ferror (fd_file), 0); ++ TEST_VERIFY (fd_file != NULL); ++ TEST_COMPARE (ftell (fd_file), 0); ++ /* Read should succeed. */ ++ ret = fread (read_buffer, sizeof (char), MAX_BUFFER_SIZE, fd_file); ++ TEST_COMPARE (ferror (fd_file), 0); ++ TEST_COMPARE (ret, strlen (DEFAULT_TEXT)); ++ TEST_VERIFY (strcmp (read_buffer, DEFAULT_TEXT) == 0); ++ /* Write should fail. */ ++ errno = 0; ++ ret = fwrite (DEFAULT_TEXT, sizeof (char), strlen (DEFAULT_TEXT), fd_file); ++ TEST_VERIFY (ferror (fd_file) != 0); ++ TEST_COMPARE (errno, EBADF); ++ TEST_COMPARE (ret, 0); ++ clearerr (fd_file); ++ /* Opening non-existent file should fail. */ ++ xfclose (fd_file); ++ errno = 0; ++ fd_file = fopen ("file-that-does-not-exist", "r"); ++ TEST_VERIFY (fd_file == NULL); ++ TEST_COMPARE (errno, ENOENT); ++ TEST_VERIFY (fd_file == NULL); ++ ++ memset (read_buffer, 0, MAX_BUFFER_SIZE); ++ ++ /* Test 2: This checks for fopen with mode "r+". Open for reading and ++ writing. The stream is positioned at the beginning of the file. */ ++ printf ("Test 2: This checks for fopen with mode \"r+\".\n"); ++ fd_file = fopen (temp_file, "r+"); ++ TEST_COMPARE (ferror (fd_file), 0); ++ TEST_VERIFY (fd_file != NULL); ++ TEST_COMPARE (ftell (fd_file), 0); ++ /* Read should succeed. */ ++ ret = fread (read_buffer, sizeof (char), MAX_BUFFER_SIZE, fd_file); ++ TEST_COMPARE (ferror (fd_file), 0); ++ TEST_COMPARE (ret, strlen (DEFAULT_TEXT)); ++ TEST_VERIFY (strcmp (read_buffer, DEFAULT_TEXT) == 0); ++ fflush (fd_file); ++ /* File position indicator expected at 0 + read bytes. */ ++ TEST_COMPARE (ftell (fd_file), ret); ++ /* Write should succeed. */ ++ ret = fwrite (DEFAULT_TEXT, sizeof (char), strlen (DEFAULT_TEXT), fd_file); ++ TEST_COMPARE (ferror (fd_file), 0); ++ TEST_COMPARE (ret, strlen (DEFAULT_TEXT)); ++ /* Opening non-existent file should fail. */ ++ xfclose (fd_file); ++ errno = 0; ++ fd_file = fopen ("file-that-does-not-exist", "r+"); ++ TEST_VERIFY (fd_file == NULL); ++ TEST_COMPARE (errno, ENOENT); ++ TEST_VERIFY (fd_file == NULL); ++ ++ memset (read_buffer, 0, MAX_BUFFER_SIZE); ++ ++ /* Test 3: This checks for fopen with mode "w". Truncate file to zero ++ length or create text file for writing. The stream is positioned ++ at the beginning of the file. */ ++ printf ("Test 3: This checks for fopen with mode \"w\".\n"); ++ fd_file = fopen (temp_file, "w"); ++ TEST_COMPARE (ferror (fd_file), 0); ++ TEST_VERIFY (fd_file != NULL); ++ TEST_COMPARE (ftell (fd_file), 0); ++ /* Read should fail. */ ++ errno = 0; ++ ret = fread (read_buffer, sizeof (char), MAX_BUFFER_SIZE, fd_file); ++ TEST_VERIFY (ferror (fd_file) != 0); ++ TEST_COMPARE (errno, EBADF); ++ TEST_COMPARE (ret, 0); ++ clearerr (fd_file); ++ /* Write should succeed. */ ++ ret = fwrite (DEFAULT_TEXT, sizeof (char), strlen (DEFAULT_TEXT), fd_file); ++ TEST_COMPARE (ferror (fd_file), 0); ++ TEST_COMPARE (ret, strlen (DEFAULT_TEXT)); ++ /* Opening non-existent file should succeed. */ ++ xfclose (fd_file); ++ fd_file = fopen ("/tmp/file-that-does-not-exist", "w"); ++ TEST_COMPARE (ferror (fd_file), 0); ++ TEST_VERIFY (fd_file != NULL); ++ TEST_COMPARE (ftell (fd_file), 0); ++ ++ xfclose (fd_file); ++ remove ("/tmp/file-that-does-not-exist"); ++ memset (read_buffer, 0, MAX_BUFFER_SIZE); ++ ++ /* Test 4: This checks for fopen with mode "w+". Open for reading and ++ writing. The file is created if it does not exist, otherwise it is ++ truncated. The stream is positioned at the beginning of the file. ++ */ ++ printf ("Test 4: This checks for fopen with mode \"w+\".\n"); ++ fd_file = fopen (temp_file, "w+"); ++ TEST_COMPARE (ferror (fd_file), 0); ++ TEST_VERIFY (fd_file != NULL); ++ TEST_COMPARE (ftell (fd_file), 0); ++ /* Read should succeed. */ ++ ret = fread (read_buffer, sizeof (char), MAX_BUFFER_SIZE, fd_file); ++ TEST_COMPARE (ferror (fd_file), 0); ++ TEST_COMPARE (ret, 0); ++ TEST_VERIFY (read_buffer[0] == '\0'); ++ /* Write should succeed. */ ++ ret = fwrite (DEFAULT_TEXT, sizeof (char), strlen (DEFAULT_TEXT), fd_file); ++ TEST_COMPARE (ferror (fd_file), 0); ++ TEST_COMPARE (ret, strlen (DEFAULT_TEXT)); ++ /* Opening non-existent file should succeed. */ ++ xfclose (fd_file); ++ fd_file = fopen ("/tmp/file-that-does-not-exist", "w+"); ++ TEST_COMPARE (ferror (fd_file), 0); ++ TEST_VERIFY (fd_file != NULL); ++ TEST_COMPARE (ftell (fd_file), 0); ++ ++ xfclose (fd_file); ++ remove ("/tmp/file-that-does-not-exist"); ++ memset (read_buffer, 0, MAX_BUFFER_SIZE); ++ ++ /* Test 5: This checks for fopen with mode "a". Open for appending ++ (writing at end of file). The file is created if it does not ++ exist. The stream is positioned at the end of the file. */ ++ printf ("Test 5: This checks for fopen with mode \"a\".\n"); ++ fd_file = fopen (temp_file, "a"); ++ TEST_COMPARE (ferror (fd_file), 0); ++ TEST_VERIFY (fd_file != NULL); ++ TEST_COMPARE (ftell (fd_file), strlen (DEFAULT_TEXT)); ++ /* Read should fail. */ ++ errno = 0; ++ ret = fread (read_buffer, sizeof (char), MAX_BUFFER_SIZE, fd_file); ++ TEST_VERIFY (ferror (fd_file) != 0); ++ TEST_COMPARE (errno, EBADF); ++ TEST_COMPARE (ret, 0); ++ clearerr (fd_file); ++ /* Write should succeed. */ ++ ret = fwrite (APPENDED_TEXT, sizeof (char), strlen (APPENDED_TEXT), fd_file); ++ TEST_COMPARE (ferror (fd_file), 0); ++ TEST_COMPARE (ret, strlen (APPENDED_TEXT)); ++ /* The file position indicator for the stream is advanced by the ++ * number of bytes successfully read or written. */ ++ TEST_COMPARE (ftell (fd_file), strlen (DEFAULT_TEXT) + ret); ++ /* Opening non-existent file should succeed. */ ++ xfclose (fd_file); ++ fd_file = fopen ("/tmp/file-that-does-not-exist", "a"); ++ TEST_COMPARE (ferror (fd_file), 0); ++ TEST_VERIFY (fd_file != NULL); ++ TEST_COMPARE (ftell (fd_file), 0); ++ ++ xfclose (fd_file); ++ remove ("/tmp/file-that-does-not-exist"); ++ memset (read_buffer, 0, MAX_BUFFER_SIZE); ++ ++ /* Test 6: This checks for fopen with mode "a+". Open for reading and ++ appending (writing at end of file). The file is created if it does ++ not exist. Output is always appended to the end of the file. The ++ initial file position for reading is at the beginning of the file, ++ but it is advanced to the end prior to each write. */ ++ printf ("Test 6: This checks for fopen with mode \"a+\".\n"); ++ errno = 0; ++ fd_file = fopen (temp_file, "a+"); ++ TEST_COMPARE (errno, 0); ++ TEST_VERIFY (fd_file != NULL); ++ TEST_COMPARE (ftell (fd_file), 0); ++ /* Read should succeed. */ ++ ret = fread (read_buffer, sizeof (char), MAX_BUFFER_SIZE, fd_file); ++ TEST_COMPARE (ferror (fd_file), 0); ++ TEST_COMPARE (ret, strlen (DEFAULT_TEXT) + strlen (APPENDED_TEXT)); ++ TEST_VERIFY (strcmp (read_buffer, DEFAULT_TEXT APPENDED_TEXT) == 0); ++ /* Write should succeed. */ ++ const char* SECOND_APPEND = "This is second append."; ++ ret = fwrite (SECOND_APPEND, sizeof (char), strlen (SECOND_APPEND), fd_file); ++ TEST_COMPARE (ferror (fd_file), 0); ++ TEST_COMPARE (ret, strlen (SECOND_APPEND)); ++ /* The file position indicator for the stream is advanced by the ++ number of bytes successfully read or written. */ ++ TEST_COMPARE (ftell (fd_file), ++ strlen (DEFAULT_TEXT) + strlen (APPENDED_TEXT) + ret); ++ /* Opening non-existent file should succeed. */ ++ xfclose (fd_file); ++ fd_file = fopen ("/tmp/file-that-does-not-exist", "a+"); ++ TEST_COMPARE (ferror (fd_file), 0); ++ TEST_VERIFY (fd_file != NULL); ++ TEST_COMPARE (ftell (fd_file), 0); ++ ++ xfclose (fd_file); ++ remove ("/tmp/file-that-does-not-exist"); ++ memset (read_buffer, 0, MAX_BUFFER_SIZE); ++ ++ /* Test 7: This checks for fopen with other valid modes set, such as ++ "rc", "we" or "am". The test calls fopen with these modes and ++ checks that no errors appear. */ ++ printf ("Test 7: This checks for fopen with other valid modes set, " ++ "such as \"rc\", \"we\" or \"am\".\n"); ++ /* These modes all operate correctly with the file already present. */ ++ static const char *valid_modes[] = ++ { "rc", "we", "am", "r+x", "wb+", "ab", 0 }; ++ const char **p = valid_modes; ++ while (*p != 0) ++ { ++ fd_file = fopen (temp_file, *p); ++ TEST_COMPARE (ferror (fd_file), 0); ++ TEST_VERIFY (fd_file != NULL); ++ xfclose (fd_file); ++ ++p; ++ } ++ ++ /* Test 8: This checks for fopen with invalid modes. The test calls ++ fopen with these modes and checks that opening existing files with ++ invalid mode fails and that opening non-existing files with invalid ++ mode doesn't create a new file. */ ++ printf ("Test 8: This checks for fopen with invalid modes.\n"); ++ static const char *invalid_modes[] = { "0", "tr", "z", "x", " ", 0 }; ++ p = invalid_modes; ++ while (*p != 0) ++ { ++ errno = 0; ++ fd_file = fopen (temp_file, *p); ++ TEST_VERIFY (fd_file == NULL); ++ TEST_COMPARE (errno, EINVAL); ++ errno = 0; ++ fd_file = fopen ("/tmp/file-that-does-not-exist", *p); ++ TEST_VERIFY (fd_file == NULL); ++ TEST_COMPARE (errno, EINVAL); ++ ++p; ++ TEST_VERIFY (access ("/tmp/file-that-does-not-exist", F_OK) == -1); ++ } ++ ++ return 0; ++} ++ ++#include +diff --git a/sysdeps/pthread/Makefile b/sysdeps/pthread/Makefile +index 8c80b7a606da4c94..ef3035cea8e1344b 100644 +--- a/sysdeps/pthread/Makefile ++++ b/sysdeps/pthread/Makefile +@@ -154,6 +154,7 @@ tests += \ + tst-exit3 \ + tst-flock1 \ + tst-flock2 \ ++ tst-fopen-threaded \ + tst-fork1 \ + tst-fork2 \ + tst-fork3 \ +diff --git a/sysdeps/pthread/tst-fopen-threaded.c b/sysdeps/pthread/tst-fopen-threaded.c +new file mode 100644 +index 0000000000000000..5c792c93e3711621 +--- /dev/null ++++ b/sysdeps/pthread/tst-fopen-threaded.c +@@ -0,0 +1,250 @@ ++/* Test for fread and fwrite with multiple threads. ++ Copyright (C) 2025 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 ++ . */ ++ ++/* Description of test intent. ++ The test creates NUM_THREADS threads for reading and writing to the ++ prepared file. The prepared file contains 'NUM_THREADS - 1' bytes ++ where each byte is unique number from 0 to 'NUM_THREADS - 2'. If all ++ operations are correctly multi-threaded safe then all concurent read ++ operations should succeed and read a unique 1 byte value. The last ++ thread to read should get an EOF. In concurrent write, all write ++ operations should succeed and the file should contain all unique 1 ++ byte values from 0 to 'NUM_THREADS - 1'. Both concurrent read and ++ concurrent write tests are repeated ITERS times to increase ++ the probability of detecting concurrency issues. */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#define NUM_THREADS 100 ++#define ITERS 10 ++ ++char *temp_file; ++pthread_barrier_t barrier; ++ ++struct thread_data ++{ ++ FILE *fd; ++ /* Read value or value to be written. */ ++ unsigned char value; ++ bool eof; ++}; ++ ++static void * ++threadReadRoutine (void *argv) ++{ ++ struct thread_data *my_data; ++ unsigned char read_buffer; ++ int ret = 0; ++ my_data = (struct thread_data *) argv; ++ /* Wait for all threads to be ready to read. */ ++ xpthread_barrier_wait (&barrier); ++ ++ ret = ++ fread (&read_buffer, sizeof (char), sizeof (read_buffer), my_data->fd); ++ if (feof (my_data->fd) != 0) ++ { ++ clearerr (my_data->fd); ++ my_data->eof = true; ++ } ++ else ++ { ++ TEST_COMPARE (ret, 1); ++ /* Save the read value. */ ++ my_data->value = read_buffer; ++ } ++ TEST_COMPARE (ferror (my_data->fd), 0); ++ return NULL; ++} ++ ++void * ++threadWriteRoutine (void *argv) ++{ ++ struct thread_data *my_data; ++ int ret = 0; ++ my_data = (struct thread_data *) argv; ++ /* Wait for all threads to be ready to write. */ ++ xpthread_barrier_wait (&barrier); ++ ++ ret = fwrite (&my_data->value, sizeof (unsigned char), 1, my_data->fd); ++ TEST_COMPARE (ferror (my_data->fd), 0); ++ TEST_COMPARE (feof (my_data->fd), 0); ++ TEST_COMPARE (ret, 1); ++ return NULL; ++} ++ ++void * ++threadOpenCloseRoutine (void *argv) ++{ ++ /* Wait for all threads to be ready to call fopen and fclose. */ ++ xpthread_barrier_wait (&barrier); ++ ++ FILE *fd = xfopen ("/tmp/openclosetest", "w+"); ++ xfclose (fd); ++ return NULL; ++} ++ ++static int ++do_test (void) ++{ ++ FILE *fd_file = NULL; ++ unsigned char buffer[NUM_THREADS] = "0"; ++ size_t ret = 0; ++ pthread_t threads[NUM_THREADS]; ++ struct thread_data thread_data_array[NUM_THREADS]; ++ bool present_values[NUM_THREADS] = { false }; ++ ++ /* Prepare files. */ ++ for (int i = 0; i < NUM_THREADS; i++) ++ buffer[i] = i; ++ int fd = create_temp_file ("tst-fopen.", &temp_file); ++ TEST_VERIFY_EXIT (fd != -1); ++ fd_file = fdopen (fd, "w"); ++ /* NUM_THREADS - 1: last thread will read EOF */ ++ ret = fwrite (buffer, sizeof (unsigned char), NUM_THREADS - 1, fd_file); ++ TEST_COMPARE (ret, NUM_THREADS - 1); ++ xfclose (fd_file); ++ ++ /* Test 1: Concurrent read. */ ++ for (int reps = 1; reps <= ITERS; reps++) ++ { ++ fd_file = xfopen (temp_file, "r"); ++ xpthread_barrier_init (&barrier, NULL, NUM_THREADS); ++ for (int i = 0; i < NUM_THREADS; i++) ++ { ++ thread_data_array[i].fd = fd_file; ++ /* Initialize with highest possible value so it's easier to debug if ++ anything goes wrong. */ ++ thread_data_array[i].value = 255; ++ thread_data_array[i].eof = false; ++ ++ threads[i] = ++ xpthread_create (support_small_stack_thread_attribute (), ++ threadReadRoutine, ++ (void *) &thread_data_array[i]); ++ } ++ ++ for (int i = 0; i < NUM_THREADS; i++) ++ { ++ xpthread_join (threads[i]); ++ } ++ xpthread_barrier_destroy (&barrier); ++ xfclose (fd_file); ++ ++ /* Verify read values. */ ++ int eof_cnt = 0; ++ for (int i = 0; i < NUM_THREADS; i++) ++ present_values[i] = false; ++ for (int i = 0; i < NUM_THREADS; i++) ++ { ++ if (thread_data_array[i].eof) ++ { ++ /* EOF was read. */ ++ present_values[NUM_THREADS - 1] = true; ++ eof_cnt++; ++ } ++ else ++ { ++ /* The same value shouldn't be read twice. */ ++ TEST_VERIFY (!present_values[thread_data_array[i].value]); ++ present_values[thread_data_array[i].value] = true; ++ } ++ } ++ /* EOF is read exactly once. */ ++ TEST_COMPARE (eof_cnt, 1); ++ for (int i = 0; i < NUM_THREADS; i++) ++ { ++ /* All values should be read. */ ++ TEST_VERIFY (present_values[i]); ++ } ++ } ++ ++ /* Test 2: Concurrent write. */ ++ for (int reps = 1; reps <= ITERS; reps++) ++ { ++ fd_file = xfopen (temp_file, "w"); ++ xpthread_barrier_init (&barrier, NULL, NUM_THREADS); ++ for (int i = 0; i < NUM_THREADS; i++) ++ { ++ thread_data_array[i].fd = fd_file; ++ thread_data_array[i].value = i; ++ ++ threads[i] = ++ xpthread_create (support_small_stack_thread_attribute (), ++ threadWriteRoutine, ++ (void *) &thread_data_array[i]); ++ } ++ ++ for (int i = 0; i < NUM_THREADS; i++) ++ { ++ xpthread_join (threads[i]); ++ } ++ xpthread_barrier_destroy (&barrier); ++ xfclose (fd_file); ++ ++ /* Verify written values. */ ++ for (int i = 0; i < NUM_THREADS; i++) ++ present_values[i] = false; ++ memset (buffer, 0, NUM_THREADS); ++ fd_file = xfopen (temp_file, "r"); ++ ret = fread (buffer, sizeof (unsigned char), NUM_THREADS, fd_file); ++ TEST_COMPARE (ret, NUM_THREADS); ++ for (int i = 0; i < NUM_THREADS; i++) ++ { ++ /* The same value shouldn't be written twice. */ ++ TEST_VERIFY (!present_values[buffer[i]]); ++ present_values[buffer[i]] = true; ++ } ++ for (int i = 0; i < NUM_THREADS; i++) ++ { ++ /* All values should be written. */ ++ TEST_VERIFY (present_values[i]); ++ } ++ xfclose (fd_file); ++ } ++ ++ /* Test 3: Concurrent open/close. */ ++ for (int reps = 1; reps <= ITERS; reps++) ++ { ++ xpthread_barrier_init (&barrier, NULL, NUM_THREADS); ++ for (int i = 0; i < NUM_THREADS; i++) ++ { ++ threads[i] = ++ xpthread_create (support_small_stack_thread_attribute (), ++ threadOpenCloseRoutine, NULL); ++ } ++ for (int i = 0; i < NUM_THREADS; i++) ++ { ++ xpthread_join (threads[i]); ++ } ++ xpthread_barrier_destroy (&barrier); ++ } ++ ++ return 0; ++} ++ ++#include diff --git a/glibc-RHEL-106562-2.patch b/glibc-RHEL-106562-2.patch new file mode 100644 index 0000000..1ea5b60 --- /dev/null +++ b/glibc-RHEL-106562-2.patch @@ -0,0 +1,529 @@ +commit ae18044f95271ed422ed847bd8d8c6d8e84674ce +Author: Joe Simmons-Talbott +Date: Mon May 20 14:09:35 2024 +0000 + + math: Add more details to the test driver output. + + Add start and end indicators that identify the test being run in the + verbose output. Better identify the tests for max errors in the + summary output. Count each exception checked for each test. Remove + double counting of tests for the check_ functions other than + check_float_internal. Rename print_max_error and + print_complex_max_error to check_max_error and check_complex_max_error + respectively since they have side effects. + + Co-Authored-By: Carlos O'Donell + Reviewed-By: Joseph Myers + +diff --git a/math/libm-test-driver.c b/math/libm-test-driver.c +index 3356f9b10d7f364e..dfb56e8cde13519a 100644 +--- a/math/libm-test-driver.c ++++ b/math/libm-test-driver.c +@@ -1083,9 +1083,9 @@ struct test_Ff_b1_data + = STR_CON3 (FUN, SUFF, TEST_SUFF) TEST_SUFF_STR; \ + init_max_error (this_func, EXACT, TEST_COND_any_ibm128) + #define END \ +- print_max_error (this_func) ++ check_max_error (this_func) + #define END_COMPLEX \ +- print_complex_max_error (this_func) ++ check_complex_max_error (this_func) + + /* Run tests for a given function in all rounding modes. */ + #define ALL_RM_TEST(FUNC, EXACT, ARRAY, LOOP_MACRO, END_MACRO, ...) \ +diff --git a/math/libm-test-support.c b/math/libm-test-support.c +index 0cae545f86ac1352..0796f9d4956e3818 100644 +--- a/math/libm-test-support.c ++++ b/math/libm-test-support.c +@@ -112,6 +112,7 @@ + #include + #include + #include ++#include + + /* This header defines func_ulps, func_real_ulps and func_imag_ulps + arrays. */ +@@ -125,10 +126,13 @@ static FILE *ulps_file; /* File to document difference. */ + static int output_ulps; /* Should ulps printed? */ + static char *output_dir; /* Directory where generated files will be written. */ + +-static int noErrors; /* number of errors */ +-static int noTests; /* number of tests (without testing exceptions) */ +-static int noExcTests; /* number of tests for exception flags */ +-static int noErrnoTests;/* number of tests for errno values */ ++#define TEST_INPUT 1 ++#define TEST_MAXERROR 2 ++static int noErrors; /* number of errors */ ++static int noTests; /* number of tests (without testing exceptions) */ ++static int noMaxErrorTests; /* number of max error tests */ ++static int noExcTests; /* number of tests for exception flags */ ++static int noErrnoTests; /* number of tests for errno values */ + + static unsigned int verbose; + static int output_max_error; /* Should the maximal errors printed? */ +@@ -299,9 +303,19 @@ print_screen_max_error (int ok) + + /* Update statistic counters. */ + static void +-update_stats (int ok) ++update_stats (int ok, int testType) + { +- ++noTests; ++ switch (testType) ++ { ++ case TEST_INPUT: ++ ++noTests; ++ break; ++ case TEST_MAXERROR: ++ ++noMaxErrorTests; ++ break; ++ default: ++ abort(); ++ } + if (!ok) + ++noErrors; + } +@@ -367,11 +381,30 @@ fpstack_test (const char *test_name) + #endif + } + ++static void ++print_test_start (int test_num, const char *test_name, int test_type) ++{ ++ if (print_screen (1)) ++ printf ("--- Start of%s test # %d, named \"%s\" ---\n", ++ test_type == TEST_MAXERROR ? " max error" : "", test_num, test_name); ++} + ++static void ++print_test_end (int test_num, const char *test_name, int test_type) ++{ ++ if (print_screen (1)) ++ printf ("--- End of%s test # %d, named \"%s\" ---\n", ++ test_type == TEST_MAXERROR ? " max error" : "", test_num, test_name); ++} ++ ++/* This is a builtin test of overall max error. */ + void +-print_max_error (const char *func_name) ++check_max_error (const char *func_name) + { + int ok = 0; ++ int thisTest = noMaxErrorTests; ++ ++ print_test_start (thisTest, func_name, TEST_MAXERROR); + + if (max_error == 0.0 || (max_error <= prev_max_error && !ignore_max_ulp)) + { +@@ -392,14 +425,19 @@ print_max_error (const char *func_name) + printf (" accepted: %s ulp\n", pmestr); + } + +- update_stats (ok); +-} ++ update_stats (ok, TEST_MAXERROR); + ++ print_test_end (thisTest, func_name, TEST_MAXERROR); ++} + ++/* This is a builtin test of overall max error. */ + void +-print_complex_max_error (const char *func_name) ++check_complex_max_error (const char *func_name) + { + int real_ok = 0, imag_ok = 0, ok; ++ int thisTest = noMaxErrorTests; ++ ++ print_test_start (thisTest, func_name, TEST_MAXERROR); + + if (real_max_error == 0 + || (real_max_error <= prev_real_max_error && !ignore_max_ulp)) +@@ -436,7 +474,8 @@ print_complex_max_error (const char *func_name) + printf (" accepted: %s ulp\n", pimestr); + } + +- update_stats (ok); ++ update_stats (ok, TEST_MAXERROR); ++ print_test_end (thisTest, func_name, TEST_MAXERROR); + } + + +@@ -477,12 +516,13 @@ test_single_exception (const char *test_name, + else + { + if (print_screen (1)) +- printf ("%s: Exception \"%s\" not set\n", test_name, ++ printf ("Pass: %s: Exception \"%s\" not set\n", test_name, + flag_name); + } + } + if (!ok) + ++noErrors; ++ ++noExcTests; + } + #endif + +@@ -494,23 +534,32 @@ test_exceptions (const char *test_name, int exception) + { + if (flag_test_exceptions && EXCEPTION_TESTS (FLOAT)) + { +- ++noExcTests; ++ int ran = 0; + #ifdef FE_DIVBYZERO + if ((exception & DIVIDE_BY_ZERO_EXCEPTION_OK) == 0) +- test_single_exception (test_name, exception, +- DIVIDE_BY_ZERO_EXCEPTION, FE_DIVBYZERO, +- "Divide by zero"); ++ { ++ test_single_exception (test_name, exception, ++ DIVIDE_BY_ZERO_EXCEPTION, FE_DIVBYZERO, ++ "Divide by zero"); ++ ran = 1; ++ } + #endif + #ifdef FE_INVALID + if ((exception & INVALID_EXCEPTION_OK) == 0) +- test_single_exception (test_name, exception, +- INVALID_EXCEPTION, FE_INVALID, +- "Invalid operation"); ++ { ++ test_single_exception (test_name, exception, ++ INVALID_EXCEPTION, FE_INVALID, ++ "Invalid operation"); ++ ran = 1; ++ } + #endif + #ifdef FE_OVERFLOW + if ((exception & OVERFLOW_EXCEPTION_OK) == 0) +- test_single_exception (test_name, exception, OVERFLOW_EXCEPTION, +- FE_OVERFLOW, "Overflow"); ++ { ++ test_single_exception (test_name, exception, OVERFLOW_EXCEPTION, ++ FE_OVERFLOW, "Overflow"); ++ ran = 1; ++ } + #endif + /* Spurious "underflow" and "inexact" exceptions are always + allowed for IBM long double, in line with the underlying +@@ -519,17 +568,30 @@ test_exceptions (const char *test_name, int exception) + if ((exception & UNDERFLOW_EXCEPTION_OK) == 0 + && !(test_ibm128 + && (exception & UNDERFLOW_EXCEPTION) == 0)) +- test_single_exception (test_name, exception, UNDERFLOW_EXCEPTION, +- FE_UNDERFLOW, "Underflow"); ++ { ++ test_single_exception (test_name, exception, UNDERFLOW_EXCEPTION, ++ FE_UNDERFLOW, "Underflow"); ++ ran = 1; ++ } ++ + #endif + #ifdef FE_INEXACT + if ((exception & (INEXACT_EXCEPTION | NO_INEXACT_EXCEPTION)) != 0 + && !(test_ibm128 + && (exception & NO_INEXACT_EXCEPTION) != 0)) +- test_single_exception (test_name, exception, INEXACT_EXCEPTION, +- FE_INEXACT, "Inexact"); ++ { ++ test_single_exception (test_name, exception, INEXACT_EXCEPTION, ++ FE_INEXACT, "Inexact"); ++ ran = 1; ++ } + #endif ++ assert (ran == 1); + } ++ else ++ { ++ if (print_screen (1)) ++ printf ("Info: %s: No exceptions tested\n", test_name); ++ } + feclearexcept (FE_ALL_EXCEPT); + } + +@@ -552,6 +614,7 @@ test_single_errno (const char *test_name, int errno_value, + printf ("Failure: %s: errno set to %d, expected %d (%s)\n", + test_name, errno_value, expected_value, expected_name); + } ++ ++noErrnoTests; + } + + /* Test whether errno (value ERRNO_VALUE) has been for TEST_NAME set +@@ -561,13 +624,39 @@ test_errno (const char *test_name, int errno_value, int exceptions) + { + if (flag_test_errno) + { +- ++noErrnoTests; ++ int ran = 0; ++ ++ if ((exceptions & (ERRNO_UNCHANGED|ERRNO_EDOM|ERRNO_ERANGE)) == 0) ++ { ++ if (print_screen (1)) ++ printf ("Info: %s: The value of errno was not tested\n", ++ test_name); ++ return; ++ } ++ ++ + if (exceptions & ERRNO_UNCHANGED) +- test_single_errno (test_name, errno_value, 0, "unchanged"); ++ { ++ test_single_errno (test_name, errno_value, 0, "unchanged"); ++ ran = 1; ++ } + if (exceptions & ERRNO_EDOM) +- test_single_errno (test_name, errno_value, EDOM, "EDOM"); ++ { ++ test_single_errno (test_name, errno_value, EDOM, "EDOM"); ++ ran = 1; ++ } + if (exceptions & ERRNO_ERANGE) +- test_single_errno (test_name, errno_value, ERANGE, "ERANGE"); ++ { ++ test_single_errno (test_name, errno_value, ERANGE, "ERANGE"); ++ ran = 1; ++ } ++ ++ assert (ran == 1); ++ } ++ else ++ { ++ if (print_screen (1)) ++ printf ("Info: %s: No errno tests\n", test_name); + } + } + +@@ -619,6 +708,9 @@ check_float_internal (const char *test_name, FLOAT computed, FLOAT expected, + FLOAT diff = 0; + FLOAT ulps = 0; + int errno_value = errno; ++ int thisTest = noTests; ++ ++ print_test_start (thisTest, test_name, TEST_INPUT); + + test_exceptions (test_name, exceptions); + test_errno (test_name, errno_value, exceptions); +@@ -716,12 +808,13 @@ check_float_internal (const char *test_name, FLOAT computed, FLOAT expected, + printf (" max.ulp : %s\n", mustrn); + } + } +- update_stats (ok); ++ update_stats (ok, TEST_INPUT); + + out: + fpstack_test (test_name); + feclearexcept (FE_ALL_EXCEPT); + errno = 0; ++ print_test_end (thisTest, test_name, TEST_INPUT); + } + + +@@ -776,12 +869,14 @@ check_int (const char *test_name, int computed, int expected, + { + int ok = 0; + int errno_value = errno; ++ int thisTest = noTests; ++ ++ print_test_start (thisTest, test_name, TEST_INPUT); + + test_exceptions (test_name, exceptions); + test_errno (test_name, errno_value, exceptions); + if (exceptions & IGNORE_RESULT) + goto out; +- noTests++; + if (computed == expected) + ok = 1; + +@@ -795,11 +890,12 @@ check_int (const char *test_name, int computed, int expected, + printf (" should be: %d\n", expected); + } + +- update_stats (ok); ++ update_stats (ok, TEST_INPUT); + out: + fpstack_test (test_name); + feclearexcept (FE_ALL_EXCEPT); + errno = 0; ++ print_test_end (thisTest, test_name, TEST_INPUT); + } + + +@@ -810,12 +906,14 @@ check_long (const char *test_name, long int computed, long int expected, + { + int ok = 0; + int errno_value = errno; ++ int thisTest = noTests; ++ ++ print_test_start (thisTest, test_name, TEST_INPUT); + + test_exceptions (test_name, exceptions); + test_errno (test_name, errno_value, exceptions); + if (exceptions & IGNORE_RESULT) + goto out; +- noTests++; + if (computed == expected) + ok = 1; + +@@ -829,11 +927,12 @@ check_long (const char *test_name, long int computed, long int expected, + printf (" should be: %ld\n", expected); + } + +- update_stats (ok); ++ update_stats (ok, TEST_INPUT); + out: + fpstack_test (test_name); + feclearexcept (FE_ALL_EXCEPT); + errno = 0; ++ print_test_end (thisTest, test_name, TEST_INPUT); + } + + +@@ -844,12 +943,14 @@ check_bool (const char *test_name, int computed, int expected, + { + int ok = 0; + int errno_value = errno; ++ int thisTest = noTests; ++ ++ print_test_start (thisTest, test_name, TEST_INPUT); + + test_exceptions (test_name, exceptions); + test_errno (test_name, errno_value, exceptions); + if (exceptions & IGNORE_RESULT) + goto out; +- noTests++; + if ((computed == 0) == (expected == 0)) + ok = 1; + +@@ -863,11 +964,12 @@ check_bool (const char *test_name, int computed, int expected, + printf (" should be: %d\n", expected); + } + +- update_stats (ok); ++ update_stats (ok, TEST_INPUT); + out: + fpstack_test (test_name); + feclearexcept (FE_ALL_EXCEPT); + errno = 0; ++ print_test_end (thisTest, test_name, TEST_INPUT); + } + + +@@ -879,12 +981,14 @@ check_longlong (const char *test_name, long long int computed, + { + int ok = 0; + int errno_value = errno; ++ int thisTest = noTests; ++ ++ print_test_start (thisTest, test_name, TEST_INPUT); + + test_exceptions (test_name, exceptions); + test_errno (test_name, errno_value, exceptions); + if (exceptions & IGNORE_RESULT) + goto out; +- noTests++; + if (computed == expected) + ok = 1; + +@@ -898,11 +1002,12 @@ check_longlong (const char *test_name, long long int computed, + printf (" should be: %lld\n", expected); + } + +- update_stats (ok); ++ update_stats (ok, TEST_INPUT); + out: + fpstack_test (test_name); + feclearexcept (FE_ALL_EXCEPT); + errno = 0; ++ print_test_end (thisTest, test_name, TEST_INPUT); + } + + +@@ -913,12 +1018,14 @@ check_intmax_t (const char *test_name, intmax_t computed, + { + int ok = 0; + int errno_value = errno; ++ int thisTest = noTests; ++ ++ print_test_start (thisTest, test_name, TEST_INPUT); + + test_exceptions (test_name, exceptions); + test_errno (test_name, errno_value, exceptions); + if (exceptions & IGNORE_RESULT) + goto out; +- noTests++; + if (computed == expected) + ok = 1; + +@@ -932,11 +1039,12 @@ check_intmax_t (const char *test_name, intmax_t computed, + printf (" should be: %jd\n", expected); + } + +- update_stats (ok); ++ update_stats (ok, TEST_INPUT); + out: + fpstack_test (test_name); + feclearexcept (FE_ALL_EXCEPT); + errno = 0; ++ print_test_end (thisTest, test_name, TEST_INPUT); + } + + +@@ -947,12 +1055,14 @@ check_uintmax_t (const char *test_name, uintmax_t computed, + { + int ok = 0; + int errno_value = errno; ++ int thisTest = noTests; ++ ++ print_test_start (thisTest, test_name, TEST_INPUT); + + test_exceptions (test_name, exceptions); + test_errno (test_name, errno_value, exceptions); + if (exceptions & IGNORE_RESULT) + goto out; +- noTests++; + if (computed == expected) + ok = 1; + +@@ -966,11 +1076,12 @@ check_uintmax_t (const char *test_name, uintmax_t computed, + printf (" should be: %ju\n", expected); + } + +- update_stats (ok); ++ update_stats (ok, TEST_INPUT); + out: + fpstack_test (test_name); + feclearexcept (FE_ALL_EXCEPT); + errno = 0; ++ print_test_end (thisTest, test_name, TEST_INPUT); + } + + /* Return whether a test with flags EXCEPTIONS should be run. */ +@@ -1211,9 +1322,11 @@ libm_test_finish (void) + fclose (ulps_file); + + printf ("\nTest suite completed:\n"); +- printf (" %d test cases plus %d tests for exception flags and\n" +- " %d tests for errno executed.\n", +- noTests, noExcTests, noErrnoTests); ++ printf (" %d max error test cases,\n", noMaxErrorTests); ++ printf (" %d input tests,\n", noTests); ++ printf (" - with %d tests for exception flags,\n", noExcTests); ++ printf (" - with %d tests for errno executed.\n", noErrnoTests); ++ + if (noErrors) + { + printf (" %d errors occurred.\n", noErrors); +diff --git a/math/libm-test-support.h b/math/libm-test-support.h +index 8baf7e1817157b2a..efb9523e9e91f64f 100644 +--- a/math/libm-test-support.h ++++ b/math/libm-test-support.h +@@ -170,8 +170,8 @@ extern const char doc[]; + + int enable_test (int); + void init_max_error (const char *, int, int); +-void print_max_error (const char *); +-void print_complex_max_error (const char *); ++void check_max_error (const char *); ++void check_complex_max_error (const char *); + void check_float (const char *, FLOAT, FLOAT, int); + void check_complex (const char *, CFLOAT, CFLOAT, int); + void check_int (const char *, int, int, int); diff --git a/glibc-RHEL-106562-20.patch b/glibc-RHEL-106562-20.patch new file mode 100644 index 0000000..e4ca16c --- /dev/null +++ b/glibc-RHEL-106562-20.patch @@ -0,0 +1,151 @@ +commit a9017caff3b77032d04e2e439f7c04a63241e63e +Author: Sergey Kolosov +Date: Tue Jan 28 23:56:26 2025 +0100 + + nptl: extend test coverage for sched_yield + + We add sched_yield() API testing to the existing thread affinity + test case because it allows us to test sched_yield() operation + in the following scenarios: + + * On a main thread. + * On multiple threads simultaneously. + * On every CPU the system reports simultaneously. + + The ensures we exercise sched_yield() in as many scenarios as + we would exercise calls to the affinity functions. + + Additionally, the test is improved by adding a semaphore to coordinate + all the threads running, so that an early starter thread won't consume + cpu resources that could be used to start the other threads. + + Co-authored-by: DJ Delorie + Reviewed-by: Carlos O'Donell + +diff --git a/sysdeps/unix/sysv/linux/tst-skeleton-affinity.c b/sysdeps/unix/sysv/linux/tst-skeleton-affinity.c +index 2f921ed397a1a4d9..7276fd8fef06d620 100644 +--- a/sysdeps/unix/sysv/linux/tst-skeleton-affinity.c ++++ b/sysdeps/unix/sysv/linux/tst-skeleton-affinity.c +@@ -38,6 +38,7 @@ + #include + #include + #include ++#include + + /* CPU set configuration determined. Can be used from early_test. */ + struct conf +@@ -253,12 +254,12 @@ do_test (void) + if (getaffinity (sizeof (set), &set) < 0 && errno == ENOSYS) + { + puts ("warning: getaffinity not supported, test cannot run"); +- return 0; ++ return EXIT_UNSUPPORTED; + } + if (sched_getcpu () < 0 && errno == ENOSYS) + { + puts ("warning: sched_getcpu not supported, test cannot run"); +- return 0; ++ return EXIT_UNSUPPORTED; + } + } + +diff --git a/sysdeps/unix/sysv/linux/tst-skeleton-thread-affinity.c b/sysdeps/unix/sysv/linux/tst-skeleton-thread-affinity.c +index 5a1e84431a30132d..507c5c94ba89e47b 100644 +--- a/sysdeps/unix/sysv/linux/tst-skeleton-thread-affinity.c ++++ b/sysdeps/unix/sysv/linux/tst-skeleton-thread-affinity.c +@@ -45,10 +45,14 @@ static int still_running; + /* 0 if no scheduling failures, 1 if failures are encountered. */ + static int failed; + ++/* Used to synchronize the threads. */ ++static pthread_barrier_t barrier; ++ + static void * + thread_burn_one_cpu (void *closure) + { + int cpu = (uintptr_t) closure; ++ xpthread_barrier_wait (&barrier); + while (__atomic_load_n (&still_running, __ATOMIC_RELAXED) == 0) + { + int current = sched_getcpu (); +@@ -61,6 +65,11 @@ thread_burn_one_cpu (void *closure) + __atomic_store_n (&still_running, 1, __ATOMIC_RELAXED); + } + } ++ if (sched_yield () != 0) ++ { ++ printf ("error: sched_yield() failed for cpu %d\n", cpu); ++ __atomic_store_n (&failed, 1, __ATOMIC_RELAXED); ++ } + return NULL; + } + +@@ -78,6 +87,7 @@ thread_burn_any_cpu (void *closure) + { + struct burn_thread *param = closure; + ++ xpthread_barrier_wait (&barrier); + /* Schedule this thread around a bit to see if it lands on another + CPU. Run this for 2 seconds, once with sched_yield, once + without. */ +@@ -99,7 +109,11 @@ thread_burn_any_cpu (void *closure) + CPU_SET_S (cpu, CPU_ALLOC_SIZE (param->conf->set_size), + param->seen_set); + if (pass == 1) +- sched_yield (); ++ if (sched_yield () != 0) ++ { ++ printf ("error: sched_yield() failed for cpu %d\n", cpu); ++ __atomic_store_n (&failed, 1, __ATOMIC_RELAXED); ++ } + } + } + return NULL; +@@ -156,6 +170,7 @@ early_test (struct conf *conf) + = calloc (conf->last_cpu + 1, sizeof (*other_threads)); + cpu_set_t *initial_set = CPU_ALLOC (conf->set_size); + cpu_set_t *scratch_set = CPU_ALLOC (conf->set_size); ++ int num_available_cpus = 0; + + if (pinned_threads == NULL || other_threads == NULL + || initial_set == NULL || scratch_set == NULL) +@@ -172,6 +187,7 @@ early_test (struct conf *conf) + { + if (!CPU_ISSET_S (cpu, CPU_ALLOC_SIZE (conf->set_size), initial_set)) + continue; ++ num_available_cpus ++; + other_threads[cpu].conf = conf; + other_threads[cpu].initial_set = initial_set; + other_threads[cpu].thread = cpu; +@@ -194,6 +210,15 @@ early_test (struct conf *conf) + } + support_set_small_thread_stack_size (&attr); + ++ /* This count assumes that all the threads below are created ++ successfully, and call pthread_barrier_wait(). If any threads ++ fail to be created, this function will return FALSE (failure) and ++ the waiting threads will eventually time out the whole test. ++ This is acceptable because we're not testing thread creation and ++ assume all threads will be created, and failure here implies a ++ failure outside the test's scope. */ ++ xpthread_barrier_init (&barrier, NULL, num_available_cpus * 2 + 1); ++ + /* Spawn a thread pinned to each available CPU. */ + for (int cpu = 0; cpu <= conf->last_cpu; ++cpu) + { +@@ -245,6 +270,15 @@ early_test (struct conf *conf) + } + } + ++ /* Test that sched_yield() works correctly in the main thread. This ++ also gives the kernel an opportunity to run the other threads, ++ randomizing thread startup a bit. */ ++ if (sched_yield () != 0) ++ { ++ printf ("error: sched_yield() failed for main thread\n"); ++ __atomic_store_n (&failed, 1, __ATOMIC_RELAXED); ++ } ++ + /* Main thread. */ + struct burn_thread main_thread; + main_thread.conf = conf; diff --git a/glibc-RHEL-106562-21.patch b/glibc-RHEL-106562-21.patch new file mode 100644 index 0000000..8ae0eae --- /dev/null +++ b/glibc-RHEL-106562-21.patch @@ -0,0 +1,62 @@ +commit 10af00f7a135c85796a9c4c75228358b8898da5c +Author: Siddhesh Poyarekar +Date: Fri Mar 14 10:18:21 2025 -0400 + + tst-fopen-threaded: Only check EOF for failing read + + The fread race checker looks for EOF in every thread, which is incorrect + since threads calling fread successfully could lag behind and read the + EOF condition, resulting in multiple threads thinking that they + encountered an EOF. + + Only look for EOF condition if fread fails to read a char. Also drop + the clearerr() since it could mask the failure of another reader, thus + hiding a test failure. + + Finally, also check for error in the stream for completeness. + + Signed-off-by: Siddhesh Poyarekar + Reviewed-by: Florian Weimer + +diff --git a/sysdeps/pthread/tst-fopen-threaded.c b/sysdeps/pthread/tst-fopen-threaded.c +index 5c792c93e3711621..ade58ad19eb209d1 100644 +--- a/sysdeps/pthread/tst-fopen-threaded.c ++++ b/sysdeps/pthread/tst-fopen-threaded.c +@@ -64,19 +64,27 @@ threadReadRoutine (void *argv) + /* Wait for all threads to be ready to read. */ + xpthread_barrier_wait (&barrier); + +- ret = +- fread (&read_buffer, sizeof (char), sizeof (read_buffer), my_data->fd); +- if (feof (my_data->fd) != 0) ++ ret = fread (&read_buffer, 1, sizeof (read_buffer), my_data->fd); ++ /* If no data is returned (we read only 1 byte, so there's no short read ++ situation here), look for EOF flag and record it in MY_DATA. The EOF flag ++ is not cleared because that could result in a test failure being masked ++ when two threads fail to read and one of them clears error/EOF flags ++ before the second one has the chance to observe it. ++ ++ Successful readers could still see the EOF if they fall behind the failing ++ read when calling feof(), which could result in a false test failure. To ++ avoid this race, we only make the failing reader check for EOF or ++ error. */ ++ if (ret == 0) + { +- clearerr (my_data->fd); +- my_data->eof = true; ++ if (feof (my_data->fd) != 0) ++ my_data->eof = true; ++ else ++ FAIL_EXIT1 ("fread failed (ferror: %d): %m", ferror (my_data->fd)); + } + else +- { +- TEST_COMPARE (ret, 1); +- /* Save the read value. */ +- my_data->value = read_buffer; +- } ++ /* Save the read value. */ ++ my_data->value = read_buffer; + TEST_COMPARE (ferror (my_data->fd), 0); + return NULL; + } diff --git a/glibc-RHEL-106562-22.patch b/glibc-RHEL-106562-22.patch new file mode 100644 index 0000000..c5058ab --- /dev/null +++ b/glibc-RHEL-106562-22.patch @@ -0,0 +1,121 @@ +commit 81e74c8676479811601b5894d72bb3d7e05f68dd +Author: DJ Delorie +Date: Fri Mar 14 16:08:12 2025 -0400 + + add ptmx support to test-container + +diff --git a/support/Makefile b/support/Makefile +index 6e3c55394fa212b6..23ce2ccec89743bb 100644 +--- a/support/Makefile ++++ b/support/Makefile +@@ -313,6 +313,7 @@ tests = \ + README-testing \ + tst-support-namespace \ + tst-support-open-dev-null-range \ ++ tst-support-openpty \ + tst-support-process_state \ + tst-support_blob_repeat \ + tst-support_capture_subprocess \ +@@ -331,6 +332,10 @@ tests = \ + tst-xsigstack \ + # tests + ++tests-container = \ ++ tst-support-openpty-c \ ++ # tests-container ++ + ifeq ($(run-built-tests),yes) + tests-special = \ + $(objpfx)tst-support_record_failure-2.out +diff --git a/support/test-container.c b/support/test-container.c +index adf2b30215273936..1696d676fd101d42 100644 +--- a/support/test-container.c ++++ b/support/test-container.c +@@ -1148,6 +1148,9 @@ main (int argc, char **argv) + devmount (new_root_path, "null"); + devmount (new_root_path, "zero"); + devmount (new_root_path, "urandom"); ++#ifdef __linux__ ++ devmount (new_root_path, "ptmx"); ++#endif + + /* We're done with the "old" root, switch to the new one. */ + if (chroot (new_root_path) < 0) +@@ -1214,6 +1217,14 @@ main (int argc, char **argv) + + maybe_xmkdir ("/tmp", 0755); + ++#ifdef __linux__ ++ maybe_xmkdir ("/dev/pts", 0777); ++ if (mount ("/dev/pts", "/dev/pts", "devpts", 0, "newinstance,ptmxmode=0666,mode=0666") < 0) ++ FAIL_EXIT1 ("can't mount /dev/pts: %m\n"); ++ if (mount ("/dev/pts/ptmx", "/dev/ptmx", "", MS_BIND | MS_REC, NULL) < 0) ++ FAIL_EXIT1 ("can't mount /dev/ptmx\n"); ++#endif ++ + if (require_pidns) + { + /* Now that we're pid 1 (effectively "root") we can mount /proc */ +diff --git a/support/tst-support-openpty-c.c b/support/tst-support-openpty-c.c +new file mode 100644 +index 0000000000000000..0a6a428fc3cd3400 +--- /dev/null ++++ b/support/tst-support-openpty-c.c +@@ -0,0 +1,2 @@ ++/* Same test, but in a test-container. */ ++#include "tst-support-openpty.c" +diff --git a/support/tst-support-openpty.c b/support/tst-support-openpty.c +new file mode 100644 +index 0000000000000000..1222d7018f9b224f +--- /dev/null ++++ b/support/tst-support-openpty.c +@@ -0,0 +1,49 @@ ++/* Basic test for support_openpty support in test-container. ++ Copyright (C) 2025 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 ++ . */ ++ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++/* Note: the purpose of this test isn't to test if ptys function ++ correctly, but only to verify that test-container's support for ++ them is correct. The many checks in support_openpty.c are ++ sufficient for this. */ ++ ++int ++do_test (void) ++{ ++ int outer, inner; ++ char *name; ++ struct termios term; ++ struct winsize win; ++ ++ cfmakeraw (&term); ++ win.ws_row = 24; ++ win.ws_col = 80; ++ ++ support_openpty (&outer, &inner, &name, &term, &win); ++ ++ return 0; ++} ++ ++#include diff --git a/glibc-RHEL-106562-23.patch b/glibc-RHEL-106562-23.patch new file mode 100644 index 0000000..17be8ef --- /dev/null +++ b/glibc-RHEL-106562-23.patch @@ -0,0 +1,1084 @@ +commit 95b780c1d0549678c0a244c6e2112ec97edf0839 +Author: DJ Delorie +Date: Fri Mar 14 16:08:35 2025 -0400 + + stdio: Add more setvbuf tests + +diff --git a/stdio-common/Makefile b/stdio-common/Makefile +index f44562df75cb98bc..74512f20d39f8fec 100644 +--- a/stdio-common/Makefile ++++ b/stdio-common/Makefile +@@ -276,7 +276,9 @@ tests := \ + # tests + + tests-container += \ +- tst-popen3 ++ tst-popen3 \ ++ tst-setvbuf2 \ ++ tst-setvbuf2-ind + # tests-container + + generated += \ +@@ -288,6 +290,8 @@ generated += \ + + tests-internal = \ + tst-grouping_iterator \ ++ tst-setvbuf2 \ ++ tst-setvbuf2-ind \ + # tests-internal + + test-srcs = \ +@@ -524,5 +528,9 @@ $(objpfx)tst-setvbuf1-cmp.out: tst-setvbuf1.expect $(objpfx)tst-setvbuf1.out + cmp $^ > $@; \ + $(evaluate-test) + ++CFLAGS-tst-setvbuf2.c += -DIND_PROC=\"$(objpfx)tst-setvbuf2-ind\" ++$(objpfx)tst-setvbuf2-ind : $(objpfx)tst-setvbuf2-ind.o ++$(objpfx)tst-setvbuf2.out: $(objpfx)tst-setvbuf2-ind ++ + $(objpfx)tst-printf-round: $(libm) + $(objpfx)tst-scanf-round: $(libm) +diff --git a/stdio-common/tst-setvbuf2-ind.c b/stdio-common/tst-setvbuf2-ind.c +new file mode 100644 +index 0000000000000000..fda2942c241961f6 +--- /dev/null ++++ b/stdio-common/tst-setvbuf2-ind.c +@@ -0,0 +1,2 @@ ++#define INDEPENDENT_PART 1 ++#include "tst-setvbuf2.c" +diff --git a/stdio-common/tst-setvbuf2.c b/stdio-common/tst-setvbuf2.c +new file mode 100644 +index 0000000000000000..6cc83355f391afab +--- /dev/null ++++ b/stdio-common/tst-setvbuf2.c +@@ -0,0 +1,1030 @@ ++/* Test setvbuf under various conditions. ++ Copyright (C) 2025 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 ++ . */ ++ ++/* This file is used twice, once as the test itself (where do_test ++ is defined) and once as a subprocess we spawn to test stdin et all ++ (where main is defined). INDEPENDENT_PART is defined for the ++ latter. ++ ++ Note also that the purpose of this test is to test setvbuf, not the ++ underlying buffering code. */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Dear future developer: If you are reading this, you are likely ++ trying to change or understand this test. In that case, these ++ debug/dump macros will be helpful. */ ++#if 0 ++# define debug printf ("\033[3%dm%s:%d\033[0m\n", \ ++ (__LINE__ % 6) + 1, __FUNCTION__, __LINE__); ++ ++static void ++dumpfp (FILE *fp) ++{ ++ char f[10], *p=f; ++ ++ if (fp->_flags & _IO_UNBUFFERED) ++ *p++ = 'N'; ++ if (fp->_flags & _IO_LINE_BUF) ++ *p++ = 'L'; ++ if (p == f) ++ *p++ = 'B'; ++ *p = 0; ++ ++ printf ("FILE %p flags %s" ++ " read %p \033[%dm%+ld \033[%dm%+ld\033[0m" ++ " write %p \033[%dm%+ld \033[%dm%+ld\033[0m %ld" ++ " buf %p \033[%dm%+ld\033[0m sz %ld pend %ld\n", ++ fp, f, ++ ++ fp->_IO_read_base, ++ fp->_IO_read_ptr == fp->_IO_read_base ? 33 : 32, ++ fp->_IO_read_ptr - fp->_IO_read_base, ++ fp->_IO_read_end == fp->_IO_read_base ? 33 : 36, ++ fp->_IO_read_end - fp->_IO_read_base, ++ ++ fp->_IO_write_base, ++ fp->_IO_write_ptr == fp->_IO_write_base ? 33 : 32, ++ fp->_IO_write_ptr - fp->_IO_write_base, ++ fp->_IO_write_end == fp->_IO_write_base ? 33 : 36, ++ fp->_IO_write_end - fp->_IO_write_base, ++ fp->_IO_write_end - fp->_IO_write_base, ++ ++ fp->_IO_buf_base, ++ fp->_IO_buf_end == fp->_IO_buf_base ? 33 : 35, ++ fp->_IO_buf_end - fp->_IO_buf_base, ++ __fbufsize (fp), __fpending (fp) ++ ); ++} ++#else ++# define debug ++# define dumpfp(FP) ++#endif ++ ++#ifndef INDEPENDENT_PART ++/* st_blksize value for that file, or BUFSIZ if out of range. */ ++static int blksize = BUFSIZ; ++#endif ++ ++/* Our test buffer. */ ++#define TEST_BUFSIZE 42 ++static int bufsize = TEST_BUFSIZE < BUFSIZ ? TEST_BUFSIZE : BUFSIZ; ++static char *buffer; ++ ++/* Test data, both written to that file and used as an in-memory ++ stream. */ ++char test_data[2 * BUFSIZ]; ++ ++#define TEST_STRING "abcdef\n" ++ ++enum test_source_case ++ { ++ test_source_file, ++ test_source_pipe, ++ test_source_fifo, ++ test_source_pseudo_terminal, ++ test_source_dev_null, ++ test_source_count, ++ }; ++ ++static const char *const test_source_name[test_source_count] = ++ { ++ "regular file", ++ "pipe", ++ "fifo", ++ "pseudo_terminal", ++ "dev_null" ++ }; ++ ++enum test_stream_case ++ { ++ test_stream_stdin, ++ test_stream_stdout, ++ test_stream_stderr, ++ test_stream_fopen_r, ++ test_stream_fdopen_r, ++ test_stream_fopen_w, ++ test_stream_fdopen_w, ++ test_stream_count ++ }; ++ ++static bool test_stream_reads[test_stream_count] = ++ { ++ true, ++ false, ++ false, ++ true, ++ true, ++ false, ++ false ++ }; ++ ++static const char *const test_stream_name[test_stream_count] = ++ { ++ "stdin", ++ "stdout", ++ "stderr", ++ "fopen (read)", ++ "fdopen (read)", ++ "fopen (write)", ++ "fdopen (write)" ++ }; ++ ++enum test_config_case ++ { ++ test_config_none, ++ test_config_unbuffered, ++ test_config_line, ++ test_config_fully, ++ test_config_count ++ }; ++ ++static const char *const test_config_name[test_config_count] = ++ { ++ "no change", ++ "unbuffered", ++ "line buffered", ++ "fully buffered" ++ }; ++ ++FILE *test_stream; ++ ++char *test_file_name = NULL; ++int pty_fd; ++char *test_pipe_name = NULL; ++int test_pipe[2]; ++ ++/* This is either -1 or represents a pre-opened file descriptor for ++ the test as returned by prepare_test_file. */ ++int test_fd; ++ ++/*------------------------------------------------------------*/ ++ ++/* Note that throughout this test we reopen, remove, and change ++ to/from a fifo, the test file. This would normally cause a race ++ condition, except that we're in a test container. No other process ++ can run in the test container simultaneously. */ ++ ++void ++prepare_test_data (void) ++{ ++ buffer = (char *) xmalloc (bufsize); ++ ++#ifndef INDEPENDENT_PART ++ /* Both file and pipe need this. */ ++ if (test_file_name == NULL) ++ { ++ debug; ++ int fd = create_temp_file ("tst-setvbuf2", &test_file_name); ++ TEST_VERIFY_EXIT (fd != -1); ++ struct stat64 st; ++ xfstat64 (fd, &st); ++ if (st.st_blksize > 0 && st.st_blksize < BUFSIZ) ++ blksize = st.st_blksize; ++ xclose (fd); ++ } ++#endif ++ ++ for (size_t i = 0; i < 2 * BUFSIZ; i++) ++ { ++ unsigned char c = TEST_STRING[i % strlen (TEST_STRING)]; ++ test_data[i] = c; ++ } ++} ++ ++#ifndef INDEPENDENT_PART ++ ++/* These functions provide a source/sink for the "other" side of any ++ pipe-style descriptor we're using for test. */ ++ ++static pthread_t writer_thread_tid = 0; ++static pthread_t reader_thread_tid = 0; ++ ++typedef struct { ++ int fd; ++ const char *fname; ++} ThreadData; ++/* It's OK if this is static, we only run one at a time. */ ++ThreadData thread_data; ++ ++static void * ++writer_thread_proc (void *closure) ++{ ++ ThreadData *td = (ThreadData *) closure; ++ int fd; ++ int i; ++ ssize_t wn; ++ debug; ++ ++ if (td->fname) ++ td->fd = xopen (td->fname, O_WRONLY, 0777); ++ fd = td->fd; ++ ++ while (1) ++ { ++ i = 0; ++ while (i < BUFSIZ) ++ { ++ wn = write (fd, test_data + i, BUFSIZ - i); ++ if (wn <= 0) ++ break; ++ i += wn; ++ } ++ } ++ return NULL; ++} ++ ++static void * ++reader_thread_proc (void *closure) ++{ ++ ThreadData *td = (ThreadData *) closure; ++ int fd; ++ ssize_t rn; ++ int n = 0; ++ debug; ++ ++ if (td->fname) ++ td->fd = xopen (td->fname, O_RDONLY, 0777); ++ fd = td->fd; ++ ++ while (1) ++ { ++ char buf[BUFSIZ]; ++ rn = read (fd, buf, BUFSIZ); ++ if (rn <= 0) ++ break; ++ TEST_COMPARE_BLOB (buf, rn, test_data+n, rn); ++ n += rn; ++ } ++ return NULL; ++} ++ ++static void ++start_writer_thread (int fd) ++{ ++ debug; ++ thread_data.fd = fd; ++ thread_data.fname = NULL; ++ writer_thread_tid = xpthread_create (NULL, writer_thread_proc, ++ (void *)&thread_data); ++} ++ ++static void ++start_writer_thread_n (const char *fname) ++{ ++ debug; ++ thread_data.fd = 0; ++ thread_data.fname = fname; ++ writer_thread_tid = xpthread_create (NULL, writer_thread_proc, ++ (void *)&thread_data); ++} ++ ++static void ++end_writer_thread (void) ++{ ++ debug; ++ if (writer_thread_tid) ++ { ++ pthread_cancel (writer_thread_tid); ++ xpthread_join (writer_thread_tid); ++ xclose (thread_data.fd); ++ writer_thread_tid = 0; ++ } ++} ++ ++static void ++start_reader_thread (int fd) ++{ ++ debug; ++ thread_data.fd = fd; ++ thread_data.fname = NULL; ++ reader_thread_tid = xpthread_create (NULL, reader_thread_proc, ++ (void *)&thread_data); ++} ++ ++static void ++start_reader_thread_n (const char *fname) ++{ ++ debug; ++ thread_data.fd = 0; ++ thread_data.fname = fname; ++ reader_thread_tid = xpthread_create (NULL, reader_thread_proc, ++ (void *)&thread_data); ++} ++ ++static void ++end_reader_thread (void) ++{ ++ debug; ++ if (reader_thread_tid) ++ { ++ pthread_cancel (reader_thread_tid); ++ xpthread_join (reader_thread_tid); ++ xclose (thread_data.fd); ++ reader_thread_tid = 0; ++ } ++} ++ ++/*------------------------------------------------------------*/ ++ ++/* These two functions are reponsible for choosing a file to be tested ++ against, typically by returning a filename but in a few cases also ++ providing a file descriptor (i.e. for fdopen). */ ++ ++static const char * ++prepare_test_file (enum test_source_case f, enum test_stream_case s) ++{ ++ debug; ++ ++ test_fd = -1; ++ ++ switch (f) ++ { ++ case test_source_file: ++ { ++ if (test_stream_reads[f]) ++ { ++ debug; ++ FILE *fp = xfopen (test_file_name, "w"); ++ TEST_VERIFY_EXIT (fwrite (test_data, 1, 2 * BUFSIZ, fp) ++ == 2 * BUFSIZ); ++ xfclose (fp); ++ } ++ debug; ++ return test_file_name; ++ } ++ ++ case test_source_pipe: ++ { ++ debug; ++ xpipe (test_pipe); ++ if (test_stream_reads[s]) ++ { ++ start_writer_thread (test_pipe[1]); ++ test_fd = test_pipe[0]; ++ } ++ else ++ { ++ start_reader_thread (test_pipe[0]); ++ test_fd = test_pipe[1]; ++ } ++ test_pipe_name = xasprintf ("/proc/self/fd/%d", test_fd); ++ debug; ++ return test_pipe_name; ++ } ++ ++ case test_source_fifo: ++ { ++ /* We do not want to fail/exit if the file doesn't exist. */ ++ unlink (test_file_name); ++ xmkfifo (test_file_name, 0600); ++ debug; ++ if (test_stream_reads[s]) ++ start_writer_thread_n (test_file_name); ++ else ++ start_reader_thread_n (test_file_name); ++ debug; ++ return test_file_name; ++ } ++ ++ case test_source_pseudo_terminal: ++ { ++ support_openpty (&pty_fd, &test_fd, &test_pipe_name, NULL, NULL); ++ ++ debug; ++ if (test_stream_reads[s]) ++ start_writer_thread (pty_fd); ++ else ++ start_reader_thread (pty_fd); ++ ++ debug; ++ return test_pipe_name; ++ } ++ ++ case test_source_dev_null: ++ debug; ++ return "/dev/null"; ++ ++ default: ++ abort (); ++ } ++} ++ ++static void ++unprepare_test_file (FILE *fp, ++ enum test_source_case f, ++ enum test_stream_case s) ++{ ++ debug; ++ switch (f) ++ { ++ case test_source_file: ++ break; ++ ++ case test_source_pipe: ++ free (test_pipe_name); ++ if (test_stream_reads[s]) ++ end_writer_thread (); ++ else ++ end_reader_thread (); ++ break; ++ ++ case test_source_fifo: ++ if (test_stream_reads[s]) ++ end_writer_thread (); ++ else ++ end_reader_thread (); ++ unlink (test_file_name); ++ break; ++ ++ case test_source_pseudo_terminal: ++ free (test_pipe_name); ++ if (test_stream_reads[s]) ++ end_writer_thread (); ++ else ++ end_reader_thread (); ++ break; ++ ++ case test_source_dev_null: ++ break; ++ ++ default: ++ abort (); ++ } ++ debug; ++} ++ ++/*------------------------------------------------------------*/ ++ ++/* This function takes a filename and returns a file descriptor, ++ opened according to the method requested. */ ++ ++static FILE * ++open_test_stream (enum test_source_case f, enum test_stream_case s) ++{ ++ int fd; ++ FILE *fp; ++ const char *fname; ++ ++ debug; ++ fname = prepare_test_file (f, s); ++ if (fname == NULL) ++ return NULL; ++ ++ switch (s) ++ { ++ case test_stream_stdin: ++ fp = xfopen (fname, "r"); ++ break; ++ ++ case test_stream_stdout: ++ fp = xfopen (fname, "w"); ++ break; ++ ++ case test_stream_stderr: ++ fp = xfopen (fname, "w"); ++ break; ++ ++ case test_stream_fopen_r: ++ fp = xfopen (fname, "r"); ++ break; ++ ++ case test_stream_fdopen_r: ++ if (test_fd == -1) ++ fd = xopen (fname, O_RDONLY, 0); ++ else ++ fd = test_fd; ++ fp = fdopen (fd, "r"); ++ break; ++ ++ case test_stream_fopen_w: ++ fp = xfopen (fname, "w"); ++ break; ++ ++ case test_stream_fdopen_w: ++ fd = xopen (fname, O_WRONLY|O_CREAT|O_TRUNC, 0777); ++ fp = fdopen (fd, "w"); ++ break; ++ ++ default: ++ abort (); ++ } ++ TEST_VERIFY_EXIT (fp != NULL); ++ ++ if (f == test_source_pseudo_terminal) ++ { ++ struct termios t; ++ /* We disable the NL to CR-LF conversion so that we can compare ++ data without having to remove the extra CRs. */ ++ if (tcgetattr (fileno (fp), &t) < 0) ++ FAIL_EXIT1 ("tcgetattr failed: %m"); ++ t.c_oflag &= ~ONLCR; ++ if (tcsetattr (fileno (fp), TCSANOW, &t) < 0) ++ FAIL_EXIT1 ("tcsetattr failed: %m"); ++ } ++ ++ debug; ++ printf ("source %s stream %s file %s fd %d\n", ++ test_source_name[f], ++ test_stream_name[s], fname, fileno (fp)); ++ return fp; ++} ++ ++#endif ++ ++/*------------------------------------------------------------*/ ++ ++/* These functions do the actual testing - setting various buffering ++ options and verifying that they buffer as expected. */ ++ ++static void ++test_put_string (FILE *fp, const char *s, int count) ++{ ++ while (*s && count--) ++ { ++ fputc (*s++, fp); ++ TEST_VERIFY_EXIT (!ferror (fp)); ++ } ++} ++ ++int ++verify_fully_buffered (FILE *fp, ++ enum test_source_case f, ++ enum test_stream_case s, ++ enum test_config_case c) ++{ ++ debug; ++ if (test_stream_reads[s]) ++ { ++ char buf[10]; ++ dumpfp (fp); ++ size_t fc = fread (buf, 1, 10 - 1, fp); ++ dumpfp (fp); ++ ++ ssize_t count = fp->_IO_read_ptr - fp->_IO_read_base; ++ ++ TEST_VERIFY (fp->_IO_read_base != NULL); ++ if (f == test_source_dev_null) ++ { ++ TEST_VERIFY (fc == 0); ++ TEST_VERIFY (count == 0); ++ } ++ else if (f == test_source_pseudo_terminal) ++ { ++ TEST_VERIFY (fc == 9); ++ TEST_VERIFY (count == 3 || count == 10); ++ } ++ else ++ { ++ TEST_VERIFY (fc == 9); ++ TEST_VERIFY (count == 10); ++ } ++ ++ /* We already checked for the first character being 'a'. */ ++ if (count > 1) ++ { ++ TEST_COMPARE_BLOB (buf, count - 1, test_data + 1, count - 1); ++ TEST_COMPARE_BLOB (fp->_IO_read_base, count, test_data, count); ++ } ++ } ++ else ++ { ++ dumpfp (fp); ++ test_put_string (fp, test_data + 1, 10 - 1); ++ dumpfp (fp); ++ TEST_COMPARE (fp->_IO_write_ptr - fp->_IO_write_base, 10); ++ TEST_COMPARE_BLOB (fp->_IO_write_base, 10, test_data, 10); ++ } ++ ++ TEST_COMPARE ((fp->_flags & (_IO_UNBUFFERED | _IO_LINE_BUF)), 0); ++ if (c != test_config_none) ++ TEST_COMPARE (__fbufsize (fp), bufsize); ++ return 0; ++} ++ ++int ++verify_line_buffered (FILE *fp, ++ enum test_source_case f, ++ enum test_stream_case s, ++ enum test_config_case c) ++{ ++ debug; ++ /* "line buffered" for inputs is not really defined; what you really ++ want here is to control the device providing input. For GLIBC a ++ line-buffered input is treated as fully buffered. */ ++ if (test_stream_reads[s]) ++ { ++ char buf[10]; ++ dumpfp (fp); ++ size_t fc = fread (buf, 1, 10 - 1, fp); ++ dumpfp (fp); ++ ++ ssize_t count = fp->_IO_read_ptr - fp->_IO_read_base; ++ ++ TEST_VERIFY (fp->_IO_read_base != NULL); ++ if (f == test_source_dev_null) ++ { ++ TEST_VERIFY (fc == 0); ++ TEST_VERIFY (count == 0); ++ } ++ else if (f == test_source_pseudo_terminal) ++ { ++ TEST_VERIFY (fc == 9); ++ TEST_VERIFY (count == 3 || count == 10); ++ } ++ else ++ { ++ TEST_VERIFY (fc == 9); ++ TEST_VERIFY (count == 10); ++ } ++ ++ /* We already checked for the first character being 'a'. */ ++ if (count > 1) ++ { ++ TEST_COMPARE_BLOB (buf, count - 1, test_data + 1, count - 1); ++ TEST_COMPARE_BLOB (fp->_IO_read_base, count, test_data, count); ++ } ++ } ++ else ++ { ++ dumpfp (fp); ++ test_put_string (fp, test_data + 1, 10 - 1); ++ dumpfp (fp); ++ TEST_COMPARE (fp->_IO_write_ptr - fp->_IO_write_base, 3); ++ /* The first "abcdef\n" got flushed, leaving "abc". */ ++ TEST_COMPARE_BLOB (fp->_IO_write_base, 3, test_data + 7, 3); ++ } ++ ++ TEST_COMPARE ((fp->_flags & (_IO_UNBUFFERED | _IO_LINE_BUF)), _IO_LINE_BUF); ++ if (c != test_config_none) ++ TEST_COMPARE (__fbufsize (fp), bufsize); ++ return 0; ++} ++ ++int ++verify_unbuffered (FILE *fp, ++ enum test_source_case f, ++ enum test_stream_case s, ++ enum test_config_case c) ++{ ++ debug; ++ if (test_stream_reads[s]) ++ { ++ /* We've already read one byte. */ ++ dumpfp (fp); ++ TEST_VERIFY (fp->_IO_read_base != NULL); ++ if (f == test_source_dev_null) ++ TEST_COMPARE (fp->_IO_read_ptr - fp->_IO_read_base, 0); ++ else ++ { ++ TEST_COMPARE (fp->_IO_read_ptr - fp->_IO_read_base, 1); ++ TEST_COMPARE (fp->_IO_read_base[0], test_data[0]); ++ TEST_VERIFY (fp->_IO_read_ptr == fp->_IO_read_end); ++ } ++ } ++ else ++ { ++ dumpfp (fp); ++ fputc (test_data[1], fp); ++ dumpfp (fp); ++ TEST_COMPARE (fp->_IO_write_ptr - fp->_IO_write_base, 0); ++ TEST_COMPARE (fp->_IO_write_base[0], test_data[1]); ++ TEST_VERIFY (fp->_IO_write_end == fp->_IO_write_base); ++ } ++ TEST_COMPARE ((fp->_flags & (_IO_UNBUFFERED | _IO_LINE_BUF)), ++ _IO_UNBUFFERED); ++ TEST_COMPARE (__fbufsize (fp), 1); ++ return 0; ++} ++ ++static int ++do_setvbuf (FILE *fp, void *buf, int flags, int size, ++ enum test_stream_case s) ++{ ++ if (s != test_stream_stdout) ++ printf ("SETVBUF %p %p %s %d\n", ++ fp, buf, ++ flags == _IONBF ? "_IONBF" ++ : flags == _IOLBF ? "_IOLBF" ++ : flags == _IOFBF ? "_IOFBF" ++ : "???", size); ++ if (setvbuf (fp, buf, flags, size)) ++ { ++ perror ("setvbuf"); ++ return 1; ++ } ++ return 0; ++} ++ ++int ++do_second_part (FILE *fp, ++ enum test_source_case f, ++ enum test_stream_case s, ++ enum test_config_case c) ++{ ++ /* At this point, FP is the stream to test according to the other ++ parameters. */ ++ ++ int rv = 0; ++ int flags_before; ++ int flags_after; ++ ++ debug; ++ ++ flags_before = fp->_flags & (_IO_UNBUFFERED | _IO_LINE_BUF); ++ ++ /* This is where we do the thing we're testing for. */ ++ switch (c) ++ { ++ case test_config_none: ++ /* Buffering is unchanged. */ ++ break; ++ ++ case test_config_unbuffered: ++ do_setvbuf (fp, NULL, _IONBF, 0, s); ++ break; ++ ++ case test_config_line: ++ do_setvbuf (fp, buffer, _IOLBF, bufsize, s); ++ break; ++ ++ case test_config_fully: ++ do_setvbuf (fp, buffer, _IOFBF, bufsize, s); ++ break; ++ ++ default: ++ abort (); ++ } ++ ++ flags_after = fp->_flags & (_IO_UNBUFFERED | _IO_LINE_BUF); ++ ++ /* Check the buffer mode after we touch it, if we touched it. */ ++ switch (c) ++ { ++ case test_config_none: ++ /* Buffering is unchanged, but may change on the first read/write. */ ++ TEST_COMPARE (flags_after, flags_before); ++ break; ++ ++ case test_config_unbuffered: ++ TEST_COMPARE (flags_after, _IO_UNBUFFERED); ++ break; ++ ++ case test_config_line: ++ TEST_COMPARE (flags_after, _IO_LINE_BUF); ++ break; ++ ++ case test_config_fully: ++ TEST_COMPARE (flags_after, 0); ++ break; ++ ++ default: ++ abort (); ++ } ++ ++ /* Glibc defers calculating the appropriate buffering mechanism ++ until it reads from or writes to the device. So we read one ++ character here, and account for that in the tests. */ ++ if (test_stream_reads[s]) ++ { ++ dumpfp (fp); ++ int c = fgetc (fp); ++ if (c != TEST_STRING[0] && f != test_source_dev_null) ++ FAIL ("first char read is %c not %c", c, TEST_STRING[0]); ++ dumpfp (fp); ++ } ++ else ++ { ++ dumpfp (fp); ++ fputc (TEST_STRING[0], fp); ++ dumpfp (fp); ++ } ++ ++ switch (fp->_flags & (_IO_UNBUFFERED | _IO_LINE_BUF)) ++ { ++ case _IO_LINE_BUF: ++ rv += verify_line_buffered (fp, f, s, c); ++ break; ++ ++ case _IO_UNBUFFERED: ++ rv += verify_unbuffered (fp, f, s, c); ++ break; ++ ++ case 0: /* Fully buffered. */ ++ rv += verify_fully_buffered (fp, f, s, c); ++ break; ++ ++ default: ++ abort (); ++ } ++ ++ ++ fclose (fp); ++ return rv; ++} ++ ++/*------------------------------------------------------------*/ ++ ++#ifdef INDEPENDENT_PART ++/* This part is the independent sub-process we call to test stdin et ++ al. */ ++ ++int ++main (int argc, char **argv) ++{ ++ /* This is one of the subprocesses we created to test stdin et ++ al. */ ++ FILE *fp; ++ ++ /* If we're called as a regular test, instead of as a sub-process, ++ don't complain. */ ++ if (argc == 1) ++ return 0; ++ ++ if (argc != 4) ++ { ++ int i; ++ for (i = 0; i <= argc; i ++) ++ printf ("argv[%d] = `%s'\n", i, argv[i] ?: "(null)"); ++ FAIL_EXIT1 ("sub-process called wrong"); ++ } ++ ++ prepare_test_data (); ++ ++ enum test_source_case f = atoi (argv[1]); ++ enum test_stream_case s = atoi (argv[2]); ++ enum test_config_case c = atoi (argv[3]); ++ ++ if (s != test_stream_stdout) ++ printf ("\n\033[41mRunning test %s : %s : %s\033[0m\n", ++ test_source_name[f], ++ test_stream_name[s], ++ test_config_name[c]); ++ ++ switch (s) ++ { ++ case test_stream_stdin: ++ fp = stdin; ++ break; ++ case test_stream_stdout: ++ fp = stdout; ++ break; ++ case test_stream_stderr: ++ fp = stderr; ++ break; ++ default: ++ abort (); ++ } ++ ++ return do_second_part (fp, f, s, c); ++} ++ ++#else ++/* This part is the standard test process. */ ++ ++/* Spawn an independent sub-process with std* redirected. */ ++int ++recurse (FILE *fp, ++ enum test_source_case f, ++ enum test_stream_case s, ++ enum test_config_case c) ++{ ++ /* We need to test stdin, stdout, or stderr, which means creating a ++ subprocess with one of those redirected from FP. */ ++ debug; ++ ++ pid_t pid; ++ int status; ++ ++ pid = fork (); ++ ++ switch (pid) ++ { ++ case -1: /* error */ ++ perror ("fork"); ++ return 1; ++ break; ++ ++ default: /* parent */ ++ fclose (fp); ++ xwaitpid (pid, &status, 0); ++ if (WIFEXITED (status) ++ && WEXITSTATUS (status) == 0) ++ return 0; ++ return 1; ++ ++ case 0: /* child */ ++ switch (s) ++ { ++ case test_stream_stdin: ++ xclose (0); ++ dup2 (fileno (fp), 0); ++ break; ++ case test_stream_stdout: ++ xclose (1); ++ dup2 (fileno (fp), 1); ++ break; ++ case test_stream_stderr: ++ xclose (2); ++ dup2 (fileno (fp), 2); ++ break; ++ default: ++ abort (); ++ } ++ fclose (fp); ++ ++ /* At this point, we have to run a program... which is tricky to ++ properly support for remote targets or crosses, because of ++ glibc versions etc. Hence we run in a test-container. */ ++ ++ char fs[10], ss[10], cs[10]; ++ sprintf (fs, "%d", f); ++ sprintf (ss, "%d", s); ++ sprintf (cs, "%d", c); ++ execl (IND_PROC, IND_PROC, fs, ss, cs, NULL); ++ if (s == test_stream_stdout) ++ fprintf (stderr, "execl (%s) failed, ", IND_PROC); ++ else ++ printf ("execl (%s) failed, ", IND_PROC); ++ perror ("The error was"); ++ exit (1); ++ break; ++ } ++ ++ return 0; ++} ++ ++int ++do_test (void) ++{ ++ int rv = 0; ++ ++ signal (SIGPIPE, SIG_IGN); ++ ++ prepare_test_data (); ++ ++ for (enum test_source_case f = 0; f < test_source_count; ++f) ++ for (enum test_stream_case s = 0; s < test_stream_count; ++s) ++ for (enum test_config_case c = 0; c < test_config_count; ++c) ++ { ++ printf ("\n\033[43mRunning test %s : %s : %s\033[0m\n", ++ test_source_name[f], ++ test_stream_name[s], ++ test_config_name[c]); ++ ++ FILE *fp = open_test_stream (f, s); ++ ++ if (fp) ++ { ++ ++ if (s <= test_stream_stderr) ++ rv += recurse (fp, f, s, c); ++ else ++ rv += do_second_part (fp, f, s, c); ++ ++ unprepare_test_file (fp, f, s); ++ } ++ } ++ ++ free (buffer); ++ ++ printf ("return %d\n", rv); ++ return rv; ++} ++ ++# include ++#endif ++ diff --git a/glibc-RHEL-106562-24.patch b/glibc-RHEL-106562-24.patch new file mode 100644 index 0000000..fc5ce1b --- /dev/null +++ b/glibc-RHEL-106562-24.patch @@ -0,0 +1,112 @@ +commit 4fa959d13d21b8f56a43aa0a416100303736c55c +Author: Florian Weimer +Date: Tue Apr 8 10:39:44 2025 +0200 + + stdio-common: In tst-setvbuf2, close helper thread descriptor only if opened + + The helper thread may get canceled before the open system + call succeds. Then ThreadData.fd remains zero, and eventually + the xclose call in end_reader_thread fails because descriptor 0 + is not open. + + Instead, initialize the fd member to -1 (not a valid descriptor) + and close the descriptor only if valid. Do this in a new end_thread + helper routine. + + Also add more error checking to close operations. + + Fixes commit 95b780c1d0549678c0a244c6e2112ec97edf0839 ("stdio: Add + more setvbuf tests"). + +diff --git a/stdio-common/tst-setvbuf2.c b/stdio-common/tst-setvbuf2.c +index 6cc83355f391afab..84d8b43a5811b4be 100644 +--- a/stdio-common/tst-setvbuf2.c ++++ b/stdio-common/tst-setvbuf2.c +@@ -240,6 +240,21 @@ typedef struct { + /* It's OK if this is static, we only run one at a time. */ + ThreadData thread_data; + ++static void ++end_thread (pthread_t *ptid) ++{ ++ if (*ptid) ++ { ++ pthread_cancel (*ptid); ++ xpthread_join (*ptid); ++ /* The descriptor was passed in, or the helper thread made ++ sufficient progress and opened the file. */ ++ if (thread_data.fd >= 0) ++ xclose (thread_data.fd); ++ *ptid = 0; ++ } ++} ++ + static void * + writer_thread_proc (void *closure) + { +@@ -306,7 +321,7 @@ static void + start_writer_thread_n (const char *fname) + { + debug; +- thread_data.fd = 0; ++ thread_data.fd = -1; + thread_data.fname = fname; + writer_thread_tid = xpthread_create (NULL, writer_thread_proc, + (void *)&thread_data); +@@ -316,13 +331,7 @@ static void + end_writer_thread (void) + { + debug; +- if (writer_thread_tid) +- { +- pthread_cancel (writer_thread_tid); +- xpthread_join (writer_thread_tid); +- xclose (thread_data.fd); +- writer_thread_tid = 0; +- } ++ end_thread (&writer_thread_tid); + } + + static void +@@ -339,7 +348,7 @@ static void + start_reader_thread_n (const char *fname) + { + debug; +- thread_data.fd = 0; ++ thread_data.fd = -1; + thread_data.fname = fname; + reader_thread_tid = xpthread_create (NULL, reader_thread_proc, + (void *)&thread_data); +@@ -349,13 +358,7 @@ static void + end_reader_thread (void) + { + debug; +- if (reader_thread_tid) +- { +- pthread_cancel (reader_thread_tid); +- xpthread_join (reader_thread_tid); +- xclose (thread_data.fd); +- reader_thread_tid = 0; +- } ++ end_thread (&reader_thread_tid); + } + + /*------------------------------------------------------------*/ +@@ -852,7 +855,7 @@ do_second_part (FILE *fp, + } + + +- fclose (fp); ++ xfclose (fp); + return rv; + } + +@@ -939,7 +942,7 @@ recurse (FILE *fp, + break; + + default: /* parent */ +- fclose (fp); ++ xfclose (fp); + xwaitpid (pid, &status, 0); + if (WIFEXITED (status) + && WEXITSTATUS (status) == 0) diff --git a/glibc-RHEL-106562-3.patch b/glibc-RHEL-106562-3.patch new file mode 100644 index 0000000..dcdbff0 --- /dev/null +++ b/glibc-RHEL-106562-3.patch @@ -0,0 +1,60 @@ +commit 3f54e459a633b4247be91b9d0f68a7e08720b8d8 +Author: Frédéric Bérat +Date: Tue Aug 13 12:01:26 2024 +0200 + + libio/tst-getdelim: Add new test covering NUL as a delimiter + + Add a new test to getdelim to verify that '\0' can be set as a + delimiter. + + Reviewed-by: Florian Weimer + +diff --git a/libio/tst-getdelim.c b/libio/tst-getdelim.c +index e6dd964b4918b02a..db15bf92855ee9e1 100644 +--- a/libio/tst-getdelim.c ++++ b/libio/tst-getdelim.c +@@ -1,4 +1,6 @@ +-/* Check that getdelim sets error indicator on error (BZ #29917) ++/* Test getdelim conforming to POSIX specifications. ++ ++ Note: Most getdelim use cases are covered by stdio-common/tst-getline. + + Copyright (C) 2023-2024 Free Software Foundation, Inc. + This file is part of the GNU C Library. +@@ -18,18 +20,36 @@ + . */ + + #include ++#include + #include + + #include ++#include ++#include + + static int + do_test (void) + { ++ /* Check that getdelim sets error indicator on error (BZ #29917) */ + clearerr (stdin); + TEST_VERIFY (getdelim (0, 0, '\n', stdin) == -1); + TEST_VERIFY (ferror (stdin) != 0); + TEST_VERIFY (errno == EINVAL); + ++ /* Test getdelim with NUL as delimiter */ ++ verbose_printf ("Testing NUL delimiter\n"); ++ char *lineptr = NULL; ++ size_t linelen = 0; ++ char membuf[] = "abc\0d\nef\0"; ++ FILE *memstream = fmemopen (membuf, sizeof (membuf), "r"); ++ TEST_VERIFY_EXIT (memstream != NULL); ++ TEST_VERIFY (getdelim (&lineptr, &linelen, '\0', memstream) != -1); ++ TEST_COMPARE_BLOB (lineptr, 4, "abc\0", 4); ++ TEST_VERIFY (getdelim (&lineptr, &linelen, '\0', memstream) != -1); ++ TEST_COMPARE_BLOB (lineptr, 5, "d\nef\0", 5); ++ fclose (memstream); ++ free (lineptr); ++ + return 0; + } + diff --git a/glibc-RHEL-106562-4.patch b/glibc-RHEL-106562-4.patch new file mode 100644 index 0000000..86c0c97 --- /dev/null +++ b/glibc-RHEL-106562-4.patch @@ -0,0 +1,29 @@ +commit b22923abb046311ac9097a36b97b9b97342bac44 +Author: Carlos O'Donell +Date: Thu Aug 15 08:12:35 2024 -0400 + + Report error if setaffinity wrapper fails (Bug 32040) + + Previously if the setaffinity wrapper failed the rest of the subtest + would not execute and the current subtest would be reported as passing. + Now if the setaffinity wrapper fails the subtest is correctly reported + as faling. Tested manually by changing the conditions of the affinity + call including setting size to zero, or checking the wrong condition. + + No regressions on x86_64. + + Reviewed-by: Florian Weimer + +diff --git a/sysdeps/unix/sysv/linux/tst-skeleton-affinity.c b/sysdeps/unix/sysv/linux/tst-skeleton-affinity.c +index 31a15b3ad789a287..2f921ed397a1a4d9 100644 +--- a/sysdeps/unix/sysv/linux/tst-skeleton-affinity.c ++++ b/sysdeps/unix/sysv/linux/tst-skeleton-affinity.c +@@ -157,7 +157,7 @@ test_size (const struct conf *conf, size_t size) + if (setaffinity (kernel_size, initial_set) < 0) + { + printf ("error: size %zu: setaffinity: %m\n", size); +- return true; ++ return false; + } + + /* Use one-CPU set to test switching between CPUs. */ diff --git a/glibc-RHEL-106562-5.patch b/glibc-RHEL-106562-5.patch new file mode 100644 index 0000000..d97d8ff --- /dev/null +++ b/glibc-RHEL-106562-5.patch @@ -0,0 +1,78 @@ +commit 921690512946d73bf66a8c495baff31316e4489f +Author: Florian Weimer +Date: Fri Aug 16 16:05:19 2024 +0200 + + support: Add the xstatx function + + Reviewed-by: Adhemerval Zanella + +diff --git a/support/Makefile b/support/Makefile +index aa57207bdccc852d..5b1c96a49e9410f4 100644 +--- a/support/Makefile ++++ b/support/Makefile +@@ -210,6 +210,7 @@ libsupport-routines = \ + xsignal \ + xsigstack \ + xsocket \ ++ xstatx \ + xstrdup \ + xstrndup \ + xsymlink \ +diff --git a/support/xstatx.c b/support/xstatx.c +new file mode 100644 +index 0000000000000000..621f2440f83b598d +--- /dev/null ++++ b/support/xstatx.c +@@ -0,0 +1,32 @@ ++/* Error-checking wrapper for statx. ++ Copyright (C) 2024 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 ++ . */ ++ ++#include ++ ++#include ++#include ++#include ++ ++void ++xstatx (int fd, const char *path, int flags, unsigned int mask, ++ struct statx *stx) ++{ ++ if (statx (fd, path, flags, mask, stx) != 0) ++ FAIL_EXIT1 ("statx (AT_FDCWD, \"%s\", 0x%x, 0x%x): %m", ++ path, (unsigned int) flags, mask); ++} +diff --git a/support/xunistd.h b/support/xunistd.h +index 13be9a46a3e6b07b..cc74c4fad07dd088 100644 +--- a/support/xunistd.h ++++ b/support/xunistd.h +@@ -30,6 +30,7 @@ + __BEGIN_DECLS + + struct stat64; ++struct statx; + + pid_t xfork (void); + pid_t xwaitpid (pid_t, int *status, int flags); +@@ -51,6 +52,7 @@ void __REDIRECT (xstat, (const char *path, struct stat *), xstat_time64); + void __REDIRECT (xlstat, (const char *path, struct stat *), xlstat_time64); + void __REDIRECT (xfstat, (int fd, struct stat *), xfstat_time64); + #endif ++void xstatx (int, const char *, int, unsigned int, struct statx *); + void xmkdir (const char *path, mode_t); + void xchroot (const char *path); + void xunlink (const char *path); diff --git a/glibc-RHEL-106562-6.patch b/glibc-RHEL-106562-6.patch new file mode 100644 index 0000000..959730e --- /dev/null +++ b/glibc-RHEL-106562-6.patch @@ -0,0 +1,391 @@ +commit bf2927484152e12996af60ea439cf94b66fcd81d +Author: Florian Weimer +Date: Fri Aug 16 16:05:20 2024 +0200 + + io: Use struct statx and xstatx in tests + + This avoids the need to define struct_statx to an appropriate + struct stat type variant because struct statx does not change + based on time/file offset flags. + + Reviewed-by: Adhemerval Zanella + +diff --git a/io/tst-futimens-time64.c b/io/tst-futimens-time64.c +index 88fcb38489b160de..71204a6166eaba56 100644 +--- a/io/tst-futimens-time64.c ++++ b/io/tst-futimens-time64.c +@@ -1,2 +1 @@ +-#define struct_stat struct stat + #include "tst-futimens.c" +diff --git a/io/tst-futimens.c b/io/tst-futimens.c +index 6204befedd869bb6..075ca42b9378d98f 100644 +--- a/io/tst-futimens.c ++++ b/io/tst-futimens.c +@@ -18,26 +18,23 @@ + + #include + #include ++#include + #include + +-#ifndef struct_stat +-# define struct_stat struct stat64 +-#endif +- + static int + test_futimens_helper (const char *file, int fd, const struct timespec *ts) + { + int result = futimens (fd, ts); + TEST_VERIFY_EXIT (result == 0); + +- struct_stat st; +- xfstat (fd, &st); ++ struct statx st; ++ xstatx (fd, "", AT_EMPTY_PATH, STATX_BASIC_STATS, &st); + + /* Check if seconds for atime match */ +- TEST_COMPARE (st.st_atime, ts[0].tv_sec); ++ TEST_COMPARE (st.stx_atime.tv_sec, ts[0].tv_sec); + + /* Check if seconds for mtime match */ +- TEST_COMPARE (st.st_mtime, ts[1].tv_sec); ++ TEST_COMPARE (st.stx_mtime.tv_sec, ts[1].tv_sec); + + return 0; + } +diff --git a/io/tst-futimes-time64.c b/io/tst-futimes-time64.c +index d489c265d1964196..eeb4bed7c4f5fb12 100644 +--- a/io/tst-futimes-time64.c ++++ b/io/tst-futimes-time64.c +@@ -1,2 +1 @@ +-#define struct_stat struct stat + #include "tst-futimes.c" +diff --git a/io/tst-futimes.c b/io/tst-futimes.c +index d21acf6a24715a10..612fe460cf505547 100644 +--- a/io/tst-futimes.c ++++ b/io/tst-futimes.c +@@ -18,27 +18,24 @@ + + #include + #include ++#include + #include + #include + +-#ifndef struct_stat +-# define struct_stat struct stat64 +-#endif +- + static int + test_futimens_helper (const char *file, int fd, const struct timeval *tv) + { + int r = futimes (fd, tv); + TEST_VERIFY_EXIT (r == 0); + +- struct_stat st; +- xfstat (fd, &st); ++ struct statx st; ++ xstatx (fd, "", AT_EMPTY_PATH, STATX_BASIC_STATS, &st); + + /* Check if seconds for atime match */ +- TEST_COMPARE (st.st_atime, tv[0].tv_sec); ++ TEST_COMPARE (st.stx_atime.tv_sec, tv[0].tv_sec); + + /* Check if seconds for mtime match */ +- TEST_COMPARE (st.st_mtime, tv[1].tv_sec); ++ TEST_COMPARE (st.stx_mtime.tv_sec, tv[1].tv_sec); + + return 0; + } +diff --git a/io/tst-futimesat-time64.c b/io/tst-futimesat-time64.c +index f6c0500eefb9c98b..15853175796e59dd 100644 +--- a/io/tst-futimesat-time64.c ++++ b/io/tst-futimesat-time64.c +@@ -1,4 +1 @@ +-#define struct_stat struct stat +-#define fstat fstat +-#define fstatat fstatat + #include "io/tst-futimesat.c" +diff --git a/io/tst-futimesat.c b/io/tst-futimesat.c +index 67a8551bebf23190..feae4e7aa76ddee7 100644 +--- a/io/tst-futimesat.c ++++ b/io/tst-futimesat.c +@@ -30,12 +30,6 @@ + #include + #include + +-#ifndef struct_stat +-# define struct_stat struct stat64 +-# define fstat fstat64 +-# define fstatat fstatat64 +-#endif +- + static int dir_fd; + + static void +@@ -118,19 +112,15 @@ do_test (void) + xwrite (fd, "hello", 5); + puts ("file created"); + +- struct_stat st1; +- if (fstat (fd, &st1) != 0) +- { +- puts ("fstat64 failed"); +- return 1; +- } ++ struct statx st1; ++ xstatx (fd, "", AT_EMPTY_PATH, STATX_BASIC_STATS, &st1); + + close (fd); + + struct timeval tv[2]; +- tv[0].tv_sec = st1.st_atime + 1; ++ tv[0].tv_sec = st1.stx_atime.tv_sec + 1; + tv[0].tv_usec = 0; +- tv[1].tv_sec = st1.st_mtime + 1; ++ tv[1].tv_sec = st1.stx_mtime.tv_sec + 1; + tv[1].tv_usec = 0; + if (futimesat (dir_fd, "some-file", tv) != 0) + { +@@ -138,16 +128,12 @@ do_test (void) + return 1; + } + +- struct_stat st2; +- if (fstatat (dir_fd, "some-file", &st2, 0) != 0) +- { +- puts ("fstatat64 failed"); +- return 1; +- } ++ struct statx st2; ++ xstatx (dir_fd, "some-file", 0, STATX_BASIC_STATS, &st2); + +- if (st2.st_mtime != tv[1].tv_sec ++ if (st2.stx_mtime.tv_sec != tv[1].tv_sec + #ifdef _STATBUF_ST_NSEC +- || st2.st_mtim.tv_nsec != 0 ++ || st2.stx_mtime.tv_nsec != 0 + #endif + ) + { +diff --git a/io/tst-lutimes-time64.c b/io/tst-lutimes-time64.c +index 06caec0a91d91b6c..c5bea965dabe6cd7 100644 +--- a/io/tst-lutimes-time64.c ++++ b/io/tst-lutimes-time64.c +@@ -1,2 +1 @@ +-#define struct_stat struct stat + #include "tst-lutimes.c" +diff --git a/io/tst-lutimes.c b/io/tst-lutimes.c +index edef5ab90e8681c7..78bcc58291fdcdc8 100644 +--- a/io/tst-lutimes.c ++++ b/io/tst-lutimes.c +@@ -18,34 +18,32 @@ + + #include + #include ++#include + #include + #include + +-#ifndef struct_stat +-# define struct_stat struct stat64 +-#endif +- + static int + test_lutimes_helper (const char *testfile, int fd, const char *testlink, + const struct timeval *tv) + { +- struct_stat stfile_orig; +- xlstat (testfile, &stfile_orig); ++ struct statx stfile_orig; ++ xstatx (AT_FDCWD, testfile, AT_SYMLINK_NOFOLLOW, STATX_BASIC_STATS, ++ &stfile_orig); + + TEST_VERIFY_EXIT (lutimes (testlink, tv) == 0); + +- struct_stat stlink; +- xlstat (testlink, &stlink); ++ struct statx stlink; ++ xstatx (AT_FDCWD, testlink, AT_SYMLINK_NOFOLLOW, STATX_BASIC_STATS, &stlink); + +- TEST_COMPARE (stlink.st_atime, tv[0].tv_sec); +- TEST_COMPARE (stlink.st_mtime, tv[1].tv_sec); ++ TEST_COMPARE (stlink.stx_atime.tv_sec, tv[0].tv_sec); ++ TEST_COMPARE (stlink.stx_mtime.tv_sec, tv[1].tv_sec); + + /* Check if the timestamp from original file is not changed. */ +- struct_stat stfile; +- xlstat (testfile, &stfile); ++ struct statx stfile; ++ xstatx (AT_FDCWD, testfile, AT_SYMLINK_NOFOLLOW, STATX_BASIC_STATS, &stfile); + +- TEST_COMPARE (stfile_orig.st_atime, stfile.st_atime); +- TEST_COMPARE (stfile_orig.st_mtime, stfile.st_mtime); ++ TEST_COMPARE (stfile_orig.stx_atime.tv_sec, stfile.stx_atime.tv_sec); ++ TEST_COMPARE (stfile_orig.stx_mtime.tv_sec, stfile.stx_mtime.tv_sec); + + return 0; + } +diff --git a/io/tst-utime-time64.c b/io/tst-utime-time64.c +index eb62f59126564896..8894592a1570a366 100644 +--- a/io/tst-utime-time64.c ++++ b/io/tst-utime-time64.c +@@ -1,2 +1 @@ +-#define struct_stat struct stat + #include "tst-utime.c" +diff --git a/io/tst-utime.c b/io/tst-utime.c +index e2e6dcd04cebb7fc..f32935828923a47f 100644 +--- a/io/tst-utime.c ++++ b/io/tst-utime.c +@@ -19,26 +19,23 @@ + #include + #include + #include ++#include + #include + +-#ifndef struct_stat +-# define struct_stat struct stat64 +-#endif +- + static int + test_utime_helper (const char *file, int fd, const struct utimbuf *ut) + { + int result = utime (file, ut); + TEST_VERIFY_EXIT (result == 0); + +- struct_stat st; +- xfstat (fd, &st); ++ struct statx st; ++ xstatx (fd, "", AT_EMPTY_PATH, STATX_BASIC_STATS, &st); + + /* Check if seconds for actime match */ +- TEST_COMPARE (st.st_atime, ut->actime); ++ TEST_COMPARE (st.stx_atime.tv_sec, ut->actime); + + /* Check if seconds for modtime match */ +- TEST_COMPARE (st.st_mtime, ut->modtime); ++ TEST_COMPARE (st.stx_mtime.tv_sec, ut->modtime); + + return 0; + } +diff --git a/io/tst-utimensat-time64.c b/io/tst-utimensat-time64.c +index 7ac7d8df1d48f0a0..5d60fce8818f7545 100644 +--- a/io/tst-utimensat-time64.c ++++ b/io/tst-utimensat-time64.c +@@ -1,2 +1 @@ +-#define struct_stat struct stat + #include "tst-utimensat.c" +diff --git a/io/tst-utimensat.c b/io/tst-utimensat.c +index 3d9a72c4719cc6c9..2a756d7b07b6b07f 100644 +--- a/io/tst-utimensat.c ++++ b/io/tst-utimensat.c +@@ -22,10 +22,6 @@ + #include + #include + +-#ifndef struct_stat +-# define struct_stat struct stat64 +-#endif +- + static int + test_utimesat_helper (const char *testfile, int fd, const char *testlink, + const struct timespec *ts) +@@ -33,35 +29,38 @@ test_utimesat_helper (const char *testfile, int fd, const char *testlink, + { + TEST_VERIFY_EXIT (utimensat (fd, testfile, ts, 0) == 0); + +- struct_stat st; +- xfstat (fd, &st); ++ struct statx st; ++ xstatx (fd, "", AT_EMPTY_PATH, STATX_BASIC_STATS, &st); + + /* Check if seconds for atime match */ +- TEST_COMPARE (st.st_atime, ts[0].tv_sec); ++ TEST_COMPARE (st.stx_atime.tv_sec, ts[0].tv_sec); + + /* Check if seconds for mtime match */ +- TEST_COMPARE (st.st_mtime, ts[1].tv_sec); ++ TEST_COMPARE (st.stx_mtime.tv_sec, ts[1].tv_sec); + } + + { +- struct_stat stfile_orig; +- xlstat (testfile, &stfile_orig); ++ struct statx stfile_orig; ++ xstatx (AT_FDCWD, testfile, AT_SYMLINK_NOFOLLOW, STATX_BASIC_STATS, ++ &stfile_orig); + + TEST_VERIFY_EXIT (utimensat (0 /* ignored */, testlink, ts, + AT_SYMLINK_NOFOLLOW) + == 0); +- struct_stat stlink; +- xlstat (testlink, &stlink); ++ struct statx stlink; ++ xstatx (AT_FDCWD, testlink, AT_SYMLINK_NOFOLLOW, STATX_BASIC_STATS, ++ &stlink); + +- TEST_COMPARE (stlink.st_atime, ts[0].tv_sec); +- TEST_COMPARE (stlink.st_mtime, ts[1].tv_sec); ++ TEST_COMPARE (stlink.stx_atime.tv_sec, ts[0].tv_sec); ++ TEST_COMPARE (stlink.stx_mtime.tv_sec, ts[1].tv_sec); + + /* Check if the timestamp from original file is not changed. */ +- struct_stat stfile; +- xlstat (testfile, &stfile); ++ struct statx stfile; ++ xstatx (AT_FDCWD, testfile, AT_SYMLINK_NOFOLLOW, STATX_BASIC_STATS, ++ &stfile); + +- TEST_COMPARE (stfile_orig.st_atime, stfile.st_atime); +- TEST_COMPARE (stfile_orig.st_mtime, stfile.st_mtime); ++ TEST_COMPARE (stfile_orig.stx_atime.tv_sec, stfile.stx_atime.tv_sec); ++ TEST_COMPARE (stfile_orig.stx_mtime.tv_sec, stfile.stx_mtime.tv_sec); + } + + return 0; +diff --git a/io/tst-utimes-time64.c b/io/tst-utimes-time64.c +index 234ec02541032017..026ef5f78dd4616c 100644 +--- a/io/tst-utimes-time64.c ++++ b/io/tst-utimes-time64.c +@@ -1,2 +1 @@ +-#define struct_stat struct stat + #include "tst-utimes.c" +diff --git a/io/tst-utimes.c b/io/tst-utimes.c +index 8edcfabebfbd978d..6cd436c5a0f94d84 100644 +--- a/io/tst-utimes.c ++++ b/io/tst-utimes.c +@@ -18,28 +18,25 @@ + + #include + #include ++#include + #include + #include + #include + +-#ifndef struct_stat +-# define struct_stat struct stat64 +-#endif +- + static int + test_utimes_helper (const char *file, int fd, const struct timeval *tv) + { + int result = utimes (file, tv); + TEST_VERIFY_EXIT (result == 0); + +- struct_stat st; +- xfstat (fd, &st); ++ struct statx st; ++ xstatx (fd, "", AT_EMPTY_PATH, STATX_BASIC_STATS, &st); + + /* Check if seconds for atime match */ +- TEST_COMPARE (st.st_atime, tv[0].tv_sec); ++ TEST_COMPARE (st.stx_atime.tv_sec, tv[0].tv_sec); + + /* Check if seconds for mtime match */ +- TEST_COMPARE (st.st_mtime, tv[1].tv_sec); ++ TEST_COMPARE (st.stx_mtime.tv_sec, tv[1].tv_sec); + + return 0; + } diff --git a/glibc-RHEL-106562-7.patch b/glibc-RHEL-106562-7.patch new file mode 100644 index 0000000..569a715 --- /dev/null +++ b/glibc-RHEL-106562-7.patch @@ -0,0 +1,415 @@ +commit e7c14e542d8d858b824b5df4f4e3dc93695e6171 +Author: Florian Weimer +Date: Fri Aug 16 16:05:20 2024 +0200 + + support: Use macros for *stat wrappers + + Macros will automatically use the correct types, without + having to fiddle with internal glibc macros. It's also + impossible to get the types wrong due to aliasing because + support_check_stat_fd and support_check_stat_path do not + depend on the struct stat* types. + + The changes reveal some inconsistencies in tests. + + Reviewed-by: Adhemerval Zanella + +diff --git a/elf/tst-ldconfig-bad-aux-cache.c b/elf/tst-ldconfig-bad-aux-cache.c +index 7f1fbb52523ac1ac..8c2e62ecc2c54c04 100644 +--- a/elf/tst-ldconfig-bad-aux-cache.c ++++ b/elf/tst-ldconfig-bad-aux-cache.c +@@ -85,7 +85,7 @@ do_test (void) + support_capture_subprocess_check (&result, "execv", 0, sc_allow_none); + support_capture_subprocess_free (&result); + +- xstat (path, &fs); ++ xstat64 (path, &fs); + + size = fs.st_size; + /* Run 3 tests, each truncating aux-cache shorter and shorter. */ +diff --git a/io/tst-copy_file_range.c b/io/tst-copy_file_range.c +index 9837b7c3395725a5..3d7b0aa90160190a 100644 +--- a/io/tst-copy_file_range.c ++++ b/io/tst-copy_file_range.c +@@ -117,7 +117,7 @@ simple_file_copy (void) + TEST_COMPARE (xlseek (outfd, 0, SEEK_CUR), 6 + length); + + struct stat64 st; +- xfstat (outfd, &st); ++ xfstat64 (outfd, &st); + if (length > 0) + TEST_COMPARE (st.st_size, out_skipped + length); + else +diff --git a/io/tst-statx.c b/io/tst-statx.c +index d84568859eb5c604..685924ae76245676 100644 +--- a/io/tst-statx.c ++++ b/io/tst-statx.c +@@ -78,7 +78,7 @@ both_implementations_tests (statx_function impl, const char *path, int fd) + struct statx stx = { 0, }; + TEST_COMPARE (statx (fd, "", AT_EMPTY_PATH, STATX_BASIC_STATS, &stx), 0); + struct stat64 st; +- xfstat (fd, &st); ++ xfstat64 (fd, &st); + TEST_COMPARE (stx.stx_mode, st.st_mode); + TEST_COMPARE (stx.stx_dev_major, major (st.st_dev)); + TEST_COMPARE (stx.stx_dev_minor, minor (st.st_dev)); +@@ -88,7 +88,7 @@ both_implementations_tests (statx_function impl, const char *path, int fd) + TEST_COMPARE (statx (AT_FDCWD, "/dev/null", 0, STATX_BASIC_STATS, &stx), + 0); + struct stat64 st; +- xstat ("/dev/null", &st); ++ xstat64 ("/dev/null", &st); + TEST_COMPARE (stx.stx_mode, st.st_mode); + TEST_COMPARE (stx.stx_dev_major, major (st.st_dev)); + TEST_COMPARE (stx.stx_dev_minor, minor (st.st_dev)); +diff --git a/locale/tst-localedef-path-norm.c b/locale/tst-localedef-path-norm.c +index ffe8cbd46732386f..f592b9a9605bff94 100644 +--- a/locale/tst-localedef-path-norm.c ++++ b/locale/tst-localedef-path-norm.c +@@ -84,7 +84,7 @@ run_test (void *closure) + support_capture_subprocess_free (&result); + + /* Verify path is present and is a directory. */ +- xstat (path, &fs); ++ xstat64 (path, &fs); + if (!S_ISDIR (fs.st_mode)) + { + support_record_failure (); +diff --git a/localedata/tst-localedef-hardlinks.c b/localedata/tst-localedef-hardlinks.c +index e88215a1507bb30a..23927b462fc2224a 100644 +--- a/localedata/tst-localedef-hardlinks.c ++++ b/localedata/tst-localedef-hardlinks.c +@@ -62,7 +62,7 @@ check_link (struct test_data step) + char *output; + + output = xasprintf ("%s/%s", support_complocaledir_prefix, step.output); +- xstat (output, &locale); ++ xstat64 (output, &locale); + free (output); + TEST_COMPARE (locale.st_nlink, step.st_nlink); + } +diff --git a/posix/tst-execveat.c b/posix/tst-execveat.c +index 4565d6b19f41ca63..dde034a9f1356453 100644 +--- a/posix/tst-execveat.c ++++ b/posix/tst-execveat.c +@@ -155,7 +155,7 @@ do_test (void) + tmp_sh = xasprintf ("%s/tmp_sh", tmp_dir); + add_temp_file (tmp_sh); + fd_out = xopen (symlink_name, O_CREAT | O_WRONLY, 0); +- xstat ("/bin/sh", &st); ++ xstat64 ("/bin/sh", &st); + fd = xopen ("/bin/sh", O_RDONLY, 0); + xcopy_file_range (fd, 0, fd_out, 0, st.st_size, 0); + xfchmod (fd_out, 0700); +diff --git a/stdio-common/tst-renameat2.c b/stdio-common/tst-renameat2.c +index b65afed75ec65ca4..7f4345f716182552 100644 +--- a/stdio-common/tst-renameat2.c ++++ b/stdio-common/tst-renameat2.c +@@ -82,7 +82,7 @@ static void + check_size (const char *path, off64_t expected_size) + { + struct stat64 st; +- xstat (path, &st); ++ xstat64 (path, &st); + if (st.st_size != expected_size) + FAIL_EXIT1 ("file \"%s\": expected size %lld, actual size %lld", + path, (unsigned long long int) expected_size, +diff --git a/stdlib/tst-system.c b/stdlib/tst-system.c +index 47c742f963a1b6b4..b5b630a41b9e4663 100644 +--- a/stdlib/tst-system.c ++++ b/stdlib/tst-system.c +@@ -169,7 +169,7 @@ do_test (void) + + { + struct stat64 st; +- xstat (_PATH_BSHELL, &st); ++ xstat64 (_PATH_BSHELL, &st); + mode_t mode = st.st_mode; + xchmod (_PATH_BSHELL, mode & ~(S_IXUSR | S_IXGRP | S_IXOTH)); + +diff --git a/support/Makefile b/support/Makefile +index 5b1c96a49e9410f4..6e3c55394fa212b6 100644 +--- a/support/Makefile ++++ b/support/Makefile +@@ -42,14 +42,12 @@ libsupport-routines = \ + resolv_test \ + set_fortify_handler \ + support-open-dev-null-range \ +- support-xfstat \ +- support-xfstat-time64 \ +- support-xstat \ +- support-xstat-time64 \ + support_become_root \ + support_can_chroot \ + support_capture_subprocess \ + support_capture_subprocess_check \ ++ support_check_stat_fd \ ++ support_check_stat_path \ + support_chroot \ + support_copy_file \ + support_copy_file_range \ +@@ -135,8 +133,6 @@ libsupport-routines = \ + xgetsockname \ + xlisten \ + xlseek \ +- xlstat \ +- xlstat-time64 \ + xmalloc \ + xmemstream \ + xmkdir \ +diff --git a/support/support-xfstat-time64.c b/support/support-xfstat-time64.c +deleted file mode 100644 +index 589a69bb3e04857d..0000000000000000 +--- a/support/support-xfstat-time64.c ++++ /dev/null +@@ -1,32 +0,0 @@ +-/* 64-bit time_t stat with error checking. +- Copyright (C) 2021-2024 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 +- . */ +- +-/* NB: Non-standard file name to avoid sysdeps override for xstat. */ +- +-#include +-#include +-#include +- +-#if __TIMESIZE != 64 +-void +-xfstat_time64 (int fd, struct __stat64_t64 *result) +-{ +- if (__fstat64_time64 (fd, result) != 0) +- FAIL_EXIT1 ("__fstat64_time64 (%d): %m", fd); +-} +-#endif +diff --git a/support/support-xstat-time64.c b/support/support-xstat-time64.c +deleted file mode 100644 +index 451948734ae0de0f..0000000000000000 +--- a/support/support-xstat-time64.c ++++ /dev/null +@@ -1,32 +0,0 @@ +-/* 64-bit time_t stat with error checking. +- Copyright (C) 2021-2024 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 +- . */ +- +-/* NB: Non-standard file name to avoid sysdeps override for xstat. */ +- +-#include +-#include +-#include +- +-#if __TIMESIZE != 64 +-void +-xstat_time64 (const char *path, struct __stat64_t64 *result) +-{ +- if (__stat64_time64 (path, result) != 0) +- FAIL_EXIT1 ("__stat64_time64 (\"%s\"): %m", path); +-} +-#endif +diff --git a/support/support-xstat.c b/support/support-xstat.c +deleted file mode 100644 +index ce866f74d242c07a..0000000000000000 +--- a/support/support-xstat.c ++++ /dev/null +@@ -1,30 +0,0 @@ +-/* stat64 with error checking. +- Copyright (C) 2017-2024 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 +- . */ +- +-/* NB: Non-standard file name to avoid sysdeps override for xstat. */ +- +-#include +-#include +-#include +- +-void +-xstat (const char *path, struct stat64 *result) +-{ +- if (stat64 (path, result) != 0) +- FAIL_EXIT1 ("stat64 (\"%s\"): %m", path); +-} +diff --git a/support/xlstat.c b/support/support_check_stat_fd.c +similarity index 76% +rename from support/xlstat.c +rename to support/support_check_stat_fd.c +index 87df988879094d5b..4c12adf6b7f68d0c 100644 +--- a/support/xlstat.c ++++ b/support/support_check_stat_fd.c +@@ -1,5 +1,5 @@ +-/* lstat64 with error checking. +- Copyright (C) 2017-2024 Free Software Foundation, Inc. ++/* Error checking for descriptor-based stat functions. ++ Copyright (C) 2024 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 +@@ -18,11 +18,10 @@ + + #include + #include +-#include + + void +-xlstat (const char *path, struct stat64 *result) ++support_check_stat_fd (const char *name, int fd, int result) + { +- if (lstat64 (path, result) != 0) +- FAIL_EXIT1 ("lstat64 (\"%s\"): %m", path); ++ if (result != 0) ++ FAIL_EXIT1 ("%s (%d): %m", name, fd); + } +diff --git a/support/support-xfstat.c b/support/support_check_stat_path.c +similarity index 81% +rename from support/support-xfstat.c +rename to support/support_check_stat_path.c +index ab4b01c97d7b5f2f..3cf72afe5901dcd5 100644 +--- a/support/support-xfstat.c ++++ b/support/support_check_stat_path.c +@@ -1,4 +1,4 @@ +-/* fstat64 with error checking. ++/* Error checking for path-based stat functions. + Copyright (C) 2017-2024 Free Software Foundation, Inc. + This file is part of the GNU C Library. + +@@ -18,11 +18,10 @@ + + #include + #include +-#include + + void +-xfstat (int fd, struct stat64 *result) ++support_check_stat_path (const char *name, const char *path, int result) + { +- if (fstat64 (fd, result) != 0) +- FAIL_EXIT1 ("fstat64 (%d): %m", fd); ++ if (result != 0) ++ FAIL_EXIT1 ("%s (\"%s\"): %m", name, path); + } +diff --git a/support/xlstat-time64.c b/support/xlstat-time64.c +deleted file mode 100644 +index 2bc3ca6593bd397d..0000000000000000 +--- a/support/xlstat-time64.c ++++ /dev/null +@@ -1,32 +0,0 @@ +-/* 64-bit time_t stat with error checking. +- Copyright (C) 2021-2024 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 +- . */ +- +-/* NB: Non-standard file name to avoid sysdeps override for xstat. */ +- +-#include +-#include +-#include +- +-#if __TIMESIZE != 64 +-void +-xlstat_time64 (const char *path, struct __stat64_t64 *result) +-{ +- if (__lstat64_time64 (path, result) != 0) +- FAIL_EXIT1 ("__lstat64_time64 (\"%s\"): %m", path); +-} +-#endif +diff --git a/support/xunistd.h b/support/xunistd.h +index cc74c4fad07dd088..204951bce75f576b 100644 +--- a/support/xunistd.h ++++ b/support/xunistd.h +@@ -29,7 +29,6 @@ + + __BEGIN_DECLS + +-struct stat64; + struct statx; + + pid_t xfork (void); +@@ -37,21 +36,20 @@ 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); +-#ifndef __USE_TIME64_REDIRECTS +-# ifdef __USE_FILE_OFFSET64 +-void xstat (const char *path, struct stat *); +-void xlstat (const char *path, struct stat *); +-void xfstat (int fd, struct stat *); +-# else +-void xstat (const char *path, struct stat64 *); +-void xlstat (const char *path, struct stat64 *); +-void xfstat (int fd, struct stat64 *); +-# endif +-#else +-void __REDIRECT (xstat, (const char *path, struct stat *), xstat_time64); +-void __REDIRECT (xlstat, (const char *path, struct stat *), xlstat_time64); +-void __REDIRECT (xfstat, (int fd, struct stat *), xfstat_time64); +-#endif ++void support_check_stat_fd (const char *name, int fd, int result); ++void support_check_stat_path (const char *name, const char *path, int result); ++#define xstat(path, st) \ ++ (support_check_stat_path ("stat", (path), stat ((path), (st)))) ++#define xfstat(fd, st) \ ++ (support_check_stat_fd ("fstat", (fd), fstat ((fd), (st)))) ++#define xlstat(path, st) \ ++ (support_check_stat_path ("lstat", (path), lstat ((path), (st)))) ++#define xstat64(path, st) \ ++ (support_check_stat_path ("stat64", (path), stat64 ((path), (st)))) ++#define xfstat64(fd, st) \ ++ (support_check_stat_fd ("fstat64", (fd), fstat64 ((fd), (st)))) ++#define xlstat64(path, st) \ ++ (support_check_stat_path ("lstat64", (path), lstat64 ((path), (st)))) + void xstatx (int, const char *, int, unsigned int, struct statx *); + void xmkdir (const char *path, mode_t); + void xchroot (const char *path); diff --git a/glibc-RHEL-106562-8.patch b/glibc-RHEL-106562-8.patch new file mode 100644 index 0000000..2eb8c05 --- /dev/null +++ b/glibc-RHEL-106562-8.patch @@ -0,0 +1,148 @@ +commit 2eee835eca960c9d4119279804214b7a1ed5d156 +Author: DJ Delorie +Date: Thu Aug 8 22:44:56 2024 -0400 + + inet: test if_nametoindex and if_indextoname + + Tests for if_nameindex, if_name2index, and if_index2name + + Tests that valid results are consistent. + + Tests that invalid parameters fail correctly. + + Reviewed-by: Florian Weimer + +diff --git a/inet/Makefile b/inet/Makefile +index 2f03e6f7ee211525..cb97b45f0f9d223f 100644 +--- a/inet/Makefile ++++ b/inet/Makefile +@@ -91,6 +91,7 @@ tests := \ + tst-getni1 \ + tst-getni2 \ + tst-if_index-long \ ++ tst-if_nameindex \ + tst-inet6_rth \ + tst-network \ + tst-ntoa \ +diff --git a/inet/tst-if_nameindex.c b/inet/tst-if_nameindex.c +new file mode 100644 +index 0000000000000000..b025cdb3a7c6b68c +--- /dev/null ++++ b/inet/tst-if_nameindex.c +@@ -0,0 +1,116 @@ ++/* Tests for if_nameindex et al. ++ Copyright (C) 2024 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static char *buffer; ++ ++static const char *test_names[] = { ++ "testing", ++ "invalid", ++ "dont-match", ++ "", ++ "\001\001\001\177", ++ NULL ++}; ++ ++static void ++checki (int i) ++{ ++ char *ifname; ++ ++ /* Test that a known-invalid index returns NULL. */ ++ /* BUFFER should not be accessed. */ ++ ++ printf ("Testing if_indextoname (%d) == NULL\n", i); ++ ifname = if_indextoname (i, NULL); ++ TEST_VERIFY (ifname == NULL); ++ TEST_VERIFY (errno == ENXIO); ++} ++ ++static int ++do_test (void) ++{ ++ struct if_nameindex *if_ni, *ifp; ++ int min_idx, max_idx, buflen = 0; ++ int i; ++ ++ if_ni = if_nameindex (); ++ TEST_VERIFY (if_ni != NULL); ++ ++ min_idx = max_idx = if_ni->if_index; ++ ++ for (ifp = if_ni; !(ifp->if_index == 0 && ifp->if_name == NULL); ifp++) ++ { ++ printf ("%u: %s\n", ifp->if_index, ifp->if_name); ++ if (ifp->if_index < min_idx) ++ min_idx = ifp->if_index; ++ if (ifp->if_index > max_idx) ++ max_idx = ifp->if_index; ++ if (strlen (ifp->if_name) + 1 > buflen) ++ buflen = strlen (ifp->if_name) + 1; ++ } ++ buffer = (char *) xmalloc (buflen); ++ ++ /* Check normal operation. */ ++ for (ifp = if_ni; !(ifp->if_index == 0 && ifp->if_name == NULL); ifp++) ++ { ++ unsigned int idx = if_nametoindex (ifp->if_name); ++ TEST_VERIFY (idx == ifp->if_index); ++ ++ char *fn = if_indextoname (ifp->if_index, buffer); ++ TEST_VERIFY (strcmp (fn, ifp->if_name) == 0); ++ } ++ ++ for (i=-2; iif_index == 0 && ifp->if_name == NULL); ifp++) ++ if (strcmp (test_names[i], ifp->if_name) == 0) ++ goto not_this_one; ++ ++ printf ("Testing if_nametoindex (%s) == 0\n", test_names[i]); ++ ++ unsigned int idx = if_nametoindex (test_names[i]); ++ TEST_VERIFY (idx == 0); ++ TEST_VERIFY (errno == ENODEV); ++ ++ not_this_one: ++ } ++ ++ ++ if_freenameindex (if_ni); ++ ++ return 0; ++} ++ ++#include diff --git a/glibc-RHEL-106562-9.patch b/glibc-RHEL-106562-9.patch new file mode 100644 index 0000000..e7b1bda --- /dev/null +++ b/glibc-RHEL-106562-9.patch @@ -0,0 +1,79 @@ +commit 55cd51d971b84fbb2cc0fe8140cc8581f98582c7 +Author: Joseph Myers +Date: Thu Aug 22 11:25:14 2024 +0000 + + Test mkdirat use of mode argument + + The test io/tst-mkdirat doesn't verify the permissions on the created + directory (thus, doesn't verify at all anything about how mkdirat uses + the mode argument). Add checks of this to the existing test. + + Tested for x86_64. + +diff --git a/io/tst-mkdirat.c b/io/tst-mkdirat.c +index 605e51ef1e966b42..b97bc3ca6d0cdf23 100644 +--- a/io/tst-mkdirat.c ++++ b/io/tst-mkdirat.c +@@ -53,6 +53,10 @@ prepare (void) + static int + do_test (void) + { ++ /* Find the current umask. */ ++ mode_t mask = umask (022); ++ umask (mask); ++ + /* fdopendir takes over the descriptor, make a copy. */ + int dupfd = dup (dir_fd); + if (dupfd == -1) +@@ -107,6 +111,13 @@ do_test (void) + puts ("mkdirat did not create a directory"); + return 1; + } ++ if ((st1.st_mode & 01777) != (~mask & 0777)) ++ { ++ printf ("mkdirat created directory with wrong mode %o, expected %o\n", ++ (unsigned int) (st1.st_mode & 01777), ++ (unsigned int) (~mask & 0777)); ++ return 1; ++ } + + dupfd = dup (dir_fd); + if (dupfd == -1) +@@ -156,6 +167,37 @@ do_test (void) + return 1; + } + ++ /* Test again with a different mode. */ ++ umask (0); ++ e = mkdirat (dir_fd, "some-dir", 01755); ++ umask (mask); ++ if (e == -1) ++ { ++ puts ("directory creation (different mode) failed"); ++ return 1; ++ } ++ if (fstatat64 (dir_fd, "some-dir", &st1, 0) != 0) ++ { ++ puts ("fstat64 (different mode) failed"); ++ return 1; ++ } ++ if (!S_ISDIR (st1.st_mode)) ++ { ++ puts ("mkdirat (different mode) did not create a directory"); ++ return 1; ++ } ++ if ((st1.st_mode & 01777) != 01755) ++ { ++ printf ("mkdirat (different mode) created directory with wrong mode %o\n", ++ (unsigned int) (st1.st_mode & 01777)); ++ return 1; ++ } ++ if (unlinkat (dir_fd, "some-dir", AT_REMOVEDIR) != 0) ++ { ++ puts ("unlinkat (different mode) failed"); ++ return 1; ++ } ++ + close (dir_fd); + + return 0; diff --git a/glibc-RHEL-107540-1.patch b/glibc-RHEL-107540-1.patch new file mode 100644 index 0000000..e3eedb7 --- /dev/null +++ b/glibc-RHEL-107540-1.patch @@ -0,0 +1,262 @@ +commit 5653ccd847f0cd3a98906e44c97c71d68652d326 +Author: Florian Weimer +Date: Mon Apr 8 16:48:55 2024 +0200 + + elf: Add CPU iteration support for future use in ld.so diagnostics + + Reviewed-by: Szabolcs Nagy + +diff --git a/elf/dl-iterate_cpu.h b/elf/dl-iterate_cpu.h +new file mode 100644 +index 0000000000000000..60db167b13e2d377 +--- /dev/null ++++ b/elf/dl-iterate_cpu.h +@@ -0,0 +1,136 @@ ++/* Iterate over all CPUs, for CPU-specific diagnostics. ++ Copyright (C) 2024 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 ++ . */ ++ ++#ifndef DL_ITERATE_CPU_H ++#define DL_ITERATE_CPU_H ++ ++#include ++#include ++ ++struct dl_iterate_cpu ++{ ++ /* Sequential iteration count, starting at 0. */ ++ unsigned int processor_index; ++ ++ /* Requested CPU. Can be -1 if affinity could not be set. */ ++ int requested_cpu; ++ ++ /* Observed current CPU. -1 if unavailable. */ ++ int actual_cpu; ++ ++ /* Observed node ID for the CPU. -1 if unavailable. */ ++ int actual_node; ++ ++ /* Internal fields to implement the iteration. */ ++ ++ /* Affinity as obtained by _dl_iterate_cpu_init, using ++ _dl_getaffinity. Space for 8,192 CPUs. */ ++ unsigned long int mask_reference[8192 / sizeof (unsigned long int) / 8]; ++ ++ /* This array is used by _dl_setaffinity calls. */ ++ unsigned long int mask_request[8192 / sizeof (unsigned long int) / 8]; ++ ++ /* Return value from the initial _dl_getaffinity call. */ ++ int length_reference; ++}; ++ ++static void ++_dl_iterate_cpu_init (struct dl_iterate_cpu *dic) ++{ ++ dic->length_reference ++ = _dl_getaffinity (dic->mask_reference, sizeof (dic->mask_reference)); ++ /* Prepare for the first _dl_iterate_cpu_next call. */ ++ dic->processor_index = -1; ++ dic->requested_cpu = -1; ++} ++ ++static bool ++_dl_iterate_cpu_next (struct dl_iterate_cpu *dic) ++{ ++ ++dic->processor_index; ++ ++ if (dic->length_reference > 0) ++ { ++ /* Search for the next CPU to switch to. */ ++ while (true) ++ { ++ ++dic->requested_cpu; ++ ++ /* Array index and bit number within the array. */ ++ unsigned int long_index ++ = dic->requested_cpu / sizeof (unsigned long int) / 8; ++ unsigned int bit_index ++ = dic->requested_cpu % (sizeof (unsigned long int) * 8); ++ ++ if (long_index * sizeof (unsigned long int) >= dic->length_reference) ++ /* All possible CPUs have been covered. */ ++ return false; ++ ++ unsigned long int bit = 1UL << bit_index; ++ if (dic->mask_reference[long_index] & bit) ++ { ++ /* The CPU is available. Try to select it. */ ++ dic->mask_request[long_index] = bit; ++ if (_dl_setaffinity (dic->mask_request, ++ (long_index + 1) ++ * sizeof (unsigned long int)) < 0) ++ { ++ /* Record that we could not perform a CPU request. */ ++ dic->length_reference = -1; ++ ++ if (dic->processor_index > 0) ++ /* We already reported something. There is no need to ++ continue because the new data is probably not useful. */ ++ return false; ++ } ++ ++ /* Clear the bit in case the next iteration switches to the ++ next long value. */ ++ dic->mask_request[long_index] = 0; ++ ++ /* We found a CPU to run on. */ ++ break; ++ } ++ } ++ } ++ else ++ { ++ /* No way to set CPU affinity. Iterate just once. */ ++ if (dic->processor_index > 0) ++ return false; ++ } ++ ++ /* Fill in the actual CPU information. CPU pinning may not actually ++ be effective, depending on the container host. */ ++ unsigned int cpu, node; ++ if (_dl_getcpu (&cpu, &node) < 0) ++ { ++ /* No CPU information available. */ ++ dic->actual_cpu = -1; ++ dic->actual_node = -1; ++ } ++ else ++ { ++ dic->actual_cpu = cpu; ++ dic->actual_node = node; ++ } ++ ++ return true; ++} ++ ++#endif /* DL_ITERATE_CPU_H */ +diff --git a/sysdeps/generic/dl-affinity.h b/sysdeps/generic/dl-affinity.h +new file mode 100644 +index 0000000000000000..d117f737e98712e0 +--- /dev/null ++++ b/sysdeps/generic/dl-affinity.h +@@ -0,0 +1,54 @@ ++/* CPU affinity handling for the dynamic linker. Stub version. ++ Copyright (C) 2024 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 ++ . */ ++ ++#ifndef DL_AFFINITY_H ++#define DL_AFFINITY_H ++ ++#include ++#include ++ ++/* On success, write the current CPU ID to *CPU, and the current node ++ ID to *NODE, and return 0. Return a negative error code on ++ failure. */ ++static inline int ++_dl_getcpu (unsigned int *cpu, unsigned int *node) ++{ ++ return -ENOSYS; ++} ++ ++/* On success, write CPU ID affinity bits for the current thread to ++ *BITS, which must be SIZE bytes long, and return the number of ++ bytes updated, a multiple of sizeof (unsigned long int). On ++ failure, return a negative error code. */ ++static int ++_dl_getaffinity (unsigned long int *bits, size_t size) ++{ ++ return -ENOSYS; ++} ++ ++/* Set the CPU affinity mask for the current thread to *BITS, using ++ the SIZE bytes from that array, which should be a multiple of ++ sizeof (unsigned long int). Return 0 on success, and a negative ++ error code on failure. */ ++static int ++_dl_setaffinity (const unsigned long int *bits, size_t size) ++{ ++ return -ENOSYS; ++} ++ ++#endif /* DL_AFFINITY_H */ +diff --git a/sysdeps/unix/sysv/linux/dl-affinity.h b/sysdeps/unix/sysv/linux/dl-affinity.h +new file mode 100644 +index 0000000000000000..bbfede7750a3037f +--- /dev/null ++++ b/sysdeps/unix/sysv/linux/dl-affinity.h +@@ -0,0 +1,46 @@ ++/* CPU affinity handling for the dynamic linker. Linux version. ++ Copyright (C) 2024 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 ++ . */ ++ ++/* See sysdeps/generic/dl-affinity.h for documentation of these interfaces. */ ++ ++#ifndef DL_AFFINITY_H ++#define DL_AFFINITY_H ++ ++#include ++#include ++#include ++ ++static inline int ++_dl_getcpu (unsigned int *cpu, unsigned int *node) ++{ ++ return INTERNAL_SYSCALL_CALL (getcpu, cpu, node); ++} ++ ++static int ++_dl_getaffinity (unsigned long int *bits, size_t size) ++{ ++ return INTERNAL_SYSCALL_CALL (sched_getaffinity, /* TID */ 0, size, bits); ++} ++ ++static int ++_dl_setaffinity (const unsigned long int *bits, size_t size) ++{ ++ return INTERNAL_SYSCALL_CALL (sched_setaffinity, /* TID */ 0, size, bits); ++} ++ ++#endif /* DL_AFFINITY_H */ diff --git a/glibc-RHEL-107540-2.patch b/glibc-RHEL-107540-2.patch new file mode 100644 index 0000000..0401b32 --- /dev/null +++ b/glibc-RHEL-107540-2.patch @@ -0,0 +1,512 @@ +commit 7a430f40c46acfa7ce4c3bff193b278c190b2efc +Author: Florian Weimer +Date: Mon Apr 8 16:48:55 2024 +0200 + + x86: Add generic CPUID data dumper to ld.so --list-diagnostics + + This is surprisingly difficult to implement if the goal is to produce + reasonably sized output. With the current approaches to output + compression (suppressing zeros and repeated results between CPUs, + folding ranges of identical subleaves, dealing with the %ecx + reflection issue), the output is less than 600 KiB even for systems + with 256 logical CPUs. + + Reviewed-by: H.J. Lu + +diff --git a/manual/dynlink.texi b/manual/dynlink.texi +index 5a93de0df6b60214..d71f7a30d6f46808 100644 +--- a/manual/dynlink.texi ++++ b/manual/dynlink.texi +@@ -262,7 +262,90 @@ The value of the @code{dczid_el0} system register on the processor + @item x86.cpu_features.@dots{} + These items are specific to the i386 and x86-64 architectures. They + reflect supported CPU features and information on cache geometry, mostly +-collected using the @code{CPUID} instruction. ++collected using the CPUID instruction. ++ ++@item x86.processor[@var{index}].@dots{} ++These are additional items for the i386 and x86-64 architectures, as ++described below. They mostly contain raw data from the CPUID ++instruction. The probes are performed for each active CPU for the ++@code{ld.so} process, and data for different probed CPUs receives a ++uniqe @var{index} value. Some CPUID data is expected to differ from CPU ++core to CPU core. In some cases, CPUs are not correctly initialized and ++indicate the presence of different feature sets. ++ ++@item x86.processor[@var{index}].requested=@var{kernel-cpu} ++The kernel is told to run the subsequent probing on the CPU numbered ++@var{kernel-cpu}. The values @var{kernel-cpu} and @var{index} can be ++distinct if there are gaps in the process CPU affinity mask. This line ++is not included if CPU affinity mask information is not available. ++ ++@item x86.processor[@var{index}].observed=@var{kernel-cpu} ++This line reports the kernel CPU number @var{kernel-cpu} on which the ++probing code initially ran. If the CPU number cannot be obtained, ++this line is not printed. ++ ++@item x86.processor[@var{index}].observed_node=@var{node} ++This reports the observed NUMA node number, as reported by the ++@code{getcpu} system call. If this information cannot be obtained, this ++line is not printed. ++ ++@item x86.processor[@var{index}].cpuid_leaves=@var{count} ++This line indicates that @var{count} distinct CPUID leaves were ++encountered. (This reflects internal @code{ld.so} storage space, it ++does not directly correspond to @code{CPUID} enumeration ranges.) ++ ++@item x86.processor[@var{index}].ecx_limit=@var{value} ++The CPUID data extraction code uses a brute-force approach to enumerate ++subleaves (see the @samp{.subleaf_eax} lines below). The last ++@code{%rcx} value used in a CPUID query on this probed CPU was ++@var{value}. ++ ++@item x86.processor[@var{index}].cpuid.eax[@var{query_eax}].eax=@var{eax} ++@itemx x86.processor[@var{index}].cpuid.eax[@var{query_eax}].ebx=@var{ebx} ++@itemx x86.processor[@var{index}].cpuid.eax[@var{query_eax}].ecx=@var{ecx} ++@itemx x86.processor[@var{index}].cpuid.eax[@var{query_eax}].edx=@var{edx} ++These lines report the register contents after executing the CPUID ++instruction with @samp{%rax == @var{query_eax}} and @samp{%rcx == 0} (a ++@dfn{leaf}). For the first probed CPU (with a zero @var{index}), only ++leaves with non-zero register contents are reported. For subsequent ++CPUs, only leaves whose register contents differs from the previously ++probed CPUs (with @var{index} one less) are reported. ++ ++Basic and extended leaves are reported using the same syntax. This ++means there is a large jump in @var{query_eax} for the first reported ++extended leaf. ++ ++@item x86.processor[@var{index}].cpuid.subleaf_eax[@var{query_eax}].ecx[@var{query_ecx}].eax=@var{eax} ++@itemx x86.processor[@var{index}].cpuid.subleaf_eax[@var{query_eax}].ecx[@var{query_ecx}].ebx=@var{ebx} ++@itemx x86.processor[@var{index}].cpuid.subleaf_eax[@var{query_eax}].ecx[@var{query_ecx}].ecx=@var{ecx} ++@itemx x86.processor[@var{index}].cpuid.subleaf_eax[@var{query_eax}].ecx[@var{query_ecx}].edx=@var{edx} ++This is similar to the leaves above, but for a @dfn{subleaf}. For ++subleaves, the CPUID instruction is executed with @samp{%rax == ++@var{query_eax}} and @samp{%rcx == @var{query_ecx}}, so the result ++depends on both register values. The same rules about filtering zero ++and identical results apply. ++ ++@item x86.processor[@var{index}].cpuid.subleaf_eax[@var{query_eax}].ecx[@var{query_ecx}].until_ecx=@var{ecx_limit} ++Some CPUID results are the same regardless the @var{query_ecx} value. ++If this situation is detected, a line with the @samp{.until_ecx} ++selector ins included, and this indicates that the CPUID register ++contents is the same for @code{%rcx} values between @var{query_ecx} ++and @var{ecx_limit} (inclusive). ++ ++@item x86.processor[@var{index}].cpuid.subleaf_eax[@var{query_eax}].ecx[@var{query_ecx}].ecx_query_mask=0xff ++This line indicates that in an @samp{.until_ecx} range, the CPUID ++instruction preserved the lowested 8 bits of the input @code{%rcx} in ++the output @code{%rcx} registers. Otherwise, the subleaves in the range ++have identical values. This special treatment is necessary to report ++compact range information in case such copying occurs (because the ++subleaves would otherwise be all different). ++ ++@item x86.processor[@var{index}].xgetbv.ecx[@var{query_ecx}]=@var{result} ++This line shows the 64-bit @var{result} value in the @code{%rdx:%rax} ++register pair after executing the XGETBV instruction with @code{%rcx} ++set to @var{query_ecx}. Zero values and values matching the previously ++probed CPU are omitted. Nothing is printed if the system does not ++support the XGETBV instruction. + @end table + + @node Dynamic Linker Introspection +diff --git a/sysdeps/x86/dl-diagnostics-cpu.c b/sysdeps/x86/dl-diagnostics-cpu.c +index 9a3e0ec8b9214a9c..7fe2c2dfd6668223 100644 +--- a/sysdeps/x86/dl-diagnostics-cpu.c ++++ b/sysdeps/x86/dl-diagnostics-cpu.c +@@ -17,7 +17,18 @@ + . */ + + #include ++ ++#include ++#include ++#include ++#include + #include ++#include ++#include ++#include ++ ++/* The generic CPUID dumping code. */ ++static void _dl_diagnostics_cpuid (void); + + static void + print_cpu_features_value (const char *label, uint64_t value) +@@ -124,4 +135,377 @@ _dl_diagnostics_cpu (void) + + sizeof (cpu_features->cachesize_non_temporal_divisor) + == sizeof (*cpu_features), + "last cpu_features field has been printed"); ++ ++ _dl_diagnostics_cpuid (); ++} ++ ++/* The following code implements a generic CPUID dumper that tries to ++ gather CPUID data without knowing about CPUID implementation ++ details. */ ++ ++/* Register arguments to CPUID. Multiple ECX subleaf values yielding ++ the same result are combined, to shorten the output. Both ++ identical matches (EAX to EDX are the same) and matches where EAX, ++ EBX, EDX, and ECX are equal except in the lower byte, which must ++ match the query ECX value. The latter is needed to compress ranges ++ on CPUs which preserve the lowest byte in ECX if an unknown leaf is ++ queried. */ ++struct cpuid_query ++{ ++ unsigned int eax; ++ unsigned ecx_first; ++ unsigned ecx_last; ++ bool ecx_preserves_query_byte; ++}; ++ ++/* Single integer value that can be used for sorting/ordering ++ comparisons. Uses Q->eax and Q->ecx_first only because ecx_last is ++ always greater than the previous ecx_first value and less than the ++ subsequent one. */ ++static inline unsigned long long int ++cpuid_query_combined (struct cpuid_query *q) ++{ ++ /* ecx can be -1 (that is, ~0U). If this happens, this the only ecx ++ value for this eax value, so the ordering does not matter. */ ++ return ((unsigned long long int) q->eax << 32) | (unsigned int) q->ecx_first; ++}; ++ ++/* Used for differential reporting of zero/non-zero values. */ ++static const struct cpuid_registers cpuid_registers_zero; ++ ++/* Register arguments to CPUID paired with the results that came back. */ ++struct cpuid_query_result ++{ ++ struct cpuid_query q; ++ struct cpuid_registers r; ++}; ++ ++/* During a first enumeration pass, we try to collect data for ++ cpuid_initial_subleaf_limit subleaves per leaf/EAX value. If we run ++ out of space, we try once more with applying the lower limit. */ ++enum { cpuid_main_leaf_limit = 128 }; ++enum { cpuid_initial_subleaf_limit = 512 }; ++enum { cpuid_subleaf_limit = 32 }; ++ ++/* Offset of the extended leaf area. */ ++enum {cpuid_extended_leaf_offset = 0x80000000 }; ++ ++/* Collected CPUID data. Everything is stored in a statically sized ++ array that is sized so that the second pass will collect some data ++ for all leaves, after the limit is applied. On the second pass, ++ ecx_limit is set to cpuid_subleaf_limit. */ ++struct cpuid_collected_data ++{ ++ unsigned int used; ++ unsigned int ecx_limit; ++ uint64_t xgetbv_ecx_0; ++ struct cpuid_query_result qr[cpuid_main_leaf_limit ++ * 2 * cpuid_subleaf_limit]; ++}; ++ ++/* Fill in the result of a CPUID query. Returns true if there is ++ room, false if nothing could be stored. */ ++static bool ++_dl_diagnostics_cpuid_store (struct cpuid_collected_data *ccd, ++ unsigned eax, int ecx) ++{ ++ if (ccd->used >= array_length (ccd->qr)) ++ return false; ++ ++ /* Tentatively fill in the next value. */ ++ __cpuid_count (eax, ecx, ++ ccd->qr[ccd->used].r.eax, ++ ccd->qr[ccd->used].r.ebx, ++ ccd->qr[ccd->used].r.ecx, ++ ccd->qr[ccd->used].r.edx); ++ ++ /* If the ECX subleaf is next subleaf after the previous one (for ++ the same leaf), and the values are the same, merge the result ++ with the already-stored one. Do this before skipping zero ++ leaves, which avoids artifiacts for ECX == 256 queries. */ ++ if (ccd->used > 0 ++ && ccd->qr[ccd->used - 1].q.eax == eax ++ && ccd->qr[ccd->used - 1].q.ecx_last + 1 == ecx) ++ { ++ /* Exact match of the previous result. Ignore the value of ++ ecx_preserves_query_byte if this is a singleton range so far ++ because we can treat ECX as fixed if the same value repeats. */ ++ if ((!ccd->qr[ccd->used - 1].q.ecx_preserves_query_byte ++ || (ccd->qr[ccd->used - 1].q.ecx_first ++ == ccd->qr[ccd->used - 1].q.ecx_last)) ++ && memcmp (&ccd->qr[ccd->used - 1].r, &ccd->qr[ccd->used].r, ++ sizeof (ccd->qr[ccd->used].r)) == 0) ++ { ++ ccd->qr[ccd->used - 1].q.ecx_last = ecx; ++ /* ECX is now fixed because the same value has been observed ++ twice, even if we had a low-byte match before. */ ++ ccd->qr[ccd->used - 1].q.ecx_preserves_query_byte = false; ++ return true; ++ } ++ /* Match except for the low byte in ECX, which must match the ++ incoming ECX value. */ ++ if (ccd->qr[ccd->used - 1].q.ecx_preserves_query_byte ++ && (ecx & 0xff) == (ccd->qr[ccd->used].r.ecx & 0xff) ++ && ccd->qr[ccd->used].r.eax == ccd->qr[ccd->used - 1].r.eax ++ && ccd->qr[ccd->used].r.ebx == ccd->qr[ccd->used - 1].r.ebx ++ && ((ccd->qr[ccd->used].r.ecx & 0xffffff00) ++ == (ccd->qr[ccd->used - 1].r.ecx & 0xffffff00)) ++ && ccd->qr[ccd->used].r.edx == ccd->qr[ccd->used - 1].r.edx) ++ { ++ ccd->qr[ccd->used - 1].q.ecx_last = ecx; ++ return true; ++ } ++ } ++ ++ /* Do not store zero results. All-zero values usually mean that the ++ subleaf is unsupported. */ ++ if (ccd->qr[ccd->used].r.eax == 0 ++ && ccd->qr[ccd->used].r.ebx == 0 ++ && ccd->qr[ccd->used].r.ecx == 0 ++ && ccd->qr[ccd->used].r.edx == 0) ++ return true; ++ ++ /* The result needs to be stored. Fill in the query parameters and ++ consume the storage. */ ++ ccd->qr[ccd->used].q.eax = eax; ++ ccd->qr[ccd->used].q.ecx_first = ecx; ++ ccd->qr[ccd->used].q.ecx_last = ecx; ++ ccd->qr[ccd->used].q.ecx_preserves_query_byte ++ = (ecx & 0xff) == (ccd->qr[ccd->used].r.ecx & 0xff); ++ ++ccd->used; ++ return true; ++} ++ ++/* Collected CPUID data into *CCD. If LIMIT, apply per-leaf limits to ++ avoid exceeding the pre-allocated space. Return true if all data ++ could be stored, false if the retrying without a limit is ++ requested. */ ++static bool ++_dl_diagnostics_cpuid_collect_1 (struct cpuid_collected_data *ccd, bool limit) ++{ ++ ccd->used = 0; ++ ccd->ecx_limit ++ = (limit ? cpuid_subleaf_limit : cpuid_initial_subleaf_limit) - 1; ++ _dl_diagnostics_cpuid_store (ccd, 0x00, 0x00); ++ if (ccd->used == 0) ++ /* CPUID reported all 0. Should not happen. */ ++ return true; ++ unsigned int maximum_leaf = ccd->qr[0x00].r.eax; ++ if (limit && maximum_leaf >= cpuid_main_leaf_limit) ++ maximum_leaf = cpuid_main_leaf_limit - 1; ++ ++ for (unsigned int eax = 1; eax <= maximum_leaf; ++eax) ++ { ++ for (unsigned int ecx = 0; ecx <= ccd->ecx_limit; ++ecx) ++ if (!_dl_diagnostics_cpuid_store (ccd, eax, ecx)) ++ return false; ++ } ++ ++ if (!_dl_diagnostics_cpuid_store (ccd, cpuid_extended_leaf_offset, 0x00)) ++ return false; ++ maximum_leaf = ccd->qr[ccd->used - 1].r.eax; ++ if (maximum_leaf < cpuid_extended_leaf_offset) ++ /* No extended CPUID information. */ ++ return true; ++ if (limit ++ && maximum_leaf - cpuid_extended_leaf_offset >= cpuid_main_leaf_limit) ++ maximum_leaf = cpuid_extended_leaf_offset + cpuid_main_leaf_limit - 1; ++ for (unsigned int eax = cpuid_extended_leaf_offset + 1; ++ eax <= maximum_leaf; ++eax) ++ { ++ for (unsigned int ecx = 0; ecx <= ccd->ecx_limit; ++ecx) ++ if (!_dl_diagnostics_cpuid_store (ccd, eax, ecx)) ++ return false; ++ } ++ return true; ++} ++ ++/* Call _dl_diagnostics_cpuid_collect_1 twice if necessary, the ++ second time with the limit applied. */ ++static void ++_dl_diagnostics_cpuid_collect (struct cpuid_collected_data *ccd) ++{ ++ if (!_dl_diagnostics_cpuid_collect_1 (ccd, false)) ++ _dl_diagnostics_cpuid_collect_1 (ccd, true); ++ ++ /* Re-use the result of the official feature probing here. */ ++ const struct cpu_features *cpu_features = __get_cpu_features (); ++ if (CPU_FEATURES_CPU_P (cpu_features, OSXSAVE)) ++ { ++ unsigned int xcrlow; ++ unsigned int xcrhigh; ++ asm ("xgetbv" : "=a" (xcrlow), "=d" (xcrhigh) : "c" (0)); ++ ccd->xgetbv_ecx_0 = ((uint64_t) xcrhigh << 32) + xcrlow; ++ } ++ else ++ ccd->xgetbv_ecx_0 = 0; ++} ++ ++/* Print a CPUID register value (passed as REG_VALUE) if it differs ++ from the expected REG_REFERENCE value. PROCESSOR_INDEX is the ++ process sequence number (always starting at zero; not a kernel ID). */ ++static void ++_dl_diagnostics_cpuid_print_reg (unsigned int processor_index, ++ const struct cpuid_query *q, ++ const char *reg_label, unsigned int reg_value, ++ bool subleaf) ++{ ++ if (subleaf) ++ _dl_printf ("x86.processor[0x%x].cpuid.subleaf_eax[0x%x]" ++ ".ecx[0x%x].%s=0x%x\n", ++ processor_index, q->eax, q->ecx_first, reg_label, reg_value); ++ else ++ _dl_printf ("x86.processor[0x%x].cpuid.eax[0x%x].%s=0x%x\n", ++ processor_index, q->eax, reg_label, reg_value); ++} ++ ++/* Print CPUID result values in *RESULT for the query in ++ CCD->qr[CCD_IDX]. PROCESSOR_INDEX is the process sequence number ++ (always starting at zero; not a kernel ID). */ ++static void ++_dl_diagnostics_cpuid_print_query (unsigned int processor_index, ++ struct cpuid_collected_data *ccd, ++ unsigned int ccd_idx, ++ const struct cpuid_registers *result) ++{ ++ /* Treat this as a value if subleaves if ecx isn't zero (maybe ++ within the [ecx_fist, ecx_last] range), or if eax matches its ++ neighbors. If the range is [0, ecx_limit], then the subleaves ++ are not distinct (independently of ecx_preserves_query_byte), ++ so do not report them separately. */ ++ struct cpuid_query *q = &ccd->qr[ccd_idx].q; ++ bool subleaf = (q->ecx_first > 0 ++ || (q->ecx_first != q->ecx_last ++ && !(q->ecx_first == 0 && q->ecx_last == ccd->ecx_limit)) ++ || (ccd_idx > 0 && q->eax == ccd->qr[ccd_idx - 1].q.eax) ++ || (ccd_idx + 1 < ccd->used ++ && q->eax == ccd->qr[ccd_idx + 1].q.eax)); ++ _dl_diagnostics_cpuid_print_reg (processor_index, q, "eax", result->eax, ++ subleaf); ++ _dl_diagnostics_cpuid_print_reg (processor_index, q, "ebx", result->ebx, ++ subleaf); ++ _dl_diagnostics_cpuid_print_reg (processor_index, q, "ecx", result->ecx, ++ subleaf); ++ _dl_diagnostics_cpuid_print_reg (processor_index, q, "edx", result->edx, ++ subleaf); ++ ++ if (subleaf && q->ecx_first != q->ecx_last) ++ { ++ _dl_printf ("x86.processor[0x%x].cpuid.subleaf_eax[0x%x]" ++ ".ecx[0x%x].until_ecx=0x%x\n", ++ processor_index, q->eax, q->ecx_first, q->ecx_last); ++ if (q->ecx_preserves_query_byte) ++ _dl_printf ("x86.processor[0x%x].cpuid.subleaf_eax[0x%x]" ++ ".ecx[0x%x].ecx_query_mask=0xff\n", ++ processor_index, q->eax, q->ecx_first); ++ } ++} ++ ++/* Perform differential reporting of the data in *CURRENT against ++ *BASE. REQUESTED_CPU is the kernel CPU ID the thread was ++ configured to run on, or -1 if no configuration was possible. ++ PROCESSOR_INDEX is the process sequence number (always starting at ++ zero; not a kernel ID). */ ++static void ++_dl_diagnostics_cpuid_report (struct dl_iterate_cpu *dci, ++ struct cpuid_collected_data *current, ++ struct cpuid_collected_data *base) ++{ ++ if (dci->requested_cpu >= 0) ++ _dl_printf ("x86.processor[0x%x].requested=0x%x\n", ++ dci->processor_index, dci->requested_cpu); ++ if (dci->actual_cpu >= 0) ++ _dl_printf ("x86.processor[0x%x].observed=0x%x\n", ++ dci->processor_index, dci->actual_cpu); ++ if (dci->actual_node >= 0) ++ _dl_printf ("x86.processor[0x%x].observed_node=0x%x\n", ++ dci->processor_index, dci->actual_node); ++ ++ _dl_printf ("x86.processor[0x%x].cpuid_leaves=0x%x\n", ++ dci->processor_index, current->used); ++ _dl_printf ("x86.processor[0x%x].ecx_limit=0x%x\n", ++ dci->processor_index, current->ecx_limit); ++ ++ unsigned int base_idx = 0; ++ for (unsigned int current_idx = 0; current_idx < current->used; ++ ++current_idx) ++ { ++ /* Report missing data on the current CPU as 0. */ ++ unsigned long long int current_query ++ = cpuid_query_combined (¤t->qr[current_idx].q); ++ while (base_idx < base->used ++ && cpuid_query_combined (&base->qr[base_idx].q) < current_query) ++ { ++ _dl_diagnostics_cpuid_print_query (dci->processor_index, ++ base, base_idx, ++ &cpuid_registers_zero); ++ ++base_idx; ++ } ++ ++ if (base_idx < base->used ++ && cpuid_query_combined (&base->qr[base_idx].q) == current_query) ++ { ++ _Static_assert (sizeof (struct cpuid_registers) == 4 * 4, ++ "no padding in struct cpuid_registers"); ++ if (current->qr[current_idx].q.ecx_last ++ != base->qr[base_idx].q.ecx_last ++ || memcmp (¤t->qr[current_idx].r, ++ &base->qr[base_idx].r, ++ sizeof (struct cpuid_registers)) != 0) ++ /* The ECX range or the values have changed. Show the ++ new values. */ ++ _dl_diagnostics_cpuid_print_query (dci->processor_index, ++ current, current_idx, ++ ¤t->qr[current_idx].r); ++ ++base_idx; ++ } ++ else ++ /* Data is absent in the base reference. Report the new data. */ ++ _dl_diagnostics_cpuid_print_query (dci->processor_index, ++ current, current_idx, ++ ¤t->qr[current_idx].r); ++ } ++ ++ if (current->xgetbv_ecx_0 != base->xgetbv_ecx_0) ++ { ++ /* Re-use the 64-bit printing routine. */ ++ _dl_printf ("x86.processor[0x%x].", dci->processor_index); ++ _dl_diagnostics_print_labeled_value ("xgetbv.ecx[0x0]", ++ current->xgetbv_ecx_0); ++ } ++} ++ ++static void ++_dl_diagnostics_cpuid (void) ++{ ++#if !HAS_CPUID ++ /* CPUID is not supported, so there is nothing to dump. */ ++ if (__get_cpuid_max (0, 0) == 0) ++ return; ++#endif ++ ++ struct dl_iterate_cpu dic; ++ _dl_iterate_cpu_init (&dic); ++ ++ /* Two copies of the data are used. Data is written to the index ++ (dic.processor_index & 1). The previous version against which the ++ data dump is reported is at index !(processor_index & 1). */ ++ struct cpuid_collected_data ccd[2]; ++ ++ /* The initial data is presumed to be all zero. Zero results are ++ not recorded. */ ++ ccd[1].used = 0; ++ ccd[1].xgetbv_ecx_0 = 0; ++ ++ /* Run the CPUID probing on a specific CPU. There are expected ++ differences for encoding core IDs and topology information in ++ CPUID output, but some firmware/kernel bugs also may result in ++ asymmetric data across CPUs in some cases. */ ++ while (_dl_iterate_cpu_next (&dic)) ++ { ++ _dl_diagnostics_cpuid_collect (&ccd[dic.processor_index & 1]); ++ _dl_diagnostics_cpuid_report ++ (&dic, &ccd[dic.processor_index & 1], ++ &ccd[!(dic.processor_index & 1)]); ++ } + } diff --git a/glibc-RHEL-107540-3.patch b/glibc-RHEL-107540-3.patch new file mode 100644 index 0000000..5a0231c --- /dev/null +++ b/glibc-RHEL-107540-3.patch @@ -0,0 +1,146 @@ +commit f8d8b1b1e6d3b8b93f224efc796b7ea083fdb83f +Author: Florian Weimer +Date: Mon Apr 8 16:48:55 2024 +0200 + + aarch64: Enhanced CPU diagnostics for ld.so + + This prints some information from struct cpu_features, and the midr_el1 + and dczid_el0 system register contents on every CPU. + + Reviewed-by: Szabolcs Nagy + +diff --git a/manual/dynlink.texi b/manual/dynlink.texi +index f2f2341818fb9d18..d71f7a30d6f46808 100644 +--- a/manual/dynlink.texi ++++ b/manual/dynlink.texi +@@ -224,6 +224,40 @@ reflect adjustment by @theglibc{}. + These Linux-specific items show the values of @code{struct utsname}, as + reported by the @code{uname} function. @xref{Platform Type}. + ++@item aarch64.cpu_features.@dots{} ++These items are specific to the AArch64 architectures. They report data ++@theglibc{} uses to activate conditionally supported features such as ++BTI and MTE, and to select alternative function implementations. ++ ++@item aarch64.processor[@var{index}].@dots{} ++These are additional items for the AArch64 architecture and are ++described below. ++ ++@item aarch64.processor[@var{index}].requested=@var{kernel-cpu} ++The kernel is told to run the subsequent probing on the CPU numbered ++@var{kernel-cpu}. The values @var{kernel-cpu} and @var{index} can be ++distinct if there are gaps in the process CPU affinity mask. This line ++is not included if CPU affinity mask information is not available. ++ ++@item aarch64.processor[@var{index}].observed=@var{kernel-cpu} ++This line reports the kernel CPU number @var{kernel-cpu} on which the ++probing code initially ran. If the CPU number cannot be obtained, ++this line is not printed. ++ ++@item aarch64.processor[@var{index}].observed_node=@var{node} ++This reports the observed NUMA node number, as reported by the ++@code{getcpu} system call. If this information cannot be obtained, this ++line is not printed. ++ ++@item aarch64.processor[@var{index}].midr_el1=@var{value} ++The value of the @code{midr_el1} system register on the processor ++@var{index}. This line is only printed if the kernel indicates that ++this system register is supported. ++ ++@item aarch64.processor[@var{index}].dczid_el0=@var{value} ++The value of the @code{dczid_el0} system register on the processor ++@var{index}. ++ + @cindex CPUID (diagnostics) + @item x86.cpu_features.@dots{} + These items are specific to the i386 and x86-64 architectures. They +diff --git a/sysdeps/aarch64/dl-diagnostics-cpu.c b/sysdeps/aarch64/dl-diagnostics-cpu.c +new file mode 100644 +index 0000000000000000..e037e6ea8c43df72 +--- /dev/null ++++ b/sysdeps/aarch64/dl-diagnostics-cpu.c +@@ -0,0 +1,84 @@ ++/* Print CPU diagnostics data in ld.so. AArch64 version. ++ Copyright (C) 2021-2024 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 ++ . */ ++ ++#include ++ ++#include ++#include ++#include ++#include ++ ++static void ++print_cpu_features_value (const char *label, uint64_t value) ++{ ++ _dl_printf ("aarch64.cpu_features."); ++ _dl_diagnostics_print_labeled_value (label, value); ++} ++ ++static void ++print_per_cpu_value (const struct dl_iterate_cpu *dic, ++ const char *label, uint64_t value) ++{ ++ _dl_printf ("aarch64.processor[0x%x].", dic->processor_index); ++ _dl_diagnostics_print_labeled_value (label, value); ++} ++ ++void ++_dl_diagnostics_cpu (void) ++{ ++ print_cpu_features_value ("bti", GLRO (dl_aarch64_cpu_features).bti); ++ print_cpu_features_value ("midr_el1", ++ GLRO (dl_aarch64_cpu_features).midr_el1); ++ print_cpu_features_value ("mops", GLRO (dl_aarch64_cpu_features).mops); ++ print_cpu_features_value ("mte_state", ++ GLRO (dl_aarch64_cpu_features).mte_state); ++ print_cpu_features_value ("prefer_sve_ifuncs", ++ GLRO (dl_aarch64_cpu_features).prefer_sve_ifuncs); ++ print_cpu_features_value ("sve", GLRO (dl_aarch64_cpu_features).sve); ++ print_cpu_features_value ("zva_size", ++ GLRO (dl_aarch64_cpu_features).zva_size); ++ ++ struct dl_iterate_cpu dic; ++ _dl_iterate_cpu_init (&dic); ++ ++ while (_dl_iterate_cpu_next (&dic)) ++ { ++ if (dic.requested_cpu >= 0) ++ _dl_printf ("aarch64.processor[0x%x].requested=0x%x\n", ++ dic.processor_index, dic.requested_cpu); ++ if (dic.actual_cpu >= 0) ++ _dl_printf ("aarch64.processor[0x%x].observed=0x%x\n", ++ dic.processor_index, dic.actual_cpu); ++ if (dic.actual_node >= 0) ++ _dl_printf ("aarch64.processor[0x%x].observed_node=0x%x\n", ++ dic.processor_index, dic.actual_node); ++ ++ if (GLRO (dl_hwcap) & HWCAP_CPUID) ++ { ++ uint64_t midr_el1; ++ asm ("mrs %0, midr_el1" : "=r" (midr_el1)); ++ print_per_cpu_value (&dic, "midr_el1", midr_el1); ++ } ++ ++ { ++ uint64_t dczid_el0; ++ asm ("mrs %0, dczid_el0" : "=r" (dczid_el0)); ++ print_per_cpu_value (&dic, "dczid_el0", dczid_el0); ++ } ++ } ++} diff --git a/glibc-RHEL-107695-1.patch b/glibc-RHEL-107695-1.patch new file mode 100644 index 0000000..ad3ab8f --- /dev/null +++ b/glibc-RHEL-107695-1.patch @@ -0,0 +1,812 @@ +commit 3de2f8755c6c036dcd0b1f4acd6bcdefe0e775c0 +Author: Joseph Myers +Date: Wed Mar 13 13:57:56 2024 +0000 + + Update syscall lists for Linux 6.8 + + Linux 6.8 adds five new syscalls. Update syscall-names.list and + regenerate the arch-syscall.h headers with build-many-glibcs.py + update-syscalls. + + Tested with build-many-glibcs.py. + +diff --git a/sysdeps/unix/sysv/linux/aarch64/arch-syscall.h b/sysdeps/unix/sysv/linux/aarch64/arch-syscall.h +index 1713897f85551c50..7ee8a2167aaae172 100644 +--- a/sysdeps/unix/sysv/linux/aarch64/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/aarch64/arch-syscall.h +@@ -122,12 +122,16 @@ + #define __NR_lgetxattr 9 + #define __NR_linkat 37 + #define __NR_listen 201 ++#define __NR_listmount 458 + #define __NR_listxattr 11 + #define __NR_llistxattr 12 + #define __NR_lookup_dcookie 18 + #define __NR_lremovexattr 15 + #define __NR_lseek 62 + #define __NR_lsetxattr 6 ++#define __NR_lsm_get_self_attr 459 ++#define __NR_lsm_list_modules 461 ++#define __NR_lsm_set_self_attr 460 + #define __NR_madvise 233 + #define __NR_map_shadow_stack 453 + #define __NR_mbind 235 +@@ -276,6 +280,7 @@ + #define __NR_socketpair 199 + #define __NR_splice 76 + #define __NR_statfs 43 ++#define __NR_statmount 457 + #define __NR_statx 291 + #define __NR_swapoff 225 + #define __NR_swapon 224 +diff --git a/sysdeps/unix/sysv/linux/alpha/arch-syscall.h b/sysdeps/unix/sysv/linux/alpha/arch-syscall.h +index 5457d2d8ae45e8ec..0f4ea7670be610be 100644 +--- a/sysdeps/unix/sysv/linux/alpha/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/alpha/arch-syscall.h +@@ -150,12 +150,16 @@ + #define __NR_link 9 + #define __NR_linkat 458 + #define __NR_listen 106 ++#define __NR_listmount 568 + #define __NR_listxattr 388 + #define __NR_llistxattr 389 + #define __NR_lookup_dcookie 406 + #define __NR_lremovexattr 392 + #define __NR_lseek 19 + #define __NR_lsetxattr 383 ++#define __NR_lsm_get_self_attr 569 ++#define __NR_lsm_list_modules 571 ++#define __NR_lsm_set_self_attr 570 + #define __NR_lstat 68 + #define __NR_lstat64 426 + #define __NR_madvise 75 +@@ -441,6 +445,7 @@ + #define __NR_stat64 425 + #define __NR_statfs 328 + #define __NR_statfs64 528 ++#define __NR_statmount 567 + #define __NR_statx 522 + #define __NR_swapoff 304 + #define __NR_swapon 322 +diff --git a/sysdeps/unix/sysv/linux/arc/arch-syscall.h b/sysdeps/unix/sysv/linux/arc/arch-syscall.h +index a66471c83ae56383..90359482a814b3f8 100644 +--- a/sysdeps/unix/sysv/linux/arc/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/arc/arch-syscall.h +@@ -126,12 +126,16 @@ + #define __NR_lgetxattr 9 + #define __NR_linkat 37 + #define __NR_listen 201 ++#define __NR_listmount 458 + #define __NR_listxattr 11 + #define __NR_llistxattr 12 + #define __NR_llseek 62 + #define __NR_lookup_dcookie 18 + #define __NR_lremovexattr 15 + #define __NR_lsetxattr 6 ++#define __NR_lsm_get_self_attr 459 ++#define __NR_lsm_list_modules 461 ++#define __NR_lsm_set_self_attr 460 + #define __NR_madvise 233 + #define __NR_map_shadow_stack 453 + #define __NR_mbind 235 +@@ -278,6 +282,7 @@ + #define __NR_socketpair 199 + #define __NR_splice 76 + #define __NR_statfs64 43 ++#define __NR_statmount 457 + #define __NR_statx 291 + #define __NR_swapoff 225 + #define __NR_swapon 224 +diff --git a/sysdeps/unix/sysv/linux/arm/arch-syscall.h b/sysdeps/unix/sysv/linux/arm/arch-syscall.h +index 74a57f4520dab365..4930167a03c97df2 100644 +--- a/sysdeps/unix/sysv/linux/arm/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/arm/arch-syscall.h +@@ -164,12 +164,16 @@ + #define __NR_link 9 + #define __NR_linkat 330 + #define __NR_listen 284 ++#define __NR_listmount 458 + #define __NR_listxattr 232 + #define __NR_llistxattr 233 + #define __NR_lookup_dcookie 249 + #define __NR_lremovexattr 236 + #define __NR_lseek 19 + #define __NR_lsetxattr 227 ++#define __NR_lsm_get_self_attr 459 ++#define __NR_lsm_list_modules 461 ++#define __NR_lsm_set_self_attr 460 + #define __NR_lstat 107 + #define __NR_lstat64 196 + #define __NR_madvise 220 +@@ -361,6 +365,7 @@ + #define __NR_stat64 195 + #define __NR_statfs 99 + #define __NR_statfs64 266 ++#define __NR_statmount 457 + #define __NR_statx 397 + #define __NR_swapoff 115 + #define __NR_swapon 87 +diff --git a/sysdeps/unix/sysv/linux/csky/arch-syscall.h b/sysdeps/unix/sysv/linux/csky/arch-syscall.h +index ba7632e0182573d0..3f16a29f5753e7a8 100644 +--- a/sysdeps/unix/sysv/linux/csky/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/csky/arch-syscall.h +@@ -131,12 +131,16 @@ + #define __NR_lgetxattr 9 + #define __NR_linkat 37 + #define __NR_listen 201 ++#define __NR_listmount 458 + #define __NR_listxattr 11 + #define __NR_llistxattr 12 + #define __NR_llseek 62 + #define __NR_lookup_dcookie 18 + #define __NR_lremovexattr 15 + #define __NR_lsetxattr 6 ++#define __NR_lsm_get_self_attr 459 ++#define __NR_lsm_list_modules 461 ++#define __NR_lsm_set_self_attr 460 + #define __NR_madvise 233 + #define __NR_map_shadow_stack 453 + #define __NR_mbind 235 +@@ -291,6 +295,7 @@ + #define __NR_socketpair 199 + #define __NR_splice 76 + #define __NR_statfs64 43 ++#define __NR_statmount 457 + #define __NR_statx 291 + #define __NR_swapoff 225 + #define __NR_swapon 224 +diff --git a/sysdeps/unix/sysv/linux/hppa/arch-syscall.h b/sysdeps/unix/sysv/linux/hppa/arch-syscall.h +index 483706de9bec060c..a1b2c819d6522018 100644 +--- a/sysdeps/unix/sysv/linux/hppa/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/hppa/arch-syscall.h +@@ -155,12 +155,16 @@ + #define __NR_link 9 + #define __NR_linkat 283 + #define __NR_listen 32 ++#define __NR_listmount 458 + #define __NR_listxattr 244 + #define __NR_llistxattr 245 + #define __NR_lookup_dcookie 223 + #define __NR_lremovexattr 248 + #define __NR_lseek 19 + #define __NR_lsetxattr 239 ++#define __NR_lsm_get_self_attr 459 ++#define __NR_lsm_list_modules 461 ++#define __NR_lsm_set_self_attr 460 + #define __NR_lstat 84 + #define __NR_lstat64 198 + #define __NR_madvise 119 +@@ -339,6 +343,7 @@ + #define __NR_stat64 101 + #define __NR_statfs 99 + #define __NR_statfs64 298 ++#define __NR_statmount 457 + #define __NR_statx 349 + #define __NR_stime 25 + #define __NR_swapoff 115 +diff --git a/sysdeps/unix/sysv/linux/i386/arch-syscall.h b/sysdeps/unix/sysv/linux/i386/arch-syscall.h +index 21c1308bb327a1b3..cc775432d663a745 100644 +--- a/sysdeps/unix/sysv/linux/i386/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/i386/arch-syscall.h +@@ -176,6 +176,7 @@ + #define __NR_link 9 + #define __NR_linkat 303 + #define __NR_listen 363 ++#define __NR_listmount 458 + #define __NR_listxattr 232 + #define __NR_llistxattr 233 + #define __NR_lock 53 +@@ -183,6 +184,9 @@ + #define __NR_lremovexattr 236 + #define __NR_lseek 19 + #define __NR_lsetxattr 227 ++#define __NR_lsm_get_self_attr 459 ++#define __NR_lsm_list_modules 461 ++#define __NR_lsm_set_self_attr 460 + #define __NR_lstat 107 + #define __NR_lstat64 196 + #define __NR_madvise 219 +@@ -386,6 +390,7 @@ + #define __NR_stat64 195 + #define __NR_statfs 99 + #define __NR_statfs64 268 ++#define __NR_statmount 457 + #define __NR_statx 383 + #define __NR_stime 25 + #define __NR_stty 31 +diff --git a/sysdeps/unix/sysv/linux/loongarch/arch-syscall.h b/sysdeps/unix/sysv/linux/loongarch/arch-syscall.h +index f6a434630ebaa542..56bb08718ad32c04 100644 +--- a/sysdeps/unix/sysv/linux/loongarch/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/loongarch/arch-syscall.h +@@ -120,12 +120,16 @@ + #define __NR_lgetxattr 9 + #define __NR_linkat 37 + #define __NR_listen 201 ++#define __NR_listmount 458 + #define __NR_listxattr 11 + #define __NR_llistxattr 12 + #define __NR_lookup_dcookie 18 + #define __NR_lremovexattr 15 + #define __NR_lseek 62 + #define __NR_lsetxattr 6 ++#define __NR_lsm_get_self_attr 459 ++#define __NR_lsm_list_modules 461 ++#define __NR_lsm_set_self_attr 460 + #define __NR_madvise 233 + #define __NR_map_shadow_stack 453 + #define __NR_mbind 235 +@@ -270,6 +274,7 @@ + #define __NR_socketpair 199 + #define __NR_splice 76 + #define __NR_statfs 43 ++#define __NR_statmount 457 + #define __NR_statx 291 + #define __NR_swapoff 225 + #define __NR_swapon 224 +diff --git a/sysdeps/unix/sysv/linux/m68k/arch-syscall.h b/sysdeps/unix/sysv/linux/m68k/arch-syscall.h +index 6d788e3440b1082c..79f277dd5b8eda7b 100644 +--- a/sysdeps/unix/sysv/linux/m68k/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/m68k/arch-syscall.h +@@ -171,12 +171,16 @@ + #define __NR_link 9 + #define __NR_linkat 296 + #define __NR_listen 360 ++#define __NR_listmount 458 + #define __NR_listxattr 229 + #define __NR_llistxattr 230 + #define __NR_lookup_dcookie 248 + #define __NR_lremovexattr 233 + #define __NR_lseek 19 + #define __NR_lsetxattr 224 ++#define __NR_lsm_get_self_attr 459 ++#define __NR_lsm_list_modules 461 ++#define __NR_lsm_set_self_attr 460 + #define __NR_lstat 107 + #define __NR_lstat64 196 + #define __NR_madvise 238 +@@ -373,6 +377,7 @@ + #define __NR_stat64 195 + #define __NR_statfs 99 + #define __NR_statfs64 263 ++#define __NR_statmount 457 + #define __NR_statx 379 + #define __NR_stime 25 + #define __NR_swapoff 115 +diff --git a/sysdeps/unix/sysv/linux/microblaze/arch-syscall.h b/sysdeps/unix/sysv/linux/microblaze/arch-syscall.h +index 91e1630f7b2e07a4..779d5d5d7029d8ff 100644 +--- a/sysdeps/unix/sysv/linux/microblaze/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/microblaze/arch-syscall.h +@@ -176,6 +176,7 @@ + #define __NR_link 9 + #define __NR_linkat 303 + #define __NR_listen 348 ++#define __NR_listmount 458 + #define __NR_listxattr 232 + #define __NR_llistxattr 233 + #define __NR_lock 53 +@@ -183,6 +184,9 @@ + #define __NR_lremovexattr 236 + #define __NR_lseek 19 + #define __NR_lsetxattr 227 ++#define __NR_lsm_get_self_attr 459 ++#define __NR_lsm_list_modules 461 ++#define __NR_lsm_set_self_attr 460 + #define __NR_lstat 107 + #define __NR_lstat64 196 + #define __NR_madvise 219 +@@ -389,6 +393,7 @@ + #define __NR_stat64 195 + #define __NR_statfs 99 + #define __NR_statfs64 268 ++#define __NR_statmount 457 + #define __NR_statx 398 + #define __NR_stime 25 + #define __NR_stty 31 +diff --git a/sysdeps/unix/sysv/linux/mips/mips32/arch-syscall.h b/sysdeps/unix/sysv/linux/mips/mips32/arch-syscall.h +index d75af9746764cc0a..86ffd5ce84556c20 100644 +--- a/sysdeps/unix/sysv/linux/mips/mips32/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/mips/mips32/arch-syscall.h +@@ -166,6 +166,7 @@ + #define __NR_link 4009 + #define __NR_linkat 4296 + #define __NR_listen 4174 ++#define __NR_listmount 4458 + #define __NR_listxattr 4230 + #define __NR_llistxattr 4231 + #define __NR_lock 4053 +@@ -173,6 +174,9 @@ + #define __NR_lremovexattr 4234 + #define __NR_lseek 4019 + #define __NR_lsetxattr 4225 ++#define __NR_lsm_get_self_attr 4459 ++#define __NR_lsm_list_modules 4461 ++#define __NR_lsm_set_self_attr 4460 + #define __NR_lstat 4107 + #define __NR_lstat64 4214 + #define __NR_madvise 4218 +@@ -362,6 +366,7 @@ + #define __NR_stat64 4213 + #define __NR_statfs 4099 + #define __NR_statfs64 4255 ++#define __NR_statmount 4457 + #define __NR_statx 4366 + #define __NR_stime 4025 + #define __NR_stty 4031 +diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/arch-syscall.h b/sysdeps/unix/sysv/linux/mips/mips64/n32/arch-syscall.h +index 05bf7d251da60f51..5d37a686e511a499 100644 +--- a/sysdeps/unix/sysv/linux/mips/mips64/n32/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/arch-syscall.h +@@ -154,12 +154,16 @@ + #define __NR_link 6084 + #define __NR_linkat 6259 + #define __NR_listen 6049 ++#define __NR_listmount 6458 + #define __NR_listxattr 6186 + #define __NR_llistxattr 6187 + #define __NR_lookup_dcookie 6206 + #define __NR_lremovexattr 6190 + #define __NR_lseek 6008 + #define __NR_lsetxattr 6181 ++#define __NR_lsm_get_self_attr 6459 ++#define __NR_lsm_list_modules 6461 ++#define __NR_lsm_set_self_attr 6460 + #define __NR_lstat 6006 + #define __NR_madvise 6027 + #define __NR_map_shadow_stack 6453 +@@ -332,6 +336,7 @@ + #define __NR_stat 6004 + #define __NR_statfs 6134 + #define __NR_statfs64 6217 ++#define __NR_statmount 6457 + #define __NR_statx 6330 + #define __NR_swapoff 6163 + #define __NR_swapon 6162 +diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/arch-syscall.h b/sysdeps/unix/sysv/linux/mips/mips64/n64/arch-syscall.h +index 41ffaf32550a6609..9b1e846e7646d791 100644 +--- a/sysdeps/unix/sysv/linux/mips/mips64/n64/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/arch-syscall.h +@@ -145,12 +145,16 @@ + #define __NR_link 5084 + #define __NR_linkat 5255 + #define __NR_listen 5049 ++#define __NR_listmount 5458 + #define __NR_listxattr 5186 + #define __NR_llistxattr 5187 + #define __NR_lookup_dcookie 5206 + #define __NR_lremovexattr 5190 + #define __NR_lseek 5008 + #define __NR_lsetxattr 5181 ++#define __NR_lsm_get_self_attr 5459 ++#define __NR_lsm_list_modules 5461 ++#define __NR_lsm_set_self_attr 5460 + #define __NR_lstat 5006 + #define __NR_madvise 5027 + #define __NR_map_shadow_stack 5453 +@@ -313,6 +317,7 @@ + #define __NR_splice 5263 + #define __NR_stat 5004 + #define __NR_statfs 5134 ++#define __NR_statmount 5457 + #define __NR_statx 5326 + #define __NR_swapoff 5163 + #define __NR_swapon 5162 +diff --git a/sysdeps/unix/sysv/linux/nios2/arch-syscall.h b/sysdeps/unix/sysv/linux/nios2/arch-syscall.h +index d94e7e9ee987a349..abbc9ab6b083be80 100644 +--- a/sysdeps/unix/sysv/linux/nios2/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/nios2/arch-syscall.h +@@ -130,12 +130,16 @@ + #define __NR_lgetxattr 9 + #define __NR_linkat 37 + #define __NR_listen 201 ++#define __NR_listmount 458 + #define __NR_listxattr 11 + #define __NR_llistxattr 12 + #define __NR_llseek 62 + #define __NR_lookup_dcookie 18 + #define __NR_lremovexattr 15 + #define __NR_lsetxattr 6 ++#define __NR_lsm_get_self_attr 459 ++#define __NR_lsm_list_modules 461 ++#define __NR_lsm_set_self_attr 460 + #define __NR_madvise 233 + #define __NR_map_shadow_stack 453 + #define __NR_mbind 235 +@@ -290,6 +294,7 @@ + #define __NR_socketpair 199 + #define __NR_splice 76 + #define __NR_statfs64 43 ++#define __NR_statmount 457 + #define __NR_statx 291 + #define __NR_swapoff 225 + #define __NR_swapon 224 +diff --git a/sysdeps/unix/sysv/linux/or1k/arch-syscall.h b/sysdeps/unix/sysv/linux/or1k/arch-syscall.h +index 39295a6f94c6f5b0..7223a93673d9c6f7 100644 +--- a/sysdeps/unix/sysv/linux/or1k/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/or1k/arch-syscall.h +@@ -130,12 +130,16 @@ + #define __NR_lgetxattr 9 + #define __NR_linkat 37 + #define __NR_listen 201 ++#define __NR_listmount 458 + #define __NR_listxattr 11 + #define __NR_llistxattr 12 + #define __NR_llseek 62 + #define __NR_lookup_dcookie 18 + #define __NR_lremovexattr 15 + #define __NR_lsetxattr 6 ++#define __NR_lsm_get_self_attr 459 ++#define __NR_lsm_list_modules 461 ++#define __NR_lsm_set_self_attr 460 + #define __NR_madvise 233 + #define __NR_map_shadow_stack 453 + #define __NR_mbind 235 +@@ -291,6 +295,7 @@ + #define __NR_socketpair 199 + #define __NR_splice 76 + #define __NR_statfs64 43 ++#define __NR_statmount 457 + #define __NR_statx 291 + #define __NR_swapoff 225 + #define __NR_swapon 224 +diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/arch-syscall.h b/sysdeps/unix/sysv/linux/powerpc/powerpc32/arch-syscall.h +index b5522e8889d505a8..af0d2b121ebc7dc7 100644 +--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/arch-syscall.h +@@ -166,6 +166,7 @@ + #define __NR_link 9 + #define __NR_linkat 294 + #define __NR_listen 329 ++#define __NR_listmount 458 + #define __NR_listxattr 215 + #define __NR_llistxattr 216 + #define __NR_lock 53 +@@ -173,6 +174,9 @@ + #define __NR_lremovexattr 219 + #define __NR_lseek 19 + #define __NR_lsetxattr 210 ++#define __NR_lsm_get_self_attr 459 ++#define __NR_lsm_list_modules 461 ++#define __NR_lsm_set_self_attr 460 + #define __NR_lstat 107 + #define __NR_lstat64 196 + #define __NR_madvise 205 +@@ -374,6 +378,7 @@ + #define __NR_stat64 195 + #define __NR_statfs 99 + #define __NR_statfs64 252 ++#define __NR_statmount 457 + #define __NR_statx 383 + #define __NR_stime 25 + #define __NR_stty 31 +diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/arch-syscall.h b/sysdeps/unix/sysv/linux/powerpc/powerpc64/arch-syscall.h +index 162d782ae6f48975..a4c70aa7fe719cb9 100644 +--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/arch-syscall.h +@@ -154,6 +154,7 @@ + #define __NR_link 9 + #define __NR_linkat 294 + #define __NR_listen 329 ++#define __NR_listmount 458 + #define __NR_listxattr 215 + #define __NR_llistxattr 216 + #define __NR_lock 53 +@@ -161,6 +162,9 @@ + #define __NR_lremovexattr 219 + #define __NR_lseek 19 + #define __NR_lsetxattr 210 ++#define __NR_lsm_get_self_attr 459 ++#define __NR_lsm_list_modules 461 ++#define __NR_lsm_set_self_attr 460 + #define __NR_lstat 107 + #define __NR_madvise 205 + #define __NR_map_shadow_stack 453 +@@ -352,6 +356,7 @@ + #define __NR_stat 106 + #define __NR_statfs 99 + #define __NR_statfs64 252 ++#define __NR_statmount 457 + #define __NR_statx 383 + #define __NR_stime 25 + #define __NR_stty 31 +diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h b/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h +index 013222e5deb65c8d..7315d164d64c89fa 100644 +--- a/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h +@@ -117,12 +117,16 @@ + #define __NR_lgetxattr 9 + #define __NR_linkat 37 + #define __NR_listen 201 ++#define __NR_listmount 458 + #define __NR_listxattr 11 + #define __NR_llistxattr 12 + #define __NR_llseek 62 + #define __NR_lookup_dcookie 18 + #define __NR_lremovexattr 15 + #define __NR_lsetxattr 6 ++#define __NR_lsm_get_self_attr 459 ++#define __NR_lsm_list_modules 461 ++#define __NR_lsm_set_self_attr 460 + #define __NR_madvise 233 + #define __NR_map_shadow_stack 453 + #define __NR_mbind 235 +@@ -268,6 +272,7 @@ + #define __NR_socketpair 199 + #define __NR_splice 76 + #define __NR_statfs64 43 ++#define __NR_statmount 457 + #define __NR_statx 291 + #define __NR_swapoff 225 + #define __NR_swapon 224 +diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h b/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h +index d03dad82008fb2a1..31a1130db9404e60 100644 +--- a/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h +@@ -122,12 +122,16 @@ + #define __NR_lgetxattr 9 + #define __NR_linkat 37 + #define __NR_listen 201 ++#define __NR_listmount 458 + #define __NR_listxattr 11 + #define __NR_llistxattr 12 + #define __NR_lookup_dcookie 18 + #define __NR_lremovexattr 15 + #define __NR_lseek 62 + #define __NR_lsetxattr 6 ++#define __NR_lsm_get_self_attr 459 ++#define __NR_lsm_list_modules 461 ++#define __NR_lsm_set_self_attr 460 + #define __NR_madvise 233 + #define __NR_map_shadow_stack 453 + #define __NR_mbind 235 +@@ -277,6 +281,7 @@ + #define __NR_socketpair 199 + #define __NR_splice 76 + #define __NR_statfs 43 ++#define __NR_statmount 457 + #define __NR_statx 291 + #define __NR_swapoff 225 + #define __NR_swapon 224 +diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/arch-syscall.h b/sysdeps/unix/sysv/linux/s390/s390-32/arch-syscall.h +index 98e6b68b3153b89b..cf8569304d9e6a16 100644 +--- a/sysdeps/unix/sysv/linux/s390/s390-32/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/s390/s390-32/arch-syscall.h +@@ -171,12 +171,16 @@ + #define __NR_link 9 + #define __NR_linkat 296 + #define __NR_listen 363 ++#define __NR_listmount 458 + #define __NR_listxattr 230 + #define __NR_llistxattr 231 + #define __NR_lookup_dcookie 110 + #define __NR_lremovexattr 234 + #define __NR_lseek 19 + #define __NR_lsetxattr 225 ++#define __NR_lsm_get_self_attr 459 ++#define __NR_lsm_list_modules 461 ++#define __NR_lsm_set_self_attr 460 + #define __NR_lstat 107 + #define __NR_lstat64 196 + #define __NR_madvise 219 +@@ -372,6 +376,7 @@ + #define __NR_stat64 195 + #define __NR_statfs 99 + #define __NR_statfs64 265 ++#define __NR_statmount 457 + #define __NR_statx 379 + #define __NR_stime 25 + #define __NR_swapoff 115 +diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/arch-syscall.h b/sysdeps/unix/sysv/linux/s390/s390-64/arch-syscall.h +index 951fbd7c97ff71d3..f3536ed03f4b7d85 100644 +--- a/sysdeps/unix/sysv/linux/s390/s390-64/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/s390/s390-64/arch-syscall.h +@@ -146,12 +146,16 @@ + #define __NR_link 9 + #define __NR_linkat 296 + #define __NR_listen 363 ++#define __NR_listmount 458 + #define __NR_listxattr 230 + #define __NR_llistxattr 231 + #define __NR_lookup_dcookie 110 + #define __NR_lremovexattr 234 + #define __NR_lseek 19 + #define __NR_lsetxattr 225 ++#define __NR_lsm_get_self_attr 459 ++#define __NR_lsm_list_modules 461 ++#define __NR_lsm_set_self_attr 460 + #define __NR_lstat 107 + #define __NR_madvise 219 + #define __NR_map_shadow_stack 453 +@@ -329,6 +333,7 @@ + #define __NR_stat 106 + #define __NR_statfs 99 + #define __NR_statfs64 265 ++#define __NR_statmount 457 + #define __NR_statx 379 + #define __NR_swapoff 115 + #define __NR_swapon 87 +diff --git a/sysdeps/unix/sysv/linux/sh/arch-syscall.h b/sysdeps/unix/sysv/linux/sh/arch-syscall.h +index 6b4418bcae4390ae..0c88bf10c77bef3a 100644 +--- a/sysdeps/unix/sysv/linux/sh/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/sh/arch-syscall.h +@@ -164,12 +164,16 @@ + #define __NR_link 9 + #define __NR_linkat 303 + #define __NR_listen 343 ++#define __NR_listmount 458 + #define __NR_listxattr 232 + #define __NR_llistxattr 233 + #define __NR_lookup_dcookie 253 + #define __NR_lremovexattr 236 + #define __NR_lseek 19 + #define __NR_lsetxattr 227 ++#define __NR_lsm_get_self_attr 459 ++#define __NR_lsm_list_modules 461 ++#define __NR_lsm_set_self_attr 460 + #define __NR_lstat 107 + #define __NR_lstat64 196 + #define __NR_madvise 219 +@@ -365,6 +369,7 @@ + #define __NR_stat64 195 + #define __NR_statfs 99 + #define __NR_statfs64 268 ++#define __NR_statmount 457 + #define __NR_statx 383 + #define __NR_stime 25 + #define __NR_swapoff 115 +diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/arch-syscall.h b/sysdeps/unix/sysv/linux/sparc/sparc32/arch-syscall.h +index 4f9460b1a3e1a353..19fa614624dc2b85 100644 +--- a/sysdeps/unix/sysv/linux/sparc/sparc32/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/sparc/sparc32/arch-syscall.h +@@ -169,12 +169,16 @@ + #define __NR_link 9 + #define __NR_linkat 292 + #define __NR_listen 354 ++#define __NR_listmount 458 + #define __NR_listxattr 178 + #define __NR_llistxattr 179 + #define __NR_lookup_dcookie 208 + #define __NR_lremovexattr 182 + #define __NR_lseek 19 + #define __NR_lsetxattr 170 ++#define __NR_lsm_get_self_attr 459 ++#define __NR_lsm_list_modules 461 ++#define __NR_lsm_set_self_attr 460 + #define __NR_lstat 40 + #define __NR_lstat64 132 + #define __NR_madvise 75 +@@ -370,6 +374,7 @@ + #define __NR_stat64 139 + #define __NR_statfs 157 + #define __NR_statfs64 234 ++#define __NR_statmount 457 + #define __NR_statx 360 + #define __NR_stime 233 + #define __NR_swapoff 213 +diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/arch-syscall.h b/sysdeps/unix/sysv/linux/sparc/sparc64/arch-syscall.h +index 129ce50646596a95..18516f20cbf25d77 100644 +--- a/sysdeps/unix/sysv/linux/sparc/sparc64/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/sparc/sparc64/arch-syscall.h +@@ -152,12 +152,16 @@ + #define __NR_link 9 + #define __NR_linkat 292 + #define __NR_listen 354 ++#define __NR_listmount 458 + #define __NR_listxattr 178 + #define __NR_llistxattr 179 + #define __NR_lookup_dcookie 208 + #define __NR_lremovexattr 182 + #define __NR_lseek 19 + #define __NR_lsetxattr 170 ++#define __NR_lsm_get_self_attr 459 ++#define __NR_lsm_list_modules 461 ++#define __NR_lsm_set_self_attr 460 + #define __NR_lstat 40 + #define __NR_lstat64 132 + #define __NR_madvise 75 +@@ -339,6 +343,7 @@ + #define __NR_stat64 139 + #define __NR_statfs 157 + #define __NR_statfs64 234 ++#define __NR_statmount 457 + #define __NR_statx 360 + #define __NR_stime 233 + #define __NR_swapoff 213 +diff --git a/sysdeps/unix/sysv/linux/syscall-names.list b/sysdeps/unix/sysv/linux/syscall-names.list +index aac065e7b327528e..6557bcfde4636158 100644 +--- a/sysdeps/unix/sysv/linux/syscall-names.list ++++ b/sysdeps/unix/sysv/linux/syscall-names.list +@@ -21,8 +21,8 @@ + # This file can list all potential system calls. The names are only + # used if the installed kernel headers also provide them. + +-# The list of system calls is current as of Linux 6.7. +-kernel 6.7 ++# The list of system calls is current as of Linux 6.8. ++kernel 6.8 + + FAST_atomic_update + FAST_cmpxchg +@@ -239,6 +239,7 @@ lgetxattr + link + linkat + listen ++listmount + listxattr + llistxattr + llseek +@@ -247,6 +248,9 @@ lookup_dcookie + lremovexattr + lseek + lsetxattr ++lsm_get_self_attr ++lsm_list_modules ++lsm_set_self_attr + lstat + lstat64 + madvise +@@ -593,6 +597,7 @@ stat + stat64 + statfs + statfs64 ++statmount + statx + stime + stty +diff --git a/sysdeps/unix/sysv/linux/x86_64/64/arch-syscall.h b/sysdeps/unix/sysv/linux/x86_64/64/arch-syscall.h +index 4fa5b942c5f8e9b7..b1222160135310ec 100644 +--- a/sysdeps/unix/sysv/linux/x86_64/64/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/x86_64/64/arch-syscall.h +@@ -149,12 +149,16 @@ + #define __NR_link 86 + #define __NR_linkat 265 + #define __NR_listen 50 ++#define __NR_listmount 458 + #define __NR_listxattr 194 + #define __NR_llistxattr 195 + #define __NR_lookup_dcookie 212 + #define __NR_lremovexattr 198 + #define __NR_lseek 8 + #define __NR_lsetxattr 189 ++#define __NR_lsm_get_self_attr 459 ++#define __NR_lsm_list_modules 461 ++#define __NR_lsm_set_self_attr 460 + #define __NR_lstat 6 + #define __NR_madvise 28 + #define __NR_map_shadow_stack 453 +@@ -321,6 +325,7 @@ + #define __NR_splice 275 + #define __NR_stat 4 + #define __NR_statfs 137 ++#define __NR_statmount 457 + #define __NR_statx 332 + #define __NR_swapoff 168 + #define __NR_swapon 167 +diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/arch-syscall.h b/sysdeps/unix/sysv/linux/x86_64/x32/arch-syscall.h +index 645e85802f95a78c..df3e22236dd3bb0e 100644 +--- a/sysdeps/unix/sysv/linux/x86_64/x32/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/x86_64/x32/arch-syscall.h +@@ -143,12 +143,16 @@ + #define __NR_link 1073741910 + #define __NR_linkat 1073742089 + #define __NR_listen 1073741874 ++#define __NR_listmount 1073742282 + #define __NR_listxattr 1073742018 + #define __NR_llistxattr 1073742019 + #define __NR_lookup_dcookie 1073742036 + #define __NR_lremovexattr 1073742022 + #define __NR_lseek 1073741832 + #define __NR_lsetxattr 1073742013 ++#define __NR_lsm_get_self_attr 1073742283 ++#define __NR_lsm_list_modules 1073742285 ++#define __NR_lsm_set_self_attr 1073742284 + #define __NR_lstat 1073741830 + #define __NR_madvise 1073741852 + #define __NR_map_shadow_stack 1073742277 +@@ -313,6 +317,7 @@ + #define __NR_splice 1073742099 + #define __NR_stat 1073741828 + #define __NR_statfs 1073741961 ++#define __NR_statmount 1073742281 + #define __NR_statx 1073742156 + #define __NR_swapoff 1073741992 + #define __NR_swapon 1073741991 diff --git a/glibc-RHEL-107695-10.patch b/glibc-RHEL-107695-10.patch new file mode 100644 index 0000000..740e1d1 --- /dev/null +++ b/glibc-RHEL-107695-10.patch @@ -0,0 +1,59 @@ +commit 86f06282ccb1b11de7a07fc10f7b77991b7d121a +Author: Adhemerval Zanella +Date: Tue Oct 8 15:45:25 2024 -0300 + + Update PIDFD_* constants for Linux 6.11 + + Linux 6.11 adds some more PIDFD_* constants for 'pidfs: allow retrieval + of namespace file descriptors' + (5b08bd408534bfb3a7cf5778da5b27d4e4fffe12). + + Tested with build-many-glibcs.py. + + Reviewed-by: H.J. Lu + +diff --git a/sysdeps/unix/sysv/linux/sys/pidfd.h b/sysdeps/unix/sysv/linux/sys/pidfd.h +index 9f88d297e884c348..85d976939b6f01fa 100644 +--- a/sysdeps/unix/sysv/linux/sys/pidfd.h ++++ b/sysdeps/unix/sysv/linux/sys/pidfd.h +@@ -20,6 +20,7 @@ + + #include + #include ++#include + + #define PIDFD_NONBLOCK O_NONBLOCK + #define PIDFD_THREAD O_EXCL +@@ -28,6 +29,19 @@ + #define PIDFD_SIGNAL_THREAD_GROUP (1UL << 1) + #define PIDFD_SIGNAL_PROCESS_GROUP (1UL << 2) + ++#define PIDFS_IOCTL_MAGIC 0xFF ++ ++#define PIDFD_GET_CGROUP_NAMESPACE _IO(PIDFS_IOCTL_MAGIC, 1) ++#define PIDFD_GET_IPC_NAMESPACE _IO(PIDFS_IOCTL_MAGIC, 2) ++#define PIDFD_GET_MNT_NAMESPACE _IO(PIDFS_IOCTL_MAGIC, 3) ++#define PIDFD_GET_NET_NAMESPACE _IO(PIDFS_IOCTL_MAGIC, 4) ++#define PIDFD_GET_PID_NAMESPACE _IO(PIDFS_IOCTL_MAGIC, 5) ++#define PIDFD_GET_PID_FOR_CHILDREN_NAMESPACE _IO(PIDFS_IOCTL_MAGIC, 6) ++#define PIDFD_GET_TIME_NAMESPACE _IO(PIDFS_IOCTL_MAGIC, 7) ++#define PIDFD_GET_TIME_FOR_CHILDREN_NAMESPACE _IO(PIDFS_IOCTL_MAGIC, 8) ++#define PIDFD_GET_USER_NAMESPACE _IO(PIDFS_IOCTL_MAGIC, 9) ++#define PIDFD_GET_UTS_NAMESPACE _IO(PIDFS_IOCTL_MAGIC, 10) ++ + /* Returns a file descriptor that refers to the process PID. The + close-on-exec is set on the file descriptor. */ + extern int pidfd_open (__pid_t __pid, unsigned int __flags) __THROW; +diff --git a/sysdeps/unix/sysv/linux/tst-pidfd-consts.py b/sysdeps/unix/sysv/linux/tst-pidfd-consts.py +index 9824fd214d477fd0..9d53102cbd73dc84 100644 +--- a/sysdeps/unix/sysv/linux/tst-pidfd-consts.py ++++ b/sysdeps/unix/sysv/linux/tst-pidfd-consts.py +@@ -39,7 +39,7 @@ def main(): + sys.exit (77) + + linux_version_headers = glibcsyscalls.linux_kernel_version(args.cc) +- linux_version_glibc = (6, 10) ++ linux_version_glibc = (6, 11) + sys.exit(glibcextract.compare_macro_consts( + '#include \n', + '#include \n' diff --git a/glibc-RHEL-107695-11.patch b/glibc-RHEL-107695-11.patch new file mode 100644 index 0000000..9d10c11 --- /dev/null +++ b/glibc-RHEL-107695-11.patch @@ -0,0 +1,61 @@ +commit f6e849fd7ce2a8954022bd23b94703975b3db0d1 +Author: Adhemerval Zanella +Date: Tue Oct 8 15:45:26 2024 -0300 + + linux: Add MAP_DROPPABLE from Linux 6.11 + + This request the page to be never written out to swap, it will be zeroed + under memory pressure (so kernel can just drop the page), it is inherited + by fork, it is not counted against @code{mlock} budget, and if there is + no enough memory to service a page faults there is no fatal error (so not + signal is sent). + + Tested with build-many-glibcs.py. + + Reviewed-by: H.J. Lu + +diff --git a/manual/llio.texi b/manual/llio.texi +index 17fe1181d5cc2cef..a8ed72c5db6ecba9 100644 +--- a/manual/llio.texi ++++ b/manual/llio.texi +@@ -1647,6 +1647,15 @@ The @code{MAP_HUGETLB} flag is specific to Linux. + @c user programs (and I don't understand the last two). MAP_LOCKED does + @c not appear to be implemented. + ++@item MAP_DROPPABLE ++Request the page to be never written out to swap, it will be zeroed ++under memory pressure (so kernel can just drop the page), it is inherited ++by fork, it is not counted against @code{mlock} budget, and if there is ++not enough memory to service a page fault there is no fatal error (so no ++signal is sent). ++ ++The @code{MAP_DROPPABLE} flag is specific to Linux. ++ + @end vtable + + @code{mmap} returns the address of the new mapping, or +diff --git a/sysdeps/unix/sysv/linux/bits/mman-linux.h b/sysdeps/unix/sysv/linux/bits/mman-linux.h +index 522333c50a04481d..161a88509682cf69 100644 +--- a/sysdeps/unix/sysv/linux/bits/mman-linux.h ++++ b/sysdeps/unix/sysv/linux/bits/mman-linux.h +@@ -43,6 +43,7 @@ + #define MAP_PRIVATE 0x02 /* Changes are private. */ + #define MAP_SHARED_VALIDATE 0x03 /* Share changes and validate + extension flags. */ ++#define MAP_DROPPABLE 0x08 /* Zero memory under memory pressure. */ + #define MAP_TYPE 0x0f /* Mask for type of mapping. */ + + /* Other flags. */ +diff --git a/sysdeps/unix/sysv/linux/tst-mman-consts.py b/sysdeps/unix/sysv/linux/tst-mman-consts.py +index a1137eb1d59d95ec..2191bea36f8f69e0 100644 +--- a/sysdeps/unix/sysv/linux/tst-mman-consts.py ++++ b/sysdeps/unix/sysv/linux/tst-mman-consts.py +@@ -33,7 +33,7 @@ def main(): + help='C compiler (including options) to use') + args = parser.parse_args() + linux_version_headers = glibcsyscalls.linux_kernel_version(args.cc) +- linux_version_glibc = (6, 10) ++ linux_version_glibc = (6, 11) + sys.exit(glibcextract.compare_macro_consts( + '#define _GNU_SOURCE 1\n' + '#include \n', diff --git a/glibc-RHEL-107695-12.patch b/glibc-RHEL-107695-12.patch new file mode 100644 index 0000000..c59be2a --- /dev/null +++ b/glibc-RHEL-107695-12.patch @@ -0,0 +1,41 @@ +commit 934d0bf426ffa58f88cebd219b08742ca21e3365 +Author: Adhemerval Zanella +Date: Tue Oct 8 15:45:27 2024 -0300 + + Update kernel version to 6.11 in header constant tests + + This patch updates the kernel version in the tests tst-mount-consts.py, + and tst-sched-consts.py to 6.11. + + There are no new constants covered by these tests in 6.11. + + Tested with build-many-glibcs.py. + + Reviewed-by: H.J. Lu + +diff --git a/sysdeps/unix/sysv/linux/tst-mount-consts.py b/sysdeps/unix/sysv/linux/tst-mount-consts.py +index 675f1790b64dd34e..b71d8a489daf0865 100755 +--- a/sysdeps/unix/sysv/linux/tst-mount-consts.py ++++ b/sysdeps/unix/sysv/linux/tst-mount-consts.py +@@ -42,7 +42,7 @@ def main(): + # Constants in glibc were updated to match Linux v6.10. When glibc + # constants are updated this value should be updated to match the + # released kernel version from which the constants were taken. +- linux_version_glibc = (6, 10) ++ linux_version_glibc = (6, 11) + def check(cte, exclude=None): + return glibcextract.compare_macro_consts( + '#include \n', +diff --git a/sysdeps/unix/sysv/linux/tst-sched-consts.py b/sysdeps/unix/sysv/linux/tst-sched-consts.py +index 70071dcd974fe064..f06ac400bddc7339 100644 +--- a/sysdeps/unix/sysv/linux/tst-sched-consts.py ++++ b/sysdeps/unix/sysv/linux/tst-sched-consts.py +@@ -33,7 +33,7 @@ def main(): + help='C compiler (including options) to use') + args = parser.parse_args() + linux_version_headers = glibcsyscalls.linux_kernel_version(args.cc) +- linux_version_glibc = (6, 10) ++ linux_version_glibc = (6, 11) + sys.exit(glibcextract.compare_macro_consts( + '#define _GNU_SOURCE 1\n' + '#include \n', diff --git a/glibc-RHEL-107695-13.patch b/glibc-RHEL-107695-13.patch new file mode 100644 index 0000000..4a45428 --- /dev/null +++ b/glibc-RHEL-107695-13.patch @@ -0,0 +1,26 @@ +commit e0a0fd64b5b223fce87061fe23dbb0b30053060c +Author: Joseph Myers +Date: Wed Dec 18 15:12:36 2024 +0000 + + Update syscall lists for Linux 6.12 + + Linux 6.12 has no new syscalls. Update the version number in + syscall-names.list to reflect that it is still current for 6.12. + + Tested with build-many-glibcs.py. + +diff --git a/sysdeps/unix/sysv/linux/syscall-names.list b/sysdeps/unix/sysv/linux/syscall-names.list +index aa5b479e2a08e7bb..d31938a002629784 100644 +--- a/sysdeps/unix/sysv/linux/syscall-names.list ++++ b/sysdeps/unix/sysv/linux/syscall-names.list +@@ -21,8 +21,8 @@ + # This file can list all potential system calls. The names are only + # used if the installed kernel headers also provide them. + +-# The list of system calls is current as of Linux 6.11. +-kernel 6.11 ++# The list of system calls is current as of Linux 6.12. ++kernel 6.12 + + FAST_atomic_update + FAST_cmpxchg diff --git a/glibc-RHEL-107695-14.patch b/glibc-RHEL-107695-14.patch new file mode 100644 index 0000000..2045994 --- /dev/null +++ b/glibc-RHEL-107695-14.patch @@ -0,0 +1,57 @@ +commit 5fcee06dc7f368770c17f9a69b59fa68119a1cec +Author: Joseph Myers +Date: Thu Dec 19 15:38:59 2024 +0000 + + Update kernel version to 6.12 in header constant tests + + There are no new constants covered by tst-mman-consts.py, + tst-mount-consts.py or tst-pidfd-consts.py in Linux 6.12 that need any + header changes, so update the kernel version in those tests. + (tst-sched-consts.py will need updating separately along with adding + SCHED_EXT.) + + Tested with build-many-glibcs.py. + +diff --git a/sysdeps/unix/sysv/linux/tst-mman-consts.py b/sysdeps/unix/sysv/linux/tst-mman-consts.py +index 2191bea36f8f69e0..584936efecbf7755 100644 +--- a/sysdeps/unix/sysv/linux/tst-mman-consts.py ++++ b/sysdeps/unix/sysv/linux/tst-mman-consts.py +@@ -33,7 +33,7 @@ def main(): + help='C compiler (including options) to use') + args = parser.parse_args() + linux_version_headers = glibcsyscalls.linux_kernel_version(args.cc) +- linux_version_glibc = (6, 11) ++ linux_version_glibc = (6, 12) + sys.exit(glibcextract.compare_macro_consts( + '#define _GNU_SOURCE 1\n' + '#include \n', +diff --git a/sysdeps/unix/sysv/linux/tst-mount-consts.py b/sysdeps/unix/sysv/linux/tst-mount-consts.py +index b71d8a489daf0865..e77579033b0fd8ec 100755 +--- a/sysdeps/unix/sysv/linux/tst-mount-consts.py ++++ b/sysdeps/unix/sysv/linux/tst-mount-consts.py +@@ -39,10 +39,10 @@ def main(): + sys.exit (77) + + linux_version_headers = glibcsyscalls.linux_kernel_version(args.cc) +- # Constants in glibc were updated to match Linux v6.10. When glibc ++ # Constants in glibc were updated to match Linux v6.12. When glibc + # constants are updated this value should be updated to match the + # released kernel version from which the constants were taken. +- linux_version_glibc = (6, 11) ++ linux_version_glibc = (6, 12) + def check(cte, exclude=None): + return glibcextract.compare_macro_consts( + '#include \n', +diff --git a/sysdeps/unix/sysv/linux/tst-pidfd-consts.py b/sysdeps/unix/sysv/linux/tst-pidfd-consts.py +index 9d53102cbd73dc84..ef896394bdb12a25 100644 +--- a/sysdeps/unix/sysv/linux/tst-pidfd-consts.py ++++ b/sysdeps/unix/sysv/linux/tst-pidfd-consts.py +@@ -39,7 +39,7 @@ def main(): + sys.exit (77) + + linux_version_headers = glibcsyscalls.linux_kernel_version(args.cc) +- linux_version_glibc = (6, 11) ++ linux_version_glibc = (6, 12) + sys.exit(glibcextract.compare_macro_consts( + '#include \n', + '#include \n' diff --git a/glibc-RHEL-107695-15.patch b/glibc-RHEL-107695-15.patch new file mode 100644 index 0000000..9548647 --- /dev/null +++ b/glibc-RHEL-107695-15.patch @@ -0,0 +1,36 @@ +commit 29ae632e76e5dcb89bdbb38402af47a5040fe1d4 +Author: Joseph Myers +Date: Thu Dec 19 17:08:38 2024 +0000 + + Add SCHED_EXT from Linux 6.12 to bits/sched.h + + Linux 6.12 adds the SCHED_EXT constant. Add it to glibc's + bits/sched.h and update the kernel version in tst-sched-consts.py. + + Tested for x86_64. + +diff --git a/sysdeps/unix/sysv/linux/bits/sched.h b/sysdeps/unix/sysv/linux/bits/sched.h +index 7c75303b80c18de2..e60cb05a60027a30 100644 +--- a/sysdeps/unix/sysv/linux/bits/sched.h ++++ b/sysdeps/unix/sysv/linux/bits/sched.h +@@ -34,6 +34,7 @@ + # define SCHED_ISO 4 + # define SCHED_IDLE 5 + # define SCHED_DEADLINE 6 ++# define SCHED_EXT 7 + + /* Flags that can be used in policy values. */ + # define SCHED_RESET_ON_FORK 0x40000000 +diff --git a/sysdeps/unix/sysv/linux/tst-sched-consts.py b/sysdeps/unix/sysv/linux/tst-sched-consts.py +index f06ac400bddc7339..6a5b837334ab45f8 100644 +--- a/sysdeps/unix/sysv/linux/tst-sched-consts.py ++++ b/sysdeps/unix/sysv/linux/tst-sched-consts.py +@@ -33,7 +33,7 @@ def main(): + help='C compiler (including options) to use') + args = parser.parse_args() + linux_version_headers = glibcsyscalls.linux_kernel_version(args.cc) +- linux_version_glibc = (6, 11) ++ linux_version_glibc = (6, 12) + sys.exit(glibcextract.compare_macro_consts( + '#define _GNU_SOURCE 1\n' + '#include \n', diff --git a/glibc-RHEL-107695-16.patch b/glibc-RHEL-107695-16.patch new file mode 100644 index 0000000..d87bf94 --- /dev/null +++ b/glibc-RHEL-107695-16.patch @@ -0,0 +1,959 @@ +commit eea6f1e079a301dfd5c7b7f4faf38b4d6e7ea059 +Author: Joseph Myers +Date: Wed Mar 12 12:51:28 2025 +0000 + + Update syscall lists for Linux 6.13 + + Linux 6.13 adds four new syscalls. Update syscall-names.list and + regenerate the arch-syscall.h headers with build-many-glibcs.py + update-syscalls. + + Tested with build-many-glibcs.py. + +diff --git a/sysdeps/unix/sysv/linux/aarch64/arch-syscall.h b/sysdeps/unix/sysv/linux/aarch64/arch-syscall.h +index 19b6316cb6ffae26..89aced0b453609e3 100644 +--- a/sysdeps/unix/sysv/linux/aarch64/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/aarch64/arch-syscall.h +@@ -95,6 +95,7 @@ + #define __NR_gettimeofday 169 + #define __NR_getuid 174 + #define __NR_getxattr 8 ++#define __NR_getxattrat 464 + #define __NR_init_module 105 + #define __NR_inotify_add_watch 27 + #define __NR_inotify_init1 26 +@@ -124,6 +125,7 @@ + #define __NR_listen 201 + #define __NR_listmount 458 + #define __NR_listxattr 11 ++#define __NR_listxattrat 465 + #define __NR_llistxattr 12 + #define __NR_lookup_dcookie 18 + #define __NR_lremovexattr 15 +@@ -212,6 +214,7 @@ + #define __NR_recvmsg 212 + #define __NR_remap_file_pages 234 + #define __NR_removexattr 14 ++#define __NR_removexattrat 466 + #define __NR_renameat 38 + #define __NR_renameat2 276 + #define __NR_request_key 218 +@@ -270,6 +273,7 @@ + #define __NR_settimeofday 170 + #define __NR_setuid 146 + #define __NR_setxattr 5 ++#define __NR_setxattrat 463 + #define __NR_shmat 196 + #define __NR_shmctl 195 + #define __NR_shmdt 197 +diff --git a/sysdeps/unix/sysv/linux/alpha/arch-syscall.h b/sysdeps/unix/sysv/linux/alpha/arch-syscall.h +index 216a5575c69d0ff3..455da93b478ab037 100644 +--- a/sysdeps/unix/sysv/linux/alpha/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/alpha/arch-syscall.h +@@ -119,6 +119,7 @@ + #define __NR_gettimeofday 359 + #define __NR_getuid 24 + #define __NR_getxattr 385 ++#define __NR_getxattrat 574 + #define __NR_getxgid 47 + #define __NR_getxpid 20 + #define __NR_getxuid 24 +@@ -153,6 +154,7 @@ + #define __NR_listen 106 + #define __NR_listmount 568 + #define __NR_listxattr 388 ++#define __NR_listxattrat 575 + #define __NR_llistxattr 389 + #define __NR_lookup_dcookie 406 + #define __NR_lremovexattr 392 +@@ -364,6 +366,7 @@ + #define __NR_recvmsg 113 + #define __NR_remap_file_pages 410 + #define __NR_removexattr 391 ++#define __NR_removexattrat 576 + #define __NR_rename 128 + #define __NR_renameat 457 + #define __NR_renameat2 510 +@@ -428,6 +431,7 @@ + #define __NR_settimeofday 360 + #define __NR_setuid 23 + #define __NR_setxattr 382 ++#define __NR_setxattrat 573 + #define __NR_shmat 209 + #define __NR_shmctl 210 + #define __NR_shmdt 211 +diff --git a/sysdeps/unix/sysv/linux/arc/arch-syscall.h b/sysdeps/unix/sysv/linux/arc/arch-syscall.h +index ea581b0a6dc0f2d4..01075e8cdfd7cd30 100644 +--- a/sysdeps/unix/sysv/linux/arc/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/arc/arch-syscall.h +@@ -98,6 +98,7 @@ + #define __NR_gettimeofday 169 + #define __NR_getuid 174 + #define __NR_getxattr 8 ++#define __NR_getxattrat 464 + #define __NR_init_module 105 + #define __NR_inotify_add_watch 27 + #define __NR_inotify_init1 26 +@@ -128,6 +129,7 @@ + #define __NR_listen 201 + #define __NR_listmount 458 + #define __NR_listxattr 11 ++#define __NR_listxattrat 465 + #define __NR_llistxattr 12 + #define __NR_llseek 62 + #define __NR_lookup_dcookie 18 +@@ -214,6 +216,7 @@ + #define __NR_recvmsg 212 + #define __NR_remap_file_pages 234 + #define __NR_removexattr 14 ++#define __NR_removexattrat 466 + #define __NR_renameat 38 + #define __NR_renameat2 276 + #define __NR_request_key 218 +@@ -272,6 +275,7 @@ + #define __NR_settimeofday 170 + #define __NR_setuid 146 + #define __NR_setxattr 5 ++#define __NR_setxattrat 463 + #define __NR_shmat 196 + #define __NR_shmctl 195 + #define __NR_shmdt 197 +diff --git a/sysdeps/unix/sysv/linux/arm/arch-syscall.h b/sysdeps/unix/sysv/linux/arm/arch-syscall.h +index 2809f52f94e9ee16..97044727fc1e24bf 100644 +--- a/sysdeps/unix/sysv/linux/arm/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/arm/arch-syscall.h +@@ -132,6 +132,7 @@ + #define __NR_getuid 24 + #define __NR_getuid32 199 + #define __NR_getxattr 229 ++#define __NR_getxattrat 464 + #define __NR_init_module 128 + #define __NR_inotify_add_watch 317 + #define __NR_inotify_init 316 +@@ -166,6 +167,7 @@ + #define __NR_listen 284 + #define __NR_listmount 458 + #define __NR_listxattr 232 ++#define __NR_listxattrat 465 + #define __NR_llistxattr 233 + #define __NR_lookup_dcookie 249 + #define __NR_lremovexattr 236 +@@ -271,6 +273,7 @@ + #define __NR_recvmsg 297 + #define __NR_remap_file_pages 253 + #define __NR_removexattr 235 ++#define __NR_removexattrat 466 + #define __NR_rename 38 + #define __NR_renameat 329 + #define __NR_renameat2 382 +@@ -346,6 +349,7 @@ + #define __NR_setuid 23 + #define __NR_setuid32 213 + #define __NR_setxattr 226 ++#define __NR_setxattrat 463 + #define __NR_shmat 305 + #define __NR_shmctl 308 + #define __NR_shmdt 306 +diff --git a/sysdeps/unix/sysv/linux/csky/arch-syscall.h b/sysdeps/unix/sysv/linux/csky/arch-syscall.h +index ede3551a00dc81c6..a719a55647383d4e 100644 +--- a/sysdeps/unix/sysv/linux/csky/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/csky/arch-syscall.h +@@ -103,6 +103,7 @@ + #define __NR_gettimeofday 169 + #define __NR_getuid 174 + #define __NR_getxattr 8 ++#define __NR_getxattrat 464 + #define __NR_init_module 105 + #define __NR_inotify_add_watch 27 + #define __NR_inotify_init1 26 +@@ -133,6 +134,7 @@ + #define __NR_listen 201 + #define __NR_listmount 458 + #define __NR_listxattr 11 ++#define __NR_listxattrat 465 + #define __NR_llistxattr 12 + #define __NR_llseek 62 + #define __NR_lookup_dcookie 18 +@@ -224,6 +226,7 @@ + #define __NR_recvmsg 212 + #define __NR_remap_file_pages 234 + #define __NR_removexattr 14 ++#define __NR_removexattrat 466 + #define __NR_renameat2 276 + #define __NR_request_key 218 + #define __NR_restart_syscall 128 +@@ -285,6 +288,7 @@ + #define __NR_settimeofday 170 + #define __NR_setuid 146 + #define __NR_setxattr 5 ++#define __NR_setxattrat 463 + #define __NR_shmat 196 + #define __NR_shmctl 195 + #define __NR_shmdt 197 +diff --git a/sysdeps/unix/sysv/linux/hppa/arch-syscall.h b/sysdeps/unix/sysv/linux/hppa/arch-syscall.h +index 08b153f2ccdf6f45..dc592c58364a1804 100644 +--- a/sysdeps/unix/sysv/linux/hppa/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/hppa/arch-syscall.h +@@ -124,6 +124,7 @@ + #define __NR_gettimeofday 78 + #define __NR_getuid 24 + #define __NR_getxattr 241 ++#define __NR_getxattrat 464 + #define __NR_init_module 128 + #define __NR_inotify_add_watch 270 + #define __NR_inotify_init 269 +@@ -157,6 +158,7 @@ + #define __NR_listen 32 + #define __NR_listmount 458 + #define __NR_listxattr 244 ++#define __NR_listxattrat 465 + #define __NR_llistxattr 245 + #define __NR_lookup_dcookie 223 + #define __NR_lremovexattr 248 +@@ -259,6 +261,7 @@ + #define __NR_recvmsg 184 + #define __NR_remap_file_pages 227 + #define __NR_removexattr 247 ++#define __NR_removexattrat 466 + #define __NR_rename 38 + #define __NR_renameat 282 + #define __NR_renameat2 337 +@@ -324,6 +327,7 @@ + #define __NR_settimeofday 79 + #define __NR_setuid 23 + #define __NR_setxattr 238 ++#define __NR_setxattrat 463 + #define __NR_sgetmask 68 + #define __NR_shmat 192 + #define __NR_shmctl 195 +diff --git a/sysdeps/unix/sysv/linux/i386/arch-syscall.h b/sysdeps/unix/sysv/linux/i386/arch-syscall.h +index 500ca1ec70e2c5fc..c10897f7b032c9fb 100644 +--- a/sysdeps/unix/sysv/linux/i386/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/i386/arch-syscall.h +@@ -140,6 +140,7 @@ + #define __NR_getuid 24 + #define __NR_getuid32 199 + #define __NR_getxattr 229 ++#define __NR_getxattrat 464 + #define __NR_gtty 32 + #define __NR_idle 112 + #define __NR_init_module 128 +@@ -178,6 +179,7 @@ + #define __NR_listen 363 + #define __NR_listmount 458 + #define __NR_listxattr 232 ++#define __NR_listxattrat 465 + #define __NR_llistxattr 233 + #define __NR_lock 53 + #define __NR_lookup_dcookie 253 +@@ -294,6 +296,7 @@ + #define __NR_recvmsg 372 + #define __NR_remap_file_pages 257 + #define __NR_removexattr 235 ++#define __NR_removexattrat 466 + #define __NR_rename 38 + #define __NR_renameat 302 + #define __NR_renameat2 353 +@@ -367,6 +370,7 @@ + #define __NR_setuid 23 + #define __NR_setuid32 213 + #define __NR_setxattr 226 ++#define __NR_setxattrat 463 + #define __NR_sgetmask 68 + #define __NR_shmat 397 + #define __NR_shmctl 396 +diff --git a/sysdeps/unix/sysv/linux/loongarch/arch-syscall.h b/sysdeps/unix/sysv/linux/loongarch/arch-syscall.h +index 7e732256fd4c6da7..a0d0d91a09fa57fb 100644 +--- a/sysdeps/unix/sysv/linux/loongarch/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/loongarch/arch-syscall.h +@@ -94,6 +94,7 @@ + #define __NR_gettimeofday 169 + #define __NR_getuid 174 + #define __NR_getxattr 8 ++#define __NR_getxattrat 464 + #define __NR_init_module 105 + #define __NR_inotify_add_watch 27 + #define __NR_inotify_init1 26 +@@ -123,6 +124,7 @@ + #define __NR_listen 201 + #define __NR_listmount 458 + #define __NR_listxattr 11 ++#define __NR_listxattrat 465 + #define __NR_llistxattr 12 + #define __NR_lookup_dcookie 18 + #define __NR_lremovexattr 15 +@@ -210,6 +212,7 @@ + #define __NR_recvmsg 212 + #define __NR_remap_file_pages 234 + #define __NR_removexattr 14 ++#define __NR_removexattrat 466 + #define __NR_renameat2 276 + #define __NR_request_key 218 + #define __NR_restart_syscall 128 +@@ -266,6 +269,7 @@ + #define __NR_settimeofday 170 + #define __NR_setuid 146 + #define __NR_setxattr 5 ++#define __NR_setxattrat 463 + #define __NR_shmat 196 + #define __NR_shmctl 195 + #define __NR_shmdt 197 +diff --git a/sysdeps/unix/sysv/linux/m68k/arch-syscall.h b/sysdeps/unix/sysv/linux/m68k/arch-syscall.h +index 4ab34f6228594c9f..715809acaf112852 100644 +--- a/sysdeps/unix/sysv/linux/m68k/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/m68k/arch-syscall.h +@@ -140,6 +140,7 @@ + #define __NR_getuid 24 + #define __NR_getuid32 199 + #define __NR_getxattr 226 ++#define __NR_getxattrat 464 + #define __NR_init_module 128 + #define __NR_inotify_add_watch 285 + #define __NR_inotify_init 284 +@@ -173,6 +174,7 @@ + #define __NR_listen 360 + #define __NR_listmount 458 + #define __NR_listxattr 229 ++#define __NR_listxattrat 465 + #define __NR_llistxattr 230 + #define __NR_lookup_dcookie 248 + #define __NR_lremovexattr 233 +@@ -281,6 +283,7 @@ + #define __NR_recvmsg 369 + #define __NR_remap_file_pages 252 + #define __NR_removexattr 232 ++#define __NR_removexattrat 466 + #define __NR_rename 38 + #define __NR_renameat 295 + #define __NR_renameat2 351 +@@ -354,6 +357,7 @@ + #define __NR_setuid 23 + #define __NR_setuid32 213 + #define __NR_setxattr 223 ++#define __NR_setxattrat 463 + #define __NR_sgetmask 68 + #define __NR_shmat 397 + #define __NR_shmctl 396 +diff --git a/sysdeps/unix/sysv/linux/microblaze/arch-syscall.h b/sysdeps/unix/sysv/linux/microblaze/arch-syscall.h +index 79e225e50c6d30b4..24e218fc86b984cc 100644 +--- a/sysdeps/unix/sysv/linux/microblaze/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/microblaze/arch-syscall.h +@@ -140,6 +140,7 @@ + #define __NR_getuid 24 + #define __NR_getuid32 199 + #define __NR_getxattr 229 ++#define __NR_getxattrat 464 + #define __NR_gtty 32 + #define __NR_idle 112 + #define __NR_init_module 128 +@@ -178,6 +179,7 @@ + #define __NR_listen 348 + #define __NR_listmount 458 + #define __NR_listxattr 232 ++#define __NR_listxattrat 465 + #define __NR_llistxattr 233 + #define __NR_lock 53 + #define __NR_lookup_dcookie 253 +@@ -294,6 +296,7 @@ + #define __NR_recvmsg 361 + #define __NR_remap_file_pages 257 + #define __NR_removexattr 235 ++#define __NR_removexattrat 466 + #define __NR_rename 38 + #define __NR_renameat 302 + #define __NR_renameat2 383 +@@ -370,6 +373,7 @@ + #define __NR_setuid 23 + #define __NR_setuid32 213 + #define __NR_setxattr 226 ++#define __NR_setxattrat 463 + #define __NR_sgetmask 68 + #define __NR_shmat 335 + #define __NR_shmctl 336 +diff --git a/sysdeps/unix/sysv/linux/mips/mips32/arch-syscall.h b/sysdeps/unix/sysv/linux/mips/mips32/arch-syscall.h +index dadd7f3130a55625..a7615cb7a0c66df6 100644 +--- a/sysdeps/unix/sysv/linux/mips/mips32/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/mips/mips32/arch-syscall.h +@@ -131,6 +131,7 @@ + #define __NR_gettimeofday 4078 + #define __NR_getuid 4024 + #define __NR_getxattr 4227 ++#define __NR_getxattrat 4464 + #define __NR_gtty 4032 + #define __NR_idle 4112 + #define __NR_init_module 4128 +@@ -168,6 +169,7 @@ + #define __NR_listen 4174 + #define __NR_listmount 4458 + #define __NR_listxattr 4230 ++#define __NR_listxattrat 4465 + #define __NR_llistxattr 4231 + #define __NR_lock 4053 + #define __NR_lookup_dcookie 4247 +@@ -279,6 +281,7 @@ + #define __NR_recvmsg 4177 + #define __NR_remap_file_pages 4251 + #define __NR_removexattr 4233 ++#define __NR_removexattrat 4466 + #define __NR_rename 4038 + #define __NR_renameat 4295 + #define __NR_renameat2 4351 +@@ -343,6 +346,7 @@ + #define __NR_settimeofday 4079 + #define __NR_setuid 4023 + #define __NR_setxattr 4224 ++#define __NR_setxattrat 4463 + #define __NR_sgetmask 4068 + #define __NR_shmat 4397 + #define __NR_shmctl 4396 +diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/arch-syscall.h b/sysdeps/unix/sysv/linux/mips/mips64/n32/arch-syscall.h +index db6b2d4609d87d3e..4d863c2dd29c3f3e 100644 +--- a/sysdeps/unix/sysv/linux/mips/mips64/n32/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/arch-syscall.h +@@ -124,6 +124,7 @@ + #define __NR_gettimeofday 6094 + #define __NR_getuid 6100 + #define __NR_getxattr 6183 ++#define __NR_getxattrat 6464 + #define __NR_init_module 6168 + #define __NR_inotify_add_watch 6248 + #define __NR_inotify_init 6247 +@@ -156,6 +157,7 @@ + #define __NR_listen 6049 + #define __NR_listmount 6458 + #define __NR_listxattr 6186 ++#define __NR_listxattrat 6465 + #define __NR_llistxattr 6187 + #define __NR_lookup_dcookie 6206 + #define __NR_lremovexattr 6190 +@@ -258,6 +260,7 @@ + #define __NR_recvmsg 6046 + #define __NR_remap_file_pages 6210 + #define __NR_removexattr 6189 ++#define __NR_removexattrat 6466 + #define __NR_rename 6080 + #define __NR_renameat 6258 + #define __NR_renameat2 6315 +@@ -323,6 +326,7 @@ + #define __NR_settimeofday 6159 + #define __NR_setuid 6103 + #define __NR_setxattr 6180 ++#define __NR_setxattrat 6463 + #define __NR_shmat 6029 + #define __NR_shmctl 6030 + #define __NR_shmdt 6065 +diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/arch-syscall.h b/sysdeps/unix/sysv/linux/mips/mips64/n64/arch-syscall.h +index b4129a4dbdf71aec..9b6683e4c1ca9312 100644 +--- a/sysdeps/unix/sysv/linux/mips/mips64/n64/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/arch-syscall.h +@@ -116,6 +116,7 @@ + #define __NR_gettimeofday 5094 + #define __NR_getuid 5100 + #define __NR_getxattr 5183 ++#define __NR_getxattrat 5464 + #define __NR_init_module 5168 + #define __NR_inotify_add_watch 5244 + #define __NR_inotify_init 5243 +@@ -147,6 +148,7 @@ + #define __NR_listen 5049 + #define __NR_listmount 5458 + #define __NR_listxattr 5186 ++#define __NR_listxattrat 5465 + #define __NR_llistxattr 5187 + #define __NR_lookup_dcookie 5206 + #define __NR_lremovexattr 5190 +@@ -244,6 +246,7 @@ + #define __NR_recvmsg 5046 + #define __NR_remap_file_pages 5210 + #define __NR_removexattr 5189 ++#define __NR_removexattrat 5466 + #define __NR_rename 5080 + #define __NR_renameat 5254 + #define __NR_renameat2 5311 +@@ -305,6 +308,7 @@ + #define __NR_settimeofday 5159 + #define __NR_setuid 5103 + #define __NR_setxattr 5180 ++#define __NR_setxattrat 5463 + #define __NR_shmat 5029 + #define __NR_shmctl 5030 + #define __NR_shmdt 5065 +diff --git a/sysdeps/unix/sysv/linux/or1k/arch-syscall.h b/sysdeps/unix/sysv/linux/or1k/arch-syscall.h +index 2d21fa208576f795..a071c76aaf82d9b6 100644 +--- a/sysdeps/unix/sysv/linux/or1k/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/or1k/arch-syscall.h +@@ -102,6 +102,7 @@ + #define __NR_gettimeofday 169 + #define __NR_getuid 174 + #define __NR_getxattr 8 ++#define __NR_getxattrat 464 + #define __NR_init_module 105 + #define __NR_inotify_add_watch 27 + #define __NR_inotify_init1 26 +@@ -132,6 +133,7 @@ + #define __NR_listen 201 + #define __NR_listmount 458 + #define __NR_listxattr 11 ++#define __NR_listxattrat 465 + #define __NR_llistxattr 12 + #define __NR_llseek 62 + #define __NR_lookup_dcookie 18 +@@ -224,6 +226,7 @@ + #define __NR_recvmsg 212 + #define __NR_remap_file_pages 234 + #define __NR_removexattr 14 ++#define __NR_removexattrat 466 + #define __NR_renameat 38 + #define __NR_renameat2 276 + #define __NR_request_key 218 +@@ -285,6 +288,7 @@ + #define __NR_settimeofday 170 + #define __NR_setuid 146 + #define __NR_setxattr 5 ++#define __NR_setxattrat 463 + #define __NR_shmat 196 + #define __NR_shmctl 195 + #define __NR_shmdt 197 +diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/arch-syscall.h b/sysdeps/unix/sysv/linux/powerpc/powerpc32/arch-syscall.h +index 206d9fd65697d152..b3481e4c242257e0 100644 +--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/arch-syscall.h +@@ -130,6 +130,7 @@ + #define __NR_gettimeofday 78 + #define __NR_getuid 24 + #define __NR_getxattr 212 ++#define __NR_getxattrat 464 + #define __NR_gtty 32 + #define __NR_idle 112 + #define __NR_init_module 128 +@@ -168,6 +169,7 @@ + #define __NR_listen 329 + #define __NR_listmount 458 + #define __NR_listxattr 215 ++#define __NR_listxattrat 465 + #define __NR_llistxattr 216 + #define __NR_lock 53 + #define __NR_lookup_dcookie 235 +@@ -288,6 +290,7 @@ + #define __NR_recvmsg 342 + #define __NR_remap_file_pages 239 + #define __NR_removexattr 218 ++#define __NR_removexattrat 466 + #define __NR_rename 38 + #define __NR_renameat 293 + #define __NR_renameat2 357 +@@ -353,6 +356,7 @@ + #define __NR_settimeofday 79 + #define __NR_setuid 23 + #define __NR_setxattr 209 ++#define __NR_setxattrat 463 + #define __NR_sgetmask 68 + #define __NR_shmat 397 + #define __NR_shmctl 396 +diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/arch-syscall.h b/sysdeps/unix/sysv/linux/powerpc/powerpc64/arch-syscall.h +index 19f72a7f694a5322..45108e8f6f5c7b6c 100644 +--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/arch-syscall.h +@@ -119,6 +119,7 @@ + #define __NR_gettimeofday 78 + #define __NR_getuid 24 + #define __NR_getxattr 212 ++#define __NR_getxattrat 464 + #define __NR_gtty 32 + #define __NR_idle 112 + #define __NR_init_module 128 +@@ -156,6 +157,7 @@ + #define __NR_listen 329 + #define __NR_listmount 458 + #define __NR_listxattr 215 ++#define __NR_listxattrat 465 + #define __NR_llistxattr 216 + #define __NR_lock 53 + #define __NR_lookup_dcookie 235 +@@ -270,6 +272,7 @@ + #define __NR_recvmsg 342 + #define __NR_remap_file_pages 239 + #define __NR_removexattr 218 ++#define __NR_removexattrat 466 + #define __NR_rename 38 + #define __NR_renameat 293 + #define __NR_renameat2 357 +@@ -332,6 +335,7 @@ + #define __NR_settimeofday 79 + #define __NR_setuid 23 + #define __NR_setxattr 209 ++#define __NR_setxattrat 463 + #define __NR_sgetmask 68 + #define __NR_shmat 397 + #define __NR_shmctl 396 +diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h b/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h +index eb9e57b02898cb79..53338790a7a9837c 100644 +--- a/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h +@@ -91,6 +91,7 @@ + #define __NR_gettid 178 + #define __NR_getuid 174 + #define __NR_getxattr 8 ++#define __NR_getxattrat 464 + #define __NR_init_module 105 + #define __NR_inotify_add_watch 27 + #define __NR_inotify_init1 26 +@@ -119,6 +120,7 @@ + #define __NR_listen 201 + #define __NR_listmount 458 + #define __NR_listxattr 11 ++#define __NR_listxattrat 465 + #define __NR_llistxattr 12 + #define __NR_llseek 62 + #define __NR_lookup_dcookie 18 +@@ -205,6 +207,7 @@ + #define __NR_recvmsg 212 + #define __NR_remap_file_pages 234 + #define __NR_removexattr 14 ++#define __NR_removexattrat 466 + #define __NR_renameat2 276 + #define __NR_request_key 218 + #define __NR_restart_syscall 128 +@@ -262,6 +265,7 @@ + #define __NR_setsockopt 208 + #define __NR_setuid 146 + #define __NR_setxattr 5 ++#define __NR_setxattrat 463 + #define __NR_shmat 196 + #define __NR_shmctl 195 + #define __NR_shmdt 197 +diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h b/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h +index 1eac18e5822d8b3e..eed1dffc321200d8 100644 +--- a/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h +@@ -95,6 +95,7 @@ + #define __NR_gettimeofday 169 + #define __NR_getuid 174 + #define __NR_getxattr 8 ++#define __NR_getxattrat 464 + #define __NR_init_module 105 + #define __NR_inotify_add_watch 27 + #define __NR_inotify_init1 26 +@@ -124,6 +125,7 @@ + #define __NR_listen 201 + #define __NR_listmount 458 + #define __NR_listxattr 11 ++#define __NR_listxattrat 465 + #define __NR_llistxattr 12 + #define __NR_lookup_dcookie 18 + #define __NR_lremovexattr 15 +@@ -212,6 +214,7 @@ + #define __NR_recvmsg 212 + #define __NR_remap_file_pages 234 + #define __NR_removexattr 14 ++#define __NR_removexattrat 466 + #define __NR_renameat2 276 + #define __NR_request_key 218 + #define __NR_restart_syscall 128 +@@ -271,6 +274,7 @@ + #define __NR_settimeofday 170 + #define __NR_setuid 146 + #define __NR_setxattr 5 ++#define __NR_setxattrat 463 + #define __NR_shmat 196 + #define __NR_shmctl 195 + #define __NR_shmdt 197 +diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/arch-syscall.h b/sysdeps/unix/sysv/linux/s390/s390-32/arch-syscall.h +index 464eca58b28ef5e0..0bf8f9582cef0fab 100644 +--- a/sysdeps/unix/sysv/linux/s390/s390-32/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/s390/s390-32/arch-syscall.h +@@ -136,6 +136,7 @@ + #define __NR_getuid 24 + #define __NR_getuid32 199 + #define __NR_getxattr 227 ++#define __NR_getxattrat 464 + #define __NR_idle 112 + #define __NR_init_module 128 + #define __NR_inotify_add_watch 285 +@@ -173,6 +174,7 @@ + #define __NR_listen 363 + #define __NR_listmount 458 + #define __NR_listxattr 230 ++#define __NR_listxattrat 465 + #define __NR_llistxattr 231 + #define __NR_lookup_dcookie 110 + #define __NR_lremovexattr 234 +@@ -279,6 +281,7 @@ + #define __NR_recvmsg 372 + #define __NR_remap_file_pages 267 + #define __NR_removexattr 233 ++#define __NR_removexattrat 466 + #define __NR_rename 38 + #define __NR_renameat 295 + #define __NR_renameat2 347 +@@ -355,6 +358,7 @@ + #define __NR_setuid 23 + #define __NR_setuid32 213 + #define __NR_setxattr 224 ++#define __NR_setxattrat 463 + #define __NR_shmat 397 + #define __NR_shmctl 396 + #define __NR_shmdt 398 +diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/arch-syscall.h b/sysdeps/unix/sysv/linux/s390/s390-64/arch-syscall.h +index 57842702fd389edd..061f8db0cab0d0e9 100644 +--- a/sysdeps/unix/sysv/linux/s390/s390-64/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/s390/s390-64/arch-syscall.h +@@ -114,6 +114,7 @@ + #define __NR_gettimeofday 78 + #define __NR_getuid 199 + #define __NR_getxattr 227 ++#define __NR_getxattrat 464 + #define __NR_idle 112 + #define __NR_init_module 128 + #define __NR_inotify_add_watch 285 +@@ -148,6 +149,7 @@ + #define __NR_listen 363 + #define __NR_listmount 458 + #define __NR_listxattr 230 ++#define __NR_listxattrat 465 + #define __NR_llistxattr 231 + #define __NR_lookup_dcookie 110 + #define __NR_lremovexattr 234 +@@ -248,6 +250,7 @@ + #define __NR_recvmsg 372 + #define __NR_remap_file_pages 267 + #define __NR_removexattr 233 ++#define __NR_removexattrat 466 + #define __NR_rename 38 + #define __NR_renameat 295 + #define __NR_renameat2 347 +@@ -313,6 +316,7 @@ + #define __NR_settimeofday 79 + #define __NR_setuid 213 + #define __NR_setxattr 224 ++#define __NR_setxattrat 463 + #define __NR_shmat 397 + #define __NR_shmctl 396 + #define __NR_shmdt 398 +diff --git a/sysdeps/unix/sysv/linux/sh/arch-syscall.h b/sysdeps/unix/sysv/linux/sh/arch-syscall.h +index 165ba017c7411aef..52cc320a9378e324 100644 +--- a/sysdeps/unix/sysv/linux/sh/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/sh/arch-syscall.h +@@ -133,6 +133,7 @@ + #define __NR_getuid 24 + #define __NR_getuid32 199 + #define __NR_getxattr 229 ++#define __NR_getxattrat 464 + #define __NR_init_module 128 + #define __NR_inotify_add_watch 291 + #define __NR_inotify_init 290 +@@ -166,6 +167,7 @@ + #define __NR_listen 343 + #define __NR_listmount 458 + #define __NR_listxattr 232 ++#define __NR_listxattrat 465 + #define __NR_llistxattr 233 + #define __NR_lookup_dcookie 253 + #define __NR_lremovexattr 236 +@@ -274,6 +276,7 @@ + #define __NR_recvmsg 356 + #define __NR_remap_file_pages 257 + #define __NR_removexattr 235 ++#define __NR_removexattrat 466 + #define __NR_rename 38 + #define __NR_renameat 302 + #define __NR_renameat2 371 +@@ -346,6 +349,7 @@ + #define __NR_setuid 23 + #define __NR_setuid32 213 + #define __NR_setxattr 226 ++#define __NR_setxattrat 463 + #define __NR_sgetmask 68 + #define __NR_shmat 397 + #define __NR_shmctl 396 +diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/arch-syscall.h b/sysdeps/unix/sysv/linux/sparc/sparc32/arch-syscall.h +index 3bad6f102ffaafb2..ee870bc7b890e0b6 100644 +--- a/sysdeps/unix/sysv/linux/sparc/sparc32/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/sparc/sparc32/arch-syscall.h +@@ -136,6 +136,7 @@ + #define __NR_getuid 24 + #define __NR_getuid32 44 + #define __NR_getxattr 172 ++#define __NR_getxattrat 464 + #define __NR_init_module 190 + #define __NR_inotify_add_watch 152 + #define __NR_inotify_init 151 +@@ -171,6 +172,7 @@ + #define __NR_listen 354 + #define __NR_listmount 458 + #define __NR_listxattr 178 ++#define __NR_listxattrat 465 + #define __NR_llistxattr 179 + #define __NR_lookup_dcookie 208 + #define __NR_lremovexattr 182 +@@ -279,6 +281,7 @@ + #define __NR_recvmsg 113 + #define __NR_remap_file_pages 192 + #define __NR_removexattr 181 ++#define __NR_removexattrat 466 + #define __NR_rename 128 + #define __NR_renameat 291 + #define __NR_renameat2 345 +@@ -351,6 +354,7 @@ + #define __NR_setuid 23 + #define __NR_setuid32 87 + #define __NR_setxattr 169 ++#define __NR_setxattrat 463 + #define __NR_sgetmask 199 + #define __NR_shmat 397 + #define __NR_shmctl 396 +diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/arch-syscall.h b/sysdeps/unix/sysv/linux/sparc/sparc64/arch-syscall.h +index 98e143792026d0e8..3acbebefa95fbbc6 100644 +--- a/sysdeps/unix/sysv/linux/sparc/sparc64/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/sparc/sparc64/arch-syscall.h +@@ -121,6 +121,7 @@ + #define __NR_gettimeofday 116 + #define __NR_getuid 24 + #define __NR_getxattr 172 ++#define __NR_getxattrat 464 + #define __NR_init_module 190 + #define __NR_inotify_add_watch 152 + #define __NR_inotify_init 151 +@@ -154,6 +155,7 @@ + #define __NR_listen 354 + #define __NR_listmount 458 + #define __NR_listxattr 178 ++#define __NR_listxattrat 465 + #define __NR_llistxattr 179 + #define __NR_lookup_dcookie 208 + #define __NR_lremovexattr 182 +@@ -257,6 +259,7 @@ + #define __NR_recvmsg 113 + #define __NR_remap_file_pages 192 + #define __NR_removexattr 181 ++#define __NR_removexattrat 466 + #define __NR_rename 128 + #define __NR_renameat 291 + #define __NR_renameat2 345 +@@ -320,6 +323,7 @@ + #define __NR_settimeofday 122 + #define __NR_setuid 23 + #define __NR_setxattr 169 ++#define __NR_setxattrat 463 + #define __NR_sgetmask 199 + #define __NR_shmat 397 + #define __NR_shmctl 396 +diff --git a/sysdeps/unix/sysv/linux/syscall-names.list b/sysdeps/unix/sysv/linux/syscall-names.list +index d31938a002629784..a0c65be7a5c49160 100644 +--- a/sysdeps/unix/sysv/linux/syscall-names.list ++++ b/sysdeps/unix/sysv/linux/syscall-names.list +@@ -21,8 +21,8 @@ + # This file can list all potential system calls. The names are only + # used if the installed kernel headers also provide them. + +-# The list of system calls is current as of Linux 6.12. +-kernel 6.12 ++# The list of system calls is current as of Linux 6.13. ++kernel 6.13 + + FAST_atomic_update + FAST_cmpxchg +@@ -198,6 +198,7 @@ getuid + getuid32 + getunwind + getxattr ++getxattrat + getxgid + getxpid + getxuid +@@ -241,6 +242,7 @@ linkat + listen + listmount + listxattr ++listxattrat + llistxattr + llseek + lock +@@ -482,6 +484,7 @@ recvmmsg_time64 + recvmsg + remap_file_pages + removexattr ++removexattrat + rename + renameat + renameat2 +@@ -572,6 +575,7 @@ settimeofday + setuid + setuid32 + setxattr ++setxattrat + sgetmask + shmat + shmctl +diff --git a/sysdeps/unix/sysv/linux/x86_64/64/arch-syscall.h b/sysdeps/unix/sysv/linux/x86_64/64/arch-syscall.h +index dfc10d0c7e8a8f1e..17b84c70f58ac276 100644 +--- a/sysdeps/unix/sysv/linux/x86_64/64/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/x86_64/64/arch-syscall.h +@@ -117,6 +117,7 @@ + #define __NR_gettimeofday 96 + #define __NR_getuid 102 + #define __NR_getxattr 191 ++#define __NR_getxattrat 464 + #define __NR_init_module 175 + #define __NR_inotify_add_watch 254 + #define __NR_inotify_init 253 +@@ -151,6 +152,7 @@ + #define __NR_listen 50 + #define __NR_listmount 458 + #define __NR_listxattr 194 ++#define __NR_listxattrat 465 + #define __NR_llistxattr 195 + #define __NR_lookup_dcookie 212 + #define __NR_lremovexattr 198 +@@ -250,6 +252,7 @@ + #define __NR_recvmsg 47 + #define __NR_remap_file_pages 216 + #define __NR_removexattr 197 ++#define __NR_removexattrat 466 + #define __NR_rename 82 + #define __NR_renameat 264 + #define __NR_renameat2 316 +@@ -313,6 +316,7 @@ + #define __NR_settimeofday 164 + #define __NR_setuid 105 + #define __NR_setxattr 188 ++#define __NR_setxattrat 463 + #define __NR_shmat 30 + #define __NR_shmctl 31 + #define __NR_shmdt 67 +diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/arch-syscall.h b/sysdeps/unix/sysv/linux/x86_64/x32/arch-syscall.h +index 9340daa967425c4a..1dcd6ab0e6b229ed 100644 +--- a/sysdeps/unix/sysv/linux/x86_64/x32/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/x86_64/x32/arch-syscall.h +@@ -111,6 +111,7 @@ + #define __NR_gettimeofday 1073741920 + #define __NR_getuid 1073741926 + #define __NR_getxattr 1073742015 ++#define __NR_getxattrat 1073742288 + #define __NR_init_module 1073741999 + #define __NR_inotify_add_watch 1073742078 + #define __NR_inotify_init 1073742077 +@@ -145,6 +146,7 @@ + #define __NR_listen 1073741874 + #define __NR_listmount 1073742282 + #define __NR_listxattr 1073742018 ++#define __NR_listxattrat 1073742289 + #define __NR_llistxattr 1073742019 + #define __NR_lookup_dcookie 1073742036 + #define __NR_lremovexattr 1073742022 +@@ -242,6 +244,7 @@ + #define __NR_recvmsg 1073742343 + #define __NR_remap_file_pages 1073742040 + #define __NR_removexattr 1073742021 ++#define __NR_removexattrat 1073742290 + #define __NR_rename 1073741906 + #define __NR_renameat 1073742088 + #define __NR_renameat2 1073742140 +@@ -305,6 +308,7 @@ + #define __NR_settimeofday 1073741988 + #define __NR_setuid 1073741929 + #define __NR_setxattr 1073742012 ++#define __NR_setxattrat 1073742287 + #define __NR_shmat 1073741854 + #define __NR_shmctl 1073741855 + #define __NR_shmdt 1073741891 diff --git a/glibc-RHEL-107695-17.patch b/glibc-RHEL-107695-17.patch new file mode 100644 index 0000000..b763fdf --- /dev/null +++ b/glibc-RHEL-107695-17.patch @@ -0,0 +1,57 @@ +commit 2fb0009ff1994db2848fd2becd9e7eaaefd7b673 +Author: Joseph Myers +Date: Mon Mar 24 15:51:23 2025 +0000 + + Update kernel version to 6.13 in header constant tests + + There are no new constants covered by tst-mman-consts.py, + tst-mount-consts.py or tst-sched-consts.py in Linux 6.13 that need any + header changes, so update the kernel version in those tests. + (tst-pidfd-consts.py will need updating separately along with adding + new constants to glibc.) + + Tested with build-many-glibcs.py. + +diff --git a/sysdeps/unix/sysv/linux/tst-mman-consts.py b/sysdeps/unix/sysv/linux/tst-mman-consts.py +index 584936efecbf7755..ce07bc772e359ffd 100644 +--- a/sysdeps/unix/sysv/linux/tst-mman-consts.py ++++ b/sysdeps/unix/sysv/linux/tst-mman-consts.py +@@ -33,7 +33,7 @@ def main(): + help='C compiler (including options) to use') + args = parser.parse_args() + linux_version_headers = glibcsyscalls.linux_kernel_version(args.cc) +- linux_version_glibc = (6, 12) ++ linux_version_glibc = (6, 13) + sys.exit(glibcextract.compare_macro_consts( + '#define _GNU_SOURCE 1\n' + '#include \n', +diff --git a/sysdeps/unix/sysv/linux/tst-mount-consts.py b/sysdeps/unix/sysv/linux/tst-mount-consts.py +index e77579033b0fd8ec..91c99bb7a89715eb 100755 +--- a/sysdeps/unix/sysv/linux/tst-mount-consts.py ++++ b/sysdeps/unix/sysv/linux/tst-mount-consts.py +@@ -39,10 +39,10 @@ def main(): + sys.exit (77) + + linux_version_headers = glibcsyscalls.linux_kernel_version(args.cc) +- # Constants in glibc were updated to match Linux v6.12. When glibc ++ # Constants in glibc were updated to match Linux v6.13. When glibc + # constants are updated this value should be updated to match the + # released kernel version from which the constants were taken. +- linux_version_glibc = (6, 12) ++ linux_version_glibc = (6, 13) + def check(cte, exclude=None): + return glibcextract.compare_macro_consts( + '#include \n', +diff --git a/sysdeps/unix/sysv/linux/tst-sched-consts.py b/sysdeps/unix/sysv/linux/tst-sched-consts.py +index 6a5b837334ab45f8..90693f8156e338f1 100644 +--- a/sysdeps/unix/sysv/linux/tst-sched-consts.py ++++ b/sysdeps/unix/sysv/linux/tst-sched-consts.py +@@ -33,7 +33,7 @@ def main(): + help='C compiler (including options) to use') + args = parser.parse_args() + linux_version_headers = glibcsyscalls.linux_kernel_version(args.cc) +- linux_version_glibc = (6, 12) ++ linux_version_glibc = (6, 13) + sys.exit(glibcextract.compare_macro_consts( + '#define _GNU_SOURCE 1\n' + '#include \n', diff --git a/glibc-RHEL-107695-18.patch b/glibc-RHEL-107695-18.patch new file mode 100644 index 0000000..8a4fd97 --- /dev/null +++ b/glibc-RHEL-107695-18.patch @@ -0,0 +1,26 @@ +commit 7f163bd2106f96e2925e9bb3e0e545cfae7ba1af +Author: Joseph Myers +Date: Tue Apr 1 12:44:26 2025 +0000 + + Update syscall lists for Linux 6.14 + + Linux 6.14 has no new syscalls. Update the version number in + syscall-names.list to reflect that it is still current for 6.14. + + Tested with build-many-glibcs.py. + +diff --git a/sysdeps/unix/sysv/linux/syscall-names.list b/sysdeps/unix/sysv/linux/syscall-names.list +index a0c65be7a5c49160..28bd84404cf83692 100644 +--- a/sysdeps/unix/sysv/linux/syscall-names.list ++++ b/sysdeps/unix/sysv/linux/syscall-names.list +@@ -21,8 +21,8 @@ + # This file can list all potential system calls. The names are only + # used if the installed kernel headers also provide them. + +-# The list of system calls is current as of Linux 6.13. +-kernel 6.13 ++# The list of system calls is current as of Linux 6.14. ++kernel 6.14 + + FAST_atomic_update + FAST_cmpxchg diff --git a/glibc-RHEL-107695-19.patch b/glibc-RHEL-107695-19.patch new file mode 100644 index 0000000..6863f45 --- /dev/null +++ b/glibc-RHEL-107695-19.patch @@ -0,0 +1,337 @@ +commit eaf88c10250b917ba64c9d5567457c4b82558ed1 +Author: Joseph Myers +Date: Thu May 29 19:21:46 2025 +0000 + + Update syscall lists for Linux 6.15 + + Linux 6.15 adds the new syscall open_tree_attr. Update + syscall-names.list and regenerate the arch-syscall.h headers with + build-many-glibcs.py update-syscalls. + + Tested with build-many-glibcs.py. + + Reviewed-by: Florian Weimer + +diff --git a/sysdeps/unix/sysv/linux/aarch64/arch-syscall.h b/sysdeps/unix/sysv/linux/aarch64/arch-syscall.h +index 89aced0b453609e3..ba4a461e90ea1709 100644 +--- a/sysdeps/unix/sysv/linux/aarch64/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/aarch64/arch-syscall.h +@@ -175,6 +175,7 @@ + #define __NR_nfsservctl 42 + #define __NR_open_by_handle_at 265 + #define __NR_open_tree 428 ++#define __NR_open_tree_attr 467 + #define __NR_openat 56 + #define __NR_openat2 437 + #define __NR_perf_event_open 241 +diff --git a/sysdeps/unix/sysv/linux/alpha/arch-syscall.h b/sysdeps/unix/sysv/linux/alpha/arch-syscall.h +index 455da93b478ab037..840d6fed9eb0c3de 100644 +--- a/sysdeps/unix/sysv/linux/alpha/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/alpha/arch-syscall.h +@@ -209,6 +209,7 @@ + #define __NR_open 45 + #define __NR_open_by_handle_at 498 + #define __NR_open_tree 538 ++#define __NR_open_tree_attr 577 + #define __NR_openat 450 + #define __NR_openat2 547 + #define __NR_osf_adjtime 140 +diff --git a/sysdeps/unix/sysv/linux/arc/arch-syscall.h b/sysdeps/unix/sysv/linux/arc/arch-syscall.h +index 01075e8cdfd7cd30..2534f0fa5c50704c 100644 +--- a/sysdeps/unix/sysv/linux/arc/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/arc/arch-syscall.h +@@ -177,6 +177,7 @@ + #define __NR_nfsservctl 42 + #define __NR_open_by_handle_at 265 + #define __NR_open_tree 428 ++#define __NR_open_tree_attr 467 + #define __NR_openat 56 + #define __NR_openat2 437 + #define __NR_perf_event_open 241 +diff --git a/sysdeps/unix/sysv/linux/arm/arch-syscall.h b/sysdeps/unix/sysv/linux/arm/arch-syscall.h +index 97044727fc1e24bf..8e585a4f9ee07607 100644 +--- a/sysdeps/unix/sysv/linux/arm/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/arm/arch-syscall.h +@@ -223,6 +223,7 @@ + #define __NR_open 5 + #define __NR_open_by_handle_at 371 + #define __NR_open_tree 428 ++#define __NR_open_tree_attr 467 + #define __NR_openat 322 + #define __NR_openat2 437 + #define __NR_pause 29 +diff --git a/sysdeps/unix/sysv/linux/csky/arch-syscall.h b/sysdeps/unix/sysv/linux/csky/arch-syscall.h +index a719a55647383d4e..73fdba14025a0836 100644 +--- a/sysdeps/unix/sysv/linux/csky/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/csky/arch-syscall.h +@@ -184,6 +184,7 @@ + #define __NR_nfsservctl 42 + #define __NR_open_by_handle_at 265 + #define __NR_open_tree 428 ++#define __NR_open_tree_attr 467 + #define __NR_openat 56 + #define __NR_openat2 437 + #define __NR_perf_event_open 241 +diff --git a/sysdeps/unix/sysv/linux/hppa/arch-syscall.h b/sysdeps/unix/sysv/linux/hppa/arch-syscall.h +index dc592c58364a1804..d8ffab9b951bc261 100644 +--- a/sysdeps/unix/sysv/linux/hppa/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/hppa/arch-syscall.h +@@ -214,6 +214,7 @@ + #define __NR_open 5 + #define __NR_open_by_handle_at 326 + #define __NR_open_tree 428 ++#define __NR_open_tree_attr 467 + #define __NR_openat 275 + #define __NR_openat2 437 + #define __NR_pause 29 +diff --git a/sysdeps/unix/sysv/linux/i386/arch-syscall.h b/sysdeps/unix/sysv/linux/i386/arch-syscall.h +index c10897f7b032c9fb..196dfec840521678 100644 +--- a/sysdeps/unix/sysv/linux/i386/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/i386/arch-syscall.h +@@ -245,6 +245,7 @@ + #define __NR_open 5 + #define __NR_open_by_handle_at 342 + #define __NR_open_tree 428 ++#define __NR_open_tree_attr 467 + #define __NR_openat 295 + #define __NR_openat2 437 + #define __NR_pause 29 +diff --git a/sysdeps/unix/sysv/linux/loongarch/arch-syscall.h b/sysdeps/unix/sysv/linux/loongarch/arch-syscall.h +index a0d0d91a09fa57fb..9a0dc6e429a5bd4f 100644 +--- a/sysdeps/unix/sysv/linux/loongarch/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/loongarch/arch-syscall.h +@@ -173,6 +173,7 @@ + #define __NR_nfsservctl 42 + #define __NR_open_by_handle_at 265 + #define __NR_open_tree 428 ++#define __NR_open_tree_attr 467 + #define __NR_openat 56 + #define __NR_openat2 437 + #define __NR_perf_event_open 241 +diff --git a/sysdeps/unix/sysv/linux/m68k/arch-syscall.h b/sysdeps/unix/sysv/linux/m68k/arch-syscall.h +index 715809acaf112852..a95cb41f56db8deb 100644 +--- a/sysdeps/unix/sysv/linux/m68k/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/m68k/arch-syscall.h +@@ -234,6 +234,7 @@ + #define __NR_open 5 + #define __NR_open_by_handle_at 341 + #define __NR_open_tree 428 ++#define __NR_open_tree_attr 467 + #define __NR_openat 288 + #define __NR_openat2 437 + #define __NR_pause 29 +diff --git a/sysdeps/unix/sysv/linux/microblaze/arch-syscall.h b/sysdeps/unix/sysv/linux/microblaze/arch-syscall.h +index 24e218fc86b984cc..fe08f5cc9e898463 100644 +--- a/sysdeps/unix/sysv/linux/microblaze/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/microblaze/arch-syscall.h +@@ -244,6 +244,7 @@ + #define __NR_open 5 + #define __NR_open_by_handle_at 372 + #define __NR_open_tree 428 ++#define __NR_open_tree_attr 467 + #define __NR_openat 295 + #define __NR_openat2 437 + #define __NR_pause 29 +diff --git a/sysdeps/unix/sysv/linux/mips/mips32/arch-syscall.h b/sysdeps/unix/sysv/linux/mips/mips32/arch-syscall.h +index a7615cb7a0c66df6..7d76d6579d2e5a09 100644 +--- a/sysdeps/unix/sysv/linux/mips/mips32/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/mips/mips32/arch-syscall.h +@@ -229,6 +229,7 @@ + #define __NR_open 4005 + #define __NR_open_by_handle_at 4340 + #define __NR_open_tree 4428 ++#define __NR_open_tree_attr 4467 + #define __NR_openat 4288 + #define __NR_openat2 4437 + #define __NR_pause 4029 +diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/arch-syscall.h b/sysdeps/unix/sysv/linux/mips/mips64/n32/arch-syscall.h +index 4d863c2dd29c3f3e..bca3ea69b3e9db42 100644 +--- a/sysdeps/unix/sysv/linux/mips/mips64/n32/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/arch-syscall.h +@@ -212,6 +212,7 @@ + #define __NR_open 6002 + #define __NR_open_by_handle_at 6304 + #define __NR_open_tree 6428 ++#define __NR_open_tree_attr 6467 + #define __NR_openat 6251 + #define __NR_openat2 6437 + #define __NR_pause 6033 +diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/arch-syscall.h b/sysdeps/unix/sysv/linux/mips/mips64/n64/arch-syscall.h +index 9b6683e4c1ca9312..5bcd92982a7da06b 100644 +--- a/sysdeps/unix/sysv/linux/mips/mips64/n64/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/arch-syscall.h +@@ -201,6 +201,7 @@ + #define __NR_open 5002 + #define __NR_open_by_handle_at 5299 + #define __NR_open_tree 5428 ++#define __NR_open_tree_attr 5467 + #define __NR_openat 5247 + #define __NR_openat2 5437 + #define __NR_pause 5033 +diff --git a/sysdeps/unix/sysv/linux/or1k/arch-syscall.h b/sysdeps/unix/sysv/linux/or1k/arch-syscall.h +index a071c76aaf82d9b6..c2a1d51552b3e1d8 100644 +--- a/sysdeps/unix/sysv/linux/or1k/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/or1k/arch-syscall.h +@@ -183,6 +183,7 @@ + #define __NR_nfsservctl 42 + #define __NR_open_by_handle_at 265 + #define __NR_open_tree 428 ++#define __NR_open_tree_attr 467 + #define __NR_openat 56 + #define __NR_openat2 437 + #define __NR_or1k_atomic 244 +diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/arch-syscall.h b/sysdeps/unix/sysv/linux/powerpc/powerpc32/arch-syscall.h +index b3481e4c242257e0..c371df8e40d54b31 100644 +--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/arch-syscall.h +@@ -235,6 +235,7 @@ + #define __NR_open 5 + #define __NR_open_by_handle_at 346 + #define __NR_open_tree 428 ++#define __NR_open_tree_attr 467 + #define __NR_openat 286 + #define __NR_openat2 437 + #define __NR_pause 29 +diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/arch-syscall.h b/sysdeps/unix/sysv/linux/powerpc/powerpc64/arch-syscall.h +index 45108e8f6f5c7b6c..df8844d3cacfc3f1 100644 +--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/arch-syscall.h +@@ -220,6 +220,7 @@ + #define __NR_open 5 + #define __NR_open_by_handle_at 346 + #define __NR_open_tree 428 ++#define __NR_open_tree_attr 467 + #define __NR_openat 286 + #define __NR_openat2 437 + #define __NR_pause 29 +diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h b/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h +index 53338790a7a9837c..1bae763c9e2bae37 100644 +--- a/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h +@@ -168,6 +168,7 @@ + #define __NR_nfsservctl 42 + #define __NR_open_by_handle_at 265 + #define __NR_open_tree 428 ++#define __NR_open_tree_attr 467 + #define __NR_openat 56 + #define __NR_openat2 437 + #define __NR_perf_event_open 241 +diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h b/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h +index eed1dffc321200d8..1a1ebf8e2f6da6fd 100644 +--- a/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h +@@ -175,6 +175,7 @@ + #define __NR_nfsservctl 42 + #define __NR_open_by_handle_at 265 + #define __NR_open_tree 428 ++#define __NR_open_tree_attr 467 + #define __NR_openat 56 + #define __NR_openat2 437 + #define __NR_perf_event_open 241 +diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/arch-syscall.h b/sysdeps/unix/sysv/linux/s390/s390-32/arch-syscall.h +index 0bf8f9582cef0fab..f77f39f1cce2e6fe 100644 +--- a/sysdeps/unix/sysv/linux/s390/s390-32/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/s390/s390-32/arch-syscall.h +@@ -232,6 +232,7 @@ + #define __NR_open 5 + #define __NR_open_by_handle_at 336 + #define __NR_open_tree 428 ++#define __NR_open_tree_attr 467 + #define __NR_openat 288 + #define __NR_openat2 437 + #define __NR_pause 29 +diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/arch-syscall.h b/sysdeps/unix/sysv/linux/s390/s390-64/arch-syscall.h +index 061f8db0cab0d0e9..65d6644e33ccb468 100644 +--- a/sysdeps/unix/sysv/linux/s390/s390-64/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/s390/s390-64/arch-syscall.h +@@ -204,6 +204,7 @@ + #define __NR_open 5 + #define __NR_open_by_handle_at 336 + #define __NR_open_tree 428 ++#define __NR_open_tree_attr 467 + #define __NR_openat 288 + #define __NR_openat2 437 + #define __NR_pause 29 +diff --git a/sysdeps/unix/sysv/linux/sh/arch-syscall.h b/sysdeps/unix/sysv/linux/sh/arch-syscall.h +index 52cc320a9378e324..5948ab099a5f79d2 100644 +--- a/sysdeps/unix/sysv/linux/sh/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/sh/arch-syscall.h +@@ -228,6 +228,7 @@ + #define __NR_open 5 + #define __NR_open_by_handle_at 360 + #define __NR_open_tree 428 ++#define __NR_open_tree_attr 467 + #define __NR_openat 295 + #define __NR_openat2 437 + #define __NR_pause 29 +diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/arch-syscall.h b/sysdeps/unix/sysv/linux/sparc/sparc32/arch-syscall.h +index ee870bc7b890e0b6..85828a8c1750a6ec 100644 +--- a/sysdeps/unix/sysv/linux/sparc/sparc32/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/sparc/sparc32/arch-syscall.h +@@ -230,6 +230,7 @@ + #define __NR_open 5 + #define __NR_open_by_handle_at 333 + #define __NR_open_tree 428 ++#define __NR_open_tree_attr 467 + #define __NR_openat 284 + #define __NR_openat2 437 + #define __NR_pause 29 +diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/arch-syscall.h b/sysdeps/unix/sysv/linux/sparc/sparc64/arch-syscall.h +index 3acbebefa95fbbc6..d83ecd15dca15268 100644 +--- a/sysdeps/unix/sysv/linux/sparc/sparc64/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/sparc/sparc64/arch-syscall.h +@@ -211,6 +211,7 @@ + #define __NR_open 5 + #define __NR_open_by_handle_at 333 + #define __NR_open_tree 428 ++#define __NR_open_tree_attr 467 + #define __NR_openat 284 + #define __NR_openat2 437 + #define __NR_pause 29 +diff --git a/sysdeps/unix/sysv/linux/syscall-names.list b/sysdeps/unix/sysv/linux/syscall-names.list +index 28bd84404cf83692..316f06695a6b378c 100644 +--- a/sysdeps/unix/sysv/linux/syscall-names.list ++++ b/sysdeps/unix/sysv/linux/syscall-names.list +@@ -21,8 +21,8 @@ + # This file can list all potential system calls. The names are only + # used if the installed kernel headers also provide them. + +-# The list of system calls is current as of Linux 6.14. +-kernel 6.14 ++# The list of system calls is current as of Linux 6.15. ++kernel 6.15 + + FAST_atomic_update + FAST_cmpxchg +@@ -316,6 +316,7 @@ olduname + open + open_by_handle_at + open_tree ++open_tree_attr + openat + openat2 + or1k_atomic +diff --git a/sysdeps/unix/sysv/linux/x86_64/64/arch-syscall.h b/sysdeps/unix/sysv/linux/x86_64/64/arch-syscall.h +index 17b84c70f58ac276..06fbae5334dbbd49 100644 +--- a/sysdeps/unix/sysv/linux/x86_64/64/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/x86_64/64/arch-syscall.h +@@ -207,6 +207,7 @@ + #define __NR_open 2 + #define __NR_open_by_handle_at 304 + #define __NR_open_tree 428 ++#define __NR_open_tree_attr 467 + #define __NR_openat 257 + #define __NR_openat2 437 + #define __NR_pause 34 +diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/arch-syscall.h b/sysdeps/unix/sysv/linux/x86_64/x32/arch-syscall.h +index 1dcd6ab0e6b229ed..135ef3d7f28f50f3 100644 +--- a/sysdeps/unix/sysv/linux/x86_64/x32/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/x86_64/x32/arch-syscall.h +@@ -200,6 +200,7 @@ + #define __NR_open 1073741826 + #define __NR_open_by_handle_at 1073742128 + #define __NR_open_tree 1073742252 ++#define __NR_open_tree_attr 1073742291 + #define __NR_openat 1073742081 + #define __NR_openat2 1073742261 + #define __NR_pause 1073741858 diff --git a/glibc-RHEL-107695-2.patch b/glibc-RHEL-107695-2.patch new file mode 100644 index 0000000..c5668ab --- /dev/null +++ b/glibc-RHEL-107695-2.patch @@ -0,0 +1,56 @@ +commit 2367bf468ce43801de987dcd54b0f99ba9d62827 +Author: Joseph Myers +Date: Wed Mar 13 19:46:21 2024 +0000 + + Update kernel version to 6.8 in header constant tests + + This patch updates the kernel version in the tests tst-mman-consts.py, + tst-mount-consts.py and tst-pidfd-consts.py to 6.8. (There are no new + constants covered by these tests in 6.8 that need any other header + changes.) + + Tested with build-many-glibcs.py. + +diff --git a/sysdeps/unix/sysv/linux/tst-mman-consts.py b/sysdeps/unix/sysv/linux/tst-mman-consts.py +index a7e101532812cbd0..56c0cf3e228ad1ae 100644 +--- a/sysdeps/unix/sysv/linux/tst-mman-consts.py ++++ b/sysdeps/unix/sysv/linux/tst-mman-consts.py +@@ -33,7 +33,7 @@ def main(): + help='C compiler (including options) to use') + args = parser.parse_args() + linux_version_headers = glibcsyscalls.linux_kernel_version(args.cc) +- linux_version_glibc = (6, 7) ++ linux_version_glibc = (6, 8) + sys.exit(glibcextract.compare_macro_consts( + '#define _GNU_SOURCE 1\n' + '#include \n', +diff --git a/sysdeps/unix/sysv/linux/tst-mount-consts.py b/sysdeps/unix/sysv/linux/tst-mount-consts.py +index 175bd8d23a7f9826..8613db96d7e3bf33 100755 +--- a/sysdeps/unix/sysv/linux/tst-mount-consts.py ++++ b/sysdeps/unix/sysv/linux/tst-mount-consts.py +@@ -39,10 +39,10 @@ def main(): + sys.exit (77) + + linux_version_headers = glibcsyscalls.linux_kernel_version(args.cc) +- # Constants in glibc were updated to match Linux v6.7. When glibc ++ # Constants in glibc were updated to match Linux v6.8. When glibc + # constants are updated this value should be updated to match the + # released kernel version from which the constants were taken. +- linux_version_glibc = (6, 7) ++ linux_version_glibc = (6, 8) + def check(cte, exclude=None): + return glibcextract.compare_macro_consts( + '#include \n', +diff --git a/sysdeps/unix/sysv/linux/tst-pidfd-consts.py b/sysdeps/unix/sysv/linux/tst-pidfd-consts.py +index 2f877722ad3f8d64..96875ac2666575df 100644 +--- a/sysdeps/unix/sysv/linux/tst-pidfd-consts.py ++++ b/sysdeps/unix/sysv/linux/tst-pidfd-consts.py +@@ -39,7 +39,7 @@ def main(): + sys.exit (77) + + linux_version_headers = glibcsyscalls.linux_kernel_version(args.cc) +- linux_version_glibc = (6, 7) ++ linux_version_glibc = (6, 8) + sys.exit(glibcextract.compare_macro_consts( + '#include \n', + '#include \n' diff --git a/glibc-RHEL-107695-3.patch b/glibc-RHEL-107695-3.patch new file mode 100644 index 0000000..f799f2f --- /dev/null +++ b/glibc-RHEL-107695-3.patch @@ -0,0 +1,26 @@ +commit cf0ca8d52e1653d4aa4311a4649af8dc541ce6b4 +Author: Joseph Myers +Date: Mon May 20 13:10:31 2024 +0000 + + Update syscall lists for Linux 6.9 + + Linux 6.9 has no new syscalls. Update the version number in + syscall-names.list to reflect that it is still current for 6.9. + + Tested with build-many-glibcs.py. + +diff --git a/sysdeps/unix/sysv/linux/syscall-names.list b/sysdeps/unix/sysv/linux/syscall-names.list +index 6557bcfde4636158..672d39eaad4491f1 100644 +--- a/sysdeps/unix/sysv/linux/syscall-names.list ++++ b/sysdeps/unix/sysv/linux/syscall-names.list +@@ -21,8 +21,8 @@ + # This file can list all potential system calls. The names are only + # used if the installed kernel headers also provide them. + +-# The list of system calls is current as of Linux 6.8. +-kernel 6.8 ++# The list of system calls is current as of Linux 6.9. ++kernel 6.9 + + FAST_atomic_update + FAST_cmpxchg diff --git a/glibc-RHEL-107695-4.patch b/glibc-RHEL-107695-4.patch new file mode 100644 index 0000000..86a7a48 --- /dev/null +++ b/glibc-RHEL-107695-4.patch @@ -0,0 +1,60 @@ +commit e9a37242f9cca80496aa934158b7e366b8b419fa +Author: Joseph Myers +Date: Thu May 23 12:22:40 2024 +0000 + + Update PIDFD_* constants for Linux 6.9 + + Linux 6.9 adds some more PIDFD_* constants. Add them to glibc's + sys/pidfd.h, including updating comments that said FLAGS was reserved + and must be 0, along with updating tst-pidfd-consts.py. + + Tested with build-many-glibcs.py. + +diff --git a/sysdeps/unix/sysv/linux/sys/pidfd.h b/sysdeps/unix/sysv/linux/sys/pidfd.h +index 10783220625f7a1d..9f88d297e884c348 100644 +--- a/sysdeps/unix/sysv/linux/sys/pidfd.h ++++ b/sysdeps/unix/sysv/linux/sys/pidfd.h +@@ -22,12 +22,14 @@ + #include + + #define PIDFD_NONBLOCK O_NONBLOCK ++#define PIDFD_THREAD O_EXCL + +-/* Returns a file descriptor that refers to the process PID. The +- close-on-exec is set on the file descriptor. ++#define PIDFD_SIGNAL_THREAD (1UL << 0) ++#define PIDFD_SIGNAL_THREAD_GROUP (1UL << 1) ++#define PIDFD_SIGNAL_PROCESS_GROUP (1UL << 2) + +- The FLAGS argument is reserved for future use, it must be specified +- as 0. */ ++/* Returns a file descriptor that refers to the process PID. The ++ close-on-exec is set on the file descriptor. */ + extern int pidfd_open (__pid_t __pid, unsigned int __flags) __THROW; + + /* Duplicates an existing file descriptor TARGETFD in the process referred +@@ -39,10 +41,7 @@ extern int pidfd_getfd (int __pidfd, int __targetfd, + unsigned int __flags) __THROW; + + /* Sends the signal SIG to the target process referred by the PIDFD. If +- INFO points to a siginfo_t buffer, it will be populated. +- +- The FLAGS argument is reserved for future use, it must be specified +- as 0. */ ++ INFO points to a siginfo_t buffer, it will be populated. */ + extern int pidfd_send_signal (int __pidfd, int __sig, siginfo_t *__info, + unsigned int __flags) __THROW; + +diff --git a/sysdeps/unix/sysv/linux/tst-pidfd-consts.py b/sysdeps/unix/sysv/linux/tst-pidfd-consts.py +index 96875ac2666575df..6f05291949d00c62 100644 +--- a/sysdeps/unix/sysv/linux/tst-pidfd-consts.py ++++ b/sysdeps/unix/sysv/linux/tst-pidfd-consts.py +@@ -39,7 +39,7 @@ def main(): + sys.exit (77) + + linux_version_headers = glibcsyscalls.linux_kernel_version(args.cc) +- linux_version_glibc = (6, 8) ++ linux_version_glibc = (6, 9) + sys.exit(glibcextract.compare_macro_consts( + '#include \n', + '#include \n' diff --git a/glibc-RHEL-107695-5.patch b/glibc-RHEL-107695-5.patch new file mode 100644 index 0000000..3a715a6 --- /dev/null +++ b/glibc-RHEL-107695-5.patch @@ -0,0 +1,44 @@ +commit 84d2762922f74f5059d6179f503972c418153b91 +Author: Joseph Myers +Date: Thu May 23 14:04:48 2024 +0000 + + Update kernel version to 6.9 in header constant tests + + This patch updates the kernel version in the tests tst-mman-consts.py + and tst-mount-consts.py to 6.9. (There are no new constants covered + by these tests in 6.9 that need any other header changes; + tst-pidfd-consts.py was updated separately along with adding new + constants relevant to that test.) + + Tested with build-many-glibcs.py. + +diff --git a/sysdeps/unix/sysv/linux/tst-mman-consts.py b/sysdeps/unix/sysv/linux/tst-mman-consts.py +index 56c0cf3e228ad1ae..4a8f4e8919aa6b3d 100644 +--- a/sysdeps/unix/sysv/linux/tst-mman-consts.py ++++ b/sysdeps/unix/sysv/linux/tst-mman-consts.py +@@ -33,7 +33,7 @@ def main(): + help='C compiler (including options) to use') + args = parser.parse_args() + linux_version_headers = glibcsyscalls.linux_kernel_version(args.cc) +- linux_version_glibc = (6, 8) ++ linux_version_glibc = (6, 9) + sys.exit(glibcextract.compare_macro_consts( + '#define _GNU_SOURCE 1\n' + '#include \n', +diff --git a/sysdeps/unix/sysv/linux/tst-mount-consts.py b/sysdeps/unix/sysv/linux/tst-mount-consts.py +index 8613db96d7e3bf33..c4a67221c1c5bc84 100755 +--- a/sysdeps/unix/sysv/linux/tst-mount-consts.py ++++ b/sysdeps/unix/sysv/linux/tst-mount-consts.py +@@ -39,10 +39,10 @@ def main(): + sys.exit (77) + + linux_version_headers = glibcsyscalls.linux_kernel_version(args.cc) +- # Constants in glibc were updated to match Linux v6.8. When glibc ++ # Constants in glibc were updated to match Linux v6.9. When glibc + # constants are updated this value should be updated to match the + # released kernel version from which the constants were taken. +- linux_version_glibc = (6, 8) ++ linux_version_glibc = (6, 9) + def check(cte, exclude=None): + return glibcextract.compare_macro_consts( + '#include \n', diff --git a/glibc-RHEL-107695-6.patch b/glibc-RHEL-107695-6.patch new file mode 100644 index 0000000..b30572d --- /dev/null +++ b/glibc-RHEL-107695-6.patch @@ -0,0 +1,120 @@ +commit 176671f6042912200ea9733bb6cc8212e06bc85e +Author: Carlos Llamas +Date: Tue Jun 18 10:56:34 2024 +0200 + + linux: add definitions for hugetlb page size encodings + + A desired hugetlb page size can be encoded in the flags parameter of + system calls such as mmap() and shmget(). The Linux UAPI headers have + included explicit definitions for these encodings since v4.14. + + This patch adds these definitions that are used along with MAP_HUGETLB + and SHM_HUGETLB flags as specified in the corresponding man pages. This + relieves programs from having to duplicate and/or compute the encodings + manually. + + Additionally, the filter on these definitions in tst-mman-consts.py is + removed, as suggested by Florian. I then ran this tests successfully, + confirming the alignment with the kernel headers. + + PASS: misc/tst-mman-consts + original exit status 0 + + Signed-off-by: Carlos Llamas + Tested-by: Florian Weimer + Reviewed-by: Florian Weimer + +diff --git a/sysdeps/unix/sysv/linux/bits/mman-linux.h b/sysdeps/unix/sysv/linux/bits/mman-linux.h +index 5c3d43b0f2b659fd..522333c50a04481d 100644 +--- a/sysdeps/unix/sysv/linux/bits/mman-linux.h ++++ b/sysdeps/unix/sysv/linux/bits/mman-linux.h +@@ -54,10 +54,29 @@ + # define MAP_ANONYMOUS 0x20 /* Don't use a file. */ + #endif + #define MAP_ANON MAP_ANONYMOUS +-/* When MAP_HUGETLB is set bits [26:31] encode the log2 of the huge page size. */ ++ ++/* When MAP_HUGETLB is set, bits [26:31] encode the log2 of the huge page size. ++ The following definitions are associated with this huge page size encoding. ++ It is responsibility of the application to know which sizes are supported on ++ the running system. See mmap(2) man page for details. */ ++ + #define MAP_HUGE_SHIFT 26 + #define MAP_HUGE_MASK 0x3f + ++#define MAP_HUGE_16KB (14 << MAP_HUGE_SHIFT) ++#define MAP_HUGE_64KB (16 << MAP_HUGE_SHIFT) ++#define MAP_HUGE_512KB (19 << MAP_HUGE_SHIFT) ++#define MAP_HUGE_1MB (20 << MAP_HUGE_SHIFT) ++#define MAP_HUGE_2MB (21 << MAP_HUGE_SHIFT) ++#define MAP_HUGE_8MB (23 << MAP_HUGE_SHIFT) ++#define MAP_HUGE_16MB (24 << MAP_HUGE_SHIFT) ++#define MAP_HUGE_32MB (25 << MAP_HUGE_SHIFT) ++#define MAP_HUGE_256MB (28 << MAP_HUGE_SHIFT) ++#define MAP_HUGE_512MB (29 << MAP_HUGE_SHIFT) ++#define MAP_HUGE_1GB (30 << MAP_HUGE_SHIFT) ++#define MAP_HUGE_2GB (31 << MAP_HUGE_SHIFT) ++#define MAP_HUGE_16GB (34U << MAP_HUGE_SHIFT) ++ + /* Flags to `msync'. */ + #define MS_ASYNC 1 /* Sync memory asynchronously. */ + #define MS_SYNC 4 /* Synchronous memory sync. */ +diff --git a/sysdeps/unix/sysv/linux/bits/shm.h b/sysdeps/unix/sysv/linux/bits/shm.h +index 95f7863913ecebdb..76144f5ad4e52c21 100644 +--- a/sysdeps/unix/sysv/linux/bits/shm.h ++++ b/sysdeps/unix/sysv/linux/bits/shm.h +@@ -58,6 +58,28 @@ typedef __syscall_ulong_t shmatt_t; + # define SHM_HUGETLB 04000 /* segment is mapped via hugetlb */ + # define SHM_NORESERVE 010000 /* don't check for reservations */ + ++/* When SHM_HUGETLB is set, bits [26:31] encode the log2 of the huge page size. ++ The following definitions are associated with this huge page size encoding. ++ It is responsibility of the application to know which sizes are supported on ++ the running system. See shmget(2) man page for details. */ ++ ++#define SHM_HUGE_SHIFT 26 ++#define SHM_HUGE_MASK 0x3f ++ ++#define SHM_HUGE_16KB (14 << SHM_HUGE_SHIFT) ++#define SHM_HUGE_64KB (16 << SHM_HUGE_SHIFT) ++#define SHM_HUGE_512KB (19 << SHM_HUGE_SHIFT) ++#define SHM_HUGE_1MB (20 << SHM_HUGE_SHIFT) ++#define SHM_HUGE_2MB (21 << SHM_HUGE_SHIFT) ++#define SHM_HUGE_8MB (23 << SHM_HUGE_SHIFT) ++#define SHM_HUGE_16MB (24 << SHM_HUGE_SHIFT) ++#define SHM_HUGE_32MB (25 << SHM_HUGE_SHIFT) ++#define SHM_HUGE_256MB (28 << SHM_HUGE_SHIFT) ++#define SHM_HUGE_512MB (29 << SHM_HUGE_SHIFT) ++#define SHM_HUGE_1GB (30 << SHM_HUGE_SHIFT) ++#define SHM_HUGE_2GB (31 << SHM_HUGE_SHIFT) ++#define SHM_HUGE_16GB (34U << SHM_HUGE_SHIFT) ++ + struct shminfo + { + __syscall_ulong_t shmmax; +diff --git a/sysdeps/unix/sysv/linux/tst-mman-consts.py b/sysdeps/unix/sysv/linux/tst-mman-consts.py +index 4a8f4e8919aa6b3d..441261c9456b2595 100644 +--- a/sysdeps/unix/sysv/linux/tst-mman-consts.py ++++ b/sysdeps/unix/sysv/linux/tst-mman-consts.py +@@ -41,8 +41,7 @@ def main(): + '#include \n', + args.cc, + 'MAP_.*', +- # A series of MAP_HUGE_ macros are defined by the kernel +- # but not by glibc. MAP_UNINITIALIZED is kernel-only. ++ # MAP_UNINITIALIZED is defined by the kernel but not by glibc. + # MAP_FAILED is not a MAP_* flag and is glibc-only, as is the + # MAP_ANON alias for MAP_ANONYMOUS. MAP_RENAME, MAP_AUTOGROW, + # MAP_LOCAL and MAP_AUTORSRV are in the kernel header for +@@ -50,9 +49,8 @@ def main(): + # in the kernel header, but does not use it. The kernel + # header for HPPA removed a define of MAP_VARIABLE to 0 in + # Linux 6.2. +- 'MAP_HUGE_[0-9].*|MAP_UNINITIALIZED|MAP_FAILED|MAP_ANON' +- '|MAP_RENAME|MAP_AUTOGROW|MAP_LOCAL|MAP_AUTORSRV|MAP_INHERIT' +- '|MAP_VARIABLE', ++ 'MAP_UNINITIALIZED|MAP_FAILED|MAP_ANON|MAP_RENAME|MAP_AUTOGROW' ++ '|MAP_LOCAL|MAP_AUTORSRV|MAP_INHERIT|MAP_VARIABLE', + linux_version_glibc > linux_version_headers, + linux_version_headers > linux_version_glibc)) + diff --git a/glibc-RHEL-107695-7.patch b/glibc-RHEL-107695-7.patch new file mode 100644 index 0000000..b797630 --- /dev/null +++ b/glibc-RHEL-107695-7.patch @@ -0,0 +1,379 @@ +commit eb0776d4e149ff0ccf9841a8073dbde658c59858 +Author: Adhemerval Zanella +Date: Tue Jul 16 17:08:46 2024 +0000 + + Update syscall lists for Linux 6.10 + + Linux 6.10 changes for syscall are: + + * mseal for all architectures. + * map_shadow_stack for x32. + * Replace sync_file_range with sync_file_range2 for csky (which + fixes a broken sync_file_range usage). + + Update syscall-names.list and regenerate the arch-syscall.h headers + with build-many-glibcs.py update-syscalls. + + Tested with build-many-glibcs.py. + Reviewed-by: Florian Weimer + +diff --git a/sysdeps/unix/sysv/linux/aarch64/arch-syscall.h b/sysdeps/unix/sysv/linux/aarch64/arch-syscall.h +index 7ee8a2167aaae172..19b6316cb6ffae26 100644 +--- a/sysdeps/unix/sysv/linux/aarch64/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/aarch64/arch-syscall.h +@@ -158,6 +158,7 @@ + #define __NR_mq_timedsend 182 + #define __NR_mq_unlink 181 + #define __NR_mremap 216 ++#define __NR_mseal 462 + #define __NR_msgctl 187 + #define __NR_msgget 186 + #define __NR_msgrcv 188 +diff --git a/sysdeps/unix/sysv/linux/alpha/arch-syscall.h b/sysdeps/unix/sysv/linux/alpha/arch-syscall.h +index 0f4ea7670be610be..216a5575c69d0ff3 100644 +--- a/sysdeps/unix/sysv/linux/alpha/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/alpha/arch-syscall.h +@@ -24,6 +24,7 @@ + #define __NR_clock_nanosleep 422 + #define __NR_clock_settime 419 + #define __NR_clone 312 ++#define __NR_clone3 545 + #define __NR_close 6 + #define __NR_close_range 546 + #define __NR_connect 98 +@@ -189,6 +190,7 @@ + #define __NR_mq_timedsend 434 + #define __NR_mq_unlink 433 + #define __NR_mremap 341 ++#define __NR_mseal 572 + #define __NR_msgctl 200 + #define __NR_msgget 201 + #define __NR_msgrcv 202 +diff --git a/sysdeps/unix/sysv/linux/arc/arch-syscall.h b/sysdeps/unix/sysv/linux/arc/arch-syscall.h +index 90359482a814b3f8..ea581b0a6dc0f2d4 100644 +--- a/sysdeps/unix/sysv/linux/arc/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/arc/arch-syscall.h +@@ -161,6 +161,7 @@ + #define __NR_mq_timedsend_time64 418 + #define __NR_mq_unlink 181 + #define __NR_mremap 216 ++#define __NR_mseal 462 + #define __NR_msgctl 187 + #define __NR_msgget 186 + #define __NR_msgrcv 188 +diff --git a/sysdeps/unix/sysv/linux/arm/arch-syscall.h b/sysdeps/unix/sysv/linux/arm/arch-syscall.h +index 4930167a03c97df2..2809f52f94e9ee16 100644 +--- a/sysdeps/unix/sysv/linux/arm/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/arm/arch-syscall.h +@@ -205,6 +205,7 @@ + #define __NR_mq_timedsend_time64 418 + #define __NR_mq_unlink 275 + #define __NR_mremap 163 ++#define __NR_mseal 462 + #define __NR_msgctl 304 + #define __NR_msgget 303 + #define __NR_msgrcv 302 +diff --git a/sysdeps/unix/sysv/linux/csky/arch-syscall.h b/sysdeps/unix/sysv/linux/csky/arch-syscall.h +index 3f16a29f5753e7a8..ede3551a00dc81c6 100644 +--- a/sysdeps/unix/sysv/linux/csky/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/csky/arch-syscall.h +@@ -168,6 +168,7 @@ + #define __NR_mq_timedsend_time64 418 + #define __NR_mq_unlink 181 + #define __NR_mremap 216 ++#define __NR_mseal 462 + #define __NR_msgctl 187 + #define __NR_msgget 186 + #define __NR_msgrcv 188 +@@ -301,7 +302,7 @@ + #define __NR_swapon 224 + #define __NR_symlinkat 36 + #define __NR_sync 81 +-#define __NR_sync_file_range 84 ++#define __NR_sync_file_range2 84 + #define __NR_syncfs 267 + #define __NR_sysinfo 179 + #define __NR_syslog 116 +diff --git a/sysdeps/unix/sysv/linux/hppa/arch-syscall.h b/sysdeps/unix/sysv/linux/hppa/arch-syscall.h +index a1b2c819d6522018..08b153f2ccdf6f45 100644 +--- a/sysdeps/unix/sysv/linux/hppa/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/hppa/arch-syscall.h +@@ -197,6 +197,7 @@ + #define __NR_mq_timedsend_time64 418 + #define __NR_mq_unlink 230 + #define __NR_mremap 163 ++#define __NR_mseal 462 + #define __NR_msgctl 191 + #define __NR_msgget 190 + #define __NR_msgrcv 189 +diff --git a/sysdeps/unix/sysv/linux/i386/arch-syscall.h b/sysdeps/unix/sysv/linux/i386/arch-syscall.h +index cc775432d663a745..500ca1ec70e2c5fc 100644 +--- a/sysdeps/unix/sysv/linux/i386/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/i386/arch-syscall.h +@@ -222,6 +222,7 @@ + #define __NR_mq_timedsend_time64 418 + #define __NR_mq_unlink 278 + #define __NR_mremap 163 ++#define __NR_mseal 462 + #define __NR_msgctl 402 + #define __NR_msgget 399 + #define __NR_msgrcv 401 +diff --git a/sysdeps/unix/sysv/linux/loongarch/arch-syscall.h b/sysdeps/unix/sysv/linux/loongarch/arch-syscall.h +index 56bb08718ad32c04..8bb82448a7570d54 100644 +--- a/sysdeps/unix/sysv/linux/loongarch/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/loongarch/arch-syscall.h +@@ -155,6 +155,7 @@ + #define __NR_mq_timedsend 182 + #define __NR_mq_unlink 181 + #define __NR_mremap 216 ++#define __NR_mseal 462 + #define __NR_msgctl 187 + #define __NR_msgget 186 + #define __NR_msgrcv 188 +diff --git a/sysdeps/unix/sysv/linux/m68k/arch-syscall.h b/sysdeps/unix/sysv/linux/m68k/arch-syscall.h +index 79f277dd5b8eda7b..4ab34f6228594c9f 100644 +--- a/sysdeps/unix/sysv/linux/m68k/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/m68k/arch-syscall.h +@@ -213,6 +213,7 @@ + #define __NR_mq_timedsend_time64 418 + #define __NR_mq_unlink 272 + #define __NR_mremap 163 ++#define __NR_mseal 462 + #define __NR_msgctl 402 + #define __NR_msgget 399 + #define __NR_msgrcv 401 +diff --git a/sysdeps/unix/sysv/linux/microblaze/arch-syscall.h b/sysdeps/unix/sysv/linux/microblaze/arch-syscall.h +index 779d5d5d7029d8ff..79e225e50c6d30b4 100644 +--- a/sysdeps/unix/sysv/linux/microblaze/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/microblaze/arch-syscall.h +@@ -221,6 +221,7 @@ + #define __NR_mq_timedsend_time64 418 + #define __NR_mq_unlink 278 + #define __NR_mremap 163 ++#define __NR_mseal 462 + #define __NR_msgctl 331 + #define __NR_msgget 332 + #define __NR_msgrcv 333 +diff --git a/sysdeps/unix/sysv/linux/mips/mips32/arch-syscall.h b/sysdeps/unix/sysv/linux/mips/mips32/arch-syscall.h +index 86ffd5ce84556c20..dadd7f3130a55625 100644 +--- a/sysdeps/unix/sysv/linux/mips/mips32/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/mips/mips32/arch-syscall.h +@@ -211,6 +211,7 @@ + #define __NR_mq_timedsend_time64 4418 + #define __NR_mq_unlink 4272 + #define __NR_mremap 4167 ++#define __NR_mseal 4462 + #define __NR_msgctl 4402 + #define __NR_msgget 4399 + #define __NR_msgrcv 4401 +diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/arch-syscall.h b/sysdeps/unix/sysv/linux/mips/mips64/n32/arch-syscall.h +index 5d37a686e511a499..db6b2d4609d87d3e 100644 +--- a/sysdeps/unix/sysv/linux/mips/mips64/n32/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/arch-syscall.h +@@ -194,6 +194,7 @@ + #define __NR_mq_timedsend_time64 6418 + #define __NR_mq_unlink 6235 + #define __NR_mremap 6024 ++#define __NR_mseal 6462 + #define __NR_msgctl 6069 + #define __NR_msgget 6066 + #define __NR_msgrcv 6068 +diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/arch-syscall.h b/sysdeps/unix/sysv/linux/mips/mips64/n64/arch-syscall.h +index 9b1e846e7646d791..b4129a4dbdf71aec 100644 +--- a/sysdeps/unix/sysv/linux/mips/mips64/n64/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/arch-syscall.h +@@ -183,6 +183,7 @@ + #define __NR_mq_timedsend 5232 + #define __NR_mq_unlink 5231 + #define __NR_mremap 5024 ++#define __NR_mseal 5462 + #define __NR_msgctl 5069 + #define __NR_msgget 5066 + #define __NR_msgrcv 5068 +diff --git a/sysdeps/unix/sysv/linux/nios2/arch-syscall.h b/sysdeps/unix/sysv/linux/nios2/arch-syscall.h +index abbc9ab6b083be80..f94e212995549062 100644 +--- a/sysdeps/unix/sysv/linux/nios2/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/nios2/arch-syscall.h +@@ -167,6 +167,7 @@ + #define __NR_mq_timedsend_time64 418 + #define __NR_mq_unlink 181 + #define __NR_mremap 216 ++#define __NR_mseal 462 + #define __NR_msgctl 187 + #define __NR_msgget 186 + #define __NR_msgrcv 188 +diff --git a/sysdeps/unix/sysv/linux/or1k/arch-syscall.h b/sysdeps/unix/sysv/linux/or1k/arch-syscall.h +index 7223a93673d9c6f7..2d21fa208576f795 100644 +--- a/sysdeps/unix/sysv/linux/or1k/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/or1k/arch-syscall.h +@@ -167,6 +167,7 @@ + #define __NR_mq_timedsend_time64 418 + #define __NR_mq_unlink 181 + #define __NR_mremap 216 ++#define __NR_mseal 462 + #define __NR_msgctl 187 + #define __NR_msgget 186 + #define __NR_msgrcv 188 +diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/arch-syscall.h b/sysdeps/unix/sysv/linux/powerpc/powerpc32/arch-syscall.h +index af0d2b121ebc7dc7..206d9fd65697d152 100644 +--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/arch-syscall.h +@@ -211,6 +211,7 @@ + #define __NR_mq_timedsend_time64 418 + #define __NR_mq_unlink 263 + #define __NR_mremap 163 ++#define __NR_mseal 462 + #define __NR_msgctl 402 + #define __NR_msgget 399 + #define __NR_msgrcv 401 +diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/arch-syscall.h b/sysdeps/unix/sysv/linux/powerpc/powerpc64/arch-syscall.h +index a4c70aa7fe719cb9..19f72a7f694a5322 100644 +--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/arch-syscall.h +@@ -195,6 +195,7 @@ + #define __NR_mq_timedsend 264 + #define __NR_mq_unlink 263 + #define __NR_mremap 163 ++#define __NR_mseal 462 + #define __NR_msgctl 402 + #define __NR_msgget 399 + #define __NR_msgrcv 401 +diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h b/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h +index 7315d164d64c89fa..eb9e57b02898cb79 100644 +--- a/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h +@@ -153,6 +153,7 @@ + #define __NR_mq_timedsend_time64 418 + #define __NR_mq_unlink 181 + #define __NR_mremap 216 ++#define __NR_mseal 462 + #define __NR_msgctl 187 + #define __NR_msgget 186 + #define __NR_msgrcv 188 +diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h b/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h +index 31a1130db9404e60..1eac18e5822d8b3e 100644 +--- a/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h +@@ -158,6 +158,7 @@ + #define __NR_mq_timedsend 182 + #define __NR_mq_unlink 181 + #define __NR_mremap 216 ++#define __NR_mseal 462 + #define __NR_msgctl 187 + #define __NR_msgget 186 + #define __NR_msgrcv 188 +diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/arch-syscall.h b/sysdeps/unix/sysv/linux/s390/s390-32/arch-syscall.h +index cf8569304d9e6a16..464eca58b28ef5e0 100644 +--- a/sysdeps/unix/sysv/linux/s390/s390-32/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/s390/s390-32/arch-syscall.h +@@ -214,6 +214,7 @@ + #define __NR_mq_timedsend_time64 418 + #define __NR_mq_unlink 272 + #define __NR_mremap 163 ++#define __NR_mseal 462 + #define __NR_msgctl 402 + #define __NR_msgget 399 + #define __NR_msgrcv 401 +diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/arch-syscall.h b/sysdeps/unix/sysv/linux/s390/s390-64/arch-syscall.h +index f3536ed03f4b7d85..57842702fd389edd 100644 +--- a/sysdeps/unix/sysv/linux/s390/s390-64/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/s390/s390-64/arch-syscall.h +@@ -185,6 +185,7 @@ + #define __NR_mq_timedsend 273 + #define __NR_mq_unlink 272 + #define __NR_mremap 163 ++#define __NR_mseal 462 + #define __NR_msgctl 402 + #define __NR_msgget 399 + #define __NR_msgrcv 401 +diff --git a/sysdeps/unix/sysv/linux/sh/arch-syscall.h b/sysdeps/unix/sysv/linux/sh/arch-syscall.h +index 0c88bf10c77bef3a..165ba017c7411aef 100644 +--- a/sysdeps/unix/sysv/linux/sh/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/sh/arch-syscall.h +@@ -206,6 +206,7 @@ + #define __NR_mq_timedsend_time64 418 + #define __NR_mq_unlink 278 + #define __NR_mremap 163 ++#define __NR_mseal 462 + #define __NR_msgctl 402 + #define __NR_msgget 399 + #define __NR_msgrcv 401 +@@ -378,6 +379,7 @@ + #define __NR_symlinkat 304 + #define __NR_sync 36 + #define __NR_sync_file_range 314 ++#define __NR_sync_file_range2 388 + #define __NR_syncfs 362 + #define __NR_sysfs 135 + #define __NR_sysinfo 116 +diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/arch-syscall.h b/sysdeps/unix/sysv/linux/sparc/sparc32/arch-syscall.h +index 19fa614624dc2b85..3bad6f102ffaafb2 100644 +--- a/sysdeps/unix/sysv/linux/sparc/sparc32/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/sparc/sparc32/arch-syscall.h +@@ -211,6 +211,7 @@ + #define __NR_mq_timedsend_time64 418 + #define __NR_mq_unlink 274 + #define __NR_mremap 250 ++#define __NR_mseal 462 + #define __NR_msgctl 402 + #define __NR_msgget 399 + #define __NR_msgrcv 401 +diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/arch-syscall.h b/sysdeps/unix/sysv/linux/sparc/sparc64/arch-syscall.h +index 18516f20cbf25d77..98e143792026d0e8 100644 +--- a/sysdeps/unix/sysv/linux/sparc/sparc64/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/sparc/sparc64/arch-syscall.h +@@ -192,6 +192,7 @@ + #define __NR_mq_timedsend 275 + #define __NR_mq_unlink 274 + #define __NR_mremap 250 ++#define __NR_mseal 462 + #define __NR_msgctl 402 + #define __NR_msgget 399 + #define __NR_msgrcv 401 +diff --git a/sysdeps/unix/sysv/linux/syscall-names.list b/sysdeps/unix/sysv/linux/syscall-names.list +index 672d39eaad4491f1..7871f93b94d731d2 100644 +--- a/sysdeps/unix/sysv/linux/syscall-names.list ++++ b/sysdeps/unix/sysv/linux/syscall-names.list +@@ -21,8 +21,8 @@ + # This file can list all potential system calls. The names are only + # used if the installed kernel headers also provide them. + +-# The list of system calls is current as of Linux 6.9. +-kernel 6.9 ++# The list of system calls is current as of Linux 6.10. ++kernel 6.10 + + FAST_atomic_update + FAST_cmpxchg +@@ -287,6 +287,7 @@ mq_timedsend + mq_timedsend_time64 + mq_unlink + mremap ++mseal + msgctl + msgget + msgrcv +diff --git a/sysdeps/unix/sysv/linux/x86_64/64/arch-syscall.h b/sysdeps/unix/sysv/linux/x86_64/64/arch-syscall.h +index b1222160135310ec..5d86e75dd556caad 100644 +--- a/sysdeps/unix/sysv/linux/x86_64/64/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/x86_64/64/arch-syscall.h +@@ -189,6 +189,7 @@ + #define __NR_mq_timedsend 242 + #define __NR_mq_unlink 241 + #define __NR_mremap 25 ++#define __NR_mseal 462 + #define __NR_msgctl 71 + #define __NR_msgget 68 + #define __NR_msgrcv 70 +diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/arch-syscall.h b/sysdeps/unix/sysv/linux/x86_64/x32/arch-syscall.h +index df3e22236dd3bb0e..6c35068d8e8f4b05 100644 +--- a/sysdeps/unix/sysv/linux/x86_64/x32/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/x86_64/x32/arch-syscall.h +@@ -183,6 +183,7 @@ + #define __NR_mq_timedsend 1073742066 + #define __NR_mq_unlink 1073742065 + #define __NR_mremap 1073741849 ++#define __NR_mseal 1073742286 + #define __NR_msgctl 1073741895 + #define __NR_msgget 1073741892 + #define __NR_msgrcv 1073741894 diff --git a/glibc-RHEL-107695-8.patch b/glibc-RHEL-107695-8.patch new file mode 100644 index 0000000..f8a2b97 --- /dev/null +++ b/glibc-RHEL-107695-8.patch @@ -0,0 +1,57 @@ +commit e433cdec9b4b50e66d2f93fa92f622df8f4b870f +Author: Adhemerval Zanella +Date: Tue Jul 16 17:08:47 2024 +0000 + + Update kernel version to 6.10 in header constant tests + + This patch updates the kernel version in the tests tst-mman-consts.py, + tst-mount-consts.py, and tst-pidfd-consts.py to 6.9. + + There are no new constants covered by these tests in 6.10. + + Tested with build-many-glibcs.py. + Reviewed-by: Florian Weimer + +diff --git a/sysdeps/unix/sysv/linux/tst-mman-consts.py b/sysdeps/unix/sysv/linux/tst-mman-consts.py +index 441261c9456b2595..a1137eb1d59d95ec 100644 +--- a/sysdeps/unix/sysv/linux/tst-mman-consts.py ++++ b/sysdeps/unix/sysv/linux/tst-mman-consts.py +@@ -33,7 +33,7 @@ def main(): + help='C compiler (including options) to use') + args = parser.parse_args() + linux_version_headers = glibcsyscalls.linux_kernel_version(args.cc) +- linux_version_glibc = (6, 9) ++ linux_version_glibc = (6, 10) + sys.exit(glibcextract.compare_macro_consts( + '#define _GNU_SOURCE 1\n' + '#include \n', +diff --git a/sysdeps/unix/sysv/linux/tst-mount-consts.py b/sysdeps/unix/sysv/linux/tst-mount-consts.py +index c4a67221c1c5bc84..675f1790b64dd34e 100755 +--- a/sysdeps/unix/sysv/linux/tst-mount-consts.py ++++ b/sysdeps/unix/sysv/linux/tst-mount-consts.py +@@ -39,10 +39,10 @@ def main(): + sys.exit (77) + + linux_version_headers = glibcsyscalls.linux_kernel_version(args.cc) +- # Constants in glibc were updated to match Linux v6.9. When glibc ++ # Constants in glibc were updated to match Linux v6.10. When glibc + # constants are updated this value should be updated to match the + # released kernel version from which the constants were taken. +- linux_version_glibc = (6, 9) ++ linux_version_glibc = (6, 10) + def check(cte, exclude=None): + return glibcextract.compare_macro_consts( + '#include \n', +diff --git a/sysdeps/unix/sysv/linux/tst-pidfd-consts.py b/sysdeps/unix/sysv/linux/tst-pidfd-consts.py +index 6f05291949d00c62..9824fd214d477fd0 100644 +--- a/sysdeps/unix/sysv/linux/tst-pidfd-consts.py ++++ b/sysdeps/unix/sysv/linux/tst-pidfd-consts.py +@@ -39,7 +39,7 @@ def main(): + sys.exit (77) + + linux_version_headers = glibcsyscalls.linux_kernel_version(args.cc) +- linux_version_glibc = (6, 9) ++ linux_version_glibc = (6, 10) + sys.exit(glibcextract.compare_macro_consts( + '#include \n', + '#include \n' diff --git a/glibc-RHEL-107695-9.patch b/glibc-RHEL-107695-9.patch new file mode 100644 index 0000000..10a864d --- /dev/null +++ b/glibc-RHEL-107695-9.patch @@ -0,0 +1,100 @@ +commit 02de16df481f15d5f6f2a8d98aa1bb2888aec13b +Author: Adhemerval Zanella +Date: Tue Oct 8 15:45:24 2024 -0300 + + Update syscall lists for Linux 6.11 + + Linux 6.11 changes for syscall are: + + * fstat/newfstatat for loongarch (it should be safe to add since + 255dc1e4ed8 that undefine them). + * clone3 for nios2, which only adds the entry point but defined + __ARCH_BROKEN_SYS_CLONE3 (the syscall will always return ENOSYS). + * uretprobe for x86_64 and x32. + + Update syscall-names.list and regenerate the arch-syscall.h headers + with build-many-glibcs.py update-syscalls. + + Tested with build-many-glibcs.py. + + Reviewed-by: H.J. Lu + +diff --git a/sysdeps/unix/sysv/linux/loongarch/arch-syscall.h b/sysdeps/unix/sysv/linux/loongarch/arch-syscall.h +index 8bb82448a7570d54..7e732256fd4c6da7 100644 +--- a/sysdeps/unix/sysv/linux/loongarch/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/loongarch/arch-syscall.h +@@ -59,6 +59,7 @@ + #define __NR_fsmount 432 + #define __NR_fsopen 430 + #define __NR_fspick 433 ++#define __NR_fstat 80 + #define __NR_fstatfs 44 + #define __NR_fsync 82 + #define __NR_ftruncate 46 +@@ -166,6 +167,7 @@ + #define __NR_munmap 215 + #define __NR_name_to_handle_at 264 + #define __NR_nanosleep 101 ++#define __NR_newfstatat 79 + #define __NR_nfsservctl 42 + #define __NR_open_by_handle_at 265 + #define __NR_open_tree 428 +diff --git a/sysdeps/unix/sysv/linux/nios2/arch-syscall.h b/sysdeps/unix/sysv/linux/nios2/arch-syscall.h +index f94e212995549062..b1d0fb6f6ec99125 100644 +--- a/sysdeps/unix/sysv/linux/nios2/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/nios2/arch-syscall.h +@@ -24,6 +24,7 @@ + #define __NR_clock_settime 112 + #define __NR_clock_settime64 404 + #define __NR_clone 220 ++#define __NR_clone3 435 + #define __NR_close 57 + #define __NR_close_range 436 + #define __NR_connect 203 +diff --git a/sysdeps/unix/sysv/linux/syscall-names.list b/sysdeps/unix/sysv/linux/syscall-names.list +index 7871f93b94d731d2..aa5b479e2a08e7bb 100644 +--- a/sysdeps/unix/sysv/linux/syscall-names.list ++++ b/sysdeps/unix/sysv/linux/syscall-names.list +@@ -21,8 +21,8 @@ + # This file can list all potential system calls. The names are only + # used if the installed kernel headers also provide them. + +-# The list of system calls is current as of Linux 6.10. +-kernel 6.10 ++# The list of system calls is current as of Linux 6.11. ++kernel 6.11 + + FAST_atomic_update + FAST_cmpxchg +@@ -653,6 +653,7 @@ uname + unlink + unlinkat + unshare ++uretprobe + uselib + userfaultfd + usr26 +diff --git a/sysdeps/unix/sysv/linux/x86_64/64/arch-syscall.h b/sysdeps/unix/sysv/linux/x86_64/64/arch-syscall.h +index 5d86e75dd556caad..dfc10d0c7e8a8f1e 100644 +--- a/sysdeps/unix/sysv/linux/x86_64/64/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/x86_64/64/arch-syscall.h +@@ -359,6 +359,7 @@ + #define __NR_unlink 87 + #define __NR_unlinkat 263 + #define __NR_unshare 272 ++#define __NR_uretprobe 335 + #define __NR_uselib 134 + #define __NR_userfaultfd 323 + #define __NR_ustat 136 +diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/arch-syscall.h b/sysdeps/unix/sysv/linux/x86_64/x32/arch-syscall.h +index 6c35068d8e8f4b05..9340daa967425c4a 100644 +--- a/sysdeps/unix/sysv/linux/x86_64/x32/arch-syscall.h ++++ b/sysdeps/unix/sysv/linux/x86_64/x32/arch-syscall.h +@@ -351,6 +351,7 @@ + #define __NR_unlink 1073741911 + #define __NR_unlinkat 1073742087 + #define __NR_unshare 1073742096 ++#define __NR_uretprobe 1073742159 + #define __NR_userfaultfd 1073742147 + #define __NR_ustat 1073741960 + #define __NR_utime 1073741956 diff --git a/glibc-RHEL-107861-1.patch b/glibc-RHEL-107861-1.patch new file mode 100644 index 0000000..29eec39 --- /dev/null +++ b/glibc-RHEL-107861-1.patch @@ -0,0 +1,27 @@ +commit a07e000e82cb71238259e674529c37c12dc7d423 +Author: DJ Delorie +Date: Fri May 10 17:34:29 2024 -0400 + + manual: add dup3 + + Reviewed-by: Florian Weimer + +diff --git a/manual/llio.texi b/manual/llio.texi +index a65230d612eba7bf..513ba9e8859b8e6e 100644 +--- a/manual/llio.texi ++++ b/manual/llio.texi +@@ -3443,6 +3443,14 @@ middle of calling @code{dup2} at which @var{new} is closed and not yet a + duplicate of @var{old}. + @end deftypefun + ++@deftypefun int dup3 (int @var{old}, int @var{new}, int @var{flags}) ++@standards{Linux, unistd.h} ++@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}} ++This function is the same as @code{dup2} but creates the new ++descriptor as if it had been opened with flags @var{flags}. The only ++allowed flag is @code{O_CLOEXEC}. ++@end deftypefun ++ + @deftypevr Macro int F_DUPFD + @standards{POSIX.1, fcntl.h} + This macro is used as the @var{command} argument to @code{fcntl}, to diff --git a/glibc-RHEL-107861-2.patch b/glibc-RHEL-107861-2.patch new file mode 100644 index 0000000..75bd3ae --- /dev/null +++ b/glibc-RHEL-107861-2.patch @@ -0,0 +1,348 @@ +commit 6c0be74305745c8f78bcfb69442c8c379459d99b +Author: DJ Delorie +Date: Mon Jul 8 17:52:15 2024 -0400 + + manual: add syscalls + + The purpose of this patch is to add some system calls that (1) aren't + otherwise documented, and (2) are merely redirected to the kernel, so + can refer to their documentation; and define a standard way of doing + so in the future. A more detailed explaination of how system calls + are wrapped is added along with reference to the Linux Man-Pages + project. + + Default version of man-pages is in configure.ac but can be overridden + by --with-man-pages=X.Y + + Reviewed-by: Alejandro Colomar + +Conflicts: + configure (skip unrelated configure changes, due to autoconf + call) + +diff --git a/config.make.in b/config.make.in +index 55e8b7563b961dfc..36096881b7af4574 100644 +--- a/config.make.in ++++ b/config.make.in +@@ -91,6 +91,7 @@ use-nscd = @use_nscd@ + build-hardcoded-path-in-tests= @hardcoded_path_in_tests@ + build-pt-chown = @build_pt_chown@ + pthread-in-libc = @pthread_in_libc@ ++man-pages-version = @man_pages_version@ + + # Build tools. + CC = @CC@ +diff --git a/configure b/configure +index 432e40a59295cffd..c25b93dd0b317e4e 100755 +--- a/configure ++++ b/configure +@@ -706,6 +706,7 @@ force_install + bindnow + hardcoded_path_in_tests + enable_timezone_tools ++man_pages_version + rtld_early_cflags + extra_nonshared_cflags + sysheaders +@@ -787,6 +788,7 @@ with_headers + with_nonshared_cflags + with_rtld_early_cflags + with_timeoutfactor ++with_man_pages + enable_sanity_checks + enable_shared + enable_profile +@@ -1509,6 +1511,8 @@ Optional Packages: + build early initialization with additional CFLAGS + --with-timeoutfactor=NUM + specify an integer to scale the timeout ++ --with-man-pages=VERSION ++ tie manual to a specific man-pages version + --with-cpu=CPU select code for CPU variant + + Some influential environment variables: +@@ -4374,6 +4378,17 @@ fi + printf "%s\n" "#define TIMEOUTFACTOR $timeoutfactor" >>confdefs.h + + ++man_pages_version=6.9.1 ++ ++ ++# Check whether --with-man-pages was given. ++if test ${with_man_pages+y} ++then : ++ withval=$with_man_pages; man_pages_version=$withval ++fi ++ ++ ++ + # Check whether --enable-sanity-checks was given. + if test ${enable_sanity_checks+y} + then : +diff --git a/configure.ac b/configure.ac +index bdc385d03c3dc7f5..f00fc36f387af09d 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -168,6 +168,15 @@ AC_ARG_WITH([timeoutfactor], + [timeoutfactor=1]) + AC_DEFINE_UNQUOTED(TIMEOUTFACTOR, $timeoutfactor) + ++man_pages_version=6.9.1 ++ ++AC_ARG_WITH([man-pages], ++ AS_HELP_STRING([--with-man-pages=VERSION], ++ [tie manual to a specific man-pages version]), ++ [man_pages_version=$withval], ++ []) ++AC_SUBST(man_pages_version) ++ + AC_ARG_ENABLE([sanity-checks], + AS_HELP_STRING([--disable-sanity-checks], + [really do not use threads (should not be used except in special situations) @<:@default=yes@:>@]), +diff --git a/manual/Makefile b/manual/Makefile +index b5fda4a7ae07a785..a6c05db540d6c1da 100644 +--- a/manual/Makefile ++++ b/manual/Makefile +@@ -117,6 +117,7 @@ $(objpfx)stamp-pkgvers: $(common-objpfx)config.make + echo "@set PKGVERSION_DEFAULT" >> $(objpfx)pkgvers-tmp; \ + fi + echo "@set REPORT_BUGS_TO $(REPORT_BUGS_TEXI)" >> $(objpfx)pkgvers-tmp ++ echo "@set man_pages_version $(man-pages-version)" >> $(objpfx)pkgvers-tmp; \ + echo "@end ifclear" >> $(objpfx)pkgvers-tmp + $(move-if-change) $(objpfx)pkgvers-tmp $(objpfx)pkgvers.texi + touch $@ +diff --git a/manual/intro.texi b/manual/intro.texi +index ff43c5a7fbb969a0..879c1b38d9b73a46 100644 +--- a/manual/intro.texi ++++ b/manual/intro.texi +@@ -85,6 +85,7 @@ standards each function or symbol comes from. + * Berkeley Unix:: BSD and SunOS. + * SVID:: The System V Interface Description. + * XPG:: The X/Open Portability Guide. ++* Linux Kernel:: The Linux kernel. + @end menu + + @node ISO C, POSIX, , Standards and Portability +@@ -941,7 +942,7 @@ inter-process communication and shared memory, the @code{hsearch} and + @code{drand48} families of functions, @code{fmtmsg} and several of the + mathematical functions. + +-@node XPG, , SVID, Standards and Portability ++@node XPG, Linux Kernel, SVID, Standards and Portability + @subsection XPG (The X/Open Portability Guide) + + The X/Open Portability Guide, published by the X/Open Company, Ltd., is +@@ -960,6 +961,20 @@ fulfilling the XPG standard with the Unix extensions is a + precondition for getting the Unix brand chances are good that the + functionality is available on commercial systems. + ++@node Linux Kernel, , XPG, Standards and Portability ++@subsection Linux (The Linux Kernel) ++ ++@Theglibc{} includes by reference the Linux man-pages ++@value{man_pages_version} documentation to document the listed ++syscalls for the Linux kernel. For reference purposes only the latest ++@uref{https://www.kernel.org/doc/man-pages/,Linux man-pages Project} ++documentation can be accessed from the ++@uref{https://www.kernel.org,Linux kernel} website. Where the syscall ++has more specific documentation in this manual that more specific ++documentation is considered authoritative. ++ ++Additional details on the Linux system call interface can be found in ++@xref{System Calls}. + + @node Using the Library, Roadmap to the Manual, Standards and Portability, Introduction + @section Using the Library +diff --git a/manual/llio.texi b/manual/llio.texi +index 513ba9e8859b8e6e..17fe1181d5cc2cef 100644 +--- a/manual/llio.texi ++++ b/manual/llio.texi +@@ -65,6 +65,7 @@ directly.) + * Interrupt Input:: Getting an asynchronous signal when + input arrives. + * IOCTLs:: Generic I/O Control operations. ++* Other Low-Level I/O APIs:: Other low-level-I/O-related functions. + @end menu + + +@@ -2242,6 +2243,8 @@ file descriptor, or until the timeout period expires. + There is another example showing the use of @code{select} to multiplex + input from multiple sockets in @ref{Server Example}. + ++For an alternate interface to this functionality, see @code{poll} ++(@pxref{Other Low-Level I/O APIs}). + + @node Synchronizing I/O + @section Synchronizing I/O operations +@@ -3325,7 +3328,9 @@ require additional arguments to be supplied. These additional arguments + and the return value and error conditions are given in the detailed + descriptions of the individual commands. + +-Briefly, here is a list of what the various commands are. ++Briefly, here is a list of what the various commands are. For an ++exhaustive list of kernel-specific options, please see @xref{System ++Calls}. + + @vtable @code + @item F_DUPFD +@@ -4661,5 +4666,28 @@ Most IOCTLs are OS-specific and/or only used in special system utilities, + and are thus beyond the scope of this document. For an example of the use + of an IOCTL, see @ref{Out-of-Band Data}. + +-@c FIXME this is undocumented: +-@c dup3 ++@node Other Low-Level I/O APIs ++@section Other low-level-I/O-related functions ++ ++@deftp {Data Type} {struct pollfd} ++@standards{POSIX.1,poll.h} ++@end deftp ++ ++@deftp {Data Type} {struct epoll_event} ++@standards{Linux,sys/epoll.h} ++@end deftp ++ ++@deftypefun int poll (struct pollfd *@var{fds}, nfds_t @var{nfds}, int @var{timeout}) ++ ++@manpagefunctionstub{poll,2} ++@end deftypefun ++ ++@deftypefun int epoll_create(int @var{size}) ++ ++@manpagefunctionstub{epoll_create,2} ++@end deftypefun ++ ++@deftypefun int epoll_wait(int @var{epfd}, struct epoll_event *@var{events}, int @var{maxevents}, int @var{timeout}) ++ ++@manpagefunctionstub{epoll_wait,2} ++@end deftypefun +diff --git a/manual/macros.texi b/manual/macros.texi +index 4a2e22f4730d2390..579da3fb81e59da0 100644 +--- a/manual/macros.texi ++++ b/manual/macros.texi +@@ -282,4 +282,11 @@ cwd\comments\ + @macro standardsx {element, standard, header} + @end macro + ++@macro manpagefunctionstub {func,sec} ++This documentation is a stub. For additional information on this ++function, consult the manual page ++@url{https://man7.org/linux/man-pages/man\sec\/\func\.\sec\.html}. ++@xref{Linux Kernel}. ++@end macro ++ + @end ifclear +diff --git a/manual/socket.texi b/manual/socket.texi +index f0e35d9e13175212..8708cbb07ca02b5c 100644 +--- a/manual/socket.texi ++++ b/manual/socket.texi +@@ -41,6 +41,7 @@ aren't documented either so far. + is to make it work with Inetd. + * Socket Options:: Miscellaneous low-level socket options. + * Networks Database:: Accessing the database of network names. ++* Other Socket APIs:: Other socket-related functions. + @end menu + + @node Socket Concepts +@@ -3134,38 +3135,8 @@ You can use plain @code{recv} (@pxref{Receiving Data}) instead of + treat all possible senders alike). Even @code{read} can be used if + you don't want to specify @var{flags} (@pxref{I/O Primitives}). + +-@ignore +-@c sendmsg and recvmsg are like readv and writev in that they +-@c use a series of buffers. It's not clear this is worth +-@c supporting or that we support them. +-@c !!! they can do more; it is hairy +- +-@deftp {Data Type} {struct msghdr} +-@standards{BSD, sys/socket.h} +-@end deftp +- +-@deftypefun ssize_t sendmsg (int @var{socket}, const struct msghdr *@var{message}, int @var{flags}) +-@standards{BSD, sys/socket.h} +-@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}} +- +-This function is defined as a cancellation point in multi-threaded +-programs, so one has to be prepared for this and make sure that +-allocated resources (like memory, files descriptors, semaphores or +-whatever) are freed even if the thread is cancel. +-@c @xref{pthread_cleanup_push}, for a method how to do this. +-@end deftypefun +- +-@deftypefun ssize_t recvmsg (int @var{socket}, struct msghdr *@var{message}, int @var{flags}) +-@standards{BSD, sys/socket.h} +-@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}} +- +-This function is defined as a cancellation point in multi-threaded +-programs, so one has to be prepared for this and make sure that +-allocated resources (like memory, files descriptors, semaphores or +-whatever) are freed even if the thread is canceled. +-@c @xref{pthread_cleanup_push}, for a method how to do this. +-@end deftypefun +-@end ignore ++If you need more flexibility and/or control over sending and receiving ++packets, see @code{sendmsg} and @code{recvmsg} (@pxref{Other Socket APIs}). + + @node Datagram Example + @subsection Datagram Socket Example +@@ -3664,3 +3635,20 @@ returns a null pointer if there are no more entries. + @c libc_lock_unlock @aculock + This function closes the networks database. + @end deftypefun ++ ++@node Other Socket APIs ++@section Other Socket APIs ++ ++@deftp {Data Type} {struct msghdr} ++@standards{BSD, sys/socket.h} ++@end deftp ++ ++@deftypefun ssize_t sendmsg (int @var{socket}, const struct msghdr *@var{message}, int @var{flags}) ++ ++@manpagefunctionstub{sendmsg,2} ++@end deftypefun ++ ++@deftypefun ssize_t recvmsg (int @var{socket}, struct msghdr *@var{message}, int @var{flags}) ++ ++@manpagefunctionstub{recvmsg,2} ++@end deftypefun +diff --git a/manual/startup.texi b/manual/startup.texi +index 9bf24123f562f75b..1426f5e1abfb2f51 100644 +--- a/manual/startup.texi ++++ b/manual/startup.texi +@@ -690,7 +690,25 @@ you don't need to know about it because you can just use @theglibc{}'s + @code{chmod} function. + + @cindex kernel call +-System calls are sometimes called kernel calls. ++System calls are sometimes called syscalls or kernel calls, and this ++interface is mostly a purely mechanical translation from the kernel's ++ABI to the C ABI. For the set of syscalls where we do not guarantee ++POSIX Thread cancellation the wrappers only organize the incoming ++arguments from the C calling convention to the calling convention of ++the target kernel. For the set of syscalls where we provided POSIX ++Thread cancellation the wrappers set some internal state in the ++library to support cancellation, but this does not impact the ++behaviour of the syscall provided by the kernel. ++ ++In some cases, if @theglibc{} detects that a system call has been ++superseded by a more capable one, the wrapper may map the old call to ++the new one. For example, @code{dup2} is implemented via @code{dup3} ++by passing an additional empty flags argument, and @code{open} calls ++@code{openat} passing the additional @code{AT_FDCWD}. Sometimes even ++more is done, such as converting between 32-bit and 64-bit time ++values. In general, though, such processing is only to make the ++system call better match the C ABI, rather than change its ++functionality. + + However, there are times when you want to make a system call explicitly, + and for that, @theglibc{} provides the @code{syscall} function. +@@ -712,6 +730,8 @@ we won't describe it here either because anyone who is coding + library source code as a specification of the interface between them + anyway. + ++@code{syscall} does not provide cancellation logic, even if the system ++call you're calling is listed as cancellable above. + + @code{syscall} is declared in @file{unistd.h}. + diff --git a/glibc-RHEL-108475-1.patch b/glibc-RHEL-108475-1.patch new file mode 100644 index 0000000..30eb2de --- /dev/null +++ b/glibc-RHEL-108475-1.patch @@ -0,0 +1,28 @@ +commit b2c3ee3724900975deaf5eae57640bb0c2d7315e +Author: Andreas Schwab +Date: Tue Jun 4 11:01:11 2024 +0200 + + Remove memory leak in fdopen (bug 31840) + + Deallocate the memory for the FILE structure when seeking to the end fails + in append mode. + + Fixes: ea33158c96 ("Fix offset caching for streams and use it for ftell (BZ #16680)") + +diff --git a/libio/iofdopen.c b/libio/iofdopen.c +index 2583fb825573aae4..14fbc7b257ad7724 100644 +--- a/libio/iofdopen.c ++++ b/libio/iofdopen.c +@@ -156,7 +156,11 @@ _IO_new_fdopen (int fd, const char *mode) + { + off64_t new_pos = _IO_SYSSEEK (&new_f->fp.file, 0, _IO_seek_end); + if (new_pos == _IO_pos_BAD && errno != ESPIPE) +- return NULL; ++ { ++ _IO_un_link (&new_f->fp); ++ free (new_f); ++ return NULL; ++ } + } + return &new_f->fp.file; + } diff --git a/glibc-RHEL-108475-2.patch b/glibc-RHEL-108475-2.patch new file mode 100644 index 0000000..a6aa741 --- /dev/null +++ b/glibc-RHEL-108475-2.patch @@ -0,0 +1,120 @@ +commit d0106b6ae26c8cc046269358a77188105c99d5e3 +Author: Florian Weimer +Date: Tue Jun 4 14:37:35 2024 +0200 + + libio: Test for fdopen memory leak without SEEK_END support (bug 31840) + + The bug report used /dev/mem, but /proc/self/mem works as well + (if available). + +diff --git a/libio/Makefile b/libio/Makefile +index 92d6c6bcab1818d0..b189455bb9b8fd1b 100644 +--- a/libio/Makefile ++++ b/libio/Makefile +@@ -94,6 +94,7 @@ tests = \ + tst-eof \ + tst-ext \ + tst-ext2 \ ++ tst-fdopen-seek-failure \ + tst-fgetc-after-eof \ + tst-fgetwc \ + tst-fgetws \ +@@ -253,6 +254,9 @@ tst_wprintf2-ARGS = "Some Text" + + test-fmemopen-ENV = MALLOC_TRACE=$(objpfx)test-fmemopen.mtrace \ + LD_PRELOAD=$(common-objpfx)/malloc/libc_malloc_debug.so ++tst-fdopen-seek-failure-ENV = \ ++ MALLOC_TRACE=$(objpfx)tst-fdopen-seek-failure.mtrace \ ++ LD_PRELOAD=$(common-objpfx)/malloc/libc_malloc_debug.so + tst-fopenloc-ENV = MALLOC_TRACE=$(objpfx)tst-fopenloc.mtrace \ + LD_PRELOAD=$(common-objpfx)/malloc/libc_malloc_debug.so + tst-bz22415-ENV = MALLOC_TRACE=$(objpfx)tst-bz22415.mtrace \ +@@ -261,6 +265,7 @@ tst-bz24228-ENV = MALLOC_TRACE=$(objpfx)tst-bz24228.mtrace \ + LD_PRELOAD=$(common-objpfx)/malloc/libc_malloc_debug.so + + generated += test-fmemopen.mtrace test-fmemopen.check ++generated += tst-fdopen-seek-failure.mtrace tst-fdopen-seek-failure.check + generated += tst-fopenloc.mtrace tst-fopenloc.check + generated += tst-bz22415.mtrace tst-bz22415.check + +@@ -283,8 +288,12 @@ shared-only-routines = oldiofopen oldiofdopen oldiofclose oldfileops \ + oldiofsetpos64 + + ifeq ($(run-built-tests),yes) +-tests-special += $(objpfx)test-freopen.out $(objpfx)test-fmemopen-mem.out \ +- $(objpfx)tst-bz22415-mem.out ++tests-special += \ ++ $(objpfx)test-fmemopen-mem.out \ ++ $(objpfx)test-freopen.out \ ++ $(objpfx)tst-bz22415-mem.out \ ++ $(objpfx)tst-fdopen-seek-failure-mem.out \ ++ # tests-special + ifeq (yes,$(build-shared)) + # Run tst-fopenloc-cmp.out and tst-openloc-mem.out only if shared + # library is enabled since they depend on tst-fopenloc.out. +@@ -372,6 +381,11 @@ $(objpfx)test-fmemopen-mem.out: $(objpfx)test-fmemopen.out + $(common-objpfx)malloc/mtrace $(objpfx)test-fmemopen.mtrace > $@; \ + $(evaluate-test) + ++$(objpfx)tst-fdopen-seek-failure-mem.out: $(objpfx)tst-fdopen-seek-failure.out ++ $(common-objpfx)malloc/mtrace \ ++ $(objpfx)tst-fdopen-seek-failure.mtrace > $@; \ ++ $(evaluate-test) ++ + $(objpfx)tst-fopenloc-mem.out: $(objpfx)tst-fopenloc.out + $(common-objpfx)malloc/mtrace $(objpfx)tst-fopenloc.mtrace > $@; \ + $(evaluate-test) +diff --git a/libio/tst-fdopen-seek-failure.c b/libio/tst-fdopen-seek-failure.c +new file mode 100644 +index 0000000000000000..5c4d40ab34158571 +--- /dev/null ++++ b/libio/tst-fdopen-seek-failure.c +@@ -0,0 +1,48 @@ ++/* Test for fdopen memory leak without SEEK_END support (bug 31840). ++ Copyright (C) 2024 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 ++ . */ ++ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static int ++do_test (void) ++{ ++ mtrace (); ++ ++ /* This file is special because it is seekable, but only ++ with SEEK_SET, not SEEK_END. */ ++ int fd = open ("/proc/self/mem", O_RDWR); ++ if (fd < 0) ++ FAIL_UNSUPPORTED ("/proc/self/mem not found: %m"); ++ FILE *fp = fdopen (fd, "a"); ++ /* The fdopen call should have failed because it tried to use ++ SEEK_END. */ ++ TEST_VERIFY (fp == NULL); ++ TEST_COMPARE (errno, EINVAL); ++ xclose (fd); ++ return 0; ++} ++ ++#include diff --git a/glibc-RHEL-108823-1.patch b/glibc-RHEL-108823-1.patch new file mode 100644 index 0000000..523f4cb --- /dev/null +++ b/glibc-RHEL-108823-1.patch @@ -0,0 +1,23 @@ +commit 34bb581e7713589d38c797c214f4c6bf2b14b702 +Author: Florian Weimer +Date: Fri Aug 16 16:05:19 2024 +0200 + + support: Include for strcmp in support_format_addrinfo.c + + This is currently implied by the internal headers, but it makes + sense not to rely on this. + + Reviewed-by: Adhemerval Zanella + +diff --git a/support/support_format_addrinfo.c b/support/support_format_addrinfo.c +index cbc72910a96a0e36..77f4db345c2912aa 100644 +--- a/support/support_format_addrinfo.c ++++ b/support/support_format_addrinfo.c +@@ -22,6 +22,7 @@ + #include + #include + #include ++#include + #include + #include + diff --git a/glibc-RHEL-108823-10.patch b/glibc-RHEL-108823-10.patch new file mode 100644 index 0000000..3795764 --- /dev/null +++ b/glibc-RHEL-108823-10.patch @@ -0,0 +1,460 @@ +commit e3db0a699c639e97deddcb15939fd9c162801c77 +Author: Florian Weimer +Date: Sat Sep 21 19:25:35 2024 +0200 + + misc: FUSE-based tests for mkstemp + + The tests check that O_EXCL is used properly, that 0600 is used + as the mode, that the characters used are as expected, and that + the distribution of names generated is reasonably random. + + The tests run very slowly on some kernel versions, so make them + xtests. + + Reviewed-by: DJ Delorie + +diff --git a/misc/Makefile b/misc/Makefile +index 235fc7eacb6a980d..a684fb1076fc2354 100644 +--- a/misc/Makefile ++++ b/misc/Makefile +@@ -286,6 +286,12 @@ tests-static := tst-empty + tests-internal += tst-fd_to_filename + tests-static += tst-fd_to_filename + ++# Tests with long run times. ++xtests += \ ++ tst-mkstemp-fuse \ ++ tst-mkstemp-fuse-parallel \ ++ # xtests ++ + ifeq ($(run-built-tests),yes) + tests-special += $(objpfx)tst-error1-mem.out \ + $(objpfx)tst-allocate_once-mem.out +diff --git a/misc/tst-mkstemp-fuse-parallel.c b/misc/tst-mkstemp-fuse-parallel.c +new file mode 100644 +index 0000000000000000..219f26cb3bf7c0ba +--- /dev/null ++++ b/misc/tst-mkstemp-fuse-parallel.c +@@ -0,0 +1,219 @@ ++/* FUSE-based test for mkstemp. Parallel collision statistics. ++ Copyright (C) 2024 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 ++ . */ ++ ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* The number of subprocesses that call mkstemp. */ ++static pid_t processes[4]; ++ ++/* Enough space to record the expected number of replies (62**3) for ++ each process. */ ++enum { results_allocated = array_length (processes) * 62 * 62 * 62 }; ++ ++/* The thread will store the results there. */ ++static uint64_t *results; ++ ++/* Currently used part of the results array. */ ++static size_t results_used; ++ ++/* Fail with EEXIST (so that mkstemp tries again). Record observed ++ names for later statistical analysis. */ ++static void ++fuse_thread (struct support_fuse *f, void *closure) ++{ ++ struct fuse_in_header *inh; ++ while ((inh = support_fuse_next (f)) != NULL) ++ { ++ if (support_fuse_handle_mountpoint (f) ++ || (inh->nodeid == 1 && support_fuse_handle_directory (f))) ++ continue; ++ if (inh->opcode != FUSE_LOOKUP || results_used >= results_allocated) ++ { ++ support_fuse_reply_error (f, EIO); ++ continue; ++ } ++ ++ char *name = support_fuse_cast (LOOKUP, inh); ++ TEST_COMPARE_BLOB (name, 3, "new", 3); ++ TEST_COMPARE (strlen (name), 9); ++ /* Extract 8 bytes of the name: 'w', the X replacements, and the ++ null terminator. Treat it as an uint64_t for easy sorting ++ below. Endianess does not matter because the relative order ++ of the entries is not important; sorting is only used to find ++ duplicates. */ ++ TEST_VERIFY_EXIT (results_used < results_allocated); ++ memcpy (&results[results_used], name + 2, 8); ++ ++results_used; ++ struct fuse_entry_out *out = support_fuse_prepare_entry (f, 2); ++ out->attr.mode = S_IFREG | 0600; ++ support_fuse_reply_prepared (f); ++ } ++} ++ ++/* Used to sort the results array, to find duplicates. */ ++static int ++results_sort (const void *a1, const void *b1) ++{ ++ const uint64_t *a = a1; ++ const uint64_t *b = b1; ++ if (*a < *b) ++ return -1; ++ if (*a == *b) ++ return 0; ++ return 1; ++} ++ ++/* Number of occurrences of certain streak lengths. */ ++static size_t streak_lengths[6]; ++ ++/* Called for every encountered streak. */ ++static inline void ++report_streak (uint64_t current, size_t length) ++{ ++ if (length > 1) ++ { ++ printf ("info: name \"ne%.8s\" repeats: %zu\n", ++ (char *) ¤t, length); ++ TEST_VERIFY_EXIT (length < array_length (streak_lengths)); ++ } ++ TEST_VERIFY_EXIT (length < array_length (streak_lengths)); ++ ++streak_lengths[length]; ++} ++ ++static int ++do_test (void) ++{ ++ support_fuse_init (); ++ ++ results = xmalloc (results_allocated * sizeof (*results)); ++ ++ struct shared ++ { ++ /* Used to synchronize the start of all subprocesses, to make it ++ more likely to expose concurrency-related bugs. */ ++ pthread_barrier_t barrier1; ++ pthread_barrier_t barrier2; ++ ++ /* Filled in after fork. */ ++ char mountpoint[4096]; ++ }; ++ ++ /* Used to synchronize the start of all subprocesses, to make it ++ more likely to expose concurrency-related bugs. */ ++ struct shared *pshared = support_shared_allocate (sizeof (*pshared)); ++ { ++ pthread_barrierattr_t attr; ++ xpthread_barrierattr_init (&attr); ++ xpthread_barrierattr_setpshared (&attr, PTHREAD_PROCESS_SHARED); ++ xpthread_barrierattr_destroy (&attr); ++ xpthread_barrier_init (&pshared->barrier1, &attr, ++ array_length (processes) + 1); ++ xpthread_barrier_init (&pshared->barrier2, &attr, ++ array_length (processes) + 1); ++ xpthread_barrierattr_destroy (&attr); ++ } ++ ++ for (int i = 0; i < array_length (processes); ++i) ++ { ++ processes[i] = xfork (); ++ if (processes[i] == 0) ++ { ++ /* Wait for mountpoint initialization. */ ++ xpthread_barrier_wait (&pshared->barrier1); ++ char *path = xasprintf ("%s/newXXXXXX", pshared->mountpoint); ++ ++ /* Park this process until all processes have started. */ ++ xpthread_barrier_wait (&pshared->barrier2); ++ errno = 0; ++ TEST_COMPARE (mkstemp (path), -1); ++ TEST_COMPARE (errno, EEXIST); ++ free (path); ++ _exit (0); ++ } ++ } ++ ++ /* Do this after the forking, to minimize initialization inteference. */ ++ struct support_fuse *f = support_fuse_mount (fuse_thread, NULL); ++ TEST_VERIFY (strlcpy (pshared->mountpoint, support_fuse_mountpoint (f), ++ sizeof (pshared->mountpoint)) ++ < sizeof (pshared->mountpoint)); ++ xpthread_barrier_wait (&pshared->barrier1); ++ ++ puts ("info: performing mkstemp calls"); ++ xpthread_barrier_wait (&pshared->barrier2); ++ ++ for (int i = 0; i < array_length (processes); ++i) ++ { ++ int status; ++ xwaitpid (processes[i], &status, 0); ++ TEST_COMPARE (status, 0); ++ } ++ ++ support_fuse_unmount (f); ++ xpthread_barrier_destroy (&pshared->barrier2); ++ xpthread_barrier_destroy (&pshared->barrier1); ++ ++ printf ("info: checking results (count %zu)\n", results_used); ++ qsort (results, results_used, sizeof (*results), results_sort); ++ ++ uint64_t current = -1; ++ size_t streak = 0; ++ for (size_t i = 0; i < results_used; ++i) ++ if (results[i] == current) ++ ++streak; ++ else ++ { ++ report_streak (current, streak); ++ current = results[i]; ++ streak = 1; ++ } ++ report_streak (current, streak); ++ ++ puts ("info: repetition count distribution:"); ++ for (int i = 1; i < array_length (streak_lengths); ++i) ++ printf (" length %d: %zu\n", i, streak_lengths[i]); ++ /* Some arbitrary threshold, hopefully unlikely enough. In over ++ 260,000 runs of a simulation of this test, at most 26 pairs were ++ observed, and only one three-way collisions. */ ++ if (streak_lengths[2] > 30) ++ FAIL ("unexpected repetition count 2: %zu", streak_lengths[2]); ++ if (streak_lengths[3] > 2) ++ FAIL ("unexpected repetition count 3: %zu", streak_lengths[3]); ++ for (int i = 4; i < array_length (streak_lengths); ++i) ++ if (streak_lengths[i] > 0) ++ FAIL ("too many repeats of count %d: %zu", i, streak_lengths[i]); ++ ++ free (results); ++ ++ return 0; ++} ++ ++#include +diff --git a/misc/tst-mkstemp-fuse.c b/misc/tst-mkstemp-fuse.c +new file mode 100644 +index 0000000000000000..5ac6a6872a9c513d +--- /dev/null ++++ b/misc/tst-mkstemp-fuse.c +@@ -0,0 +1,197 @@ ++/* FUSE-based test for mkstemp. ++ Copyright (C) 2024 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 ++ . */ ++ ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Set to true in do_test to cause the first FUSE_CREATE attempt to fail. */ ++static _Atomic bool simulate_creat_race; ++ ++/* Basic tests with eventually successful creation. */ ++static void ++fuse_thread_basic (struct support_fuse *f, void *closure) ++{ ++ char *previous_name = NULL; ++ int state = 0; ++ struct fuse_in_header *inh; ++ while ((inh = support_fuse_next (f)) != NULL) ++ { ++ if (support_fuse_handle_mountpoint (f) ++ || (inh->nodeid == 1 && support_fuse_handle_directory (f))) ++ continue; ++ ++ switch (inh->opcode) ++ { ++ case FUSE_LOOKUP: ++ /* File does not exist initially. */ ++ TEST_COMPARE (inh->nodeid, 1); ++ if (simulate_creat_race) ++ { ++ if (state < 3) ++ ++state; ++ else ++ FAIL ("invalid state: %d", state); ++ } ++ else ++ { ++ TEST_COMPARE (state, 0); ++ state = 3; ++ } ++ support_fuse_reply_error (f, ENOENT); ++ break; ++ case FUSE_CREATE: ++ { ++ TEST_COMPARE (inh->nodeid, 1); ++ char *name; ++ struct fuse_create_in *p ++ = support_fuse_cast_name (CREATE, inh, &name); ++ /* Name follows after struct fuse_create_in. */ ++ TEST_COMPARE (p->flags & O_ACCMODE, O_RDWR); ++ TEST_VERIFY (p->flags & O_EXCL); ++ TEST_VERIFY (p->flags & O_CREAT); ++ TEST_COMPARE (p->mode & 07777, 0600); ++ TEST_VERIFY (S_ISREG (p->mode)); ++ TEST_COMPARE_BLOB (name, 3, "new", 3); ++ ++ if (state != 3 && simulate_creat_race) ++ { ++ ++state; ++ support_fuse_reply_error (f, EEXIST); ++ } ++ else ++ { ++ if (previous_name != NULL) ++ /* This test has a very small probability of failure ++ due to a harmless collision (one in 62**6 tests). */ ++ TEST_VERIFY (strcmp (name, previous_name) != 0); ++ TEST_COMPARE (state, 3); ++ ++state; ++ struct fuse_entry_out *entry; ++ struct fuse_open_out *open; ++ support_fuse_prepare_create (f, 2, &entry, &open); ++ entry->attr.mode = S_IFREG | 0600; ++ support_fuse_reply_prepared (f); ++ } ++ free (previous_name); ++ previous_name = xstrdup (name); ++ } ++ break; ++ case FUSE_FLUSH: ++ case FUSE_RELEASE: ++ TEST_COMPARE (state, 4); ++ TEST_COMPARE (inh->nodeid, 2); ++ support_fuse_reply_empty (f); ++ break; ++ default: ++ support_fuse_reply_error (f, EIO); ++ } ++ } ++ free (previous_name); ++} ++ ++/* Reply that all files exist. */ ++static void ++fuse_thread_eexist (struct support_fuse *f, void *closure) ++{ ++ uint64_t counter = 0; ++ struct fuse_in_header *inh; ++ while ((inh = support_fuse_next (f)) != NULL) ++ { ++ if (support_fuse_handle_mountpoint (f) ++ || (inh->nodeid == 1 && support_fuse_handle_directory (f))) ++ continue; ++ ++ switch (inh->opcode) ++ { ++ case FUSE_LOOKUP: ++ ++counter; ++ TEST_COMPARE (inh->nodeid, 1); ++ char *name = support_fuse_cast (LOOKUP, inh); ++ TEST_COMPARE_BLOB (name, 3, "new", 3); ++ TEST_COMPARE (strlen (name), 9); ++ for (int i = 3; i <= 8; ++i) ++ { ++ /* The glibc implementation uses letters and digits only. */ ++ char ch = name[i]; ++ TEST_VERIFY (('0' <= ch && ch <= '9') ++ || ('a' <= ch && ch <= 'z') ++ || ('A' <= ch && ch <= 'Z')); ++ } ++ struct fuse_entry_out out = ++ { ++ .nodeid = 2, ++ .attr = { ++ .mode = S_IFREG | 0600, ++ .ino = 2, ++ }, ++ }; ++ support_fuse_reply (f, &out, sizeof (out)); ++ break; ++ default: ++ support_fuse_reply_error (f, EIO); ++ } ++ } ++ /* Verify that mkstemp has retried a lot. The current ++ implementation tries 62 * 62 * 62 times until it goves up. */ ++ TEST_VERIFY (counter >= 200000); ++} ++ ++static int ++do_test (void) ++{ ++ support_fuse_init (); ++ ++ for (int do_simulate_creat_race = 0; do_simulate_creat_race < 2; ++ ++do_simulate_creat_race) ++ { ++ simulate_creat_race = do_simulate_creat_race; ++ printf ("info: testing with simulate_creat_race == %d\n", ++ (int) simulate_creat_race); ++ struct support_fuse *f = support_fuse_mount (fuse_thread_basic, NULL); ++ char *path = xasprintf ("%s/newXXXXXX", support_fuse_mountpoint (f)); ++ int fd = mkstemp (path); ++ TEST_VERIFY (fd > 2); ++ xclose (fd); ++ free (path); ++ support_fuse_unmount (f); ++ } ++ ++ puts ("info: testing EEXIST failure case for mkstemp"); ++ { ++ struct support_fuse *f = support_fuse_mount (fuse_thread_eexist, NULL); ++ char *path = xasprintf ("%s/newXXXXXX", support_fuse_mountpoint (f)); ++ errno = 0; ++ TEST_COMPARE (mkstemp (path), -1); ++ TEST_COMPARE (errno, EEXIST); ++ free (path); ++ support_fuse_unmount (f); ++ } ++ ++ return 0; ++} ++ ++#include diff --git a/glibc-RHEL-108823-11.patch b/glibc-RHEL-108823-11.patch new file mode 100644 index 0000000..bd288f7 --- /dev/null +++ b/glibc-RHEL-108823-11.patch @@ -0,0 +1,33 @@ +commit 455c7622835d16c79e49fe75b8d3a1ae59a3d0ee +Author: Florian Weimer +Date: Sat Sep 21 19:25:35 2024 +0200 + + support: Fix memory leaks in FUSE tests + + The internal read buffer (used by all FUSE tests) was not freed. + The support/tst-support_fuse test missed a deallocation. + +diff --git a/support/support_fuse.c b/support/support_fuse.c +index 135dbf1198d5a4c7..f6c063b549e2c26c 100644 +--- a/support/support_fuse.c ++++ b/support/support_fuse.c +@@ -659,6 +659,7 @@ support_fuse_unmount (struct support_fuse *f) + if (rmdir (f->mountpoint) != 0) + FAIL ("FUSE: rmdir (\"%s\"): %m", f->mountpoint); + xclose (f->fd); ++ free (f->buffer_start); + free (f->mountpoint); + free (f->readdir_buffer); + free (f); +diff --git a/support/tst-support_fuse.c b/support/tst-support_fuse.c +index c4075a6608d9dd65..9ee637cbab6f6b9e 100644 +--- a/support/tst-support_fuse.c ++++ b/support/tst-support_fuse.c +@@ -331,6 +331,7 @@ do_test (void) + { + char *subdir_path = xasprintf ("%s/subdir", support_fuse_mountpoint (f)); + xmkdir (subdir_path, 01234); ++ free (subdir_path); + } + + { diff --git a/glibc-RHEL-108823-12.patch b/glibc-RHEL-108823-12.patch new file mode 100644 index 0000000..51097ab --- /dev/null +++ b/glibc-RHEL-108823-12.patch @@ -0,0 +1,26 @@ +commit 366cce74d2aa2e5753d8787d415b745fd57fda04 +Author: Florian Weimer +Date: Sat Sep 21 19:29:13 2024 +0200 + + support: Add valgrind instructions to + + Replacing an outdated comment (namespace setup is now handled by + support_fuse_init). + +diff --git a/support/fuse.h b/support/fuse.h +index 4c365fbc0c7408b9..1c862bedbe487ce6 100644 +--- a/support/fuse.h ++++ b/support/fuse.h +@@ -16,8 +16,10 @@ + License along with the GNU C Library; if not, see + . */ + +-/* Before using this functionality, use support_enter_mount_namespace +- to ensure that mounts do not impact the overall system. */ ++/* To run FUSE tests under valgrind, pass the ++ --sim-hints=fuse-compatible option to valgrind. This option tells ++ valgrind that additional system calls effectively call back into ++ the current program. */ + + #ifndef SUPPORT_FUSE_H + #define SUPPORT_FUSE_H diff --git a/glibc-RHEL-108823-13.patch b/glibc-RHEL-108823-13.patch new file mode 100644 index 0000000..9d43247 --- /dev/null +++ b/glibc-RHEL-108823-13.patch @@ -0,0 +1,17 @@ +commit 3ef26b708725b528a1c69ab3eb523036c50b89d6 +Author: Florian Weimer +Date: Tue Sep 24 13:05:48 2024 +0200 + + misc: Link tst-mkstemp-fuse-parallel with $(shared-thread-library) + + The barrier functions require this on Hurd. + +diff --git a/misc/Makefile b/misc/Makefile +index a684fb1076fc2354..6aa74d332b40ca94 100644 +--- a/misc/Makefile ++++ b/misc/Makefile +@@ -369,3 +369,4 @@ $(objpfx)tst-select: $(librt) + $(objpfx)tst-select-time64: $(librt) + $(objpfx)tst-pselect: $(librt) + $(objpfx)tst-pselect-time64: $(librt) ++$(objpfx)tst-mkstemp-fuse-parallel: $(shared-thread-library) diff --git a/glibc-RHEL-108823-14.patch b/glibc-RHEL-108823-14.patch new file mode 100644 index 0000000..ee16c69 --- /dev/null +++ b/glibc-RHEL-108823-14.patch @@ -0,0 +1,39 @@ +commit 6f999af332c91035350390ef8af96388b8f4fd2c +Author: Arjun Shankar +Date: Mon Aug 18 15:33:13 2025 +0200 + + support: Handle FUSE_GETXATTR during FUSE FS mount + + When testing with some kernel versions, support FUSE infrastructure + encounters a FUSE_GETXATTR request, leading to FUSE tests hanging until + timed out. Therefore, pass FUSE_GETXATTR requests from + support_fuse_handle_mountpoint to support_fuse_handle_directory, and + adjust support_fuse_handle_directory to return ENOSYS so that tests can + proceed. + + Reviewed-by: Florian Weimer + +diff --git a/support/support_fuse.c b/support/support_fuse.c +index f6c063b549e2c26c..5af2f7d8ab93a5ea 100644 +--- a/support/support_fuse.c ++++ b/support/support_fuse.c +@@ -212,6 +212,9 @@ support_fuse_handle_directory (struct support_fuse *f) + support_fuse_reply_prepared (f); + } + return true; ++ case FUSE_GETXATTR: ++ support_fuse_reply_error (f, ENOSYS); ++ return true; + default: + return false; + } +@@ -222,7 +225,8 @@ support_fuse_handle_mountpoint (struct support_fuse *f) + { + TEST_VERIFY (f->inh != NULL); + /* 1 is the root node. */ +- if (f->inh->opcode == FUSE_GETATTR && f->inh->nodeid == 1) ++ if ((f->inh->opcode == FUSE_GETATTR || f->inh->opcode == FUSE_GETXATTR) ++ && f->inh->nodeid == 1) + return support_fuse_handle_directory (f); + return false; + } diff --git a/glibc-RHEL-108823-2.patch b/glibc-RHEL-108823-2.patch new file mode 100644 index 0000000..9b7c559 --- /dev/null +++ b/glibc-RHEL-108823-2.patch @@ -0,0 +1,41 @@ +commit 34e52acd55d69964d14fb3188c5538442b8b32be +Author: Florian Weimer +Date: Thu Aug 22 16:14:17 2024 +0200 + + support: Report errno constants in TEST_COMPARE failures + + If the expression is errno, decode it as an errno constant + using strerrorname_np. + + Reviewed-by: Arjun Shankar + +diff --git a/support/support_test_compare_failure.c b/support/support_test_compare_failure.c +index ae73d200cda81ea9..dba79e413feffec5 100644 +--- a/support/support_test_compare_failure.c ++++ b/support/support_test_compare_failure.c +@@ -17,7 +17,9 @@ + . */ + + #include ++#include + #include ++#include + #include + + static void +@@ -31,7 +33,14 @@ report (const char *which, const char *expr, long long value, int positive, + printf ("%lld", value); + unsigned long long mask + = (~0ULL) >> (8 * (sizeof (unsigned long long) - size)); +- printf (" (0x%llx); from: %s\n", (unsigned long long) value & mask, expr); ++ const char *errno_constant = NULL; ++ if (strcmp (expr, "errno") == 0 ++ && positive && (unsigned long long int) value <= INT_MAX) ++ errno_constant = strerrorname_np (value); ++ printf (" (0x%llx", (unsigned long long) value & mask); ++ if (errno_constant != NULL) ++ printf (", %s", errno_constant); ++ printf ("); from: %s\n", expr); + } + + void diff --git a/glibc-RHEL-108823-3.patch b/glibc-RHEL-108823-3.patch new file mode 100644 index 0000000..b5e48ab --- /dev/null +++ b/glibc-RHEL-108823-3.patch @@ -0,0 +1,88 @@ +commit 424d97be50488beb6196c0ff0bc3dfeb87b4281c +Author: Florian Weimer +Date: Fri Aug 30 20:37:18 2024 +0200 + + io: Add error tests for fchmod + + On Linux most descriptors that do not correspond to file system + entities (such as anonymous pipes and sockets) have file permissions + that can be changed. While it is possible to create a custom file + system that returns (say) EINVAL for an fchmod attempt, testing this + does not appear to be useful. + + Reviewed-by: Carlos O'Donell + +diff --git a/io/Makefile b/io/Makefile +index 54d950d51f31758b..8ecd2842e20fef97 100644 +--- a/io/Makefile ++++ b/io/Makefile +@@ -188,6 +188,7 @@ tests := \ + tst-closefrom \ + tst-copy_file_range \ + tst-faccessat \ ++ tst-fchmod-errors \ + tst-fchmodat \ + tst-fchownat \ + tst-fcntl \ +diff --git a/io/tst-fchmod-errors.c b/io/tst-fchmod-errors.c +new file mode 100644 +index 0000000000000000..ee15300fc3edf6f0 +--- /dev/null ++++ b/io/tst-fchmod-errors.c +@@ -0,0 +1,56 @@ ++/* Test various fchmod error cases. ++ Copyright (C) 2024 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++ ++static int ++do_test (void) ++{ ++ { ++ /* Permissions on /dev/null (the opened descriptor) cannot be changed. */ ++ int fd = xopen ("/dev/null", O_RDWR, 0); ++ errno = 0; ++ TEST_COMPARE (fchmod (fd, 0), -1); ++ TEST_COMPARE (errno, EPERM); ++ xclose (fd); ++ ++ /* Now testing an invalid file descriptor. */ ++ errno = 0; ++ TEST_COMPARE (fchmod (fd, 0600), -1); ++ TEST_COMPARE (errno, EBADF); ++ } ++ ++ errno = 0; ++ TEST_COMPARE (fchmod (-1, 0600), -1); ++ TEST_COMPARE (errno, EBADF); ++ ++ errno = 0; ++ TEST_COMPARE (fchmod (AT_FDCWD, 0600), -1); ++ TEST_COMPARE (errno, EBADF); ++ ++ /* Linux supports fchmod on pretty much all file descriptors, so ++ there is no check for failure on specific types of descriptors ++ here. */ ++ ++ return 0; ++} ++ ++#include diff --git a/glibc-RHEL-108823-4.patch b/glibc-RHEL-108823-4.patch new file mode 100644 index 0000000..3236001 --- /dev/null +++ b/glibc-RHEL-108823-4.patch @@ -0,0 +1,44 @@ +commit 3844cdc33093dbe1e33ddb831eada9bdb4a482b9 +Author: Florian Weimer +Date: Fri Aug 30 22:07:12 2024 +0200 + + io: Fix destructive nature of tst-fchmod-errors + + We must not change the permissions of /dev/null if running + as root. + + Reviewed-by: Carlos O'Donell + +diff --git a/io/tst-fchmod-errors.c b/io/tst-fchmod-errors.c +index ee15300fc3edf6f0..bf2a4c568e33aeaa 100644 +--- a/io/tst-fchmod-errors.c ++++ b/io/tst-fchmod-errors.c +@@ -18,8 +18,10 @@ + + #include + #include ++#include + #include + #include ++#include + + static int + do_test (void) +@@ -27,9 +29,14 @@ do_test (void) + { + /* Permissions on /dev/null (the opened descriptor) cannot be changed. */ + int fd = xopen ("/dev/null", O_RDWR, 0); +- errno = 0; +- TEST_COMPARE (fchmod (fd, 0), -1); +- TEST_COMPARE (errno, EPERM); ++ if (getuid () == 0) ++ puts ("info: /dev/null fchmod test skipped because of root privileges"); ++ else ++ { ++ errno = 0; ++ TEST_COMPARE (fchmod (fd, 0), -1); ++ TEST_COMPARE (errno, EPERM); ++ } + xclose (fd); + + /* Now testing an invalid file descriptor. */ diff --git a/glibc-RHEL-108823-5.patch b/glibc-RHEL-108823-5.patch new file mode 100644 index 0000000..aa39f6c --- /dev/null +++ b/glibc-RHEL-108823-5.patch @@ -0,0 +1,1646 @@ +commit b09a520bb6d98d465818aadfd0641751ce824053 +Author: Florian Weimer +Date: Fri Aug 30 21:51:46 2024 +0200 + + Bundle userspace header from Linux 6.10 + + And include the required licensing information. The only + change is a removed trailing empty line in + LICENSES/exceptions/Linux-syscall-note. + + Bundling is the recommended way to deal with + the evolution of the FUSE userspace interface because + structs change sizes over time. The kernel maintains + compatibility, but source-level compatibility on recompilation + may require additional code that is aware of older struct sizes. + + Signed-off-by: Florian Weimer + Reviewed-by: DJ Delorie + +diff --git a/support/bundled/README b/support/bundled/README +new file mode 100644 +index 0000000000000000..e861b3d40a7cf5c5 +--- /dev/null ++++ b/support/bundled/README +@@ -0,0 +1,5 @@ ++This subtree contains bundled files included verbatim from other ++sources. They are used for building the support/ infrastructure. ++ ++linux/ ++ Select files from the Linux 6.10 source tree. +diff --git a/support/bundled/linux/COPYING b/support/bundled/linux/COPYING +new file mode 100644 +index 0000000000000000..a635a38ef9405fdf +--- /dev/null ++++ b/support/bundled/linux/COPYING +@@ -0,0 +1,20 @@ ++The Linux Kernel is provided under: ++ ++ SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note ++ ++Being under the terms of the GNU General Public License version 2 only, ++according with: ++ ++ LICENSES/preferred/GPL-2.0 ++ ++With an explicit syscall exception, as stated at: ++ ++ LICENSES/exceptions/Linux-syscall-note ++ ++In addition, other licenses may also apply. Please see: ++ ++ Documentation/process/license-rules.rst ++ ++for more details. ++ ++All contributions to the Linux Kernel are subject to this COPYING file. +diff --git a/support/bundled/linux/LICENSES/exceptions/Linux-syscall-note b/support/bundled/linux/LICENSES/exceptions/Linux-syscall-note +new file mode 100644 +index 0000000000000000..adbe756a05027794 +--- /dev/null ++++ b/support/bundled/linux/LICENSES/exceptions/Linux-syscall-note +@@ -0,0 +1,24 @@ ++SPDX-Exception-Identifier: Linux-syscall-note ++SPDX-URL: https://spdx.org/licenses/Linux-syscall-note.html ++SPDX-Licenses: GPL-2.0, GPL-2.0+, GPL-1.0+, LGPL-2.0, LGPL-2.0+, LGPL-2.1, LGPL-2.1+, GPL-2.0-only, GPL-2.0-or-later ++Usage-Guide: ++ This exception is used together with one of the above SPDX-Licenses ++ to mark user space API (uapi) header files so they can be included ++ into non GPL compliant user space application code. ++ To use this exception add it with the keyword WITH to one of the ++ identifiers in the SPDX-Licenses tag: ++ SPDX-License-Identifier: WITH Linux-syscall-note ++License-Text: ++ ++ NOTE! This copyright does *not* cover user programs that use kernel ++ services by normal system calls - this is merely considered normal use ++ of the kernel, and does *not* fall under the heading of "derived work". ++ Also note that the GPL below is copyrighted by the Free Software ++ Foundation, but the instance of code that it refers to (the Linux ++ kernel) is copyrighted by me and others who actually wrote it. ++ ++ Also note that the only valid version of the GPL as far as the kernel ++ is concerned is _this_ particular version of the license (ie v2, not ++ v2.2 or v3.x or whatever), unless explicitly otherwise stated. ++ ++ Linus Torvalds +diff --git a/support/bundled/linux/LICENSES/preferred/GPL-2.0 b/support/bundled/linux/LICENSES/preferred/GPL-2.0 +new file mode 100644 +index 0000000000000000..ff0812fd89cc41fc +--- /dev/null ++++ b/support/bundled/linux/LICENSES/preferred/GPL-2.0 +@@ -0,0 +1,359 @@ ++Valid-License-Identifier: GPL-2.0 ++Valid-License-Identifier: GPL-2.0-only ++Valid-License-Identifier: GPL-2.0+ ++Valid-License-Identifier: GPL-2.0-or-later ++SPDX-URL: https://spdx.org/licenses/GPL-2.0.html ++Usage-Guide: ++ To use this license in source code, put one of the following SPDX ++ tag/value pairs into a comment according to the placement ++ guidelines in the licensing rules documentation. ++ For 'GNU General Public License (GPL) version 2 only' use: ++ SPDX-License-Identifier: GPL-2.0 ++ or ++ SPDX-License-Identifier: GPL-2.0-only ++ For 'GNU General Public License (GPL) version 2 or any later version' use: ++ SPDX-License-Identifier: GPL-2.0+ ++ or ++ SPDX-License-Identifier: GPL-2.0-or-later ++License-Text: ++ ++ GNU GENERAL PUBLIC LICENSE ++ Version 2, June 1991 ++ ++ Copyright (C) 1989, 1991 Free Software Foundation, Inc. ++ 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ Everyone is permitted to copy and distribute verbatim copies ++ of this license document, but changing it is not allowed. ++ ++ Preamble ++ ++ The licenses for most software are designed to take away your ++freedom to share and change it. By contrast, the GNU General Public ++License is intended to guarantee your freedom to share and change free ++software--to make sure the software is free for all its users. This ++General Public License applies to most of the Free Software ++Foundation's software and to any other program whose authors commit to ++using it. (Some other Free Software Foundation software is covered by ++the GNU Library General Public License instead.) You can apply it to ++your programs, too. ++ ++ When we speak of free software, we are referring to freedom, not ++price. Our General Public Licenses are designed to make sure that you ++have the freedom to distribute copies of free software (and charge for ++this service if you wish), that you receive source code or can get it ++if you want it, that you can change the software or use pieces of it ++in new free programs; and that you know you can do these things. ++ ++ To protect your rights, we need to make restrictions that forbid ++anyone to deny you these rights or to ask you to surrender the rights. ++These restrictions translate to certain responsibilities for you if you ++distribute copies of the software, or if you modify it. ++ ++ For example, if you distribute copies of such a program, whether ++gratis or for a fee, you must give the recipients all the rights that ++you have. You must make sure that they, too, receive or can get the ++source code. And you must show them these terms so they know their ++rights. ++ ++ We protect your rights with two steps: (1) copyright the software, and ++(2) offer you this license which gives you legal permission to copy, ++distribute and/or modify the software. ++ ++ Also, for each author's protection and ours, we want to make certain ++that everyone understands that there is no warranty for this free ++software. If the software is modified by someone else and passed on, we ++want its recipients to know that what they have is not the original, so ++that any problems introduced by others will not reflect on the original ++authors' reputations. ++ ++ Finally, any free program is threatened constantly by software ++patents. We wish to avoid the danger that redistributors of a free ++program will individually obtain patent licenses, in effect making the ++program proprietary. To prevent this, we have made it clear that any ++patent must be licensed for everyone's free use or not licensed at all. ++ ++ The precise terms and conditions for copying, distribution and ++modification follow. ++ ++ GNU GENERAL PUBLIC LICENSE ++ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION ++ ++ 0. This License applies to any program or other work which contains ++a notice placed by the copyright holder saying it may be distributed ++under the terms of this General Public License. The "Program", below, ++refers to any such program or work, and a "work based on the Program" ++means either the Program or any derivative work under copyright law: ++that is to say, a work containing the Program or a portion of it, ++either verbatim or with modifications and/or translated into another ++language. (Hereinafter, translation is included without limitation in ++the term "modification".) Each licensee is addressed as "you". ++ ++Activities other than copying, distribution and modification are not ++covered by this License; they are outside its scope. The act of ++running the Program is not restricted, and the output from the Program ++is covered only if its contents constitute a work based on the ++Program (independent of having been made by running the Program). ++Whether that is true depends on what the Program does. ++ ++ 1. You may copy and distribute verbatim copies of the Program's ++source code as you receive it, in any medium, provided that you ++conspicuously and appropriately publish on each copy an appropriate ++copyright notice and disclaimer of warranty; keep intact all the ++notices that refer to this License and to the absence of any warranty; ++and give any other recipients of the Program a copy of this License ++along with the Program. ++ ++You may charge a fee for the physical act of transferring a copy, and ++you may at your option offer warranty protection in exchange for a fee. ++ ++ 2. You may modify your copy or copies of the Program or any portion ++of it, thus forming a work based on the Program, and copy and ++distribute such modifications or work under the terms of Section 1 ++above, provided that you also meet all of these conditions: ++ ++ a) You must cause the modified files to carry prominent notices ++ stating that you changed the files and the date of any change. ++ ++ b) You must cause any work that you distribute or publish, that in ++ whole or in part contains or is derived from the Program or any ++ part thereof, to be licensed as a whole at no charge to all third ++ parties under the terms of this License. ++ ++ c) If the modified program normally reads commands interactively ++ when run, you must cause it, when started running for such ++ interactive use in the most ordinary way, to print or display an ++ announcement including an appropriate copyright notice and a ++ notice that there is no warranty (or else, saying that you provide ++ a warranty) and that users may redistribute the program under ++ these conditions, and telling the user how to view a copy of this ++ License. (Exception: if the Program itself is interactive but ++ does not normally print such an announcement, your work based on ++ the Program is not required to print an announcement.) ++ ++These requirements apply to the modified work as a whole. If ++identifiable sections of that work are not derived from the Program, ++and can be reasonably considered independent and separate works in ++themselves, then this License, and its terms, do not apply to those ++sections when you distribute them as separate works. But when you ++distribute the same sections as part of a whole which is a work based ++on the Program, the distribution of the whole must be on the terms of ++this License, whose permissions for other licensees extend to the ++entire whole, and thus to each and every part regardless of who wrote it. ++ ++Thus, it is not the intent of this section to claim rights or contest ++your rights to work written entirely by you; rather, the intent is to ++exercise the right to control the distribution of derivative or ++collective works based on the Program. ++ ++In addition, mere aggregation of another work not based on the Program ++with the Program (or with a work based on the Program) on a volume of ++a storage or distribution medium does not bring the other work under ++the scope of this License. ++ ++ 3. You may copy and distribute the Program (or a work based on it, ++under Section 2) in object code or executable form under the terms of ++Sections 1 and 2 above provided that you also do one of the following: ++ ++ a) Accompany it with the complete corresponding machine-readable ++ source code, which must be distributed under the terms of Sections ++ 1 and 2 above on a medium customarily used for software interchange; or, ++ ++ b) Accompany it with a written offer, valid for at least three ++ years, to give any third party, for a charge no more than your ++ cost of physically performing source distribution, a complete ++ machine-readable copy of the corresponding source code, to be ++ distributed under the terms of Sections 1 and 2 above on a medium ++ customarily used for software interchange; or, ++ ++ c) Accompany it with the information you received as to the offer ++ to distribute corresponding source code. (This alternative is ++ allowed only for noncommercial distribution and only if you ++ received the program in object code or executable form with such ++ an offer, in accord with Subsection b above.) ++ ++The source code for a work means the preferred form of the work for ++making modifications to it. For an executable work, complete source ++code means all the source code for all modules it contains, plus any ++associated interface definition files, plus the scripts used to ++control compilation and installation of the executable. However, as a ++special exception, the source code distributed need not include ++anything that is normally distributed (in either source or binary ++form) with the major components (compiler, kernel, and so on) of the ++operating system on which the executable runs, unless that component ++itself accompanies the executable. ++ ++If distribution of executable or object code is made by offering ++access to copy from a designated place, then offering equivalent ++access to copy the source code from the same place counts as ++distribution of the source code, even though third parties are not ++compelled to copy the source along with the object code. ++ ++ 4. You may not copy, modify, sublicense, or distribute the Program ++except as expressly provided under this License. Any attempt ++otherwise to copy, modify, sublicense or distribute the Program is ++void, and will automatically terminate your rights under this License. ++However, parties who have received copies, or rights, from you under ++this License will not have their licenses terminated so long as such ++parties remain in full compliance. ++ ++ 5. You are not required to accept this License, since you have not ++signed it. However, nothing else grants you permission to modify or ++distribute the Program or its derivative works. These actions are ++prohibited by law if you do not accept this License. Therefore, by ++modifying or distributing the Program (or any work based on the ++Program), you indicate your acceptance of this License to do so, and ++all its terms and conditions for copying, distributing or modifying ++the Program or works based on it. ++ ++ 6. Each time you redistribute the Program (or any work based on the ++Program), the recipient automatically receives a license from the ++original licensor to copy, distribute or modify the Program subject to ++these terms and conditions. You may not impose any further ++restrictions on the recipients' exercise of the rights granted herein. ++You are not responsible for enforcing compliance by third parties to ++this License. ++ ++ 7. If, as a consequence of a court judgment or allegation of patent ++infringement or for any other reason (not limited to patent issues), ++conditions are imposed on you (whether by court order, agreement or ++otherwise) that contradict the conditions of this License, they do not ++excuse you from the conditions of this License. If you cannot ++distribute so as to satisfy simultaneously your obligations under this ++License and any other pertinent obligations, then as a consequence you ++may not distribute the Program at all. For example, if a patent ++license would not permit royalty-free redistribution of the Program by ++all those who receive copies directly or indirectly through you, then ++the only way you could satisfy both it and this License would be to ++refrain entirely from distribution of the Program. ++ ++If any portion of this section is held invalid or unenforceable under ++any particular circumstance, the balance of the section is intended to ++apply and the section as a whole is intended to apply in other ++circumstances. ++ ++It is not the purpose of this section to induce you to infringe any ++patents or other property right claims or to contest validity of any ++such claims; this section has the sole purpose of protecting the ++integrity of the free software distribution system, which is ++implemented by public license practices. Many people have made ++generous contributions to the wide range of software distributed ++through that system in reliance on consistent application of that ++system; it is up to the author/donor to decide if he or she is willing ++to distribute software through any other system and a licensee cannot ++impose that choice. ++ ++This section is intended to make thoroughly clear what is believed to ++be a consequence of the rest of this License. ++ ++ 8. If the distribution and/or use of the Program is restricted in ++certain countries either by patents or by copyrighted interfaces, the ++original copyright holder who places the Program under this License ++may add an explicit geographical distribution limitation excluding ++those countries, so that distribution is permitted only in or among ++countries not thus excluded. In such case, this License incorporates ++the limitation as if written in the body of this License. ++ ++ 9. The Free Software Foundation may publish revised and/or new versions ++of the General Public License from time to time. Such new versions will ++be similar in spirit to the present version, but may differ in detail to ++address new problems or concerns. ++ ++Each version is given a distinguishing version number. If the Program ++specifies a version number of this License which applies to it and "any ++later version", you have the option of following the terms and conditions ++either of that version or of any later version published by the Free ++Software Foundation. If the Program does not specify a version number of ++this License, you may choose any version ever published by the Free Software ++Foundation. ++ ++ 10. If you wish to incorporate parts of the Program into other free ++programs whose distribution conditions are different, write to the author ++to ask for permission. For software which is copyrighted by the Free ++Software Foundation, write to the Free Software Foundation; we sometimes ++make exceptions for this. Our decision will be guided by the two goals ++of preserving the free status of all derivatives of our free software and ++of promoting the sharing and reuse of software generally. ++ ++ NO WARRANTY ++ ++ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY ++FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN ++OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES ++PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED ++OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF ++MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS ++TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE ++PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, ++REPAIR OR CORRECTION. ++ ++ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING ++WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR ++REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, ++INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING ++OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED ++TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY ++YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER ++PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE ++POSSIBILITY OF SUCH DAMAGES. ++ ++ END OF TERMS AND CONDITIONS ++ ++ How to Apply These Terms to Your New Programs ++ ++ If you develop a new program, and you want it to be of the greatest ++possible use to the public, the best way to achieve this is to make it ++free software which everyone can redistribute and change under these terms. ++ ++ To do so, attach the following notices to the program. It is safest ++to attach them to the start of each source file to most effectively ++convey the exclusion of warranty; and each file should have at least ++the "copyright" line and a pointer to where the full notice is found. ++ ++ ++ Copyright (C) ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation; either version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, write to the Free Software ++ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ ++ ++Also add information on how to contact you by electronic and paper mail. ++ ++If the program is interactive, make it output a short notice like this ++when it starts in an interactive mode: ++ ++ Gnomovision version 69, Copyright (C) year name of author ++ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. ++ This is free software, and you are welcome to redistribute it ++ under certain conditions; type `show c' for details. ++ ++The hypothetical commands `show w' and `show c' should show the appropriate ++parts of the General Public License. Of course, the commands you use may ++be called something other than `show w' and `show c'; they could even be ++mouse-clicks or menu items--whatever suits your program. ++ ++You should also get your employer (if you work as a programmer) or your ++school, if any, to sign a "copyright disclaimer" for the program, if ++necessary. Here is a sample; alter the names: ++ ++ Yoyodyne, Inc., hereby disclaims all copyright interest in the program ++ `Gnomovision' (which makes passes at compilers) written by James Hacker. ++ ++ , 1 April 1989 ++ Ty Coon, President of Vice ++ ++This General Public License does not permit incorporating your program into ++proprietary programs. If your program is a subroutine library, you may ++consider it more useful to permit linking proprietary applications with the ++library. If this is what you want to do, use the GNU Library General ++Public License instead of this License. +diff --git a/support/bundled/linux/include/uapi/linux/fuse.h b/support/bundled/linux/include/uapi/linux/fuse.h +new file mode 100644 +index 0000000000000000..d08b99d60f6fd6d0 +--- /dev/null ++++ b/support/bundled/linux/include/uapi/linux/fuse.h +@@ -0,0 +1,1189 @@ ++/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-2-Clause) */ ++/* ++ This file defines the kernel interface of FUSE ++ Copyright (C) 2001-2008 Miklos Szeredi ++ ++ This program can be distributed under the terms of the GNU GPL. ++ See the file COPYING. ++ ++ This -- and only this -- header file may also be distributed under ++ the terms of the BSD Licence as follows: ++ ++ Copyright (C) 2001-2007 Miklos Szeredi. All rights reserved. ++ ++ Redistribution and use in source and binary forms, with or without ++ modification, are permitted provided that the following conditions ++ are met: ++ 1. Redistributions of source code must retain the above copyright ++ notice, this list of conditions and the following disclaimer. ++ 2. Redistributions in binary form must reproduce the above copyright ++ notice, this list of conditions and the following disclaimer in the ++ documentation and/or other materials provided with the distribution. ++ ++ THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND ++ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ++ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ++ ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE ++ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ++ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ++ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ++ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ++ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ++ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ++ SUCH DAMAGE. ++*/ ++ ++/* ++ * This file defines the kernel interface of FUSE ++ * ++ * Protocol changelog: ++ * ++ * 7.1: ++ * - add the following messages: ++ * FUSE_SETATTR, FUSE_SYMLINK, FUSE_MKNOD, FUSE_MKDIR, FUSE_UNLINK, ++ * FUSE_RMDIR, FUSE_RENAME, FUSE_LINK, FUSE_OPEN, FUSE_READ, FUSE_WRITE, ++ * FUSE_RELEASE, FUSE_FSYNC, FUSE_FLUSH, FUSE_SETXATTR, FUSE_GETXATTR, ++ * FUSE_LISTXATTR, FUSE_REMOVEXATTR, FUSE_OPENDIR, FUSE_READDIR, ++ * FUSE_RELEASEDIR ++ * - add padding to messages to accommodate 32-bit servers on 64-bit kernels ++ * ++ * 7.2: ++ * - add FOPEN_DIRECT_IO and FOPEN_KEEP_CACHE flags ++ * - add FUSE_FSYNCDIR message ++ * ++ * 7.3: ++ * - add FUSE_ACCESS message ++ * - add FUSE_CREATE message ++ * - add filehandle to fuse_setattr_in ++ * ++ * 7.4: ++ * - add frsize to fuse_kstatfs ++ * - clean up request size limit checking ++ * ++ * 7.5: ++ * - add flags and max_write to fuse_init_out ++ * ++ * 7.6: ++ * - add max_readahead to fuse_init_in and fuse_init_out ++ * ++ * 7.7: ++ * - add FUSE_INTERRUPT message ++ * - add POSIX file lock support ++ * ++ * 7.8: ++ * - add lock_owner and flags fields to fuse_release_in ++ * - add FUSE_BMAP message ++ * - add FUSE_DESTROY message ++ * ++ * 7.9: ++ * - new fuse_getattr_in input argument of GETATTR ++ * - add lk_flags in fuse_lk_in ++ * - add lock_owner field to fuse_setattr_in, fuse_read_in and fuse_write_in ++ * - add blksize field to fuse_attr ++ * - add file flags field to fuse_read_in and fuse_write_in ++ * - Add ATIME_NOW and MTIME_NOW flags to fuse_setattr_in ++ * ++ * 7.10 ++ * - add nonseekable open flag ++ * ++ * 7.11 ++ * - add IOCTL message ++ * - add unsolicited notification support ++ * - add POLL message and NOTIFY_POLL notification ++ * ++ * 7.12 ++ * - add umask flag to input argument of create, mknod and mkdir ++ * - add notification messages for invalidation of inodes and ++ * directory entries ++ * ++ * 7.13 ++ * - make max number of background requests and congestion threshold ++ * tunables ++ * ++ * 7.14 ++ * - add splice support to fuse device ++ * ++ * 7.15 ++ * - add store notify ++ * - add retrieve notify ++ * ++ * 7.16 ++ * - add BATCH_FORGET request ++ * - FUSE_IOCTL_UNRESTRICTED shall now return with array of 'struct ++ * fuse_ioctl_iovec' instead of ambiguous 'struct iovec' ++ * - add FUSE_IOCTL_32BIT flag ++ * ++ * 7.17 ++ * - add FUSE_FLOCK_LOCKS and FUSE_RELEASE_FLOCK_UNLOCK ++ * ++ * 7.18 ++ * - add FUSE_IOCTL_DIR flag ++ * - add FUSE_NOTIFY_DELETE ++ * ++ * 7.19 ++ * - add FUSE_FALLOCATE ++ * ++ * 7.20 ++ * - add FUSE_AUTO_INVAL_DATA ++ * ++ * 7.21 ++ * - add FUSE_READDIRPLUS ++ * - send the requested events in POLL request ++ * ++ * 7.22 ++ * - add FUSE_ASYNC_DIO ++ * ++ * 7.23 ++ * - add FUSE_WRITEBACK_CACHE ++ * - add time_gran to fuse_init_out ++ * - add reserved space to fuse_init_out ++ * - add FATTR_CTIME ++ * - add ctime and ctimensec to fuse_setattr_in ++ * - add FUSE_RENAME2 request ++ * - add FUSE_NO_OPEN_SUPPORT flag ++ * ++ * 7.24 ++ * - add FUSE_LSEEK for SEEK_HOLE and SEEK_DATA support ++ * ++ * 7.25 ++ * - add FUSE_PARALLEL_DIROPS ++ * ++ * 7.26 ++ * - add FUSE_HANDLE_KILLPRIV ++ * - add FUSE_POSIX_ACL ++ * ++ * 7.27 ++ * - add FUSE_ABORT_ERROR ++ * ++ * 7.28 ++ * - add FUSE_COPY_FILE_RANGE ++ * - add FOPEN_CACHE_DIR ++ * - add FUSE_MAX_PAGES, add max_pages to init_out ++ * - add FUSE_CACHE_SYMLINKS ++ * ++ * 7.29 ++ * - add FUSE_NO_OPENDIR_SUPPORT flag ++ * ++ * 7.30 ++ * - add FUSE_EXPLICIT_INVAL_DATA ++ * - add FUSE_IOCTL_COMPAT_X32 ++ * ++ * 7.31 ++ * - add FUSE_WRITE_KILL_PRIV flag ++ * - add FUSE_SETUPMAPPING and FUSE_REMOVEMAPPING ++ * - add map_alignment to fuse_init_out, add FUSE_MAP_ALIGNMENT flag ++ * ++ * 7.32 ++ * - add flags to fuse_attr, add FUSE_ATTR_SUBMOUNT, add FUSE_SUBMOUNTS ++ * ++ * 7.33 ++ * - add FUSE_HANDLE_KILLPRIV_V2, FUSE_WRITE_KILL_SUIDGID, FATTR_KILL_SUIDGID ++ * - add FUSE_OPEN_KILL_SUIDGID ++ * - extend fuse_setxattr_in, add FUSE_SETXATTR_EXT ++ * - add FUSE_SETXATTR_ACL_KILL_SGID ++ * ++ * 7.34 ++ * - add FUSE_SYNCFS ++ * ++ * 7.35 ++ * - add FOPEN_NOFLUSH ++ * ++ * 7.36 ++ * - extend fuse_init_in with reserved fields, add FUSE_INIT_EXT init flag ++ * - add flags2 to fuse_init_in and fuse_init_out ++ * - add FUSE_SECURITY_CTX init flag ++ * - add security context to create, mkdir, symlink, and mknod requests ++ * - add FUSE_HAS_INODE_DAX, FUSE_ATTR_DAX ++ * ++ * 7.37 ++ * - add FUSE_TMPFILE ++ * ++ * 7.38 ++ * - add FUSE_EXPIRE_ONLY flag to fuse_notify_inval_entry ++ * - add FOPEN_PARALLEL_DIRECT_WRITES ++ * - add total_extlen to fuse_in_header ++ * - add FUSE_MAX_NR_SECCTX ++ * - add extension header ++ * - add FUSE_EXT_GROUPS ++ * - add FUSE_CREATE_SUPP_GROUP ++ * - add FUSE_HAS_EXPIRE_ONLY ++ * ++ * 7.39 ++ * - add FUSE_DIRECT_IO_ALLOW_MMAP ++ * - add FUSE_STATX and related structures ++ * ++ * 7.40 ++ * - add max_stack_depth to fuse_init_out, add FUSE_PASSTHROUGH init flag ++ * - add backing_id to fuse_open_out, add FOPEN_PASSTHROUGH open flag ++ * - add FUSE_NO_EXPORT_SUPPORT init flag ++ * - add FUSE_NOTIFY_RESEND, add FUSE_HAS_RESEND init flag ++ */ ++ ++#ifndef _LINUX_FUSE_H ++#define _LINUX_FUSE_H ++ ++#ifdef __KERNEL__ ++#include ++#else ++#include ++#endif ++ ++/* ++ * Version negotiation: ++ * ++ * Both the kernel and userspace send the version they support in the ++ * INIT request and reply respectively. ++ * ++ * If the major versions match then both shall use the smallest ++ * of the two minor versions for communication. ++ * ++ * If the kernel supports a larger major version, then userspace shall ++ * reply with the major version it supports, ignore the rest of the ++ * INIT message and expect a new INIT message from the kernel with a ++ * matching major version. ++ * ++ * If the library supports a larger major version, then it shall fall ++ * back to the major protocol version sent by the kernel for ++ * communication and reply with that major version (and an arbitrary ++ * supported minor version). ++ */ ++ ++/** Version number of this interface */ ++#define FUSE_KERNEL_VERSION 7 ++ ++/** Minor version number of this interface */ ++#define FUSE_KERNEL_MINOR_VERSION 40 ++ ++/** The node ID of the root inode */ ++#define FUSE_ROOT_ID 1 ++ ++/* Make sure all structures are padded to 64bit boundary, so 32bit ++ userspace works under 64bit kernels */ ++ ++struct fuse_attr { ++ uint64_t ino; ++ uint64_t size; ++ uint64_t blocks; ++ uint64_t atime; ++ uint64_t mtime; ++ uint64_t ctime; ++ uint32_t atimensec; ++ uint32_t mtimensec; ++ uint32_t ctimensec; ++ uint32_t mode; ++ uint32_t nlink; ++ uint32_t uid; ++ uint32_t gid; ++ uint32_t rdev; ++ uint32_t blksize; ++ uint32_t flags; ++}; ++ ++/* ++ * The following structures are bit-for-bit compatible with the statx(2) ABI in ++ * Linux. ++ */ ++struct fuse_sx_time { ++ int64_t tv_sec; ++ uint32_t tv_nsec; ++ int32_t __reserved; ++}; ++ ++struct fuse_statx { ++ uint32_t mask; ++ uint32_t blksize; ++ uint64_t attributes; ++ uint32_t nlink; ++ uint32_t uid; ++ uint32_t gid; ++ uint16_t mode; ++ uint16_t __spare0[1]; ++ uint64_t ino; ++ uint64_t size; ++ uint64_t blocks; ++ uint64_t attributes_mask; ++ struct fuse_sx_time atime; ++ struct fuse_sx_time btime; ++ struct fuse_sx_time ctime; ++ struct fuse_sx_time mtime; ++ uint32_t rdev_major; ++ uint32_t rdev_minor; ++ uint32_t dev_major; ++ uint32_t dev_minor; ++ uint64_t __spare2[14]; ++}; ++ ++struct fuse_kstatfs { ++ uint64_t blocks; ++ uint64_t bfree; ++ uint64_t bavail; ++ uint64_t files; ++ uint64_t ffree; ++ uint32_t bsize; ++ uint32_t namelen; ++ uint32_t frsize; ++ uint32_t padding; ++ uint32_t spare[6]; ++}; ++ ++struct fuse_file_lock { ++ uint64_t start; ++ uint64_t end; ++ uint32_t type; ++ uint32_t pid; /* tgid */ ++}; ++ ++/** ++ * Bitmasks for fuse_setattr_in.valid ++ */ ++#define FATTR_MODE (1 << 0) ++#define FATTR_UID (1 << 1) ++#define FATTR_GID (1 << 2) ++#define FATTR_SIZE (1 << 3) ++#define FATTR_ATIME (1 << 4) ++#define FATTR_MTIME (1 << 5) ++#define FATTR_FH (1 << 6) ++#define FATTR_ATIME_NOW (1 << 7) ++#define FATTR_MTIME_NOW (1 << 8) ++#define FATTR_LOCKOWNER (1 << 9) ++#define FATTR_CTIME (1 << 10) ++#define FATTR_KILL_SUIDGID (1 << 11) ++ ++/** ++ * Flags returned by the OPEN request ++ * ++ * FOPEN_DIRECT_IO: bypass page cache for this open file ++ * FOPEN_KEEP_CACHE: don't invalidate the data cache on open ++ * FOPEN_NONSEEKABLE: the file is not seekable ++ * FOPEN_CACHE_DIR: allow caching this directory ++ * FOPEN_STREAM: the file is stream-like (no file position at all) ++ * FOPEN_NOFLUSH: don't flush data cache on close (unless FUSE_WRITEBACK_CACHE) ++ * FOPEN_PARALLEL_DIRECT_WRITES: Allow concurrent direct writes on the same inode ++ * FOPEN_PASSTHROUGH: passthrough read/write io for this open file ++ */ ++#define FOPEN_DIRECT_IO (1 << 0) ++#define FOPEN_KEEP_CACHE (1 << 1) ++#define FOPEN_NONSEEKABLE (1 << 2) ++#define FOPEN_CACHE_DIR (1 << 3) ++#define FOPEN_STREAM (1 << 4) ++#define FOPEN_NOFLUSH (1 << 5) ++#define FOPEN_PARALLEL_DIRECT_WRITES (1 << 6) ++#define FOPEN_PASSTHROUGH (1 << 7) ++ ++/** ++ * INIT request/reply flags ++ * ++ * FUSE_ASYNC_READ: asynchronous read requests ++ * FUSE_POSIX_LOCKS: remote locking for POSIX file locks ++ * FUSE_FILE_OPS: kernel sends file handle for fstat, etc... (not yet supported) ++ * FUSE_ATOMIC_O_TRUNC: handles the O_TRUNC open flag in the filesystem ++ * FUSE_EXPORT_SUPPORT: filesystem handles lookups of "." and ".." ++ * FUSE_BIG_WRITES: filesystem can handle write size larger than 4kB ++ * FUSE_DONT_MASK: don't apply umask to file mode on create operations ++ * FUSE_SPLICE_WRITE: kernel supports splice write on the device ++ * FUSE_SPLICE_MOVE: kernel supports splice move on the device ++ * FUSE_SPLICE_READ: kernel supports splice read on the device ++ * FUSE_FLOCK_LOCKS: remote locking for BSD style file locks ++ * FUSE_HAS_IOCTL_DIR: kernel supports ioctl on directories ++ * FUSE_AUTO_INVAL_DATA: automatically invalidate cached pages ++ * FUSE_DO_READDIRPLUS: do READDIRPLUS (READDIR+LOOKUP in one) ++ * FUSE_READDIRPLUS_AUTO: adaptive readdirplus ++ * FUSE_ASYNC_DIO: asynchronous direct I/O submission ++ * FUSE_WRITEBACK_CACHE: use writeback cache for buffered writes ++ * FUSE_NO_OPEN_SUPPORT: kernel supports zero-message opens ++ * FUSE_PARALLEL_DIROPS: allow parallel lookups and readdir ++ * FUSE_HANDLE_KILLPRIV: fs handles killing suid/sgid/cap on write/chown/trunc ++ * FUSE_POSIX_ACL: filesystem supports posix acls ++ * FUSE_ABORT_ERROR: reading the device after abort returns ECONNABORTED ++ * FUSE_MAX_PAGES: init_out.max_pages contains the max number of req pages ++ * FUSE_CACHE_SYMLINKS: cache READLINK responses ++ * FUSE_NO_OPENDIR_SUPPORT: kernel supports zero-message opendir ++ * FUSE_EXPLICIT_INVAL_DATA: only invalidate cached pages on explicit request ++ * FUSE_MAP_ALIGNMENT: init_out.map_alignment contains log2(byte alignment) for ++ * foffset and moffset fields in struct ++ * fuse_setupmapping_out and fuse_removemapping_one. ++ * FUSE_SUBMOUNTS: kernel supports auto-mounting directory submounts ++ * FUSE_HANDLE_KILLPRIV_V2: fs kills suid/sgid/cap on write/chown/trunc. ++ * Upon write/truncate suid/sgid is only killed if caller ++ * does not have CAP_FSETID. Additionally upon ++ * write/truncate sgid is killed only if file has group ++ * execute permission. (Same as Linux VFS behavior). ++ * FUSE_SETXATTR_EXT: Server supports extended struct fuse_setxattr_in ++ * FUSE_INIT_EXT: extended fuse_init_in request ++ * FUSE_INIT_RESERVED: reserved, do not use ++ * FUSE_SECURITY_CTX: add security context to create, mkdir, symlink, and ++ * mknod ++ * FUSE_HAS_INODE_DAX: use per inode DAX ++ * FUSE_CREATE_SUPP_GROUP: add supplementary group info to create, mkdir, ++ * symlink and mknod (single group that matches parent) ++ * FUSE_HAS_EXPIRE_ONLY: kernel supports expiry-only entry invalidation ++ * FUSE_DIRECT_IO_ALLOW_MMAP: allow shared mmap in FOPEN_DIRECT_IO mode. ++ * FUSE_NO_EXPORT_SUPPORT: explicitly disable export support ++ * FUSE_HAS_RESEND: kernel supports resending pending requests, and the high bit ++ * of the request ID indicates resend requests ++ */ ++#define FUSE_ASYNC_READ (1 << 0) ++#define FUSE_POSIX_LOCKS (1 << 1) ++#define FUSE_FILE_OPS (1 << 2) ++#define FUSE_ATOMIC_O_TRUNC (1 << 3) ++#define FUSE_EXPORT_SUPPORT (1 << 4) ++#define FUSE_BIG_WRITES (1 << 5) ++#define FUSE_DONT_MASK (1 << 6) ++#define FUSE_SPLICE_WRITE (1 << 7) ++#define FUSE_SPLICE_MOVE (1 << 8) ++#define FUSE_SPLICE_READ (1 << 9) ++#define FUSE_FLOCK_LOCKS (1 << 10) ++#define FUSE_HAS_IOCTL_DIR (1 << 11) ++#define FUSE_AUTO_INVAL_DATA (1 << 12) ++#define FUSE_DO_READDIRPLUS (1 << 13) ++#define FUSE_READDIRPLUS_AUTO (1 << 14) ++#define FUSE_ASYNC_DIO (1 << 15) ++#define FUSE_WRITEBACK_CACHE (1 << 16) ++#define FUSE_NO_OPEN_SUPPORT (1 << 17) ++#define FUSE_PARALLEL_DIROPS (1 << 18) ++#define FUSE_HANDLE_KILLPRIV (1 << 19) ++#define FUSE_POSIX_ACL (1 << 20) ++#define FUSE_ABORT_ERROR (1 << 21) ++#define FUSE_MAX_PAGES (1 << 22) ++#define FUSE_CACHE_SYMLINKS (1 << 23) ++#define FUSE_NO_OPENDIR_SUPPORT (1 << 24) ++#define FUSE_EXPLICIT_INVAL_DATA (1 << 25) ++#define FUSE_MAP_ALIGNMENT (1 << 26) ++#define FUSE_SUBMOUNTS (1 << 27) ++#define FUSE_HANDLE_KILLPRIV_V2 (1 << 28) ++#define FUSE_SETXATTR_EXT (1 << 29) ++#define FUSE_INIT_EXT (1 << 30) ++#define FUSE_INIT_RESERVED (1 << 31) ++/* bits 32..63 get shifted down 32 bits into the flags2 field */ ++#define FUSE_SECURITY_CTX (1ULL << 32) ++#define FUSE_HAS_INODE_DAX (1ULL << 33) ++#define FUSE_CREATE_SUPP_GROUP (1ULL << 34) ++#define FUSE_HAS_EXPIRE_ONLY (1ULL << 35) ++#define FUSE_DIRECT_IO_ALLOW_MMAP (1ULL << 36) ++#define FUSE_PASSTHROUGH (1ULL << 37) ++#define FUSE_NO_EXPORT_SUPPORT (1ULL << 38) ++#define FUSE_HAS_RESEND (1ULL << 39) ++ ++/* Obsolete alias for FUSE_DIRECT_IO_ALLOW_MMAP */ ++#define FUSE_DIRECT_IO_RELAX FUSE_DIRECT_IO_ALLOW_MMAP ++ ++/** ++ * CUSE INIT request/reply flags ++ * ++ * CUSE_UNRESTRICTED_IOCTL: use unrestricted ioctl ++ */ ++#define CUSE_UNRESTRICTED_IOCTL (1 << 0) ++ ++/** ++ * Release flags ++ */ ++#define FUSE_RELEASE_FLUSH (1 << 0) ++#define FUSE_RELEASE_FLOCK_UNLOCK (1 << 1) ++ ++/** ++ * Getattr flags ++ */ ++#define FUSE_GETATTR_FH (1 << 0) ++ ++/** ++ * Lock flags ++ */ ++#define FUSE_LK_FLOCK (1 << 0) ++ ++/** ++ * WRITE flags ++ * ++ * FUSE_WRITE_CACHE: delayed write from page cache, file handle is guessed ++ * FUSE_WRITE_LOCKOWNER: lock_owner field is valid ++ * FUSE_WRITE_KILL_SUIDGID: kill suid and sgid bits ++ */ ++#define FUSE_WRITE_CACHE (1 << 0) ++#define FUSE_WRITE_LOCKOWNER (1 << 1) ++#define FUSE_WRITE_KILL_SUIDGID (1 << 2) ++ ++/* Obsolete alias; this flag implies killing suid/sgid only. */ ++#define FUSE_WRITE_KILL_PRIV FUSE_WRITE_KILL_SUIDGID ++ ++/** ++ * Read flags ++ */ ++#define FUSE_READ_LOCKOWNER (1 << 1) ++ ++/** ++ * Ioctl flags ++ * ++ * FUSE_IOCTL_COMPAT: 32bit compat ioctl on 64bit machine ++ * FUSE_IOCTL_UNRESTRICTED: not restricted to well-formed ioctls, retry allowed ++ * FUSE_IOCTL_RETRY: retry with new iovecs ++ * FUSE_IOCTL_32BIT: 32bit ioctl ++ * FUSE_IOCTL_DIR: is a directory ++ * FUSE_IOCTL_COMPAT_X32: x32 compat ioctl on 64bit machine (64bit time_t) ++ * ++ * FUSE_IOCTL_MAX_IOV: maximum of in_iovecs + out_iovecs ++ */ ++#define FUSE_IOCTL_COMPAT (1 << 0) ++#define FUSE_IOCTL_UNRESTRICTED (1 << 1) ++#define FUSE_IOCTL_RETRY (1 << 2) ++#define FUSE_IOCTL_32BIT (1 << 3) ++#define FUSE_IOCTL_DIR (1 << 4) ++#define FUSE_IOCTL_COMPAT_X32 (1 << 5) ++ ++#define FUSE_IOCTL_MAX_IOV 256 ++ ++/** ++ * Poll flags ++ * ++ * FUSE_POLL_SCHEDULE_NOTIFY: request poll notify ++ */ ++#define FUSE_POLL_SCHEDULE_NOTIFY (1 << 0) ++ ++/** ++ * Fsync flags ++ * ++ * FUSE_FSYNC_FDATASYNC: Sync data only, not metadata ++ */ ++#define FUSE_FSYNC_FDATASYNC (1 << 0) ++ ++/** ++ * fuse_attr flags ++ * ++ * FUSE_ATTR_SUBMOUNT: Object is a submount root ++ * FUSE_ATTR_DAX: Enable DAX for this file in per inode DAX mode ++ */ ++#define FUSE_ATTR_SUBMOUNT (1 << 0) ++#define FUSE_ATTR_DAX (1 << 1) ++ ++/** ++ * Open flags ++ * FUSE_OPEN_KILL_SUIDGID: Kill suid and sgid if executable ++ */ ++#define FUSE_OPEN_KILL_SUIDGID (1 << 0) ++ ++/** ++ * setxattr flags ++ * FUSE_SETXATTR_ACL_KILL_SGID: Clear SGID when system.posix_acl_access is set ++ */ ++#define FUSE_SETXATTR_ACL_KILL_SGID (1 << 0) ++ ++/** ++ * notify_inval_entry flags ++ * FUSE_EXPIRE_ONLY ++ */ ++#define FUSE_EXPIRE_ONLY (1 << 0) ++ ++/** ++ * extension type ++ * FUSE_MAX_NR_SECCTX: maximum value of &fuse_secctx_header.nr_secctx ++ * FUSE_EXT_GROUPS: &fuse_supp_groups extension ++ */ ++enum fuse_ext_type { ++ /* Types 0..31 are reserved for fuse_secctx_header */ ++ FUSE_MAX_NR_SECCTX = 31, ++ FUSE_EXT_GROUPS = 32, ++}; ++ ++enum fuse_opcode { ++ FUSE_LOOKUP = 1, ++ FUSE_FORGET = 2, /* no reply */ ++ FUSE_GETATTR = 3, ++ FUSE_SETATTR = 4, ++ FUSE_READLINK = 5, ++ FUSE_SYMLINK = 6, ++ FUSE_MKNOD = 8, ++ FUSE_MKDIR = 9, ++ FUSE_UNLINK = 10, ++ FUSE_RMDIR = 11, ++ FUSE_RENAME = 12, ++ FUSE_LINK = 13, ++ FUSE_OPEN = 14, ++ FUSE_READ = 15, ++ FUSE_WRITE = 16, ++ FUSE_STATFS = 17, ++ FUSE_RELEASE = 18, ++ FUSE_FSYNC = 20, ++ FUSE_SETXATTR = 21, ++ FUSE_GETXATTR = 22, ++ FUSE_LISTXATTR = 23, ++ FUSE_REMOVEXATTR = 24, ++ FUSE_FLUSH = 25, ++ FUSE_INIT = 26, ++ FUSE_OPENDIR = 27, ++ FUSE_READDIR = 28, ++ FUSE_RELEASEDIR = 29, ++ FUSE_FSYNCDIR = 30, ++ FUSE_GETLK = 31, ++ FUSE_SETLK = 32, ++ FUSE_SETLKW = 33, ++ FUSE_ACCESS = 34, ++ FUSE_CREATE = 35, ++ FUSE_INTERRUPT = 36, ++ FUSE_BMAP = 37, ++ FUSE_DESTROY = 38, ++ FUSE_IOCTL = 39, ++ FUSE_POLL = 40, ++ FUSE_NOTIFY_REPLY = 41, ++ FUSE_BATCH_FORGET = 42, ++ FUSE_FALLOCATE = 43, ++ FUSE_READDIRPLUS = 44, ++ FUSE_RENAME2 = 45, ++ FUSE_LSEEK = 46, ++ FUSE_COPY_FILE_RANGE = 47, ++ FUSE_SETUPMAPPING = 48, ++ FUSE_REMOVEMAPPING = 49, ++ FUSE_SYNCFS = 50, ++ FUSE_TMPFILE = 51, ++ FUSE_STATX = 52, ++ ++ /* CUSE specific operations */ ++ CUSE_INIT = 4096, ++ ++ /* Reserved opcodes: helpful to detect structure endian-ness */ ++ CUSE_INIT_BSWAP_RESERVED = 1048576, /* CUSE_INIT << 8 */ ++ FUSE_INIT_BSWAP_RESERVED = 436207616, /* FUSE_INIT << 24 */ ++}; ++ ++enum fuse_notify_code { ++ FUSE_NOTIFY_POLL = 1, ++ FUSE_NOTIFY_INVAL_INODE = 2, ++ FUSE_NOTIFY_INVAL_ENTRY = 3, ++ FUSE_NOTIFY_STORE = 4, ++ FUSE_NOTIFY_RETRIEVE = 5, ++ FUSE_NOTIFY_DELETE = 6, ++ FUSE_NOTIFY_RESEND = 7, ++ FUSE_NOTIFY_CODE_MAX, ++}; ++ ++/* The read buffer is required to be at least 8k, but may be much larger */ ++#define FUSE_MIN_READ_BUFFER 8192 ++ ++#define FUSE_COMPAT_ENTRY_OUT_SIZE 120 ++ ++struct fuse_entry_out { ++ uint64_t nodeid; /* Inode ID */ ++ uint64_t generation; /* Inode generation: nodeid:gen must ++ be unique for the fs's lifetime */ ++ uint64_t entry_valid; /* Cache timeout for the name */ ++ uint64_t attr_valid; /* Cache timeout for the attributes */ ++ uint32_t entry_valid_nsec; ++ uint32_t attr_valid_nsec; ++ struct fuse_attr attr; ++}; ++ ++struct fuse_forget_in { ++ uint64_t nlookup; ++}; ++ ++struct fuse_forget_one { ++ uint64_t nodeid; ++ uint64_t nlookup; ++}; ++ ++struct fuse_batch_forget_in { ++ uint32_t count; ++ uint32_t dummy; ++}; ++ ++struct fuse_getattr_in { ++ uint32_t getattr_flags; ++ uint32_t dummy; ++ uint64_t fh; ++}; ++ ++#define FUSE_COMPAT_ATTR_OUT_SIZE 96 ++ ++struct fuse_attr_out { ++ uint64_t attr_valid; /* Cache timeout for the attributes */ ++ uint32_t attr_valid_nsec; ++ uint32_t dummy; ++ struct fuse_attr attr; ++}; ++ ++struct fuse_statx_in { ++ uint32_t getattr_flags; ++ uint32_t reserved; ++ uint64_t fh; ++ uint32_t sx_flags; ++ uint32_t sx_mask; ++}; ++ ++struct fuse_statx_out { ++ uint64_t attr_valid; /* Cache timeout for the attributes */ ++ uint32_t attr_valid_nsec; ++ uint32_t flags; ++ uint64_t spare[2]; ++ struct fuse_statx stat; ++}; ++ ++#define FUSE_COMPAT_MKNOD_IN_SIZE 8 ++ ++struct fuse_mknod_in { ++ uint32_t mode; ++ uint32_t rdev; ++ uint32_t umask; ++ uint32_t padding; ++}; ++ ++struct fuse_mkdir_in { ++ uint32_t mode; ++ uint32_t umask; ++}; ++ ++struct fuse_rename_in { ++ uint64_t newdir; ++}; ++ ++struct fuse_rename2_in { ++ uint64_t newdir; ++ uint32_t flags; ++ uint32_t padding; ++}; ++ ++struct fuse_link_in { ++ uint64_t oldnodeid; ++}; ++ ++struct fuse_setattr_in { ++ uint32_t valid; ++ uint32_t padding; ++ uint64_t fh; ++ uint64_t size; ++ uint64_t lock_owner; ++ uint64_t atime; ++ uint64_t mtime; ++ uint64_t ctime; ++ uint32_t atimensec; ++ uint32_t mtimensec; ++ uint32_t ctimensec; ++ uint32_t mode; ++ uint32_t unused4; ++ uint32_t uid; ++ uint32_t gid; ++ uint32_t unused5; ++}; ++ ++struct fuse_open_in { ++ uint32_t flags; ++ uint32_t open_flags; /* FUSE_OPEN_... */ ++}; ++ ++struct fuse_create_in { ++ uint32_t flags; ++ uint32_t mode; ++ uint32_t umask; ++ uint32_t open_flags; /* FUSE_OPEN_... */ ++}; ++ ++struct fuse_open_out { ++ uint64_t fh; ++ uint32_t open_flags; ++ int32_t backing_id; ++}; ++ ++struct fuse_release_in { ++ uint64_t fh; ++ uint32_t flags; ++ uint32_t release_flags; ++ uint64_t lock_owner; ++}; ++ ++struct fuse_flush_in { ++ uint64_t fh; ++ uint32_t unused; ++ uint32_t padding; ++ uint64_t lock_owner; ++}; ++ ++struct fuse_read_in { ++ uint64_t fh; ++ uint64_t offset; ++ uint32_t size; ++ uint32_t read_flags; ++ uint64_t lock_owner; ++ uint32_t flags; ++ uint32_t padding; ++}; ++ ++#define FUSE_COMPAT_WRITE_IN_SIZE 24 ++ ++struct fuse_write_in { ++ uint64_t fh; ++ uint64_t offset; ++ uint32_t size; ++ uint32_t write_flags; ++ uint64_t lock_owner; ++ uint32_t flags; ++ uint32_t padding; ++}; ++ ++struct fuse_write_out { ++ uint32_t size; ++ uint32_t padding; ++}; ++ ++#define FUSE_COMPAT_STATFS_SIZE 48 ++ ++struct fuse_statfs_out { ++ struct fuse_kstatfs st; ++}; ++ ++struct fuse_fsync_in { ++ uint64_t fh; ++ uint32_t fsync_flags; ++ uint32_t padding; ++}; ++ ++#define FUSE_COMPAT_SETXATTR_IN_SIZE 8 ++ ++struct fuse_setxattr_in { ++ uint32_t size; ++ uint32_t flags; ++ uint32_t setxattr_flags; ++ uint32_t padding; ++}; ++ ++struct fuse_getxattr_in { ++ uint32_t size; ++ uint32_t padding; ++}; ++ ++struct fuse_getxattr_out { ++ uint32_t size; ++ uint32_t padding; ++}; ++ ++struct fuse_lk_in { ++ uint64_t fh; ++ uint64_t owner; ++ struct fuse_file_lock lk; ++ uint32_t lk_flags; ++ uint32_t padding; ++}; ++ ++struct fuse_lk_out { ++ struct fuse_file_lock lk; ++}; ++ ++struct fuse_access_in { ++ uint32_t mask; ++ uint32_t padding; ++}; ++ ++struct fuse_init_in { ++ uint32_t major; ++ uint32_t minor; ++ uint32_t max_readahead; ++ uint32_t flags; ++ uint32_t flags2; ++ uint32_t unused[11]; ++}; ++ ++#define FUSE_COMPAT_INIT_OUT_SIZE 8 ++#define FUSE_COMPAT_22_INIT_OUT_SIZE 24 ++ ++struct fuse_init_out { ++ uint32_t major; ++ uint32_t minor; ++ uint32_t max_readahead; ++ uint32_t flags; ++ uint16_t max_background; ++ uint16_t congestion_threshold; ++ uint32_t max_write; ++ uint32_t time_gran; ++ uint16_t max_pages; ++ uint16_t map_alignment; ++ uint32_t flags2; ++ uint32_t max_stack_depth; ++ uint32_t unused[6]; ++}; ++ ++#define CUSE_INIT_INFO_MAX 4096 ++ ++struct cuse_init_in { ++ uint32_t major; ++ uint32_t minor; ++ uint32_t unused; ++ uint32_t flags; ++}; ++ ++struct cuse_init_out { ++ uint32_t major; ++ uint32_t minor; ++ uint32_t unused; ++ uint32_t flags; ++ uint32_t max_read; ++ uint32_t max_write; ++ uint32_t dev_major; /* chardev major */ ++ uint32_t dev_minor; /* chardev minor */ ++ uint32_t spare[10]; ++}; ++ ++struct fuse_interrupt_in { ++ uint64_t unique; ++}; ++ ++struct fuse_bmap_in { ++ uint64_t block; ++ uint32_t blocksize; ++ uint32_t padding; ++}; ++ ++struct fuse_bmap_out { ++ uint64_t block; ++}; ++ ++struct fuse_ioctl_in { ++ uint64_t fh; ++ uint32_t flags; ++ uint32_t cmd; ++ uint64_t arg; ++ uint32_t in_size; ++ uint32_t out_size; ++}; ++ ++struct fuse_ioctl_iovec { ++ uint64_t base; ++ uint64_t len; ++}; ++ ++struct fuse_ioctl_out { ++ int32_t result; ++ uint32_t flags; ++ uint32_t in_iovs; ++ uint32_t out_iovs; ++}; ++ ++struct fuse_poll_in { ++ uint64_t fh; ++ uint64_t kh; ++ uint32_t flags; ++ uint32_t events; ++}; ++ ++struct fuse_poll_out { ++ uint32_t revents; ++ uint32_t padding; ++}; ++ ++struct fuse_notify_poll_wakeup_out { ++ uint64_t kh; ++}; ++ ++struct fuse_fallocate_in { ++ uint64_t fh; ++ uint64_t offset; ++ uint64_t length; ++ uint32_t mode; ++ uint32_t padding; ++}; ++ ++/** ++ * FUSE request unique ID flag ++ * ++ * Indicates whether this is a resend request. The receiver should handle this ++ * request accordingly. ++ */ ++#define FUSE_UNIQUE_RESEND (1ULL << 63) ++ ++struct fuse_in_header { ++ uint32_t len; ++ uint32_t opcode; ++ uint64_t unique; ++ uint64_t nodeid; ++ uint32_t uid; ++ uint32_t gid; ++ uint32_t pid; ++ uint16_t total_extlen; /* length of extensions in 8byte units */ ++ uint16_t padding; ++}; ++ ++struct fuse_out_header { ++ uint32_t len; ++ int32_t error; ++ uint64_t unique; ++}; ++ ++struct fuse_dirent { ++ uint64_t ino; ++ uint64_t off; ++ uint32_t namelen; ++ uint32_t type; ++ char name[]; ++}; ++ ++/* Align variable length records to 64bit boundary */ ++#define FUSE_REC_ALIGN(x) \ ++ (((x) + sizeof(uint64_t) - 1) & ~(sizeof(uint64_t) - 1)) ++ ++#define FUSE_NAME_OFFSET offsetof(struct fuse_dirent, name) ++#define FUSE_DIRENT_ALIGN(x) FUSE_REC_ALIGN(x) ++#define FUSE_DIRENT_SIZE(d) \ ++ FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET + (d)->namelen) ++ ++struct fuse_direntplus { ++ struct fuse_entry_out entry_out; ++ struct fuse_dirent dirent; ++}; ++ ++#define FUSE_NAME_OFFSET_DIRENTPLUS \ ++ offsetof(struct fuse_direntplus, dirent.name) ++#define FUSE_DIRENTPLUS_SIZE(d) \ ++ FUSE_DIRENT_ALIGN(FUSE_NAME_OFFSET_DIRENTPLUS + (d)->dirent.namelen) ++ ++struct fuse_notify_inval_inode_out { ++ uint64_t ino; ++ int64_t off; ++ int64_t len; ++}; ++ ++struct fuse_notify_inval_entry_out { ++ uint64_t parent; ++ uint32_t namelen; ++ uint32_t flags; ++}; ++ ++struct fuse_notify_delete_out { ++ uint64_t parent; ++ uint64_t child; ++ uint32_t namelen; ++ uint32_t padding; ++}; ++ ++struct fuse_notify_store_out { ++ uint64_t nodeid; ++ uint64_t offset; ++ uint32_t size; ++ uint32_t padding; ++}; ++ ++struct fuse_notify_retrieve_out { ++ uint64_t notify_unique; ++ uint64_t nodeid; ++ uint64_t offset; ++ uint32_t size; ++ uint32_t padding; ++}; ++ ++/* Matches the size of fuse_write_in */ ++struct fuse_notify_retrieve_in { ++ uint64_t dummy1; ++ uint64_t offset; ++ uint32_t size; ++ uint32_t dummy2; ++ uint64_t dummy3; ++ uint64_t dummy4; ++}; ++ ++struct fuse_backing_map { ++ int32_t fd; ++ uint32_t flags; ++ uint64_t padding; ++}; ++ ++/* Device ioctls: */ ++#define FUSE_DEV_IOC_MAGIC 229 ++#define FUSE_DEV_IOC_CLONE _IOR(FUSE_DEV_IOC_MAGIC, 0, uint32_t) ++#define FUSE_DEV_IOC_BACKING_OPEN _IOW(FUSE_DEV_IOC_MAGIC, 1, \ ++ struct fuse_backing_map) ++#define FUSE_DEV_IOC_BACKING_CLOSE _IOW(FUSE_DEV_IOC_MAGIC, 2, uint32_t) ++ ++struct fuse_lseek_in { ++ uint64_t fh; ++ uint64_t offset; ++ uint32_t whence; ++ uint32_t padding; ++}; ++ ++struct fuse_lseek_out { ++ uint64_t offset; ++}; ++ ++struct fuse_copy_file_range_in { ++ uint64_t fh_in; ++ uint64_t off_in; ++ uint64_t nodeid_out; ++ uint64_t fh_out; ++ uint64_t off_out; ++ uint64_t len; ++ uint64_t flags; ++}; ++ ++#define FUSE_SETUPMAPPING_FLAG_WRITE (1ull << 0) ++#define FUSE_SETUPMAPPING_FLAG_READ (1ull << 1) ++struct fuse_setupmapping_in { ++ /* An already open handle */ ++ uint64_t fh; ++ /* Offset into the file to start the mapping */ ++ uint64_t foffset; ++ /* Length of mapping required */ ++ uint64_t len; ++ /* Flags, FUSE_SETUPMAPPING_FLAG_* */ ++ uint64_t flags; ++ /* Offset in Memory Window */ ++ uint64_t moffset; ++}; ++ ++struct fuse_removemapping_in { ++ /* number of fuse_removemapping_one follows */ ++ uint32_t count; ++}; ++ ++struct fuse_removemapping_one { ++ /* Offset into the dax window start the unmapping */ ++ uint64_t moffset; ++ /* Length of mapping required */ ++ uint64_t len; ++}; ++ ++#define FUSE_REMOVEMAPPING_MAX_ENTRY \ ++ (PAGE_SIZE / sizeof(struct fuse_removemapping_one)) ++ ++struct fuse_syncfs_in { ++ uint64_t padding; ++}; ++ ++/* ++ * For each security context, send fuse_secctx with size of security context ++ * fuse_secctx will be followed by security context name and this in turn ++ * will be followed by actual context label. ++ * fuse_secctx, name, context ++ */ ++struct fuse_secctx { ++ uint32_t size; ++ uint32_t padding; ++}; ++ ++/* ++ * Contains the information about how many fuse_secctx structures are being ++ * sent and what's the total size of all security contexts (including ++ * size of fuse_secctx_header). ++ * ++ */ ++struct fuse_secctx_header { ++ uint32_t size; ++ uint32_t nr_secctx; ++}; ++ ++/** ++ * struct fuse_ext_header - extension header ++ * @size: total size of this extension including this header ++ * @type: type of extension ++ * ++ * This is made compatible with fuse_secctx_header by using type values > ++ * FUSE_MAX_NR_SECCTX ++ */ ++struct fuse_ext_header { ++ uint32_t size; ++ uint32_t type; ++}; ++ ++/** ++ * struct fuse_supp_groups - Supplementary group extension ++ * @nr_groups: number of supplementary groups ++ * @groups: flexible array of group IDs ++ */ ++struct fuse_supp_groups { ++ uint32_t nr_groups; ++ uint32_t groups[]; ++}; ++ ++#endif /* _LINUX_FUSE_H */ diff --git a/glibc-RHEL-108823-6.patch b/glibc-RHEL-108823-6.patch new file mode 100644 index 0000000..a86174b --- /dev/null +++ b/glibc-RHEL-108823-6.patch @@ -0,0 +1,414 @@ +commit 3b1d32177635023e37bec7fbfd77c3cfb2659eb1 +Author: Florian Weimer +Date: Fri Aug 30 21:52:10 2024 +0200 + + support: Add + + Use static functions for readdir/readdir_r, so that + -D_FILE_OFFSET_BITS=64 does not improperly redirect calls to the wrong + implementation. + + Reviewed-by: DJ Delorie + +diff --git a/support/Makefile b/support/Makefile +index 23ce2ccec89743bb..2cc0654e86a5e0de 100644 +--- a/support/Makefile ++++ b/support/Makefile +@@ -73,6 +73,8 @@ libsupport-routines = \ + support_quote_blob \ + support_quote_blob_wide \ + support_quote_string \ ++ support_readdir_check \ ++ support_readdir_r_check \ + support_record_failure \ + support_run_diff \ + support_select_modifies_timeout \ +@@ -115,6 +117,7 @@ libsupport-routines = \ + xclock_settime_time64 \ + xclone \ + xclose \ ++ xclosedir \ + xconnect \ + xcopy_file_range \ + xdlfcn \ +@@ -122,6 +125,7 @@ libsupport-routines = \ + xdup2 \ + xfchmod \ + xfclose \ ++ xfdopendir \ + xfgets \ + xfopen \ + xfork \ +@@ -143,6 +147,7 @@ libsupport-routines = \ + xmunmap \ + xnewlocale \ + xopen \ ++ xopendir \ + xpipe \ + xpoll \ + xposix_memalign \ +@@ -328,6 +333,7 @@ tests = \ + tst-test_compare_string \ + tst-test_compare_string_wide \ + tst-timespec \ ++ tst-xdirent \ + tst-xreadlink \ + tst-xsigstack \ + # tests +diff --git a/support/support_readdir_check.c b/support/support_readdir_check.c +new file mode 100644 +index 0000000000000000..5687004276f87d93 +--- /dev/null ++++ b/support/support_readdir_check.c +@@ -0,0 +1,30 @@ ++/* Error-checking helper for xreaddir, xreaddir64. ++ Copyright (C) 2024 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 ++ . */ ++ ++#include ++ ++#include ++ ++void * ++support_readdir_check (const char *name, void *result, int saved_errno) ++{ ++ if (result == NULL && errno != 0) ++ FAIL_EXIT1 ("%s: %m", name); ++ errno = saved_errno; ++ return result; ++} +diff --git a/support/support_readdir_r_check.c b/support/support_readdir_r_check.c +new file mode 100644 +index 0000000000000000..6bbb0d0b32fb949e +--- /dev/null ++++ b/support/support_readdir_r_check.c +@@ -0,0 +1,35 @@ ++/* Error-checking helper for xreaddir_r, xreaddir64_r. ++ Copyright (C) 2024 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 ++ . */ ++ ++#include ++ ++#include ++ ++int ++support_readdir_r_check (const char *name, int result, void *buf, void *ptr) ++{ ++ if (result != 0) ++ { ++ errno = result; ++ FAIL_EXIT1 ("%s: %m", name); ++ } ++ if (buf != ptr) ++ FAIL_EXIT1 ("%s: buffer pointer and returned pointer differ: %p != %p", ++ name, buf, ptr); ++ return result; ++} +diff --git a/support/tst-xdirent.c b/support/tst-xdirent.c +new file mode 100644 +index 0000000000000000..642483165a36765c +--- /dev/null ++++ b/support/tst-xdirent.c +@@ -0,0 +1,76 @@ ++/* Compile test for error-checking wrappers for ++ Copyright (C) 2024 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 ++ . */ ++ ++#include ++ ++#include ++#include ++#include ++ ++static int ++do_test (void) ++{ ++ { ++ DIR *d = xopendir ("."); ++ struct dirent *e = xreaddir (d); ++ /* Assume that the "." special entry always comes first. */ ++ TEST_COMPARE_STRING (e->d_name, "."); ++ while (xreaddir (d) != NULL) ++ ; ++ xclosedir (d); ++ } ++ ++ { ++ DIR *d = xopendir ("."); ++ struct dirent64 *e = xreaddir64 (d); ++ TEST_COMPARE_STRING (e->d_name, "."); ++ while (xreaddir64 (d) != NULL) ++ ; ++ xclosedir (d); ++ } ++ ++ /* The functions readdir_r, readdir64_r were deprecated in glibc 2.24. */ ++ DIAG_PUSH_NEEDS_COMMENT; ++ DIAG_IGNORE_NEEDS_COMMENT (4.9, "-Wdeprecated-declarations"); ++ ++ { ++ DIR *d = xopendir ("."); ++ struct dirent buf = { 0, }; ++ TEST_VERIFY (xreaddir_r (d, &buf)); ++ TEST_COMPARE_STRING (buf.d_name, "."); ++ while (xreaddir_r (d, &buf)) ++ ; ++ xclosedir (d); ++ } ++ ++ { ++ DIR *d = xopendir ("."); ++ struct dirent64 buf = { 0, }; ++ TEST_VERIFY (xreaddir64_r (d, &buf)); ++ TEST_COMPARE_STRING (buf.d_name, "."); ++ while (xreaddir64_r (d, &buf)) ++ ; ++ xclosedir (d); ++ } ++ ++ DIAG_POP_NEEDS_COMMENT; ++ ++ return 0; ++} ++ ++#include +diff --git a/support/xclosedir.c b/support/xclosedir.c +new file mode 100644 +index 0000000000000000..b490df5598e76226 +--- /dev/null ++++ b/support/xclosedir.c +@@ -0,0 +1,28 @@ ++/* Error-checking wrapper for closedir. ++ Copyright (C) 2024 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 ++ . */ ++ ++#include ++ ++#include ++ ++void ++xclosedir (DIR *dir) ++{ ++ if (closedir (dir) != 0) ++ FAIL_EXIT1 ("closedir: %m"); ++} +diff --git a/support/xdirent.h b/support/xdirent.h +new file mode 100644 +index 0000000000000000..8465d70ec1ea97d8 +--- /dev/null ++++ b/support/xdirent.h +@@ -0,0 +1,86 @@ ++/* Error-checking wrappers for ++ Copyright (C) 2024 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 ++ . */ ++ ++#ifndef SUPPORT_XDIRENT_H ++#define SUPPORT_XDIRENT_H ++ ++#include ++#include ++#include ++#include ++#include ++ ++__BEGIN_DECLS ++ ++DIR *xopendir (const char *path); ++DIR *xfdopendir (int fd); ++void xclosedir (DIR *); ++ ++void *support_readdir_check (const char *, void *, int); ++ ++static __attribute__ ((unused)) struct dirent * ++xreaddir (DIR *stream) ++{ ++ int saved_errno = errno; ++ errno = 0; ++ struct dirent *result = readdir (stream); ++ return support_readdir_check ("readdir", result, saved_errno); ++} ++ ++static __attribute__ ((unused)) struct dirent64 * ++xreaddir64 (DIR *stream) ++{ ++ int saved_errno = errno; ++ errno = 0; ++ struct dirent64 *result = readdir64 (stream); ++ return support_readdir_check ("readdir64", result, saved_errno); ++} ++ ++/* The functions readdir_r, readdir64_r were deprecated in glibc 2.24. */ ++DIAG_PUSH_NEEDS_COMMENT; ++DIAG_IGNORE_NEEDS_COMMENT (4.9, "-Wdeprecated-declarations"); ++ ++int support_readdir_r_check (const char *, int, void *, void *); ++ ++static __attribute__ ((unused)) bool ++xreaddir_r (DIR *stream, struct dirent *buf) ++{ ++ struct dirent *ptr; ++ int ret = readdir_r (stream, buf, &ptr); ++ if (ret == 0 && ptr == NULL) ++ return false; ++ support_readdir_r_check ("readdir_r", ret, buf, ptr); ++ return true; ++} ++ ++static __attribute__ ((unused)) bool ++xreaddir64_r (DIR *stream, struct dirent64 *buf) ++{ ++ struct dirent64 *ptr; ++ int ret = readdir64_r (stream, buf, &ptr); ++ if (ret == 0 && ptr == NULL) ++ return false; ++ support_readdir_r_check ("readdir64_r", ret, buf, ptr); ++ return true; ++} ++ ++DIAG_POP_NEEDS_COMMENT; ++ ++__END_DECLS ++ ++#endif /* SUPPORT_XDIRENT_H */ +diff --git a/support/xfdopendir.c b/support/xfdopendir.c +new file mode 100644 +index 0000000000000000..d881d28c738a26a8 +--- /dev/null ++++ b/support/xfdopendir.c +@@ -0,0 +1,30 @@ ++/* Error-checking wrapper for fdopendir. ++ Copyright (C) 2024 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 ++ . */ ++ ++#include ++ ++#include ++ ++DIR * ++xfdopendir (int fd) ++{ ++ DIR *result = fdopendir (fd); ++ if (result == NULL) ++ FAIL_EXIT1 ("fdopendir (%d): %m", fd); ++ return result; ++} +diff --git a/support/xopendir.c b/support/xopendir.c +new file mode 100644 +index 0000000000000000..e4aee07fee074d5e +--- /dev/null ++++ b/support/xopendir.c +@@ -0,0 +1,30 @@ ++/* Error-checking wrapper for opendir. ++ Copyright (C) 2024 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 ++ . */ ++ ++#include ++ ++#include ++ ++DIR * ++xopendir (const char *path) ++{ ++ DIR *result = opendir (path); ++ if (result == NULL) ++ FAIL_EXIT1 ("opendir (\"%s\"): %m", path); ++ return result; ++} diff --git a/glibc-RHEL-108823-7.patch b/glibc-RHEL-108823-7.patch new file mode 100644 index 0000000..bdbe840 --- /dev/null +++ b/glibc-RHEL-108823-7.patch @@ -0,0 +1,1320 @@ +commit f169509ded534537eec9df00cfada6dbca908352 +Author: Florian Weimer +Date: Fri Aug 30 21:52:53 2024 +0200 + + support: Add FUSE-based file system test framework to support/ + + This allows to monitor the exact file system operations + performed by glibc and inject errors. + + Hurd does not have . To get the sources to compile + at least, the same approach as in support/test-container.c is used. + + Reviewed-by: DJ Delorie + +diff --git a/support/Makefile b/support/Makefile +index 2cc0654e86a5e0de..480d3a91b8b9b625 100644 +--- a/support/Makefile ++++ b/support/Makefile +@@ -62,6 +62,7 @@ libsupport-routines = \ + support_format_herrno \ + support_format_hostent \ + support_format_netent \ ++ support_fuse \ + support_isolate_in_subprocess \ + support_mutex_pi_monotonic \ + support_need_proc \ +@@ -324,6 +325,7 @@ tests = \ + tst-support_capture_subprocess \ + tst-support_descriptors \ + tst-support_format_dns_packet \ ++ tst-support_fuse \ + tst-support_quote_blob \ + tst-support_quote_blob_wide \ + tst-support_quote_string \ +diff --git a/support/fuse.h b/support/fuse.h +new file mode 100644 +index 0000000000000000..4c365fbc0c7408b9 +--- /dev/null ++++ b/support/fuse.h +@@ -0,0 +1,215 @@ ++/* Facilities for FUSE-backed file system tests. ++ Copyright (C) 2024 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 ++ . */ ++ ++/* Before using this functionality, use support_enter_mount_namespace ++ to ensure that mounts do not impact the overall system. */ ++ ++#ifndef SUPPORT_FUSE_H ++#define SUPPORT_FUSE_H ++ ++#include ++#include ++#include ++#include ++ ++#include ++ ++/* This function must be called furst, before support_fuse_mount, to ++ prepare unprivileged mounting. */ ++void support_fuse_init (void); ++ ++/* This function can be called instead of support_fuse_init. It does ++ not use mount and user namespaces, so it requires root privileges, ++ and cleanup after testing may be incomplete. This is intended only ++ for test development. */ ++void support_fuse_init_no_namespace (void); ++ ++/* Opaque type for tracking FUSE mount state. */ ++struct support_fuse; ++ ++/* This function disables a mount point created using ++ support_fuse_mount. */ ++void support_fuse_unmount (struct support_fuse *) __nonnull ((1)); ++ ++/* This function is called on a separate thread after calling ++ support_fuse_mount. F is the mount state, and CLOSURE the argument ++ that was passed to support_fuse_mount. The callback function is ++ expected to call support_fuse_next to read packets from the kernel ++ and handle them according to the test's need. */ ++typedef void (*support_fuse_callback) (struct support_fuse *f, void *closure); ++ ++/* This function creates a new mount point, implemented by CALLBACK. ++ CLOSURE is passed to CALLBACK as the second argument. */ ++struct support_fuse *support_fuse_mount (support_fuse_callback callback, ++ void *closure) ++ __nonnull ((1)) __attr_dealloc (support_fuse_unmount, 1); ++ ++/* This function returns the path to the mount point for F. The ++ returned string is valid until support_fuse_unmount (F) is called. */ ++const char * support_fuse_mountpoint (struct support_fuse *f) __nonnull ((1)); ++ ++ ++/* Renders the OPCODE as a string (FUSE_* constant. The caller must ++ free the returned string. */ ++char * support_fuse_opcode (uint32_t opcode) __attr_dealloc_free; ++ ++/* Use to provide a checked cast facility. Use the ++ support_fuse_in_cast macro below. */ ++void *support_fuse_cast_internal (struct fuse_in_header *, uint32_t) ++ __nonnull ((1)); ++void *support_fuse_cast_name_internal (struct fuse_in_header *, uint32_t, ++ size_t skip, char **name) ++ __nonnull ((1)); ++ ++/* The macro expansion support_fuse_in_cast (P, TYPE) casts the ++ pointer INH to the appropriate type corresponding to the FUSE_TYPE ++ opcode. It fails (terminates the process) if INH->opcode does not ++ match FUSE_TYPE. The type of the returned pointer matches that of ++ the FUSE_* constant. ++ ++ Maintenance note: Adding support for additional struct fuse_*_in ++ types is generally easy, except when there is trailing data after ++ the struct (see below for support_fuse_cast_name, for example), and ++ the kernel has changed struct sizes over time. This has happened ++ recently with struct fuse_setxattr_in, and would require special ++ handling if implemented. */ ++#define support_fuse_payload_type_INIT struct fuse_init_in ++#define support_fuse_payload_type_LOOKUP char ++#define support_fuse_payload_type_OPEN struct fuse_open_in ++#define support_fuse_payload_type_READ struct fuse_read_in ++#define support_fuse_payload_type_SETATTR struct fuse_setattr_in ++#define support_fuse_payload_type_WRITE struct fuse_write_in ++#define support_fuse_cast(typ, inh) \ ++ ((support_fuse_payload_type_##typ *) \ ++ support_fuse_cast_internal ((inh), FUSE_##typ)) ++ ++/* Same as support_fuse_cast, but also writes the passed name to *NAMEP. */ ++#define support_fuse_payload_name_type_CREATE struct fuse_create_in ++#define support_fuse_payload_name_type_MKDIR struct fuse_mkdir_in ++#define support_fuse_cast_name(typ, inh, namep) \ ++ ((support_fuse_payload_name_type_##typ *) \ ++ support_fuse_cast_name_internal \ ++ ((inh), FUSE_##typ, sizeof (support_fuse_payload_name_type_##typ), \ ++ (namep))) ++ ++/* This function should be called from the callback function. It ++ returns NULL if the mount point has been unmounted. The result can ++ be cast using support_fuse_in_cast. The pointer is invalidated ++ with the next call to support_fuse_next. ++ ++ Typical use involves handling some basics using the ++ support_fuse_handle_* building blocks, following by a switch ++ statement on the result member of the returned struct, to implement ++ what a particular test needs. Casts to payload data should be made ++ using support_fuse_in_cast. ++ ++ By default, FUSE_FORGET responses are filtered. See ++ support_fuse_filter_forget for turning that off. */ ++struct fuse_in_header *support_fuse_next (struct support_fuse *f) ++ __nonnull ((1)); ++ ++/* This function can be called from a callback function to handle ++ basic aspects of directories (OPENDIR, GETATTR, RELEASEDIR). ++ inh->nodeid is used as the inode number for the directory. This ++ function must be called after support_fuse_next. */ ++bool support_fuse_handle_directory (struct support_fuse *f) __nonnull ((1)); ++ ++/* This function can be called from a callback function to handle ++ access to the mount point itself, after call support_fuse_next. */ ++bool support_fuse_handle_mountpoint (struct support_fuse *f) __nonnull ((1)); ++ ++/* If FILTER_ENABLED, future support_fuse_next calls will not return ++ FUSE_FORGET events (and simply discared them, as they require no ++ reply). If !FILTER_ENABLED, the callback needs to handle ++ FUSE_FORGET events and call support_fuse_no_reply. */ ++void support_fuse_filter_forget (struct support_fuse *f, bool filter_enabled) ++ __nonnull ((1)); ++ ++/* This function should be called from the callback function after ++ support_fuse_next returned a non-null pointer. It sends out a ++ response packet on the FUSE device with the supplied payload data. */ ++void support_fuse_reply (struct support_fuse *f, ++ const void *payload, size_t payload_size) ++ __nonnull ((1)) __attr_access ((__read_only__, 2, 3)); ++ ++/* This function should be called from the callback function. It ++ replies to a request with an error indicator. ERROR must be positive. */ ++void support_fuse_reply_error (struct support_fuse *f, uint32_t error) ++ __nonnull ((1)); ++ ++/* This function should be called from the callback function. It ++ sends out an empty (but success-indicating) reply packet. */ ++void support_fuse_reply_empty (struct support_fuse *f) __nonnull ((1)); ++ ++/* Do not send a reply. Only to be used after a support_fuse_next ++ call that returned a FUSE_FORGET event. */ ++void support_fuse_no_reply (struct support_fuse *f) __nonnull ((1)); ++ ++/* Specific reponse preparation functions. The returned object can be ++ updated as needed. If a NODEID argument is present, it will be ++ used to set the inode and FUSE nodeid fields. Without such an ++ argument, it is initialized from the current request (if the reply ++ requires this field). This function must be called after ++ support_fuse_next. The actual response must be sent using ++ support_fuse_reply_prepared (or a support_fuse_reply_error call can ++ be used to cancel the response). */ ++struct fuse_entry_out *support_fuse_prepare_entry (struct support_fuse *f, ++ uint64_t nodeid) ++ __nonnull ((1)); ++struct fuse_attr_out *support_fuse_prepare_attr (struct support_fuse *f) ++ __nonnull ((1)); ++ ++/* Similar to the other support_fuse_prepare_* functions, but it ++ prepares for two response packets. They can be updated through the ++ pointers written to *OUT_ENTRY and *OUT_OPEN prior to calling ++ support_fuse_reply_prepared. */ ++void support_fuse_prepare_create (struct support_fuse *f, ++ uint64_t nodeid, ++ struct fuse_entry_out **out_entry, ++ struct fuse_open_out **out_open) ++ __nonnull ((1, 3, 4)); ++ ++ ++/* Prepare sending a directory stream. Must be called after ++ support_fuse_next and before support_fuse_dirstream_add. */ ++struct support_fuse_dirstream; ++struct support_fuse_dirstream *support_fuse_prepare_readdir (struct ++ support_fuse *f); ++ ++/* Adds directory using D_INO, D_OFF, D_TYPE, D_NAME to the directory ++ stream D. Must be called after support_fuse_prepare_readdir. ++ ++ D_OFF is the offset of the next directory entry, not the current ++ one. The first entry has offset zero. The first requested offset ++ can be obtained from the READ payload (struct fuse_read_in) prior ++ to calling this function. ++ ++ Returns true if the entry could be added to the buffer, or false if ++ there was insufficient room. Sending the buffer is delayed until ++ support_fuse_reply_prepared is called. */ ++bool support_fuse_dirstream_add (struct support_fuse_dirstream *d, ++ uint64_t d_ino, uint64_t d_off, ++ uint32_t d_type, ++ const char *d_name); ++ ++/* Send a prepared response. Must be called after one of the ++ support_fuse_prepare_* functions and before the next ++ support_fuse_next call. */ ++void support_fuse_reply_prepared (struct support_fuse *f) __nonnull ((1)); ++ ++#endif /* SUPPORT_FUSE_H */ +diff --git a/support/support_fuse.c b/support/support_fuse.c +new file mode 100644 +index 0000000000000000..135dbf1198d5a4c7 +--- /dev/null ++++ b/support/support_fuse.c +@@ -0,0 +1,705 @@ ++/* Facilities for FUSE-backed file system tests. ++ Copyright (C) 2024 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 ++ . */ ++ ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#ifdef __linux__ ++# include ++#else ++/* Fallback definitions that mark the test as unsupported. */ ++# define mount(...) ({ FAIL_UNSUPPORTED ("mount"); -1; }) ++# define umount(...) ({ FAIL_UNSUPPORTED ("mount"); -1; }) ++#endif ++ ++struct support_fuse ++{ ++ char *mountpoint; ++ void *buffer_start; /* Begin of allocation. */ ++ void *buffer_next; /* Next read position. */ ++ void *buffer_limit; /* End of buffered data. */ ++ void *buffer_end; /* End of allocation. */ ++ struct fuse_in_header *inh; /* Most recent request (support_fuse_next). */ ++ union /* Space for prepared responses. */ ++ { ++ struct fuse_attr_out attr; ++ struct fuse_entry_out entry; ++ struct ++ { ++ struct fuse_entry_out entry; ++ struct fuse_open_out open; ++ } create; ++ } prepared; ++ void *prepared_pointer; /* NULL if inactive. */ ++ size_t prepared_size; /* 0 if inactive. */ ++ ++ /* Used for preparing readdir responses. Already used-up area for ++ the current request is counted by prepared_size. */ ++ void *readdir_buffer; ++ size_t readdir_buffer_size; ++ ++ pthread_t handler; /* Thread handling requests. */ ++ uid_t uid; /* Cached value for the current process. */ ++ uid_t gid; /* Cached value for the current process. */ ++ int fd; /* FUSE file descriptor. */ ++ int connection; /* Entry under /sys/fs/fuse/connections. */ ++ bool filter_forget; /* Controls FUSE_FORGET event dropping. */ ++ _Atomic bool disconnected; ++}; ++ ++struct fuse_thread_wrapper_args ++{ ++ struct support_fuse *f; ++ support_fuse_callback callback; ++ void *closure; ++}; ++ ++/* Set by support_fuse_init to indicate that support_fuse_mount may be ++ called. */ ++static bool support_fuse_init_called; ++ ++/* Allocate the read buffer in F with SIZE bytes capacity. Does not ++ free the previously allocated buffer. */ ++static void support_fuse_allocate (struct support_fuse *f, size_t size) ++ __nonnull ((1)); ++ ++/* Internal mkdtemp replacement */ ++static char * support_fuse_mkdir (const char *prefix) __nonnull ((1)); ++ ++/* Low-level allocation function for support_fuse_mount. Does not ++ perform the mount. */ ++static struct support_fuse *support_fuse_open (void); ++ ++/* Thread wrapper function for use with pthread_create. Uses struct ++ fuse_thread_wrapper_args. */ ++static void *support_fuse_thread_wrapper (void *closure) __nonnull ((1)); ++ ++/* Initial step before preparing a reply. SIZE must be the size of ++ the F->prepared member that is going to be used. */ ++static void support_fuse_prepare_1 (struct support_fuse *f, size_t size); ++ ++/* Similar to support_fuse_reply_error, but not check that ERROR is ++ not zero. */ ++static void support_fuse_reply_error_1 (struct support_fuse *f, ++ uint32_t error) __nonnull ((1)); ++ ++/* Path to the directory containing mount points. Initialized by an ++ ELF constructor. All mountpoints are collected there so that the ++ test wrapper can clean them up without keeping track of them ++ individually. */ ++static char *support_fuse_mountpoints; ++ ++/* PID of the process that should clean up the mount points in the ELF ++ destructor. */ ++static pid_t support_fuse_cleanup_pid; ++ ++static void ++support_fuse_allocate (struct support_fuse *f, size_t size) ++{ ++ f->buffer_start = xmalloc (size); ++ f->buffer_end = f->buffer_start + size; ++ f->buffer_limit = f->buffer_start; ++ f->buffer_next = f->buffer_limit; ++} ++ ++void ++support_fuse_filter_forget (struct support_fuse *f, bool filter) ++{ ++ f->filter_forget = filter; ++} ++ ++void * ++support_fuse_cast_internal (struct fuse_in_header *p, uint32_t expected) ++{ ++ if (expected != p->opcode ++ && !(expected == FUSE_READ && p->opcode == FUSE_READDIR)) ++ { ++ char *expected1 = support_fuse_opcode (expected); ++ char *actual = support_fuse_opcode (p->opcode); ++ FAIL_EXIT1 ("attempt to cast %s to %s", actual, expected1); ++ } ++ return p + 1; ++} ++ ++void * ++support_fuse_cast_name_internal (struct fuse_in_header *p, uint32_t expected, ++ size_t skip, char **name) ++{ ++ char *result = support_fuse_cast_internal (p, expected); ++ *name = result + skip; ++ return result; ++} ++ ++bool ++support_fuse_dirstream_add (struct support_fuse_dirstream *d, ++ uint64_t d_ino, uint64_t d_off, ++ uint32_t d_type, const char *d_name) ++{ ++ struct support_fuse *f = (struct support_fuse *) d; ++ size_t structlen = offsetof (struct fuse_dirent, name); ++ size_t namelen = strlen (d_name); /* No null termination. */ ++ size_t required_size = FUSE_DIRENT_ALIGN (structlen + namelen); ++ if (f->readdir_buffer_size - f->prepared_size < required_size) ++ return false; ++ struct fuse_dirent entry = ++ { ++ .ino = d_ino, ++ .off = d_off, ++ .type = d_type, ++ .namelen = namelen, ++ }; ++ memcpy (f->readdir_buffer + f->prepared_size, &entry, structlen); ++ /* Use strncpy to write padding and avoid passing uninitialized ++ bytes to the read system call. */ ++ strncpy (f->readdir_buffer + f->prepared_size + structlen, d_name, ++ required_size - structlen); ++ f->prepared_size += required_size; ++ return true; ++} ++ ++bool ++support_fuse_handle_directory (struct support_fuse *f) ++{ ++ TEST_VERIFY (f->inh != NULL); ++ switch (f->inh->opcode) ++ { ++ case FUSE_OPENDIR: ++ { ++ struct fuse_open_out out = ++ { ++ }; ++ support_fuse_reply (f, &out, sizeof (out)); ++ } ++ return true; ++ case FUSE_RELEASEDIR: ++ support_fuse_reply_empty (f); ++ return true; ++ case FUSE_GETATTR: ++ { ++ struct fuse_attr_out *out = support_fuse_prepare_attr (f); ++ out->attr.mode = S_IFDIR | 0700; ++ support_fuse_reply_prepared (f); ++ } ++ return true; ++ default: ++ return false; ++ } ++} ++ ++bool ++support_fuse_handle_mountpoint (struct support_fuse *f) ++{ ++ TEST_VERIFY (f->inh != NULL); ++ /* 1 is the root node. */ ++ if (f->inh->opcode == FUSE_GETATTR && f->inh->nodeid == 1) ++ return support_fuse_handle_directory (f); ++ return false; ++} ++ ++void ++support_fuse_init (void) ++{ ++ support_fuse_init_called = true; ++ ++ support_become_root (); ++ if (!support_enter_mount_namespace ()) ++ FAIL_UNSUPPORTED ("mount namespaces not supported"); ++} ++ ++void ++support_fuse_init_no_namespace (void) ++{ ++ support_fuse_init_called = true; ++} ++ ++static char * ++support_fuse_mkdir (const char *prefix) ++{ ++ /* Do not use mkdtemp to avoid interfering with its tests. */ ++ unsigned int counter = 1; ++ unsigned int pid = getpid (); ++ while (true) ++ { ++ char *path = xasprintf ("%s%u.%u/", prefix, pid, counter); ++ if (mkdir (path, 0700) == 0) ++ return path; ++ if (errno != EEXIST) ++ FAIL_EXIT1 ("mkdir (\"%s\"): %m", path); ++ free (path); ++ ++counter; ++ } ++} ++ ++struct support_fuse * ++support_fuse_mount (support_fuse_callback callback, void *closure) ++{ ++ TEST_VERIFY_EXIT (support_fuse_init_called); ++ ++ /* Request at least minor version 12 because it changed struct sizes. */ ++ enum { min_version = 12 }; ++ ++ struct support_fuse *f = support_fuse_open (); ++ char *mount_options ++ = xasprintf ("fd=%d,rootmode=040700,user_id=%u,group_id=%u", ++ f->fd, f->uid, f->gid); ++ if (mount ("fuse", f->mountpoint, "fuse.glibc", ++ MS_NOSUID|MS_NODEV, mount_options) ++ != 0) ++ FAIL_EXIT1 ("FUSE mount on %s: %m", f->mountpoint); ++ free (mount_options); ++ ++ /* Retry with an older FUSE version. */ ++ while (true) ++ { ++ struct fuse_in_header *inh = support_fuse_next (f); ++ struct fuse_init_in *init_in = support_fuse_cast (INIT, inh); ++ if (init_in->major < 7 ++ || (init_in->major == 7 && init_in->minor < min_version)) ++ FAIL_UNSUPPORTED ("kernel FUSE version is %u.%u, too old", ++ init_in->major, init_in->minor); ++ if (init_in->major > 7) ++ { ++ uint32_t major = 7; ++ support_fuse_reply (f, &major, sizeof (major)); ++ continue; ++ } ++ TEST_VERIFY (init_in->flags & FUSE_DONT_MASK); ++ struct fuse_init_out out = ++ { ++ .major = 7, ++ .minor = min_version, ++ /* Request that the kernel does not apply umask. */ ++ .flags = FUSE_DONT_MASK, ++ }; ++ support_fuse_reply (f, &out, sizeof (out)); ++ ++ { ++ struct fuse_thread_wrapper_args args = ++ { ++ .f = f, ++ .callback = callback, ++ .closure = closure, ++ }; ++ f->handler = xpthread_create (NULL, ++ support_fuse_thread_wrapper, &args); ++ struct stat64 st; ++ xstat64 (f->mountpoint, &st); ++ f->connection = minor (st.st_dev); ++ /* Got a reply from the thread, safe to deallocate args. */ ++ } ++ ++ return f; ++ } ++} ++ ++const char * ++support_fuse_mountpoint (struct support_fuse *f) ++{ ++ return f->mountpoint; ++} ++ ++void ++support_fuse_no_reply (struct support_fuse *f) ++{ ++ TEST_VERIFY (f->inh != NULL); ++ TEST_COMPARE (f->inh->opcode, FUSE_FORGET); ++ f->inh = NULL; ++} ++ ++char * ++support_fuse_opcode (uint32_t op) ++{ ++ const char *result; ++ switch (op) ++ { ++#define X(n) case n: result = #n; break ++ X(FUSE_LOOKUP); ++ X(FUSE_FORGET); ++ X(FUSE_GETATTR); ++ X(FUSE_SETATTR); ++ X(FUSE_READLINK); ++ X(FUSE_SYMLINK); ++ X(FUSE_MKNOD); ++ X(FUSE_MKDIR); ++ X(FUSE_UNLINK); ++ X(FUSE_RMDIR); ++ X(FUSE_RENAME); ++ X(FUSE_LINK); ++ X(FUSE_OPEN); ++ X(FUSE_READ); ++ X(FUSE_WRITE); ++ X(FUSE_STATFS); ++ X(FUSE_RELEASE); ++ X(FUSE_FSYNC); ++ X(FUSE_SETXATTR); ++ X(FUSE_GETXATTR); ++ X(FUSE_LISTXATTR); ++ X(FUSE_REMOVEXATTR); ++ X(FUSE_FLUSH); ++ X(FUSE_INIT); ++ X(FUSE_OPENDIR); ++ X(FUSE_READDIR); ++ X(FUSE_RELEASEDIR); ++ X(FUSE_FSYNCDIR); ++ X(FUSE_GETLK); ++ X(FUSE_SETLK); ++ X(FUSE_SETLKW); ++ X(FUSE_ACCESS); ++ X(FUSE_CREATE); ++ X(FUSE_INTERRUPT); ++ X(FUSE_BMAP); ++ X(FUSE_DESTROY); ++ X(FUSE_IOCTL); ++ X(FUSE_POLL); ++ X(FUSE_NOTIFY_REPLY); ++ X(FUSE_BATCH_FORGET); ++ X(FUSE_FALLOCATE); ++ X(FUSE_READDIRPLUS); ++ X(FUSE_RENAME2); ++ X(FUSE_LSEEK); ++ X(FUSE_COPY_FILE_RANGE); ++ X(FUSE_SETUPMAPPING); ++ X(FUSE_REMOVEMAPPING); ++ X(FUSE_SYNCFS); ++ X(FUSE_TMPFILE); ++ X(FUSE_STATX); ++#undef X ++ default: ++ return xasprintf ("FUSE_unknown_%u", op); ++ } ++ return xstrdup (result); ++} ++ ++static struct support_fuse * ++support_fuse_open (void) ++{ ++ struct support_fuse *result = xmalloc (sizeof (*result)); ++ result->mountpoint = support_fuse_mkdir (support_fuse_mountpoints); ++ result->inh = NULL; ++ result->prepared_pointer = NULL; ++ result->prepared_size = 0; ++ result->readdir_buffer = NULL; ++ result->readdir_buffer_size = 0; ++ result->uid = getuid (); ++ result->gid = getgid (); ++ result->fd = open ("/dev/fuse", O_RDWR, 0); ++ if (result->fd < 0) ++ { ++ if (errno == ENOENT || errno == ENODEV || errno == EPERM ++ || errno == EACCES) ++ FAIL_UNSUPPORTED ("cannot open /dev/fuse: %m"); ++ else ++ FAIL_EXIT1 ("cannot open /dev/fuse: %m"); ++ } ++ result->connection = -1; ++ result->filter_forget = true; ++ result->disconnected = false; ++ support_fuse_allocate (result, FUSE_MIN_READ_BUFFER); ++ return result; ++} ++ ++static void ++support_fuse_prepare_1 (struct support_fuse *f, size_t size) ++{ ++ TEST_VERIFY (f->prepared_pointer == NULL); ++ f->prepared_size = size; ++ memset (&f->prepared, 0, size); ++ f->prepared_pointer = &f->prepared; ++} ++ ++struct fuse_attr_out * ++support_fuse_prepare_attr (struct support_fuse *f) ++{ ++ support_fuse_prepare_1 (f, sizeof (f->prepared.attr)); ++ f->prepared.attr.attr.uid = f->uid; ++ f->prepared.attr.attr.gid = f->gid; ++ f->prepared.attr.attr.ino = f->inh->nodeid; ++ return &f->prepared.attr; ++} ++ ++void ++support_fuse_prepare_create (struct support_fuse *f, ++ uint64_t nodeid, ++ struct fuse_entry_out **out_entry, ++ struct fuse_open_out **out_open) ++{ ++ support_fuse_prepare_1 (f, sizeof (f->prepared.create)); ++ f->prepared.create.entry.nodeid = nodeid; ++ f->prepared.create.entry.attr.uid = f->uid; ++ f->prepared.create.entry.attr.gid = f->gid; ++ f->prepared.create.entry.attr.ino = nodeid; ++ *out_entry = &f->prepared.create.entry; ++ *out_open = &f->prepared.create.open; ++} ++ ++struct fuse_entry_out * ++support_fuse_prepare_entry (struct support_fuse *f, uint64_t nodeid) ++{ ++ support_fuse_prepare_1 (f, sizeof (f->prepared.entry)); ++ f->prepared.entry.nodeid = nodeid; ++ f->prepared.entry.attr.uid = f->uid; ++ f->prepared.entry.attr.gid = f->gid; ++ f->prepared.entry.attr.ino = nodeid; ++ return &f->prepared.entry; ++} ++ ++struct support_fuse_dirstream * ++support_fuse_prepare_readdir (struct support_fuse *f) ++{ ++ support_fuse_prepare_1 (f, 0); ++ struct fuse_read_in *p = support_fuse_cast (READ, f->inh); ++ if (p->size > f->readdir_buffer_size) ++ { ++ free (f->readdir_buffer); ++ f->readdir_buffer = xmalloc (p->size); ++ f->readdir_buffer_size = p->size; ++ } ++ f->prepared_pointer = f->readdir_buffer; ++ return (struct support_fuse_dirstream *) f; ++} ++ ++struct fuse_in_header * ++support_fuse_next (struct support_fuse *f) ++{ ++ TEST_VERIFY (f->inh == NULL); ++ while (true) ++ { ++ if (f->buffer_next < f->buffer_limit) ++ { ++ f->inh = f->buffer_next; ++ f->buffer_next = (void *) f->buffer_next + f->inh->len; ++ /* Suppress FUSE_FORGET responses if requested. */ ++ if (f->filter_forget && f->inh->opcode == FUSE_FORGET) ++ { ++ f->inh = NULL; ++ continue; ++ } ++ return f->inh; ++ } ++ ssize_t ret = read (f->fd, f->buffer_start, ++ f->buffer_end - f->buffer_start); ++ if (ret == 0) ++ FAIL_EXIT (1, "unexpected EOF on FUSE device"); ++ if (ret < 0 && errno == EINVAL) ++ { ++ /* Increase buffer size. */ ++ size_t new_size = 2 * (size_t) (f->buffer_end - f->buffer_start); ++ free (f->buffer_start); ++ support_fuse_allocate (f, new_size); ++ continue; ++ } ++ if (ret < 0) ++ { ++ if (f->disconnected) ++ /* Unmount detected. */ ++ return NULL; ++ FAIL_EXIT1 ("read error on FUSE device: %m"); ++ } ++ /* Read was successful, make [next, limit) the active buffer area. */ ++ f->buffer_next = f->buffer_start; ++ f->buffer_limit = (void *) f->buffer_start + ret; ++ } ++} ++ ++void ++support_fuse_reply (struct support_fuse *f, ++ const void *payload, size_t payload_size) ++{ ++ TEST_VERIFY_EXIT (f->inh != NULL); ++ TEST_VERIFY (f->prepared_pointer == NULL); ++ struct fuse_out_header outh = ++ { ++ .len = sizeof (outh) + payload_size, ++ .unique = f->inh->unique, ++ }; ++ struct iovec iov[] = ++ { ++ { &outh, sizeof (outh) }, ++ { (void *) payload, payload_size }, ++ }; ++ ssize_t ret = writev (f->fd, iov, array_length (iov)); ++ if (ret < 0) ++ { ++ if (!f->disconnected) ++ /* Some kernels produce write errors upon disconnect. */ ++ FAIL_EXIT1 ("FUSE write failed for %s response" ++ " (%zu bytes payload): %m", ++ support_fuse_opcode (f->inh->opcode), payload_size); ++ } ++ else if (ret != sizeof (outh) + payload_size) ++ FAIL_EXIT1 ("FUSE write short for %s response (%zu bytes payload):" ++ " %zd bytes", ++ support_fuse_opcode (f->inh->opcode), payload_size, ret); ++ f->inh = NULL; ++} ++ ++void ++support_fuse_reply_empty (struct support_fuse *f) ++{ ++ support_fuse_reply_error_1 (f, 0); ++} ++ ++static void ++support_fuse_reply_error_1 (struct support_fuse *f, uint32_t error) ++{ ++ TEST_VERIFY_EXIT (f->inh != NULL); ++ struct fuse_out_header outh = ++ { ++ .len = sizeof (outh), ++ .error = -error, ++ .unique = f->inh->unique, ++ }; ++ ssize_t ret = write (f->fd, &outh, sizeof (outh)); ++ if (ret < 0) ++ { ++ /* Some kernels produce write errors upon disconnect. */ ++ if (!f->disconnected) ++ FAIL_EXIT1 ("FUSE write failed for %s error response: %m", ++ support_fuse_opcode (f->inh->opcode)); ++ } ++ else if (ret != sizeof (outh)) ++ FAIL_EXIT1 ("FUSE write short for %s error response: %zd bytes", ++ support_fuse_opcode (f->inh->opcode), ret); ++ f->inh = NULL; ++ f->prepared_pointer = NULL; ++ f->prepared_size = 0; ++} ++ ++void ++support_fuse_reply_error (struct support_fuse *f, uint32_t error) ++{ ++ TEST_VERIFY (error > 0); ++ support_fuse_reply_error_1 (f, error); ++} ++ ++void ++support_fuse_reply_prepared (struct support_fuse *f) ++{ ++ TEST_VERIFY_EXIT (f->prepared_pointer != NULL); ++ /* Re-use the non-prepared reply function. It requires ++ f->prepared_* to be non-null, so reset the fields before the call. */ ++ void *prepared_pointer = f->prepared_pointer; ++ size_t prepared_size = f->prepared_size; ++ f->prepared_pointer = NULL; ++ f->prepared_size = 0; ++ support_fuse_reply (f, prepared_pointer, prepared_size); ++} ++ ++static void * ++support_fuse_thread_wrapper (void *closure) ++{ ++ struct fuse_thread_wrapper_args args ++ = *(struct fuse_thread_wrapper_args *) closure; ++ ++ /* Handle the initial stat call. */ ++ struct fuse_in_header *inh = support_fuse_next (args.f); ++ if (inh == NULL || !support_fuse_handle_mountpoint (args.f)) ++ { ++ support_fuse_reply_error (args.f, EIO); ++ return NULL; ++ } ++ ++ args.callback (args.f, args.closure); ++ return NULL; ++} ++ ++void ++support_fuse_unmount (struct support_fuse *f) ++{ ++ /* Signal the unmount to the handler thread. Some kernels report ++ not just ENODEV errors on read. */ ++ f->disconnected = true; ++ ++ { ++ char *path = xasprintf ("/sys/fs/fuse/connections/%d/abort", ++ f->connection); ++ /* Some kernels do not support these files under /sys. */ ++ int fd = open (path, O_RDWR | O_TRUNC); ++ if (fd >= 0) ++ { ++ TEST_COMPARE (write (fd, "1", 1), 1); ++ xclose (fd); ++ } ++ free (path); ++ } ++ if (umount (f->mountpoint) != 0) ++ FAIL ("FUSE: umount (\"%s\"): %m", f->mountpoint); ++ xpthread_join (f->handler); ++ if (rmdir (f->mountpoint) != 0) ++ FAIL ("FUSE: rmdir (\"%s\"): %m", f->mountpoint); ++ xclose (f->fd); ++ free (f->mountpoint); ++ free (f->readdir_buffer); ++ free (f); ++} ++ ++static void __attribute__ ((constructor)) ++init (void) ++{ ++ /* The test_dir test driver variable is not yet set at this point. */ ++ const char *tmpdir = getenv ("TMPDIR"); ++ if (tmpdir == NULL || tmpdir[0] == '\0') ++ tmpdir = "/tmp"; ++ ++ char *prefix = xasprintf ("%s/glibc-tst-fuse.", tmpdir); ++ support_fuse_mountpoints = support_fuse_mkdir (prefix); ++ free (prefix); ++ support_fuse_cleanup_pid = getpid (); ++} ++ ++static void __attribute__ ((destructor)) ++fini (void) ++{ ++ if (support_fuse_cleanup_pid != getpid () ++ || support_fuse_mountpoints == NULL) ++ return; ++ DIR *dir = xopendir (support_fuse_mountpoints); ++ while (true) ++ { ++ struct dirent64 *e = readdir64 (dir); ++ if (e == NULL) ++ /* Ignore errors. */ ++ break; ++ if (*e->d_name == '.') ++ /* Skip "." and "..". No hidden files expected. */ ++ continue; ++ if (unlinkat (dirfd (dir), e->d_name, AT_REMOVEDIR) != 0) ++ break; ++ rewinddir (dir); ++ } ++ xclosedir (dir); ++ rmdir (support_fuse_mountpoints); ++ free (support_fuse_mountpoints); ++ support_fuse_mountpoints = NULL; ++} +diff --git a/support/tst-support_fuse.c b/support/tst-support_fuse.c +new file mode 100644 +index 0000000000000000..c4075a6608d9dd65 +--- /dev/null ++++ b/support/tst-support_fuse.c +@@ -0,0 +1,348 @@ ++/* Facilities for FUSE-backed file system tests. ++ Copyright (C) 2024 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 ++ . */ ++ ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static void ++fuse_thread (struct support_fuse *f, void *closure) ++{ ++ /* Turn on returning FUSE_FORGET responses. */ ++ support_fuse_filter_forget (f, false); ++ ++ /* Inode and nodeid for "file" and "new". */ ++ enum { NODE_FILE = 2, NODE_NEW, NODE_SUBDIR, NODE_SYMLINK }; ++ struct fuse_in_header *inh; ++ while ((inh = support_fuse_next (f)) != NULL) ++ { ++ { ++ char *opcode = support_fuse_opcode (inh->opcode); ++ printf ("info: (T) event %s(%llu) len=%u nodeid=%llu\n", ++ opcode, (unsigned long long int) inh->unique, inh->len, ++ (unsigned long long int) inh->nodeid); ++ free (opcode); ++ } ++ ++ /* Handle mountpoint and basic directory operation for the root (1). */ ++ if (support_fuse_handle_mountpoint (f) ++ || (inh->nodeid == 1 && support_fuse_handle_directory (f))) ++ continue; ++ ++ switch (inh->opcode) ++ { ++ case FUSE_READDIR: ++ /* Implementation of getdents64. */ ++ if (inh->nodeid == 1) ++ { ++ struct support_fuse_dirstream *d ++ = support_fuse_prepare_readdir (f); ++ TEST_COMPARE (support_fuse_cast (READ, inh)->offset, 0); ++ TEST_VERIFY (support_fuse_dirstream_add (d, 1, 1, DT_DIR, ".")); ++ TEST_VERIFY (support_fuse_dirstream_add (d, 1, 2, DT_DIR, "..")); ++ TEST_VERIFY (support_fuse_dirstream_add (d, NODE_FILE, 3, DT_REG, ++ "file")); ++ support_fuse_reply_prepared (f); ++ } ++ else ++ support_fuse_reply_error (f, EIO); ++ break; ++ case FUSE_LOOKUP: ++ /* Part of the implementation of open. */ ++ { ++ char *name = support_fuse_cast (LOOKUP, inh); ++ printf (" name: %s\n", name); ++ if (inh->nodeid == 1 && strcmp (name, "file") == 0) ++ { ++ struct fuse_entry_out *out ++ = support_fuse_prepare_entry (f, NODE_FILE); ++ out->attr.mode = S_IFREG | 0600; ++ support_fuse_reply_prepared (f); ++ } ++ else if (inh->nodeid == 1 && strcmp (name, "symlink") == 0) ++ { ++ struct fuse_entry_out *out ++ = support_fuse_prepare_entry (f, NODE_SYMLINK); ++ out->attr.mode = S_IFLNK | 0777; ++ support_fuse_reply_prepared (f); ++ } ++ else ++ support_fuse_reply_error (f, ENOENT); ++ } ++ break; ++ case FUSE_OPEN: ++ /* Implementation of open. */ ++ { ++ struct fuse_open_in *p = support_fuse_cast (OPEN, inh); ++ if (inh->nodeid == NODE_FILE) ++ { ++ TEST_VERIFY (!(p->flags & O_EXCL)); ++ struct fuse_open_out out = { 0, }; ++ support_fuse_reply (f, &out, sizeof (out)); ++ } ++ else ++ support_fuse_reply_error (f, ENOENT); ++ } ++ break; ++ case FUSE_GETATTR: ++ /* Happens after open. */ ++ if (inh->nodeid == NODE_FILE) ++ { ++ struct fuse_attr_out *out = support_fuse_prepare_attr (f); ++ out->attr.mode = S_IFREG | 0600; ++ out->attr.size = strlen ("Hello, world!"); ++ support_fuse_reply_prepared (f); ++ } ++ else ++ support_fuse_reply_error (f, ENOENT); ++ break; ++ case FUSE_READ: ++ /* Implementation of read. */ ++ if (inh->nodeid == NODE_FILE) ++ { ++ struct fuse_read_in *p = support_fuse_cast (READ, inh); ++ TEST_COMPARE (p->offset, 0); ++ TEST_VERIFY (p->size >= strlen ("Hello, world!")); ++ support_fuse_reply (f, ++ "Hello, world!", strlen ("Hello, world!")); ++ } ++ else ++ support_fuse_reply_error (f, EIO); ++ break; ++ case FUSE_FLUSH: ++ /* Sent in response to close. */ ++ support_fuse_reply_empty (f); ++ break; ++ case FUSE_GETXATTR: ++ /* This happens as part of a open-for-write operation. ++ Signal no support for extended attributes. */ ++ support_fuse_reply_error (f, ENOSYS); ++ break; ++ case FUSE_SETATTR: ++ /* This happens as part of a open-for-write operation to ++ implement O_TRUNC. */ ++ if (inh->nodeid == NODE_FILE) ++ { ++ struct fuse_setattr_in *p = support_fuse_cast (SETATTR, inh); ++ /* FATTR_LOCKOWNER may also be set. */ ++ TEST_COMPARE ((p->valid) & ~ FATTR_LOCKOWNER, FATTR_SIZE); ++ TEST_COMPARE (p->size, 0); ++ struct fuse_attr_out *out = support_fuse_prepare_attr (f); ++ out->attr.mode = S_IFREG | 0600; ++ support_fuse_reply_prepared (f); ++ } ++ else ++ support_fuse_reply_error (f, EIO); ++ break; ++ case FUSE_WRITE: ++ /* Implementation of write. */ ++ if (inh->nodeid == NODE_FILE) ++ { ++ struct fuse_write_in *p = support_fuse_cast (WRITE, inh); ++ TEST_COMPARE (p->offset, 0); ++ /* Write payload follows after struct fuse_write_in. */ ++ TEST_COMPARE_BLOB (p + 1, p->size, ++ "Good day to you too.", ++ strlen ("Good day to you too.")); ++ struct fuse_write_out out = ++ { ++ .size = p->size, ++ }; ++ support_fuse_reply (f, &out, sizeof (out)); ++ } ++ else ++ support_fuse_reply_error (f, EIO); ++ break; ++ case FUSE_CREATE: ++ /* Implementation of O_CREAT. */ ++ if (inh->nodeid == 1) ++ { ++ char *name; ++ struct fuse_create_in *p ++ = support_fuse_cast_name (CREATE, inh, &name); ++ TEST_VERIFY (S_ISREG (p->mode)); ++ TEST_COMPARE (p->mode & 07777, 0600); ++ TEST_COMPARE_STRING (name, "new"); ++ struct fuse_entry_out *out_entry; ++ struct fuse_open_out *out_open; ++ support_fuse_prepare_create (f, NODE_NEW, &out_entry, &out_open); ++ out_entry->attr.mode = S_IFREG | 0600; ++ support_fuse_reply_prepared (f); ++ } ++ else ++ support_fuse_reply_error (f, EIO); ++ break; ++ case FUSE_MKDIR: ++ /* Implementation of mkdir. */ ++ { ++ if (inh->nodeid == 1) ++ { ++ char *name; ++ struct fuse_mkdir_in *p ++ = support_fuse_cast_name (MKDIR, inh, &name); ++ TEST_COMPARE (p->mode, 01234); ++ TEST_COMPARE_STRING (name, "subdir"); ++ struct fuse_entry_out *out ++ = support_fuse_prepare_entry (f, NODE_SUBDIR); ++ out->attr.mode = S_IFDIR | p->mode; ++ support_fuse_reply_prepared (f); ++ } ++ else ++ support_fuse_reply_error (f, EIO); ++ } ++ break; ++ case FUSE_READLINK: ++ /* Implementation of readlink. */ ++ TEST_COMPARE (inh->nodeid, NODE_SYMLINK); ++ if (inh->nodeid == NODE_SYMLINK) ++ support_fuse_reply (f, "target-of-symbolic-link", ++ strlen ("target-of-symbolic-link")); ++ else ++ support_fuse_reply_error (f, EINVAL); ++ break; ++ case FUSE_FORGET: ++ support_fuse_no_reply (f); ++ break; ++ default: ++ support_fuse_reply_error (f, EIO); ++ } ++ } ++} ++ ++static int ++do_test (void) ++{ ++ support_fuse_init (); ++ ++ struct support_fuse *f = support_fuse_mount (fuse_thread, NULL); ++ ++ printf ("info: Attributes of mountpoint/root directory %s\n", ++ support_fuse_mountpoint (f)); ++ { ++ struct statx st; ++ xstatx (AT_FDCWD, support_fuse_mountpoint (f), 0, STATX_BASIC_STATS, &st); ++ TEST_COMPARE (st.stx_uid, getuid ()); ++ TEST_COMPARE (st.stx_gid, getgid ()); ++ TEST_VERIFY (S_ISDIR (st.stx_mode)); ++ TEST_COMPARE (st.stx_mode & 07777, 0700); ++ } ++ ++ printf ("info: List directory %s\n", support_fuse_mountpoint (f)); ++ { ++ DIR *dir = xopendir (support_fuse_mountpoint (f)); ++ ++ struct dirent *e = xreaddir (dir); ++ TEST_COMPARE (e->d_ino, 1); ++#ifdef _DIRENT_HAVE_D_OFF ++ TEST_COMPARE (e->d_off, 1); ++#endif ++ TEST_COMPARE (e->d_type, DT_DIR); ++ TEST_COMPARE_STRING (e->d_name, "."); ++ ++ e = xreaddir (dir); ++ TEST_COMPARE (e->d_ino, 1); ++#ifdef _DIRENT_HAVE_D_OFF ++ TEST_COMPARE (e->d_off, 2); ++#endif ++ TEST_COMPARE (e->d_type, DT_DIR); ++ TEST_COMPARE_STRING (e->d_name, ".."); ++ ++ e = xreaddir (dir); ++ TEST_COMPARE (e->d_ino, 2); ++#ifdef _DIRENT_HAVE_D_OFF ++ TEST_COMPARE (e->d_off, 3); ++#endif ++ TEST_COMPARE (e->d_type, DT_REG); ++ TEST_COMPARE_STRING (e->d_name, "file"); ++ ++ TEST_COMPARE (closedir (dir), 0); ++ } ++ ++ char *file_path = xasprintf ("%s/file", support_fuse_mountpoint (f)); ++ ++ printf ("info: Attributes of file %s\n", file_path); ++ { ++ struct statx st; ++ xstatx (AT_FDCWD, file_path, 0, STATX_BASIC_STATS, &st); ++ TEST_COMPARE (st.stx_uid, getuid ()); ++ TEST_COMPARE (st.stx_gid, getgid ()); ++ TEST_VERIFY (S_ISREG (st.stx_mode)); ++ TEST_COMPARE (st.stx_mode & 07777, 0600); ++ TEST_COMPARE (st.stx_size, strlen ("Hello, world!")); ++ } ++ ++ printf ("info: Read from %s\n", file_path); ++ { ++ int fd = xopen (file_path, O_RDONLY, 0); ++ char buf[64]; ++ ssize_t len = read (fd, buf, sizeof (buf)); ++ if (len < 0) ++ FAIL_EXIT1 ("read: %m"); ++ TEST_COMPARE_BLOB (buf, len, "Hello, world!", strlen ("Hello, world!")); ++ xclose (fd); ++ } ++ ++ printf ("info: Write to %s\n", file_path); ++ { ++ int fd = xopen (file_path, O_WRONLY | O_TRUNC, 0); ++ xwrite (fd, "Good day to you too.", strlen ("Good day to you too.")); ++ xclose (fd); ++ } ++ ++ printf ("info: Attempt O_EXCL creation of existing %s\n", file_path); ++ /* O_EXCL creation shall fail. */ ++ errno = 0; ++ TEST_COMPARE (open64 (file_path, O_RDWR | O_EXCL | O_CREAT, 0600), -1); ++ TEST_COMPARE (errno, EEXIST); ++ ++ free (file_path); ++ ++ { ++ char *new_path = xasprintf ("%s/new", support_fuse_mountpoint (f)); ++ printf ("info: Test successful O_EXCL creation at %s\n", new_path); ++ int fd = xopen (new_path, O_RDWR | O_EXCL | O_CREAT, 0600); ++ xclose (fd); ++ free (new_path); ++ } ++ ++ { ++ char *subdir_path = xasprintf ("%s/subdir", support_fuse_mountpoint (f)); ++ xmkdir (subdir_path, 01234); ++ } ++ ++ { ++ char *symlink_path = xasprintf ("%s/symlink", support_fuse_mountpoint (f)); ++ char *target = xreadlink (symlink_path); ++ TEST_COMPARE_STRING (target, "target-of-symbolic-link"); ++ free (target); ++ free (symlink_path); ++ } ++ ++ support_fuse_unmount (f); ++ return 0; ++} ++ ++#include diff --git a/glibc-RHEL-108823-8.patch b/glibc-RHEL-108823-8.patch new file mode 100644 index 0000000..c967f2b --- /dev/null +++ b/glibc-RHEL-108823-8.patch @@ -0,0 +1,141 @@ +commit f4ae345810942db891bddf9b482c72b3a120c3b2 +Author: Florian Weimer +Date: Thu Aug 29 11:06:08 2024 +0200 + + io: Add tst-lstat-nofollow, tst-lstat-nofollow-time64 + + They verify that lstat, lstat64 do not follow symbolic links. + + Reviewed-by: DJ Delorie + +diff --git a/io/Makefile b/io/Makefile +index 8ecd2842e20fef97..ed9d4c3eed5941a3 100644 +--- a/io/Makefile ++++ b/io/Makefile +@@ -208,6 +208,7 @@ tests := \ + tst-lchmod \ + tst-linkat \ + tst-lockf \ ++ tst-lstat-nofollow \ + tst-lutimes \ + tst-mkdirat \ + tst-mkfifoat \ +@@ -236,6 +237,7 @@ tests-time64 := \ + tst-futimes-time64\ + tst-futimesat-time64 \ + tst-lchmod-time64 \ ++ tst-lstat-nofollow-time64 \ + tst-lutimes-time64 \ + tst-stat-time64 \ + tst-utime-time64 \ +diff --git a/io/tst-lstat-nofollow-time64.c b/io/tst-lstat-nofollow-time64.c +new file mode 100644 +index 0000000000000000..45feb3f13085ae44 +--- /dev/null ++++ b/io/tst-lstat-nofollow-time64.c +@@ -0,0 +1 @@ ++#include "tst-lstat-nofollow.c" +diff --git a/io/tst-lstat-nofollow.c b/io/tst-lstat-nofollow.c +new file mode 100644 +index 0000000000000000..5bbb557c72938a8a +--- /dev/null ++++ b/io/tst-lstat-nofollow.c +@@ -0,0 +1,98 @@ ++/* Test that lstat does not follow symbolic links. ++ Copyright (C) 2024 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static void ++fuse_thread (struct support_fuse *f, void *closure) ++{ ++ struct fuse_in_header *inh; ++ while ((inh = support_fuse_next (f)) != NULL) ++ { ++ if (support_fuse_handle_mountpoint (f) ++ || (inh->nodeid == 1 && support_fuse_handle_directory (f))) ++ continue; ++ switch (inh->opcode) ++ { ++ case FUSE_LOOKUP: ++ { ++ TEST_COMPARE (inh->nodeid, 1); ++ TEST_COMPARE_STRING (support_fuse_cast (LOOKUP, inh), "symlink"); ++ struct fuse_entry_out *out = support_fuse_prepare_entry (f, 2); ++ out->attr.mode = S_IFLNK | 0777; ++ out->attr.size = strlen ("target"); ++ support_fuse_reply_prepared (f); ++ } ++ break; ++ case FUSE_GETATTR: ++ { ++ TEST_COMPARE (inh->nodeid, 2); ++ struct fuse_attr_out *out = support_fuse_prepare_attr (f); ++ out->attr.mode = S_IFLNK | 0777; ++ out->attr.size = strlen ("target"); ++ support_fuse_reply_prepared (f); ++ } ++ break; ++ case FUSE_READLINK: ++ /* The lstat operation must not attempt to look at the ++ symbolic link target. */ ++ FAIL ("attempt to obtain target of symblic link for node %llu", ++ (unsigned long long int) inh->nodeid); ++ break; ++ default: ++ FAIL ("unexpected event %s", support_fuse_opcode (inh->opcode)); ++ } ++ } ++} ++ ++static int ++do_test (void) ++{ ++ support_fuse_init (); ++ struct support_fuse *f = support_fuse_mount (fuse_thread, NULL); ++ char *symlink_path = xasprintf ("%s/symlink", support_fuse_mountpoint (f)); ++ ++ { ++ struct stat st = { 0, }; ++ TEST_COMPARE (lstat (symlink_path, &st), 0); ++ TEST_COMPARE (st.st_uid, getuid ()); ++ TEST_COMPARE (st.st_gid, getgid ()); ++ TEST_COMPARE (st.st_size, 6); ++ TEST_COMPARE (st.st_mode, S_IFLNK | 0777); ++ } ++ ++ { ++ struct stat64 st = { 0, }; ++ TEST_COMPARE (lstat64 (symlink_path, &st), 0); ++ TEST_COMPARE (st.st_uid, getuid ()); ++ TEST_COMPARE (st.st_gid, getgid ()); ++ TEST_COMPARE (st.st_size, 6); ++ TEST_COMPARE (st.st_mode, S_IFLNK | 0777); ++ } ++ ++ free (symlink_path); ++ support_fuse_unmount (f); ++ return 0; ++} ++ ++#include diff --git a/glibc-RHEL-108823-9.patch b/glibc-RHEL-108823-9.patch new file mode 100644 index 0000000..03dce5d --- /dev/null +++ b/glibc-RHEL-108823-9.patch @@ -0,0 +1,143 @@ +commit 43669fcf7315f494bbbc2c040cedeb0fa8416a5f +Author: Florian Weimer +Date: Thu Aug 22 11:02:51 2024 +0200 + + io: Add FUSE-based test for fchmod + + Test all mode arguments, and that extra bits are ignored + as required by POSIX. + + Reviewed-by: DJ Delorie + +diff --git a/io/Makefile b/io/Makefile +index ed9d4c3eed5941a3..085c7db66a406793 100644 +--- a/io/Makefile ++++ b/io/Makefile +@@ -189,6 +189,7 @@ tests := \ + tst-copy_file_range \ + tst-faccessat \ + tst-fchmod-errors \ ++ tst-fchmod-fuse \ + tst-fchmodat \ + tst-fchownat \ + tst-fcntl \ +diff --git a/io/tst-fchmod-fuse.c b/io/tst-fchmod-fuse.c +new file mode 100644 +index 0000000000000000..fbd3309963491105 +--- /dev/null ++++ b/io/tst-fchmod-fuse.c +@@ -0,0 +1,114 @@ ++/* FUSE-based test for fchmod. ++ Copyright (C) 2024 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 ++ . */ ++ ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Set from do_test to indicate the expected incoming mode change request. */ ++static _Atomic int expected_mode; ++ ++static void ++fuse_thread (struct support_fuse *f, void *closure) ++{ ++ struct fuse_in_header *inh; ++ while ((inh = support_fuse_next (f)) != NULL) ++ { ++ if (support_fuse_handle_mountpoint (f) ++ || (inh->nodeid == 1 && support_fuse_handle_directory (f))) ++ continue; ++ switch (inh->opcode) ++ { ++ case FUSE_LOOKUP: ++ { ++ char *name = support_fuse_cast (LOOKUP, inh); ++ TEST_COMPARE_STRING (name, "file"); ++ struct fuse_entry_out *out ++ = support_fuse_prepare_entry (f, 2); ++ out->attr.mode = S_IFREG | 0600; ++ support_fuse_reply_prepared (f); ++ } ++ break; ++ case FUSE_OPEN: ++ { ++ TEST_COMPARE (inh->nodeid, 2); ++ struct fuse_open_in *p = support_fuse_cast (OPEN, inh); ++ TEST_COMPARE (p->flags & O_ACCMODE, O_RDWR); ++ struct fuse_open_out out = { 0, }; ++ support_fuse_reply (f, &out, sizeof (out)); ++ } ++ break; ++ case FUSE_SETATTR: ++ { ++ TEST_COMPARE (inh->nodeid, 2); ++ struct fuse_setattr_in *p = support_fuse_cast (SETATTR, inh); ++ TEST_COMPARE (p->valid , FATTR_MODE); ++ TEST_COMPARE (p->mode, S_IFREG | expected_mode); ++ struct fuse_attr_out *out = support_fuse_prepare_attr (f); ++ out->attr.mode = S_IFREG | p->mode; ++ support_fuse_reply_prepared (f); ++ } ++ break; ++ case FUSE_FLUSH: ++ support_fuse_reply_empty (f); ++ break; ++ default: ++ support_fuse_reply_error (f, EIO); ++ } ++ } ++} ++ ++/* Test all mode values with the specified extra bits. */ ++static void ++test_with_bits (int fd, unsigned int extra_bits) ++{ ++ for (int do_mode = 0; do_mode <= 07777; ++do_mode) ++ { ++ expected_mode = do_mode; ++ TEST_COMPARE (fchmod (fd, extra_bits | do_mode), 0); ++ } ++} ++ ++static int ++do_test (void) ++{ ++ support_fuse_init (); ++ ++ struct support_fuse *f = support_fuse_mount (fuse_thread, NULL); ++ char *path = xasprintf ("%s/file", support_fuse_mountpoint (f)); ++ int fd = xopen (path, O_RDWR, 0600); ++ free (path); ++ ++ test_with_bits (fd, 0); ++ /* POSIX requires that the extra bits are ignored. */ ++ test_with_bits (fd, S_IFREG); ++ test_with_bits (fd, S_IFDIR); ++ test_with_bits (fd, ~07777); ++ ++ xclose (fd); ++ support_fuse_unmount (f); ++ ++ return 0; ++} ++ ++#include diff --git a/glibc-RHEL-108974-1.patch b/glibc-RHEL-108974-1.patch new file mode 100644 index 0000000..5608e8e --- /dev/null +++ b/glibc-RHEL-108974-1.patch @@ -0,0 +1,41 @@ +commit 400bdb5c85af5a52b3f5653357c9fca87f036bd3 +Author: Paul Eggert +Date: Tue May 28 10:07:47 2024 -0700 + + Improve doc for time_t range (BZ 31808) + +diff --git a/manual/time.texi b/manual/time.texi +index 7d9efc7c6f5b8a43..2e029975b952ac29 100644 +--- a/manual/time.texi ++++ b/manual/time.texi +@@ -123,7 +123,7 @@ The number of clock ticks per second is system-specific. + @code{time_t} is the simplest data type used to represent simple + calendar time. + +-In ISO C, @code{time_t} can be either an integer or a floating-point ++In ISO C, @code{time_t} can be either an integer or a real floating + type, and the meaning of @code{time_t} values is not specified. The + only things a strictly conforming program can do with @code{time_t} + values are: pass them to @code{difftime} to get the elapsed time +@@ -134,11 +134,21 @@ and pass them to the functions that convert them to broken-down time + On POSIX-conformant systems, @code{time_t} is an integer type and its + values represent the number of seconds elapsed since the @dfn{epoch}, + which is 00:00:00 on January 1, 1970, Coordinated Universal Time. ++The count of seconds ignores leap seconds. + + @Theglibc{} additionally guarantees that @code{time_t} is a signed + type, and that all of its functions operate correctly on negative + @code{time_t} values, which are interpreted as times before the epoch. ++Functions like @code{localtime} assume the Gregorian calendar even ++though this is historically inaccurate for timestamps before the ++calendar was introduced or after the calendar will become obsolete. + @cindex epoch ++@Theglibc{} also supports leap seconds as an option, in which case ++@code{time_t} counts leap seconds instead of ignoring them. ++Currently the @code{time_t} type is 64 bits wide on all platforms ++supported by @theglibc{}, except that it is 32 bits wide on a few ++older platforms unless you define @code{_TIME_BITS} to 64. ++@xref{Feature Test Macros}. + @end deftp + + @deftp {Data Type} {struct timespec} diff --git a/glibc-RHEL-108974-10.patch b/glibc-RHEL-108974-10.patch new file mode 100644 index 0000000..700841f --- /dev/null +++ b/glibc-RHEL-108974-10.patch @@ -0,0 +1,70 @@ +commit 7fe1fde499507126f7de10ebf12fecaf77ae6602 +Author: Joseph Myers +Date: Mon Oct 28 22:22:26 2024 +0000 + + Document further requirement on mixing streams / file descriptors + + The gilbc manual has some documentation in llio.texi of requirements + for moving between I/O on FILE * streams and file descriptors on the + same open file description. + + The documentation of what must be done on a FILE * stream to move from + it to either a file descriptor or another FILE * for the same open + file description seems to match POSIX. However, there is an + additional requirement in POSIX on the *second* of the two handles + being moved between, which is not mentioned in the glibc manual: "If + any previous active handle has been used by a function that explicitly + changed the file offset, except as required above for the first + handle, the application shall perform an lseek() or fseek() (as + appropriate to the type of handle) to an appropriate location.". + + Document this requirement on seeking in the glibc manual, limited to + the case that seems relevant to glibc (the new channel is a previously + active stream, on which the seeking previously occurred). Note that + I'm not sure what the "except as required above for the first handle" + is meant to be about, so I haven't documented anything for it. As far + as I can tell, nothing specified for moving from the first handle + actually list calling a seek function as one of the steps to be done. + (Current POSIX doesn't seem to have any relevant rationale for this + section. The rationale in the 1996 edition says "In requiring the + seek to an appropriate location for the new handle, the application is + required to know what it is doing if it is passing streams with seeks + involved. If the required seek is not done, the results are undefined + (and in fact the program probably will not work on many common + implementations)." - which also doesn't help in understanding the + purpose of "except as required above for the first handle".) + + Tested with "make info" and "make pdf". + +diff --git a/manual/llio.texi b/manual/llio.texi +index 850d09205a604589..7121a513a6d6d41b 100644 +--- a/manual/llio.texi ++++ b/manual/llio.texi +@@ -1097,6 +1097,27 @@ streams persist in other processes, their file positions become + undefined as a result. To prevent this, you must clean up the streams + before destroying them. + ++In addition to cleaning up a stream before doing I/O using another ++linked channel, additional precautions are needed to ensure a ++well-defined file position indicator in some cases. If both the ++following conditions hold, you must set the file position indicator on ++the new channel (a stream) using a function such as @code{fseek}. ++ ++@itemize @bullet ++@item ++The new linked channel is a stream that was previously active. ++ ++@item ++The file position indicator was previously set on that channel (while ++it was previously active) with a function such as @code{fseek}. ++@end itemize ++ ++POSIX requires such precautions in more cases: if either the old or ++the new linked channel is a stream (whether or not previously active) ++and the file position indicator was previously set on any channel ++linked to those channels with a function such as @code{fseek} or ++@code{lseek}. ++ + @node Independent Channels + @subsection Independent Channels + @cindex independent channels diff --git a/glibc-RHEL-108974-11.patch b/glibc-RHEL-108974-11.patch new file mode 100644 index 0000000..e9e4d11 --- /dev/null +++ b/glibc-RHEL-108974-11.patch @@ -0,0 +1,146 @@ +commit b7d4de086ce7fcc531cdd67a61dc27b5b3eff482 +Author: Florian Weimer +Date: Mon Aug 5 16:01:12 2024 +0200 + + manual: Describe struct link_map, support link maps with dlinfo + + This does not describe how to use RTLD_DI_ORIGIN and l_name + to reconstruct a full path for the an object. The reason + is that I think we should not recommend further use of + RTLD_DI_ORIGIN due to its buffer overflow potential (bug 24298). + This should be covered by another dlinfo extension. It would + also obsolete the need for the dladdr approach to obtain + the file name for the main executable. + + Obtaining the lowest address from load segments in program + headers is quite clumsy and should be provided directly + via dlinfo. + + Reviewed-by: Carlos O'Donell + +diff --git a/manual/dynlink.texi b/manual/dynlink.texi +index d71f7a30d6f46808..ead5455e30c10a61 100644 +--- a/manual/dynlink.texi ++++ b/manual/dynlink.texi +@@ -351,16 +351,119 @@ support the XGETBV instruction. + @node Dynamic Linker Introspection + @section Dynamic Linker Introspection + +-@Theglibc{} provides various functions for querying information from the ++@Theglibc{} provides various facilities for querying information from the + dynamic linker. + ++@deftp {Data Type} {struct link_map} ++ ++@cindex link map ++A @dfn{link map} is associated with the main executable and each shared ++object. Some fields of the link map are accessible to applications and ++exposed through the @code{struct link_map}. Applications must not modify ++the link map directly. ++ ++Pointers to link maps can be obtained from the @code{_r_debug} variable, ++from the @code{RTLD_DI_LINKMAP} request for @code{dlinfo}, and from the ++@code{_dl_find_object} function. See below for details. ++ ++@table @code ++@item l_addr ++@cindex load address ++This field contains the @dfn{load address} of the object. This is the ++offset that needs to be applied to unrelocated addresses in the object ++image (as stored on disk) to form an address that can be used at run ++time for accessing data or running code. For position-dependent ++executables, the load address is typically zero, and no adjustment is ++required. For position-independent objects, the @code{l_addr} field ++usually contains the address of the object's ELF header in the process ++image. However, this correspondence is not guaranteed because the ELF ++header might not be mapped at all, and the ELF file as stored on disk ++might use zero as the lowest virtual address. Due to the second ++variable, values of the @code{l_addr} field do not necessarily uniquely ++identify a shared object. ++ ++On Linux, to obtain the lowest loaded address of the main program, use ++@code{getauxval} to obtain the @code{AT_PHDR} and @code{AT_PHNUM} values ++for the current process. Alternatively, call ++@samp{dlinfo (_r_debug.r_map, &@var{phdr})} ++to obtain the number of program headers, and the address of the program ++header array will be stored in @var{phdr} ++(of type @code{const ElfW(Phdr) *}, as explained below). ++These values allow processing the array of program headers and the ++address information in the @code{PT_LOAD} entries among them. ++This works even when the program was started with an explicit loader ++invocation. ++ ++@item l_name ++For a shared object, this field contains the file name that the ++@theglibc{} dynamic loader used when opening the object. This can be ++a relative path (relative to the current directory at process start, ++or if the object was loaded later, via @code{dlopen} or ++@code{dlmopen}). Symbolic links are not necessarily resolved. ++ ++For the main executable, @code{l_name} is @samp{""} (the empty string). ++(The main executable is not loaded by @theglibc{}, so its file name is ++not available.) On Linux, the main executable is available as ++@file{/proc/self/exe} (unless an explicit loader invocation was used to ++start the program). The file name @file{/proc/self/exe} continues to ++resolve to the same file even if it is moved within or deleted from the ++file system. Its current location can be read using @code{readlink}. ++@xref{Symbolic Links}. (Although @file{/proc/self/exe} is not actually ++a symbol link, it is only presented as one.) Note that @file{/proc} may ++not be mounted, in which case @file{/proc/self/exe} is not available. ++ ++If an explicit loader invocation is used (such as @samp{ld.so ++/usr/bin/emacs}), the @file{/proc/self/exe} approach does not work ++because the file name refers to the dynamic linker @code{ld.so}, and not ++the @code{/usr/bin/emacs} program. An approximation to the executable ++path is still available in the @code{@var{info}.dli_fname} member after ++calling @samp{dladdr (_r_debug.r_map->l_ld, &@var{info})}. Note that ++this could be a relative path, and it is supplied by the process that ++created the current process, not the kernel, so it could be inaccurate. ++ ++@item l_ld ++This is a pointer to the ELF dynamic segment, an array of tag/value ++pairs that provide various pieces of information that the dynamic ++linking process uses. On most architectures, addresses in the dynamic ++segment are relocated at run time, but on some architectures and in some ++run-time configurations, it is necessary to add the @code{l_addr} field ++value to obtain a proper address. ++ ++@item l_prev ++@itemx l_next ++These fields are used to maintain a double-linked linked list of all ++link maps within one @code{dlmopen} namespace. Note that there is ++currently no thread-safe way to iterate over this list. The ++callback-based @code{dl_iterate_phdr} interface can be used instead. ++@end table ++@end deftp ++ ++@strong{Portability note:} It is not possible to create a @code{struct ++link_map} object and pass a pointer to a function that expects a ++@code{struct link_map *} argument. Only link map pointers initially ++supplied by @theglibc{} are permitted as arguments. In current versions ++of @theglibc{}, handles returned by @code{dlopen} and @code{dlmopen} are ++pointers to link maps. However, this is not a portable assumption, and ++may even change in future versions of @theglibc{}. To obtain the link ++map associated with a handle, see @code{dlinfo} and ++@code{RTLD_DI_LINKMAP} below. If a function accepts both ++@code{dlopen}/@code{dlmopen} handles and @code{struct link_map} pointers ++in its @code{void *} argument, that is documented explicitly. ++ ++@subsection Querying information for loaded objects ++ ++The @code{dlinfo} function provides access to internal information ++associated with @code{dlopen}/@code{dlmopen} handles and link maps. ++ + @deftypefun {int} dlinfo (void *@var{handle}, int @var{request}, void *@var{arg}) + @safety{@mtsafe{}@asunsafe{@asucorrupt{}}@acunsafe{@acucorrupt{}}} + @standards{GNU, dlfcn.h} + This function returns information about @var{handle} in the memory + location @var{arg}, based on @var{request}. The @var{handle} argument + must be a pointer returned by @code{dlopen} or @code{dlmopen}; it must +-not have been closed by @code{dlclose}. ++not have been closed by @code{dlclose}. Alternatively, @var{handle} ++can be a @code{struct link_map *} value for a link map of an object ++that has not been closed. + + On success, @code{dlinfo} returns 0 for most request types; exceptions + are noted below. If there is an error, the function returns @math{-1}, diff --git a/glibc-RHEL-108974-12.patch b/glibc-RHEL-108974-12.patch new file mode 100644 index 0000000..e504313 --- /dev/null +++ b/glibc-RHEL-108974-12.patch @@ -0,0 +1,83 @@ +commit 87cd94bba4091d22e24116298ade33b712ada235 +Author: DJ Delorie +Date: Tue Dec 10 17:07:21 2024 -0500 + + manual: Document more sigaction flags + + Adds documentation for three-argument handler + + Adds remainder of the SA_* flags + + Reviewed-by: Florian Weimer + +diff --git a/manual/signal.texi b/manual/signal.texi +index 5c2ba7dae6072926..2012980efe5e2ccc 100644 +--- a/manual/signal.texi ++++ b/manual/signal.texi +@@ -1141,6 +1141,15 @@ This is used in the same way as the @var{action} argument to the + @code{signal} function. The value can be @code{SIG_DFL}, + @code{SIG_IGN}, or a function pointer. @xref{Basic Signal Handling}. + ++@item void (*sa_sigaction) (int @var{signum}, siginfo_t *@var{info}, void *@var{ucontext}) ++This is an alternate to @code{sa_handler} that is used when the ++@code{sa_flags} includes the @code{flag SA_SIGINFO}. Note that this ++and @code{sa_handler} overlap; only ever set one at a time. ++ ++The contents of the @var{info} and @var{ucontext} structures are ++kernel and architecture dependent. Please see ++@manpageurl{sigaction,2} for details. ++ + @item sigset_t sa_mask + This specifies a set of signals to be blocked while the handler runs. + Blocking is explained in @ref{Blocking for Handler}. Note that the +@@ -1324,6 +1333,24 @@ delivered for both terminated children and stopped children. + Setting this flag for a signal other than @code{SIGCHLD} has no effect. + @end deftypevr + ++@deftypevr Macro int SA_NOCLDWAIT ++This flag is meaningful only for the @code{SIGCHLD} signal. When the ++flag is set, the terminated child will not wait for the parent to reap ++it, or become a zombie if not reaped. The child will instead be ++reaped by the kernel immediately on termination, similar to setting ++SIGCHLD to SIG_IGN. ++ ++Setting this flag for a signal other than @code{SIGCHLD} has no effect. ++@end deftypevr ++ ++@deftypevr Macro int SA_NODEFER ++Normally a signal is added to the signal mask while running its own ++handler; this negates that, so that the same signal can be received ++while it's handler is running. Note that if the signal is included in ++@code{sa_mask}, it is masked regardless of this flag. Only useful when ++assigning a function as a signal handler. ++@end deftypevr ++ + @deftypevr Macro int SA_ONSTACK + @standards{BSD, signal.h} + If this flag is set for a particular signal number, the system uses the +@@ -1332,6 +1359,12 @@ If a signal with this flag arrives and you have not set a signal stack, + the normal user stack is used instead, as if the flag had not been set. + @end deftypevr + ++@deftypevr Macro int SA_RESETHAND ++Resets the handler for a signal to SIG_DFL, at the moment specified ++handler function begins. I.e. the handler is called once, then the ++action resets. ++@end deftypevr ++ + @deftypevr Macro int SA_RESTART + @standards{BSD, signal.h} + This flag controls what happens when a signal is delivered during +@@ -1347,6 +1380,12 @@ clear, returning from a handler makes the function fail. + @xref{Interrupted Primitives}. + @end deftypevr + ++@deftypevr Macro int SA_SIGINFO ++Indicates that the @code{sa_sigaction} three-argument form of the ++handler should be used in setting up a handler instead of the ++one-argument @code{sa_handler} form. ++@end deftypevr ++ + @node Initial Signal Actions + @subsection Initial Signal Actions + @cindex initial signal actions diff --git a/glibc-RHEL-108974-13.patch b/glibc-RHEL-108974-13.patch new file mode 100644 index 0000000..73762e4 --- /dev/null +++ b/glibc-RHEL-108974-13.patch @@ -0,0 +1,220 @@ +commit a3a5634d9b0e193502d16488205452598dc4aa74 +Author: Arjun Shankar +Date: Tue Jan 14 02:52:09 2025 +0100 + + manual: Consolidate POSIX Semaphores docs in Threads chapter + + This commit moves the `sem_*' family of functions from the IPC chapter, + replacing them with a reference to their new location in the Threads + chapter. `sem_clockwait' is also moved out of the Non-POSIX Extensions + subsection since it is now included in the standard since Issue 8: + https://pubs.opengroup.org/onlinepubs/9799919799/functions/sem_clockwait.html + + Reviewed-by: Adhemerval Zanella + +diff --git a/manual/ipc.texi b/manual/ipc.texi +index 32c5ac066fb94579..f9c763835961ec32 100644 +--- a/manual/ipc.texi ++++ b/manual/ipc.texi +@@ -46,71 +46,6 @@ by @theglibc{}. + @end deftypefun + + @subsection POSIX Semaphores +- +-@deftypefun int sem_init (sem_t *@var{sem}, int @var{pshared}, unsigned int @var{value}) +-@safety{@prelim{}@mtsafe{}@assafe{}@acunsafe{@acucorrupt{}}} +-@c Does not atomically update sem_t therefore AC-unsafe +-@c because it can leave sem_t partially initialized. +-@end deftypefun +- +-@deftypefun int sem_destroy (sem_t *@var{sem}) +-@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}} +-@c Function does nothing and is therefore always safe. +-@end deftypefun +- +-@deftypefun {sem_t *} sem_open (const char *@var{name}, int @var{oflag}, ...) +-@safety{@prelim{}@mtsafe{}@asunsafe{@asuinit{}}@acunsafe{@acuinit{}}} +-@c pthread_once asuinit +-@c +-@c We are AC-Unsafe because we use pthread_once to initialize +-@c a global variable that holds the location of the mounted +-@c shmfs on Linux. +-@end deftypefun +- +-@deftypefun int sem_close (sem_t *@var{sem}) +-@safety{@prelim{}@mtsafe{}@asunsafe{@asulock{}}@acunsafe{@aculock{}}} +-@c lll_lock asulock aculock +-@c twalk mtsrace{:root} +-@c +-@c We are AS-unsafe because we take a non-recursive lock. +-@c We are AC-unsafe because several internal data structures +-@c are not updated atomically. +-@end deftypefun +- +-@deftypefun int sem_unlink (const char *@var{name}) +-@safety{@prelim{}@mtsafe{}@asunsafe{@asuinit{}}@acunsafe{@acucorrupt{}}} +-@c pthread_once asuinit acucorrupt aculock +-@c mempcpy acucorrupt +-@end deftypefun +- +-@deftypefun int sem_wait (sem_t *@var{sem}) +-@safety{@prelim{}@mtsafe{}@assafe{}@acunsafe{@acucorrupt{}}} +-@c atomic_fetch_add_relaxed (nwaiters) acucorrupt +-@c +-@c Given the use atomic operations this function seems +-@c to be AS-safe. It is AC-unsafe because there is still +-@c a window between atomic_fetch_add_relaxed and the pthread_push +-@c of the handler that undoes that operation. A cancellation +-@c at that point would fail to remove the process from the +-@c waiters count. +-@end deftypefun +- +-@deftypefun int sem_timedwait (sem_t *@var{sem}, const struct timespec *@var{abstime}) +-@safety{@prelim{}@mtsafe{}@assafe{}@acunsafe{@acucorrupt{}}} +-@c Same safety issues as sem_wait. +-@end deftypefun +- +-@deftypefun int sem_trywait (sem_t *@var{sem}) +-@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}} +-@c All atomic operations are safe in all contexts. +-@end deftypefun +- +-@deftypefun int sem_post (sem_t *@var{sem}) +-@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}} +-@c Same safety as sem_trywait. +-@end deftypefun +- +-@deftypefun int sem_getvalue (sem_t *@var{sem}, int *@var{sval}) +-@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}} +-@c Atomic write of a value is safe in all contexts. +-@end deftypefun ++@Theglibc{} provides POSIX semaphores as well. These functions' names begin ++with @code{sem_} and they are declared in @file{semaphore.h}. @xref{POSIX ++Semaphores}. +diff --git a/manual/threads.texi b/manual/threads.texi +index 9ea137cb9663b89c..806ab866c5231015 100644 +--- a/manual/threads.texi ++++ b/manual/threads.texi +@@ -554,6 +554,8 @@ This section describes the @glibcadj{} POSIX Threads implementation. + @menu + * Thread-specific Data:: Support for creating and + managing thread-specific data ++* POSIX Semaphores:: Support for process and thread ++ synchronization using semaphores + * Non-POSIX Extensions:: Additional functions to extend + POSIX Thread functionality + @end menu +@@ -615,6 +617,86 @@ Associate the thread-specific @var{value} with @var{key} in the calling thread. + @end deftypefun + + ++@node POSIX Semaphores ++@subsection POSIX Semaphores ++ ++@deftypefun int sem_init (sem_t *@var{sem}, int @var{pshared}, unsigned int @var{value}) ++@safety{@prelim{}@mtsafe{}@assafe{}@acunsafe{@acucorrupt{}}} ++@c Does not atomically update sem_t therefore AC-unsafe ++@c because it can leave sem_t partially initialized. ++@end deftypefun ++ ++@deftypefun int sem_destroy (sem_t *@var{sem}) ++@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}} ++@c Function does nothing and is therefore always safe. ++@end deftypefun ++ ++@deftypefun {sem_t *} sem_open (const char *@var{name}, int @var{oflag}, ...) ++@safety{@prelim{}@mtsafe{}@asunsafe{@asuinit{}}@acunsafe{@acuinit{}}} ++@c pthread_once asuinit ++@c ++@c We are AC-Unsafe because we use pthread_once to initialize ++@c a global variable that holds the location of the mounted ++@c shmfs on Linux. ++@end deftypefun ++ ++@deftypefun int sem_close (sem_t *@var{sem}) ++@safety{@prelim{}@mtsafe{}@asunsafe{@asulock{}}@acunsafe{@aculock{}}} ++@c lll_lock asulock aculock ++@c twalk mtsrace{:root} ++@c ++@c We are AS-unsafe because we take a non-recursive lock. ++@c We are AC-unsafe because several internal data structures ++@c are not updated atomically. ++@end deftypefun ++ ++@deftypefun int sem_unlink (const char *@var{name}) ++@safety{@prelim{}@mtsafe{}@asunsafe{@asuinit{}}@acunsafe{@acucorrupt{}}} ++@c pthread_once asuinit acucorrupt aculock ++@c mempcpy acucorrupt ++@end deftypefun ++ ++@deftypefun int sem_wait (sem_t *@var{sem}) ++@safety{@prelim{}@mtsafe{}@assafe{}@acunsafe{@acucorrupt{}}} ++@c atomic_fetch_add_relaxed (nwaiters) acucorrupt ++@c ++@c Given the use atomic operations this function seems ++@c to be AS-safe. It is AC-unsafe because there is still ++@c a window between atomic_fetch_add_relaxed and the pthread_push ++@c of the handler that undoes that operation. A cancellation ++@c at that point would fail to remove the process from the ++@c waiters count. ++@end deftypefun ++ ++@deftypefun int sem_timedwait (sem_t *@var{sem}, const struct timespec *@var{abstime}) ++@safety{@prelim{}@mtsafe{}@assafe{}@acunsafe{@acucorrupt{}}} ++@c Same safety issues as sem_wait. ++@end deftypefun ++ ++@deftypefun int sem_clockwait (sem_t *@var{sem}, clockid_t @var{clockid}, const struct timespec *@var{abstime}) ++@safety{@prelim{}@mtsafe{}@asunsafe{@asulock{}}@acunsafe{@aculock{}}} ++Behaves like @code{sem_timedwait} except the time @var{abstime} is measured ++against the clock specified by @var{clockid} rather than ++@code{CLOCK_REALTIME}. Currently, @var{clockid} must be either ++@code{CLOCK_MONOTONIC} or @code{CLOCK_REALTIME}. ++@end deftypefun ++ ++@deftypefun int sem_trywait (sem_t *@var{sem}) ++@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}} ++@c All atomic operations are safe in all contexts. ++@end deftypefun ++ ++@deftypefun int sem_post (sem_t *@var{sem}) ++@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}} ++@c Same safety as sem_trywait. ++@end deftypefun ++ ++@deftypefun int sem_getvalue (sem_t *@var{sem}, int *@var{sval}) ++@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}} ++@c Atomic write of a value is safe in all contexts. ++@end deftypefun ++ ++ + @node Non-POSIX Extensions + @subsection Non-POSIX Extensions + +@@ -752,16 +834,6 @@ freed. + @Theglibc{} provides several waiting functions that expect an explicit + @code{clockid_t} argument. + +-@comment semaphore.h +-@comment POSIX-proposed +-@deftypefun int sem_clockwait (sem_t *@var{sem}, clockid_t @var{clockid}, const struct timespec *@var{abstime}) +-@safety{@prelim{}@mtsafe{}@asunsafe{@asulock{}}@acunsafe{@aculock{}}} +-Behaves like @code{sem_timedwait} except the time @var{abstime} is measured +-against the clock specified by @var{clockid} rather than +-@code{CLOCK_REALTIME}. Currently, @var{clockid} must be either +-@code{CLOCK_MONOTONIC} or @code{CLOCK_REALTIME}. +-@end deftypefun +- + @comment pthread.h + @comment POSIX-proposed + @deftypefun int pthread_cond_clockwait (pthread_cond_t *@var{cond}, pthread_mutex_t *@var{mutex}, clockid_t @var{clockid}, const struct timespec *@var{abstime}) +@@ -835,6 +907,9 @@ Currently, @var{clockid} must be either @code{CLOCK_MONOTONIC} or + @code{CLOCK_REALTIME}. + @end deftypefun + ++The @code{sem_clockwait} function also works using a @code{clockid_t} ++argument. @xref{POSIX Semaphores}. ++ + @node Single-Threaded + @subsubsection Detecting Single-Threaded Execution + diff --git a/glibc-RHEL-108974-14.patch b/glibc-RHEL-108974-14.patch new file mode 100644 index 0000000..3ff468d --- /dev/null +++ b/glibc-RHEL-108974-14.patch @@ -0,0 +1,111 @@ +commit 47c4f4045caaaad1e6165cb638e45d633d6ca97f +Author: Arjun Shankar +Date: Tue Jan 14 02:52:10 2025 +0100 + + manual: Add links to POSIX Semaphores man-pages documentation + + The POSIX Semaphores functions are currently undocumented in our info + pages. This commit adds links to the man-pages documentation for all + the `sem_*' functions (except `sem_clockwait') so that they refer to + some useful documentation instead of just being stubs. `sem_clockwait' + isn't documented by man-pages but thankfully already has a small useful + blurb in our own docs. + + Reviewed-by: Adhemerval Zanella + +diff --git a/manual/threads.texi b/manual/threads.texi +index 806ab866c5231015..7b9c79636c9cc79c 100644 +--- a/manual/threads.texi ++++ b/manual/threads.texi +@@ -621,18 +621,24 @@ Associate the thread-specific @var{value} with @var{key} in the calling thread. + @subsection POSIX Semaphores + + @deftypefun int sem_init (sem_t *@var{sem}, int @var{pshared}, unsigned int @var{value}) ++@standards{POSIX.1-2008, semaphore.h} + @safety{@prelim{}@mtsafe{}@assafe{}@acunsafe{@acucorrupt{}}} ++@manpagefunctionstub{sem_init,3} + @c Does not atomically update sem_t therefore AC-unsafe + @c because it can leave sem_t partially initialized. + @end deftypefun + + @deftypefun int sem_destroy (sem_t *@var{sem}) ++@standards{POSIX.1-2008, semaphore.h} + @safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}} ++@manpagefunctionstub{sem_destroy,3} + @c Function does nothing and is therefore always safe. + @end deftypefun + + @deftypefun {sem_t *} sem_open (const char *@var{name}, int @var{oflag}, ...) ++@standards{POSIX.1-2008, semaphore.h} + @safety{@prelim{}@mtsafe{}@asunsafe{@asuinit{}}@acunsafe{@acuinit{}}} ++@manpagefunctionstub{sem_open,3} + @c pthread_once asuinit + @c + @c We are AC-Unsafe because we use pthread_once to initialize +@@ -641,7 +647,9 @@ Associate the thread-specific @var{value} with @var{key} in the calling thread. + @end deftypefun + + @deftypefun int sem_close (sem_t *@var{sem}) ++@standards{POSIX.1-2008, semaphore.h} + @safety{@prelim{}@mtsafe{}@asunsafe{@asulock{}}@acunsafe{@aculock{}}} ++@manpagefunctionstub{sem_close,3} + @c lll_lock asulock aculock + @c twalk mtsrace{:root} + @c +@@ -651,13 +659,17 @@ Associate the thread-specific @var{value} with @var{key} in the calling thread. + @end deftypefun + + @deftypefun int sem_unlink (const char *@var{name}) ++@standards{POSIX.1-2008, semaphore.h} + @safety{@prelim{}@mtsafe{}@asunsafe{@asuinit{}}@acunsafe{@acucorrupt{}}} ++@manpagefunctionstub{sem_unlink,3} + @c pthread_once asuinit acucorrupt aculock + @c mempcpy acucorrupt + @end deftypefun + + @deftypefun int sem_wait (sem_t *@var{sem}) ++@standards{POSIX.1-2008, semaphore.h} + @safety{@prelim{}@mtsafe{}@assafe{}@acunsafe{@acucorrupt{}}} ++@manpagefunctionstub{sem_wait,3} + @c atomic_fetch_add_relaxed (nwaiters) acucorrupt + @c + @c Given the use atomic operations this function seems +@@ -669,11 +681,14 @@ Associate the thread-specific @var{value} with @var{key} in the calling thread. + @end deftypefun + + @deftypefun int sem_timedwait (sem_t *@var{sem}, const struct timespec *@var{abstime}) ++@standards{POSIX.1-2008, semaphore.h} + @safety{@prelim{}@mtsafe{}@assafe{}@acunsafe{@acucorrupt{}}} ++@manpagefunctionstub{sem_timedwait,3} + @c Same safety issues as sem_wait. + @end deftypefun + + @deftypefun int sem_clockwait (sem_t *@var{sem}, clockid_t @var{clockid}, const struct timespec *@var{abstime}) ++@standards{POSIX.1-2024, semaphore.h} + @safety{@prelim{}@mtsafe{}@asunsafe{@asulock{}}@acunsafe{@aculock{}}} + Behaves like @code{sem_timedwait} except the time @var{abstime} is measured + against the clock specified by @var{clockid} rather than +@@ -682,17 +697,23 @@ against the clock specified by @var{clockid} rather than + @end deftypefun + + @deftypefun int sem_trywait (sem_t *@var{sem}) ++@standards{POSIX.1-2008, semaphore.h} + @safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}} ++@manpagefunctionstub{sem_trywait,3} + @c All atomic operations are safe in all contexts. + @end deftypefun + + @deftypefun int sem_post (sem_t *@var{sem}) ++@standards{POSIX.1-2008, semaphore.h} + @safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}} ++@manpagefunctionstub{sem_post,3} + @c Same safety as sem_trywait. + @end deftypefun + + @deftypefun int sem_getvalue (sem_t *@var{sem}, int *@var{sval}) ++@standards{POSIX.1-2008, semaphore.h} + @safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}} ++@manpagefunctionstub{sem_getvalue,3} + @c Atomic write of a value is safe in all contexts. + @end deftypefun + diff --git a/glibc-RHEL-108974-15.patch b/glibc-RHEL-108974-15.patch new file mode 100644 index 0000000..ca629f2 --- /dev/null +++ b/glibc-RHEL-108974-15.patch @@ -0,0 +1,31 @@ +commit 1b29cb7b781ecf3f6dc4647c32861119bacbd5ef +Author: Tulio Magno Quites Machado Filho +Date: Tue Jan 28 15:31:01 2025 -0300 + + manual: Safety annotations for timespec_get and timespec_getres + + Add preliminary annotations that are consistent with clock_gettime and + clock_getres. + + Reviewed-by: Florian Weimer + +diff --git a/manual/time.texi b/manual/time.texi +index 6ccb07fcfc10449b..6abae3f43640e8ec 100644 +--- a/manual/time.texi ++++ b/manual/time.texi +@@ -595,6 +595,7 @@ Systems may support more than just this @w{ISO C} clock. + + @deftypefun int timespec_get (struct timespec *@var{ts}, int @var{base}) + @standards{ISO, time.h} ++@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}} + Store into @code{*@var{ts}} the current time according to the @w{ISO + C} time @var{base}. + +@@ -603,6 +604,7 @@ The return value is @var{base} on success and @code{0} on failure. + + @deftypefun int timespec_getres (struct timespec *@var{res}, int @var{base}) + @standards{ISO, time.h} ++@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}} + If @var{ts} is non-null, store into @code{*@var{ts}} the resolution of + the time provided by @code{timespec_get} function for the @w{ISO C} + time @var{base}. diff --git a/glibc-RHEL-108974-16.patch b/glibc-RHEL-108974-16.patch new file mode 100644 index 0000000..69d20b9 --- /dev/null +++ b/glibc-RHEL-108974-16.patch @@ -0,0 +1,94 @@ +commit 37a0933e1bf97346b45463bde0c4631be8abaa07 +Author: DJ Delorie +Date: Tue Dec 10 16:57:21 2024 -0500 + + manual: make @manpageurl more specific to each output + + Tweak the @manpageurl macro to customize the output for + each of html, info, and pdf output. HTML and PDF (at + least, these days) support clicking on the link title, + whereas info does not. Add text to the intro section + explaining which man pages are normative and which + aren't. + +diff --git a/manual/intro.texi b/manual/intro.texi +index 879c1b38d9b73a46..d95648468db6f224 100644 +--- a/manual/intro.texi ++++ b/manual/intro.texi +@@ -966,13 +966,25 @@ functionality is available on commercial systems. + + @Theglibc{} includes by reference the Linux man-pages + @value{man_pages_version} documentation to document the listed +-syscalls for the Linux kernel. For reference purposes only the latest ++syscalls for the Linux kernel. For reference purposes only, the latest + @uref{https://www.kernel.org/doc/man-pages/,Linux man-pages Project} + documentation can be accessed from the + @uref{https://www.kernel.org,Linux kernel} website. Where the syscall + has more specific documentation in this manual that more specific + documentation is considered authoritative. + ++Throughout this manual, when we refer to a man page, for example: ++@quotation ++@manpageurl{sendmsg,2} ++@end quotation ++@noindent ++we are referring primarily to the specific version noted above (the ++``normative'' version), typically accessed by running (for example) ++@code{man 2 sendmsg} on a system with that version installed. For ++convenience, we will also link to the online latest copy of the man ++pages, but keep in mind that version will almost always be newer than, ++and thus different than, the normative version noted above. ++ + Additional details on the Linux system call interface can be found in + @xref{System Calls}. + +diff --git a/manual/macros.texi b/manual/macros.texi +index f48dd4ec2282634f..2003ce2678054ae4 100644 +--- a/manual/macros.texi ++++ b/manual/macros.texi +@@ -282,14 +282,22 @@ cwd\comments\ + @macro standardsx {element, standard, header} + @end macro + ++@ifhtml + @macro manpageurl {func, sec} +-@url{https://man7.org/linux/man-pages/man\sec\/\func\.\sec\.html} ++@url{https://man7.org/linux/man-pages/man\sec\/\func\.\sec\.html,,\func\(\sec\)} ++@xref{Linux Kernel} + @end macro ++@end ifhtml ++@ifnothtml ++@macro manpageurl {func, sec} ++\func\(\sec\) (Latest, online: @url{https://man7.org/linux/man-pages/man\sec\/\func\.\sec\.html}) ++@xref{Linux Kernel} ++@end macro ++@end ifnothtml + + @macro manpagefunctionstub {func,sec} + This documentation is a stub. For additional information on this + function, consult the manual page @manpageurl{\func\,\sec\}. +-@xref{Linux Kernel}. + @end macro + + @end ifclear +diff --git a/manual/resource.texi b/manual/resource.texi +index 6729ada79402f0ad..23952a6b8b9f4f58 100644 +--- a/manual/resource.texi ++++ b/manual/resource.texi +@@ -966,7 +966,6 @@ scheduling policies. + + For additional information about scheduling policies, consult consult + the manual pages @manpageurl{sched,7} and @manpageurl{sched_setattr,2}. +-@xref{Linux Kernel}. + + @strong{Note:} Calling the @code{sched_setattr} function is incompatible + with support for @code{PTHREAD_PRIO_PROTECT} mutexes. +@@ -1000,7 +999,7 @@ Scheduling flags associated with the scheduling policy. + + In addition to the generic fields, policy-specific fields are available. + For additional information, consult the manual page +-@manpageurl{sched_setattr,2}. @xref{Linux Kernel}. ++@manpageurl{sched_setattr,2}. + @end deftp + + @deftypefun int sched_setattr (pid_t @var{tid}, struct sched_attr *@var{attr}, unsigned int flags) diff --git a/glibc-RHEL-108974-17.patch b/glibc-RHEL-108974-17.patch new file mode 100644 index 0000000..7e2532f --- /dev/null +++ b/glibc-RHEL-108974-17.patch @@ -0,0 +1,86 @@ +commit bb6496b96444dfd55d7105396780f6eba14b1cd9 +Author: DJ Delorie +Date: Fri Jan 17 17:34:02 2025 -0500 + + manual: Update signal descriptions + + Based on auditing all the signals and source trees for Hurd and + Linux... + + SIGSYS - This is not used for a bad system call (ENOSYS is used + for that). This is used by SECCOMP and some cases where an invalid + sub-function was requested. + + SIGSTKFLT - Note it used to be a coprocessor stack fault but is now + obsolete and available for general user use. + + SIGLOST - Hurd only now; note that its original purpose as an NFS + lock lost signal is obsolete. + + SIGPWR - Note this is for power lost *and* power restored, and is + more a user-mode signal than a kernel-generated signal. + + Reviewed-by: Florian Weimer + +diff --git a/manual/signal.texi b/manual/signal.texi +index 2012980efe5e2ccc..842b4e49a275bd3b 100644 +--- a/manual/signal.texi ++++ b/manual/signal.texi +@@ -427,9 +427,18 @@ failure to properly emulate them. + + @deftypevr Macro int SIGSYS + @standards{Unix, signal.h} +-Bad system call; that is to say, the instruction to trap to the +-operating system was executed, but the code number for the system call +-to perform was invalid. ++System call event. This signal may be generated by a valid system ++call which requested an invalid sub-function, and also by the SECCOMP ++filter when it filters or traps a system call. ++ ++If the system call itself is invalid or unsupported by the kernel, the ++call will not raise this signal, but will return @code{ENOSYS}. ++@end deftypevr ++ ++@deftypevr Macro int SIGSTKFLT ++Coprocessor stack fault. Obsolete, no longer generated. This signal ++may be used by applications in much the way @code{SIGUSR1} and ++@code{SIGUSR2} are. + @end deftypevr + + @node Termination Signals +@@ -752,12 +761,11 @@ that isn't connected. @xref{Sending Data}. + @deftypevr Macro int SIGLOST + @standards{GNU, signal.h} + @cindex lost resource signal +-Resource lost. This signal is generated when you have an advisory lock +-on an NFS file, and the NFS server reboots and forgets about your lock. +- +-On @gnuhurdsystems{}, @code{SIGLOST} is generated when any server program +-dies unexpectedly. It is usually fine to ignore the signal; whatever +-call was made to the server that died just returns an error. ++Resource lost. On @gnuhurdsystems{}, @code{SIGLOST} is generated when ++any server program dies unexpectedly. It is usually fine to ignore ++the signal; whatever call was made to the server that died just ++returns an error. This signal's original purpose of signalling a lost ++NFS lock is obsolete. + @end deftypevr + + @deftypevr Macro int SIGXCPU +@@ -817,6 +825,17 @@ to print some status information about the system and what the process + is doing. Otherwise the default is to do nothing. + @end deftypevr + ++@deftypevr Macro int SIGPWR ++@cindex power event signal ++Power lost or restored. On s390x Linux systems, this signal is ++generated when a machine check warning is issued, and is sent to the ++process designated to receive ctrl-alt-del notifications. Otherwise, ++it is up to userspace applications to generate this signal and manage ++notifications as to the type of power event that happened. ++ ++The default action is to terminate the process. ++@end deftypevr ++ + @node Signal Messages + @subsection Signal Messages + @cindex signal messages diff --git a/glibc-RHEL-108974-18.patch b/glibc-RHEL-108974-18.patch new file mode 100644 index 0000000..61b300e --- /dev/null +++ b/glibc-RHEL-108974-18.patch @@ -0,0 +1,60 @@ +commit 226476e32251b5688eead482a9338c04ce84d715 +Author: Siddhesh Poyarekar +Date: Thu Jan 30 10:05:17 2025 -0500 + + manual: Explain sched_yield semantics with different schedulers + + The manual entry for sched_yield mentions that the function call could + be a nop if there are no other tasks with the same absolute priority. + Expand the explanation to include example schedulers on Linux so that + it's clear that sched_yield may not always result in a different task + being scheduled. + + Signed-off-by: Siddhesh Poyarekar + Reviewed-by: Joseph Myers + +diff --git a/manual/resource.texi b/manual/resource.texi +index 23952a6b8b9f4f58..685ddd6defc57818 100644 +--- a/manual/resource.texi ++++ b/manual/resource.texi +@@ -929,18 +929,31 @@ function, so there are no specific @code{errno} values. + @c Direct syscall on Linux; alias to swtch on HURD. + + This function voluntarily gives up the task's claim on the CPU. +- +-Technically, @code{sched_yield} causes the calling task to be made +-immediately ready to run (as opposed to running, which is what it was +-before). This means that if it has absolute priority higher than 0, it +-gets pushed onto the tail of the queue of tasks that share its ++Depending on the scheduling policy in effect and the tasks ready to run ++on the system, another task may be scheduled to run instead. ++ ++A call to @code{sched_yield} does not guarantee that a different task ++from the calling task is scheduled as a result; it depends on the ++scheduling policy used on the target system. It is possible that the ++call may not result in any visible effect, i.e., the same task gets ++scheduled again. ++ ++For example on Linux systems, when a simple priority-based FIFO ++scheduling policy (@code{SCHED_FIFO}) is in effect, the calling task is ++made immediately ready to run (as opposed to running, which is what it ++was before). This means that if it has absolute priority higher than 0, ++it gets pushed onto the tail of the queue of tasks that share its + absolute priority and are ready to run, and it will run again when its + turn next arrives. If its absolute priority is 0, it is more + complicated, but still has the effect of yielding the CPU to other +-tasks. +- +-If there are no other tasks that share the calling task's absolute +-priority, this function doesn't have any effect. ++tasks. If there are no other tasks that share the calling task's ++absolute priority, it will be scheduled again as if @code{sched_yield} ++was never called. ++ ++Another example could be a time slice based preemptive round-robin ++policy, such as the @code{SCHED_RR} policy on Linux. It is possible ++with this policy that the calling task is scheduled again because it ++still has time left in its slice. + + To the extent that the containing program is oblivious to what other + processes in the system are doing and how fast it executes, this diff --git a/glibc-RHEL-108974-19.patch b/glibc-RHEL-108974-19.patch new file mode 100644 index 0000000..3475b31 --- /dev/null +++ b/glibc-RHEL-108974-19.patch @@ -0,0 +1,65 @@ +commit f451a02a8c3c0bc6b41dac5e9e6ad49dd1c9529c +Author: Joseph Myers +Date: Mon May 12 14:56:07 2025 +0000 + + Document all CLOCK_* values + + The manual documents CLOCK_REALTIME and CLOCK_MONOTONIC but not other + CLOCK_* values. Add documentation of the POSIX clocks + CLOCK_PROCESS_CPUTIME_ID and CLOCK_THREAD_CPUTIME_ID, along with a + reference to the Linux man pages for the semantics of the + Linux-specific clocks supported (as with some other functionality + coming direct from the Linux kernel where the man pages can be + considered the main documentation). + + Note: CLOCK_MONOTONIC_RAW, CLOCK_REALTIME_COARSE and + CLOCK_MONOTONIC_COARSE are also defined in the toplevel bits/time.h, + as used for Hurd. Nevertheless, I see no sign that the Hurd code in + glibc actually has any support for those clocks, so I think it is + correct to document them as Linux-specific (and to refer only to the + Linux man pages for their semantics). + + Reviewed-by: Carlos O'Donell + +diff --git a/manual/time.texi b/manual/time.texi +index 6abae3f43640e8ec..4dde875dde4d8075 100644 +--- a/manual/time.texi ++++ b/manual/time.texi +@@ -528,7 +528,36 @@ Therefore, @code{CLOCK_MONOTONIC} cannot be used to measure + absolute time, only elapsed time. + @end deftypevr + +-Systems may support more than just these two POSIX clocks. ++The following clocks are defined by POSIX, but may not be supported by ++all POSIX systems: ++ ++@deftypevr Macro clockid_t CLOCK_PROCESS_CPUTIME_ID ++@standards{POSIX.1, time.h} ++This POSIX clock measures the amount of CPU time used by the calling ++process. ++@end deftypevr ++ ++@deftypevr Macro clockid_t CLOCK_THREAD_CPUTIME_ID ++@standards{POSIX.1, time.h} ++This POSIX clock measures the amount of CPU time used by the calling ++thread. ++@end deftypevr ++ ++The following clocks are Linux extensions: ++ ++@deftypevr Macro clockid_t CLOCK_MONOTONIC_RAW ++@deftypevrx Macro clockid_t CLOCK_REALTIME_COARSE ++@deftypevrx Macro clockid_t CLOCK_MONOTONIC_COARSE ++@deftypevrx Macro clockid_t CLOCK_BOOTTIME ++@deftypevrx Macro clockid_t CLOCK_REALTIME_ALARM ++@deftypevrx Macro clockid_t CLOCK_BOOTTIME_ALARM ++@deftypevrx Macro clockid_t CLOCK_TAI ++@standards{Linux, time.h} ++For details of these clocks, see the manual page ++@manpageurl{clock_gettime,2}. ++@end deftypevr ++ ++Systems may support additional clocks beyond those listed here. + + @deftypefun int clock_gettime (clockid_t @var{clock}, struct timespec *@var{ts}) + @standards{POSIX.1, time.h} diff --git a/glibc-RHEL-108974-2.patch b/glibc-RHEL-108974-2.patch new file mode 100644 index 0000000..093af88 --- /dev/null +++ b/glibc-RHEL-108974-2.patch @@ -0,0 +1,1893 @@ +commit ee768a30fe9099972dad04c49972c2508a208b9b +Author: Paul Eggert +Date: Sat Jun 8 09:48:25 2024 -0700 + + Modernize and fix doc’s “Date and Time” (BZ 31876) + + POSIX.1-2024 (now official) specifies tm_gmtoff and tm_zone. + This is a good time to update the manual’s “Date and Time” + chapter so I went through it, fixed some outdated + stuff that had been in there for decades, and improved it to match + POSIX.1-2024 better and to clarify some implementation-defined + behavior. Glibc already conforms to POSIX.1-2024 in these matters, so + this is merely a documentation change. + + * manual/examples/strftim.c: Use snprintf instead of now-deprecated + function asctime. Check for localtime failure. Simplify by using + puts instead of fputs. Prefer ‘buf, sizeof buf’ to less-obvious + ‘buffer, SIZE’. + + * manual/examples/timespec_subtract.c: Modernize to use struct + timespec not struct timeval, and rename from timeval_subtract.c. + All uses changed. Check for overflow. Do not check for negative + return value, which ought to be OK since negative time_t is OK. + Use GNU indenting style. + + * manual/time.texi: + + Document CLOCKS_PER_SEC, TIME_UTC, timespec_get, timespec_getres, + strftime_l. + + Document the storage lifetime of tm_zone and of tzname. + + Caution against use of tzname, timezone and daylight, saying that + these variables have unspecified values when TZ is geographic. + This is what glibc actually does (contrary to what the manual said + before this patch), and POSIX is planned to say the same thing + . + Also say that directly accessing the variables is not thread-safe. + + Say that localtime_r and ctime_r don’t necessarily set time zone + state. Similarly, in the tzset documentation, say that it is called + by ctime, localtime, mktime, strftime, not that it is called by all + time conversion functions that depend on the time zone. + + Say that tm_isdst is useful mostly just for mktime, and that + other uses should prefer tm_gmtoff and tm_zone instead. + + Do not say that strftime ignores tm_gmtoff and tm_zone, because + it doesn’t do that. + + Document what gmtime does to tm_gmtoff and tm_zone. + + Say that the asctime, asctime_r, ctime, and ctime_r are now deprecated + and/or obsolescent, and that behavior is undefined if the year is < + 1000 or > 9999. Document strftime before these now-obsolescent + functions, so that readers see the useful function first. + + Coin the terms “geographical format” and “proleptic format” for the + two main formats of TZ settings, to simplify exposition. Use this + wording consistently. + + Update top-level proleptic syntax to match POSIX.1-2024, which glibc + already implements. Document the angle-bracket quoted forms of time + zone abbreviations in proleptic TZ. Say that time zone abbreviations + can contain only ASCII alphanumerics, ‘+’, and ‘-’. + + Document what happens if the proleptic form specifies a DST + abbreviation and offset but omits the rules. POSIX says this is + implementation-defined so we need to document it. Although this + documentation mentions ‘posixrules’ tersely, we need to rethink + ‘posixrules’ since I think it stops working after 2038. + + Clarify wording about TZ settings beginning with ‘;’. + + Say that timegm is in ISO C (as of C23). + + Say that POSIX.1-2024 removed gettimeofday. + + Say that tm_gmtoff and tm_zone are extensions to ISO C, which is + clearer than saying they are invisible in a struct ISO C enviroment, + and gives us more wiggle room if we want to make them visible in + strict ISO C, something that ISO C allows. + + Drop mention of old standards like POSIX.1c and POSIX.2-1992 in the + text when the history is so old that it’s no longer useful in a + general-purpose manual. + + Define Coordinated Universal Time (UTC), time zone, time zone ruleset, + and POSIX Epoch, and use these phrases more consistently. + + Improve TZ examples to show more variety, and to reflect current + practice and timestamps. Remove obsolete example about Argentina. + Add an example for Ireland. + + Don’t rely on GCC extensions when explaining ctime_r. + + Do not say that difftime produces the mathematically correct result, + since it might be inexact. + + For clock_t don’t say “as in the example above” when there is no + such example, and don’t say that casting to double works “properly + and consistently no matter what”, as it suffers from rounding and + overflow. + + Don’t say broken-down time is not useful for calculations; it’s + merely painful. + + Say that UTC is not defined before 1960. + + Rename Time Zone Functions to Time Zone State. All uses changed. + + Update Internet RFC 822 → 5322, 1305 → 5905. Drop specific years of + ISO 8601 as they don’t matter. + + Minor style changes: @code{"..."} → @t{"..."} to avoid overquoting in + info files, @code → @env for environment variables, Daylight Saving + Time → daylight saving time, white space → whitespace, prime meridian + → Prime Meridian. + +diff --git a/benchtests/strcoll-inputs/filelist#en_US.UTF-8 b/benchtests/strcoll-inputs/filelist#en_US.UTF-8 +index 197700ec90c4cd17..0d8f1c722baae2d7 100644 +--- a/benchtests/strcoll-inputs/filelist#en_US.UTF-8 ++++ b/benchtests/strcoll-inputs/filelist#en_US.UTF-8 +@@ -14260,7 +14260,7 @@ sigusr.c + dir2.c + inetsrv.c + argp-ex3.c +-timeval_subtract.c ++timespec_subtract.c + popen.c + filecli.c + db.c +diff --git a/manual/conf.texi b/manual/conf.texi +index 158285dbf06c76ab..be680e0692b1d0e4 100644 +--- a/manual/conf.texi ++++ b/manual/conf.texi +@@ -89,7 +89,7 @@ process can have open simultaneously. @xref{Opening Streams}. + @deftypevr Macro int TZNAME_MAX + @standards{POSIX.1, limits.h} + If defined, the unvarying maximum length of a time zone abbreviation. +-@xref{Time Zone Functions}. ++@xref{TZ Variable}. + @end deftypevr + + These limit macros are always defined in @file{limits.h}. +diff --git a/manual/contrib.texi b/manual/contrib.texi +index 6f987aab227049d5..5b2710f0bad15f26 100644 +--- a/manual/contrib.texi ++++ b/manual/contrib.texi +@@ -630,7 +630,7 @@ a different license: + + @itemize @bullet + @item +-The timezone support code is derived from the public-domain timezone ++The time zone support code is derived from the public-domain time zone + package by Arthur David Olson and his many contributors. + + @item +diff --git a/manual/examples/strftim.c b/manual/examples/strftim.c +index 304981dfc35558d7..6e1e0474c74f0641 100644 +--- a/manual/examples/strftim.c ++++ b/manual/examples/strftim.c +@@ -18,30 +18,32 @@ + #include + #include + +-#define SIZE 256 +- + int + main (void) + { +- char buffer[SIZE]; +- time_t curtime; +- struct tm *loctime; ++ /* This buffer is big enough that the strftime calls ++ below cannot possibly exhaust it. */ ++ char buf[256]; + + /* Get the current time. */ +- curtime = time (NULL); ++ time_t curtime = time (NULL); + + /* Convert it to local time representation. */ +- loctime = localtime (&curtime); ++ struct tm *lt = localtime (&curtime); ++ if (!lt) ++ return 1; + +- /* Print out the date and time in the standard format. */ +- fputs (asctime (loctime), stdout); ++ /* Print the date and time in a simple format ++ that is independent of locale. */ ++ strftime (buf, sizeof buf, "%Y-%m-%d %H:%M:%S", lt); ++ puts (buf); + + /*@group*/ +- /* Print it out in a nice format. */ +- strftime (buffer, SIZE, "Today is %A, %B %d.\n", loctime); +- fputs (buffer, stdout); +- strftime (buffer, SIZE, "The time is %I:%M %p.\n", loctime); +- fputs (buffer, stdout); ++ /* Print it in a nicer English format. */ ++ strftime (buf, sizeof buf, "Today is %A, %B %d.", lt); ++ puts (buf); ++ strftime (buf, sizeof buf, "The time is %I:%M %p.", lt); ++ puts (buf); + + return 0; + } +diff --git a/manual/examples/timespec_subtract.c b/manual/examples/timespec_subtract.c +new file mode 100644 +index 0000000000000000..380d173aabb5b30a +--- /dev/null ++++ b/manual/examples/timespec_subtract.c +@@ -0,0 +1,36 @@ ++/* struct timespec subtraction. ++ Copyright (C) 1991-2024 Free Software Foundation, Inc. ++ ++ This program is free software; you can redistribute it and/or ++ modify it under the terms of the GNU General Public License ++ as published by the Free Software Foundation; either version 2 ++ of the License, or (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, see . ++*/ ++#include ++#include ++ ++/* Put into *R the difference between X and Y. ++ Return true if overflow occurs, false otherwise. */ ++ ++bool ++timespec_subtract (struct timespec *r, ++ struct timespec x, struct timespec y) ++{ ++ /* Compute nanoseconds, setting @var{borrow} to 1, 0, or -1 ++ for propagation into seconds. */ ++ long int nsec_diff = x.tv_nsec - y.tv_nsec; ++ int borrow = (nsec_diff < 0) - ! (nsec_diff < 1000000000); ++ r->tv_nsec = nsec_diff + 1000000000 * borrow; ++ ++ /* Compute seconds, returning true if this overflows. */ ++ bool v = ckd_sub (&r->tv_sec, x.tv_sec, y.tv_sec); ++ return v ^ ckd_sub (&r->tv_sec, r->tv_sec, borrow); ++} +diff --git a/manual/examples/timeval_subtract.c b/manual/examples/timeval_subtract.c +deleted file mode 100644 +index 20c246320d06beb7..0000000000000000 +--- a/manual/examples/timeval_subtract.c ++++ /dev/null +@@ -1,44 +0,0 @@ +-/* struct timeval subtraction. +- Copyright (C) 1991-2024 Free Software Foundation, Inc. +- +- This program is free software; you can redistribute it and/or +- modify it under the terms of the GNU General Public License +- as published by the Free Software Foundation; either version 2 +- of the License, or (at your option) any later version. +- +- This program is distributed in the hope that it will be useful, +- but WITHOUT ANY WARRANTY; without even the implied warranty of +- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- GNU General Public License for more details. +- +- You should have received a copy of the GNU General Public License +- along with this program; if not, see . +-*/ +- +-/* Subtract the `struct timeval' values X and Y, +- storing the result in RESULT. +- Return 1 if the difference is negative, otherwise 0. */ +- +-int +-timeval_subtract (struct timeval *result, struct timeval *x, struct timeval *y) +-{ +- /* Perform the carry for the later subtraction by updating @var{y}. */ +- if (x->tv_usec < y->tv_usec) { +- int nsec = (y->tv_usec - x->tv_usec) / 1000000 + 1; +- y->tv_usec -= 1000000 * nsec; +- y->tv_sec += nsec; +- } +- if (x->tv_usec - y->tv_usec > 1000000) { +- int nsec = (x->tv_usec - y->tv_usec) / 1000000; +- y->tv_usec += 1000000 * nsec; +- y->tv_sec -= nsec; +- } +- +- /* Compute the time remaining to wait. +- @code{tv_usec} is certainly positive. */ +- result->tv_sec = x->tv_sec - y->tv_sec; +- result->tv_usec = x->tv_usec - y->tv_usec; +- +- /* Return 1 if result is negative. */ +- return x->tv_sec < y->tv_sec; +-} +diff --git a/manual/install.texi b/manual/install.texi +index 7c445946176f0269..c5f159163ab07fa7 100644 +--- a/manual/install.texi ++++ b/manual/install.texi +@@ -206,7 +206,7 @@ This option hardcodes the newly built C library path in dynamic tests + so that they can be invoked directly. + + @item --disable-timezone-tools +-By default, timezone related utilities (@command{zic}, @command{zdump}, ++By default, time zone related utilities (@command{zic}, @command{zdump}, + and @command{tzselect}) are installed with @theglibc{}. If you are building + these independently (e.g. by using the @samp{tzcode} package), then this + option will allow disabling the install of these. +@@ -456,9 +456,9 @@ permissions on a pseudoterminal so it can be used by the calling process. + If you are using a Linux kernel with the @code{devpts} filesystem enabled + and mounted at @file{/dev/pts}, you don't need this program. + +-After installation you should configure the timezone and install locales +-for your system. The time zone configuration ensures that your system +-time matches the time for your current timezone. The locales ensure that ++After installation you should configure the time zone ruleset and install ++locales for your system. The time zone ruleset ensures that timestamps ++are processed correctly for your location. The locales ensure that + the display of information on your system matches the expectations of + your language and geographic region. + +@@ -481,12 +481,12 @@ as files in the default configured locale installation directory (derived from + root use @samp{DESTDIR} e.g.@: @samp{make localedata/install-locale-files + DESTDIR=/opt/glibc}, but note that this does not change the configured prefix. + +-To configure the locally used timezone, set the @code{TZ} environment ++To configure the time zone ruleset, set the @code{TZ} environment + variable. The script @code{tzselect} helps you to select the right value. + As an example, for Germany, @code{tzselect} would tell you to use + @samp{TZ='Europe/Berlin'}. For a system wide installation (the given + paths are for an installation with @samp{--prefix=/usr}), link the +-timezone file which is in @file{/usr/share/zoneinfo} to the file ++time zone file which is in @file{/usr/share/zoneinfo} to the file + @file{/etc/localtime}. For Germany, you might execute @samp{ln -s + /usr/share/zoneinfo/Europe/Berlin /etc/localtime}. + +diff --git a/manual/startup.texi b/manual/startup.texi +index 1426f5e1abfb2f51..c421563d16979c64 100644 +--- a/manual/startup.texi ++++ b/manual/startup.texi +@@ -567,8 +567,7 @@ Manual}) use the @code{TERM} environment variable, for example. + @item TZ + @cindex @code{TZ} environment variable + +-This specifies the time zone. @xref{TZ Variable}, for information about +-the format of this string and how it is used. ++This specifies the time zone ruleset. @xref{TZ Variable}. + + @item LANG + @cindex @code{LANG} environment variable +diff --git a/manual/time.texi b/manual/time.texi +index 2e029975b952ac29..ab5063be81cf0af9 100644 +--- a/manual/time.texi ++++ b/manual/time.texi +@@ -26,18 +26,22 @@ Discussing time in a technical manual can be difficult because the word + we use a rigorous terminology to avoid confusion, and the only thing we + use the simple word ``time'' for is to talk about the abstract concept. + +-A @dfn{calendar time} is a point in the time continuum, for example +-November 4, 1990, at 18:02.5 UTC. Sometimes this is called ``absolute +-time''. ++A @dfn{calendar time}, sometimes called ``absolute time'', ++is a point in the Earth's time continuum, for example ++June 9, 2024, at 13:50:06.5 Coordinated Universal Time (UTC)@. + @cindex calendar time ++UTC, formerly called Greenwich Mean Time, is the primary time ++standard on Earth, and is the basis for civil time and time zones. ++@cindex Coordinated Universal Time ++@cindex UTC + + We don't speak of a ``date'', because that is inherent in a calendar + time. + @cindex date + + An @dfn{interval} is a contiguous part of the time continuum between two +-calendar times, for example the hour between 9:00 and 10:00 on July 4, +-1980. ++calendar times, for example the hour on June 9, 2024, ++between 13:00 and 14:00 UTC. + @cindex interval + + An @dfn{elapsed time} is the length of an interval, for example, 35 +@@ -85,6 +89,16 @@ easier for people to understand, but more difficult to calculate with. + @cindex Gregorian calendar + @cindex calendar, Gregorian + ++A @dfn{time zone} is a single fixed offset from UTC, along with ++a @dfn{time zone abbreviation} that is a string of characters ++that can include ASCII alphanumerics, @samp{+}, and @samp{-}. ++For example, the current time zone in Japan is ++9 hours ahead (east) of the Prime Meridian with abbreviation @t{"JST"}. ++ ++A @dfn{time zone ruleset} maps each simple calendar time to a single ++time zone. For example, Paris's time zone ruleset might list over a ++dozen time zones that Paris has experienced during its history. ++ + @dfn{CPU time} measures the amount of time that a single process has + actively used a CPU to perform computations. It does not include the + time that process has spent waiting for external events. The system +@@ -132,16 +146,17 @@ and pass them to the functions that convert them to broken-down time + (@pxref{Broken-down Time}). + + On POSIX-conformant systems, @code{time_t} is an integer type and its +-values represent the number of seconds elapsed since the @dfn{epoch}, +-which is 00:00:00 on January 1, 1970, Coordinated Universal Time. ++values represent the number of seconds elapsed since the @dfn{POSIX Epoch}, ++which is January 1, 1970, at 00:00:00 Coordinated Universal Time (UTC)@. + The count of seconds ignores leap seconds. + + @Theglibc{} additionally guarantees that @code{time_t} is a signed + type, and that all of its functions operate correctly on negative +-@code{time_t} values, which are interpreted as times before the epoch. +-Functions like @code{localtime} assume the Gregorian calendar even +-though this is historically inaccurate for timestamps before the +-calendar was introduced or after the calendar will become obsolete. ++@code{time_t} values, which are interpreted as times before the POSIX Epoch. ++Functions like @code{localtime} assume the Gregorian calendar and UTC ++even though this is historically inaccurate for dates before 1582, ++for times before 1960, and for timestamps after the Gregorian calendar ++and UTC will become obsolete. + @cindex epoch + @Theglibc{} also supports leap seconds as an option, in which case + @code{time_t} counts leap seconds instead of ignoring them. +@@ -226,7 +241,7 @@ a value of type @code{double}. + + On POSIX-conformant systems, the advantage of using + @samp{difftime (@var{end}, @var{begin})} over @samp{@var{end} - @var{begin}} +-is that it will produce the mathematically correct result even if ++is that it will not overflow even if + @var{end} and @var{begin} are so far apart that a simple subtraction + would overflow. However, if they are so far apart that a @code{double} + cannot exactly represent the difference, the result will be inexact. +@@ -237,13 +252,13 @@ would be the only way to compute their difference. + @end deftypefun + + @Theglibc{} does not provide any functions for computing the +-difference between two values of type @w{@code{struct timeval}} or +-@w{@code{struct timespec}}. Here is the recommended way to do this +-calculation by hand. It works even on some peculiar operating systems ++difference between two values of type @w{@code{struct timespec}} or ++@w{@code{struct timeval}}. Here is one way to do this ++calculation by hand. It works even on peculiar operating systems + where the @code{tv_sec} member has an unsigned type. + + @smallexample +-@include timeval_subtract.c.texi ++@include timespec_subtract.c.texi + @end smallexample + + @node Processor And CPU Time +@@ -252,7 +267,7 @@ where the @code{tv_sec} member has an unsigned type. + If you're trying to optimize your program or measure its efficiency, + it's very useful to know how much processor time it uses. For that, + calendar time and elapsed times are useless because a process may spend +-time waiting for I/O or for other processes to use the CPU. However, ++time waiting for I/O or for other processes to use the CPU@. However, + you can get the information with the functions in this section. + + CPU time (@pxref{Time Basics}) is represented by the data type +@@ -267,12 +282,16 @@ time before and after the computation. + @cindex clock ticks + @cindex ticks, clock + ++@defvr Macro CLOCKS_PER_SEC ++@standards{ISO, time.h} ++The number of clock ticks per second. ++@end defvr ++ + On @gnulinuxhurdsystems{}, @code{clock_t} is equivalent to @code{long int} and + @code{CLOCKS_PER_SEC} is an integer value. But in other systems, both + @code{clock_t} and the macro @code{CLOCKS_PER_SEC} can be either integer +-or floating-point types. Casting CPU time values to @code{double}, as +-in the example above, makes sure that operations such as arithmetic and +-printing work properly and consistently no matter what the underlying ++or floating-point types. Converting CPU time values to @code{double} ++can help code be more portable no matter what the underlying + representation is. + + Note that the clock can wrap around. On a 32bit system with +@@ -434,8 +453,8 @@ manipulating calendar times. + * Formatting Calendar Time:: Converting times to strings. + * Parsing Date and Time:: Convert textual time and date information back + into broken-down time values. +-* TZ Variable:: How users specify the time zone. +-* Time Zone Functions:: Functions to examine or specify the time zone. ++* TZ Variable:: How users specify the time zone ruleset. ++* Time Zone State:: Time zone state variables. + * Time Functions Example:: An example program showing use of some of + the time functions. + @end menu +@@ -464,30 +483,30 @@ This function cannot fail. + + Some applications need more precise timekeeping than is possible with + a @code{time_t} alone. Some applications also need more control over +-what is meant by ``the current time.'' For these applications, POSIX +-provides a function @code{clock_gettime} that can retrieve the time ++what is meant by ``the current time.'' For these applications, ++POSIX and @w{ISO C} provide functions to retrieve the time + with up to nanosecond precision, from a variety of different clocks. + Clocks can be system-wide, measuring time the same for all processes; + or they can be per-process or per-thread, measuring CPU time consumed + by a particular process, or some other similar resource. Each clock +-has its own resolution and epoch. You can find the resolution of a +-clock with the function @code{clock_getres}. There is no function to ++has its own resolution and epoch. POSIX and @w{ISO C} also provide functions ++for finding the resolution of a clock. There is no function to + get the epoch for a clock; either it is fixed and documented, or the + clock is not meant to be used to measure absolute times. + + @deftp {Data Type} clockid_t + @standards{POSIX.1, time.h} + The type @code{clockid_t} is used for constants that indicate which of +-several system clocks one wishes to use. ++several POSIX system clocks one wishes to use. + @end deftp + +-All systems that support this family of functions will define at least ++All systems that support the POSIX functions will define at least + this clock constant: + + @deftypevr Macro clockid_t CLOCK_REALTIME + @standards{POSIX.1, time.h} +-This clock uses the POSIX epoch, 00:00:00 on January 1, 1970, Coordinated +-Universal Time. It is close to, but not necessarily in lock-step with, the ++This POSIX clock uses the POSIX Epoch, 1970-01-01 00:00:00 UTC@. ++It is close to, but not necessarily in lock-step with, the + clocks of @code{time} (above) and of @code{gettimeofday} (below). + @end deftypevr + +@@ -499,7 +518,7 @@ measurements are not affected by changes to the system clock. + + @deftypevr Macro clockid_t CLOCK_MONOTONIC + @standards{POSIX.1, time.h} +-System-wide clock that continuously measures the advancement of ++This system-wide POSIX clock continuously measures the advancement of + calendar time, ignoring discontinuous changes to the system's + setting for absolute calendar time. + +@@ -509,7 +528,7 @@ Therefore, @code{CLOCK_MONOTONIC} cannot be used to measure + absolute time, only elapsed time. + @end deftypevr + +-Systems may support more than just these two clocks. ++Systems may support more than just these two POSIX clocks. + + @deftypefun int clock_gettime (clockid_t @var{clock}, struct timespec *@var{ts}) + @standards{POSIX.1, time.h} +@@ -552,15 +571,45 @@ The clock identified by @var{clock} is not supported. + @end table + @end deftypefun + +-These functions, and the constants that identify particular clocks, +-are declared in @file{time.h}. +- + @strong{Portability Note:} On some systems, including systems that use + older versions of @theglibc{}, programs that use @code{clock_gettime} + or @code{clock_setres} must be linked with the @code{-lrt} library. + This has not been necessary with @theglibc{} since version 2.17. + +-@Theglibc{} also provides an older, but still widely used, function ++The following @w{ISO C} macros and functions for higher-resolution ++timestamps were standardized more recently than the POSIX functions, ++so they are less portable to older POSIX systems. However, the @w{ISO ++C} functions are portable to C platforms that do not support POSIX. ++ ++@deftypevr Macro int TIME_UTC ++@standards{ISO, time.h} ++This is a positive integer constant designating a simple calendar time base. ++In @theglibc{} and other POSIX systems, ++this is equivalent to the POSIX @code{CLOCK_REALTIME} clock. ++On non-POSIX systems, though, the epoch is implementation-defined. ++@end deftypevr ++ ++Systems may support more than just this @w{ISO C} clock. ++ ++@deftypefun int timespec_get (struct timespec *@var{ts}, int @var{base}) ++@standards{ISO, time.h} ++Store into @code{*@var{ts}} the current time according to the @w{ISO ++C} time @var{base}. ++ ++The return value is @var{base} on success and @code{0} on failure. ++@end deftypefun ++ ++@deftypefun int timespec_getres (struct timespec *@var{res}, int @var{base}) ++@standards{ISO, time.h} ++If @var{ts} is non-null, store into @code{*@var{ts}} the resolution of ++the time provided by @code{timespec_get} function for the @w{ISO C} ++time @var{base}. ++ ++The return value is @var{base} on success and @code{0} on failure. ++@end deftypefun ++ ++The previous functions, data types and constants are declared in @file{time.h}. ++@Theglibc{} also provides an older function + for getting the current time with a resolution of microseconds. This + function is declared in @file{sys/time.h}. + +@@ -577,15 +626,15 @@ On some historic systems, if @var{tzp} was not a null pointer, + information about a system-wide time zone would be written to + @code{*@var{tzp}}. This feature is obsolete and not supported on + @gnusystems{}. You should always supply a null pointer for this +-argument. Instead, use the facilities described in @ref{Time Zone +-Functions} and in @ref{Broken-down Time} for working with time zones. ++argument. Instead, use the facilities described in ++@ref{Broken-down Time} for working with time zones. + + This function cannot fail, and its return value is always @code{0}. + +-@strong{Portability Note:} As of the 2008 revision of POSIX, this +-function is considered obsolete. @Theglibc{} will continue to provide +-this function indefinitely, but new programs should use +-@code{clock_gettime} instead. ++@strong{Portability Note:} POSIX.1-2024 removed this function. ++Although @theglibc{} will continue to provide it indefinitely, ++portable programs should use @code{clock_gettime} or ++@code{timespec_get} instead. + @end deftypefun + + @node Setting and Adjusting the Time +@@ -613,7 +662,7 @@ privileges), but the @code{CLOCK_MONOTONIC} clock cannot. + Because simple calendar times are independent of time zone, this + function should not be used when the time zone changes (e.g.@: if the + computer is physically moved from one zone to another). Instead, use +-the facilities described in @ref{Time Zone Functions}. ++the facilities described in @ref{Time Zone State}. + + @code{clock_settime} causes the clock to jump forwards or backwards, + which can cause a variety of problems. Changing the +@@ -761,7 +810,7 @@ system clock. The value is expressed in microseconds. + + @item long int tolerance + This value represents the maximum frequency error of the system clock in +-scaled PPM. This value is used to increase the @code{maxerror} every ++scaled PPM@. This value is used to increase the @code{maxerror} every + second. + + @item struct timeval time +@@ -845,7 +894,7 @@ The process specified a settings update, but is not superuser. + + @end table + +-For more details see RFC1305 (Network Time Protocol, Version 3) and ++For more details see @w{RFC 5905} (Network Time Protocol, Version 4) and + related documents. + + @strong{Portability note:} Early versions of @theglibc{} did not +@@ -869,7 +918,7 @@ wait longer for the time to become correct. + The @var{delta} argument specifies a relative adjustment to be made to + the clock time. If negative, the system clock is slowed down for a + while until it has lost this much elapsed time. If positive, the system +-clock is speeded up for a while. ++clock is sped up for a while. + + If the @var{olddelta} argument is not a null pointer, the @code{adjtime} + function returns information about any previous time adjustment that +@@ -933,9 +982,9 @@ same as calling @w{@samp{clock_settime (CLOCK_REALTIME)}}, except that + the new time can only be set to a precision of one microsecond. + + When @var{tzp} is not a null pointer, the data it points to @emph{may} +-be used to set a system-wide idea of the current timezone. This ++be used to set a system-wide idea of the current time zone. This + feature is obsolete and not supported on @gnusystems{}. Instead, use +-the facilities described in @ref{Time Zone Functions} and in ++the facilities described in @ref{Time Zone State} and in + @ref{Broken-down Time} for working with time zones. + + The return value is @code{0} on success and @code{-1} on failure. The +@@ -966,8 +1015,8 @@ Simple calendar times represent absolute times as elapsed times since + an epoch. This is convenient for computation, but has no relation to + the way people normally think of calendar time. By contrast, + @dfn{broken-down time} is a binary representation of calendar time +-separated into year, month, day, and so on. Broken-down time values +-are not useful for calculations, but they are useful for printing ++separated into year, month, day, and so on. Although broken-down time ++values are painful to calculate with, they are useful for printing + human readable time information. + + A broken-down time value is always relative to a choice of time +@@ -1018,27 +1067,34 @@ This is the number of full days since the beginning of the year (in the + range @code{0} through @code{365}). + + @item int tm_isdst +-@cindex Daylight Saving Time ++@cindex daylight saving time + @cindex summer time +-This is a flag that indicates whether Daylight Saving Time is (or was, or ++This is a flag that indicates whether daylight saving time is (or was, or + will be) in effect at the time described. The value is positive if +-Daylight Saving Time is in effect, zero if it is not, and negative if the ++daylight saving time is in effect, zero if it is not, and negative if the + information is not available. ++Although this flag is useful when passing a broken-down time to the ++@code{mktime} function, for other uses this flag should be ignored and ++the @code{tm_gmtoff} and @code{tm_zone} fields should be inspected instead. + + @item long int tm_gmtoff + This field describes the time zone that was used to compute this + broken-down time value, including any adjustment for daylight saving; it + is the number of seconds that you must add to UTC to get local time. +-You can also think of this as the number of seconds east of UTC. For +-example, for U.S. Eastern Standard Time, the value is @code{-5*60*60}. +-The @code{tm_gmtoff} field is derived from BSD and is a GNU library +-extension; it is not visible in a strict @w{ISO C} environment. ++You can also think of this as the number of seconds east of the Prime Meridian. ++For example, for U.S. Eastern Standard Time, the value is @code{-5*60*60}. + + @item const char *tm_zone + This field is the abbreviation for the time zone that was used to compute this +-broken-down time value. Like @code{tm_gmtoff}, this field is a BSD and +-GNU extension, and is not visible in a strict @w{ISO C} environment. ++broken-down time value. + @end table ++ ++@strong{Portability note:} The @code{tm_gmtoff} and @code{tm_zone} fields ++are derived from BSD and are POSIX extensions to @w{ISO C}@. ++Code intended to be portable to operating systems that lack ++these fields can instead use time zone state variables, although ++those variables are unreliable when the @env{TZ} environment variable ++has a geographical format. @xref{Time Zone State}. + @end deftp + + +@@ -1053,21 +1109,24 @@ The @code{localtime} function converts the simple time pointed to by + user's specified time zone. + + The return value is a pointer to a static broken-down time structure, which +-might be overwritten by subsequent calls to @code{ctime}, @code{gmtime}, +-or @code{localtime}. (But no other library function overwrites the contents +-of this object.) ++might be overwritten by subsequent calls to @code{gmtime} ++or @code{localtime}. (No other library function overwrites the contents ++of this object.) In @theglibc{}, the structure's @code{tm_zone} ++points to a string with a storage lifetime that lasts indefinitely; ++on other platforms, the lifetime may expire when the @env{TZ} ++environment variable is changed. + + The return value is the null pointer if @var{time} cannot be represented + as a broken-down time; typically this is because the year cannot fit into + an @code{int}. + +-Calling @code{localtime} also sets the current time zone as if +-@code{tzset} were called. @xref{Time Zone Functions}. ++Calling @code{localtime} also sets the time zone state as if ++@code{tzset} were called. @xref{Time Zone State}. + @end deftypefun + + Using the @code{localtime} function is a big problem in multi-threaded + programs. The result is returned in a static buffer and this is used in +-all threads. POSIX.1c introduced a variant of this function. ++all threads. A variant function avoids this problem. + + @deftypefun {struct tm *} localtime_r (const time_t *@var{time}, struct tm *@var{resultp}) + @standards{POSIX.1c, time.h} +@@ -1158,7 +1217,8 @@ and converts it to the broken-down time format. + + But the result is not placed in a static buffer. Instead it is placed + in the object of type @code{struct tm} to which the parameter +-@var{resultp} points. ++@var{resultp} points. Also, the time zone state is not necessarily ++set as if @code{tzset} were called. + + If the conversion is successful the function returns a pointer to the + object the result was written into, i.e., it returns @var{resultp}. +@@ -1171,13 +1231,14 @@ object the result was written into, i.e., it returns @var{resultp}. + @c gmtime @mtasurace:tmbuf @mtsenv @mtslocale @ascuheap @asulock @aculock @acsmem @acsfd + @c tz_convert dup @mtsenv @mtslocale @ascuheap @asulock @aculock @acsmem @acsfd + This function is similar to @code{localtime}, except that the broken-down +-time is expressed as Coordinated Universal Time (UTC) (formerly called +-Greenwich Mean Time (GMT)) rather than relative to a local time zone. ++time is expressed as UTC rather than relative to a local time zone. ++The broken-down time's @code{tm_gmtoff} is 0, and its ++@code{tm_zone} is a string @t{"UTC"} with static storage duration. + + @end deftypefun + + As for the @code{localtime} function we have the problem that the result +-is placed in a static variable. POSIX.1c also provides a replacement for ++is placed in a static variable. A thread-safe replacement is also provided for + @code{gmtime}. + + @deftypefun {struct tm *} gmtime_r (const time_t *@var{time}, struct tm *@var{resultp}) +@@ -1192,7 +1253,7 @@ is placed in a static variable. POSIX.1c also provides a replacement for + @c gmtime_r @mtsenv @mtslocale @ascuheap @asulock @aculock @acsmem @acsfd + @c tz_convert(gmtime_r) dup @mtsenv @mtslocale @ascuheap @asulock @aculock @acsmem @acsfd + This function is similar to @code{localtime_r}, except that it converts +-just like @code{gmtime} the given time as Coordinated Universal Time. ++just like @code{gmtime} the given time as UTC. + + If the conversion is successful the function returns a pointer to the + object the result was written into, i.e., it returns @var{resultp}. +@@ -1242,10 +1303,10 @@ If the specified broken-down time cannot be represented as a simple time, + @code{mktime} returns a value of @code{(time_t)(-1)} and does not modify + the contents of @var{brokentime}. + +-Calling @code{mktime} also sets the current time zone as if ++Calling @code{mktime} also sets the time zone state as if + @code{tzset} were called; @code{mktime} uses this information instead + of @var{brokentime}'s initial @code{tm_gmtoff} and @code{tm_zone} +-members. @xref{Time Zone Functions}. ++members. @xref{Time Zone State}. + @end deftypefun + + @deftypefun time_t timelocal (struct tm *@var{brokentime}) +@@ -1263,7 +1324,7 @@ available. @code{timelocal} is rather rare. + @end deftypefun + + @deftypefun time_t timegm (struct tm *@var{brokentime}) +-@standards{???, time.h} ++@standards{ISO, time.h} + @safety{@prelim{}@mtsafe{@mtsenv{} @mtslocale{}}@asunsafe{@ascuheap{} @asulock{}}@acunsafe{@aculock{} @acsmem{} @acsfd{}}} + @c timegm @mtsenv @mtslocale @ascuheap @asulock @aculock @acsmem @acsfd + @c gmtime_offset triggers the same caveats as localtime_offset in mktime. +@@ -1279,16 +1340,16 @@ available. @code{timelocal} is rather rare. + @c tzfile_compute(!use_localtime) ok + + @code{timegm} is functionally identical to @code{mktime} except it +-always takes the input values to be Coordinated Universal Time (UTC) ++always takes the input values to be UTC + regardless of any local time zone setting. + + Note that @code{timegm} is the inverse of @code{gmtime}. + + @strong{Portability note:} @code{mktime} is essentially universally +-available. @code{timegm} is rather rare. For the most portable +-conversion from a UTC broken-down time to a simple time, set +-the @code{TZ} environment variable to UTC, call @code{mktime}, then set +-@code{TZ} back. ++available. Although @code{timegm} is standardized by C23, some ++other systems lack it; to be portable to them, you can set ++the @env{TZ} environment variable to UTC, call @code{mktime}, then set ++@env{TZ} back. + + @end deftypefun + +@@ -1301,89 +1362,6 @@ The functions described in this section format calendar time values as + strings. These functions are declared in the header file @file{time.h}. + @pindex time.h + +-@deftypefun {char *} asctime (const struct tm *@var{brokentime}) +-@standards{ISO, time.h} +-@safety{@prelim{}@mtunsafe{@mtasurace{:asctime} @mtslocale{}}@asunsafe{}@acsafe{}} +-@c asctime @mtasurace:asctime @mtslocale +-@c Uses a static buffer. +-@c asctime_internal @mtslocale +-@c snprintf dup @mtslocale [no @acsuheap @acsmem] +-@c ab_day_name @mtslocale +-@c ab_month_name @mtslocale +-The @code{asctime} function converts the broken-down time value that +-@var{brokentime} points to into a string in a standard format: +- +-@smallexample +-"Tue May 21 13:46:22 1991\n" +-@end smallexample +- +-The abbreviations for the days of week are: @samp{Sun}, @samp{Mon}, +-@samp{Tue}, @samp{Wed}, @samp{Thu}, @samp{Fri}, and @samp{Sat}. +- +-The abbreviations for the months are: @samp{Jan}, @samp{Feb}, +-@samp{Mar}, @samp{Apr}, @samp{May}, @samp{Jun}, @samp{Jul}, @samp{Aug}, +-@samp{Sep}, @samp{Oct}, @samp{Nov}, and @samp{Dec}. +- +-The return value points to a statically allocated string, which might be +-overwritten by subsequent calls to @code{asctime} or @code{ctime}. +-(But no other library function overwrites the contents of this +-string.) +-@end deftypefun +- +-@deftypefun {char *} asctime_r (const struct tm *@var{brokentime}, char *@var{buffer}) +-@standards{POSIX.1c, time.h} +-@safety{@prelim{}@mtsafe{@mtslocale{}}@assafe{}@acsafe{}} +-@c asctime_r @mtslocale +-@c asctime_internal dup @mtslocale +-This function is similar to @code{asctime} but instead of placing the +-result in a static buffer it writes the string in the buffer pointed to +-by the parameter @var{buffer}. This buffer should have room +-for at least 26 bytes, including the terminating null. +- +-If no error occurred the function returns a pointer to the string the +-result was written into, i.e., it returns @var{buffer}. Otherwise +-it returns @code{NULL}. +-@end deftypefun +- +- +-@deftypefun {char *} ctime (const time_t *@var{time}) +-@standards{ISO, time.h} +-@safety{@prelim{}@mtunsafe{@mtasurace{:tmbuf} @mtasurace{:asctime} @mtsenv{} @mtslocale{}}@asunsafe{@ascuheap{} @asulock{}}@acunsafe{@aculock{} @acsmem{} @acsfd{}}} +-@c ctime @mtasurace:tmbuf @mtasurace:asctime @mtsenv @mtslocale @ascuheap @asulock @aculock @acsmem @acsfd +-@c localtime dup @mtasurace:tmbuf @mtsenv @mtslocale @ascuheap @asulock @aculock @acsmem @acsfd +-@c asctime dup @mtasurace:asctime @mtslocale +-The @code{ctime} function is similar to @code{asctime}, except that you +-specify the calendar time argument as a @code{time_t} simple time value +-rather than in broken-down local time format. It is equivalent to +- +-@smallexample +-asctime (localtime (@var{time})) +-@end smallexample +- +-Calling @code{ctime} also sets the current time zone as if +-@code{tzset} were called. @xref{Time Zone Functions}. +-@end deftypefun +- +-@deftypefun {char *} ctime_r (const time_t *@var{time}, char *@var{buffer}) +-@standards{POSIX.1c, time.h} +-@safety{@prelim{}@mtsafe{@mtsenv{} @mtslocale{}}@asunsafe{@ascuheap{} @asulock{}}@acunsafe{@aculock{} @acsmem{} @acsfd{}}} +-@c ctime_r @mtsenv @mtslocale @ascuheap @asulock @aculock @acsmem @acsfd +-@c localtime_r dup @mtsenv @mtslocale @ascuheap @asulock @aculock @acsmem @acsfd +-@c asctime_r dup @mtslocale +-This function is similar to @code{ctime}, but places the result in the +-string pointed to by @var{buffer}. It is equivalent to (written using +-gcc extensions, @pxref{Statement Exprs,,,gcc,Porting and Using gcc}): +- +-@smallexample +-(@{ struct tm tm; asctime_r (localtime_r (time, &tm), buf); @}) +-@end smallexample +- +-If no error occurred the function returns a pointer to the string the +-result was written into, i.e., it returns @var{buffer}. Otherwise +-it returns @code{NULL}. +-@end deftypefun +- +- + @deftypefun size_t strftime (char *@var{s}, size_t @var{size}, const char *@var{template}, const struct tm *@var{brokentime}) + @standards{ISO, time.h} + @safety{@prelim{}@mtsafe{@mtsenv{} @mtslocale{}}@asunsafe{@asucorrupt{} @ascuheap{} @asulock{} @ascudlopen{}}@acunsafe{@acucorrupt{} @aculock{} @acsmem{} @acsfd{}}} +@@ -1445,10 +1423,10 @@ it returns @code{NULL}. + @c tm_diff ok + This function is similar to the @code{sprintf} function (@pxref{Formatted + Input}), but the conversion specifications that can appear in the format +-template @var{template} are specialized for printing components of the date +-and time @var{brokentime} according to the locale currently specified for ++template @var{template} are specialized for printing components of ++@var{brokentime} according to the locale currently specified for + time conversion (@pxref{Locales}) and the current time zone +-(@pxref{Time Zone Functions}). ++(@pxref{Time Zone State}). + + Ordinary characters appearing in the @var{template} are copied to the + output string @var{s}; this can include multibyte character sequences. +@@ -1484,8 +1462,7 @@ the result is written right adjusted and space padded to the given + size. + + An optional modifier can follow the optional flag and width +-specification. The modifiers, which were first standardized by +-POSIX.2-1992 and by @w{ISO C99}, are: ++specification. The modifiers are: + + @table @code + @item E +@@ -1553,51 +1530,36 @@ If the @code{E} modifier is specified (@code{%EC}), instead produces + the name of the period for the year (e.g.@: an era name) in the + locale's alternative calendar. + +-This format was first standardized by POSIX.2-1992 and by @w{ISO C99}. +- + @item %d + The day of the month as a decimal number (range @code{01} through @code{31}). + + @item %D + The date using the format @code{%m/%d/%y}. + +-This format was first standardized by POSIX.2-1992 and by @w{ISO C99}. +- + @item %e + The day of the month like with @code{%d}, but padded with spaces (range + @code{ 1} through @code{31}). + +-This format was first standardized by POSIX.2-1992 and by @w{ISO C99}. +- + @item %F + The date using the format @code{%Y-%m-%d}. This is the form specified + in the @w{ISO 8601} standard and is the preferred form for all uses. + +-This format was first standardized by @w{ISO C99} and by POSIX.1-2001. +- + @item %g + The year corresponding to the ISO week number, but without the century + (range @code{00} through @code{99}). This has the same format and value + as @code{%y}, except that if the ISO week number (see @code{%V}) belongs + to the previous or next year, that year is used instead. + +-This format was first standardized by @w{ISO C99} and by POSIX.1-2001. +- + @item %G + The year corresponding to the ISO week number. This has the same format + and value as @code{%Y}, except that if the ISO week number (see + @code{%V}) belongs to the previous or next year, that year is used + instead. + +-This format was first standardized by @w{ISO C99} and by POSIX.1-2001 +-but was previously available as a GNU extension. +- + @item %h + The abbreviated month name according to the current locale. The action + is the same as for @code{%b}. + +-This format was first standardized by POSIX.2-1992 and by @w{ISO C99}. +- + @item %H + The hour as a decimal number, using a 24-hour clock (range @code{00} through + @code{23}). +@@ -1630,13 +1592,11 @@ The minute as a decimal number (range @code{00} through @code{59}). + @item %n + A single @samp{\n} (newline) character. + +-This format was first standardized by POSIX.2-1992 and by @w{ISO C99}. +- + @item %p + Either @samp{AM} or @samp{PM}, according to the given time value; or the + corresponding strings for the current locale. Noon is treated as + @samp{PM} and midnight as @samp{AM}. In most locales +-@samp{AM}/@samp{PM} format is not supported, in such cases @code{"%p"} ++@samp{AM}/@samp{PM} format is not supported, in such cases @t{"%p"} + yields an empty string. + + @ignore +@@ -1648,24 +1608,21 @@ Either @samp{am} or @samp{pm}, according to the given time value; or the + corresponding strings for the current locale, printed in lowercase + characters. Noon is treated as @samp{pm} and midnight as @samp{am}. In + most locales @samp{AM}/@samp{PM} format is not supported, in such cases +-@code{"%P"} yields an empty string. ++@t{"%P"} yields an empty string. + + This format is a GNU extension. + + @item %r + The complete calendar time using the AM/PM format of the current locale. + +-This format was first standardized by POSIX.2-1992 and by @w{ISO C99}. + In the POSIX locale, this format is equivalent to @code{%I:%M:%S %p}. + + @item %R + The hour and minute in decimal numbers using the format @code{%H:%M}. + +-This format was first standardized by @w{ISO C99} and by POSIX.1-2001 +-but was previously available as a GNU extension. +- + @item %s +-The number of seconds since the epoch, i.e., since 1970-01-01 00:00:00 UTC. ++The number of seconds since the POSIX Epoch, ++i.e., since 1970-01-01 00:00:00 UTC@. + Leap seconds are not counted unless leap second support is available. + + This format is a GNU extension. +@@ -1676,19 +1633,13 @@ The seconds as a decimal number (range @code{00} through @code{60}). + @item %t + A single @samp{\t} (tabulator) character. + +-This format was first standardized by POSIX.2-1992 and by @w{ISO C99}. +- + @item %T + The time of day using decimal numbers using the format @code{%H:%M:%S}. + +-This format was first standardized by POSIX.2-1992 and by @w{ISO C99}. +- + @item %u + The day of the week as a decimal number (range @code{1} through + @code{7}), Monday being @code{1}. + +-This format was first standardized by POSIX.2-1992 and by @w{ISO C99}. +- + @item %U + The week number of the current year as a decimal number (range @code{00} + through @code{53}), starting with the first Sunday as the first day of +@@ -1696,7 +1647,7 @@ the first week. Days preceding the first Sunday in the year are + considered to be in week @code{00}. + + @item %V +-The @w{ISO 8601:1988} week number as a decimal number (range @code{01} ++The @w{ISO 8601} week number as a decimal number (range @code{01} + through @code{53}). ISO weeks start with Monday and end with Sunday. + Week @code{01} of a year is the first week which has the majority of its + days in that year; this is equivalent to the week containing the year's +@@ -1706,8 +1657,6 @@ The week before week @code{01} of a year is the last week (@code{52} or + @code{53}) of the previous year even if it contains days from the new + year. + +-This format was first standardized by POSIX.2-1992 and by @w{ISO C99}. +- + @item %w + The day of the week as a decimal number (range @code{0} through + @code{6}), Sunday being @code{0}. +@@ -1747,16 +1696,13 @@ extension, the formatting flags @code{_} or @code{-} may be used with + this conversion specifier; they affect how the year number is printed. + + @item %z +-@w{RFC 822}/@w{ISO 8601:1988} style numeric time zone (e.g., ++@w{RFC 5322}/@w{ISO 8601} style numeric time zone (e.g., + @code{-0600} or @code{+0100}), or nothing if no time zone is + determinable. + +-This format was first standardized by @w{ISO C99} and by POSIX.1-2001 +-but was previously available as a GNU extension. +- +-In the POSIX locale, a full @w{RFC 822} timestamp is generated by the format +-@w{@samp{"%a, %d %b %Y %H:%M:%S %z"}} (or the equivalent +-@w{@samp{"%a, %d %b %Y %T %z"}}). ++In the POSIX locale, a full @w{RFC 5322} timestamp is generated by the format ++@w{@t{"%a, %d %b %Y %H:%M:%S %z"}} (or the equivalent ++@w{@t{"%a, %d %b %Y %T %z"}}). + + @item %Z + The time zone abbreviation (empty if the time zone can't be determined). +@@ -1779,7 +1725,7 @@ format strings and certain locales the output really can be the empty + string and this cannot be discovered by testing the return value only. + E.g., in most locales the AM/PM time format is not supported (most of + the world uses the 24 hour time representation). In such locales +-@code{"%p"} will return the empty string, i.e., the return value is ++@t{"%p"} will return the empty string, i.e., the return value is + zero. To detect situations like this something similar to the following + code should be used: + +@@ -1796,16 +1742,22 @@ if (len == 0 && buf[0] != '\0') + If @var{s} is a null pointer, @code{strftime} does not actually write + anything, but instead returns the number of characters it would have written. + +-Calling @code{strftime} also sets the current time zone as if +-@code{tzset} were called; @code{strftime} uses this information +-instead of @var{brokentime}'s @code{tm_gmtoff} and @code{tm_zone} +-members. @xref{Time Zone Functions}. ++Calling @code{strftime} also sets the time zone state as if ++@code{tzset} were called. @xref{Time Zone State}. + + For an example of @code{strftime}, see @ref{Time Functions Example}. + @end deftypefun + ++@deftypefun size_t strftime_l (char *restrict @var{s}, size_t @var{size}, const char *restrict @var{template}, const struct tm *@var{brokentime}, locale_t @var{locale}) ++@standards{POSIX.1, time.h} ++@safety{@prelim{}@mtsafe{@mtsenv{} @mtslocale{}}@asunsafe{@asucorrupt{} @ascuheap{} @asulock{} @ascudlopen{}}@acunsafe{@acucorrupt{} @aculock{} @acsmem{} @acsfd{}}} ++The @code{strftime_l} function is equivalent to the @code{strftime} ++function except that it operates in @var{locale} rather than in ++the current locale. ++@end deftypefun ++ + @deftypefun size_t wcsftime (wchar_t *@var{s}, size_t @var{size}, const wchar_t *@var{template}, const struct tm *@var{brokentime}) +-@standards{ISO/Amend1, time.h} ++@standards{ISO, time.h} + @safety{@prelim{}@mtsafe{@mtsenv{} @mtslocale{}}@asunsafe{@asucorrupt{} @ascuheap{} @asulock{} @ascudlopen{}}@acunsafe{@acucorrupt{} @aculock{} @acsmem{} @acsfd{}}} + @c wcsftime @mtsenv @mtslocale @asucorrupt @ascuheap @asulock @ascudlopen @acucorrupt @aculock @acsmem @acsfd + @c wcsftime_l @mtsenv @mtslocale @asucorrupt @ascuheap @asulock @ascudlopen @acucorrupt @aculock @acsmem @acsfd +@@ -1875,6 +1827,114 @@ can be placed in the buffer @var{s} the return value is zero, with the + same problems indicated in the @code{strftime} documentation. + @end deftypefun + ++@deftypefun {Deprecated function} {char *} asctime (const struct tm *@var{brokentime}) ++@standards{ISO, time.h} ++@safety{@prelim{}@mtunsafe{@mtasurace{:asctime} @mtslocale{}}@asunsafe{}@acsafe{}} ++@c asctime @mtasurace:asctime @mtslocale ++@c Uses a static buffer. ++@c asctime_internal @mtslocale ++@c snprintf dup @mtslocale [no @acsuheap @acsmem] ++@c ab_day_name @mtslocale ++@c ab_month_name @mtslocale ++The @code{asctime} function converts the broken-down time value that ++@var{brokentime} points to into a string in a standard format: ++ ++@smallexample ++"Tue May 21 13:46:22 1991\n" ++@end smallexample ++ ++The abbreviations for the days of week are: @samp{Sun}, @samp{Mon}, ++@samp{Tue}, @samp{Wed}, @samp{Thu}, @samp{Fri}, and @samp{Sat}. ++ ++The abbreviations for the months are: @samp{Jan}, @samp{Feb}, ++@samp{Mar}, @samp{Apr}, @samp{May}, @samp{Jun}, @samp{Jul}, @samp{Aug}, ++@samp{Sep}, @samp{Oct}, @samp{Nov}, and @samp{Dec}. ++ ++Behavior is undefined if the calculated year would be less than 1000 ++or greater than 9999. ++ ++The return value points to a statically allocated string, which might be ++overwritten by subsequent calls to @code{asctime} or @code{ctime}. ++(No other library function overwrites the contents of this ++string.) ++ ++@strong{Portability note:} ++This obsolescent function is deprecated in C23. ++Programs should instead use @code{strftime} or even @code{sprintf}. ++@end deftypefun ++ ++@deftypefun {Deprecated function} {char *} asctime_r (const struct tm *@var{brokentime}, char *@var{buffer}) ++@standards{???, time.h} ++@safety{@prelim{}@mtsafe{@mtslocale{}}@assafe{}@acsafe{}} ++@c asctime_r @mtslocale ++@c asctime_internal dup @mtslocale ++This function is similar to @code{asctime} but instead of placing the ++result in a static buffer it writes the string in the buffer pointed to ++by the parameter @var{buffer}. This buffer should have room ++for at least 26 bytes, including the terminating null. ++Behavior is undefined if the calculated year would be less than 1000 ++or greater than 9999. ++ ++If no error occurred the function returns a pointer to the string the ++result was written into, i.e., it returns @var{buffer}. Otherwise ++it returns @code{NULL}. ++ ++@strong{Portability Note:} ++POSIX.1-2024 removed this obsolescent function. ++Programs should instead use @code{strftime} or even @code{sprintf}. ++@end deftypefun ++ ++@deftypefun {Deprecated function} {char *} ctime (const time_t *@var{time}) ++@standards{ISO, time.h} ++@safety{@prelim{}@mtunsafe{@mtasurace{:tmbuf} @mtasurace{:asctime} @mtsenv{} @mtslocale{}}@asunsafe{@ascuheap{} @asulock{}}@acunsafe{@aculock{} @acsmem{} @acsfd{}}} ++@c ctime @mtasurace:tmbuf @mtasurace:asctime @mtsenv @mtslocale @ascuheap @asulock @aculock @acsmem @acsfd ++@c localtime dup @mtasurace:tmbuf @mtsenv @mtslocale @ascuheap @asulock @aculock @acsmem @acsfd ++@c asctime dup @mtasurace:asctime @mtslocale ++The @code{ctime} function is similar to @code{asctime}, except that you ++specify the calendar time argument as a @code{time_t} simple time value ++rather than in broken-down local time format. It is equivalent to ++ ++@smallexample ++asctime (localtime (@var{time})) ++@end smallexample ++ ++Behavior is undefined if the calculated year would be less than 1000 ++or greater than 9999. ++ ++Calling @code{ctime} also sets the time zone state as if ++@code{tzset} were called. @xref{Time Zone State}. ++ ++@strong{Portability note:} ++This obsolescent function is deprecated in C23. ++Programs should instead use @code{strftime} or even @code{sprintf}. ++@end deftypefun ++ ++@deftypefun {Deprecated function} {char *} ctime_r (const time_t *@var{time}, char *@var{buffer}) ++@standards{???, time.h} ++@safety{@prelim{}@mtsafe{@mtsenv{} @mtslocale{}}@asunsafe{@ascuheap{} @asulock{}}@acunsafe{@aculock{} @acsmem{} @acsfd{}}} ++@c ctime_r @mtsenv @mtslocale @ascuheap @asulock @aculock @acsmem @acsfd ++@c localtime_r dup @mtsenv @mtslocale @ascuheap @asulock @aculock @acsmem @acsfd ++@c asctime_r dup @mtslocale ++This function is similar to @code{ctime}, but places the result in the ++string pointed to by @var{buffer}, and the time zone state is not ++necessarily set as if @code{tzset} were called. It is equivalent to: ++ ++@smallexample ++asctime_r (localtime_r (@var{time}, &(struct tm) @{0@}), @var{buffer}) ++@end smallexample ++ ++Behavior is undefined if the calculated year would be less than 1000 ++or greater than 9999. ++ ++If no error occurred the function returns a pointer to the string the ++result was written into, i.e., it returns @var{buffer}. Otherwise ++it returns @code{NULL}. ++ ++@strong{Portability Note:} ++POSIX.1-2024 removed this obsolescent function. ++Programs should instead use @code{strftime} or even @code{sprintf}. ++@end deftypefun ++ + @node Parsing Date and Time + @subsection Convert textual time and date information back + +@@ -1934,13 +1994,13 @@ structure @var{tp}. + + The input string could be generated by a @code{strftime} call or + obtained any other way. It does not need to be in a human-recognizable +-format; e.g. a date passed as @code{"02:1999:9"} is acceptable, even ++format; e.g. a date passed as @t{"02:1999:9"} is acceptable, even + though it is ambiguous without context. As long as the format string + @var{fmt} matches the input string the function will succeed. + + The user has to make sure, though, that the input can be parsed in a +-unambiguous way. The string @code{"1999112"} can be parsed using the +-format @code{"%Y%m%d"} as 1999-1-12, 1999-11-2, or even 19991-1-2. It ++unambiguous way. The string @t{"1999112"} can be parsed using the ++format @t{"%Y%m%d"} as 1999-1-12, 1999-11-2, or even 19991-1-2. It + is necessary to add appropriate separators to reliably get results. + + The format string consists of the same components as the format string +@@ -2074,7 +2134,7 @@ Same as @code{%M} but using the locale's alternative numeric symbols. + + @item %n + @itemx %t +-Matches any white space. ++Matches any whitespace. + + @item %p + @item %P +@@ -2098,7 +2158,8 @@ The hour and minute in decimal numbers using the format @code{%H:%M}. + @code{%R} is a GNU extension following a GNU extension to @code{strftime}. + + @item %s +-The number of seconds since the epoch, i.e., since 1970-01-01 00:00:00 UTC. ++The number of seconds since the POSIX Epoch, ++i.e., since 1970-01-01 00:00:00 UTC@. + Leap seconds are not counted unless leap second support is available. + + @code{%s} is a GNU extension following a GNU extension to @code{strftime}. +@@ -2138,7 +2199,7 @@ Leading zeroes are permitted but not required. + Same as @code{%U} but using the locale's alternative numeric symbols. + + @item %V +-The @w{ISO 8601:1988} week number as a decimal number (range @code{1} ++The @w{ISO 8601} week number as a decimal number (range @code{1} + through @code{53}). + + Leading zeroes are permitted but not required. +@@ -2212,7 +2273,7 @@ The year as a decimal number, using the Gregorian calendar. + The full alternative year representation. + + @item %z +-The offset from GMT in @w{ISO 8601}/RFC822 format. ++The offset from UTC in @w{ISO 8601}/@w{RFC 5322} format. + + @item %Z + The time zone abbreviation. +@@ -2225,7 +2286,7 @@ A literal @samp{%} character. + @end table + + All other characters in the format string must have a matching character +-in the input string. Exceptions are white spaces in the input string ++in the input string. Exceptions are whitespace characters in the input string + which can match zero or more whitespace characters in the format string. + + @strong{Portability Note:} The XPG standard advises applications to use +@@ -2233,10 +2294,10 @@ at least one whitespace character (as specified by @code{isspace}) or + other non-alphanumeric characters between any two conversion + specifications. @Theglibc{} does not have this limitation but + other libraries might have trouble parsing formats like +-@code{"%d%m%Y%H%M%S"}. ++@t{"%d%m%Y%H%M%S"}. + + The @code{strptime} function processes the input string from right to +-left. Each of the three possible input elements (white space, literal, ++left. Each of the three possible input elements (whitespace, literal, + or format) are handled one after the other. If the input cannot be + matched to the format string the function stops. The remainder of the + format and input strings are not processed. +@@ -2312,8 +2373,8 @@ The Unix standard defines another function for parsing date strings. + The interface is weird, but if the function happens to suit your + application it is just fine. It is problematic to use this function + in multi-threaded programs or libraries, since it returns a pointer to +-a static variable, and uses a global variable and global state (an +-environment variable). ++a static variable, and uses a global variable and global state based ++on an environment variable. + + @defvar getdate_err + @standards{Unix98, time.h} +@@ -2322,9 +2383,9 @@ unsuccessful call to @code{getdate}. Defined values are: + + @table @math + @item 1 +-The environment variable @code{DATEMSK} is not defined or null. ++The environment variable @env{DATEMSK} is not defined or null. + @item 2 +-The template file denoted by the @code{DATEMSK} environment variable ++The template file denoted by the @env{DATEMSK} environment variable + cannot be opened. + @item 3 + Information about the template file cannot retrieved. +@@ -2355,7 +2416,7 @@ string and the result is returned in a statically-allocated variable. + The details about how the string is processed are hidden from the user. + In fact, they can be outside the control of the program. Which formats + are recognized is controlled by the file named by the environment +-variable @code{DATEMSK}. This file should contain ++variable @env{DATEMSK}. This file should contain + lines of valid format strings which could be passed to @code{strptime}. + + The @code{getdate} function reads these format strings one after the +@@ -2372,7 +2433,7 @@ extensions to the @code{strptime} behavior: + @itemize @bullet + @item + If the @code{%Z} format is given the broken-down time is based on the +-current time of the timezone matched, not of the current timezone of the ++current time of the time zone matched, not of the current time zone of the + runtime environment. + + @emph{Note}: This is not implemented (currently). The problem is that +@@ -2451,7 +2512,7 @@ description above for a list of the possible error values. + + @emph{Warning:} The @code{getdate} function should @emph{never} be + used in SUID-programs. The reason is obvious: using the +-@code{DATEMSK} environment variable you can get the function to open ++@env{DATEMSK} environment variable you can get the function to open + any arbitrary file and chances are high that with some bogus input + (such as a binary file) the program will crash. + @end deftypefun +@@ -2500,71 +2561,174 @@ The warning against using @code{getdate} in SUID-programs applies to + @end deftypefun + + @node TZ Variable +-@subsection Specifying the Time Zone with @code{TZ} ++@subsection Specifying the Time Zone with @env{TZ} + + In POSIX systems, a user can specify the time zone by means of the +-@code{TZ} environment variable. For information about how to set ++@env{TZ} environment variable. For information about how to set + environment variables, see @ref{Environment Variables}. The functions + for accessing the time zone are declared in @file{time.h}. + @pindex time.h + @cindex time zone + +-You should not normally need to set @code{TZ}. If the system is ++You should not normally need to set @env{TZ}. If the system is + configured properly, the default time zone will be correct. You might +-set @code{TZ} if you are using a computer over a network from a ++set @env{TZ} if you are using a computer over a network from a + different time zone, and would like times reported to you in the time + zone local to you, rather than what is local to the computer. + +-In POSIX.1 systems the value of the @code{TZ} variable can be in one of +-three formats. With @theglibc{}, the most common format is the +-last one, which can specify a selection from a large database of time +-zone information for many regions of the world. The first two formats +-are used to describe the time zone information directly, which is both +-more cumbersome and less precise. But the POSIX.1 standard only +-specifies the details of the first two formats, so it is good to be +-familiar with them in case you come across a POSIX.1 system that doesn't +-support a time zone information database. ++The value of @env{TZ} can be in one of the following formats: + +-The first format is used when there is no Daylight Saving Time (or +-summer time) in the local time zone: ++@itemize ++@item ++The @dfn{geographical format} specifies a location that stands for ++the past and future time zones observed in that location. ++@xref{Geographical TZ}. ++Here are some examples: + + @smallexample +-@r{@var{std} @var{offset}} ++Asia/Tokyo ++America/New_York ++/usr/share/zoneinfo/America/Nuuk + @end smallexample + +-The @var{std} string specifies the time zone abbreviation. It must be +-three or more characters long and must not contain a leading colon, +-embedded digits, commas, nor plus and minus signs. There is no space ++@item ++The @dfn{proleptic format} represents a time zone that has always ++been and always will be the same offset from UTC, ++optionally with a simple daylight saving scheme that has always been ++(and always will be) used every year. ++@xref{Proleptic TZ}. ++Here are some examples: ++ ++@smallexample ++JST-9 ++EST+5EDT,M3.2.0/2,M11.1.0/2 ++<-02>+2<-01>,M3.5.0/-1,M10.5.0/0 ++@end smallexample ++ ++@item ++The @dfn{colon format} begins with @samp{:}. Here is an example. ++ ++@smallexample ++:/etc/localtime ++@end smallexample ++ ++@noindent ++Each operating system can interpret this format differently; ++in @theglibc{}, the @samp{:} is ignored and @var{characters} ++are treated as if they specified the geographical or proleptic format. ++ ++@item ++As an extension to POSIX, when the value of @env{TZ} is the empty string, ++@theglibc{} uses UTC. ++@end itemize ++ ++@pindex /etc/localtime ++@pindex localtime ++If the @env{TZ} environment variable does not have a value, the ++implementation chooses a time zone by default. In @theglibc{}, the ++default time zone is like the specification @samp{TZ=/etc/localtime} ++(or @samp{TZ=/usr/local/etc/localtime}, depending on how @theglibc{} ++was configured; @pxref{Installation}). Other C libraries use their own ++rule for choosing the default time zone, so there is little we can say ++about them. ++ ++@menu ++* Geographical TZ:: @env{TZ} settings like @samp{America/New_York}. ++* Proleptic TZ:: @env{TZ} settings like @samp{EST+5EDT,M3.2.0/2,M11.1.0/2}. ++@end menu ++ ++@node Geographical TZ ++@subsubsection Geographical Format for @env{TZ} ++ ++The geographical format names a time zone ruleset maintained by the ++@url{http://www.iana.org/time-zones, ++Time Zone Database} of time zone and daylight saving time ++information for most regions of the world. ++This public-domain database is maintained by a community of volunteers. ++@cindex time zone database ++@pindex /usr/share/zoneinfo ++@pindex zoneinfo ++ ++If the format's @var{characters} begin with @samp{/} ++it is an absolute file name; ++otherwise the library looks for the file ++@w{@file{/usr/share/zoneinfo/@var{characters}}}. The @file{zoneinfo} ++directory contains data files describing time zone rulesets in many ++different parts of the world. The names represent major cities, with ++subdirectories for geographical areas; for example, ++@file{America/New_York}, @file{Europe/London}, @file{Asia/Tokyo}. ++These data files are installed by the system administrator, who also ++sets @file{/etc/localtime} to point to the data file for the local time ++zone ruleset. ++ ++If the file corresponding to @var{characters} cannot be read or has ++invalid data, and @var{characters} are not in the proleptic format, ++then @theglibc{} silently defaults to UTC@. However, applications ++should not depend on this, as @env{TZ} formats may be extended in the ++future. ++ ++@node Proleptic TZ ++@subsubsection Proleptic Format for @env{TZ} ++ ++Although the proleptic format is cumbersome and inaccurate for old timestamps, ++POSIX.1-2017 and earlier specified details only for the proleptic format, ++and you may need to use it on small systems that lack a time zone ++information database. ++ ++The proleptic format is: ++ ++@smallexample ++@r{@var{std}@var{offset}[@var{dst}[@var{offset}][@t{,}@var{start}[@t{/}@var{time}]@t{,}@var{end}[@t{/}@var{time}]]]} ++@end smallexample ++ ++The @var{std} string specifies the time zone abbreviation, ++which must be at least three bytes long, ++and which can appear in unquoted or quoted form. ++The unquoted form can contain only ASCII alphabetic characters. ++The quoted form can also contain ASCII digits, @samp{+}, and @samp{-}; ++it is quoted by surrounding it by @samp{<} and @samp{>}, ++which are not part of the abbreviation. There is no space + character separating the time zone abbreviation from the @var{offset}, so these + restrictions are necessary to parse the specification correctly. + + The @var{offset} specifies the time value you must add to the local time +-to get a Coordinated Universal Time value. It has syntax like +-[@code{+}|@code{-}]@var{hh}[@code{:}@var{mm}[@code{:}@var{ss}]]. This +-is positive if the local time zone is west of the Prime Meridian and +-negative if it is east. The hour must be between @code{0} and +-@code{24}, and the minute and seconds between @code{0} and @code{59}. +- +-For example, here is how we would specify Eastern Standard Time, but +-without any Daylight Saving Time alternative: ++to get a UTC value. It has syntax like: + + @smallexample +-EST+5 ++[@t{+}|@t{-}]@var{hh}[@t{:}@var{mm}[@t{:}@var{ss}]] + @end smallexample + +-The second format is used when there is Daylight Saving Time: ++@noindent ++This ++is positive if the local time zone is west of the Prime Meridian and ++negative if it is east; this is opposite from the usual convention ++that positive time zone offsets are east of the Prime Meridian. ++The hour @var{hh} must be between 0 and 24 ++and may be a single digit, and the minutes @var{mm} and seconds ++@var{ss}, if present, must be between 0 and 59. ++ ++For example, to specify time in Panama, which is Eastern Standard Time ++without any daylight saving time alternative: + + @smallexample +-@r{@var{std} @var{offset} @var{dst} [@var{offset}]@code{,}@var{start}[@code{/}@var{time}]@code{,}@var{end}[@code{/}@var{time}]} ++EST+5 + @end smallexample + ++When daylight saving time is used, the proleptic format is more complicated. + The initial @var{std} and @var{offset} specify the standard time zone, as + described above. The @var{dst} string and @var{offset} are the abbreviation +-and offset for the corresponding Daylight Saving Time zone; if the ++and offset for the corresponding daylight saving time zone; if the + @var{offset} is omitted, it defaults to one hour ahead of standard time. + +-The remainder of the specification describes when Daylight Saving Time is +-in effect. The @var{start} field is when Daylight Saving Time goes into ++The remainder of the proleptic format, which starts with the first comma, ++describes when daylight saving time is in effect. This remainder is ++optional and if omitted, @theglibc{} defaults to the daylight saving ++rules that would be used if @env{TZ} had the value @t{"posixrules"}. ++However, other POSIX implementations default to different daylight ++saving rules, so portable @env{TZ} settings should not omit the ++remainder. ++ ++In the remainder, the @var{start} field is when daylight saving time goes into + effect and the @var{end} field is when the change is made back to standard + time. The following formats are recognized for these fields: + +@@ -2587,132 +2751,67 @@ between @code{1} and @code{12}. + @end table + + The @var{time} fields specify when, in the local time currently in +-effect, the change to the other time occurs. If omitted, the default is +-@code{02:00:00}. The hours part of the time fields can range from +-@minus{}167 through 167; this is an extension to POSIX.1, which allows +-only the range 0 through 24. +- +-Here are some example @code{TZ} values, including the appropriate +-Daylight Saving Time and its dates of applicability. In North +-American Eastern Standard Time (EST) and Eastern Daylight Time (EDT), ++effect, the change to the other time occurs. They have the same ++format as @var{offset} except the hours part can range from ++@minus{}167 through 167; for example, @code{-22:30} stands for 01:30 ++the previous day and @code{25:30} stands for 01:30 the next day. If ++omitted, @var{time} defaults to @code{02:00:00}. ++ ++Here are example @env{TZ} values with daylight saving time rules. ++ ++@table @samp ++@item EST+5EDT,M3.2.0/2,M11.1.0/2 ++In North American Eastern Standard Time (EST) and Eastern Daylight Time (EDT), + the normal offset from UTC is 5 hours; since this is +-west of the prime meridian, the sign is positive. Summer time begins on ++west of the Prime Meridian, the sign is positive. Summer time begins on + March's second Sunday at 2:00am, and ends on November's first Sunday + at 2:00am. + +-@smallexample +-EST+5EDT,M3.2.0/2,M11.1.0/2 +-@end smallexample +- ++@item IST-2IDT,M3.4.4/26,M10.5.0 + Israel Standard Time (IST) and Israel Daylight Time (IDT) are 2 hours + ahead of the prime meridian in winter, springing forward an hour on + March's fourth Thursday at 26:00 (i.e., 02:00 on the first Friday on or + after March 23), and falling back on October's last Sunday at 02:00. + +-@smallexample +-IST-2IDT,M3.4.4/26,M10.5.0 +-@end smallexample +- +-Western Argentina Summer Time (WARST) is 3 hours behind the prime +-meridian all year. There is a dummy fall-back transition on December +-31 at 25:00 daylight saving time (i.e., 24:00 standard time, +-equivalent to January 1 at 00:00 standard time), and a simultaneous +-spring-forward transition on January 1 at 00:00 standard time, so +-daylight saving time is in effect all year and the initial @code{WART} +-is a placeholder. ++@item IST-1GMT0,M10.5.0,M3.5.0/1 ++Irish Standard Time (IST) is 1 hour behind the Prime Meridian in ++summer, falling forward to Greenwich Mean Time (GMT, the Prime ++Meridian's time), on October's last Sunday at 00:00 and springing back ++on March's last Sunday at 01:00. This is an example of ``negative ++daylight saving''; here, daylight saving time is one hour west of ++standard time instead of the more usual one hour east. + +-@smallexample +-WART4WARST,J1/0,J365/25 +-@end smallexample +- +-Western Greenland Time (WGT) and Western Greenland Summer Time (WGST) +-are 3 hours behind UTC in the winter. Its clocks follow the European ++@item <-02>+2<-01>,M3.5.0/-1,M10.5.0/0 ++Most of Greenland is 2 hours behind UTC in winter. Clocks follow the European + Union rules of springing forward by one hour on March's last Sunday at +-01:00 UTC (@minus{}02:00 local time) and falling back on October's +-last Sunday at 01:00 UTC (@minus{}01:00 local time). +- +-@smallexample +-WGT3WGST,M3.5.0/-2,M10.5.0/-1 +-@end smallexample ++01:00 UTC (@minus{}01:00 local time) and falling back on October's ++last Sunday at 01:00 UTC (00:00 local time). ++The numeric abbreviations @samp{-02} and @samp{-01} stand ++for standard and daylight saving time, respectively. ++@end table + +-The schedule of Daylight Saving Time in any particular jurisdiction has ++The schedule of daylight saving time in any particular jurisdiction has + changed over the years. To be strictly correct, the conversion of dates + and times in the past should be based on the schedule that was in effect +-then. However, this format has no facilities to let you specify how the ++then. However, the proleptic format does not let you specify how the + schedule has changed from year to year. The most you can do is specify + one particular schedule---usually the present day schedule---and this is + used to convert any date, no matter when. For precise time zone +-specifications, it is best to use the time zone information database +-(see below). +- +-The third format looks like this: +- +-@smallexample +-:@var{characters} +-@end smallexample +- +-Each operating system interprets this format differently; in +-@theglibc{}, @var{characters} is the name of a file which describes the time +-zone. +- +-@pindex /etc/localtime +-@pindex localtime +-If the @code{TZ} environment variable does not have a value, the +-operation chooses a time zone by default. In @theglibc{}, the +-default time zone is like the specification @samp{TZ=:/etc/localtime} +-(or @samp{TZ=:/usr/local/etc/localtime}, depending on how @theglibc{} +-was configured; @pxref{Installation}). Other C libraries use their own +-rule for choosing the default time zone, so there is little we can say +-about them. +- +-@cindex time zone database +-@pindex /usr/share/zoneinfo +-@pindex zoneinfo +-If @var{characters} begins with a slash, it is an absolute file name; +-otherwise the library looks for the file +-@w{@file{/usr/share/zoneinfo/@var{characters}}}. The @file{zoneinfo} +-directory contains data files describing local time zones in many +-different parts of the world. The names represent major cities, with +-subdirectories for geographical areas; for example, +-@file{America/New_York}, @file{Europe/London}, @file{Asia/Hong_Kong}. +-These data files are installed by the system administrator, who also +-sets @file{/etc/localtime} to point to the data file for the local time +-zone. The files typically come from the @url{http://www.iana.org/time-zones, +-Time Zone Database} of time zone and daylight saving time +-information for most regions of the world, which is maintained by a +-community of volunteers and put in the public domain. +- +-@node Time Zone Functions +-@subsection Functions and Variables for Time Zones +- +-@deftypevar {char *} tzname [2] +-@standards{POSIX.1, time.h} +-The array @code{tzname} contains two strings, which are the standard +-abbreviations of the pair of time zones (standard and Daylight +-Saving) that the user has selected. @code{tzname[0]} abbreviates +-the standard time zone (for example, @code{"EST"}), and @code{tzname[1]} +-abbreviates the time zone when Daylight Saving Time is in use (for +-example, @code{"EDT"}). These correspond to the @var{std} and @var{dst} +-strings (respectively) from the @code{TZ} environment variable. If +-Daylight Saving Time is never used, @code{tzname[1]} is the empty string. +- +-The @code{tzname} array is initialized from the @code{TZ} environment +-variable whenever @code{tzset}, @code{ctime}, @code{strftime}, +-@code{mktime}, or @code{localtime} is called. If multiple abbreviations +-have been used (e.g. @code{"EWT"} and @code{"EDT"} for U.S. Eastern War +-Time and Eastern Daylight Time), the array contains the most recent +-abbreviation. +- +-The @code{tzname} array is required for POSIX.1 compatibility, but in +-GNU programs it is better to use the @code{tm_zone} member of the +-broken-down time structure, since @code{tm_zone} reports the correct +-abbreviation even when it is not the latest one. +- +-Though the strings are declared as @code{char *} the user must refrain +-from modifying these strings. Modifying the strings will almost certainly +-lead to trouble. +- +-@end deftypevar ++specifications, it is best to use the geographical format. ++@xref{Geographical TZ}. ++ ++@node Time Zone State ++@subsection State Variables for Time Zones ++ ++For compatibility with POSIX, @theglibc{} defines global state ++variables that depend on time zone rules specified by the @env{TZ} ++environment variable. However, these state variables are obsolescent ++and are planned to be removed in a future version of POSIX, ++and programs generally should avoid them because they are not ++thread-safe and their values are specified only when @env{TZ} uses the ++proleptic format. @xref{TZ Variable}. ++Programs should instead use the @code{tm_gmtoff} and ++@code{tm_zone} members of @code{struct tm}. @xref{Broken-down Time}. + + @deftypefun void tzset (void) + @standards{POSIX.1, time.h} +@@ -2721,34 +2820,64 @@ lead to trouble. + @c libc_lock_lock dup @asulock @aculock + @c tzset_internal dup @mtsenv @mtslocale @ascuheap @asulock @aculock @acsmem @acsfd + @c libc_lock_unlock dup @aculock +-The @code{tzset} function initializes the @code{tzname} variable from +-the value of the @code{TZ} environment variable. It is not usually +-necessary for your program to call this function, because it is called +-automatically when you use the other time conversion functions that +-depend on the time zone. ++The @code{tzset} function initializes the state variables from ++the value of the @env{TZ} environment variable. ++It is not usually necessary for your program to call this function, ++partly because your program should not use the state variables, ++and partly because this function is called automatically ++when you use the time conversion functions @code{localtime}, ++@code{mktime}, @code{strftime}, @code{strftime_l}, and ++@code{wcsftime}, or the deprecated function @code{ctime}. ++Behavior is undefined if one thread accesses any of these variables directly ++while another thread is calling @code{tzset} or any other function ++that is required or allowed to behave as if it called @code{tzset}. + @end deftypefun + +-The following variables are defined for compatibility with System V +-Unix. Like @code{tzname}, these variables are set by calling +-@code{tzset} or the other time conversion functions. ++@deftypevar {char *} tzname [2] ++@standards{POSIX.1, time.h} ++The array @code{tzname} contains two strings, which are ++abbreviations of time zones (standard and Daylight ++Saving) that the user has selected. @code{tzname[0]} abbreviates ++a standard time zone (for example, @t{"EST"}), and @code{tzname[1]} ++abbreviates a time zone when daylight saving time is in use (for ++example, @t{"EDT"}). These correspond to the @var{std} and @var{dst} ++strings (respectively) when the @env{TZ} environment variable ++uses the proleptic format. ++The string values are unspecified if @env{TZ} uses the geographical format, ++so it is generally better to use the broken-down time structure's ++@code{tm_zone} member instead. ++ ++In @theglibc{}, the strings have a storage lifetime that lasts indefinitely; ++on some other platforms, the lifetime lasts only until @env{TZ} is changed. ++ ++The @code{tzname} array is initialized by @code{tzset}. ++Though the strings are declared as @code{char *} ++the user must refrain from modifying them. ++Modifying the strings will almost certainly lead to trouble. ++ ++@end deftypevar + + @deftypevar {long int} timezone +-@standards{SVID, time.h} +-This contains the difference between UTC and the latest local standard +-time, in seconds west of UTC. For example, in the U.S. Eastern time ++@standards{POSIX.1, time.h} ++This contains the difference between UTC and local standard ++time, in seconds west of the Prime Meridian. ++For example, in the U.S. Eastern time + zone, the value is @code{5*60*60}. Unlike the @code{tm_gmtoff} member + of the broken-down time structure, this value is not adjusted for +-daylight saving, and its sign is reversed. In GNU programs it is better +-to use @code{tm_gmtoff}, since it contains the correct offset even when +-it is not the latest one. ++daylight saving, and its sign is reversed. ++The value is unspecified if @env{TZ} uses the geographical format, ++so it is generally better to use the broken-down time structure's ++@code{tm_gmtoff} member instead. + @end deftypevar + + @deftypevar int daylight +-@standards{SVID, time.h} +-This variable has a nonzero value if Daylight Saving Time rules apply. +-A nonzero value does not necessarily mean that Daylight Saving Time is +-now in effect; it means only that Daylight Saving Time is sometimes in +-effect. ++@standards{POSIX.1, time.h} ++ ++This variable is nonzero if daylight saving time rules apply. ++A nonzero value does not necessarily mean that daylight saving time is ++now in effect; it means only that daylight saving time is sometimes in effect. ++This variable has little or no practical use; ++it is present for POSIX compatibility. + @end deftypevar + + @node Time Functions Example +@@ -2764,9 +2893,9 @@ functions. + It produces output like this: + + @smallexample +-Wed Jul 31 13:02:36 1991 +-Today is Wednesday, July 31. +-The time is 01:02 PM. ++2024-06-09 13:50:06 ++Today is Sunday, June 09. ++The time is 01:50 PM. + @end smallexample + + +@@ -2955,7 +3084,7 @@ amount of delay involved. + + @strong{Portability Note:} The @code{setitimer} and @code{getitimer} + functions are derived from BSD Unix, while the @code{alarm} function is +-specified by the POSIX.1 standard. @code{setitimer} is more powerful than ++specified by POSIX@. @code{setitimer} is more powerful than + @code{alarm}, but @code{alarm} is more widely used. + + @node Sleeping +diff --git a/time/localtime.c b/time/localtime.c +index 8bf916fd6ddbe92c..77d19ff5e718fdc7 100644 +--- a/time/localtime.c ++++ b/time/localtime.c +@@ -18,7 +18,10 @@ + + #include + +-/* The C Standard says that localtime and gmtime return the same pointer. */ ++/* C89 says that localtime and gmtime return the same pointer. ++ Although C99 and later relax this to let localtime and gmtime ++ return different pointers, POSIX and glibc currently follow C89's stricter ++ requirement even though this can cause naive programs to misbehave. */ + struct tm _tmbuf; + + diff --git a/glibc-RHEL-108974-20.patch b/glibc-RHEL-108974-20.patch new file mode 100644 index 0000000..f94124f --- /dev/null +++ b/glibc-RHEL-108974-20.patch @@ -0,0 +1,144 @@ +commit 6c9bb270d6a624f82a38443545e3d99f5b1e07e1 +Author: Florian Weimer +Date: Fri May 16 16:47:02 2025 +0200 + + manual: Clarifications for listing directories + + Support for seeking is limited. Using the d_off and d_reclen members + of struct dirent is discouraged, especially with readdir. Concurrent + modification of directories during iteration may result in duplicate + or missing etnries. + +diff --git a/manual/filesys.texi b/manual/filesys.texi +index aabb68385b6b9732..450d175e614d8834 100644 +--- a/manual/filesys.texi ++++ b/manual/filesys.texi +@@ -409,18 +409,41 @@ entries. It contains the following fields: + This is the null-terminated file name component. This is the only + field you can count on in all POSIX systems. + ++While this field is defined with a specified length, functions such as ++@code{readdir} may return a pointer to a @code{struct dirent} where the ++@code{d_name} extends beyond the end of the struct. ++ + @item ino_t d_fileno + This is the file serial number. For BSD compatibility, you can also + refer to this member as @code{d_ino}. On @gnulinuxhurdsystems{} and most POSIX + systems, for most files this the same as the @code{st_ino} member that + @code{stat} will return for the file. @xref{File Attributes}. + ++@item off_t d_off ++This value contains the offset of the next directory entry (after this ++entry) in the directory stream. The value may not be compatible with ++@code{lseek} or @code{seekdir}, especially if the width of @code{d_off} ++is less than 64 bits. Directory entries are not ordered by offset, and ++the @code{d_off} and @code{d_reclen} values are unrelated. Seeking on ++directory streams is not recommended. The symbol ++@code{_DIRENT_HAVE_D_OFF} is defined if the @code{d_ino} member is ++available. ++ + @item unsigned char d_namlen + This is the length of the file name, not including the terminating + null character. Its type is @code{unsigned char} because that is the + integer type of the appropriate size. This member is a BSD extension. + The symbol @code{_DIRENT_HAVE_D_NAMLEN} is defined if this member is +-available. ++available. (It is not available on Linux.) ++ ++@item unsigned short int d_reclen ++This is the length of the entire directory record. When iterating ++through a buffer filled by @code{getdents64} (@pxref{Low-level Directory ++Access}), this value needs to be added to the offset of the current ++directory entry to obtain the offset of the next entry. When using ++@code{readdir} and related functions, the value of @code{d_reclen} is ++undefined and should not be accessed. The symbol ++@code{_DIRENT_HAVE_D_RECLEN} is defined if this member is available. + + @item unsigned char d_type + This is the type of the file, possibly unknown. The following constants +@@ -457,7 +480,7 @@ This member is a BSD extension. The symbol @code{_DIRENT_HAVE_D_TYPE} + is defined if this member is available. On systems where it is used, it + corresponds to the file type bits in the @code{st_mode} member of + @code{struct stat}. If the value cannot be determined the member +-value is DT_UNKNOWN. These two macros convert between @code{d_type} ++value is @code{DT_UNKNOWN}. These two macros convert between @code{d_type} + values and @code{st_mode} values: + + @deftypefun int IFTODT (mode_t @var{mode}) +@@ -632,6 +655,20 @@ and can be rewritten by a subsequent call. + return entries for @file{.} and @file{..}, even though these are always + valid file names in any directory. @xref{File Name Resolution}. + ++If a directory is modified between a call to @code{readdir} and after ++the directory stream was created or @code{rewinddir} was last called on ++it, it is unspecified according to POSIX whether newly created or ++removed entries appear among the entries returned by repeated ++@code{readdir} calls before the end of the directory is reached. ++However, due to practical implementation constraints, it is possible ++that entries (including unrelated, unmodified entries) appear multiple ++times or do not appear at all if the directory is modified while listing ++it. If the application intends to create files in the directory, it may ++be necessary to complete the iteration first and create a copy of the ++information obtained before creating any new files. (See below for ++instructions regarding copying of @code{d_name}.) The iteration can be ++restarted using @code{rewinddir}. @xref{Random Access Directory}. ++ + If there are no more entries in the directory or an error is detected, + @code{readdir} returns a null pointer. The following @code{errno} error + conditions are defined for this function: +@@ -812,6 +849,10 @@ directory since it was opened with @code{opendir}. (Entries for these + files might or might not be returned by @code{readdir} if they were + added or removed since you last called @code{opendir} or + @code{rewinddir}.) ++ ++For example, it is recommended to call @code{rewinddir} followed by ++@code{readdir} to check if a directory is empty after listing it with ++@code{readdir} and deleting all encountered files from it. + @end deftypefun + + @deftypefun {long int} telldir (DIR *@var{dirstream}) +@@ -823,6 +864,13 @@ added or removed since you last called @code{opendir} or + The @code{telldir} function returns the file position of the directory + stream @var{dirstream}. You can use this value with @code{seekdir} to + restore the directory stream to that position. ++ ++Using the the @code{telldir} function is not recommended. ++ ++The value returned by @code{telldir} may not be compatible with the ++@code{d_off} field in @code{struct dirent}, and cannot be used with the ++@code{lseek} function. The returned value may not unambiguously ++identify the position in the directory stream. + @end deftypefun + + @deftypefun void seekdir (DIR *@var{dirstream}, long int @var{pos}) +@@ -836,6 +884,9 @@ stream @var{dirstream} to @var{pos}. The value @var{pos} must be the + result of a previous call to @code{telldir} on this particular stream; + closing and reopening the directory can invalidate values returned by + @code{telldir}. ++ ++Using the the @code{seekdir} function is not recommended. To seek to ++the beginning of the directory stream, use @code{rewinddir}. + @end deftypefun + + +@@ -1007,9 +1058,20 @@ Note that some file systems support file names longer than + @code{NAME_MAX} bytes (e.g., because they support up to 255 Unicode + characters), so a buffer size of at least 1024 is recommended. + ++If the directory has been modified since the first call to ++@code{getdents64} on the directory (opening the descriptor or seeking to ++offset zero), it is possible that the buffer contains entries that have ++been encountered before. Likewise, it is possible that files that are ++still present are not reported before the end of the directory is ++encountered (and @code{getdents64} returns zero). ++ + This function is specific to Linux. + @end deftypefun + ++Systems that support @code{getdents64} support seeking on directory ++streams. @xref{File Position Primitive}. However, the only offset that ++works reliably is offset zero, indicating that reading the directory ++should start from the beginning. + + @node Working with Directory Trees + @section Working with Directory Trees diff --git a/glibc-RHEL-108974-21.patch b/glibc-RHEL-108974-21.patch new file mode 100644 index 0000000..cbcf694 --- /dev/null +++ b/glibc-RHEL-108974-21.patch @@ -0,0 +1,67 @@ +commit 43afae31e0d7579deef13536c4c3704afaa017da +Author: Maciej W. Rozycki +Date: Thu May 29 22:11:38 2025 +0100 + + manual: Document error codes missing for 'socket' + + Add missing EAFNOSUPPORT, ESOCKTNOSUPPORT, EPROTOTYPE, EINVAL, EPERM, + and ENOMEM error codes, and adjust existing descriptions accordingly. + + On Linux either ENOBUFS or ENOMEM is returned in the case of a memory + allocation failure, depending on the namespace requested, e.g. AF_INET + returns ENOMEM while AF_INET6 returns ENOBUFS, so document these codes + as alternatives. + + Similarly EPERM is returned rather than EACCES on Linux, so document + these codes as alternatives as well. We might want to convert EPERM to + EACCES for POSIX compliance, but it is beyond the scope of this change, + and software has to expect either anyway, owing to the long-established + practice. + + Finally ESOCKTNOSUPPORT is returned rather than EPROTONOSUPPORT for an + unsupported style except for the AF_QIPCRTR namespace where EPROTOTYPE + is used, so document these codes as alternatives too. + + Reviewed-by: Florian Weimer + +diff --git a/manual/socket.texi b/manual/socket.texi +index 8708cbb07ca02b5c..ed24cd5bd41ce8c0 100644 +--- a/manual/socket.texi ++++ b/manual/socket.texi +@@ -2205,9 +2205,19 @@ socket, or @code{-1} in case of error. The following @code{errno} error + conditions are defined for this function: + + @table @code ++@item EAFNOSUPPORT ++The @var{namespace} requested is not supported. ++ ++@item ESOCKTNOSUPPORT ++@itemx EPROTONOSUPPORT ++@itemx EPROTOTYPE ++The @var{style} is not supported by the @var{namespace} specified. ++ + @item EPROTONOSUPPORT +-The @var{protocol} or @var{style} is not supported by the +-@var{namespace} specified. ++The @var{protocol} is not supported by the @var{namespace} specified. ++ ++@item EINVAL ++The @var{style} or @var{protocol} requested is not valid. + + @item EMFILE + The process already has too many file descriptors open. +@@ -2216,11 +2226,13 @@ The process already has too many file descriptors open. + The system already has too many file descriptors open. + + @item EACCES ++@itemx EPERM + The process does not have the privilege to create a socket of the specified + @var{style} or @var{protocol}. + + @item ENOBUFS +-The system ran out of internal buffer space. ++@itemx ENOMEM ++Insufficient memory was available. + @end table + + The file descriptor returned by the @code{socket} function supports both diff --git a/glibc-RHEL-108974-22.patch b/glibc-RHEL-108974-22.patch new file mode 100644 index 0000000..8fac712 --- /dev/null +++ b/glibc-RHEL-108974-22.patch @@ -0,0 +1,36 @@ +commit 79b5febd762d6735ba8e878086a50ea04993e340 +Author: Maciej W. Rozycki +Date: Thu May 29 22:11:38 2025 +0100 + + manual: Document error codes missing for 'inet_ntop' + + Add documentation for EAFNOSUPPORT and ENOSPC error codes returned, and + the return value on failure. + + Reviewed-by: Florian Weimer + +diff --git a/manual/socket.texi b/manual/socket.texi +index ed24cd5bd41ce8c0..2f0e7509e92974d1 100644 +--- a/manual/socket.texi ++++ b/manual/socket.texi +@@ -1211,7 +1211,19 @@ network (binary) to presentation (textual) form. @var{af} should be + either @code{AF_INET} or @code{AF_INET6}, as appropriate. @var{cp} is a + pointer to the address to be converted. @var{buf} should be a pointer + to a buffer to hold the result, and @var{len} is the length of this +-buffer. The return value from the function will be this buffer address. ++buffer. ++ ++The return value is @var{buf} on success. On failure, the function's ++return value is a null pointer and @code{errno} is set accordingly. ++The following @code{errno} values are specific to this function: ++ ++@table @code ++@item EAFNOSUPPORT ++The address family requested is neither @code{AF_INET} nor @code{AF_INET6}. ++ ++@item ENOSPC ++Insufficient space available for the result in the buffer provided. ++@end table + @end deftypefun + + @node Host Names diff --git a/glibc-RHEL-108974-23.patch b/glibc-RHEL-108974-23.patch new file mode 100644 index 0000000..fac9b8c --- /dev/null +++ b/glibc-RHEL-108974-23.patch @@ -0,0 +1,23 @@ +commit 9a743032cd59c59167bf615d8ab4acc96b2bf47e +Author: Maciej W. Rozycki +Date: Fri May 30 15:01:51 2025 +0100 + + manual: Fix invalid 'illegal' usage with 'nanosleep' + + The GNU Coding Standards demand that 'illegal' only be used to refer to + activities prohibited by law. Replace it with 'invalid' accordingly in + the description of the EINVAL error condition for 'nanosleep'. + +diff --git a/manual/time.texi b/manual/time.texi +index 4dde875dde4d8075..e754d3a7e7f5c52d 100644 +--- a/manual/time.texi ++++ b/manual/time.texi +@@ -3212,7 +3212,7 @@ elapsed time. + + @item EINVAL + The nanosecond value in the @var{requested_time} parameter contains an +-illegal value. Either the value is negative or greater than or equal to ++invalid value. Either the value is negative or greater than or equal to + 1000 million. + @end table + diff --git a/glibc-RHEL-108974-24.patch b/glibc-RHEL-108974-24.patch new file mode 100644 index 0000000..834d182 --- /dev/null +++ b/glibc-RHEL-108974-24.patch @@ -0,0 +1,121 @@ +commit 1a3d8f2201d4d613401ce5be9a283f4f28c43093 +Author: Arjun Shankar +Date: Fri May 30 02:09:50 2025 +0200 + + manual: Document clock_nanosleep + + Make minor clarifications in the documentation for 'nanosleep' and add + an entry for 'clock_nanosleep' as a generalized variant of the former + function that allows clock selection. + Reviewed-by: Maciej W. Rozycki + +diff --git a/manual/time.texi b/manual/time.texi +index e754d3a7e7f5c52d..60e4d4b6fab1482b 100644 +--- a/manual/time.texi ++++ b/manual/time.texi +@@ -3179,12 +3179,12 @@ On @gnusystems{}, it is safe to use @code{sleep} and @code{SIGALRM} in + the same program, because @code{sleep} does not work by means of + @code{SIGALRM}. + +-@deftypefun int nanosleep (const struct timespec *@var{requested_time}, struct timespec *@var{remaining}) ++@deftypefun int nanosleep (const struct timespec *@var{requested_time}, struct timespec *@var{remaining_time}) + @standards{POSIX.1, time.h} + @safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}} + @c On Linux, it's a syscall. On Mach, it calls gettimeofday and uses + @c ports. +-If resolution to seconds is not enough the @code{nanosleep} function can ++If resolution to seconds is not enough, the @code{nanosleep} function can + be used. As the name suggests the sleep interval can be specified in + nanoseconds. The actual elapsed time of the sleep interval might be + longer since the system rounds the elapsed time you request up to the +@@ -3193,21 +3193,22 @@ next integer multiple of the actual resolution the system can deliver. + @code{*@var{requested_time}} is the elapsed time of the interval you + want to sleep. + +-The function returns as @code{*@var{remaining}} the elapsed time left +-in the interval for which you requested to sleep. If the interval +-completed without getting interrupted by a signal, this is zero. ++If @var{remaining_time} is not the null pointer, the function returns as ++@code{*@var{remaining_time}} the elapsed time left in the interval for which ++you requested to sleep. If the interval completed without getting ++interrupted by a signal, this is zero. + + @code{struct timespec} is described in @ref{Time Types}. + +-If the function returns because the interval is over the return value is +-zero. If the function returns @math{-1} the global variable @code{errno} ++If the function returns because the interval is over, the return value is ++zero. If the function returns @math{-1}, the global variable @code{errno} + is set to the following values: + + @table @code + @item EINTR + The call was interrupted because a signal was delivered to the thread. +-If the @var{remaining} parameter is not the null pointer the structure +-pointed to by @var{remaining} is updated to contain the remaining ++If the @var{remaining_time} parameter is not the null pointer, the structure ++pointed to by @var{remaining_time} is updated to contain the remaining + elapsed time. + + @item EINVAL +@@ -3219,10 +3220,58 @@ invalid value. Either the value is negative or greater than or equal to + This function is a cancellation point in multi-threaded programs. This + is a problem if the thread allocates some resources (like memory, file + descriptors, semaphores or whatever) at the time @code{nanosleep} is +-called. If the thread gets canceled these resources stay allocated +-until the program ends. To avoid this calls to @code{nanosleep} should ++called. If the thread gets canceled, these resources stay allocated ++until the program ends. To avoid this, calls to @code{nanosleep} should + be protected using cancellation handlers. + @c ref pthread_cleanup_push / pthread_cleanup_pop + + The @code{nanosleep} function is declared in @file{time.h}. + @end deftypefun ++ ++@deftypefun int clock_nanosleep (clockid_t @var{clock}, int @var{flags}, const struct timespec *@var{requested_time}, struct timespec *@var{remaining_time}) ++@standards{POSIX.1-2001, time.h} ++@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}} ++This function is a generalized variant of @code{nanosleep}, providing the ++caller with a way to specify the clock to be used to measure elapsed time ++and express the sleep interval in absolute or relative terms. The call: ++ ++@smallexample ++nanosleep (@var{requested_time}, @var{remaining_time}) ++@end smallexample ++ ++is equivalent to: ++ ++@smallexample ++clock_nanosleep (CLOCK_REALTIME, 0, @var{requested_time}, @var{remaining_time}) ++@end smallexample ++ ++The @var{clock} argument specifies the clock to use. ++@xref{Getting the Time}, for the @code{clockid_t} type and possible values ++of @var{clock}. Not all clocks listed are supported for use with ++@code{clock_nanosleep}. For details, see the manual page ++@manpageurl{clock_nanosleep,2}. ++ ++The @var{flags} argument is either @code{0} or @code{TIMER_ABSTIME}. If ++@var{flags} is @code{0}, then @code{clock_nanosleep} interprets ++@var{requested_time} as an interval relative to the current time specified ++by @var{clock}. If it is @code{TIMER_ABSTIME} instead, @var{requested_time} ++specifies an absolute time measured by @var{clock}; if at the time of the ++call the value requested is less than or equal to the clock specified, then ++the function returns right away. When @var{flags} is @code{TIMER_ABSTIME}, ++@var{remaining_time} is not updated. ++ ++The return values and error conditions for @code{clock_nanosleep} are the ++same as for @code{nanosleep}, with the following conditions additionally ++defined: ++ ++@table @code ++@item EINVAL ++The @var{clock} argument is not a valid clock. ++ ++@item EOPNOTSUPP ++The @var{clock} argument is not supported by the kernel for ++@code{clock_nanosleep}. ++@end table ++ ++The @code{clock_nanosleep} function is declared in @file{time.h}. ++@end deftypefun diff --git a/glibc-RHEL-108974-25.patch b/glibc-RHEL-108974-25.patch new file mode 100644 index 0000000..54b66c9 --- /dev/null +++ b/glibc-RHEL-108974-25.patch @@ -0,0 +1,74 @@ +commit 591283a68965fe61a7186c9c81f7812e71b282b4 +Author: Arjun Shankar +Date: Mon Jun 2 10:41:02 2025 +0200 + + manual: Correct return value description of 'clock_nanosleep' + + Commit 1a3d8f2201d4d613401ce5be9a283f4f28c43093 incorrectly described + 'clock_nanosleep' as having the same return values as 'nanosleep'. Fix + this, clarifying that 'clock_nanosleep' returns a positive error number + upon failure instead of setting 'errno'. Also clarify that 'nanosleep' + returns '-1' upon error. + + Fixes: 1a3d8f2201d4d613401ce5be9a283f4f28c43093 + Reported-by: Mark Harris + Reviewed-by: Mark Harris + +diff --git a/manual/time.texi b/manual/time.texi +index 60e4d4b6fab1482b..a7c276e1e4f074a6 100644 +--- a/manual/time.texi ++++ b/manual/time.texi +@@ -3200,9 +3200,9 @@ interrupted by a signal, this is zero. + + @code{struct timespec} is described in @ref{Time Types}. + +-If the function returns because the interval is over, the return value is +-zero. If the function returns @math{-1}, the global variable @code{errno} +-is set to the following values: ++If the function returns because the interval is over, it returns zero. ++Otherwise it returns @math{-1} and sets the global variable @code{errno} to ++one of the following values: + + @table @code + @item EINTR +@@ -3231,19 +3231,14 @@ The @code{nanosleep} function is declared in @file{time.h}. + @deftypefun int clock_nanosleep (clockid_t @var{clock}, int @var{flags}, const struct timespec *@var{requested_time}, struct timespec *@var{remaining_time}) + @standards{POSIX.1-2001, time.h} + @safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}} +-This function is a generalized variant of @code{nanosleep}, providing the +-caller with a way to specify the clock to be used to measure elapsed time +-and express the sleep interval in absolute or relative terms. The call: +- +-@smallexample +-nanosleep (@var{requested_time}, @var{remaining_time}) +-@end smallexample +- +-is equivalent to: +- +-@smallexample +-clock_nanosleep (CLOCK_REALTIME, 0, @var{requested_time}, @var{remaining_time}) +-@end smallexample ++This function is similar to @code{nanosleep} while additionally providing ++the caller with a way to specify the clock to be used to measure elapsed ++time and express the sleep interval in absolute or relative terms. It ++returns zero when returning because the interval is over, and a positive ++error number corresponding to the error encountered otherwise. This is ++different from @code{nanosleep}, which returns @math{-1} upon failure and ++sets the global variable @code{errno} according to the error encountered ++instead. + + The @var{clock} argument specifies the clock to use. + @xref{Getting the Time}, for the @code{clockid_t} type and possible values +@@ -3260,9 +3255,9 @@ call the value requested is less than or equal to the clock specified, then + the function returns right away. When @var{flags} is @code{TIMER_ABSTIME}, + @var{remaining_time} is not updated. + +-The return values and error conditions for @code{clock_nanosleep} are the +-same as for @code{nanosleep}, with the following conditions additionally +-defined: ++The @code{clock_nanosleep} function returns error codes as positive return ++values. The error conditions for @code{clock_nanosleep} are the same as for ++@code{nanosleep}, with the following conditions additionally defined: + + @table @code + @item EINVAL diff --git a/glibc-RHEL-108974-26.patch b/glibc-RHEL-108974-26.patch new file mode 100644 index 0000000..e2d1a64 --- /dev/null +++ b/glibc-RHEL-108974-26.patch @@ -0,0 +1,47 @@ +commit 46acdf46cc1948187d6540cdf4abee5053cd8bcc +Author: Maciej W. Rozycki +Date: Wed Jun 4 16:27:20 2025 +0100 + + manual: Document error codes missing for 'if_indextoname' + + Add documentation for ENXIO error code returned and refer to 'socket' + for further possible codes from the underlying function call. + + While changing the text clarify the description by mentioning 'ifname' + and replace @code tags with @var ones where referring to a function + parameter. + + Reviewed-by: Florian Weimer + +diff --git a/manual/socket.texi b/manual/socket.texi +index 2f0e7509e92974d1..a6fb6b1b7e2b0473 100644 +--- a/manual/socket.texi ++++ b/manual/socket.texi +@@ -505,11 +505,22 @@ name. If no interface exists with the name given, it returns 0. + @safety{@prelim{}@mtsafe{}@asunsafe{@asulock{}}@acunsafe{@aculock{} @acsfd{}}} + @c It opens a socket with opensock to use ioctl on the fd to get the + @c name from the index. +-This function maps an interface index to its corresponding name. The +-returned name is placed in the buffer pointed to by @code{ifname}, which +-must be at least @code{IFNAMSIZ} bytes in length. If the index was +-invalid, the function's return value is a null pointer, otherwise it is +-@code{ifname}. ++This function maps an interface index @var{ifindex} to its corresponding ++name. The returned name is placed in the buffer pointed to by @var{ifname}, ++which must be at least @code{IFNAMSIZ} bytes in length. ++ ++The return value is @var{ifname} on success. On failure, the function's ++return value is a null pointer and @code{errno} is set accordingly. The ++following @code{errno} values are specific to this function: ++ ++@table @code ++@item ENXIO ++There is no interface at the index requested. ++@end table ++ ++Additionally, since @code{if_indextoname} invokes @code{socket} ++internally, @code{errno} may also be set to a value listed for the ++@code{socket} function (@pxref{Creating a Socket}). + @end deftypefun + + @deftp {Data Type} {struct if_nameindex} diff --git a/glibc-RHEL-108974-27.patch b/glibc-RHEL-108974-27.patch new file mode 100644 index 0000000..665ff17 --- /dev/null +++ b/glibc-RHEL-108974-27.patch @@ -0,0 +1,39 @@ +commit 5a9020eeb27eee88e7839ff5e9cea94892ec90ff +Author: Maciej W. Rozycki +Date: Wed Jun 4 16:27:20 2025 +0100 + + manual: Document error codes missing for 'if_nametoindex' + + Add documentation for ENODEV error code returned and refer to 'socket' + for further possible codes from the underlying function call. + + While changing the text clarify the description by mentioning 'ifname'. + + Reviewed-by: Florian Weimer + +diff --git a/manual/socket.texi b/manual/socket.texi +index a6fb6b1b7e2b0473..e8285b9200bbfc6d 100644 +--- a/manual/socket.texi ++++ b/manual/socket.texi +@@ -497,7 +497,20 @@ interface name, including its terminating zero byte. + @c takes a lock, which makes all callers AS- and AC-Unsafe. + @c opensock @asulock @aculock @acsfd + This function yields the interface index corresponding to a particular +-name. If no interface exists with the name given, it returns 0. ++name specified with @var{ifname}. ++ ++The return value is the interface index on success. On failure, the ++function's return value is zero and @code{errno} is set accordingly. ++The following @code{errno} values are specific to this function: ++ ++@table @code ++@item ENODEV ++There is no interface by the name requested. ++@end table ++ ++Additionally, since @code{if_nametoindex} invokes @code{socket} ++internally, @code{errno} may also be set to a value listed for the ++@code{socket} function (@pxref{Creating a Socket}). + @end deftypefun + + @deftypefun {char *} if_indextoname (unsigned int @var{ifindex}, char *@var{ifname}) diff --git a/glibc-RHEL-108974-28.patch b/glibc-RHEL-108974-28.patch new file mode 100644 index 0000000..cf8f209 --- /dev/null +++ b/glibc-RHEL-108974-28.patch @@ -0,0 +1,33 @@ +commit 140b20e9716b51659a5223b182dcf07ac62b3f77 +Author: Maciej W. Rozycki +Date: Wed Jun 4 16:27:20 2025 +0100 + + manual: Document error codes missing for 'inet_pton' + + Add documentation for EAFNOSUPPORT error code returned, and the possible + return values on non-success. + + Reviewed-by: Florian Weimer + +diff --git a/manual/socket.texi b/manual/socket.texi +index e8285b9200bbfc6d..d804c7a48b91b403 100644 +--- a/manual/socket.texi ++++ b/manual/socket.texi +@@ -1216,6 +1216,17 @@ either @code{AF_INET} or @code{AF_INET6}, as appropriate for the type of + address being converted. @var{cp} is a pointer to the input string, and + @var{buf} is a pointer to a buffer for the result. It is the caller's + responsibility to make sure the buffer is large enough. ++ ++The return value is @code{1} on success and @code{0} if @var{cp} does not ++point to a valid address string for the address family @var{af} requested. ++On failure, the function's return value is @code{-1} and @code{errno} is ++set accordingly. The following @code{errno} values are specific to this ++function: ++ ++@table @code ++@item EAFNOSUPPORT ++The address family requested is neither @code{AF_INET} nor @code{AF_INET6}. ++@end table + @end deftypefun + + @deftypefun {const char *} inet_ntop (int @var{af}, const void *@var{cp}, char *@var{buf}, socklen_t @var{len}) diff --git a/glibc-RHEL-108974-29.patch b/glibc-RHEL-108974-29.patch new file mode 100644 index 0000000..2f53691 --- /dev/null +++ b/glibc-RHEL-108974-29.patch @@ -0,0 +1,67 @@ +commit 3b21166c4d34ee032093bcf599ffac42ad8a4371 +Author: Arjun Shankar +Date: Wed Jun 4 13:08:53 2025 +0200 + + manual: Expand Descriptor-Relative Access section + + Improve the clarity of the paragraphs describing common flags and add a + list of common error conditions for descriptor-relative functions. + Reviewed-by: Florian Weimer + +diff --git a/manual/filesys.texi b/manual/filesys.texi +index 450d175e614d8834..28d38f23fc58c51f 100644 +--- a/manual/filesys.texi ++++ b/manual/filesys.texi +@@ -310,12 +310,17 @@ This is a GNU extension. + The flags argument in @code{@dots{}at} functions can be a combination of + the following flags, defined in @file{fcntl.h}. Not all such functions + support all flags, and some (such as @code{openat}) do not accept a +-flags argument at all. +- +-In the flag descriptions below, the @dfn{effective final path component} +-refers to the final component (basename) of the full path constructed +-from the descriptor and file name arguments, using file name lookup, as +-described above. ++flags argument at all. Although the flags specific to each function have ++distinct values from each other, some flags (relevant to different ++functions) might share the same value and therefore are not guaranteed to ++have unique values. ++ ++A non-exhaustive list of common flags and their descriptions follows. Flags ++specific to a function are described alongside the function itself. In ++these flag descriptions, the @dfn{effective final path component} refers to ++the final component (basename) of the full path constructed from the ++descriptor and file name arguments, using file name lookup, as described ++above. + + @vtable @code + @item AT_EMPTY_PATH +@@ -353,6 +358,28 @@ a non-final component of the file name are still followed. + argument to the @code{getauxval} function (with @code{AT_@dots{}} + constants defined in @file{elf.h}). @xref{Auxiliary Vector}. + ++@cindex common errors in descriptor-relative functions ++@cindex common errors in @code{@dots{}at} functions ++ ++The @code{@dots{}at} functions have some common error conditions due to the ++nature of descriptor-relative access. A list of common errors and their ++descriptions follows. Errors specific to a function are described alongside ++the function itself. ++ ++@table @code ++@item EBADF ++The file name argument is a relative path but the descriptor argument ++is neither @code{AT_FDCWD} nor a valid file descriptor. ++ ++@item EINVAL ++If the function accepts a @var{flags} argument, the flag combination passed ++is not valid for the function. ++ ++@item ENOTDIR ++The file name argument is a relative file name but the descriptor ++argument is associated with a file that is not a directory. ++@end table ++ + @node Accessing Directories + @section Accessing Directories + @cindex accessing directories diff --git a/glibc-RHEL-108974-3.patch b/glibc-RHEL-108974-3.patch new file mode 100644 index 0000000..aea3b56 --- /dev/null +++ b/glibc-RHEL-108974-3.patch @@ -0,0 +1,206 @@ +commit dce754b1553b86fc6352636f1fa490a85b7cf0ff +Author: DJ Delorie +Date: Fri May 10 14:52:09 2024 -0400 + + Update mmap() flags and errors lists + + Extend the list of MAP_* macros to include all macros available + to the average program (gcc -E -dM | grep MAP_*) + + Extend the list of errno codes. + + Reviewed-by: Florian Weimer + +diff --git a/manual/llio.texi b/manual/llio.texi +index a8ed72c5db6ecba9..be55dca1b7c9ebcd 100644 +--- a/manual/llio.texi ++++ b/manual/llio.texi +@@ -1574,10 +1574,15 @@ permitted. They include @code{PROT_READ}, @code{PROT_WRITE}, and + of address space for future use. The @code{mprotect} function can be + used to change the protection flags. @xref{Memory Protection}. + +-@var{flags} contains flags that control the nature of the map. +-One of @code{MAP_SHARED} or @code{MAP_PRIVATE} must be specified. ++The @var{flags} parameter contains flags that control the nature of ++the map. One of @code{MAP_SHARED}, @code{MAP_SHARED_VALIDATE}, or ++@code{MAP_PRIVATE} must be specified. Additional flags may be bitwise ++OR'd to further define the mapping. + +-They include: ++Note that, aside from @code{MAP_PRIVATE} and @code{MAP_SHARED}, not ++all flags are supported on all versions of all operating systems. ++Consult the kernel-specific documentation for details. The flags ++include: + + @vtable @code + @item MAP_PRIVATE +@@ -1599,9 +1604,19 @@ Note that actual writing may take place at any time. You need to use + @code{msync}, described below, if it is important that other processes + using conventional I/O get a consistent view of the file. + ++@item MAP_SHARED_VALIDATE ++Similar to @code{MAP_SHARED} except that additional flags will be ++validated by the kernel, and the call will fail if an unrecognized ++flag is provided. With @code{MAP_SHARED} using a flag on a kernel ++that doesn't support it causes the flag to be ignored. ++@code{MAP_SHARED_VALIDATE} should be used when the behavior of all ++flags is required. ++ + @item MAP_FIXED + This forces the system to use the exact mapping address specified in +-@var{address} and fail if it can't. ++@var{address} and fail if it can't. Note that if the new mapping ++would overlap an existing mapping, the overlapping portion of the ++existing map is unmapped. + + @c One of these is official - the other is obviously an obsolete synonym + @c Which is which? +@@ -1642,10 +1657,73 @@ The @code{MAP_HUGETLB} flag is specific to Linux. + @c There is a mechanism to select different hugepage sizes; see + @c include/uapi/asm-generic/hugetlb_encode.h in the kernel sources. + +-@c Linux has some other MAP_ options, which I have not discussed here. +-@c MAP_DENYWRITE, MAP_EXECUTABLE and MAP_GROWSDOWN don't seem applicable to +-@c user programs (and I don't understand the last two). MAP_LOCKED does +-@c not appear to be implemented. ++@item MAP_32BIT ++Require addresses that can be accessed with a signed 32 bit pointer, ++i.e., within the first 2 GiB. Ignored if MAP_FIXED is specified. ++ ++@item MAP_DENYWRITE ++@itemx MAP_EXECUTABLE ++@itemx MAP_FILE ++ ++Provided for compatibility. Ignored by the Linux kernel. ++ ++@item MAP_FIXED_NOREPLACE ++Similar to @code{MAP_FIXED} except the call will fail with ++@code{EEXIST} if the new mapping would overwrite an existing mapping. ++To test for support for this flag, specify MAP_FIXED_NOREPLACE without ++MAP_FIXED, and (if the call was successful) check the actual address ++returned. If it does not match the address passed, then this flag is ++not supported. ++ ++@item MAP_GROWSDOWN ++This flag is used to make stacks, and is typically only needed inside ++the program loader to set up the main stack for the running process. ++The mapping is created according to the other flags, except an ++additional page just prior to the mapping is marked as a ``guard ++page''. If a write is attempted inside this guard page, that page is ++mapped, the mapping is extended, and a new guard page is created. ++Thus, the mapping continues to grow towards lower addresses until it ++encounters some other mapping. ++ ++Note that accessing memory beyond the guard page will not trigger this ++feature. In gcc, use @code{-fstack-clash-protection} to ensure the ++guard page is always touched. ++ ++@item MAP_LOCKED ++A hint that requests that mapped pages are locked in memory (i.e. not ++paged out). Note that this is a request and not a requirement; use ++@code{mlock} if locking is required. ++ ++@item MAP_POPULATE ++@itemx MAP_NONBLOCK ++@code{MAP_POPULATE} is a hint that requests that the kernel read-ahead ++a file-backed mapping, causing pages to be mapped before they're ++needed. @code{MAP_NONBLOCK} is a hint that requests that the kernel ++@emph{not} attempt such except for pages are already in memory. Note ++that neither of these hints affects future paging activity, use ++@code{mlock} if such needs to be controlled. ++ ++@item MAP_NORESERVE ++Asks the kernel to not reserve physical backing (i.e. space in a swap ++device) for a mapping. This would be useful for, for example, a very ++large but sparsely used mapping which need not be limited in total ++length by available RAM, but with very few mapped pages. Note that ++writes to such a mapping may cause a @code{SIGSEGV} if the system is ++unable to map a page due to lack of resources. ++ ++On Linux, this flag's behavior may be overwridden by ++@file{/proc/sys/vm/overcommit_memory} as documented in the proc(5) man ++page. ++ ++@item MAP_STACK ++Ensures that the resulting mapping is suitable for use as a program ++stack. For example, the use of huge pages might be precluded. ++ ++@item MAP_SYNC ++This is a special flag for DAX devices, which tells the kernel to ++write dirty metadata out whenever dirty data is written out. Unlike ++most other flags, this one will fail unless @code{MAP_SHARED_VALIDATE} ++is also given. + + @item MAP_DROPPABLE + Request the page to be never written out to swap, it will be zeroed +@@ -1665,6 +1743,24 @@ Possible errors include: + + @table @code + ++@item EACCES ++ ++@var{filedes} was not open for the type of access specified in @var{protect}. ++ ++@item EAGAIN ++ ++The system has temporarily run out of resources. ++ ++@item EBADF ++ ++The @var{fd} passed is invalid, and a valid file descriptor is ++required (i.e. MAP_ANONYMOUS was not specified). ++ ++@item EEXIST ++ ++@code{MAP_FIXED_NOREPLACE} was specified and an existing mapping was ++found overlapping the requested address range. ++ + @item EINVAL + + Either @var{address} was unusable (because it is not a multiple of the +@@ -1673,23 +1769,37 @@ applicable page size), or inconsistent @var{flags} were given. + If @code{MAP_HUGETLB} was specified, the file or system does not support + large page sizes. + +-@item EACCES ++@item ENODEV + +-@var{filedes} was not open for the type of access specified in @var{protect}. ++This file is of a type that doesn't support mapping, the process has ++exceeded its data space limit, or the map request would exceed the ++process's virtual address space. + + @item ENOMEM + +-Either there is not enough memory for the operation, or the process is +-out of address space. +- +-@item ENODEV +- +-This file is of a type that doesn't support mapping. ++There is not enough memory for the operation, the process is out of ++address space, or there are too many mappings. On Linux, the maximum ++number of mappings can be controlled via ++@file{/proc/sys/vm/max_map_count} or, if your OS supports it, via ++the @code{vm.max_map_count} @code{sysctl} setting. + + @item ENOEXEC + + The file is on a filesystem that doesn't support mapping. + ++@item EPERM ++ ++@code{PROT_EXEC} was requested but the file is on a filesystem that ++was mounted with execution denied, a file seal prevented the mapping, ++or the caller set MAP_HUDETLB but does not have the required ++priviledges. ++ ++@item EOVERFLOW ++ ++Either the offset into the file plus the length of the mapping causes ++internal page counts to overflow, or the offset requested exceeds the ++length of the file. ++ + @c On Linux, EAGAIN will appear if the file has a conflicting mandatory lock. + @c However mandatory locks are not discussed in this manual. + @c diff --git a/glibc-RHEL-108974-30.patch b/glibc-RHEL-108974-30.patch new file mode 100644 index 0000000..1fc1bb8 --- /dev/null +++ b/glibc-RHEL-108974-30.patch @@ -0,0 +1,50 @@ +commit 941157dbcdf1c410960bde991206bfb6d9bb292f +Author: Arjun Shankar +Date: Wed Jun 4 13:08:54 2025 +0200 + + manual: Document faccessat + + Reviewed-by: Florian Weimer + +diff --git a/manual/filesys.texi b/manual/filesys.texi +index 28d38f23fc58c51f..17c15b54037e719d 100644 +--- a/manual/filesys.texi ++++ b/manual/filesys.texi +@@ -3069,6 +3069,29 @@ Flag meaning test for execute/search permission. + Flag meaning test for existence of the file. + @end deftypevr + ++@deftypefun int faccessat (int @var{filedes}, const char *@var{filename}, int @var{how}, int @var{flags}) ++@standards{POSIX.1-2008, unistd.h} ++@comment Unaudited and therefore marked AC-Unsafe and AS-Unsafe by default ++@safety{@mtsafe{}@asunsafe{@asucorrupt{}}@acunsafe{@acucorrupt{}}} ++This function is a descriptor-relative version of the @code{access} ++function above. @xref{Descriptor-Relative Access}. The @var{flags} ++argument can contain a combination of the flags @code{AT_EACCESS} described ++below, @code{AT_EMPTY_PATH}, and @code{AT_SYMLINK_NOFOLLOW}. ++ ++@vtable @code ++@item AT_EACCESS ++This flag when passed to the @code{faccessat} function causes it to perform ++access checks using effective user and group IDs instead of real IDs, which ++is the default and matches the @code{access} function. ++@end vtable ++ ++Compared to @code{access}, some additional error conditions can occur. ++@xref{Descriptor-Relative Access}. ++ ++This function may not work correctly on older kernels missing the ++@code{faccessat2} system call. ++@end deftypefun ++ + @node File Times + @subsection File Times + +@@ -3849,7 +3872,6 @@ creation always works like @code{open} with @code{O_EXCL}. + The @code{mkdtemp} function comes from OpenBSD. + + @c FIXME these are undocumented: +-@c faccessat + @c fchmodat + @c fchownat + @c futimesat diff --git a/glibc-RHEL-108974-31.patch b/glibc-RHEL-108974-31.patch new file mode 100644 index 0000000..cd96eb5 --- /dev/null +++ b/glibc-RHEL-108974-31.patch @@ -0,0 +1,38 @@ +commit 49766eb1a5b93d093bd0fada55ca7a42dfdb10d6 +Author: Arjun Shankar +Date: Wed Jun 4 13:08:55 2025 +0200 + + manual: Document mkdirat + + Reviewed-by: Florian Weimer + +diff --git a/manual/filesys.texi b/manual/filesys.texi +index 17c15b54037e719d..d8f362f3beda9b28 100644 +--- a/manual/filesys.texi ++++ b/manual/filesys.texi +@@ -1964,6 +1964,17 @@ To use this function, your program should include the header file + @pindex sys/stat.h + @end deftypefun + ++@deftypefun int mkdirat (int @var{filedes}, const char *@var{filename}, mode_t @var{mode}) ++@standards{POSIX.1-2008, sys/stat.h} ++@comment Unaudited and therefore marked AC-Unsafe and AS-Unsafe by default ++@safety{@mtsafe{}@asunsafe{@asucorrupt{}}@acunsafe{@acucorrupt{}}} ++This function is a descriptor-relative version of the @code{mkdir} ++function above. @xref{Descriptor-Relative Access}. ++ ++Compared to @code{mkdir}, some additional error conditions can occur. ++@xref{Descriptor-Relative Access}. ++@end deftypefun ++ + @node File Attributes + @section File Attributes + +@@ -3877,7 +3888,6 @@ The @code{mkdtemp} function comes from OpenBSD. + @c futimesat + @c fstatat (there's a commented-out safety assessment for this one) + @c statx +-@c mkdirat + @c mkfifoat + @c name_to_handle_at + @c openat diff --git a/glibc-RHEL-108974-32.patch b/glibc-RHEL-108974-32.patch new file mode 100644 index 0000000..6fc1c7b --- /dev/null +++ b/glibc-RHEL-108974-32.patch @@ -0,0 +1,38 @@ +commit 60f86c9cd062882cbeb04b2944c3dfb7457ee5c5 +Author: Arjun Shankar +Date: Wed Jun 4 13:08:56 2025 +0200 + + manual: Document renameat + + Reviewed-by: Florian Weimer + +diff --git a/manual/filesys.texi b/manual/filesys.texi +index d8f362f3beda9b28..8a173c562fa71f83 100644 +--- a/manual/filesys.texi ++++ b/manual/filesys.texi +@@ -1910,6 +1910,17 @@ file systems. + @end table + @end deftypefun + ++@deftypefun int renameat (int @var{oldfiledes}, const char *@var{oldname}, int @var{newfiledes}, const char *@var{newname}) ++@standards{POSIX.1-2008, stdio.h} ++@comment Unaudited and therefore marked AC-Unsafe and AS-Unsafe by default ++@safety{@mtsafe{}@asunsafe{@asucorrupt{}}@acunsafe{@acucorrupt{}}} ++This function is a descriptor-relative version of the @code{rename} ++function above. @xref{Descriptor-Relative Access}. ++ ++Compared to @code{rename}, some additional error conditions can occur. ++@xref{Descriptor-Relative Access}. ++@end deftypefun ++ + @node Creating Directories + @section Creating Directories + @cindex creating a directory +@@ -3893,7 +3904,6 @@ The @code{mkdtemp} function comes from OpenBSD. + @c openat + @c open_by_handle_at + @c readlinkat +-@c renameat + @c renameat2 + @c scandirat + @c symlinkat diff --git a/glibc-RHEL-108974-33.patch b/glibc-RHEL-108974-33.patch new file mode 100644 index 0000000..cf770e4 --- /dev/null +++ b/glibc-RHEL-108974-33.patch @@ -0,0 +1,51 @@ +commit 75b725717ff23d0ae38fc7f4a0361cb1bdffbe2e +Author: Arjun Shankar +Date: Wed Jun 4 13:08:57 2025 +0200 + + manual: Document unlinkat + + Reviewed-by: Florian Weimer + +diff --git a/manual/filesys.texi b/manual/filesys.texi +index 8a173c562fa71f83..396d68c32925c501 100644 +--- a/manual/filesys.texi ++++ b/manual/filesys.texi +@@ -1779,6 +1779,31 @@ file system and can't be modified. + @end table + @end deftypefun + ++@deftypefun int unlinkat (int @var{filedes}, const char *@var{filename}, int @var{flags}) ++@standards{POSIX.1-2008, unistd.h} ++@comment Unaudited and therefore marked AC-Unsafe and AS-Unsafe by default ++@safety{@mtsafe{}@asunsafe{@asucorrupt{}}@acunsafe{@acucorrupt{}}} ++This function is a descriptor-relative version of the @code{unlink} ++function above. @xref{Descriptor-Relative Access}. The @var{flags} ++argument may either be @code{0} or contain the flag @code{AT_REMOVEDIR}: ++ ++@table @code ++@item AT_REMOVEDIR ++This flag causes @code{unlinkat} to perform an @code{rmdir} operation on ++@code{filename} instead of performing the equivalent of @code{unlink}. ++@end table ++ ++Compared to @code{unlink}, some additional error conditions can occur due to ++descriptor-relative access. @xref{Descriptor-Relative Access}. In ++addition to this, the following other errors can also occur: ++ ++@table @code ++@item EISDIR ++The effective final path derived from @var{filename} and @var{filedes} is a ++directory but @code{AT_REMOVEDIR} was not passed in @code{flags}. ++@end table ++@end deftypefun ++ + @deftypefun int rmdir (const char *@var{filename}) + @standards{POSIX.1, unistd.h} + @safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}} +@@ -3907,6 +3932,5 @@ The @code{mkdtemp} function comes from OpenBSD. + @c renameat2 + @c scandirat + @c symlinkat +-@c unlinkat + @c utimensat + @c mknodat diff --git a/glibc-RHEL-108974-34.patch b/glibc-RHEL-108974-34.patch new file mode 100644 index 0000000..fa83a4c --- /dev/null +++ b/glibc-RHEL-108974-34.patch @@ -0,0 +1,97 @@ +commit 25f1d945766a3a757d9b54eb48fe7c3c48c0f791 +Author: Arjun Shankar +Date: Wed Jun 4 13:08:58 2025 +0200 + + manual: Document futimens and utimensat + + Document futimens and utimensat. Also document the EINVAL error + condition for futimes. It is inherited by futimens and utimensat as + well. + Reviewed-by: Florian Weimer + +diff --git a/manual/filesys.texi b/manual/filesys.texi +index 396d68c32925c501..f21f21804251e480 100644 +--- a/manual/filesys.texi ++++ b/manual/filesys.texi +@@ -3307,6 +3307,10 @@ permission for the file, or be a privileged user. + @item EBADF + The @var{filedes} argument is not a valid file descriptor. + ++@item EINVAL ++At least one of the fields in the @code{tvp} array passed has an invalid ++value. ++ + @item EPERM + If the @var{times} argument is not a null pointer, you must either be + the owner of the file or be a privileged user. +@@ -3316,6 +3320,64 @@ The file lives on a read-only file system. + @end table + @end deftypefun + ++@deftypefun int futimens (int @var{filedes}, const struct timespec @var{tsp}@t{[2]}) ++@standards{POSIX.1-2008, sys/stat.h} ++@comment Unaudited and therefore marked AC-Unsafe and AS-Unsafe by default ++@safety{@mtsafe{}@asunsafe{@asucorrupt{}}@acunsafe{@acucorrupt{}}} ++This function is like @code{futimes}, except that it sets the file access ++and modification timestamps with nanosecond precision. The argument ++@code{tsp} is used similarly to @code{futimes}' @code{tvp}, but has a ++@code{const struct timespec} type that can express calendar time with ++nanosecond precision. @xref{Time Types}. ++@end deftypefun ++ ++@deftypefun int utimensat (int @var{filedes}, const char *@var{filename}, const struct timespec @var{tsp}@t{[2]}, int @var{flags}) ++@standards{POSIX.1-2008, sys/stat.h} ++@comment Unaudited and therefore marked AC-Unsafe and AS-Unsafe by default ++@safety{@mtsafe{}@asunsafe{@asucorrupt{}}@acunsafe{@acucorrupt{}}} ++This function is a descriptor-relative version of the @code{futimens} ++function above. @xref{Descriptor-Relative Access}. The @var{flags} ++argument can contain a combination of the flags @code{AT_EMPTY_PATH}, and ++@code{AT_SYMLINK_NOFOLLOW}. The call: ++ ++@smallexample ++futimens (@var{filedes}, @var{tsp}) ++@end smallexample ++ ++is equivalent to: ++ ++@smallexample ++utimensat (@var{filedes}, @code{NULL}, @var{tsp}, 0) ++@end smallexample ++ ++Compared to @code{futimens}, some additional error conditions can occur due ++to descriptor-relative access. @xref{Descriptor-Relative Access}. In ++addition to this, the following other errors can also occur: ++ ++@table @code ++@item EINVAL ++The @var{filename} argument is NULL, @var{filedes} is not @code{AT_FDCWD}, ++and @var{flags} is not @code{0}. ++ ++@item ELOOP ++There are too many levels of indirection. This can be the result of ++circular symbolic links to directories. ++ ++@item ENAMETOOLONG ++The resulting path is too long. This error only occurs on systems which ++have a limit on the file name length. ++ ++@item ENOENT ++The @var{filename} argument is an empty string and @var{flags} does not ++contain @code{AT_EMPTY_PATH}, or @var{filename} does not refer to an ++existing file. ++ ++@item ESRCH ++Search permission was denied for one of the prefix components of the the ++@var{filename} argument. ++@end table ++@end deftypefun ++ + @node File Size + @subsection File Size + +@@ -3932,5 +3994,4 @@ The @code{mkdtemp} function comes from OpenBSD. + @c renameat2 + @c scandirat + @c symlinkat +-@c utimensat + @c mknodat diff --git a/glibc-RHEL-108974-4.patch b/glibc-RHEL-108974-4.patch new file mode 100644 index 0000000..cbb1d58 --- /dev/null +++ b/glibc-RHEL-108974-4.patch @@ -0,0 +1,44 @@ +commit 0e16db440cc73d2cdd94e439c0efa1ec43d92b2a +Author: Florian Weimer +Date: Tue Aug 13 15:52:34 2024 +0200 + + manual: Document generic printf error codes + + Describe EOVERFLOW, ENOMEN, EILSEQ. + + Reviewed-by: Carlos O'Donell + +diff --git a/manual/stdio.texi b/manual/stdio.texi +index 393ed9c665792609..19b4a53299410ca6 100644 +--- a/manual/stdio.texi ++++ b/manual/stdio.texi +@@ -2354,6 +2354,29 @@ the easiest way to make sure you have all the right prototypes is to + just include @file{stdio.h}. + @pindex stdio.h + ++The @code{printf} family shares the error codes listed below. ++Individual functions may report additional @code{errno} values if they ++fail. ++ ++@table @code ++@item EOVERFLOW ++The number of written bytes would have exceeded @code{INT_MAX}, and thus ++could not be represented in the return type @code{int}. ++ ++@item ENOMEM ++The function could not allocate memory during processing. Long argument ++lists and certain floating point conversions may require memory ++allocation, as does initialization of an output stream upon first use. ++ ++@item EILSEQ ++POSIX specifies this error code should be used if a wide character is ++encountered that does not have a matching valid character. @Theglibc{} ++always performs transliteration, using a replacement character if ++necessary, so this error condition cannot occur on output. However, ++@theglibc{} uses @code{EILSEQ} to indicate that an input character ++sequence (wide or multi-byte) could not be converted successfully. ++@end table ++ + @deftypefun int printf (const char *@var{template}, @dots{}) + @standards{ISO, stdio.h} + @safety{@prelim{}@mtsafe{@mtslocale{}}@asunsafe{@asucorrupt{} @ascuheap{}}@acunsafe{@acsmem{} @aculock{} @acucorrupt{}}} diff --git a/glibc-RHEL-108974-5.patch b/glibc-RHEL-108974-5.patch new file mode 100644 index 0000000..1ef6c35 --- /dev/null +++ b/glibc-RHEL-108974-5.patch @@ -0,0 +1,53 @@ +commit 2be0572f3a41d5d5a8bb3b2b04244b7c01ac0f58 +Author: Florian Weimer +Date: Tue Aug 13 15:52:34 2024 +0200 + + manual: Document dprintf and vdprintf + + Reviewed-by: Carlos O'Donell + +diff --git a/manual/stdio.texi b/manual/stdio.texi +index 19b4a53299410ca6..3f837fa99c3c6574 100644 +--- a/manual/stdio.texi ++++ b/manual/stdio.texi +@@ -2523,6 +2523,26 @@ store the result in which case @code{-1} is returned. This was + changed in order to comply with the @w{ISO C99} standard. + @end deftypefun + ++@deftypefun dprintf (int @var{fd}, @var{template}, ...) ++@standards{POSIX, stdio.h} ++@safety{@mtsafe{@mtslocale{}}@asunsafe{@ascuheap{}}@acunsafe{@acsmem{}}} ++This function formats its arguments according to @var{template} and ++writes the result to the file descriptor @var{fd}, using the ++@code{write} function. It returns the number of bytes written, or a ++negative value if there was an error. In the error case, @code{errno} ++is set appropriately. The possible @code{errno} values depend on the ++type of the file descriptor @var{fd}, in addition to the general ++@code{printf} error codes. ++ ++The number of calls to @code{write} is unspecified, and some @code{write} ++calls may have happened even if @code{dprintf} returns with an error. ++ ++@strong{Portability Note:} POSIX does not require that this function is ++async-signal-safe, and @theglibc{} implementation is not. However, some ++other systems offer this function as an async-signal-safe alternative to ++@code{fprintf}. @xref{POSIX Safety Concepts}. ++@end deftypefun ++ + @node Dynamic Output + @subsection Dynamically Allocating Formatted Output + +@@ -2736,6 +2756,13 @@ The @code{obstack_vprintf} function is the equivalent of + as for @code{vprintf}. + @end deftypefun + ++@deftypefun int vdprintf (int @var{fd}, const char *@var{template}, va_list @var{ap}) ++@standards{POSIX, stdio.h} ++@safety{@mtsafe{@mtslocale{}}@asunsafe{@ascuheap{}}@acunsafe{@acsmem{}}} ++The @code{vdprintf} is the equivalent of @code{dprintf}, but processes ++an argument list. ++@end deftypefun ++ + Here's an example showing how you might use @code{vfprintf}. This is a + function that prints error messages to the stream @code{stderr}, along + with a prefix indicating the name of the program diff --git a/glibc-RHEL-108974-6.patch b/glibc-RHEL-108974-6.patch new file mode 100644 index 0000000..0d5ec50 --- /dev/null +++ b/glibc-RHEL-108974-6.patch @@ -0,0 +1,321 @@ +commit 3de73f974fab55430177c811c9c9ba3f251d5747 +Author: Florian Weimer +Date: Wed Aug 7 14:57:41 2024 +0200 + + manual: Add Descriptor-Relative Access section + + Reference this new section from the O_PATH documentation. + + And document the functions openat, openat64, fstatat, fstatat64. + (The safety assessment for fstatat was already obsolete because + current glibc assumes kernel support for the underlying system + call.) + + Reviewed-by: Adhemerval Zanella + +diff --git a/manual/filesys.texi b/manual/filesys.texi +index 47d929744eea75dd..aabb68385b6b9732 100644 +--- a/manual/filesys.texi ++++ b/manual/filesys.texi +@@ -15,6 +15,7 @@ access permissions and modification times. + @menu + * Working Directory:: This is used to resolve relative + file names. ++* Descriptor-Relative Access:: Ways to control file name lookup. + * Accessing Directories:: Finding out what files a directory + contains. + * Working with Directory Trees:: Apply actions to all files or a selectable +@@ -206,6 +207,151 @@ An I/O error occurred. + @end table + @end deftypefun + ++@node Descriptor-Relative Access ++@section Descriptor-Relative Access ++@cindex file name resolution based on descriptors ++@cindex descriptor-based file name resolution ++@cindex @code{@dots{}at} functions ++ ++Many functions that accept file names have @code{@dots{}at} variants ++which accept a file descriptor and a file name argument instead of just ++a file name argument. For example, @code{fstatat} is the ++descriptor-based variant of the @code{fstat} function. Most such ++functions also accept an additional flags argument which changes the ++behavior of the file name lookup based on the passed @code{AT_@dots{}} ++flags. ++ ++There are several reasons to use descriptor-relative access: ++ ++@itemize @bullet ++@item ++The working directory is a process-wide resource, so individual threads ++cannot change it without affecting other threads in the process. ++Explicitly specifying the directory against which relative paths are ++resolved can be a thread-safe alternative to changing the working ++directory. ++ ++@item ++If a program wishes to access a directory tree which is being modified ++concurrently, perhaps even by a different user on the system, the ++program must avoid looking up file names with multiple components, in ++order to detect symbolic links, using the @code{O_NOFOLLOW} flag ++(@pxref{Open-time Flags}) or the @code{AT_SYMLINK_FOLLOW} flag ++(described below). Without directory-relative access, it is necessary ++to use the @code{fchdir} function to change the working directory ++(@pxref{Working Directory}), which is not thread-safe. ++ ++@item ++Listing directory contents using the @code{readdir} or @code{readdir64} ++functions (@pxref{Reading/Closing Directory}) does not provide full file ++name paths. Using @code{@dots{}at} functions, it is possible to use the ++file names directly, without having to construct such full paths. ++ ++@item ++Additional flags available with some of the @code{@dots{}at} functions ++provide access to functionality which is not available otherwise. ++@end itemize ++ ++The file descriptor used by these @code{@dots{}at} functions has the ++following uses: ++ ++@itemize @bullet ++@item ++It can be a file descriptor referring to a directory. Such a descriptor ++can be created explicitly using the @code{open} function and the ++@code{O_RDONLY} file access mode, with or without the @code{O_DIRECTORY} ++flag. @xref{Opening and Closing Files}. Or it can be created ++implicitly by @code{opendir} and retrieved using the @code{dirfd} ++function. @xref{Opening a Directory}. ++ ++If a directory descriptor is used with one of the @code{@dots{}at} ++functions, a relative file name argument is resolved relative to ++directory referred to by the file descriptor, just as if that directory ++were the current working directory. Absolute file name arguments ++(starting with @samp{/}) are resolved against the file system root, and ++the descriptor argument is effectively ignored. ++ ++This means that file name lookup is not constrained to the directory of ++the descriptor. For example, it is possible to access a file ++@file{example} in the descriptor's parent directory using a file name ++argument @code{"../example"}, or in the root directory using ++@code{"/example"}. ++ ++If the file descriptor refers to a directory, the empty string @code{""} ++is not a valid file name argument. It is possible to use @code{"."} to ++refer to the directory itself. Also see @code{AT_EMPTY_PATH} below. ++ ++@item ++@vindex @code{AT_FDCWD} ++The special value @code{AT_FDCWD}. This means that the current working ++directory is used for the lookup if the file name is a relative. For ++@code{@dots{}at} functions with an @code{AT_@dots{}} flags argument, ++this provides a shortcut to use those flags with regular (not ++descriptor-based) file name lookups. ++ ++If @code{AT_FDCWD} is used, the empty string @code{""} is not a valid ++file name argument. ++ ++@item ++An arbitrary file descriptor, along with an empty string @code{""} as ++the file name argument, and the @code{AT_EMPTY_PATH} flag. In this ++case, the operation uses the file descriptor directly, without further ++file name resolution. On Linux, this allows operations on descriptors ++opened with the @code{O_PATH} flag. For regular descriptors (opened ++without @code{O_PATH}), the same functionality is also available through ++the plain descriptor-based functions (for example, @code{fstat} instead ++of @code{fstatat}). ++ ++This is a GNU extension. ++@end itemize ++ ++@cindex file name resolution flags ++@cindex @code{AT_*} file name resolution flags ++The flags argument in @code{@dots{}at} functions can be a combination of ++the following flags, defined in @file{fcntl.h}. Not all such functions ++support all flags, and some (such as @code{openat}) do not accept a ++flags argument at all. ++ ++In the flag descriptions below, the @dfn{effective final path component} ++refers to the final component (basename) of the full path constructed ++from the descriptor and file name arguments, using file name lookup, as ++described above. ++ ++@vtable @code ++@item AT_EMPTY_PATH ++This flag is used with an empty file name @code{""} and a descriptor ++which does not necessarily refer to a directory. It is most useful with ++@code{O_PATH} descriptors, as described above. This flag is a GNU ++extension. ++ ++@item AT_NO_AUTOMOUNT ++If the effective final path component refers to a potential file system ++mount point controlled by an auto-mounting service, the operation does ++not trigger auto-mounting and refers to the unmounted mount point ++instead. @xref{Mount-Unmount-Remount}. If a file system has already ++been mounted at the effective final path component, the operation ++applies to the file or directory in the mounted file system, not the ++underlying file system that was mounted over. This flag is a GNU ++extension. ++ ++@item AT_SYMLINK_FOLLOW ++If the effective final path component is a symbolic link, the ++operation follows the symbolic link and operates on its target. (For ++most functions, this is the default behavior.) ++ ++@item AT_SYMLINK_NOFOLLOW ++If the effective final path component is a symbolic link, the ++operation operates on the symbolic link, without following it. The ++difference in behavior enabled by this flag is similar to the difference ++between the @code{lstat} and @code{stat} functions, or the behavior ++activated by the @code{O_NOFOLLOW} argument to the @code{open} function. ++Even with the @code{AT_SYMLINK_NOFOLLOW} flag present, symbolic links in ++a non-final component of the file name are still followed. ++@end vtable ++ ++@strong{Note:} There is no relationship between these flags and the type ++argument to the @code{getauxval} function (with @code{AT_@dots{}} ++constants defined in @file{elf.h}). @xref{Auxiliary Vector}. + + @node Accessing Directories + @section Accessing Directories +@@ -1250,10 +1396,11 @@ A hardware error occurred while trying to read or write the to filesystem. + + The @code{linkat} function is analogous to the @code{link} function, + except that it identifies its source and target using a combination of a +-file descriptor (referring to a directory) and a pathname. If a +-pathnames is not absolute, it is resolved relative to the corresponding +-file descriptor. The special file descriptor @code{AT_FDCWD} denotes +-the current directory. ++file descriptor (referring to a directory) and a file name. ++@xref{Descriptor-Relative Access}. For @code{linkat}, if a file name is ++not absolute, it is resolved relative to the corresponding file ++descriptor. As usual, the special value @code{AT_FDCWD} denotes the ++current directory. + + The @var{flags} argument is a combination of the following flags: + +@@ -2091,9 +2238,44 @@ function is available under the name @code{fstat} and so transparently + replaces the interface for small files on 32-bit machines. + @end deftypefun + +-@c fstatat will call alloca and snprintf if the syscall is not +-@c available. +-@c @safety{@mtsafe{}@asunsafe{@ascuheap{}}@acunsafe{@acsmem{}}} ++@deftypefun int fstatat (int @var{filedes}, const char *@var{filename}, struct stat *@var{buf}, int @var{flags}) ++@standards{POSIX.1, sys/stat.h} ++@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}} ++This function is a descriptor-relative version of the @code{fstat} ++function above. @xref{Descriptor-Relative Access}. The @var{flags} ++argument can contain a combination of the flags @code{AT_EMPTY_PATH}, ++@code{AT_NO_AUTOMOUNT}, @code{AT_SYMLINK_NOFOLLOW}. ++ ++Compared to @code{fstat}, the following additional error conditions can ++occur: ++ ++@table @code ++@item EBADF ++The @var{filedes} argument is not a valid file descriptor. ++ ++@item EINVAL ++The @var{flags} argument is not valid for this function. ++ ++@item ENOTDIR ++The descriptor @var{filedes} is not associated with a directory, and ++@var{filename} is a relative file name. ++@end table ++ ++When the sources are compiled with @code{_FILE_OFFSET_BITS == 64} this ++function is in fact @code{fstatat64} since the LFS interface transparently ++replaces the normal implementation. ++@end deftypefun ++ ++@deftypefun int fstatat64 (int @var{filedes}, const char *@var{filename}, struct stat64 *@var{buf}, int @var{flags}) ++@standards{GNU, sys/stat.h} ++@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}} ++This function is the large-file variant of @code{fstatat}, similar to ++how @code{fstat64} is the variant of @code{fstat}. ++ ++When the sources are compiled with @code{_FILE_OFFSET_BITS == 64} this ++function is available under the name @code{fstatat} and so transparently ++replaces the interface for small files on 32-bit machines. ++@end deftypefun + + @deftypefun int lstat (const char *@var{filename}, struct stat *@var{buf}) + @standards{BSD, sys/stat.h} +diff --git a/manual/llio.texi b/manual/llio.texi +index be55dca1b7c9ebcd..05ab44c6e7a5d4fd 100644 +--- a/manual/llio.texi ++++ b/manual/llio.texi +@@ -181,6 +181,43 @@ new, extended API using 64 bit file sizes and offsets transparently + replaces the old API. + @end deftypefun + ++@deftypefun int openat (int @var{filedes}, const char *@var{filename}, int @var{flags}[, mode_t @var{mode}]) ++@standards{POSIX.1, fcntl.h} ++@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{@acsfd{}}} ++This function is the descriptor-relative variant of the @code{open} ++function. @xref{Descriptor-Relative Access}. ++ ++Note that the @var{flags} argument of @code{openat} does not accept ++@code{AT_@dots{}} flags, only the flags described for the @code{open} ++function above. ++ ++The @code{openat} function can fail for additional reasons: ++ ++@table @code ++@item EBADF ++The @var{filedes} argument is not a valid file descriptor. ++ ++@item ENOTDIR ++The descriptor @var{filedes} is not associated with a directory, and ++@var{filename} is a relative file name. ++@end table ++ ++When the sources are compiled with @code{_FILE_OFFSET_BITS == 64} this ++function is in fact @code{openat64} since the LFS interface transparently ++replaces the normal implementation. ++@end deftypefun ++ ++@deftypefun int openat64 (int @var{filedes}, const char *@var{filename}, int @var{flags}[, mode_t @var{mode}]) ++@standards{GNU, fcntl.h} ++The large-file variant of the @code{openat}, similar to how ++@code{open64} is the large-file variant of @code{open}. ++ ++When the sources are translated with @code{_FILE_OFFSET_BITS == 64} this ++function is actually available under the name @code{openat}. I.e., the ++new, extended API using 64 bit file sizes and offsets transparently ++replaces the old API. ++@end deftypefun ++ + @deftypefn {Obsolete function} int creat (const char *@var{filename}, mode_t @var{mode}) + @standards{POSIX.1, fcntl.h} + @safety{@prelim{}@mtsafe{}@assafe{}@acsafe{@acsfd{}}} +@@ -3816,7 +3853,9 @@ contains it is still needed), and permissions are checked when the + descriptor is used later on. + + For example, such descriptors can be used with the @code{fexecve} +-function (@pxref{Executing a File}). ++function (@pxref{Executing a File}). Other applications involve the ++@samp{*at} function variants, along with the @code{AT_EMPTY_PATH} flag. ++@xref{Descriptor-Relative Access}. + + This access mode is specific to Linux. On @gnuhurdsystems{}, it is + possible to use @code{O_EXEC} explicitly, or specify no access modes +diff --git a/manual/startup.texi b/manual/startup.texi +index c421563d16979c64..c1a3683d584cb914 100644 +--- a/manual/startup.texi ++++ b/manual/startup.texi +@@ -664,8 +664,12 @@ basis there may be information that is not available any other way. + This function is used to inquire about the entries in the auxiliary + vector. The @var{type} argument should be one of the @samp{AT_} symbols + defined in @file{elf.h}. If a matching entry is found, the value is +-returned; if the entry is not found, zero is returned and @code{errno} is +-set to @code{ENOENT}. ++returned; if the entry is not found, zero is returned and @code{errno} ++is set to @code{ENOENT}. ++ ++@strong{Note:} There is no relationship between the @samp{AT_} contants ++defined in @file{elf.h} and the file name lookup flags in ++@file{fcntl.h}. @xref{Descriptor-Relative Access}. + @end deftypefun + + For some platforms, the key @code{AT_HWCAP} is the easiest way to inquire diff --git a/glibc-RHEL-108974-7.patch b/glibc-RHEL-108974-7.patch new file mode 100644 index 0000000..7606d74 --- /dev/null +++ b/glibc-RHEL-108974-7.patch @@ -0,0 +1,31 @@ +commit 6efd6cd46bf2257e674be4933a034542d80944eb +Author: Florian Weimer +Date: Fri Sep 6 14:07:00 2024 +0200 + + manual: Safety annotations for clock_gettime, clock_getres + + The annotations are preliminary, for consistency with existing + annotations on gettimeofday etc. + + Reviewed-by: Carlos O'Donell + +diff --git a/manual/time.texi b/manual/time.texi +index ab5063be81cf0af9..d292e269ebb2f975 100644 +--- a/manual/time.texi ++++ b/manual/time.texi +@@ -532,6 +532,7 @@ Systems may support more than just these two POSIX clocks. + + @deftypefun int clock_gettime (clockid_t @var{clock}, struct timespec *@var{ts}) + @standards{POSIX.1, time.h} ++@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}} + Get the current time according to the clock identified by @var{clock}, + storing it as seconds and nanoseconds in @code{*@var{ts}}. + @xref{Time Types}, for a description of @code{struct timespec}. +@@ -553,6 +554,7 @@ clock: + + @deftypefun int clock_getres (clockid_t @var{clock}, struct timespec *@var{res}) + @standards{POSIX.1, time.h} ++@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}} + Get the actual resolution of the clock identified by @var{clock}, + storing it in @code{*@var{ts}}. + diff --git a/glibc-RHEL-108974-8.patch b/glibc-RHEL-108974-8.patch new file mode 100644 index 0000000..96e2962 --- /dev/null +++ b/glibc-RHEL-108974-8.patch @@ -0,0 +1,387 @@ +commit 83a1cc3bc3d28c97d1af6c0957b11fe39fd786d8 +Author: Carlos O'Donell +Date: Wed Oct 9 18:32:26 2024 -0400 + + manual: Fix and test @deftypef* function formatting + + The manual contained several instances of incorrect formatting + that were correct texinfo but produced incorrectly rendered manuals + or incorrect behaviour from the tooling. + + The most important was incorrect quoting of function returns + by failing to use {} to quote the return. The impact of this + mistake means that 'info libc func' does not jump to the function + in question but instead to the introductory page under the assumption + that func doesn't exist. The function returns are now correctly + quoted. + + The second issue was the use of a category specifier with + @deftypefun which doesn't accept a category specifier. If a category + specifier is required then @deftypefn needs to be used. This is + corrected by changing the command to @deftypefn for such functions + that used {Deprecated function} as a category. + + The last issue is a missing space between the function name and the + arguments which results in odd function names like "epoll_wait(int" + instead of "epoll_wait". This also impacts the use of 'info libc' + and is corrected. + + We additionally remove ';' from the end of function arguments and + add an 'int' return type for dprintf. + + Lastly we add a new test check-deftype.sh which verifies the expected + formatting of @deftypefun, @deftypefunx, @deftypefn, and + @deftypefnx. The new test is also run as the summary file is + generated to ensure we don't generate incorrect results. + + The existing check-safety.sh is also run directly as a test to increase + coverage since the existing tests only ran on manual install. + + The new tests now run as part of the standard "make check" that + pre-commit CI runs and developers should run. + + No regressions on x86_64. + + HTML and PDF rendering reviewed and looks correct for all changes. + + Reviewed-by: H.J. Lu + +diff --git a/manual/Makefile b/manual/Makefile +index a6c05db540d6c1da..6a4cfbeb765265f3 100644 +--- a/manual/Makefile ++++ b/manual/Makefile +@@ -69,6 +69,11 @@ chapters.% top-menu.%: libc-texinfo.sh $(texis-path) Makefile + '$(chapters)' \ + '$(appendices) $(licenses)' + ++# Verify validity of texinfo sources against project rules. ++tests-special += \ ++ $(objpfx)check-deftype.out \ ++ $(objpfx)check-safety.out \ ++ # tests-special + + $(objpfx)libc.dvi $(objpfx)libc.pdf $(objpfx)libc.info: \ + $(addprefix $(objpfx),$(libc-texi-generated)) +@@ -83,10 +88,19 @@ $(objpfx)summary.texi: $(objpfx)stamp-summary ; + $(objpfx)stamp-summary: summary.pl $(filter-out $(objpfx)summary.texi, \ + $(texis-path)) + $(SHELL) ./check-safety.sh $(filter-out $(objpfx)%, $(texis-path)) ++ $(SHELL) ./check-deftype.sh $(filter-out $(objpfx)%, $(texis-path)) + LC_ALL=C $(PERL) $^ > $(objpfx)summary-tmp + $(move-if-change) $(objpfx)summary-tmp $(objpfx)summary.texi + touch $@ + ++$(objpfx)check-safety.out: check-safety.sh ++ $(SHELL) $< > $@ ; \ ++ $(evaluate-test) ++ ++$(objpfx)check-deftype.out: check-deftype.sh ++ $(SHELL) $< > $@ ; \ ++ $(evaluate-test) ++ + # Generate a file which can be added to the `dir' content to provide direct + # access to the documentation of the function, variables, and other + # definitions. +@@ -152,10 +166,19 @@ $(objpfx)%.pdf: %.texinfo + + + # Distribution. +-minimal-dist = summary.pl texis.awk tsort.awk libc-texinfo.sh libc.texinfo \ +- libm-err.texi stamp-libm-err check-safety.sh \ +- $(filter-out summary.texi, $(nonexamples)) \ +- $(patsubst %.c.texi,examples/%.c, $(examples)) ++minimal-dist = \ ++ $(filter-out summary.texi, $(nonexamples)) \ ++ $(patsubst %.c.texi,examples/%.c, $(examples)) \ ++ check-deftype.sh \ ++ check-safety.sh \ ++ libc-texinfo.sh \ ++ libc.texinfo \ ++ libm-err.texi \ ++ stamp-libm-err \ ++ summary.pl \ ++ texis.awk \ ++ tsort.awk \ ++ # minimal-dist + + indices = cp fn pg tp vr ky + generated-dirs += libc +diff --git a/manual/check-deftype.sh b/manual/check-deftype.sh +new file mode 100644 +index 0000000000000000..395c99af6afe1fdd +--- /dev/null ++++ b/manual/check-deftype.sh +@@ -0,0 +1,50 @@ ++#!/bin/sh ++ ++# Copyright 2024 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 ++# . ++ ++# Check that the @deftypefun command is called with the expected ++# arguments and includes checking for common mistakes including ++# failure to include a space after the function name, or incorrect ++# quoting. ++ ++success=: ++ ++# If no arguments are given, take all *.texi files in the current directory. ++test $# != 0 || set *.texi ++ ++# We search for all @deftypefun and @deftypefunx command uses. ++# Then we remove all of those that match our expectations. ++# A @deftypefun or @deftypefunx command takes 3 arguments: ++# - return type ++# - name ++# - arguments ++# This is different from @deftypefn which includes an additional ++# category which is implicit here. ++grep -n -r '^@deftypefun' "$@" | ++grep -v '^.*@deftypefunx\?'\ ++' \({\?[a-zA-Z0-9_ *]*}\?\) \([a-zA-Z0-9_]*\) (.*)$' && ++success=false ++ ++# We search for all @deftypefn and @deftypefnx command uses. ++# We have 4 arguments in the command including the category. ++grep -n -r '^@deftypefn' "$@" | ++grep -v '^.*@deftypefnx\?'\ ++' {\?[a-zA-Z ]*}\? \({\?[a-zA-Z0-9@{}_ *]*}\?\) \([a-zA-Z0-9_]*\) (.*)$' && ++success=false ++ ++$success +diff --git a/manual/ipc.texi b/manual/ipc.texi +index 6a6e5ad410c14387..32c5ac066fb94579 100644 +--- a/manual/ipc.texi ++++ b/manual/ipc.texi +@@ -20,7 +20,7 @@ by @theglibc{}. + @c Need descriptions for all of these functions. + + @subsection System V Semaphores +-@deftypefun int semctl (int @var{semid}, int @var{semnum}, int @var{cmd}); ++@deftypefun int semctl (int @var{semid}, int @var{semnum}, int @var{cmd}) + @safety{@prelim{}@mtsafe{}@assafe{}@acunsafe{@acucorrupt{/linux}}} + @c syscall(ipc) ok + @c +@@ -30,35 +30,35 @@ by @theglibc{}. + @c semid_ds. + @end deftypefun + +-@deftypefun int semget (key_t @var{key}, int @var{nsems}, int @var{semflg}); ++@deftypefun int semget (key_t @var{key}, int @var{nsems}, int @var{semflg}) + @safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}} + @c syscall(ipc) ok + @end deftypefun + +-@deftypefun int semop (int @var{semid}, struct sembuf *@var{sops}, size_t @var{nsops}); ++@deftypefun int semop (int @var{semid}, struct sembuf *@var{sops}, size_t @var{nsops}) + @safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}} + @c syscall(ipc) ok + @end deftypefun + +-@deftypefun int semtimedop (int @var{semid}, struct sembuf *@var{sops}, size_t @var{nsops}, const struct timespec *@var{timeout}); ++@deftypefun int semtimedop (int @var{semid}, struct sembuf *@var{sops}, size_t @var{nsops}, const struct timespec *@var{timeout}) + @safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}} + @c syscall(ipc) ok + @end deftypefun + + @subsection POSIX Semaphores + +-@deftypefun int sem_init (sem_t *@var{sem}, int @var{pshared}, unsigned int @var{value}); ++@deftypefun int sem_init (sem_t *@var{sem}, int @var{pshared}, unsigned int @var{value}) + @safety{@prelim{}@mtsafe{}@assafe{}@acunsafe{@acucorrupt{}}} + @c Does not atomically update sem_t therefore AC-unsafe + @c because it can leave sem_t partially initialized. + @end deftypefun + +-@deftypefun int sem_destroy (sem_t *@var{sem}); ++@deftypefun int sem_destroy (sem_t *@var{sem}) + @safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}} + @c Function does nothing and is therefore always safe. + @end deftypefun + +-@deftypefun sem_t *sem_open (const char *@var{name}, int @var{oflag}, ...); ++@deftypefun {sem_t *} sem_open (const char *@var{name}, int @var{oflag}, ...) + @safety{@prelim{}@mtsafe{}@asunsafe{@asuinit{}}@acunsafe{@acuinit{}}} + @c pthread_once asuinit + @c +@@ -67,7 +67,7 @@ by @theglibc{}. + @c shmfs on Linux. + @end deftypefun + +-@deftypefun int sem_close (sem_t *@var{sem}); ++@deftypefun int sem_close (sem_t *@var{sem}) + @safety{@prelim{}@mtsafe{}@asunsafe{@asulock{}}@acunsafe{@aculock{}}} + @c lll_lock asulock aculock + @c twalk mtsrace{:root} +@@ -77,13 +77,13 @@ by @theglibc{}. + @c are not updated atomically. + @end deftypefun + +-@deftypefun int sem_unlink (const char *@var{name}); ++@deftypefun int sem_unlink (const char *@var{name}) + @safety{@prelim{}@mtsafe{}@asunsafe{@asuinit{}}@acunsafe{@acucorrupt{}}} + @c pthread_once asuinit acucorrupt aculock + @c mempcpy acucorrupt + @end deftypefun + +-@deftypefun int sem_wait (sem_t *@var{sem}); ++@deftypefun int sem_wait (sem_t *@var{sem}) + @safety{@prelim{}@mtsafe{}@assafe{}@acunsafe{@acucorrupt{}}} + @c atomic_fetch_add_relaxed (nwaiters) acucorrupt + @c +@@ -95,22 +95,22 @@ by @theglibc{}. + @c waiters count. + @end deftypefun + +-@deftypefun int sem_timedwait (sem_t *@var{sem}, const struct timespec *@var{abstime}); ++@deftypefun int sem_timedwait (sem_t *@var{sem}, const struct timespec *@var{abstime}) + @safety{@prelim{}@mtsafe{}@assafe{}@acunsafe{@acucorrupt{}}} + @c Same safety issues as sem_wait. + @end deftypefun + +-@deftypefun int sem_trywait (sem_t *@var{sem}); ++@deftypefun int sem_trywait (sem_t *@var{sem}) + @safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}} + @c All atomic operations are safe in all contexts. + @end deftypefun + +-@deftypefun int sem_post (sem_t *@var{sem}); ++@deftypefun int sem_post (sem_t *@var{sem}) + @safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}} + @c Same safety as sem_trywait. + @end deftypefun + +-@deftypefun int sem_getvalue (sem_t *@var{sem}, int *@var{sval}); ++@deftypefun int sem_getvalue (sem_t *@var{sem}, int *@var{sval}) + @safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}} + @c Atomic write of a value is safe in all contexts. + @end deftypefun +diff --git a/manual/llio.texi b/manual/llio.texi +index 05ab44c6e7a5d4fd..850d09205a604589 100644 +--- a/manual/llio.texi ++++ b/manual/llio.texi +@@ -4840,12 +4840,12 @@ of an IOCTL, see @ref{Out-of-Band Data}. + @manpagefunctionstub{poll,2} + @end deftypefun + +-@deftypefun int epoll_create(int @var{size}) ++@deftypefun int epoll_create (int @var{size}) + + @manpagefunctionstub{epoll_create,2} + @end deftypefun + +-@deftypefun int epoll_wait(int @var{epfd}, struct epoll_event *@var{events}, int @var{maxevents}, int @var{timeout}) ++@deftypefun int epoll_wait (int @var{epfd}, struct epoll_event *@var{events}, int @var{maxevents}, int @var{timeout}) + + @manpagefunctionstub{epoll_wait,2} + @end deftypefun +diff --git a/manual/memory.texi b/manual/memory.texi +index 3710d7ec667519cc..58683ee93dace783 100644 +--- a/manual/memory.texi ++++ b/manual/memory.texi +@@ -2935,7 +2935,7 @@ exceed the process' data storage limit. + @end deftypefun + + +-@deftypefun void *sbrk (ptrdiff_t @var{delta}) ++@deftypefun {void *} sbrk (ptrdiff_t @var{delta}) + @standards{BSD, unistd.h} + @safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}} + +diff --git a/manual/stdio.texi b/manual/stdio.texi +index 3f837fa99c3c6574..aa137e9888b5b59d 100644 +--- a/manual/stdio.texi ++++ b/manual/stdio.texi +@@ -2523,7 +2523,7 @@ store the result in which case @code{-1} is returned. This was + changed in order to comply with the @w{ISO C99} standard. + @end deftypefun + +-@deftypefun dprintf (int @var{fd}, @var{template}, ...) ++@deftypefun int dprintf (int @var{fd}, @var{template}, ...) + @standards{POSIX, stdio.h} + @safety{@mtsafe{@mtslocale{}}@asunsafe{@ascuheap{}}@acunsafe{@acsmem{}}} + This function formats its arguments according to @var{template} and +diff --git a/manual/threads.texi b/manual/threads.texi +index 25e99c9606dcad77..9ea137cb9663b89c 100644 +--- a/manual/threads.texi ++++ b/manual/threads.texi +@@ -592,7 +592,7 @@ destructor for the thread-specific data is not called during destruction, nor + is it called during thread exit. + @end deftypefun + +-@deftypefun void *pthread_getspecific (pthread_key_t @var{key}) ++@deftypefun {void *} pthread_getspecific (pthread_key_t @var{key}) + @standards{POSIX, pthread.h} + @safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}} + @c pthread_getspecific ok +diff --git a/manual/time.texi b/manual/time.texi +index d292e269ebb2f975..6ccb07fcfc10449b 100644 +--- a/manual/time.texi ++++ b/manual/time.texi +@@ -1829,7 +1829,7 @@ can be placed in the buffer @var{s} the return value is zero, with the + same problems indicated in the @code{strftime} documentation. + @end deftypefun + +-@deftypefun {Deprecated function} {char *} asctime (const struct tm *@var{brokentime}) ++@deftypefn {Deprecated function} {char *} asctime (const struct tm *@var{brokentime}) + @standards{ISO, time.h} + @safety{@prelim{}@mtunsafe{@mtasurace{:asctime} @mtslocale{}}@asunsafe{}@acsafe{}} + @c asctime @mtasurace:asctime @mtslocale +@@ -1863,9 +1863,9 @@ string.) + @strong{Portability note:} + This obsolescent function is deprecated in C23. + Programs should instead use @code{strftime} or even @code{sprintf}. +-@end deftypefun ++@end deftypefn + +-@deftypefun {Deprecated function} {char *} asctime_r (const struct tm *@var{brokentime}, char *@var{buffer}) ++@deftypefn {Deprecated function} {char *} asctime_r (const struct tm *@var{brokentime}, char *@var{buffer}) + @standards{???, time.h} + @safety{@prelim{}@mtsafe{@mtslocale{}}@assafe{}@acsafe{}} + @c asctime_r @mtslocale +@@ -1884,9 +1884,9 @@ it returns @code{NULL}. + @strong{Portability Note:} + POSIX.1-2024 removed this obsolescent function. + Programs should instead use @code{strftime} or even @code{sprintf}. +-@end deftypefun ++@end deftypefn + +-@deftypefun {Deprecated function} {char *} ctime (const time_t *@var{time}) ++@deftypefn {Deprecated function} {char *} ctime (const time_t *@var{time}) + @standards{ISO, time.h} + @safety{@prelim{}@mtunsafe{@mtasurace{:tmbuf} @mtasurace{:asctime} @mtsenv{} @mtslocale{}}@asunsafe{@ascuheap{} @asulock{}}@acunsafe{@aculock{} @acsmem{} @acsfd{}}} + @c ctime @mtasurace:tmbuf @mtasurace:asctime @mtsenv @mtslocale @ascuheap @asulock @aculock @acsmem @acsfd +@@ -1909,9 +1909,9 @@ Calling @code{ctime} also sets the time zone state as if + @strong{Portability note:} + This obsolescent function is deprecated in C23. + Programs should instead use @code{strftime} or even @code{sprintf}. +-@end deftypefun ++@end deftypefn + +-@deftypefun {Deprecated function} {char *} ctime_r (const time_t *@var{time}, char *@var{buffer}) ++@deftypefn {Deprecated function} {char *} ctime_r (const time_t *@var{time}, char *@var{buffer}) + @standards{???, time.h} + @safety{@prelim{}@mtsafe{@mtsenv{} @mtslocale{}}@asunsafe{@ascuheap{} @asulock{}}@acunsafe{@aculock{} @acsmem{} @acsfd{}}} + @c ctime_r @mtsenv @mtslocale @ascuheap @asulock @aculock @acsmem @acsfd +@@ -1935,7 +1935,7 @@ it returns @code{NULL}. + @strong{Portability Note:} + POSIX.1-2024 removed this obsolescent function. + Programs should instead use @code{strftime} or even @code{sprintf}. +-@end deftypefun ++@end deftypefn + + @node Parsing Date and Time + @subsection Convert textual time and date information back diff --git a/glibc-RHEL-108974-9.patch b/glibc-RHEL-108974-9.patch new file mode 100644 index 0000000..66bb23f --- /dev/null +++ b/glibc-RHEL-108974-9.patch @@ -0,0 +1,58 @@ +commit dcad78507433a9a64b8b548b19e110933f8d939a +Author: DJ Delorie +Date: Thu Oct 10 17:16:35 2024 -0400 + + manual: Document stdio.h functions that may be macros + + Glibc has two gnu-extension functions that are implemented as + macros but not documented as such: fread_unlocked and + fwrite_unlocked. Document them as such. + + Additionally, putc_unlocked and getc_unlocked are documented in + POSIX as possibly being macros. Update the manual to add a warning + about those also, depite glibc not implementing them as macros. + +diff --git a/manual/stdio.texi b/manual/stdio.texi +index aa137e9888b5b59d..1708d33b10a63b89 100644 +--- a/manual/stdio.texi ++++ b/manual/stdio.texi +@@ -921,6 +921,9 @@ Therefore, @var{stream} should never be an expression with side-effects. + @safety{@prelim{}@mtsafe{@mtsrace{:stream}}@asunsafe{@asucorrupt{}}@acunsafe{@acucorrupt{}}} + The @code{putc_unlocked} function is equivalent to the @code{putc} + function except that it does not implicitly lock the stream. ++Like @code{putc}, it may be implemented as a macro and may evaluate ++the @var{stream} argument more than once. Therefore, @var{stream} ++should not be an expression with side-effects. + @end deftypefun + + @deftypefun wint_t putwc_unlocked (wchar_t @var{wc}, FILE *@var{stream}) +@@ -1124,6 +1127,9 @@ Therefore, @var{stream} should never be an expression with side-effects. + @safety{@prelim{}@mtsafe{@mtsrace{:stream}}@asunsafe{@asucorrupt{}}@acunsafe{@acucorrupt{}}} + The @code{getc_unlocked} function is equivalent to the @code{getc} + function except that it does not implicitly lock the stream. ++Like @code{getc}, it may be implemented as a macro and may evaluate ++the @var{stream} argument more than once. Therefore, @var{stream} ++should not be an expression with side-effects. + @end deftypefun + + @deftypefun wint_t getwc_unlocked (FILE *@var{stream}) +@@ -1563,6 +1569,9 @@ The @code{fread_unlocked} function is equivalent to the @code{fread} + function except that it does not implicitly lock the stream. + + This function is a GNU extension. ++This function may be implemented as a macro and may evaluate ++@var{stream} more than once. Therefore, @var{stream} should not be an ++expression with side-effects. + @end deftypefun + + @deftypefun size_t fwrite (const void *@var{data}, size_t @var{size}, size_t @var{count}, FILE *@var{stream}) +@@ -1581,6 +1590,9 @@ The @code{fwrite_unlocked} function is equivalent to the @code{fwrite} + function except that it does not implicitly lock the stream. + + This function is a GNU extension. ++This function may be implemented as a macro and may evaluate ++@var{stream} more than once. Therefore, @var{stream} should not be an ++expression with side-effects. + @end deftypefun + + @node Formatted Output diff --git a/glibc-RHEL-110949-2.patch b/glibc-RHEL-113196.patch similarity index 88% rename from glibc-RHEL-110949-2.patch rename to glibc-RHEL-113196.patch index d8d7062..3df6ea0 100644 --- a/glibc-RHEL-110949-2.patch +++ b/glibc-RHEL-113196.patch @@ -18,10 +18,10 @@ Date: Thu Sep 4 20:30:41 2025 +0200 Reviewed-by: H.J. Lu diff --git a/sysdeps/x86_64/Makefile b/sysdeps/x86_64/Makefile -index 06d8c27473c22a0e..cd243adb49ca4e1e 100644 +index c97b3ac13af248c0..1f2455a4d0dce4e5 100644 --- a/sysdeps/x86_64/Makefile +++ b/sysdeps/x86_64/Makefile -@@ -209,6 +209,7 @@ LDFLAGS-tst-plt-rewrite2 = -Wl,-z,now +@@ -206,6 +206,7 @@ LDFLAGS-tst-plt-rewrite2 = -Wl,-z,now LDFLAGS-tst-plt-rewritemod2.so = -Wl,-z,now,-z,undefs tst-plt-rewrite2-ENV = GLIBC_TUNABLES=glibc.cpu.plt_rewrite=2 $(objpfx)tst-plt-rewrite2: $(objpfx)tst-plt-rewritemod2.so @@ -29,7 +29,7 @@ index 06d8c27473c22a0e..cd243adb49ca4e1e 100644 tests-special += $(objpfx)check-dt-x86-64-plt.out -@@ -218,7 +219,6 @@ $(objpfx)check-dt-x86-64-plt.out: $(common-objpfx)libc.so +@@ -215,7 +216,6 @@ $(objpfx)check-dt-x86-64-plt.out: $(common-objpfx)libc.so | grep GLIBC_ABI_DT_X86_64_PLT > $@; \ $(evaluate-test) generated += check-dt-x86-64-plt.out diff --git a/glibc-RHEL-114263.patch b/glibc-RHEL-114264.patch similarity index 100% rename from glibc-RHEL-114263.patch rename to glibc-RHEL-114264.patch diff --git a/glibc-RHEL-58357-1.patch b/glibc-RHEL-58357-1.patch new file mode 100644 index 0000000..0666d3c --- /dev/null +++ b/glibc-RHEL-58357-1.patch @@ -0,0 +1,30 @@ +commit 7d6e30b4b4e83429cc77222d4fe4d5e8843d8e2b +Author: Florian Weimer +Date: Fri Sep 6 14:07:00 2024 +0200 + + stdlib: Do not use GLIBC_PRIVATE ABI for errno in libc_nonshared.a + + Using TLS directly introduces a GLIBC_PRIVATE ABI dependency + into libc_nonshared.a, and thus indirectly into applications. + Adding the !defined LIBC_NONSHARED condition deactivates direct + TLS access, and libc_nonshared.a code switches to using + __errno_location, like application code. + + Currently, this has no effect because there is no code in + libc_nonshared.a that accesses errno. + + Reviewed-by: Carlos O'Donell + +diff --git a/include/errno.h b/include/errno.h +index c361a785c24b928f..f0ccaa74dd8bebed 100644 +--- a/include/errno.h ++++ b/include/errno.h +@@ -20,7 +20,7 @@ + # define errno rtld_errno + extern int rtld_errno attribute_hidden; + +-# elif IS_IN_LIB && !IS_IN (rtld) ++# elif IS_IN_LIB && !IS_IN (rtld) && !defined LIBC_NONSHARED + + # undef errno + # if IS_IN (libc) diff --git a/glibc-RHEL-58357-10.patch b/glibc-RHEL-58357-10.patch new file mode 100644 index 0000000..a412332 --- /dev/null +++ b/glibc-RHEL-58357-10.patch @@ -0,0 +1,50 @@ +commit 517846c85dfc48aa231e28e95e8f90a6d8a8efde +Author: Florian Weimer +Date: Wed Mar 12 11:29:10 2025 +0100 + + Makefile: Clean up pthread_atfork integration + + Do not add the pthread_atfork routine again in nptl/Makefile, + instead rely on sysdeps/pthread/Makefile for the integration + (as this is the directory that contains the source file). + + In sysdeps/pthread/Makefile, add to static-only-routines. + + Reviewed-by: Joseph Myers + +Conflicts: + nptl/Makefile (Fixup context due to previous patches) + +diff --git a/nptl/Makefile b/nptl/Makefile +index e72b28dc92cd5852..c9d9079cdb8a5643 100644 +--- a/nptl/Makefile ++++ b/nptl/Makefile +@@ -63,7 +63,6 @@ routines = \ + old_pthread_cond_signal \ + old_pthread_cond_timedwait \ + old_pthread_cond_wait \ +- pthread_atfork \ + pthread_attr_copy \ + pthread_attr_destroy \ + pthread_attr_extension \ +@@ -211,7 +210,6 @@ routines = \ + # routines + + static-only-routines += \ +- pthread_atfork \ + pthread_gettid_np \ + # static-only-routines + +diff --git a/sysdeps/pthread/Makefile b/sysdeps/pthread/Makefile +index 04ea56559ef3a79b..a0f67c8e09327114 100644 +--- a/sysdeps/pthread/Makefile ++++ b/sysdeps/pthread/Makefile +@@ -297,7 +297,7 @@ tests-time64 += \ + tst-thrd-sleep-time64 \ + # tests-time64 + +-static-only-routines = pthread_atfork ++static-only-routines += pthread_atfork + + # Files which must not be linked with libpthread. + tests-nolibpthread += \ diff --git a/glibc-RHEL-58357-11.patch b/glibc-RHEL-58357-11.patch new file mode 100644 index 0000000..376d72b --- /dev/null +++ b/glibc-RHEL-58357-11.patch @@ -0,0 +1,33 @@ +commit f176bf2a06b458dea8186fb2ff3bb8ea24da6d67 +Author: DJ Delorie +Date: Wed May 7 19:23:06 2025 -0400 + + manual: fix typo for sched_[sg]etattr + + Originally added in 41a90f3f5f which says it's adding sched_getattr + and sched_setattr. + + Reviewed-by: Collin Funk + +diff --git a/manual/resource.texi b/manual/resource.texi +index 40ab3572e04747c7..6729ada79402f0ad 100644 +--- a/manual/resource.texi ++++ b/manual/resource.texi +@@ -1003,7 +1003,7 @@ For additional information, consult the manual page + @manpageurl{sched_setattr,2}. @xref{Linux Kernel}. + @end deftp + +-@deftypefun int sched_setaddr (pid_t @var{tid}, struct sched_attr *@var{attr}, unsigned int flags) ++@deftypefun int sched_setattr (pid_t @var{tid}, struct sched_attr *@var{attr}, unsigned int flags) + @standards{Linux, sched.h} + @safety{@mtsafe{}@assafe{}@acsafe{}} + This functions applies the scheduling policy described by +@@ -1046,7 +1046,7 @@ policy of the thread @var{tid}. + Other error codes depend on the scheduling policy. + @end deftypefun + +-@deftypefun int sched_getaddr (pid_t @var{tid}, struct sched_attr *@var{attr}, unsigned int size, unsigned int flags) ++@deftypefun int sched_getattr (pid_t @var{tid}, struct sched_attr *@var{attr}, unsigned int size, unsigned int flags) + @standards{Linux, sched.h} + @safety{@mtsafe{}@assafe{}@acsafe{}} + This function obtains the scheduling policy of the thread @var{tid} diff --git a/glibc-RHEL-58357-2.patch b/glibc-RHEL-58357-2.patch new file mode 100644 index 0000000..be69718 --- /dev/null +++ b/glibc-RHEL-58357-2.patch @@ -0,0 +1,32 @@ +commit 298bc488fdc047da37482f4003023cb9adef78f8 +Author: Florian Weimer +Date: Wed Sep 11 10:05:08 2024 +0200 + + manual: Extract the @manpageurl{func,sec} macro + + From the existing @manpagefunctionstub{func,sec} macro, + so that URLs can be included in the manual without the + stub text. + + Reviewed-by: Carlos O'Donell + +diff --git a/manual/macros.texi b/manual/macros.texi +index 579da3fb81e59da0..f48dd4ec2282634f 100644 +--- a/manual/macros.texi ++++ b/manual/macros.texi +@@ -282,10 +282,13 @@ cwd\comments\ + @macro standardsx {element, standard, header} + @end macro + ++@macro manpageurl {func, sec} ++@url{https://man7.org/linux/man-pages/man\sec\/\func\.\sec\.html} ++@end macro ++ + @macro manpagefunctionstub {func,sec} + This documentation is a stub. For additional information on this +-function, consult the manual page +-@url{https://man7.org/linux/man-pages/man\sec\/\func\.\sec\.html}. ++function, consult the manual page @manpageurl{\func\,\sec\}. + @xref{Linux Kernel}. + @end macro + diff --git a/glibc-RHEL-58357-3.patch b/glibc-RHEL-58357-3.patch new file mode 100644 index 0000000..97ec4f9 --- /dev/null +++ b/glibc-RHEL-58357-3.patch @@ -0,0 +1,454 @@ +Partial backport (without ABI changes, using libc_nonshared.a instead) +of: + +commit 21571ca0d70302909cf72707b2a7736cf12190a0 +Author: Florian Weimer +Date: Wed Sep 11 10:05:08 2024 +0200 + + Linux: Add the sched_setattr and sched_getattr functions + + And struct sched_attr. + + In sysdeps/unix/sysv/linux/bits/sched.h, the hack that defines + sched_param around the inclusion of is quite + ugly, but the definition of struct sched_param has already been + dropped by the kernel, so there is nothing else we can do and maintain + compatibility of with a wide range of kernel header + versions. (An alternative would involve introducing a separate header + for this functionality, but this seems unnecessary.) + + The existing sched_* functions that change scheduler parameters + are already incompatible with PTHREAD_PRIO_PROTECT mutexes, so + there is no harm in adding more functionality in this area. + + The documentation mostly defers to the Linux manual pages. + + Reviewed-by: Carlos O'Donell + +Conflicts: + sysdeps/unix/sysv/linux/Makefile + (variables not sorted downstream, libc_nonshared.a + integration downstream) + sysdeps/unix/sysv/linux/Versions + (not backported) + sysdeps/unix/sysv/linux/*/libc.abilist + (not backported) + +The implementation uses the syscall function, not , +to avoid implicit TCB layout dependencies. Such dependencies +could happen if the system call macros use information in the +TCB to select the way the kernel is entered. + +diff --git a/manual/resource.texi b/manual/resource.texi +index 743cc9439665b9d5..c92df6ee4f028fd6 100644 +--- a/manual/resource.texi ++++ b/manual/resource.texi +@@ -478,6 +478,7 @@ POSIX syntax had in mind. + * Absolute Priority:: The first tier of priority. Posix + * Realtime Scheduling:: Scheduling among the process nobility + * Basic Scheduling Functions:: Get/set scheduling policy, priority ++* Extensible Scheduling:: Parameterized scheduling policies. + * Traditional Scheduling:: Scheduling among the vulgar masses + * CPU Affinity:: Limiting execution to certain CPUs + @end menu +@@ -952,6 +953,120 @@ function, so there are no specific @code{errno} values. + + @end deftypefun + ++@node Extensible Scheduling ++@subsection Extensible Scheduling ++@cindex scheduling, extensible ++ ++The type @code{struct sched_attr} and the functions @code{sched_setattr} ++and @code{sched_getattr} are used to implement scheduling policies with ++multiple parameters (not just priority and niceness). ++ ++It is expected that these interfaces will be compatible with all future ++scheduling policies. ++ ++For additional information about scheduling policies, consult consult ++the manual pages @manpageurl{sched,7} and @manpageurl{sched_setattr,2}. ++@xref{Linux Kernel}. ++ ++@strong{Note:} Calling the @code{sched_setattr} function is incompatible ++with support for @code{PTHREAD_PRIO_PROTECT} mutexes. ++ ++@deftp {Data Type} {struct sched_attr} ++@standards{Linux, sched.h} ++The @code{sched_attr} structure describes a parameterized scheduling policy. ++ ++@strong{Portability note:} In the future, additional fields can be added ++to @code{struct sched_attr} at the end, so that the size of this data ++type changes. Do not use it in places where this matters, such as ++structure fields in installed header files, where such a change could ++impact the application binary interface (ABI). ++ ++The following generic fields are available. ++ ++@table @code ++@item size ++The actually used size of the data structure. See the description of ++the functions @code{sched_setattr} and @code{sched_getattr} below how this ++field is used to support extension of @code{struct sched_attr} with ++more fields. ++ ++@item sched_policy ++The scheduling policy. This field determines which fields in the ++structure are used, and how the @code{sched_flags} field is interpreted. ++ ++@item sched_flags ++Scheduling flags associated with the scheduling policy. ++@end table ++ ++In addition to the generic fields, policy-specific fields are available. ++For additional information, consult the manual page ++@manpageurl{sched_setattr,2}. @xref{Linux Kernel}. ++@end deftp ++ ++@deftypefun int sched_setaddr (pid_t @var{tid}, struct sched_attr *@var{attr}, unsigned int flags) ++@standards{Linux, sched.h} ++@safety{@mtsafe{}@assafe{}@acsafe{}} ++This functions applies the scheduling policy described by ++@code{*@var{attr}} to the thread @var{tid} (the value zero denotes the ++current thread). ++ ++It is recommended to initialize unused fields to zero, either using ++@code{memset}, or using a structure initializer. The ++@code{@var{attr->size}} field should be set to @code{sizeof (struct ++sched_attr)}, to inform the kernel of the structure version in use. ++ ++The @var{flags} argument must be zero. Other values may become ++available in the future. ++ ++On failure, @code{sched_setattr} returns @math{-1} and sets ++@code{errno}. The following errors are related the way ++extensibility is handled. ++@table @code ++@item E2BIG ++A field in @code{*@var{attr}} has a non-zero value, but is unknown to ++the kernel. The application could try to apply a modified policy, where ++more fields are zero. ++ ++@item EINVAL ++The policy in @code{@var{attr}->sched_policy} is unknown to the kernel, ++or flags are set in @code{@var{attr}->sched_flags} that the kernel does ++not know how to interpret. The application could try with fewer flags ++set, or a different scheduling policy. ++ ++This error also occurs if @var{attr} is @code{NULL} or @var{flags} is ++not zero. ++ ++@item EPERM ++The current thread is not sufficiently privileged to assign the policy, ++either because access to the policy is restricted in general, or because ++the current thread does not have the rights to change the scheduling ++policy of the thread @var{tid}. ++@end table ++ ++Other error codes depend on the scheduling policy. ++@end deftypefun ++ ++@deftypefun int sched_getaddr (pid_t @var{tid}, struct sched_attr *@var{attr}, unsigned int size, unsigned int flags) ++@standards{Linux, sched.h} ++@safety{@mtsafe{}@assafe{}@acsafe{}} ++This function obtains the scheduling policy of the thread @var{tid} ++(zero denotes the current thread) and store it in @code{*@var{attr}}, ++which must have space for at least @var{size} bytes. ++ ++The @var{flags} argument must be zero. Other values may become ++available in the future. ++ ++Upon success, @code{@var{attr}->size} contains the size of the structure ++version used by the kernel. Fields with offsets greater or equal to ++@code{@var{attr}->size} are not updated by the kernel. To obtain ++predictable values for unknown fields, use @code{memset} to set ++all @var{size} bytes to zero prior to calling @code{sched_getattr}. ++ ++On failure, @code{sched_getattr} returns @math{-1} and sets @code{errno}. ++If @code{errno} is @code{E2BIG}, this means that the buffer is not large ++large enough, and the application could retry with a larger buffer. ++@end deftypefun ++ + @node Traditional Scheduling + @subsection Traditional Scheduling + @cindex scheduling, traditional +diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile +index eee91c7b64d79fe7..a0f79f7513a64616 100644 +--- a/sysdeps/unix/sysv/linux/Makefile ++++ b/sysdeps/unix/sysv/linux/Makefile +@@ -95,6 +95,8 @@ sysdep_routines += \ + process_vm_writev \ + pselect32 \ + readahead \ ++ sched_getattr \ ++ sched_setattr \ + setfsgid \ + setfsuid \ + setvmaname \ +@@ -113,6 +115,12 @@ sysdep_routines += \ + xstat64 \ + # sysdep_routines + ++# The implementations go into libc_nonshared.a, to preserve ABI. ++static-only-routines += \ ++ sched_getattr \ ++ sched_setattr \ ++ # static-only-routines ++ + CFLAGS-gethostid.c = -fexceptions + CFLAGS-tee.c = -fexceptions -fasynchronous-unwind-tables + CFLAGS-vmsplice.c = -fexceptions -fasynchronous-unwind-tables +@@ -223,6 +231,7 @@ tests += \ + tst-process_mrelease \ + tst-quota \ + tst-rlimit-infinity \ ++ tst-sched_setattr \ + tst-scm_rights \ + tst-sigtimedwait \ + tst-sync_file_range \ +diff --git a/sysdeps/unix/sysv/linux/bits/sched.h b/sysdeps/unix/sysv/linux/bits/sched.h +index a53e1362a07596bc..e5b7efb887fb98da 100644 +--- a/sysdeps/unix/sysv/linux/bits/sched.h ++++ b/sysdeps/unix/sysv/linux/bits/sched.h +@@ -34,10 +34,39 @@ + # define SCHED_IDLE 5 + # define SCHED_DEADLINE 6 + ++/* Flags that can be used in policy values. */ + # define SCHED_RESET_ON_FORK 0x40000000 +-#endif + +-#ifdef __USE_GNU ++/* Use "" to work around incorrect macro expansion of the ++ __has_include argument (GCC PR 80005). */ ++# ifdef __has_include ++# if __has_include ("linux/sched/types.h") ++/* Some older Linux versions defined sched_param in . */ ++# define sched_param __glibc_mask_sched_param ++# include ++# undef sched_param ++# endif ++# endif ++# ifndef SCHED_ATTR_SIZE_VER0 ++# include ++# define SCHED_ATTR_SIZE_VER0 48 ++# define SCHED_ATTR_SIZE_VER1 56 ++struct sched_attr ++{ ++ __u32 size; ++ __u32 sched_policy; ++ __u64 sched_flags; ++ __s32 sched_nice; ++ __u32 sched_priority; ++ __u64 sched_runtime; ++ __u64 sched_deadline; ++ __u64 sched_period; ++ __u32 sched_util_min; ++ __u32 sched_util_max; ++ /* Additional fields may be added at the end. */ ++}; ++# endif /* !SCHED_ATTR_SIZE_VER0 */ ++ + /* Cloning flags. */ + # define CSIGNAL 0x000000ff /* Signal mask to be sent at exit. */ + # define CLONE_VM 0x00000100 /* Set if VM shared between processes. */ +@@ -97,6 +126,17 @@ extern int getcpu (unsigned int *, unsigned int *) __THROW; + + /* Switch process to namespace of type NSTYPE indicated by FD. */ + extern int setns (int __fd, int __nstype) __THROW; ++ ++/* Apply the scheduling attributes from *ATTR to the process or thread TID. */ ++int sched_setattr (pid_t tid, struct sched_attr *attr, unsigned int flags) ++ __THROW __nonnull ((2)); ++ ++/* Obtain the scheduling attributes of the process or thread TID and ++ store it in *ATTR. */ ++int sched_getattr (pid_t tid, struct sched_attr *attr, unsigned int size, ++ unsigned int flags) ++ __THROW __nonnull ((2)) __attr_access ((__write_only__, 2, 3)); ++ + #endif + + __END_DECLS +diff --git a/sysdeps/unix/sysv/linux/sched_getattr.c b/sysdeps/unix/sysv/linux/sched_getattr.c +new file mode 100644 +index 0000000000000000..64f0b70514f2b143 +--- /dev/null ++++ b/sysdeps/unix/sysv/linux/sched_getattr.c +@@ -0,0 +1,30 @@ ++/* Reading scheduling policy and attributes. ++ Copyright (C) 2024 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 ++ . */ ++ ++#include ++#include ++#include ++ ++int ++attribute_hidden ++sched_getattr (pid_t pid, struct sched_attr *attr, unsigned int size, ++ unsigned int flags) ++{ ++ /* Use the syscall function for compatibility with libc_nonshared.a. */ ++ return syscall (__NR_sched_getattr, pid, attr, size, flags); ++} +diff --git a/sysdeps/unix/sysv/linux/sched_setattr.c b/sysdeps/unix/sysv/linux/sched_setattr.c +new file mode 100644 +index 0000000000000000..2a24a734e8d5125b +--- /dev/null ++++ b/sysdeps/unix/sysv/linux/sched_setattr.c +@@ -0,0 +1,29 @@ ++/* Setting scheduling policy and attributes. ++ Copyright (C) 2024 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 ++ . */ ++ ++#include ++#include ++#include ++ ++int ++attribute_hidden ++sched_setattr (pid_t pid, struct sched_attr *attr, unsigned int flags) ++{ ++ /* Use the syscall function for compatibility with libc_nonshared.a. */ ++ return syscall (__NR_sched_setattr, pid, attr, flags); ++} +diff --git a/sysdeps/unix/sysv/linux/tst-sched_setattr.c b/sysdeps/unix/sysv/linux/tst-sched_setattr.c +new file mode 100644 +index 0000000000000000..a6288a1a7cc2d01b +--- /dev/null ++++ b/sysdeps/unix/sysv/linux/tst-sched_setattr.c +@@ -0,0 +1,105 @@ ++/* Tests for sched_setattr and sched_getattr. ++ Copyright (C) 2024 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 ++ . */ ++ ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Padding struct to detect unexpected writes. */ ++union ++{ ++ struct sched_attr attr; ++ /* Hopefully the kernel will never need as much. */ ++ unsigned char padding[4096]; ++} u; ++ ++static void ++check_unused (void) ++{ ++ TEST_VERIFY (u.attr.size < sizeof (u)); ++ for (unsigned int i = u.attr.size; i < sizeof (u); ++i) ++ TEST_COMPARE (u.padding[i], 0xcc); ++} ++ ++static int ++do_test (void) ++{ ++ TEST_VERIFY (sizeof (struct sched_attr) < sizeof (u)); ++ ++ /* Check that reading and re-applying the current policy works. */ ++ memset (&u, 0xcc, sizeof (u)); ++ /* Compiler barrier to bypass write access attribute. */ ++ volatile unsigned int size = sizeof (u); ++ TEST_COMPARE (sched_getattr (0, (struct sched_attr *) &u, size, 0), 0); ++ check_unused (); ++ TEST_COMPARE (sched_setattr (0, &u.attr, 0), 0); /* Apply unchanged. */ ++ ++ /* Try to switch to the SCHED_OTHER policy. */ ++ memset (&u, 0, sizeof (u)); ++ u.attr.size = sizeof (u); /* With padding, kernel should accept zeroes. */ ++ u.attr.sched_policy = SCHED_OTHER; /* Should be the default. */ ++ { ++ errno = 0; ++ int prio = getpriority (PRIO_PROCESS, 0); ++ if (errno != 0) ++ prio = 0; ++ u.attr.sched_nice = prio; ++ } ++ TEST_COMPARE (sched_setattr (0, &u.attr, 0), 0); ++ ++ /* Non-zero values not known to the kernel result in an E2BIG error. */ ++ memset (&u, 0, sizeof (u)); ++ TEST_COMPARE (sched_getattr (0, (struct sched_attr *) &u, size, 0), 0); ++ u.padding[u.attr.size] = 0xcc; ++ u.attr.size = sizeof (u); ++ errno = 0; ++ TEST_COMPARE (sched_setattr (0, &u.attr, 0), -1); ++ TEST_COMPARE (errno, E2BIG); ++ ++ memset (&u, 0xcc, sizeof (u)); ++ TEST_COMPARE (sched_getattr (0, (struct sched_attr *) &u, size, 0), 0); ++ TEST_COMPARE (u.attr.sched_policy, SCHED_OTHER); ++ check_unused (); ++ ++ /* Raise the niceless level to 19 and observe its effect. */ ++ TEST_COMPARE (nice (19), 19); ++ TEST_COMPARE (sched_getattr (0, &u.attr, sizeof (u.attr), 0), 0); ++ TEST_COMPARE (u.attr.sched_policy, SCHED_OTHER); ++ TEST_COMPARE (u.attr.sched_nice, 19); ++ check_unused (); ++ ++ /* Invalid buffer arguments result in EINVAL (not EFAULT). */ ++ { ++ errno = 0; ++ void *volatile null_pointer = NULL; /* compiler barrier. */ ++ TEST_COMPARE (sched_setattr (0, null_pointer, 0), -1); ++ TEST_COMPARE (errno, EINVAL); ++ errno = 0; ++ TEST_COMPARE (sched_getattr (0, null_pointer, size, 0), -1); ++ TEST_COMPARE (errno, EINVAL); ++ } ++ ++ return 0; ++} ++ ++#include diff --git a/glibc-RHEL-58357-4.patch b/glibc-RHEL-58357-4.patch new file mode 100644 index 0000000..e58de6c --- /dev/null +++ b/glibc-RHEL-58357-4.patch @@ -0,0 +1,139 @@ +commit c444cc1d8335243c5c4e636d6a26c472df85522c +Author: Florian Weimer +Date: Wed Sep 11 10:05:08 2024 +0200 + + Linux: Add missing scheduler constants to + + And add a test, misc/tst-sched-consts, that checks + consistency with . + + Reviewed-by: Carlos O'Donell + +diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile +index a0f79f7513a64616..af7fbac14534e601 100644 +--- a/sysdeps/unix/sysv/linux/Makefile ++++ b/sysdeps/unix/sysv/linux/Makefile +@@ -403,6 +403,16 @@ $(objpfx)tst-mount-compile.out: ../sysdeps/unix/sysv/linux/tst-mount-compile.py + < /dev/null > $@ 2>&1; $(evaluate-test) + $(objpfx)tst-mount-compile.out: $(sysdeps-linux-python-deps) + ++tests-special += \ ++ $(objpfx)tst-sched-consts.out \ ++ # tests-special ++$(objpfx)tst-sched-consts.out: ../sysdeps/unix/sysv/linux/tst-sched-consts.py ++ $(sysdeps-linux-python) \ ++ ../sysdeps/unix/sysv/linux/tst-sched-consts.py \ ++ $(sysdeps-linux-python-cc) \ ++ < /dev/null > $@ 2>&1; $(evaluate-test) ++$(objpfx)tst-sched-consts.out: $(sysdeps-linux-python-deps) ++ + tst-rseq-disable-ENV = GLIBC_TUNABLES=glibc.pthread.rseq=0 + + endif # $(subdir) == misc +diff --git a/sysdeps/unix/sysv/linux/bits/sched.h b/sysdeps/unix/sysv/linux/bits/sched.h +index e5b7efb887fb98da..a02cb69de77794fa 100644 +--- a/sysdeps/unix/sysv/linux/bits/sched.h ++++ b/sysdeps/unix/sysv/linux/bits/sched.h +@@ -29,6 +29,7 @@ + #define SCHED_FIFO 1 + #define SCHED_RR 2 + #ifdef __USE_GNU ++# define SCHED_NORMAL SCHED_OTHER + # define SCHED_BATCH 3 + # define SCHED_ISO 4 + # define SCHED_IDLE 5 +@@ -37,6 +38,19 @@ + /* Flags that can be used in policy values. */ + # define SCHED_RESET_ON_FORK 0x40000000 + ++/* Flags for the sched_flags field in struct sched_attr. */ ++#define SCHED_FLAG_RESET_ON_FORK 0x01 ++#define SCHED_FLAG_RECLAIM 0x02 ++#define SCHED_FLAG_DL_OVERRUN 0x04 ++#define SCHED_FLAG_KEEP_POLICY 0x08 ++#define SCHED_FLAG_KEEP_PARAMS 0x10 ++#define SCHED_FLAG_UTIL_CLAMP_MIN 0x20 ++#define SCHED_FLAG_UTIL_CLAMP_MAX 0x40 ++ ++/* Combinations of sched_flags fields. */ ++#define SCHED_FLAG_KEEP_ALL 0x18 ++#define SCHED_FLAG_UTIL_CLAMP 0x60 ++ + /* Use "" to work around incorrect macro expansion of the + __has_include argument (GCC PR 80005). */ + # ifdef __has_include +diff --git a/sysdeps/unix/sysv/linux/tst-sched-consts.py b/sysdeps/unix/sysv/linux/tst-sched-consts.py +new file mode 100644 +index 0000000000000000..70071dcd974fe064 +--- /dev/null ++++ b/sysdeps/unix/sysv/linux/tst-sched-consts.py +@@ -0,0 +1,56 @@ ++#!/usr/bin/python3 ++# Test that glibc's sched.h constants match the kernel's. ++# Copyright (C) 2018-2024 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 ++# . ++ ++import argparse ++import sys ++ ++import glibcextract ++import glibcsyscalls ++ ++ ++def main(): ++ """The main entry point.""" ++ parser = argparse.ArgumentParser( ++ description="Test that glibc's sched.h constants " ++ "match the kernel's.") ++ parser.add_argument('--cc', metavar='CC', ++ help='C compiler (including options) to use') ++ args = parser.parse_args() ++ linux_version_headers = glibcsyscalls.linux_kernel_version(args.cc) ++ linux_version_glibc = (6, 10) ++ sys.exit(glibcextract.compare_macro_consts( ++ '#define _GNU_SOURCE 1\n' ++ '#include \n', ++ '#define _GNU_SOURCE 1\n' ++ '#include \n' ++ '#include \n', ++ args.cc, ++ 'SCHED_.*', ++ # SCHED_ISO is reserved, but not implemented in the kernel. ++ # SCHED_OTHER is the standard name for SCHED_NORMAL. ++ # SCHED_FLAG_ALL will receive more and more flags, so ++ # exposing it to userspace does not seem useful. ++ 'SCHED_ISO' ++ '|SCHED_OTHER' ++ '|SCHED_FLAG_ALL', ++ linux_version_glibc > linux_version_headers, ++ linux_version_headers > linux_version_glibc)) ++ ++if __name__ == '__main__': ++ main() +diff --git a/sysdeps/unix/sysv/linux/tst-sched_setattr.c b/sysdeps/unix/sysv/linux/tst-sched_setattr.c +index a6288a1a7cc2d01b..fbb73c31a72de311 100644 +--- a/sysdeps/unix/sysv/linux/tst-sched_setattr.c ++++ b/sysdeps/unix/sysv/linux/tst-sched_setattr.c +@@ -44,6 +44,8 @@ check_unused (void) + static int + do_test (void) + { ++ _Static_assert (SCHED_OTHER == SCHED_NORMAL, ++ "SCHED_OTHER, SCHED_NORMAL values"); + TEST_VERIFY (sizeof (struct sched_attr) < sizeof (u)); + + /* Check that reading and re-applying the current policy works. */ diff --git a/glibc-RHEL-58357-5.patch b/glibc-RHEL-58357-5.patch new file mode 100644 index 0000000..6a42bde --- /dev/null +++ b/glibc-RHEL-58357-5.patch @@ -0,0 +1,73 @@ +commit b3a6bd625ce96bcec0e5d41b9835b1367d97e548 +Author: Florian Weimer +Date: Mon Jan 20 09:57:09 2025 +0100 + + Linux: Do not check unused bytes after sched_getattr in tst-sched_setattr + + Linux 6.13 was released with a change that overwrites those bytes. + This means that the check_unused subtest fails. + + Update the manual accordingly. + + Tested-by: Xi Ruoyao + Reviewed-by: Adhemerval Zanella + +diff --git a/manual/resource.texi b/manual/resource.texi +index c92df6ee4f028fd6..40ab3572e04747c7 100644 +--- a/manual/resource.texi ++++ b/manual/resource.texi +@@ -1058,9 +1058,9 @@ available in the future. + + Upon success, @code{@var{attr}->size} contains the size of the structure + version used by the kernel. Fields with offsets greater or equal to +-@code{@var{attr}->size} are not updated by the kernel. To obtain +-predictable values for unknown fields, use @code{memset} to set +-all @var{size} bytes to zero prior to calling @code{sched_getattr}. ++@code{@var{attr}->size} may not be overwritten by the kernel. To obtain ++predictable values for unknown fields, use @code{memset} to set all ++@var{size} bytes to zero prior to calling @code{sched_getattr}. + + On failure, @code{sched_getattr} returns @math{-1} and sets @code{errno}. + If @code{errno} is @code{E2BIG}, this means that the buffer is not large +diff --git a/sysdeps/unix/sysv/linux/tst-sched_setattr.c b/sysdeps/unix/sysv/linux/tst-sched_setattr.c +index fbb73c31a72de311..6b0913aebae96abe 100644 +--- a/sysdeps/unix/sysv/linux/tst-sched_setattr.c ++++ b/sysdeps/unix/sysv/linux/tst-sched_setattr.c +@@ -33,14 +33,6 @@ union + unsigned char padding[4096]; + } u; + +-static void +-check_unused (void) +-{ +- TEST_VERIFY (u.attr.size < sizeof (u)); +- for (unsigned int i = u.attr.size; i < sizeof (u); ++i) +- TEST_COMPARE (u.padding[i], 0xcc); +-} +- + static int + do_test (void) + { +@@ -53,7 +45,6 @@ do_test (void) + /* Compiler barrier to bypass write access attribute. */ + volatile unsigned int size = sizeof (u); + TEST_COMPARE (sched_getattr (0, (struct sched_attr *) &u, size, 0), 0); +- check_unused (); + TEST_COMPARE (sched_setattr (0, &u.attr, 0), 0); /* Apply unchanged. */ + + /* Try to switch to the SCHED_OTHER policy. */ +@@ -81,14 +72,12 @@ do_test (void) + memset (&u, 0xcc, sizeof (u)); + TEST_COMPARE (sched_getattr (0, (struct sched_attr *) &u, size, 0), 0); + TEST_COMPARE (u.attr.sched_policy, SCHED_OTHER); +- check_unused (); + + /* Raise the niceless level to 19 and observe its effect. */ + TEST_COMPARE (nice (19), 19); + TEST_COMPARE (sched_getattr (0, &u.attr, sizeof (u.attr), 0), 0); + TEST_COMPARE (u.attr.sched_policy, SCHED_OTHER); + TEST_COMPARE (u.attr.sched_nice, 19); +- check_unused (); + + /* Invalid buffer arguments result in EINVAL (not EFAULT). */ + { diff --git a/glibc-RHEL-58357-6.patch b/glibc-RHEL-58357-6.patch new file mode 100644 index 0000000..daf6b65 --- /dev/null +++ b/glibc-RHEL-58357-6.patch @@ -0,0 +1,225 @@ +Partial backport (without ABI changes, using libc_nonshared.a instead) +of: + +commit 74d463c50bb1096efef47022405c7db33f83fb5a +Author: Florian Weimer +Date: Wed Mar 12 10:16:31 2025 +0100 + + Linux: Add the pthread_gettid_np function (bug 27880) + + Current Bionic has this function, with enhanced error checking + (the undefined case terminates the process). + + Reviewed-by: Joseph Myers + +Conflicts: + sysdeps/unix/sysv/linux/*/libc.abilist + (not backported) + nptl/Versions + (not backported) + +The alternate libc_nonshared.a implementation relies on the UAPI +encoding of pthread_getcpuclockid, and avoids a TCB layout +dependency. + +diff --git a/manual/process.texi b/manual/process.texi +index 8254e5ee864e2515..a8f37e55a3b5b7cd 100644 +--- a/manual/process.texi ++++ b/manual/process.texi +@@ -239,6 +239,24 @@ especially regarding reuse of the IDs of threads which have exited. + This function is specific to Linux. + @end deftypefun + ++@deftypefun pid_t pthread_gettid_np (pthread_t @var{thread}) ++@standards{Linux, pthread.h} ++@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}} ++This function returns the same value that @code{gettid} would return if ++executed on the running thread @var{thread}. ++ ++If @var{thread} is no longer running but it is joinable, it is ++unspecified whether this function returns @minus{}1, or if it returns ++the thread ID of the thread while it was running. If @var{thread} is ++not running and is not joinable, the behavior is undefined. ++ ++@strong{Portability Note:} Linux thread IDs can be reused rather quickly, ++so this function differs from the @code{pthread_getunique_np} function ++found on other systems. ++ ++This function is specific to Linux. ++@end deftypefun ++ + @node Creating a Process + @section Creating a Process + +diff --git a/nptl/Makefile b/nptl/Makefile +index bf09603e7b94b286..e72b28dc92cd5852 100644 +--- a/nptl/Makefile ++++ b/nptl/Makefile +@@ -124,6 +124,7 @@ routines = \ + pthread_getname \ + pthread_getschedparam \ + pthread_getspecific \ ++ pthread_gettid_np \ + pthread_join \ + pthread_join_common \ + pthread_key_create \ +@@ -209,7 +210,11 @@ routines = \ + vars \ + # routines + +-static-only-routines = pthread_atfork ++static-only-routines += \ ++ pthread_atfork \ ++ pthread_gettid_np \ ++ # static-only-routines ++ + libpthread-routines = libpthread-compat + libpthread-shared-only-routines = libpthread-compat + +@@ -318,6 +323,7 @@ tests = \ + tst-pthread-timedlock-lockloop \ + tst-pthread_exit-nothreads \ + tst-pthread_exit-nothreads-static \ ++ tst-pthread_gettid_np \ + tst-robust-fork \ + tst-robustpi1 \ + tst-robustpi2 \ +diff --git a/nptl/pthread_gettid_np.c b/nptl/pthread_gettid_np.c +new file mode 100644 +index 0000000000000000..b602eb7a30bf42a5 +--- /dev/null ++++ b/nptl/pthread_gettid_np.c +@@ -0,0 +1,32 @@ ++/* Get the Linux TID from a pthread_t handle. ++ Copyright (C) 2025 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; see the file COPYING.LIB. If ++ not, see . */ ++ ++#include ++#include ++ ++pid_t ++attribute_hidden ++pthread_gettid_np (pthread_t threadid) ++{ ++ clockid_t clock; ++ if (pthread_getcpuclockid (threadid, &clock) != 0) ++ return -1; ++ /* Reverse the clock ID encoding to obtain the TID. This is part of ++ the kernel/userspace interface, so it is stable ABI. */ ++ return ~(clock >> 3); ++} +diff --git a/nptl/tst-pthread_gettid_np.c b/nptl/tst-pthread_gettid_np.c +new file mode 100644 +index 0000000000000000..6a98d864e222b9f5 +--- /dev/null ++++ b/nptl/tst-pthread_gettid_np.c +@@ -0,0 +1,79 @@ ++/* Test for pthread_gettid_np. ++ Copyright (C) 2025 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; see the file COPYING.LIB. If ++ not, see . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static pthread_barrier_t barrier; ++ ++static pid_t thread_tid; ++ ++static void * ++thread_func (void *ignored) ++{ ++ thread_tid = gettid (); ++ TEST_VERIFY (thread_tid != getpid ()); ++ TEST_COMPARE (thread_tid, pthread_gettid_np (pthread_self ())); ++ xpthread_barrier_wait (&barrier); ++ /* The main thread calls pthread_gettid_np here. */ ++ xpthread_barrier_wait (&barrier); ++ return NULL; ++} ++ ++static int ++do_test (void) ++{ ++ TEST_COMPARE (pthread_gettid_np (pthread_self ()), getpid ()); ++ TEST_COMPARE (pthread_gettid_np (pthread_self ()), gettid ()); ++ ++ xpthread_barrier_init (&barrier, NULL, 2); ++ ++ pthread_t thr = xpthread_create (NULL, thread_func, NULL); ++ xpthread_barrier_wait (&barrier); ++ TEST_COMPARE (thread_tid, pthread_gettid_np (thr)); ++ xpthread_barrier_wait (&barrier); ++ ++ while (true) ++ { ++ /* Check if the kernel thread is still running. */ ++ if (tgkill (getpid (), thread_tid, 0)) ++ { ++ TEST_COMPARE (errno, ESRCH); ++ break; ++ } ++ ++ pid_t tid = pthread_gettid_np (thr); ++ if (tid != thread_tid) ++ { ++ TEST_COMPARE (tid, -1); ++ break; ++ } ++ TEST_COMPARE (sched_yield (), 0); ++ } ++ ++ TEST_VERIFY (xpthread_join (thr) == NULL); ++ ++ return 0; ++} ++ ++#include +diff --git a/sysdeps/nptl/pthread.h b/sysdeps/nptl/pthread.h +index 3d4f4a756c66750d..846e12b4ce484fb7 100644 +--- a/sysdeps/nptl/pthread.h ++++ b/sysdeps/nptl/pthread.h +@@ -1317,6 +1317,11 @@ extern int pthread_getcpuclockid (pthread_t __thread_id, + __THROW __nonnull ((2)); + #endif + ++#ifdef __USE_GNU ++/* Return the Linux TID for THREAD_ID. Returns -1 on failure. */ ++extern pid_t pthread_gettid_np (pthread_t __thread_id); ++#endif ++ + + /* Install handlers to be called when a new process is created with FORK. + The PREPARE handler is called in the parent process just before performing diff --git a/glibc-RHEL-58357-7.patch b/glibc-RHEL-58357-7.patch new file mode 100644 index 0000000..87a8adb --- /dev/null +++ b/glibc-RHEL-58357-7.patch @@ -0,0 +1,21 @@ +commit 74c68fa61b5ebf4c64605a3cc5e47154a66671ce +Author: Florian Weimer +Date: Wed Mar 12 10:23:47 2025 +0100 + + Linux: Remove attribute access from sched_getattr (bug 32781) + + The GCC attribute expects an element count, not bytes. + +diff --git a/sysdeps/unix/sysv/linux/bits/sched.h b/sysdeps/unix/sysv/linux/bits/sched.h +index a02cb69de77794fa..7c75303b80c18de2 100644 +--- a/sysdeps/unix/sysv/linux/bits/sched.h ++++ b/sysdeps/unix/sysv/linux/bits/sched.h +@@ -149,7 +149,7 @@ int sched_setattr (pid_t tid, struct sched_attr *attr, unsigned int flags) + store it in *ATTR. */ + int sched_getattr (pid_t tid, struct sched_attr *attr, unsigned int size, + unsigned int flags) +- __THROW __nonnull ((2)) __attr_access ((__write_only__, 2, 3)); ++ __THROW __nonnull ((2)); + + #endif + diff --git a/glibc-RHEL-58357-8.patch b/glibc-RHEL-58357-8.patch new file mode 100644 index 0000000..9e4d933 --- /dev/null +++ b/glibc-RHEL-58357-8.patch @@ -0,0 +1,145 @@ +commit 1ec411f7aec1bb7fb0992c8e23a42cea306305aa +Author: Florian Weimer +Date: Wed Mar 12 10:23:47 2025 +0100 + + Linux: Add new test misc/tst-sched_setattr-thread + + The straightforward sched_getattr call serves as a test for + bug 32781, too. + + Reviewed-by: Joseph Myers + +diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile +index af7fbac14534e601..463e3f52bd7e0448 100644 +--- a/sysdeps/unix/sysv/linux/Makefile ++++ b/sysdeps/unix/sysv/linux/Makefile +@@ -232,6 +232,7 @@ tests += \ + tst-quota \ + tst-rlimit-infinity \ + tst-sched_setattr \ ++ tst-sched_setattr-thread \ + tst-scm_rights \ + tst-sigtimedwait \ + tst-sync_file_range \ +diff --git a/sysdeps/unix/sysv/linux/tst-sched_setattr-thread.c b/sysdeps/unix/sysv/linux/tst-sched_setattr-thread.c +new file mode 100644 +index 0000000000000000..4600be92fd0a4c28 +--- /dev/null ++++ b/sysdeps/unix/sysv/linux/tst-sched_setattr-thread.c +@@ -0,0 +1,116 @@ ++/* Test for sched_setattr, sched_getattr involving multiple threads. ++ Copyright (C) 2024-2025 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 ++ . */ ++ ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++enum { initial_nice_value = 15 }; ++ ++/* Check that thread TID has nice value EXPECTED. */ ++static void ++check_nice_value (int tid, int expected) ++{ ++ struct sched_attr attr; ++ if (sched_getattr (tid, &attr, sizeof (attr), 0) != 0) ++ FAIL_EXIT1 ("sched_getattr (%d) failed: %m", tid); ++ TEST_COMPARE (attr.sched_policy, SCHED_OTHER); ++ int nice_value = attr.sched_nice; ++ if (attr.sched_nice != expected) ++ FAIL_EXIT1 ("thread %d: expected nice value %d, got %d" ++ " (called from thread %d)", ++ tid, expected, nice_value, (int) gettid ()); ++ printf ("info: thread %d: nice value %d (called from thread %d)\n", ++ tid, nice_value, (int) gettid ()); ++} ++ ++/* Set the nice value for TID to VALUE. */ ++static void ++set_nice_value (int tid, int value) ++{ ++ struct sched_attr attr = ++ { ++ .size = sizeof (attr), ++ .sched_policy = SCHED_OTHER, ++ .sched_nice = value, ++ }; ++ if (sched_setattr (tid, &attr, 0) != 0) ++ FAIL_EXIT1 ("sched_setattr (%d) failed: %m", tid); ++} ++ ++static pthread_barrier_t barrier; ++ ++static void * ++thread_routine (void *nice_value_ptr) ++{ ++ int nice_value = *(int *) nice_value_ptr; ++ /* Check that the nice value was inherited. */ ++ check_nice_value (gettid (), initial_nice_value); ++ xpthread_barrier_wait (&barrier); ++ /* Main thread sets nice value. */ ++ xpthread_barrier_wait (&barrier); ++ check_nice_value (gettid (), nice_value); ++ set_nice_value (gettid (), nice_value + 2); ++ xpthread_barrier_wait (&barrier); ++ /* Main thread sets checks value. */ ++ xpthread_barrier_wait (&barrier); ++ return NULL; ++} ++ ++static int ++do_test (void) ++{ ++ if (nice (initial_nice_value) != initial_nice_value) ++ FAIL_UNSUPPORTED ("cannot set nice value to initial_nice_value: %m"); ++ ++ xpthread_barrier_init (&barrier, NULL, 3); ++ ++ check_nice_value (0, initial_nice_value); ++ check_nice_value (gettid (), initial_nice_value); ++ ++ int nice0 = initial_nice_value + 1; ++ pthread_t thr0 = xpthread_create (NULL, thread_routine, &nice0); ++ int nice1 = initial_nice_value + 2; ++ pthread_t thr1 = xpthread_create (NULL, thread_routine, &nice1); ++ check_nice_value (pthread_gettid_np (thr0), initial_nice_value); ++ check_nice_value (pthread_gettid_np (thr1), initial_nice_value); ++ xpthread_barrier_wait (&barrier); ++ set_nice_value (pthread_gettid_np (thr0), nice0); ++ check_nice_value (pthread_gettid_np (thr0), nice0); ++ check_nice_value (pthread_gettid_np (thr1), initial_nice_value); ++ set_nice_value (pthread_gettid_np (thr1), nice1); ++ check_nice_value (pthread_gettid_np (thr0), nice0); ++ check_nice_value (pthread_gettid_np (thr1), nice1); ++ xpthread_barrier_wait (&barrier); ++ /* Threads set nice value. */ ++ xpthread_barrier_wait (&barrier); ++ check_nice_value (pthread_gettid_np (thr0), nice0 + 2); ++ check_nice_value (pthread_gettid_np (thr1), nice1 + 2); ++ xpthread_barrier_wait (&barrier); ++ ++ TEST_VERIFY (xpthread_join (thr1) == NULL); ++ TEST_VERIFY (xpthread_join (thr0) == NULL); ++ ++ return 0; ++} ++ ++#include diff --git a/glibc-RHEL-58357-9.patch b/glibc-RHEL-58357-9.patch new file mode 100644 index 0000000..7fe51f5 --- /dev/null +++ b/glibc-RHEL-58357-9.patch @@ -0,0 +1,20 @@ +commit 6e30efe570f1ba135747c6d8f4004e78cd24c49c +Author: Florian Weimer +Date: Wed Mar 12 11:10:14 2025 +0100 + + nptl: Include in tst-pthread_gettid_np.c + + The test uses the while (true) construct. + +diff --git a/nptl/tst-pthread_gettid_np.c b/nptl/tst-pthread_gettid_np.c +index 6a98d864e222b9f5..ced42915106f5390 100644 +--- a/nptl/tst-pthread_gettid_np.c ++++ b/nptl/tst-pthread_gettid_np.c +@@ -20,6 +20,7 @@ + #include + #include + #include ++#include + #include + #include + #include diff --git a/glibc-RHEL-72564-1.patch b/glibc-RHEL-72564-1.patch new file mode 100644 index 0000000..c61dfcb --- /dev/null +++ b/glibc-RHEL-72564-1.patch @@ -0,0 +1,636 @@ +commit 4f6dae219578d6df475864e273da40bde9d30806 +Author: Stefan Liebler +Date: Tue Apr 29 13:28:58 2025 +0200 + + S390: Add new s390 platform z17. + + The glibc-hwcaps subdirectories are extended by "z17". Libraries are loaded if + the z17 facility bits are active: + - Miscellaneous-instruction-extensions facility 4 + - Vector-enhancements-facility 3 + - Vector-Packed-Decimal-Enhancement Facility 3 + - CPU: Concurrent-Functions Facility + + tst-glibc-hwcaps.c is extended in order to test z17 via new marker6. + In case of running on a z17 with a kernel not recognizing z17 yet, + AT_PLATFORM will be z900 but vector-bit in AT_HWCAP is set. This situation + is now recognized and this testcase does not fail. + + A fatal glibc error is dumped if glibc was build with architecture + level set for z17, but run on an older machine (See dl-hwcap-check.h). + Note, you might get an SIGILL before this check if you don't use: + configure --with-rtld-early-cflags=-march= + + ld.so --list-diagnostics now also dumps information about s390.cpu_features. + + Independent from z17, the s390x kernel won't introduce new HWCAP-Bits if there + is no special handling needed in kernel itself. For z17, we don't have new + HWCAP flags, but have to check the facility bits retrieved by + stfle-instruction. + + Instead of storing all the stfle-bits (currently four 64bit values) in the + cpu_features struct, we now only store those bits, which are needed within + glibc itself. Note that we have this list twice, one with original values and + the other one which can be filtered with GLIBC_TUNABLES=glibc.cpu.hwcaps. + Those new fields are stored in so far reserved space in cpu_features struct. + Thus processes started in between the update of glibc package and we e.g. have + a new ld.so and an old libc.so, won't crash. The glibc internal ifunc-resolvers + would not select the best optimized variant. + + The users of stfle-bits are also updated: + - parsing of GLIBC_TUNABLES=glibc.cpu.hwcaps + - glibc internal ifunc-resolvers + - __libc_ifunc_impl_list + - sysconf + +Conflicts: + elf/Makefile (fixup context) + sysdeps/s390/s390-64/dl-hwcaps-subdirs.c (fixup context) + +diff --git a/elf/Makefile b/elf/Makefile +index 0d34de3b2c99e5bd..a46c4f69d98553f7 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -701,6 +701,12 @@ modules-names += \ + libmarkermod5-3 \ + libmarkermod5-4 \ + libmarkermod5-5 \ ++ libmarkermod6-1 \ ++ libmarkermod6-2 \ ++ libmarkermod6-3 \ ++ libmarkermod6-4 \ ++ libmarkermod6-5 \ ++ libmarkermod6-6 \ + libtracemod1-1 \ + libtracemod2-1 \ + libtracemod3-1 \ +@@ -2652,6 +2658,7 @@ LDFLAGS-libmarkermod2-1.so += -Wl,-soname,libmarkermod2.so + LDFLAGS-libmarkermod3-1.so += -Wl,-soname,libmarkermod3.so + LDFLAGS-libmarkermod4-1.so += -Wl,-soname,libmarkermod4.so + LDFLAGS-libmarkermod5-1.so += -Wl,-soname,libmarkermod5.so ++LDFLAGS-libmarkermod6-1.so += -Wl,-soname,libmarkermod6.so + $(objpfx)libmarkermod%.os : markermodMARKER-VALUE.c + $(compile-command.c) \ + -DMARKER=marker$(firstword $(subst -, ,$*)) \ +@@ -2666,6 +2673,8 @@ $(objpfx)libmarkermod4.so: $(objpfx)libmarkermod4-1.so + cp $< $@ + $(objpfx)libmarkermod5.so: $(objpfx)libmarkermod5-1.so + cp $< $@ ++$(objpfx)libmarkermod6.so: $(objpfx)libmarkermod6-1.so ++ cp $< $@ + + # tst-glibc-hwcaps-prepend checks that --glibc-hwcaps-prepend is + # preferred over auto-detected subdirectories. +diff --git a/elf/tst-glibc-hwcaps-cache.script b/elf/tst-glibc-hwcaps-cache.script +index d58fc8c5de3c5198..af89e9c6f811f483 100644 +--- a/elf/tst-glibc-hwcaps-cache.script ++++ b/elf/tst-glibc-hwcaps-cache.script +@@ -5,6 +5,7 @@ cp $B/elf/libmarkermod2-1.so $L/libmarkermod2.so + cp $B/elf/libmarkermod3-1.so $L/libmarkermod3.so + cp $B/elf/libmarkermod4-1.so $L/libmarkermod4.so + cp $B/elf/libmarkermod5-1.so $L/libmarkermod5.so ++cp $B/elf/libmarkermod6-1.so $L/libmarkermod6.so + + mkdirp 0770 $L/glibc-hwcaps/power9 + cp $B/elf/libmarkermod2-2.so $L/glibc-hwcaps/power9/libmarkermod2.so +@@ -26,6 +27,12 @@ cp $B/elf/libmarkermod5-2.so $L/glibc-hwcaps/z13/libmarkermod5.so + cp $B/elf/libmarkermod5-3.so $L/glibc-hwcaps/z14/libmarkermod5.so + cp $B/elf/libmarkermod5-4.so $L/glibc-hwcaps/z15/libmarkermod5.so + cp $B/elf/libmarkermod5-5.so $L/glibc-hwcaps/z16/libmarkermod5.so ++mkdirp 0770 $L/glibc-hwcaps/z17 ++cp $B/elf/libmarkermod6-2.so $L/glibc-hwcaps/z13/libmarkermod6.so ++cp $B/elf/libmarkermod6-3.so $L/glibc-hwcaps/z14/libmarkermod6.so ++cp $B/elf/libmarkermod6-4.so $L/glibc-hwcaps/z15/libmarkermod6.so ++cp $B/elf/libmarkermod6-5.so $L/glibc-hwcaps/z16/libmarkermod6.so ++cp $B/elf/libmarkermod6-6.so $L/glibc-hwcaps/z17/libmarkermod6.so + + mkdirp 0770 $L/glibc-hwcaps/x86-64-v2 + cp $B/elf/libmarkermod2-2.so $L/glibc-hwcaps/x86-64-v2/libmarkermod2.so +diff --git a/sysdeps/s390/cpu-features.c b/sysdeps/s390/cpu-features.c +index bc4ad601f1d1db87..f44270bd76697c0b 100644 +--- a/sysdeps/s390/cpu-features.c ++++ b/sysdeps/s390/cpu-features.c +@@ -26,7 +26,7 @@ + + #define S390_COPY_CPU_FEATURES(SRC_PTR, DEST_PTR) \ + (DEST_PTR)->hwcap = (SRC_PTR)->hwcap; \ +- (DEST_PTR)->stfle_bits[0] = (SRC_PTR)->stfle_bits[0]; ++ (DEST_PTR)->stfle_filtered = (SRC_PTR)->stfle_filtered; + + static void + TUNABLE_CALLBACK (set_hwcaps) (tunable_val_t *valp) +@@ -76,7 +76,7 @@ TUNABLE_CALLBACK (set_hwcaps) (tunable_val_t *valp) + disable = true; + hwcap_mask = HWCAP_S390_VXRS | HWCAP_S390_VXRS_EXT + | HWCAP_S390_VXRS_EXT2; +- stfle_bits0_mask = S390_STFLE_MASK_ARCH13_MIE3; ++ stfle_bits0_mask = S390_STFLE_BIT61_ARCH13_MIE3; + } + else if (tunable_str_comma_strcmp_cte (&t, "z13") + || tunable_str_comma_strcmp_cte (&t, "arch11")) +@@ -84,7 +84,7 @@ TUNABLE_CALLBACK (set_hwcaps) (tunable_val_t *valp) + reset_features = true; + disable = true; + hwcap_mask = HWCAP_S390_VXRS_EXT | HWCAP_S390_VXRS_EXT2; +- stfle_bits0_mask = S390_STFLE_MASK_ARCH13_MIE3; ++ stfle_bits0_mask = S390_STFLE_BIT61_ARCH13_MIE3; + } + else if (tunable_str_comma_strcmp_cte (&t, "z14") + || tunable_str_comma_strcmp_cte (&t, "arch12")) +@@ -92,12 +92,14 @@ TUNABLE_CALLBACK (set_hwcaps) (tunable_val_t *valp) + reset_features = true; + disable = true; + hwcap_mask = HWCAP_S390_VXRS_EXT2; +- stfle_bits0_mask = S390_STFLE_MASK_ARCH13_MIE3; ++ stfle_bits0_mask = S390_STFLE_BIT61_ARCH13_MIE3; + } + else if (tunable_str_comma_strcmp_cte (&t, "z15") + || tunable_str_comma_strcmp_cte (&t, "z16") ++ || tunable_str_comma_strcmp_cte (&t, "z17") + || tunable_str_comma_strcmp_cte (&t, "arch13") +- || tunable_str_comma_strcmp_cte (&t, "arch14")) ++ || tunable_str_comma_strcmp_cte (&t, "arch14") ++ || tunable_str_comma_strcmp_cte (&t, "arch15")) + { + /* For z15 or newer we don't have to disable something, but we have + to reset to the original values. */ +@@ -124,7 +126,7 @@ TUNABLE_CALLBACK (set_hwcaps) (tunable_val_t *valp) + hwcap_mask |= HWCAP_S390_VXRS | HWCAP_S390_VXRS_EXT; + } + else if (tunable_str_comma_strcmp_cte (&t, "STFLE_MIE3")) +- stfle_bits0_mask = S390_STFLE_MASK_ARCH13_MIE3; ++ stfle_bits0_mask = S390_STFLE_BIT61_ARCH13_MIE3; + + /* Perform the actions determined above. */ + if (reset_features) +@@ -143,22 +145,26 @@ TUNABLE_CALLBACK (set_hwcaps) (tunable_val_t *valp) + if (stfle_bits0_mask != 0ULL) + { + if (disable) +- cpu_features_curr.stfle_bits[0] &= ~stfle_bits0_mask; ++ cpu_features_curr.stfle_filtered &= ~stfle_bits0_mask; + else +- cpu_features_curr.stfle_bits[0] |= stfle_bits0_mask; ++ cpu_features_curr.stfle_filtered |= stfle_bits0_mask; + } + } + + /* Copy back the features after checking that no unsupported features were + enabled by user. */ + cpu_features->hwcap = cpu_features_curr.hwcap & cpu_features_orig.hwcap; +- cpu_features->stfle_bits[0] = cpu_features_curr.stfle_bits[0] +- & cpu_features_orig.stfle_bits[0]; ++ cpu_features->stfle_filtered = cpu_features_curr.stfle_filtered ++ & cpu_features_orig.stfle_filtered; + } + + static inline void +-init_cpu_features (struct cpu_features *cpu_features) ++init_cpu_features_no_tunables (struct cpu_features *cpu_features) + { ++ /* Only initialize once. */ ++ if (cpu_features->hwcap != 0) ++ return; ++ + /* Fill cpu_features as passed by kernel and machine. */ + cpu_features->hwcap = GLRO(dl_hwcap); + +@@ -167,20 +173,57 @@ init_cpu_features (struct cpu_features *cpu_features) + && (cpu_features->hwcap & HWCAP_S390_ZARCH) + && (cpu_features->hwcap & HWCAP_S390_HIGH_GPRS))) + { +- register unsigned long reg0 __asm__("0") = 0; ++ unsigned long long stfle_bits[4] = { 0 }; ++ register unsigned long reg0 __asm__("0") = 3; + __asm__ __volatile__(".machine push" "\n\t" + ".machine \"z9-109\"" "\n\t" + ".machinemode \"zarch_nohighgprs\"\n\t" + "stfle %0" "\n\t" + ".machine pop" "\n" +- : "=QS" (cpu_features->stfle_bits[0]), ++ : "=QS" (stfle_bits[0]), + "+d" (reg0) + : : "cc"); ++ ++ unsigned long long internal_stfle_bits = 0; ++ ++ /* Facility bit 34: z10: General instructions extension. */ ++ if ((stfle_bits[0] & (1ULL << (63 - 34))) != 0) ++ internal_stfle_bits |= S390_STFLE_BIT34_Z10; ++ ++ /* Facility bit 45: z196: Distinct operands, popcount, ... */ ++ if ((stfle_bits[0] & (1ULL << (63 - 45))) != 0) ++ internal_stfle_bits |= S390_STFLE_BIT45_Z196; ++ ++ /* Facility bit 61: arch13/z15: Miscellaneous-Instruction-Extensions ++ Facility 3, e.g. mvcrl. */ ++ if ((stfle_bits[0] & (1ULL << (63 - 61))) != 0) ++ internal_stfle_bits |= S390_STFLE_BIT61_ARCH13_MIE3; ++ ++ /* Facility bit 84: arch15/z17: Miscellaneous-instruction-extensions 4 */ ++ if ((stfle_bits[1] & (1ULL << (127 - 84))) != 0) ++ internal_stfle_bits |= S390_STFLE_BIT84_ARCH15_MIE4; ++ ++ /* Facility bit 198: arch15/z17: Vector-enhancements-facility 3 */ ++ if ((stfle_bits[3] & (1ULL << (255 - 198))) != 0) ++ internal_stfle_bits |= S390_STFLE_BIT198_ARCH15_VXRS_EXT3; ++ ++ /* Facility bit 199: arch15/z17: Vector-Packed-Decimal-Enhancement 3 */ ++ if ((stfle_bits[3] & (1ULL << (255 - 199))) != 0) ++ internal_stfle_bits |= S390_STFLE_BIT199_ARCH15_VXRS_PDE3; ++ ++ /* Facility bit 201: arch15/z17: CPU: Concurrent-Functions Facility */ ++ if ((stfle_bits[3] & (1ULL << (255 - 201))) != 0) ++ internal_stfle_bits |= S390_STFLE_BIT201_ARCH15_CON; ++ ++ cpu_features->stfle_orig = internal_stfle_bits; ++ cpu_features->stfle_filtered = internal_stfle_bits; + } +- else +- { +- cpu_features->stfle_bits[0] = 0ULL; +- } ++} ++ ++static inline void ++init_cpu_features (struct cpu_features *cpu_features) ++{ ++ init_cpu_features_no_tunables (cpu_features); + + TUNABLE_GET (glibc, cpu, hwcaps, tunable_val_t *, TUNABLE_CALLBACK (set_hwcaps)); + } +diff --git a/sysdeps/s390/cpu-features.h b/sysdeps/s390/cpu-features.h +index 6efea28e3548e25e..fa92fbeb44a49969 100644 +--- a/sysdeps/s390/cpu-features.h ++++ b/sysdeps/s390/cpu-features.h +@@ -18,29 +18,58 @@ + #ifndef __CPU_FEATURES_S390X_H + # define __CPU_FEATURES_S390X_H + +-#define S390_STFLE_BITS_Z10 34 /* General instructions extension */ +-#define S390_STFLE_BITS_Z196 45 /* Distinct operands, pop ... */ +-#define S390_STFLE_BITS_ARCH13_MIE3 61 /* Miscellaneous-Instruction-Extensions +- Facility 3, e.g. mvcrl. */ ++/* The following stfle bit definitions are intended to be used for the ++ glibc internal stfle_orig and stfle_filtered fields in cpu_features ++ struct. They can't be used on the double words retrieved by the ++ stfle-instruction. */ + +-#define S390_STFLE_MASK_ARCH13_MIE3 (1ULL << (63 - S390_STFLE_BITS_ARCH13_MIE3)) ++/* Facility bit 34: z10: General instructions extension. */ ++#define S390_STFLE_BIT34_Z10 (1ULL << 0) + ++/* Facility bit 45: z196: Distinct operands, popcount, ... */ ++#define S390_STFLE_BIT45_Z196 (1ULL << 1) + +-#define S390_IS_ARCH13_MIE3(STFLE_BITS_ARRAY) \ +- (((STFLE_BITS_ARRAY)[0] & S390_STFLE_MASK_ARCH13_MIE3) != 0) ++/* Facility bit 61: arch13/z15: Miscellaneous-Instruction-Extensions ++ Facility 3, e.g. mvcrl. */ ++#define S390_STFLE_BIT61_ARCH13_MIE3 (1ULL << 2) + +-#define S390_IS_Z196(STFLE_BITS_ARRAY) \ +- (((STFLE_BITS_ARRAY)[0] & (1ULL << (63 - S390_STFLE_BITS_Z196))) != 0) ++/* Facility bit 84: arch15/z17: Miscellaneous-instruction-extensions ++ facility 4 */ ++#define S390_STFLE_BIT84_ARCH15_MIE4 (1ULL << 3) + +-#define S390_IS_Z10(STFLE_BITS_ARRAY) \ +- (((STFLE_BITS_ARRAY)[0] & (1ULL << (63 - S390_STFLE_BITS_Z10))) != 0) ++/* Facility bit 198: arch15/z17: Vector-enhancements-facility 3 */ ++#define S390_STFLE_BIT198_ARCH15_VXRS_EXT3 (1ULL << 4) ++ ++/* Facility bit 199: arch15/z17: Vector-Packed-Decimal-Enhancement ++ Facility 3 */ ++#define S390_STFLE_BIT199_ARCH15_VXRS_PDE3 (1ULL << 5) ++ ++/* Facility bit 201: arch15/z17: CPU: Concurrent-Functions Facility */ ++#define S390_STFLE_BIT201_ARCH15_CON (1ULL << 6) ++ ++#define S390_IS_ARCH15(STFLE_BITS) \ ++ ((((STFLE_BITS) & S390_STFLE_BIT84_ARCH15_MIE4) != 0) \ ++ && (((STFLE_BITS) & S390_STFLE_BIT198_ARCH15_VXRS_EXT3) != 0) \ ++ && (((STFLE_BITS) & S390_STFLE_BIT199_ARCH15_VXRS_PDE3) != 0) \ ++ && (((STFLE_BITS) & S390_STFLE_BIT201_ARCH15_CON) != 0)) ++ ++#define S390_IS_ARCH13_MIE3(STFLE_BITS) \ ++ (((STFLE_BITS) & S390_STFLE_BIT61_ARCH13_MIE3) != 0) ++ ++#define S390_IS_Z196(STFLE_BITS) \ ++ (((STFLE_BITS) & S390_STFLE_BIT45_Z196) != 0) ++ ++#define S390_IS_Z10(STFLE_BITS) \ ++ (((STFLE_BITS) & S390_STFLE_BIT34_Z10) != 0) + + struct cpu_features + { + unsigned long int hwcap; + unsigned long int __reserved_hwcap2; +- unsigned long long stfle_bits[3]; +- unsigned long long __reserved[11]; ++ unsigned long long __reserved; ++ unsigned long long stfle_orig; ++ unsigned long long stfle_filtered; ++ unsigned long long __reserved2[11]; + }; + + #endif /* __CPU_FEATURES_S390X_H */ +diff --git a/sysdeps/s390/dl-diagnostics-cpu.c b/sysdeps/s390/dl-diagnostics-cpu.c +new file mode 100644 +index 0000000000000000..426af2df7a34b55e +--- /dev/null ++++ b/sysdeps/s390/dl-diagnostics-cpu.c +@@ -0,0 +1,37 @@ ++/* Print CPU diagnostics data in ld.so. s390 version. ++ Copyright (C) 2025 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 ++ . */ ++ ++#include ++#include ++#include ++ ++static void ++print_cpu_features_value (const char *label, uint64_t value) ++{ ++ _dl_printf ("s390.cpu_features."); ++ _dl_diagnostics_print_labeled_value (label, value); ++} ++ ++void ++_dl_diagnostics_cpu (void) ++{ ++ const struct cpu_features *cpu_features = &GLRO(dl_s390_cpu_features); ++ print_cpu_features_value ("hwcap", cpu_features->hwcap); ++ print_cpu_features_value ("stfle_orig", cpu_features->stfle_orig); ++ print_cpu_features_value ("stfle_filtered", cpu_features->stfle_filtered); ++} +diff --git a/sysdeps/s390/multiarch/ifunc-impl-list.c b/sysdeps/s390/multiarch/ifunc-impl-list.c +index b05b86f6bd2f76c5..48252785cdcb0b0c 100644 +--- a/sysdeps/s390/multiarch/ifunc-impl-list.c ++++ b/sysdeps/s390/multiarch/ifunc-impl-list.c +@@ -81,8 +81,8 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array, + /* Get hardware information. */ + const struct cpu_features *features = &GLRO(dl_s390_cpu_features); + unsigned long int dl_hwcap __attribute__ ((unused)) = features->hwcap; +- const unsigned long long * __attribute__((unused)) stfle_bits +- = features->stfle_bits; ++ const unsigned long long __attribute__((unused)) stfle_bits ++ = features->stfle_filtered; + + #if HAVE_MEMSET_IFUNC + IFUNC_IMPL (i, name, memset, +diff --git a/sysdeps/s390/multiarch/ifunc-resolve.h b/sysdeps/s390/multiarch/ifunc-resolve.h +index 2a0c4a56a4a8b627..d63b624d0f5b8f1b 100644 +--- a/sysdeps/s390/multiarch/ifunc-resolve.h ++++ b/sysdeps/s390/multiarch/ifunc-resolve.h +@@ -22,7 +22,7 @@ + #include + + #define s390_libc_ifunc_expr_stfle_init() \ +- const unsigned long long *stfle_bits = features->stfle_bits; ++ const unsigned long long stfle_bits = features->stfle_filtered; + + #define s390_libc_ifunc_expr_init() \ + const struct cpu_features *features = &GLRO(dl_s390_cpu_features); \ +diff --git a/sysdeps/s390/s390-64/Makefile b/sysdeps/s390/s390-64/Makefile +index 66ed844e68df5159..991025cd2a97c203 100644 +--- a/sysdeps/s390/s390-64/Makefile ++++ b/sysdeps/s390/s390-64/Makefile +@@ -11,7 +11,8 @@ $(objpfx)tst-glibc-hwcaps: \ + $(objpfx)libmarkermod2-1.so \ + $(objpfx)libmarkermod3-1.so \ + $(objpfx)libmarkermod4-1.so \ +- $(objpfx)libmarkermod5-1.so ++ $(objpfx)libmarkermod5-1.so \ ++ $(objpfx)libmarkermod6-1.so + $(objpfx)tst-glibc-hwcaps.out: \ + $(objpfx)libmarkermod2.so \ + $(objpfx)glibc-hwcaps/z13/libmarkermod2.so \ +@@ -26,7 +27,14 @@ $(objpfx)tst-glibc-hwcaps.out: \ + $(objpfx)glibc-hwcaps/z13/libmarkermod5.so \ + $(objpfx)glibc-hwcaps/z14/libmarkermod5.so \ + $(objpfx)glibc-hwcaps/z15/libmarkermod5.so \ +- $(objpfx)glibc-hwcaps/z16/libmarkermod5.so ++ $(objpfx)glibc-hwcaps/z16/libmarkermod5.so \ ++ $(objpfx)libmarkermod6.so \ ++ $(objpfx)glibc-hwcaps/z13/libmarkermod6.so \ ++ $(objpfx)glibc-hwcaps/z14/libmarkermod6.so \ ++ $(objpfx)glibc-hwcaps/z15/libmarkermod6.so \ ++ $(objpfx)glibc-hwcaps/z16/libmarkermod6.so \ ++ $(objpfx)glibc-hwcaps/z17/libmarkermod6.so ++ + + $(objpfx)glibc-hwcaps/z13/libmarkermod2.so: $(objpfx)libmarkermod2-2.so + $(make-target-directory) +@@ -58,6 +66,21 @@ $(objpfx)glibc-hwcaps/z15/libmarkermod5.so: $(objpfx)libmarkermod5-4.so + $(objpfx)glibc-hwcaps/z16/libmarkermod5.so: $(objpfx)libmarkermod5-5.so + $(make-target-directory) + cp $< $@ ++$(objpfx)glibc-hwcaps/z13/libmarkermod6.so: $(objpfx)libmarkermod6-2.so ++ $(make-target-directory) ++ cp $< $@ ++$(objpfx)glibc-hwcaps/z14/libmarkermod6.so: $(objpfx)libmarkermod6-3.so ++ $(make-target-directory) ++ cp $< $@ ++$(objpfx)glibc-hwcaps/z15/libmarkermod6.so: $(objpfx)libmarkermod6-4.so ++ $(make-target-directory) ++ cp $< $@ ++$(objpfx)glibc-hwcaps/z16/libmarkermod6.so: $(objpfx)libmarkermod6-5.so ++ $(make-target-directory) ++ cp $< $@ ++$(objpfx)glibc-hwcaps/z17/libmarkermod6.so: $(objpfx)libmarkermod6-6.so ++ $(make-target-directory) ++ cp $< $@ + + + ifeq (no,$(build-hardcoded-path-in-tests)) +diff --git a/sysdeps/s390/s390-64/dl-hwcap-check.h b/sysdeps/s390/s390-64/dl-hwcap-check.h +index 6ad3242cc9940468..433a1ebbe8593d92 100644 +--- a/sysdeps/s390/s390-64/dl-hwcap-check.h ++++ b/sysdeps/s390/s390-64/dl-hwcap-check.h +@@ -25,8 +25,23 @@ + static inline void + dl_hwcap_check (void) + { +-#if defined __ARCH__ +-# if GCCMACRO__ARCH__ >= 14 ++ /* Note: The s390x kernel won't introduce new HWCAP-Bits if there is ++ no special handling needed in kernel itself. Thus we have have ++ to check the facility-list retrieved with the stfle instruction. ++ We already have a common storage of this list in cpu-features.c. ++ This dl-hwcap-check.h file is included in ++ sysdeps/unix/sysv/linux/dl-sysdep.c, where also dl-machine.h and ++ cpu-features.c is included. Therefore we don't have a special ++ include here. */ ++ ++#if defined GCCMACRO__ARCH__ ++# if GCCMACRO__ARCH__ >= 15 ++ init_cpu_features_no_tunables (&GLRO(dl_s390_cpu_features)); ++ if (!(S390_IS_ARCH15 (GLRO(dl_s390_cpu_features).stfle_orig))) ++ _dl_fatal_printf ("\ ++Fatal glibc error: CPU lacks VXRS_EXT3/VXRS_PDE3/MIE4/Concurrent-functions \ ++support (z17 or later required)\n"); ++# elif GCCMACRO__ARCH__ >= 14 + if (!(GLRO(dl_hwcap) & HWCAP_S390_VXRS_PDE2)) + _dl_fatal_printf ("\ + Fatal glibc error: CPU lacks VXRS_PDE2 support (z16 or later required)\n"); +@@ -39,7 +54,7 @@ Fatal glibc error: CPU lacks VXRS_EXT2 support (z15 or later required)\n"); + _dl_fatal_printf ("\ + Fatal glibc error: CPU lacks VXE support (z14 or later required)\n"); + # endif +-#endif /* __ARCH__ */ ++#endif /* GCCMACRO__ARCH__ */ + } + + #endif /* _DL_HWCAP_CHECK_H */ +diff --git a/sysdeps/s390/s390-64/dl-hwcaps-subdirs.c b/sysdeps/s390/s390-64/dl-hwcaps-subdirs.c +index 0a8cce1d3c2bccd5..11c4bbe4f2ec6c38 100644 +--- a/sysdeps/s390/s390-64/dl-hwcaps-subdirs.c ++++ b/sysdeps/s390/s390-64/dl-hwcaps-subdirs.c +@@ -18,9 +18,10 @@ + + #include + #include ++#include + +-const char _dl_hwcaps_subdirs[] = "z16:z15:z14:z13"; +-enum { subdirs_count = 4 }; /* Number of components in _dl_hwcaps_subdirs. */ ++const char _dl_hwcaps_subdirs[] = "z17:z16:z15:z14:z13"; ++enum { subdirs_count = 5 }; /* Number of components in _dl_hwcaps_subdirs. */ + + uint32_t + _dl_hwcaps_subdirs_active (void) +@@ -57,5 +58,12 @@ _dl_hwcaps_subdirs_active (void) + return _dl_hwcaps_subdirs_build_bitmask (subdirs_count, active); + ++active; + ++ /* z17. ++ Note: The kernel has not introduced new HWCAP bits as the new facilities do ++ not require kernel interaction. Thus we check the features via stfle. */ ++ if (!(S390_IS_ARCH15 (GLRO(dl_s390_cpu_features).stfle_orig))) ++ return _dl_hwcaps_subdirs_build_bitmask (subdirs_count, active); ++ ++active; ++ + return _dl_hwcaps_subdirs_build_bitmask (subdirs_count, active); + } +diff --git a/sysdeps/s390/s390-64/tst-glibc-hwcaps.c b/sysdeps/s390/s390-64/tst-glibc-hwcaps.c +index a7dec68d32d2b8c2..391816dfde49c93d 100644 +--- a/sysdeps/s390/s390-64/tst-glibc-hwcaps.c ++++ b/sysdeps/s390/s390-64/tst-glibc-hwcaps.c +@@ -26,35 +26,53 @@ extern int marker2 (void); + extern int marker3 (void); + extern int marker4 (void); + extern int marker5 (void); ++extern int marker6 (void); + + /* Return the arch level, 10 for the baseline libmarkermod*.so's. */ + static int + compute_level (void) + { + const char *platform = (const char *) getauxval (AT_PLATFORM); ++ const unsigned long int hwcap = getauxval (AT_HWCAP); ++ const int latest_level = 15; + + /* The arch* versions refer to the edition of the Principles of + Operation, and they are off by two when compared with the recent + product names. (The code below should not be considered an + accurate mapping to Principles of Operation editions for earlier + AT_PLATFORM strings). */ +- if (strcmp (platform, "z900") == 0) +- return 10; +- if (strcmp (platform, "z990") == 0) +- return 10; +- if (strcmp (platform, "z9-109") == 0) +- return 10; +- if (strcmp (platform, "z10") == 0) +- return 10; +- if (strcmp (platform, "z196") == 0) +- return 10; +- if (strcmp (platform, "zEC12") == 0) +- return 10; ++ if ((strcmp (platform, "z900") == 0) ++ || (strcmp (platform, "z990") == 0) ++ || (strcmp (platform, "z9-109") == 0) ++ || (strcmp (platform, "z10") == 0) ++ || (strcmp (platform, "z196") == 0) ++ || (strcmp (platform, "zEC12") == 0)) ++ { ++ if ((hwcap & HWCAP_S390_VX) == 0) ++ { ++ /* As vector-support was introduced with the newer z13 ++ architecture, we are really on one of the tested older ++ architectures. */ ++ return 10; ++ } ++ else ++ { ++ /* According to AT_PLATFORM we are on an older architecture ++ without vector-support, but according to HWCAPs vector ++ registers are supported. This means we are running on a ++ new architecture which is not yet known by the kernel. ++ Thus the default AT_PLATFORM string is used, which is the ++ oldest supported one. For this test, assume we are on ++ the latest known architecture. See ++ /arch/s390/kernel/processor.c:setup_elf_platform(). ++ */ ++ return latest_level; ++ } ++ } + + /* If we are running on z13 or newer and the kernel was booted with novx, + then AT_PLATFORM is z13 or newer, but _dl_hwcaps_subdirs_active will + return zero and the _dl_hwcaps_subdirs are not searched. */ +- const unsigned long int hwcap = getauxval (AT_HWCAP); + if ((hwcap & HWCAP_S390_VX) == 0) + return 10; + +@@ -66,9 +84,12 @@ compute_level (void) + return 13; + if (strcmp (platform, "z16") == 0) + return 14; ++ if (strcmp (platform, "z17") == 0) ++ return latest_level; ++ + printf ("warning: unrecognized AT_PLATFORM value: %s\n", platform); +- /* Assume that the new platform supports z16. */ +- return 14; ++ /* Assume that the new platform supports the latest known architecture. */ ++ return latest_level; + } + + static int +@@ -80,6 +101,7 @@ do_test (void) + TEST_COMPARE (marker3 (), MIN (level - 9, 3)); + TEST_COMPARE (marker4 (), MIN (level - 9, 4)); + TEST_COMPARE (marker5 (), MIN (level - 9, 5)); ++ TEST_COMPARE (marker6 (), MIN (level - 9, 6)); + return 0; + } + +diff --git a/sysdeps/unix/sysv/linux/s390/sysconf.c b/sysdeps/unix/sysv/linux/s390/sysconf.c +index ca25822811ae500e..8b50a7f86056664e 100644 +--- a/sysdeps/unix/sysv/linux/s390/sysconf.c ++++ b/sysdeps/unix/sysv/linux/s390/sysconf.c +@@ -65,7 +65,7 @@ get_cache_info (int level, int attr, int type) + return 0L; + } + +- if (!S390_IS_Z10 (features->stfle_bits)) ++ if (!S390_IS_Z10 (features->stfle_orig)) + { + /* We are at least on a z9 machine. + Return 256byte for LINESIZE for L1 d/i-cache, diff --git a/glibc-RHEL-72564-2.patch b/glibc-RHEL-72564-2.patch new file mode 100644 index 0000000..ea1afdf --- /dev/null +++ b/glibc-RHEL-72564-2.patch @@ -0,0 +1,42 @@ +Downstream patch. + +From: Stefan Liebler +Date: Tue, 6 May 2025 14:49:22 +0200 +Subject: [PATCH 2/2] S390: Add z17 to legacy hwcap/platform mechanism + + As glibc 2.39 is still generating ld.so.cache entries for libraries + in /usr/lib64/z16/libtest.so, do the same for z17 to have the same behavior. + + See upstream glibc commits: + commit b78ff5a25dc8ba9d8c6df10bb0a533254bdd193f + 'elf: Remove legacy hwcaps support from ldconfig' + https://sourceware.org/git/?p=glibc.git;a=commit;h=b78ff5a25dc8ba9d8c6df10bb0a533254bdd193f + + commit c5aa5fd40adc81c4f0b18e01f329aeaf86518c7b + 'elf: Remove loading legacy hwcaps/platform entries in dynamic loader' + https://sourceware.org/git/?p=glibc.git;a=commit;h=c5aa5fd40adc81c4f0b18e01f329aeaf86518c7b + +diff --git a/sysdeps/s390/dl-procinfo-s390.c b/sysdeps/s390/dl-procinfo-s390.c +index 2821e40cb141249c..95cd3c38396c7f26 100644 +--- a/sysdeps/s390/dl-procinfo-s390.c ++++ b/sysdeps/s390/dl-procinfo-s390.c +@@ -28,5 +28,5 @@ const char _dl_s390_cap_flags[_DL_HWCAP_COUNT][9] = + const char _dl_s390_platforms[_DL_PLATFORMS_COUNT][7] = + { + "g5", "z900", "z990", "z9-109", "z10", "z196", "zEC12", "z13", "z14", "z15", +- "z16" ++ "z16", "z17" + }; +diff --git a/sysdeps/s390/dl-procinfo.h b/sysdeps/s390/dl-procinfo.h +index 38e77f7ad9858701..c77557cf57d94fef 100644 +--- a/sysdeps/s390/dl-procinfo.h ++++ b/sysdeps/s390/dl-procinfo.h +@@ -23,7 +23,7 @@ + #define _DL_HWCAP_COUNT 23 + extern const char _dl_s390_cap_flags[_DL_HWCAP_COUNT][9] attribute_hidden; + +-#define _DL_PLATFORMS_COUNT 11 ++#define _DL_PLATFORMS_COUNT 12 + extern const char _dl_s390_platforms[_DL_PLATFORMS_COUNT][7] attribute_hidden; + + /* The kernel provides up to 32 capability bits with elf_hwcap. */ diff --git a/glibc-upstream-2.39-213.patch b/glibc-upstream-2.39-213.patch new file mode 100644 index 0000000..17ed68b --- /dev/null +++ b/glibc-upstream-2.39-213.patch @@ -0,0 +1,27 @@ +commit b6ea8902a72fb746ae5cd71ddf1172c5ead89972 +Author: Wilco Dijkstra +Date: Fri Jun 27 14:10:55 2025 +0000 + + AArch64: Avoid memset ifunc in cpu-features.c [BZ #33112] + + During early startup memcpy or memset must not be called since many targets + use ifuncs for them which won't be initialized yet. Security hardening may + use -ftrivial-auto-var-init=zero which inserts calls to memset. Redirect + memset to memset_generic by including dl-symbol-redir-ifunc.h in cpu-features.c. + This fixes BZ #33112. + + Reviewed-by: Adhemerval Zanella + (cherry picked from commit 681a24ae4d0cb8ed92de98b4da660308840b09ba) + +diff --git a/sysdeps/unix/sysv/linux/aarch64/cpu-features.c b/sysdeps/unix/sysv/linux/aarch64/cpu-features.c +index c0b047bc0dbeae42..0ad55a0c7f66618f 100644 +--- a/sysdeps/unix/sysv/linux/aarch64/cpu-features.c ++++ b/sysdeps/unix/sysv/linux/aarch64/cpu-features.c +@@ -23,6 +23,7 @@ + #include + #include + #include ++#include + + #define DCZID_DZP_MASK (1 << 4) + #define DCZID_BS_MASK (0xf) diff --git a/glibc-upstream-2.39-214.patch b/glibc-upstream-2.39-214.patch new file mode 100644 index 0000000..d4732e8 --- /dev/null +++ b/glibc-upstream-2.39-214.patch @@ -0,0 +1,1638 @@ +commit 3a78a276a37720019ac714e4180910cd5e5d5d58 +Author: Dylan Fleming +Date: Mon May 19 11:36:51 2025 +0000 + + AArch64: Optimize inverse trig functions + + Improve performance of Inverse trig functions by altering how coefficients are + loaded. + + Performance improvement on Neoverse V1: + SVE acos 14% + AdvSIMD acos 6% + + AdvSIMD asin 6% + SVE asin 5% + AdvSIMD asinf 2% + + AdvSIMD atanf 22% + SVE atanf 20% + SVE atan 11% + AdvSIMD atan 5% + + SVE atan2 7% + SVE atan2f 4% + AdvSIMD atan2f 3% + AdvSIMD atan2 2% + + Reviewed-by: Wilco Dijkstra + (cherry picked from commit 1e84509e0041c0a83997aba602a585bb3b8285f0) + +diff --git a/sysdeps/aarch64/fpu/acos_advsimd.c b/sysdeps/aarch64/fpu/acos_advsimd.c +index 0a86c9823a279766..aaf874f4eab63762 100644 +--- a/sysdeps/aarch64/fpu/acos_advsimd.c ++++ b/sysdeps/aarch64/fpu/acos_advsimd.c +@@ -18,24 +18,23 @@ + . */ + + #include "v_math.h" +-#include "poly_advsimd_f64.h" + + static const struct data + { +- float64x2_t poly[12]; +- float64x2_t pi, pi_over_2; ++ double c1, c3, c5, c7, c9, c11; ++ float64x2_t c0, c2, c4, c6, c8, c10; + uint64x2_t abs_mask; ++ float64x2_t pi, pi_over_2; + } data = { + /* Polynomial approximation of (asin(sqrt(x)) - sqrt(x)) / (x * sqrt(x)) + on [ 0x1p-106, 0x1p-2 ], relative error: 0x1.c3d8e169p-57. */ +- .poly = { V2 (0x1.555555555554ep-3), V2 (0x1.3333333337233p-4), +- V2 (0x1.6db6db67f6d9fp-5), V2 (0x1.f1c71fbd29fbbp-6), +- V2 (0x1.6e8b264d467d6p-6), V2 (0x1.1c5997c357e9dp-6), +- V2 (0x1.c86a22cd9389dp-7), V2 (0x1.856073c22ebbep-7), +- V2 (0x1.fd1151acb6bedp-8), V2 (0x1.087182f799c1dp-6), +- V2 (-0x1.6602748120927p-7), V2 (0x1.cfa0dd1f9478p-6), }, +- .pi = V2 (0x1.921fb54442d18p+1), +- .pi_over_2 = V2 (0x1.921fb54442d18p+0), ++ .c0 = V2 (0x1.555555555554ep-3), .c1 = 0x1.3333333337233p-4, ++ .c2 = V2 (0x1.6db6db67f6d9fp-5), .c3 = 0x1.f1c71fbd29fbbp-6, ++ .c4 = V2 (0x1.6e8b264d467d6p-6), .c5 = 0x1.1c5997c357e9dp-6, ++ .c6 = V2 (0x1.c86a22cd9389dp-7), .c7 = 0x1.856073c22ebbep-7, ++ .c8 = V2 (0x1.fd1151acb6bedp-8), .c9 = 0x1.087182f799c1dp-6, ++ .c10 = V2 (-0x1.6602748120927p-7), .c11 = 0x1.cfa0dd1f9478p-6, ++ .pi = V2 (0x1.921fb54442d18p+1), .pi_over_2 = V2 (0x1.921fb54442d18p+0), + .abs_mask = V2 (0x7fffffffffffffff), + }; + +@@ -63,7 +62,7 @@ special_case (float64x2_t x, float64x2_t y, uint64x2_t special) + + acos(x) ~ pi/2 - (x + x^3 P(x^2)). + +- The largest observed error in this region is 1.18 ulps, ++ The largest observed error in this region is 1.18 ulp: + _ZGVnN2v_acos (0x1.fbab0a7c460f6p-2) got 0x1.0d54d1985c068p+0 + want 0x1.0d54d1985c069p+0. + +@@ -71,9 +70,9 @@ special_case (float64x2_t x, float64x2_t y, uint64x2_t special) + + acos(x) = y + y * z * P(z), with z = (1-x)/2 and y = sqrt(z). + +- The largest observed error in this region is 1.52 ulps, +- _ZGVnN2v_acos (0x1.23d362722f591p-1) got 0x1.edbbedf8a7d6ep-1 +- want 0x1.edbbedf8a7d6cp-1. */ ++ The largest observed error in this region is 1.50 ulp: ++ _ZGVnN2v_acos (0x1.252a2cf3fb9acp-1) got 0x1.ec1a46aa82901p-1 ++ want 0x1.ec1a46aa829p-1. */ + float64x2_t VPCS_ATTR V_NAME_D1 (acos) (float64x2_t x) + { + const struct data *d = ptr_barrier (&data); +@@ -99,13 +98,32 @@ float64x2_t VPCS_ATTR V_NAME_D1 (acos) (float64x2_t x) + float64x2_t z = vbslq_f64 (a_le_half, ax, vsqrtq_f64 (z2)); + + /* Use a single polynomial approximation P for both intervals. */ ++ float64x2_t z3 = vmulq_f64 (z2, z); + float64x2_t z4 = vmulq_f64 (z2, z2); + float64x2_t z8 = vmulq_f64 (z4, z4); +- float64x2_t z16 = vmulq_f64 (z8, z8); +- float64x2_t p = v_estrin_11_f64 (z2, z4, z8, z16, d->poly); + +- /* Finalize polynomial: z + z * z2 * P(z2). */ +- p = vfmaq_f64 (z, vmulq_f64 (z, z2), p); ++ /* Order-11 Estrin. */ ++ float64x2_t c13 = vld1q_f64 (&d->c1); ++ float64x2_t c57 = vld1q_f64 (&d->c5); ++ float64x2_t c911 = vld1q_f64 (&d->c9); ++ ++ float64x2_t p01 = vfmaq_laneq_f64 (d->c0, z2, c13, 0); ++ float64x2_t p23 = vfmaq_laneq_f64 (d->c2, z2, c13, 1); ++ float64x2_t p03 = vfmaq_f64 (p01, z4, p23); ++ ++ float64x2_t p45 = vfmaq_laneq_f64 (d->c4, z2, c57, 0); ++ float64x2_t p67 = vfmaq_laneq_f64 (d->c6, z2, c57, 1); ++ float64x2_t p47 = vfmaq_f64 (p45, z4, p67); ++ ++ float64x2_t p89 = vfmaq_laneq_f64 (d->c8, z2, c911, 0); ++ float64x2_t p1011 = vfmaq_laneq_f64 (d->c10, z2, c911, 1); ++ float64x2_t p811 = vfmaq_f64 (p89, z4, p1011); ++ ++ float64x2_t p411 = vfmaq_f64 (p47, z8, p811); ++ float64x2_t p = vfmaq_f64 (p03, z8, p411); ++ ++ /* Finalize polynomial: z + z3 * P(z2). */ ++ p = vfmaq_f64 (z, z3, p); + + /* acos(|x|) = pi/2 - sign(x) * Q(|x|), for |x| < 0.5 + = 2 Q(|x|) , for 0.5 < x < 1.0 +diff --git a/sysdeps/aarch64/fpu/acos_sve.c b/sysdeps/aarch64/fpu/acos_sve.c +index 99dbfac3e6b1e086..870d8062cfd22dee 100644 +--- a/sysdeps/aarch64/fpu/acos_sve.c ++++ b/sysdeps/aarch64/fpu/acos_sve.c +@@ -18,20 +18,21 @@ + . */ + + #include "sv_math.h" +-#include "poly_sve_f64.h" + + static const struct data + { +- float64_t poly[12]; +- float64_t pi, pi_over_2; ++ float64_t c1, c3, c5, c7, c9, c11; ++ float64_t c0, c2, c4, c6, c8, c10; ++ float64_t pi_over_2; + } data = { + /* Polynomial approximation of (asin(sqrt(x)) - sqrt(x)) / (x * sqrt(x)) + on [ 0x1p-106, 0x1p-2 ], relative error: 0x1.c3d8e169p-57. */ +- .poly = { 0x1.555555555554ep-3, 0x1.3333333337233p-4, 0x1.6db6db67f6d9fp-5, +- 0x1.f1c71fbd29fbbp-6, 0x1.6e8b264d467d6p-6, 0x1.1c5997c357e9dp-6, +- 0x1.c86a22cd9389dp-7, 0x1.856073c22ebbep-7, 0x1.fd1151acb6bedp-8, +- 0x1.087182f799c1dp-6, -0x1.6602748120927p-7, 0x1.cfa0dd1f9478p-6, }, +- .pi = 0x1.921fb54442d18p+1, ++ .c0 = 0x1.555555555554ep-3, .c1 = 0x1.3333333337233p-4, ++ .c2 = 0x1.6db6db67f6d9fp-5, .c3 = 0x1.f1c71fbd29fbbp-6, ++ .c4 = 0x1.6e8b264d467d6p-6, .c5 = 0x1.1c5997c357e9dp-6, ++ .c6 = 0x1.c86a22cd9389dp-7, .c7 = 0x1.856073c22ebbep-7, ++ .c8 = 0x1.fd1151acb6bedp-8, .c9 = 0x1.087182f799c1dp-6, ++ .c10 = -0x1.6602748120927p-7, .c11 = 0x1.cfa0dd1f9478p-6, + .pi_over_2 = 0x1.921fb54442d18p+0, + }; + +@@ -42,20 +43,21 @@ static const struct data + + acos(x) ~ pi/2 - (x + x^3 P(x^2)). + +- The largest observed error in this region is 1.18 ulps, +- _ZGVsMxv_acos (0x1.fbc5fe28ee9e3p-2) got 0x1.0d4d0f55667f6p+0 +- want 0x1.0d4d0f55667f7p+0. ++ The largest observed error in this region is 1.18 ulp: ++ _ZGVsMxv_acos (0x1.fbb7c9079b429p-2) got 0x1.0d51266607582p+0 ++ want 0x1.0d51266607583p+0. + + For |x| in [0.5, 1.0], use same approximation with a change of variable + + acos(x) = y + y * z * P(z), with z = (1-x)/2 and y = sqrt(z). + +- The largest observed error in this region is 1.52 ulps, +- _ZGVsMxv_acos (0x1.24024271a500ap-1) got 0x1.ed82df4243f0dp-1 +- want 0x1.ed82df4243f0bp-1. */ ++ The largest observed error in this region is 1.50 ulp: ++ _ZGVsMxv_acos (0x1.252a2cf3fb9acp-1) got 0x1.ec1a46aa82901p-1 ++ want 0x1.ec1a46aa829p-1. */ + svfloat64_t SV_NAME_D1 (acos) (svfloat64_t x, const svbool_t pg) + { + const struct data *d = ptr_barrier (&data); ++ svbool_t ptrue = svptrue_b64 (); + + svuint64_t sign = svand_x (pg, svreinterpret_u64 (x), 0x8000000000000000); + svfloat64_t ax = svabs_x (pg, x); +@@ -70,24 +72,41 @@ svfloat64_t SV_NAME_D1 (acos) (svfloat64_t x, const svbool_t pg) + svfloat64_t z = svsqrt_m (ax, a_gt_half, z2); + + /* Use a single polynomial approximation P for both intervals. */ +- svfloat64_t z4 = svmul_x (pg, z2, z2); +- svfloat64_t z8 = svmul_x (pg, z4, z4); +- svfloat64_t z16 = svmul_x (pg, z8, z8); +- svfloat64_t p = sv_estrin_11_f64_x (pg, z2, z4, z8, z16, d->poly); ++ svfloat64_t z3 = svmul_x (ptrue, z2, z); ++ svfloat64_t z4 = svmul_x (ptrue, z2, z2); ++ svfloat64_t z8 = svmul_x (ptrue, z4, z4); ++ ++ svfloat64_t c13 = svld1rq (ptrue, &d->c1); ++ svfloat64_t c57 = svld1rq (ptrue, &d->c5); ++ svfloat64_t c911 = svld1rq (ptrue, &d->c9); ++ ++ svfloat64_t p01 = svmla_lane (sv_f64 (d->c0), z2, c13, 0); ++ svfloat64_t p23 = svmla_lane (sv_f64 (d->c2), z2, c13, 1); ++ svfloat64_t p03 = svmla_x (pg, p01, z4, p23); ++ ++ svfloat64_t p45 = svmla_lane (sv_f64 (d->c4), z2, c57, 0); ++ svfloat64_t p67 = svmla_lane (sv_f64 (d->c6), z2, c57, 1); ++ svfloat64_t p47 = svmla_x (pg, p45, z4, p67); ++ ++ svfloat64_t p89 = svmla_lane (sv_f64 (d->c8), z2, c911, 0); ++ svfloat64_t p1011 = svmla_lane (sv_f64 (d->c10), z2, c911, 1); ++ svfloat64_t p811 = svmla_x (pg, p89, z4, p1011); ++ ++ svfloat64_t p411 = svmla_x (pg, p47, z8, p811); ++ svfloat64_t p = svmad_x (pg, p411, z8, p03); + + /* Finalize polynomial: z + z * z2 * P(z2). */ +- p = svmla_x (pg, z, svmul_x (pg, z, z2), p); ++ p = svmad_x (pg, p, z3, z); + + /* acos(|x|) = pi/2 - sign(x) * Q(|x|), for |x| < 0.5 + = 2 Q(|x|) , for 0.5 < x < 1.0 + = pi - 2 Q(|x|) , for -1.0 < x < -0.5. */ +- svfloat64_t y +- = svreinterpret_f64 (svorr_x (pg, svreinterpret_u64 (p), sign)); +- +- svbool_t is_neg = svcmplt (pg, x, 0.0); +- svfloat64_t off = svdup_f64_z (is_neg, d->pi); +- svfloat64_t mul = svsel (a_gt_half, sv_f64 (2.0), sv_f64 (-1.0)); +- svfloat64_t add = svsel (a_gt_half, off, sv_f64 (d->pi_over_2)); +- +- return svmla_x (pg, add, mul, y); ++ svfloat64_t mul = svreinterpret_f64 ( ++ svlsl_m (a_gt_half, svreinterpret_u64 (sv_f64 (1.0)), 10)); ++ mul = svreinterpret_f64 (sveor_x (ptrue, svreinterpret_u64 (mul), sign)); ++ svfloat64_t add = svreinterpret_f64 ( ++ svorr_x (ptrue, sign, svreinterpret_u64 (sv_f64 (d->pi_over_2)))); ++ add = svsub_m (a_gt_half, sv_f64 (d->pi_over_2), add); ++ ++ return svmsb_x (pg, p, mul, add); + } +diff --git a/sysdeps/aarch64/fpu/asin_advsimd.c b/sysdeps/aarch64/fpu/asin_advsimd.c +index 2de6eff40782bc79..f4884227a5c45fe5 100644 +--- a/sysdeps/aarch64/fpu/asin_advsimd.c ++++ b/sysdeps/aarch64/fpu/asin_advsimd.c +@@ -18,24 +18,23 @@ + . */ + + #include "v_math.h" +-#include "poly_advsimd_f64.h" + + static const struct data + { +- float64x2_t poly[12]; ++ float64x2_t c0, c2, c4, c6, c8, c10; + float64x2_t pi_over_2; + uint64x2_t abs_mask; ++ double c1, c3, c5, c7, c9, c11; + } data = { + /* Polynomial approximation of (asin(sqrt(x)) - sqrt(x)) / (x * sqrt(x)) + on [ 0x1p-106, 0x1p-2 ], relative error: 0x1.c3d8e169p-57. */ +- .poly = { V2 (0x1.555555555554ep-3), V2 (0x1.3333333337233p-4), +- V2 (0x1.6db6db67f6d9fp-5), V2 (0x1.f1c71fbd29fbbp-6), +- V2 (0x1.6e8b264d467d6p-6), V2 (0x1.1c5997c357e9dp-6), +- V2 (0x1.c86a22cd9389dp-7), V2 (0x1.856073c22ebbep-7), +- V2 (0x1.fd1151acb6bedp-8), V2 (0x1.087182f799c1dp-6), +- V2 (-0x1.6602748120927p-7), V2 (0x1.cfa0dd1f9478p-6), }, +- .pi_over_2 = V2 (0x1.921fb54442d18p+0), +- .abs_mask = V2 (0x7fffffffffffffff), ++ .c0 = V2 (0x1.555555555554ep-3), .c1 = 0x1.3333333337233p-4, ++ .c2 = V2 (0x1.6db6db67f6d9fp-5), .c3 = 0x1.f1c71fbd29fbbp-6, ++ .c4 = V2 (0x1.6e8b264d467d6p-6), .c5 = 0x1.1c5997c357e9dp-6, ++ .c6 = V2 (0x1.c86a22cd9389dp-7), .c7 = 0x1.856073c22ebbep-7, ++ .c8 = V2 (0x1.fd1151acb6bedp-8), .c9 = 0x1.087182f799c1dp-6, ++ .c10 = V2 (-0x1.6602748120927p-7), .c11 = 0x1.cfa0dd1f9478p-6, ++ .pi_over_2 = V2 (0x1.921fb54442d18p+0), .abs_mask = V2 (0x7fffffffffffffff), + }; + + #define AllMask v_u64 (0xffffffffffffffff) +@@ -68,8 +67,8 @@ special_case (float64x2_t x, float64x2_t y, uint64x2_t special) + asin(x) = pi/2 - (y + y * z * P(z)), with z = (1-x)/2 and y = sqrt(z). + + The largest observed error in this region is 2.69 ulps, +- _ZGVnN2v_asin (0x1.044ac9819f573p-1) got 0x1.110d7e85fdd5p-1 +- want 0x1.110d7e85fdd53p-1. */ ++ _ZGVnN2v_asin (0x1.044e8cefee301p-1) got 0x1.1111dd54ddf96p-1 ++ want 0x1.1111dd54ddf99p-1. */ + float64x2_t VPCS_ATTR V_NAME_D1 (asin) (float64x2_t x) + { + const struct data *d = ptr_barrier (&data); +@@ -86,7 +85,7 @@ float64x2_t VPCS_ATTR V_NAME_D1 (asin) (float64x2_t x) + return special_case (x, x, AllMask); + #endif + +- uint64x2_t a_lt_half = vcltq_f64 (ax, v_f64 (0.5)); ++ uint64x2_t a_lt_half = vcaltq_f64 (x, v_f64 (0.5)); + + /* Evaluate polynomial Q(x) = y + y * z * P(z) with + z = x ^ 2 and y = |x| , if |x| < 0.5 +@@ -99,7 +98,26 @@ float64x2_t VPCS_ATTR V_NAME_D1 (asin) (float64x2_t x) + float64x2_t z4 = vmulq_f64 (z2, z2); + float64x2_t z8 = vmulq_f64 (z4, z4); + float64x2_t z16 = vmulq_f64 (z8, z8); +- float64x2_t p = v_estrin_11_f64 (z2, z4, z8, z16, d->poly); ++ ++ /* order-11 estrin. */ ++ float64x2_t c13 = vld1q_f64 (&d->c1); ++ float64x2_t c57 = vld1q_f64 (&d->c5); ++ float64x2_t c911 = vld1q_f64 (&d->c9); ++ ++ float64x2_t p01 = vfmaq_laneq_f64 (d->c0, z2, c13, 0); ++ float64x2_t p23 = vfmaq_laneq_f64 (d->c2, z2, c13, 1); ++ float64x2_t p03 = vfmaq_f64 (p01, z4, p23); ++ ++ float64x2_t p45 = vfmaq_laneq_f64 (d->c4, z2, c57, 0); ++ float64x2_t p67 = vfmaq_laneq_f64 (d->c6, z2, c57, 1); ++ float64x2_t p47 = vfmaq_f64 (p45, z4, p67); ++ ++ float64x2_t p89 = vfmaq_laneq_f64 (d->c8, z2, c911, 0); ++ float64x2_t p1011 = vfmaq_laneq_f64 (d->c10, z2, c911, 1); ++ float64x2_t p811 = vfmaq_f64 (p89, z4, p1011); ++ ++ float64x2_t p07 = vfmaq_f64 (p03, z8, p47); ++ float64x2_t p = vfmaq_f64 (p07, z16, p811); + + /* Finalize polynomial: z + z * z2 * P(z2). */ + p = vfmaq_f64 (z, vmulq_f64 (z, z2), p); +diff --git a/sysdeps/aarch64/fpu/asin_sve.c b/sysdeps/aarch64/fpu/asin_sve.c +index 9daa382e34510201..acbf1b3bdd2c5bb6 100644 +--- a/sysdeps/aarch64/fpu/asin_sve.c ++++ b/sysdeps/aarch64/fpu/asin_sve.c +@@ -18,45 +18,43 @@ + . */ + + #include "sv_math.h" +-#include "poly_sve_f64.h" + + static const struct data + { +- float64_t poly[12]; +- float64_t pi_over_2f; ++ float64_t c1, c3, c5, c7, c9, c11; ++ float64_t c0, c2, c4, c6, c8, c10; ++ float64_t pi_over_2; + } data = { + /* Polynomial approximation of (asin(sqrt(x)) - sqrt(x)) / (x * sqrt(x)) + on [ 0x1p-106, 0x1p-2 ], relative error: 0x1.c3d8e169p-57. */ +- .poly = { 0x1.555555555554ep-3, 0x1.3333333337233p-4, +- 0x1.6db6db67f6d9fp-5, 0x1.f1c71fbd29fbbp-6, +- 0x1.6e8b264d467d6p-6, 0x1.1c5997c357e9dp-6, +- 0x1.c86a22cd9389dp-7, 0x1.856073c22ebbep-7, +- 0x1.fd1151acb6bedp-8, 0x1.087182f799c1dp-6, +- -0x1.6602748120927p-7, 0x1.cfa0dd1f9478p-6, }, +- .pi_over_2f = 0x1.921fb54442d18p+0, ++ .c0 = 0x1.555555555554ep-3, .c1 = 0x1.3333333337233p-4, ++ .c2 = 0x1.6db6db67f6d9fp-5, .c3 = 0x1.f1c71fbd29fbbp-6, ++ .c4 = 0x1.6e8b264d467d6p-6, .c5 = 0x1.1c5997c357e9dp-6, ++ .c6 = 0x1.c86a22cd9389dp-7, .c7 = 0x1.856073c22ebbep-7, ++ .c8 = 0x1.fd1151acb6bedp-8, .c9 = 0x1.087182f799c1dp-6, ++ .c10 = -0x1.6602748120927p-7, .c11 = 0x1.cfa0dd1f9478p-6, ++ .pi_over_2 = 0x1.921fb54442d18p+0, + }; + +-#define P(i) sv_f64 (d->poly[i]) +- + /* Double-precision SVE implementation of vector asin(x). + + For |x| in [0, 0.5], use an order 11 polynomial P such that the final + approximation is an odd polynomial: asin(x) ~ x + x^3 P(x^2). + +- The largest observed error in this region is 0.52 ulps, +- _ZGVsMxv_asin(0x1.d95ae04998b6cp-2) got 0x1.ec13757305f27p-2 +- want 0x1.ec13757305f26p-2. +- +- For |x| in [0.5, 1.0], use same approximation with a change of variable ++ The largest observed error in this region is 0.98 ulp: ++ _ZGVsMxv_asin (0x1.d98f6a748ed8ap-2) got 0x1.ec4eb661a73d3p-2 ++ want 0x1.ec4eb661a73d2p-2. + +- asin(x) = pi/2 - (y + y * z * P(z)), with z = (1-x)/2 and y = sqrt(z). ++ For |x| in [0.5, 1.0], use same approximation with a change of variable: ++ asin(x) = pi/2 - (y + y * z * P(z)), with z = (1-x)/2 and y = sqrt(z). + +- The largest observed error in this region is 2.69 ulps, +- _ZGVsMxv_asin(0x1.044ac9819f573p-1) got 0x1.110d7e85fdd5p-1 +- want 0x1.110d7e85fdd53p-1. */ ++ The largest observed error in this region is 2.66 ulp: ++ _ZGVsMxv_asin (0x1.04024f6e2a2fbp-1) got 0x1.10b9586f087a8p-1 ++ want 0x1.10b9586f087abp-1. */ + svfloat64_t SV_NAME_D1 (asin) (svfloat64_t x, const svbool_t pg) + { + const struct data *d = ptr_barrier (&data); ++ svbool_t ptrue = svptrue_b64 (); + + svuint64_t sign = svand_x (pg, svreinterpret_u64 (x), 0x8000000000000000); + svfloat64_t ax = svabs_x (pg, x); +@@ -70,17 +68,37 @@ svfloat64_t SV_NAME_D1 (asin) (svfloat64_t x, const svbool_t pg) + svfloat64_t z = svsqrt_m (ax, a_ge_half, z2); + + /* Use a single polynomial approximation P for both intervals. */ ++ svfloat64_t z3 = svmul_x (pg, z2, z); + svfloat64_t z4 = svmul_x (pg, z2, z2); + svfloat64_t z8 = svmul_x (pg, z4, z4); +- svfloat64_t z16 = svmul_x (pg, z8, z8); +- svfloat64_t p = sv_estrin_11_f64_x (pg, z2, z4, z8, z16, d->poly); ++ ++ svfloat64_t c13 = svld1rq (ptrue, &d->c1); ++ svfloat64_t c57 = svld1rq (ptrue, &d->c5); ++ svfloat64_t c911 = svld1rq (ptrue, &d->c9); ++ ++ /* Order-11 Estrin scheme. */ ++ svfloat64_t p01 = svmla_lane (sv_f64 (d->c0), z2, c13, 0); ++ svfloat64_t p23 = svmla_lane (sv_f64 (d->c2), z2, c13, 1); ++ svfloat64_t p03 = svmla_x (pg, p01, z4, p23); ++ ++ svfloat64_t p45 = svmla_lane (sv_f64 (d->c4), z2, c57, 0); ++ svfloat64_t p67 = svmla_lane (sv_f64 (d->c6), z2, c57, 1); ++ svfloat64_t p47 = svmla_x (pg, p45, z4, p67); ++ ++ svfloat64_t p89 = svmla_lane (sv_f64 (d->c8), z2, c911, 0); ++ svfloat64_t p1011 = svmla_lane (sv_f64 (d->c10), z2, c911, 1); ++ svfloat64_t p811 = svmla_x (pg, p89, z4, p1011); ++ ++ svfloat64_t p411 = svmla_x (pg, p47, z8, p811); ++ svfloat64_t p = svmla_x (pg, p03, z8, p411); ++ + /* Finalize polynomial: z + z * z2 * P(z2). */ +- p = svmla_x (pg, z, svmul_x (pg, z, z2), p); ++ p = svmla_x (pg, z, z3, p); + +- /* asin(|x|) = Q(|x|) , for |x| < 0.5 +- = pi/2 - 2 Q(|x|), for |x| >= 0.5. */ +- svfloat64_t y = svmad_m (a_ge_half, p, sv_f64 (-2.0), d->pi_over_2f); ++ /* asin(|x|) = Q(|x|), for |x| < 0.5 ++ = pi/2 - 2 Q(|x|), for |x| >= 0.5. */ ++ svfloat64_t y = svmad_m (a_ge_half, p, sv_f64 (-2.0), d->pi_over_2); + +- /* Copy sign. */ ++ /* Reinsert the sign from the argument. */ + return svreinterpret_f64 (svorr_x (pg, svreinterpret_u64 (y), sign)); + } +diff --git a/sysdeps/aarch64/fpu/asinf_advsimd.c b/sysdeps/aarch64/fpu/asinf_advsimd.c +index 59d870ca3693abac..88437f85abec4729 100644 +--- a/sysdeps/aarch64/fpu/asinf_advsimd.c ++++ b/sysdeps/aarch64/fpu/asinf_advsimd.c +@@ -18,22 +18,21 @@ + . */ + + #include "v_math.h" +-#include "poly_advsimd_f32.h" + + static const struct data + { +- float32x4_t poly[5]; ++ float32x4_t c0, c2, c4; ++ float c1, c3; + float32x4_t pi_over_2f; + } data = { + /* Polynomial approximation of (asin(sqrt(x)) - sqrt(x)) / (x * sqrt(x)) on + [ 0x1p-24 0x1p-2 ] order = 4 rel error: 0x1.00a23bbp-29 . */ +- .poly = { V4 (0x1.55555ep-3), V4 (0x1.33261ap-4), V4 (0x1.70d7dcp-5), +- V4 (0x1.b059dp-6), V4 (0x1.3af7d8p-5) }, +- .pi_over_2f = V4 (0x1.921fb6p+0f), ++ .c0 = V4 (0x1.55555ep-3f), .c1 = 0x1.33261ap-4f, ++ .c2 = V4 (0x1.70d7dcp-5f), .c3 = 0x1.b059dp-6f, ++ .c4 = V4 (0x1.3af7d8p-5f), .pi_over_2f = V4 (0x1.921fb6p+0f), + }; + + #define AbsMask 0x7fffffff +-#define Half 0x3f000000 + #define One 0x3f800000 + #define Small 0x39800000 /* 2^-12. */ + +@@ -47,11 +46,8 @@ special_case (float32x4_t x, float32x4_t y, uint32x4_t special) + + /* Single-precision implementation of vector asin(x). + +- For |x| < Small, approximate asin(x) by x. Small = 2^-12 for correct +- rounding. If WANT_SIMD_EXCEPT = 0, Small = 0 and we proceed with the +- following approximation. + +- For |x| in [Small, 0.5], use order 4 polynomial P such that the final ++ For |x| <0.5, use order 4 polynomial P such that the final + approximation is an odd polynomial: asin(x) ~ x + x^3 P(x^2). + + The largest observed error in this region is 0.83 ulps, +@@ -80,24 +76,31 @@ float32x4_t VPCS_ATTR NOINLINE V_NAME_F1 (asin) (float32x4_t x) + #endif + + float32x4_t ax = vreinterpretq_f32_u32 (ia); +- uint32x4_t a_lt_half = vcltq_u32 (ia, v_u32 (Half)); ++ uint32x4_t a_lt_half = vcaltq_f32 (x, v_f32 (0.5f)); + + /* Evaluate polynomial Q(x) = y + y * z * P(z) with + z = x ^ 2 and y = |x| , if |x| < 0.5 + z = (1 - |x|) / 2 and y = sqrt(z), if |x| >= 0.5. */ + float32x4_t z2 = vbslq_f32 (a_lt_half, vmulq_f32 (x, x), +- vfmsq_n_f32 (v_f32 (0.5), ax, 0.5)); ++ vfmsq_n_f32 (v_f32 (0.5f), ax, 0.5f)); + float32x4_t z = vbslq_f32 (a_lt_half, ax, vsqrtq_f32 (z2)); + + /* Use a single polynomial approximation P for both intervals. */ +- float32x4_t p = v_horner_4_f32 (z2, d->poly); ++ ++ /* PW Horner 3 evaluation scheme. */ ++ float32x4_t z4 = vmulq_f32 (z2, z2); ++ float32x4_t c13 = vld1q_f32 (&d->c1); ++ float32x4_t p01 = vfmaq_laneq_f32 (d->c0, z2, c13, 0); ++ float32x4_t p23 = vfmaq_laneq_f32 (d->c2, z2, c13, 1); ++ float32x4_t p = vfmaq_f32 (p23, d->c4, z4); ++ p = vfmaq_f32 (p01, p, z4); + /* Finalize polynomial: z + z * z2 * P(z2). */ + p = vfmaq_f32 (z, vmulq_f32 (z, z2), p); + + /* asin(|x|) = Q(|x|) , for |x| < 0.5 + = pi/2 - 2 Q(|x|), for |x| >= 0.5. */ + float32x4_t y +- = vbslq_f32 (a_lt_half, p, vfmsq_n_f32 (d->pi_over_2f, p, 2.0)); ++ = vbslq_f32 (a_lt_half, p, vfmsq_n_f32 (d->pi_over_2f, p, 2.0f)); + + /* Copy sign. */ + return vbslq_f32 (v_u32 (AbsMask), y, x); +diff --git a/sysdeps/aarch64/fpu/atan2_advsimd.c b/sysdeps/aarch64/fpu/atan2_advsimd.c +index 5df4b99ff4277c6a..36be4ce83ac15727 100644 +--- a/sysdeps/aarch64/fpu/atan2_advsimd.c ++++ b/sysdeps/aarch64/fpu/atan2_advsimd.c +@@ -18,40 +18,38 @@ + . */ + + #include "v_math.h" +-#include "poly_advsimd_f64.h" + + static const struct data + { ++ double c1, c3, c5, c7, c9, c11, c13, c15, c17, c19; + float64x2_t c0, c2, c4, c6, c8, c10, c12, c14, c16, c18; + float64x2_t pi_over_2; +- double c1, c3, c5, c7, c9, c11, c13, c15, c17, c19; +- uint64x2_t zeroinfnan, minustwo; ++ uint64x2_t zeroinfnan; + } data = { +- /* Coefficients of polynomial P such that atan(x)~x+x*P(x^2) on +- [2**-1022, 1.0]. */ +- .c0 = V2 (-0x1.5555555555555p-2), +- .c1 = 0x1.99999999996c1p-3, +- .c2 = V2 (-0x1.2492492478f88p-3), +- .c3 = 0x1.c71c71bc3951cp-4, +- .c4 = V2 (-0x1.745d160a7e368p-4), +- .c5 = 0x1.3b139b6a88ba1p-4, +- .c6 = V2 (-0x1.11100ee084227p-4), +- .c7 = 0x1.e1d0f9696f63bp-5, +- .c8 = V2 (-0x1.aebfe7b418581p-5), +- .c9 = 0x1.842dbe9b0d916p-5, +- .c10 = V2 (-0x1.5d30140ae5e99p-5), +- .c11 = 0x1.338e31eb2fbbcp-5, +- .c12 = V2 (-0x1.00e6eece7de8p-5), +- .c13 = 0x1.860897b29e5efp-6, +- .c14 = V2 (-0x1.0051381722a59p-6), +- .c15 = 0x1.14e9dc19a4a4ep-7, +- .c16 = V2 (-0x1.d0062b42fe3bfp-9), +- .c17 = 0x1.17739e210171ap-10, +- .c18 = V2 (-0x1.ab24da7be7402p-13), +- .c19 = 0x1.358851160a528p-16, ++ /* Coefficients of polynomial P such that ++ atan(x)~x+x*P(x^2) on [2^-1022, 1.0]. */ ++ .c0 = V2 (-0x1.555555555552ap-2), ++ .c1 = 0x1.9999999995aebp-3, ++ .c2 = V2 (-0x1.24924923923f6p-3), ++ .c3 = 0x1.c71c7184288a2p-4, ++ .c4 = V2 (-0x1.745d11fb3d32bp-4), ++ .c5 = 0x1.3b136a18051b9p-4, ++ .c6 = V2 (-0x1.110e6d985f496p-4), ++ .c7 = 0x1.e1bcf7f08801dp-5, ++ .c8 = V2 (-0x1.ae644e28058c3p-5), ++ .c9 = 0x1.82eeb1fed85c6p-5, ++ .c10 = V2 (-0x1.59d7f901566cbp-5), ++ .c11 = 0x1.2c982855ab069p-5, ++ .c12 = V2 (-0x1.eb49592998177p-6), ++ .c13 = 0x1.69d8b396e3d38p-6, ++ .c14 = V2 (-0x1.ca980345c4204p-7), ++ .c15 = 0x1.dc050eafde0b3p-8, ++ .c16 = V2 (-0x1.7ea70755b8eccp-9), ++ .c17 = 0x1.ba3da3de903e8p-11, ++ .c18 = V2 (-0x1.44a4b059b6f67p-13), ++ .c19 = 0x1.c4a45029e5a91p-17, + .pi_over_2 = V2 (0x1.921fb54442d18p+0), + .zeroinfnan = V2 (2 * 0x7ff0000000000000ul - 1), +- .minustwo = V2 (0xc000000000000000), + }; + + #define SignMask v_u64 (0x8000000000000000) +@@ -76,10 +74,9 @@ zeroinfnan (uint64x2_t i, const struct data *d) + } + + /* Fast implementation of vector atan2. +- Maximum observed error is 2.8 ulps: +- _ZGVnN2vv_atan2 (0x1.9651a429a859ap+5, 0x1.953075f4ee26p+5) +- got 0x1.92d628ab678ccp-1 +- want 0x1.92d628ab678cfp-1. */ ++ Maximum observed error is 1.97 ulps: ++ _ZGVnN2vv_atan2 (0x1.42337dba73768p+5, 0x1.422d748cd3e29p+5) ++ got 0x1.9224810264efcp-1 want 0x1.9224810264efep-1. */ + float64x2_t VPCS_ATTR V_NAME_D2 (atan2) (float64x2_t y, float64x2_t x) + { + const struct data *d = ptr_barrier (&data); +@@ -100,26 +97,29 @@ float64x2_t VPCS_ATTR V_NAME_D2 (atan2) (float64x2_t y, float64x2_t x) + uint64x2_t pred_xlt0 = vcltzq_f64 (x); + uint64x2_t pred_aygtax = vcagtq_f64 (y, x); + +- /* Set up z for call to atan. */ +- float64x2_t n = vbslq_f64 (pred_aygtax, vnegq_f64 (ax), ay); +- float64x2_t q = vbslq_f64 (pred_aygtax, ay, ax); +- float64x2_t z = vdivq_f64 (n, q); +- +- /* Work out the correct shift. */ +- float64x2_t shift +- = vreinterpretq_f64_u64 (vandq_u64 (pred_xlt0, d->minustwo)); +- shift = vbslq_f64 (pred_aygtax, vaddq_f64 (shift, v_f64 (1.0)), shift); +- shift = vmulq_f64 (shift, d->pi_over_2); +- +- /* Calculate the polynomial approximation. +- Use split Estrin scheme for P(z^2) with deg(P)=19. Use split instead of +- full scheme to avoid underflow in x^16. +- The order 19 polynomial P approximates +- (atan(sqrt(x))-sqrt(x))/x^(3/2). */ ++ /* Set up z for evaluation of atan. */ ++ float64x2_t num = vbslq_f64 (pred_aygtax, vnegq_f64 (ax), ay); ++ float64x2_t den = vbslq_f64 (pred_aygtax, ay, ax); ++ float64x2_t z = vdivq_f64 (num, den); ++ ++ /* Work out the correct shift for atan2: ++ Multiplication by pi is done later. ++ -pi when x < 0 and ax < ay ++ -pi/2 when x < 0 and ax > ay ++ 0 when x >= 0 and ax < ay ++ pi/2 when x >= 0 and ax > ay. */ ++ float64x2_t shift = vreinterpretq_f64_u64 ( ++ vandq_u64 (pred_xlt0, vreinterpretq_u64_f64 (v_f64 (-2.0)))); ++ float64x2_t shift2 = vreinterpretq_f64_u64 ( ++ vandq_u64 (pred_aygtax, vreinterpretq_u64_f64 (v_f64 (1.0)))); ++ shift = vaddq_f64 (shift, shift2); ++ ++ /* Calculate the polynomial approximation. */ + float64x2_t z2 = vmulq_f64 (z, z); +- float64x2_t x2 = vmulq_f64 (z2, z2); +- float64x2_t x4 = vmulq_f64 (x2, x2); +- float64x2_t x8 = vmulq_f64 (x4, x4); ++ float64x2_t z3 = vmulq_f64 (z2, z); ++ float64x2_t z4 = vmulq_f64 (z2, z2); ++ float64x2_t z8 = vmulq_f64 (z4, z4); ++ float64x2_t z16 = vmulq_f64 (z8, z8); + + float64x2_t c13 = vld1q_f64 (&d->c1); + float64x2_t c57 = vld1q_f64 (&d->c5); +@@ -127,45 +127,43 @@ float64x2_t VPCS_ATTR V_NAME_D2 (atan2) (float64x2_t y, float64x2_t x) + float64x2_t c1315 = vld1q_f64 (&d->c13); + float64x2_t c1719 = vld1q_f64 (&d->c17); + +- /* estrin_7. */ ++ /* Order-7 Estrin. */ + float64x2_t p01 = vfmaq_laneq_f64 (d->c0, z2, c13, 0); + float64x2_t p23 = vfmaq_laneq_f64 (d->c2, z2, c13, 1); +- float64x2_t p03 = vfmaq_f64 (p01, x2, p23); ++ float64x2_t p03 = vfmaq_f64 (p01, z4, p23); + + float64x2_t p45 = vfmaq_laneq_f64 (d->c4, z2, c57, 0); + float64x2_t p67 = vfmaq_laneq_f64 (d->c6, z2, c57, 1); +- float64x2_t p47 = vfmaq_f64 (p45, x2, p67); ++ float64x2_t p47 = vfmaq_f64 (p45, z4, p67); + +- float64x2_t p07 = vfmaq_f64 (p03, x4, p47); ++ float64x2_t p07 = vfmaq_f64 (p03, z8, p47); + +- /* estrin_11. */ ++ /* Order-11 Estrin. */ + float64x2_t p89 = vfmaq_laneq_f64 (d->c8, z2, c911, 0); + float64x2_t p1011 = vfmaq_laneq_f64 (d->c10, z2, c911, 1); +- float64x2_t p811 = vfmaq_f64 (p89, x2, p1011); ++ float64x2_t p811 = vfmaq_f64 (p89, z4, p1011); + + float64x2_t p1213 = vfmaq_laneq_f64 (d->c12, z2, c1315, 0); + float64x2_t p1415 = vfmaq_laneq_f64 (d->c14, z2, c1315, 1); +- float64x2_t p1215 = vfmaq_f64 (p1213, x2, p1415); ++ float64x2_t p1215 = vfmaq_f64 (p1213, z4, p1415); + + float64x2_t p1617 = vfmaq_laneq_f64 (d->c16, z2, c1719, 0); + float64x2_t p1819 = vfmaq_laneq_f64 (d->c18, z2, c1719, 1); +- float64x2_t p1619 = vfmaq_f64 (p1617, x2, p1819); ++ float64x2_t p1619 = vfmaq_f64 (p1617, z4, p1819); + +- float64x2_t p815 = vfmaq_f64 (p811, x4, p1215); +- float64x2_t p819 = vfmaq_f64 (p815, x8, p1619); ++ float64x2_t p815 = vfmaq_f64 (p811, z8, p1215); ++ float64x2_t p819 = vfmaq_f64 (p815, z16, p1619); + +- float64x2_t ret = vfmaq_f64 (p07, p819, x8); ++ float64x2_t poly = vfmaq_f64 (p07, p819, z16); + + /* Finalize. y = shift + z + z^3 * P(z^2). */ +- ret = vfmaq_f64 (z, ret, vmulq_f64 (z2, z)); +- ret = vaddq_f64 (ret, shift); ++ float64x2_t ret = vfmaq_f64 (z, shift, d->pi_over_2); ++ ret = vfmaq_f64 (ret, z3, poly); + + if (__glibc_unlikely (v_any_u64 (special_cases))) + return special_case (y, x, ret, sign_xy, special_cases); + + /* Account for the sign of x and y. */ +- ret = vreinterpretq_f64_u64 ( ++ return vreinterpretq_f64_u64 ( + veorq_u64 (vreinterpretq_u64_f64 (ret), sign_xy)); +- +- return ret; + } +diff --git a/sysdeps/aarch64/fpu/atan2_sve.c b/sysdeps/aarch64/fpu/atan2_sve.c +index 04fa71fa37c3de29..7af4931cdb89a1c5 100644 +--- a/sysdeps/aarch64/fpu/atan2_sve.c ++++ b/sysdeps/aarch64/fpu/atan2_sve.c +@@ -18,25 +18,25 @@ + . */ + + #include "sv_math.h" +-#include "poly_sve_f64.h" + + static const struct data + { +- float64_t poly[20]; +- float64_t pi_over_2; ++ float64_t c0, c2, c4, c6, c8, c10, c12, c14, c16, c18; ++ float64_t c1, c3, c5, c7, c9, c11, c13, c15, c17, c19; + } data = { + /* Coefficients of polynomial P such that atan(x)~x+x*P(x^2) on + [2**-1022, 1.0]. */ +- .poly = { -0x1.5555555555555p-2, 0x1.99999999996c1p-3, -0x1.2492492478f88p-3, +- 0x1.c71c71bc3951cp-4, -0x1.745d160a7e368p-4, 0x1.3b139b6a88ba1p-4, +- -0x1.11100ee084227p-4, 0x1.e1d0f9696f63bp-5, -0x1.aebfe7b418581p-5, +- 0x1.842dbe9b0d916p-5, -0x1.5d30140ae5e99p-5, 0x1.338e31eb2fbbcp-5, +- -0x1.00e6eece7de8p-5, 0x1.860897b29e5efp-6, -0x1.0051381722a59p-6, +- 0x1.14e9dc19a4a4ep-7, -0x1.d0062b42fe3bfp-9, 0x1.17739e210171ap-10, +- -0x1.ab24da7be7402p-13, 0x1.358851160a528p-16, }, +- .pi_over_2 = 0x1.921fb54442d18p+0, ++ .c0 = -0x1.555555555552ap-2, .c1 = 0x1.9999999995aebp-3, ++ .c2 = -0x1.24924923923f6p-3, .c3 = 0x1.c71c7184288a2p-4, ++ .c4 = -0x1.745d11fb3d32bp-4, .c5 = 0x1.3b136a18051b9p-4, ++ .c6 = -0x1.110e6d985f496p-4, .c7 = 0x1.e1bcf7f08801dp-5, ++ .c8 = -0x1.ae644e28058c3p-5, .c9 = 0x1.82eeb1fed85c6p-5, ++ .c10 = -0x1.59d7f901566cbp-5, .c11 = 0x1.2c982855ab069p-5, ++ .c12 = -0x1.eb49592998177p-6, .c13 = 0x1.69d8b396e3d38p-6, ++ .c14 = -0x1.ca980345c4204p-7, .c15 = 0x1.dc050eafde0b3p-8, ++ .c16 = -0x1.7ea70755b8eccp-9, .c17 = 0x1.ba3da3de903e8p-11, ++ .c18 = -0x1.44a4b059b6f67p-13, .c19 = 0x1.c4a45029e5a91p-17, + }; +- + /* Special cases i.e. 0, infinity, nan (fall back to scalar calls). */ + static svfloat64_t NOINLINE + special_case (svfloat64_t y, svfloat64_t x, svfloat64_t ret, +@@ -55,15 +55,17 @@ zeroinfnan (svuint64_t i, const svbool_t pg) + } + + /* Fast implementation of SVE atan2. Errors are greatest when y and +- x are reasonably close together. The greatest observed error is 2.28 ULP: +- _ZGVsMxvv_atan2 (-0x1.5915b1498e82fp+732, 0x1.54d11ef838826p+732) +- got -0x1.954f42f1fa841p-1 want -0x1.954f42f1fa843p-1. */ +-svfloat64_t SV_NAME_D2 (atan2) (svfloat64_t y, svfloat64_t x, const svbool_t pg) ++ x are reasonably close together. The greatest observed error is 1.94 ULP: ++ _ZGVsMxvv_atan2 (0x1.8a4bf7167228ap+5, 0x1.84971226bb57bp+5) ++ got 0x1.95db19dfef9ccp-1 want 0x1.95db19dfef9cep-1. */ ++svfloat64_t SV_NAME_D2 (atan2) (svfloat64_t y, svfloat64_t x, ++ const svbool_t pg) + { +- const struct data *data_ptr = ptr_barrier (&data); ++ const struct data *d = ptr_barrier (&data); + + svuint64_t ix = svreinterpret_u64 (x); + svuint64_t iy = svreinterpret_u64 (y); ++ svbool_t ptrue = svptrue_b64 (); + + svbool_t cmp_x = zeroinfnan (ix, pg); + svbool_t cmp_y = zeroinfnan (iy, pg); +@@ -80,32 +82,67 @@ svfloat64_t SV_NAME_D2 (atan2) (svfloat64_t y, svfloat64_t x, const svbool_t pg) + + svbool_t pred_aygtax = svcmpgt (pg, ay, ax); + +- /* Set up z for call to atan. */ +- svfloat64_t n = svsel (pred_aygtax, svneg_x (pg, ax), ay); +- svfloat64_t d = svsel (pred_aygtax, ay, ax); +- svfloat64_t z = svdiv_x (pg, n, d); +- +- /* Work out the correct shift. */ ++ /* Set up z for evaluation of atan. */ ++ svfloat64_t num = svsel (pred_aygtax, svneg_x (pg, ax), ay); ++ svfloat64_t den = svsel (pred_aygtax, ay, ax); ++ svfloat64_t z = svdiv_x (pg, num, den); ++ ++ /* Work out the correct shift for atan2: ++ Multiplication by pi is done later. ++ -pi when x < 0 and ax < ay ++ -pi/2 when x < 0 and ax > ay ++ 0 when x >= 0 and ax < ay ++ pi/2 when x >= 0 and ax > ay. */ + svfloat64_t shift = svreinterpret_f64 (svlsr_x (pg, sign_x, 1)); ++ svfloat64_t shift_mul = svreinterpret_f64 ( ++ svorr_x (pg, sign_x, svreinterpret_u64 (sv_f64 (0x1.921fb54442d18p+0)))); + shift = svsel (pred_aygtax, sv_f64 (1.0), shift); +- shift = svreinterpret_f64 (svorr_x (pg, sign_x, svreinterpret_u64 (shift))); +- shift = svmul_x (pg, shift, data_ptr->pi_over_2); ++ shift = svmla_x (pg, z, shift, shift_mul); + + /* Use split Estrin scheme for P(z^2) with deg(P)=19. */ + svfloat64_t z2 = svmul_x (pg, z, z); +- svfloat64_t x2 = svmul_x (pg, z2, z2); +- svfloat64_t x4 = svmul_x (pg, x2, x2); +- svfloat64_t x8 = svmul_x (pg, x4, x4); ++ svfloat64_t z3 = svmul_x (pg, z2, z); ++ svfloat64_t z4 = svmul_x (pg, z2, z2); ++ svfloat64_t z8 = svmul_x (pg, z4, z4); ++ svfloat64_t z16 = svmul_x (pg, z8, z8); + +- svfloat64_t ret = svmla_x ( +- pg, sv_estrin_7_f64_x (pg, z2, x2, x4, data_ptr->poly), +- sv_estrin_11_f64_x (pg, z2, x2, x4, x8, data_ptr->poly + 8), x8); ++ /* Order-7 Estrin. */ ++ svfloat64_t c13 = svld1rq (ptrue, &d->c1); ++ svfloat64_t c57 = svld1rq (ptrue, &d->c5); + +- /* y = shift + z + z^3 * P(z^2). */ +- svfloat64_t z3 = svmul_x (pg, z2, z); +- ret = svmla_x (pg, z, z3, ret); ++ svfloat64_t p01 = svmla_lane (sv_f64 (d->c0), z2, c13, 0); ++ svfloat64_t p23 = svmla_lane (sv_f64 (d->c2), z2, c13, 1); ++ svfloat64_t p45 = svmla_lane (sv_f64 (d->c4), z2, c57, 0); ++ svfloat64_t p67 = svmla_lane (sv_f64 (d->c6), z2, c57, 1); ++ ++ svfloat64_t p03 = svmla_x (pg, p01, z4, p23); ++ svfloat64_t p47 = svmla_x (pg, p45, z4, p67); ++ svfloat64_t p07 = svmla_x (pg, p03, z8, p47); ++ ++ /* Order-11 Estrin. */ ++ svfloat64_t c911 = svld1rq (ptrue, &d->c9); ++ svfloat64_t c1315 = svld1rq (ptrue, &d->c13); ++ svfloat64_t c1719 = svld1rq (ptrue, &d->c17); + +- ret = svadd_m (pg, ret, shift); ++ svfloat64_t p89 = svmla_lane (sv_f64 (d->c8), z2, c911, 0); ++ svfloat64_t p1011 = svmla_lane (sv_f64 (d->c10), z2, c911, 1); ++ svfloat64_t p811 = svmla_x (pg, p89, z4, p1011); ++ ++ svfloat64_t p1213 = svmla_lane (sv_f64 (d->c12), z2, c1315, 0); ++ svfloat64_t p1415 = svmla_lane (sv_f64 (d->c14), z2, c1315, 1); ++ svfloat64_t p1215 = svmla_x (pg, p1213, z4, p1415); ++ ++ svfloat64_t p1617 = svmla_lane (sv_f64 (d->c16), z2, c1719, 0); ++ svfloat64_t p1819 = svmla_lane (sv_f64 (d->c18), z2, c1719, 1); ++ svfloat64_t p1619 = svmla_x (pg, p1617, z4, p1819); ++ ++ svfloat64_t p815 = svmla_x (pg, p811, z8, p1215); ++ svfloat64_t p819 = svmla_x (pg, p815, z16, p1619); ++ ++ svfloat64_t poly = svmla_x (pg, p07, z16, p819); ++ ++ /* y = shift + z + z^3 * P(z^2). */ ++ svfloat64_t ret = svmla_x (pg, shift, z3, poly); + + /* Account for the sign of x and y. */ + if (__glibc_unlikely (svptest_any (pg, cmp_xy))) +diff --git a/sysdeps/aarch64/fpu/atan2f_advsimd.c b/sysdeps/aarch64/fpu/atan2f_advsimd.c +index 88daacd76cdd3998..23a825e63bfb53b2 100644 +--- a/sysdeps/aarch64/fpu/atan2f_advsimd.c ++++ b/sysdeps/aarch64/fpu/atan2f_advsimd.c +@@ -18,22 +18,22 @@ + . */ + + #include "v_math.h" +-#include "poly_advsimd_f32.h" + + static const struct data + { +- float32x4_t c0, pi_over_2, c4, c6, c2; ++ float32x4_t c0, c4, c6, c2; + float c1, c3, c5, c7; + uint32x4_t comp_const; ++ float32x4_t pi; + } data = { + /* Coefficients of polynomial P such that atan(x)~x+x*P(x^2) on + [2**-128, 1.0]. + Generated using fpminimax between FLT_MIN and 1. */ +- .c0 = V4 (-0x1.55555p-2f), .c1 = 0x1.99935ep-3f, +- .c2 = V4 (-0x1.24051ep-3f), .c3 = 0x1.bd7368p-4f, +- .c4 = V4 (-0x1.491f0ep-4f), .c5 = 0x1.93a2c0p-5f, +- .c6 = V4 (-0x1.4c3c60p-6f), .c7 = 0x1.01fd88p-8f, +- .pi_over_2 = V4 (0x1.921fb6p+0f), .comp_const = V4 (2 * 0x7f800000lu - 1), ++ .c0 = V4 (-0x1.5554dcp-2), .c1 = 0x1.9978ecp-3, ++ .c2 = V4 (-0x1.230a94p-3), .c3 = 0x1.b4debp-4, ++ .c4 = V4 (-0x1.3550dap-4), .c5 = 0x1.61eebp-5, ++ .c6 = V4 (-0x1.0c17d4p-6), .c7 = 0x1.7ea694p-9, ++ .pi = V4 (0x1.921fb6p+1f), .comp_const = V4 (2 * 0x7f800000lu - 1), + }; + + #define SignMask v_u32 (0x80000000) +@@ -54,13 +54,13 @@ static inline uint32x4_t + zeroinfnan (uint32x4_t i, const struct data *d) + { + /* 2 * i - 1 >= 2 * 0x7f800000lu - 1. */ +- return vcgeq_u32 (vsubq_u32 (vmulq_n_u32 (i, 2), v_u32 (1)), d->comp_const); ++ return vcgeq_u32 (vsubq_u32 (vshlq_n_u32 (i, 1), v_u32 (1)), d->comp_const); + } + + /* Fast implementation of vector atan2f. Maximum observed error is +- 2.95 ULP in [0x1.9300d6p+6 0x1.93c0c6p+6] x [0x1.8c2dbp+6 0x1.8cea6p+6]: +- _ZGVnN4vv_atan2f (0x1.93836cp+6, 0x1.8cae1p+6) got 0x1.967f06p-1 +- want 0x1.967f00p-1. */ ++ 2.13 ULP in [0x1.9300d6p+6 0x1.93c0c6p+6] x [0x1.8c2dbp+6 0x1.8cea6p+6]: ++ _ZGVnN4vv_atan2f (0x1.14a9d4p-87, 0x1.0eb886p-87) got 0x1.97aea2p-1 ++ want 0x1.97ae9ep-1. */ + float32x4_t VPCS_ATTR NOINLINE V_NAME_F2 (atan2) (float32x4_t y, float32x4_t x) + { + const struct data *d = ptr_barrier (&data); +@@ -81,28 +81,31 @@ float32x4_t VPCS_ATTR NOINLINE V_NAME_F2 (atan2) (float32x4_t y, float32x4_t x) + uint32x4_t pred_xlt0 = vcltzq_f32 (x); + uint32x4_t pred_aygtax = vcgtq_f32 (ay, ax); + +- /* Set up z for call to atanf. */ +- float32x4_t n = vbslq_f32 (pred_aygtax, vnegq_f32 (ax), ay); +- float32x4_t q = vbslq_f32 (pred_aygtax, ay, ax); +- float32x4_t z = vdivq_f32 (n, q); +- +- /* Work out the correct shift. */ ++ /* Set up z for evaluation of atanf. */ ++ float32x4_t num = vbslq_f32 (pred_aygtax, vnegq_f32 (ax), ay); ++ float32x4_t den = vbslq_f32 (pred_aygtax, ay, ax); ++ float32x4_t z = vdivq_f32 (num, den); ++ ++ /* Work out the correct shift for atan2: ++ Multiplication by pi is done later. ++ -pi when x < 0 and ax < ay ++ -pi/2 when x < 0 and ax > ay ++ 0 when x >= 0 and ax < ay ++ pi/2 when x >= 0 and ax > ay. */ + float32x4_t shift = vreinterpretq_f32_u32 ( +- vandq_u32 (pred_xlt0, vreinterpretq_u32_f32 (v_f32 (-2.0f)))); +- shift = vbslq_f32 (pred_aygtax, vaddq_f32 (shift, v_f32 (1.0f)), shift); +- shift = vmulq_f32 (shift, d->pi_over_2); +- +- /* Calculate the polynomial approximation. +- Use 2-level Estrin scheme for P(z^2) with deg(P)=7. However, +- a standard implementation using z8 creates spurious underflow +- in the very last fma (when z^8 is small enough). +- Therefore, we split the last fma into a mul and an fma. +- Horner and single-level Estrin have higher errors that exceed +- threshold. */ ++ vandq_u32 (pred_xlt0, vreinterpretq_u32_f32 (v_f32 (-1.0f)))); ++ float32x4_t shift2 = vreinterpretq_f32_u32 ( ++ vandq_u32 (pred_aygtax, vreinterpretq_u32_f32 (v_f32 (0.5f)))); ++ shift = vaddq_f32 (shift, shift2); ++ ++ /* Calculate the polynomial approximation. */ + float32x4_t z2 = vmulq_f32 (z, z); ++ float32x4_t z3 = vmulq_f32 (z2, z); + float32x4_t z4 = vmulq_f32 (z2, z2); ++ float32x4_t z8 = vmulq_f32 (z4, z4); + + float32x4_t c1357 = vld1q_f32 (&d->c1); ++ + float32x4_t p01 = vfmaq_laneq_f32 (d->c0, z2, c1357, 0); + float32x4_t p23 = vfmaq_laneq_f32 (d->c2, z2, c1357, 1); + float32x4_t p45 = vfmaq_laneq_f32 (d->c4, z2, c1357, 2); +@@ -110,10 +113,11 @@ float32x4_t VPCS_ATTR NOINLINE V_NAME_F2 (atan2) (float32x4_t y, float32x4_t x) + float32x4_t p03 = vfmaq_f32 (p01, z4, p23); + float32x4_t p47 = vfmaq_f32 (p45, z4, p67); + +- float32x4_t ret = vfmaq_f32 (p03, z4, vmulq_f32 (z4, p47)); ++ float32x4_t poly = vfmaq_f32 (p03, z8, p47); + + /* y = shift + z * P(z^2). */ +- ret = vaddq_f32 (vfmaq_f32 (z, ret, vmulq_f32 (z2, z)), shift); ++ float32x4_t ret = vfmaq_f32 (z, shift, d->pi); ++ ret = vfmaq_f32 (ret, z3, poly); + + if (__glibc_unlikely (v_any_u32 (special_cases))) + { +diff --git a/sysdeps/aarch64/fpu/atan2f_sve.c b/sysdeps/aarch64/fpu/atan2f_sve.c +index 9ea197147ccca0ac..f7f6d40ca668192f 100644 +--- a/sysdeps/aarch64/fpu/atan2f_sve.c ++++ b/sysdeps/aarch64/fpu/atan2f_sve.c +@@ -18,18 +18,18 @@ + . */ + + #include "sv_math.h" +-#include "poly_sve_f32.h" + + static const struct data + { +- float32_t poly[8]; ++ float32_t c0, c2, c4, c6; ++ float32_t c1, c3, c5, c7; + float32_t pi_over_2; + } data = { + /* Coefficients of polynomial P such that atan(x)~x+x*P(x^2) on + [2**-128, 1.0]. */ +- .poly = { -0x1.55555p-2f, 0x1.99935ep-3f, -0x1.24051ep-3f, 0x1.bd7368p-4f, +- -0x1.491f0ep-4f, 0x1.93a2c0p-5f, -0x1.4c3c60p-6f, 0x1.01fd88p-8f }, +- .pi_over_2 = 0x1.921fb6p+0f, ++ .c0 = -0x1.5554dcp-2, .c1 = 0x1.9978ecp-3, .c2 = -0x1.230a94p-3, ++ .c3 = 0x1.b4debp-4, .c4 = -0x1.3550dap-4, .c5 = 0x1.61eebp-5, ++ .c6 = -0x1.0c17d4p-6, .c7 = 0x1.7ea694p-9, .pi_over_2 = 0x1.921fb6p+0f, + }; + + /* Special cases i.e. 0, infinity, nan (fall back to scalar calls). */ +@@ -51,12 +51,14 @@ zeroinfnan (svuint32_t i, const svbool_t pg) + + /* Fast implementation of SVE atan2f based on atan(x) ~ shift + z + z^3 * + P(z^2) with reduction to [0,1] using z=1/x and shift = pi/2. Maximum +- observed error is 2.95 ULP: +- _ZGVsMxvv_atan2f (0x1.93836cp+6, 0x1.8cae1p+6) got 0x1.967f06p-1 +- want 0x1.967f00p-1. */ +-svfloat32_t SV_NAME_F2 (atan2) (svfloat32_t y, svfloat32_t x, const svbool_t pg) ++ observed error is 2.21 ULP: ++ _ZGVnN4vv_atan2f (0x1.a04aa8p+6, 0x1.9a274p+6) got 0x1.95ed3ap-1 ++ want 0x1.95ed36p-1. */ ++svfloat32_t SV_NAME_F2 (atan2) (svfloat32_t y, svfloat32_t x, ++ const svbool_t pg) + { +- const struct data *data_ptr = ptr_barrier (&data); ++ const struct data *d = ptr_barrier (&data); ++ svbool_t ptrue = svptrue_b32 (); + + svuint32_t ix = svreinterpret_u32 (x); + svuint32_t iy = svreinterpret_u32 (y); +@@ -76,29 +78,42 @@ svfloat32_t SV_NAME_F2 (atan2) (svfloat32_t y, svfloat32_t x, const svbool_t pg) + + svbool_t pred_aygtax = svcmpgt (pg, ay, ax); + +- /* Set up z for call to atan. */ +- svfloat32_t n = svsel (pred_aygtax, svneg_x (pg, ax), ay); +- svfloat32_t d = svsel (pred_aygtax, ay, ax); +- svfloat32_t z = svdiv_x (pg, n, d); +- +- /* Work out the correct shift. */ ++ /* Set up z for evaluation of atanf. */ ++ svfloat32_t num = svsel (pred_aygtax, svneg_x (pg, ax), ay); ++ svfloat32_t den = svsel (pred_aygtax, ay, ax); ++ svfloat32_t z = svdiv_x (ptrue, num, den); ++ ++ /* Work out the correct shift for atan2: ++ Multiplication by pi is done later. ++ -pi when x < 0 and ax < ay ++ -pi/2 when x < 0 and ax > ay ++ 0 when x >= 0 and ax < ay ++ pi/2 when x >= 0 and ax > ay. */ + svfloat32_t shift = svreinterpret_f32 (svlsr_x (pg, sign_x, 1)); + shift = svsel (pred_aygtax, sv_f32 (1.0), shift); + shift = svreinterpret_f32 (svorr_x (pg, sign_x, svreinterpret_u32 (shift))); +- shift = svmul_x (pg, shift, sv_f32 (data_ptr->pi_over_2)); + + /* Use pure Estrin scheme for P(z^2) with deg(P)=7. */ +- svfloat32_t z2 = svmul_x (pg, z, z); ++ svfloat32_t z2 = svmul_x (ptrue, z, z); ++ svfloat32_t z3 = svmul_x (pg, z2, z); + svfloat32_t z4 = svmul_x (pg, z2, z2); + svfloat32_t z8 = svmul_x (pg, z4, z4); + +- svfloat32_t ret = sv_estrin_7_f32_x (pg, z2, z4, z8, data_ptr->poly); ++ svfloat32_t odd_coeffs = svld1rq (ptrue, &d->c1); + +- /* ret = shift + z + z^3 * P(z^2). */ +- svfloat32_t z3 = svmul_x (pg, z2, z); +- ret = svmla_x (pg, z, z3, ret); ++ svfloat32_t p01 = svmla_lane (sv_f32 (d->c0), z2, odd_coeffs, 0); ++ svfloat32_t p23 = svmla_lane (sv_f32 (d->c2), z2, odd_coeffs, 1); ++ svfloat32_t p45 = svmla_lane (sv_f32 (d->c4), z2, odd_coeffs, 2); ++ svfloat32_t p67 = svmla_lane (sv_f32 (d->c6), z2, odd_coeffs, 3); + +- ret = svadd_m (pg, ret, shift); ++ svfloat32_t p03 = svmla_x (pg, p01, z4, p23); ++ svfloat32_t p47 = svmla_x (pg, p45, z4, p67); ++ ++ svfloat32_t poly = svmla_x (pg, p03, z8, p47); ++ ++ /* ret = shift + z + z^3 * P(z^2). */ ++ svfloat32_t ret = svmla_x (pg, z, shift, sv_f32 (d->pi_over_2)); ++ ret = svmla_x (pg, ret, z3, poly); + + /* Account for the sign of x and y. */ + +diff --git a/sysdeps/aarch64/fpu/atan_advsimd.c b/sysdeps/aarch64/fpu/atan_advsimd.c +index 14f1809796f05246..f835dae828ae9d3a 100644 +--- a/sysdeps/aarch64/fpu/atan_advsimd.c ++++ b/sysdeps/aarch64/fpu/atan_advsimd.c +@@ -18,7 +18,6 @@ + . */ + + #include "v_math.h" +-#include "poly_advsimd_f64.h" + + static const struct data + { +@@ -28,16 +27,16 @@ static const struct data + } data = { + /* Coefficients of polynomial P such that atan(x)~x+x*P(x^2) on + [2**-1022, 1.0]. */ +- .c0 = V2 (-0x1.5555555555555p-2), .c1 = 0x1.99999999996c1p-3, +- .c2 = V2 (-0x1.2492492478f88p-3), .c3 = 0x1.c71c71bc3951cp-4, +- .c4 = V2 (-0x1.745d160a7e368p-4), .c5 = 0x1.3b139b6a88ba1p-4, +- .c6 = V2 (-0x1.11100ee084227p-4), .c7 = 0x1.e1d0f9696f63bp-5, +- .c8 = V2 (-0x1.aebfe7b418581p-5), .c9 = 0x1.842dbe9b0d916p-5, +- .c10 = V2 (-0x1.5d30140ae5e99p-5), .c11 = 0x1.338e31eb2fbbcp-5, +- .c12 = V2 (-0x1.00e6eece7de8p-5), .c13 = 0x1.860897b29e5efp-6, +- .c14 = V2 (-0x1.0051381722a59p-6), .c15 = 0x1.14e9dc19a4a4ep-7, +- .c16 = V2 (-0x1.d0062b42fe3bfp-9), .c17 = 0x1.17739e210171ap-10, +- .c18 = V2 (-0x1.ab24da7be7402p-13), .c19 = 0x1.358851160a528p-16, ++ .c0 = V2 (-0x1.555555555552ap-2), .c1 = 0x1.9999999995aebp-3, ++ .c2 = V2 (-0x1.24924923923f6p-3), .c3 = 0x1.c71c7184288a2p-4, ++ .c4 = V2 (-0x1.745d11fb3d32bp-4), .c5 = 0x1.3b136a18051b9p-4, ++ .c6 = V2 (-0x1.110e6d985f496p-4), .c7 = 0x1.e1bcf7f08801dp-5, ++ .c8 = V2 (-0x1.ae644e28058c3p-5), .c9 = 0x1.82eeb1fed85c6p-5, ++ .c10 = V2 (-0x1.59d7f901566cbp-5), .c11 = 0x1.2c982855ab069p-5, ++ .c12 = V2 (-0x1.eb49592998177p-6), .c13 = 0x1.69d8b396e3d38p-6, ++ .c14 = V2 (-0x1.ca980345c4204p-7), .c15 = 0x1.dc050eafde0b3p-8, ++ .c16 = V2 (-0x1.7ea70755b8eccp-9), .c17 = 0x1.ba3da3de903e8p-11, ++ .c18 = V2 (-0x1.44a4b059b6f67p-13), .c19 = 0x1.c4a45029e5a91p-17, + .pi_over_2 = V2 (0x1.921fb54442d18p+0), + }; + +@@ -47,9 +46,9 @@ static const struct data + + /* Fast implementation of vector atan. + Based on atan(x) ~ shift + z + z^3 * P(z^2) with reduction to [0,1] using +- z=1/x and shift = pi/2. Maximum observed error is 2.27 ulps: +- _ZGVnN2v_atan (0x1.0005af27c23e9p+0) got 0x1.9225645bdd7c1p-1 +- want 0x1.9225645bdd7c3p-1. */ ++ z=1/x and shift = pi/2. Maximum observed error is 2.45 ulps: ++ _ZGVnN2v_atan (0x1.0008d737eb3e6p+0) got 0x1.92288c551a4c1p-1 ++ want 0x1.92288c551a4c3p-1. */ + float64x2_t VPCS_ATTR V_NAME_D1 (atan) (float64x2_t x) + { + const struct data *d = ptr_barrier (&data); +@@ -78,59 +77,53 @@ float64x2_t VPCS_ATTR V_NAME_D1 (atan) (float64x2_t x) + y := arctan(x) for x < 1 + y := pi/2 + arctan(-1/x) for x > 1 + Hence, use z=-1/a if x>=1, otherwise z=a. */ +- uint64x2_t red = vcagtq_f64 (x, v_f64 (1.0)); ++ uint64x2_t red = vcagtq_f64 (x, v_f64 (-1.0)); + /* Avoid dependency in abs(x) in division (and comparison). */ +- float64x2_t z = vbslq_f64 (red, vdivq_f64 (v_f64 (1.0), x), x); ++ float64x2_t z = vbslq_f64 (red, vdivq_f64 (v_f64 (-1.0), x), x); ++ + float64x2_t shift = vreinterpretq_f64_u64 ( + vandq_u64 (red, vreinterpretq_u64_f64 (d->pi_over_2))); +- /* Use absolute value only when needed (odd powers of z). */ +- float64x2_t az = vbslq_f64 ( +- SignMask, vreinterpretq_f64_u64 (vandq_u64 (SignMask, red)), z); +- +- /* Calculate the polynomial approximation. +- Use split Estrin scheme for P(z^2) with deg(P)=19. Use split instead of +- full scheme to avoid underflow in x^16. +- The order 19 polynomial P approximates +- (atan(sqrt(x))-sqrt(x))/x^(3/2). */ ++ ++ /* Reinsert sign bit from argument into the shift value. */ ++ shift = vreinterpretq_f64_u64 ( ++ veorq_u64 (vreinterpretq_u64_f64 (shift), sign)); ++ ++ /* Calculate polynomial approximation P(z^2) with deg(P)=19. */ + float64x2_t z2 = vmulq_f64 (z, z); +- float64x2_t x2 = vmulq_f64 (z2, z2); +- float64x2_t x4 = vmulq_f64 (x2, x2); +- float64x2_t x8 = vmulq_f64 (x4, x4); ++ float64x2_t z4 = vmulq_f64 (z2, z2); ++ float64x2_t z8 = vmulq_f64 (z4, z4); ++ float64x2_t z16 = vmulq_f64 (z8, z8); + +- /* estrin_7. */ ++ /* Order-7 Estrin. */ + float64x2_t p01 = vfmaq_laneq_f64 (d->c0, z2, c13, 0); + float64x2_t p23 = vfmaq_laneq_f64 (d->c2, z2, c13, 1); +- float64x2_t p03 = vfmaq_f64 (p01, x2, p23); ++ float64x2_t p03 = vfmaq_f64 (p01, z4, p23); + + float64x2_t p45 = vfmaq_laneq_f64 (d->c4, z2, c57, 0); + float64x2_t p67 = vfmaq_laneq_f64 (d->c6, z2, c57, 1); +- float64x2_t p47 = vfmaq_f64 (p45, x2, p67); ++ float64x2_t p47 = vfmaq_f64 (p45, z4, p67); + +- float64x2_t p07 = vfmaq_f64 (p03, x4, p47); ++ float64x2_t p07 = vfmaq_f64 (p03, z8, p47); + +- /* estrin_11. */ ++ /* Order-11 Estrin. */ + float64x2_t p89 = vfmaq_laneq_f64 (d->c8, z2, c911, 0); + float64x2_t p1011 = vfmaq_laneq_f64 (d->c10, z2, c911, 1); +- float64x2_t p811 = vfmaq_f64 (p89, x2, p1011); ++ float64x2_t p811 = vfmaq_f64 (p89, z4, p1011); + + float64x2_t p1213 = vfmaq_laneq_f64 (d->c12, z2, c1315, 0); + float64x2_t p1415 = vfmaq_laneq_f64 (d->c14, z2, c1315, 1); +- float64x2_t p1215 = vfmaq_f64 (p1213, x2, p1415); ++ float64x2_t p1215 = vfmaq_f64 (p1213, z4, p1415); + + float64x2_t p1617 = vfmaq_laneq_f64 (d->c16, z2, c1719, 0); + float64x2_t p1819 = vfmaq_laneq_f64 (d->c18, z2, c1719, 1); +- float64x2_t p1619 = vfmaq_f64 (p1617, x2, p1819); ++ float64x2_t p1619 = vfmaq_f64 (p1617, z4, p1819); + +- float64x2_t p815 = vfmaq_f64 (p811, x4, p1215); +- float64x2_t p819 = vfmaq_f64 (p815, x8, p1619); ++ float64x2_t p815 = vfmaq_f64 (p811, z8, p1215); ++ float64x2_t p819 = vfmaq_f64 (p815, z16, p1619); + +- float64x2_t y = vfmaq_f64 (p07, p819, x8); ++ float64x2_t y = vfmaq_f64 (p07, p819, z16); + + /* Finalize. y = shift + z + z^3 * P(z^2). */ +- y = vfmaq_f64 (az, y, vmulq_f64 (z2, az)); +- y = vaddq_f64 (y, shift); +- +- /* y = atan(x) if x>0, -atan(-x) otherwise. */ +- y = vreinterpretq_f64_u64 (veorq_u64 (vreinterpretq_u64_f64 (y), sign)); +- return y; ++ y = vfmsq_f64 (v_f64 (-1.0), z2, y); ++ return vfmsq_f64 (shift, z, y); + } +diff --git a/sysdeps/aarch64/fpu/atan_sve.c b/sysdeps/aarch64/fpu/atan_sve.c +index fa1630304cd43ce4..046c04fbb197b75a 100644 +--- a/sysdeps/aarch64/fpu/atan_sve.c ++++ b/sysdeps/aarch64/fpu/atan_sve.c +@@ -18,23 +18,26 @@ + . */ + + #include "sv_math.h" +-#include "poly_sve_f64.h" + + static const struct data + { +- float64_t poly[20]; +- float64_t pi_over_2; ++ float64_t c0, c2, c4, c6, c8, c10, c12, c14, c16, c18; ++ float64_t c1, c3, c5, c7, c9, c11, c13, c15, c17, c19; ++ float64_t shift_val, neg_one; + } data = { + /* Coefficients of polynomial P such that atan(x)~x+x*P(x^2) on + [2**-1022, 1.0]. */ +- .poly = { -0x1.5555555555555p-2, 0x1.99999999996c1p-3, -0x1.2492492478f88p-3, +- 0x1.c71c71bc3951cp-4, -0x1.745d160a7e368p-4, 0x1.3b139b6a88ba1p-4, +- -0x1.11100ee084227p-4, 0x1.e1d0f9696f63bp-5, -0x1.aebfe7b418581p-5, +- 0x1.842dbe9b0d916p-5, -0x1.5d30140ae5e99p-5, 0x1.338e31eb2fbbcp-5, +- -0x1.00e6eece7de8p-5, 0x1.860897b29e5efp-6, -0x1.0051381722a59p-6, +- 0x1.14e9dc19a4a4ep-7, -0x1.d0062b42fe3bfp-9, 0x1.17739e210171ap-10, +- -0x1.ab24da7be7402p-13, 0x1.358851160a528p-16, }, +- .pi_over_2 = 0x1.921fb54442d18p+0, ++ .c0 = -0x1.555555555552ap-2, .c1 = 0x1.9999999995aebp-3, ++ .c2 = -0x1.24924923923f6p-3, .c3 = 0x1.c71c7184288a2p-4, ++ .c4 = -0x1.745d11fb3d32bp-4, .c5 = 0x1.3b136a18051b9p-4, ++ .c6 = -0x1.110e6d985f496p-4, .c7 = 0x1.e1bcf7f08801dp-5, ++ .c8 = -0x1.ae644e28058c3p-5, .c9 = 0x1.82eeb1fed85c6p-5, ++ .c10 = -0x1.59d7f901566cbp-5, .c11 = 0x1.2c982855ab069p-5, ++ .c12 = -0x1.eb49592998177p-6, .c13 = 0x1.69d8b396e3d38p-6, ++ .c14 = -0x1.ca980345c4204p-7, .c15 = 0x1.dc050eafde0b3p-8, ++ .c16 = -0x1.7ea70755b8eccp-9, .c17 = 0x1.ba3da3de903e8p-11, ++ .c18 = -0x1.44a4b059b6f67p-13, .c19 = 0x1.c4a45029e5a91p-17, ++ .shift_val = 0x1.490fdaa22168cp+1, .neg_one = -1, + }; + + /* Useful constants. */ +@@ -43,15 +46,14 @@ static const struct data + /* Fast implementation of SVE atan. + Based on atan(x) ~ shift + z + z^3 * P(z^2) with reduction to [0,1] using + z=1/x and shift = pi/2. Largest errors are close to 1. The maximum observed +- error is 2.27 ulps: +- _ZGVsMxv_atan (0x1.0005af27c23e9p+0) got 0x1.9225645bdd7c1p-1 +- want 0x1.9225645bdd7c3p-1. */ ++ error is 2.08 ulps: ++ _ZGVsMxv_atan (0x1.000a7c56975e8p+0) got 0x1.922a3163e15c2p-1 ++ want 0x1.922a3163e15c4p-1. */ + svfloat64_t SV_NAME_D1 (atan) (svfloat64_t x, const svbool_t pg) + { + const struct data *d = ptr_barrier (&data); + +- /* No need to trigger special case. Small cases, infs and nans +- are supported by our approximation technique. */ ++ svbool_t ptrue = svptrue_b64 (); + svuint64_t ix = svreinterpret_u64 (x); + svuint64_t sign = svand_x (pg, ix, SignMask); + +@@ -59,32 +61,60 @@ svfloat64_t SV_NAME_D1 (atan) (svfloat64_t x, const svbool_t pg) + y := arctan(x) for x < 1 + y := pi/2 + arctan(-1/x) for x > 1 + Hence, use z=-1/a if x>=1, otherwise z=a. */ +- svbool_t red = svacgt (pg, x, 1.0); +- /* Avoid dependency in abs(x) in division (and comparison). */ +- svfloat64_t z = svsel (red, svdivr_x (pg, x, 1.0), x); +- /* Use absolute value only when needed (odd powers of z). */ +- svfloat64_t az = svabs_x (pg, z); +- az = svneg_m (az, red, az); ++ svbool_t red = svacgt (pg, x, d->neg_one); ++ svfloat64_t z = svsel (red, svdiv_x (pg, sv_f64 (d->neg_one), x), x); ++ ++ /* Reuse of -1.0f to reduce constant loads, ++ We need a shift value of 1/2, which is created via -1 + (1 + 1/2). */ ++ svfloat64_t shift ++ = svadd_z (red, sv_f64 (d->neg_one), sv_f64 (d->shift_val)); ++ ++ /* Reinserts the sign bit of the argument to handle the case of x < -1. */ ++ shift = svreinterpret_f64 (sveor_x (pg, svreinterpret_u64 (shift), sign)); + + /* Use split Estrin scheme for P(z^2) with deg(P)=19. */ +- svfloat64_t z2 = svmul_x (pg, z, z); +- svfloat64_t x2 = svmul_x (pg, z2, z2); +- svfloat64_t x4 = svmul_x (pg, x2, x2); +- svfloat64_t x8 = svmul_x (pg, x4, x4); ++ svfloat64_t z2 = svmul_x (ptrue, z, z); ++ svfloat64_t z4 = svmul_x (ptrue, z2, z2); ++ svfloat64_t z8 = svmul_x (ptrue, z4, z4); ++ svfloat64_t z16 = svmul_x (ptrue, z8, z8); + +- svfloat64_t y +- = svmla_x (pg, sv_estrin_7_f64_x (pg, z2, x2, x4, d->poly), +- sv_estrin_11_f64_x (pg, z2, x2, x4, x8, d->poly + 8), x8); ++ /* Order-7 Estrin. */ ++ svfloat64_t c13 = svld1rq (ptrue, &d->c1); ++ svfloat64_t c57 = svld1rq (ptrue, &d->c5); + +- /* y = shift + z + z^3 * P(z^2). */ +- svfloat64_t z3 = svmul_x (pg, z2, az); +- y = svmla_x (pg, az, z3, y); ++ svfloat64_t p01 = svmla_lane (sv_f64 (d->c0), z2, c13, 0); ++ svfloat64_t p23 = svmla_lane (sv_f64 (d->c2), z2, c13, 1); ++ svfloat64_t p45 = svmla_lane (sv_f64 (d->c4), z2, c57, 0); ++ svfloat64_t p67 = svmla_lane (sv_f64 (d->c6), z2, c57, 1); ++ ++ svfloat64_t p03 = svmla_x (pg, p01, z4, p23); ++ svfloat64_t p47 = svmla_x (pg, p45, z4, p67); ++ svfloat64_t p07 = svmla_x (pg, p03, z8, p47); ++ ++ /* Order-11 Estrin. */ ++ svfloat64_t c911 = svld1rq (ptrue, &d->c9); ++ svfloat64_t c1315 = svld1rq (ptrue, &d->c13); ++ svfloat64_t c1719 = svld1rq (ptrue, &d->c17); + +- /* Apply shift as indicated by `red` predicate. */ +- y = svadd_m (red, y, d->pi_over_2); ++ svfloat64_t p89 = svmla_lane (sv_f64 (d->c8), z2, c911, 0); ++ svfloat64_t p1011 = svmla_lane (sv_f64 (d->c10), z2, c911, 1); ++ svfloat64_t p811 = svmla_x (pg, p89, z4, p1011); + +- /* y = atan(x) if x>0, -atan(-x) otherwise. */ +- y = svreinterpret_f64 (sveor_x (pg, svreinterpret_u64 (y), sign)); ++ svfloat64_t p1213 = svmla_lane (sv_f64 (d->c12), z2, c1315, 0); ++ svfloat64_t p1415 = svmla_lane (sv_f64 (d->c14), z2, c1315, 1); ++ svfloat64_t p1215 = svmla_x (pg, p1213, z4, p1415); + +- return y; ++ svfloat64_t p1617 = svmla_lane (sv_f64 (d->c16), z2, c1719, 0); ++ svfloat64_t p1819 = svmla_lane (sv_f64 (d->c18), z2, c1719, 1); ++ svfloat64_t p1619 = svmla_x (pg, p1617, z4, p1819); ++ ++ svfloat64_t p815 = svmla_x (pg, p811, z8, p1215); ++ svfloat64_t p819 = svmla_x (pg, p815, z16, p1619); ++ ++ svfloat64_t y = svmla_x (pg, p07, z16, p819); ++ ++ /* y = shift + z + z^3 * P(z^2). */ ++ shift = svadd_m (red, z, shift); ++ y = svmul_x (pg, z2, y); ++ return svmla_x (pg, shift, z, y); + } +diff --git a/sysdeps/aarch64/fpu/atanf_advsimd.c b/sysdeps/aarch64/fpu/atanf_advsimd.c +index d015cc70ad4a369c..e72074ec6206e572 100644 +--- a/sysdeps/aarch64/fpu/atanf_advsimd.c ++++ b/sysdeps/aarch64/fpu/atanf_advsimd.c +@@ -22,26 +22,35 @@ + + static const struct data + { ++ uint32x4_t sign_mask, pi_over_2; ++ float32x4_t neg_one; ++#if WANT_SIMD_EXCEPT + float32x4_t poly[8]; +- float32x4_t pi_over_2; ++} data = { ++ .poly = { V4 (-0x1.5554dcp-2), V4 (0x1.9978ecp-3), V4 (-0x1.230a94p-3), ++ V4 (0x1.b4debp-4), V4 (-0x1.3550dap-4), V4 (0x1.61eebp-5), ++ V4 (-0x1.0c17d4p-6), V4 (0x1.7ea694p-9) }, ++#else ++ float32x4_t c0, c2, c4, c6; ++ float c1, c3, c5, c7; + } data = { + /* Coefficients of polynomial P such that atan(x)~x+x*P(x^2) on + [2**-128, 1.0]. + Generated using fpminimax between FLT_MIN and 1. */ +- .poly = { V4 (-0x1.55555p-2f), V4 (0x1.99935ep-3f), V4 (-0x1.24051ep-3f), +- V4 (0x1.bd7368p-4f), V4 (-0x1.491f0ep-4f), V4 (0x1.93a2c0p-5f), +- V4 (-0x1.4c3c60p-6f), V4 (0x1.01fd88p-8f) }, +- .pi_over_2 = V4 (0x1.921fb6p+0f), ++ .c0 = V4 (-0x1.5554dcp-2), .c1 = 0x1.9978ecp-3, ++ .c2 = V4 (-0x1.230a94p-3), .c3 = 0x1.b4debp-4, ++ .c4 = V4 (-0x1.3550dap-4), .c5 = 0x1.61eebp-5, ++ .c6 = V4 (-0x1.0c17d4p-6), .c7 = 0x1.7ea694p-9, ++#endif ++ .pi_over_2 = V4 (0x3fc90fdb), ++ .neg_one = V4 (-1.0f), ++ .sign_mask = V4 (0x80000000), + }; + +-#define SignMask v_u32 (0x80000000) +- +-#define P(i) d->poly[i] +- ++#if WANT_SIMD_EXCEPT + #define TinyBound 0x30800000 /* asuint(0x1p-30). */ + #define BigBound 0x4e800000 /* asuint(0x1p30). */ + +-#if WANT_SIMD_EXCEPT + static float32x4_t VPCS_ATTR NOINLINE + special_case (float32x4_t x, float32x4_t y, uint32x4_t special) + { +@@ -51,19 +60,20 @@ special_case (float32x4_t x, float32x4_t y, uint32x4_t special) + + /* Fast implementation of vector atanf based on + atan(x) ~ shift + z + z^3 * P(z^2) with reduction to [0,1] +- using z=-1/x and shift = pi/2. Maximum observed error is 2.9ulps: +- _ZGVnN4v_atanf (0x1.0468f6p+0) got 0x1.967f06p-1 want 0x1.967fp-1. */ ++ using z=-1/x and shift = pi/2. Maximum observed error is 2.02 ulps: ++ _ZGVnN4v_atanf (0x1.03d4cep+0) got 0x1.95ed3ap-1 ++ want 0x1.95ed36p-1. */ + float32x4_t VPCS_ATTR NOINLINE V_NAME_F1 (atan) (float32x4_t x) + { + const struct data *d = ptr_barrier (&data); + +- /* Small cases, infs and nans are supported by our approximation technique, +- but do not set fenv flags correctly. Only trigger special case if we need +- fenv. */ + uint32x4_t ix = vreinterpretq_u32_f32 (x); +- uint32x4_t sign = vandq_u32 (ix, SignMask); ++ uint32x4_t sign = vandq_u32 (ix, d->sign_mask); + + #if WANT_SIMD_EXCEPT ++ /* Small cases, infs and nans are supported by our approximation technique, ++ but do not set fenv flags correctly. Only trigger special case if we need ++ fenv. */ + uint32x4_t ia = vandq_u32 (ix, v_u32 (0x7ff00000)); + uint32x4_t special = vcgtq_u32 (vsubq_u32 (ia, v_u32 (TinyBound)), + v_u32 (BigBound - TinyBound)); +@@ -71,41 +81,52 @@ float32x4_t VPCS_ATTR NOINLINE V_NAME_F1 (atan) (float32x4_t x) + if (__glibc_unlikely (v_any_u32 (special))) + return special_case (x, x, v_u32 (-1)); + #endif +- + /* Argument reduction: +- y := arctan(x) for x < 1 +- y := pi/2 + arctan(-1/x) for x > 1 +- Hence, use z=-1/a if x>=1, otherwise z=a. */ +- uint32x4_t red = vcagtq_f32 (x, v_f32 (1.0)); +- /* Avoid dependency in abs(x) in division (and comparison). */ +- float32x4_t z = vbslq_f32 (red, vdivq_f32 (v_f32 (1.0f), x), x); ++ y := arctan(x) for |x| < 1 ++ y := arctan(-1/x) + pi/2 for x > +1 ++ y := arctan(-1/x) - pi/2 for x < -1 ++ Hence, use z=-1/a if x>=|-1|, otherwise z=a. */ ++ uint32x4_t red = vcagtq_f32 (x, d->neg_one); ++ ++ float32x4_t z = vbslq_f32 (red, vdivq_f32 (d->neg_one, x), x); ++ ++ /* Shift is calculated as +-pi/2 or 0, depending on the argument case. */ + float32x4_t shift = vreinterpretq_f32_u32 ( +- vandq_u32 (red, vreinterpretq_u32_f32 (d->pi_over_2))); +- /* Use absolute value only when needed (odd powers of z). */ +- float32x4_t az = vbslq_f32 ( +- SignMask, vreinterpretq_f32_u32 (vandq_u32 (SignMask, red)), z); ++ vandq_u32 (red, veorq_u32 (d->pi_over_2, sign))); ++ ++ float32x4_t z2 = vmulq_f32 (z, z); ++ float32x4_t z3 = vmulq_f32 (z, z2); ++ float32x4_t z4 = vmulq_f32 (z2, z2); ++#if WANT_SIMD_EXCEPT + + /* Calculate the polynomial approximation. + Use 2-level Estrin scheme for P(z^2) with deg(P)=7. However, + a standard implementation using z8 creates spurious underflow + in the very last fma (when z^8 is small enough). +- Therefore, we split the last fma into a mul and an fma. +- Horner and single-level Estrin have higher errors that exceed +- threshold. */ +- float32x4_t z2 = vmulq_f32 (z, z); +- float32x4_t z4 = vmulq_f32 (z2, z2); +- ++ Therefore, we split the last fma into a mul and an fma. */ + float32x4_t y = vfmaq_f32 ( + v_pairwise_poly_3_f32 (z2, z4, d->poly), z4, + vmulq_f32 (z4, v_pairwise_poly_3_f32 (z2, z4, d->poly + 4))); + +- /* y = shift + z * P(z^2). */ +- y = vaddq_f32 (vfmaq_f32 (az, y, vmulq_f32 (z2, az)), shift); ++#else ++ float32x4_t z8 = vmulq_f32 (z4, z4); ++ ++ /* Uses an Estrin scheme for polynomial approximation. */ ++ float32x4_t odd_coeffs = vld1q_f32 (&d->c1); ++ ++ float32x4_t p01 = vfmaq_laneq_f32 (d->c0, z2, odd_coeffs, 0); ++ float32x4_t p23 = vfmaq_laneq_f32 (d->c2, z2, odd_coeffs, 1); ++ float32x4_t p45 = vfmaq_laneq_f32 (d->c4, z2, odd_coeffs, 2); ++ float32x4_t p67 = vfmaq_laneq_f32 (d->c6, z2, odd_coeffs, 3); + +- /* y = atan(x) if x>0, -atan(-x) otherwise. */ +- y = vreinterpretq_f32_u32 (veorq_u32 (vreinterpretq_u32_f32 (y), sign)); ++ float32x4_t p03 = vfmaq_f32 (p01, z4, p23); ++ float32x4_t p47 = vfmaq_f32 (p45, z4, p67); + +- return y; ++ float32x4_t y = vfmaq_f32 (p03, z8, p47); ++#endif ++ ++ /* y = shift + z * P(z^2). */ ++ return vfmaq_f32 (vaddq_f32 (shift, z), z3, y); + } + libmvec_hidden_def (V_NAME_F1 (atan)) + HALF_WIDTH_ALIAS_F1 (atan) +diff --git a/sysdeps/aarch64/fpu/atanf_sve.c b/sysdeps/aarch64/fpu/atanf_sve.c +index 7b54094586c20590..0f5a054743dc47d3 100644 +--- a/sysdeps/aarch64/fpu/atanf_sve.c ++++ b/sysdeps/aarch64/fpu/atanf_sve.c +@@ -18,18 +18,26 @@ + . */ + + #include "sv_math.h" +-#include "poly_sve_f32.h" + + static const struct data + { +- float32_t poly[8]; +- float32_t pi_over_2; ++ float32_t c1, c3, c5, c7; ++ float32_t c0, c2, c4, c6; ++ float32_t shift_val, neg_one; + } data = { + /* Coefficients of polynomial P such that atan(x)~x+x*P(x^2) on + [2**-128, 1.0]. */ +- .poly = { -0x1.55555p-2f, 0x1.99935ep-3f, -0x1.24051ep-3f, 0x1.bd7368p-4f, +- -0x1.491f0ep-4f, 0x1.93a2c0p-5f, -0x1.4c3c60p-6f, 0x1.01fd88p-8f }, +- .pi_over_2 = 0x1.921fb6p+0f, ++ .c0 = -0x1.5554dcp-2, ++ .c1 = 0x1.9978ecp-3, ++ .c2 = -0x1.230a94p-3, ++ .c3 = 0x1.b4debp-4, ++ .c4 = -0x1.3550dap-4, ++ .c5 = 0x1.61eebp-5, ++ .c6 = -0x1.0c17d4p-6, ++ .c7 = 0x1.7ea694p-9, ++ /* pi/2, used as a shift value after reduction. */ ++ .shift_val = 0x1.921fb54442d18p+0, ++ .neg_one = -1.0f, + }; + + #define SignMask (0x80000000) +@@ -37,43 +45,49 @@ static const struct data + /* Fast implementation of SVE atanf based on + atan(x) ~ shift + z + z^3 * P(z^2) with reduction to [0,1] using + z=-1/x and shift = pi/2. +- Largest observed error is 2.9 ULP, close to +/-1.0: +- _ZGVsMxv_atanf (0x1.0468f6p+0) got -0x1.967f06p-1 +- want -0x1.967fp-1. */ ++ Largest observed error is 2.12 ULP: ++ _ZGVsMxv_atanf (0x1.03d4cep+0) got 0x1.95ed3ap-1 ++ want 0x1.95ed36p-1. */ + svfloat32_t SV_NAME_F1 (atan) (svfloat32_t x, const svbool_t pg) + { + const struct data *d = ptr_barrier (&data); ++ svbool_t ptrue = svptrue_b32 (); + + /* No need to trigger special case. Small cases, infs and nans + are supported by our approximation technique. */ + svuint32_t ix = svreinterpret_u32 (x); +- svuint32_t sign = svand_x (pg, ix, SignMask); ++ svuint32_t sign = svand_x (ptrue, ix, SignMask); + + /* Argument reduction: + y := arctan(x) for x < 1 +- y := pi/2 + arctan(-1/x) for x > 1 +- Hence, use z=-1/a if x>=1, otherwise z=a. */ +- svbool_t red = svacgt (pg, x, 1.0f); +- /* Avoid dependency in abs(x) in division (and comparison). */ +- svfloat32_t z = svsel (red, svdiv_x (pg, sv_f32 (1.0f), x), x); +- /* Use absolute value only when needed (odd powers of z). */ +- svfloat32_t az = svabs_x (pg, z); +- az = svneg_m (az, red, az); +- +- /* Use split Estrin scheme for P(z^2) with deg(P)=7. */ +- svfloat32_t z2 = svmul_x (pg, z, z); +- svfloat32_t z4 = svmul_x (pg, z2, z2); +- svfloat32_t z8 = svmul_x (pg, z4, z4); +- +- svfloat32_t y = sv_estrin_7_f32_x (pg, z2, z4, z8, d->poly); +- +- /* y = shift + z + z^3 * P(z^2). */ +- svfloat32_t z3 = svmul_x (pg, z2, az); +- y = svmla_x (pg, az, z3, y); +- +- /* Apply shift as indicated by 'red' predicate. */ +- y = svadd_m (red, y, sv_f32 (d->pi_over_2)); +- +- /* y = atan(x) if x>0, -atan(-x) otherwise. */ +- return svreinterpret_f32 (sveor_x (pg, svreinterpret_u32 (y), sign)); ++ y := arctan(-1/x) + pi/2 for x > +1 ++ y := arctan(-1/x) - pi/2 for x < -1 ++ Hence, use z=-1/a if |x|>=|-1|, otherwise z=a. */ ++ svbool_t red = svacgt (pg, x, d->neg_one); ++ svfloat32_t z = svsel (red, svdiv_x (pg, sv_f32 (d->neg_one), x), x); ++ ++ /* Reinserts the sign bit of the argument to handle the case of x < -1. */ ++ svfloat32_t shift = svreinterpret_f32 ( ++ sveor_x (red, svreinterpret_u32 (sv_f32 (d->shift_val)), sign)); ++ ++ svfloat32_t z2 = svmul_x (ptrue, z, z); ++ svfloat32_t z3 = svmul_x (ptrue, z2, z); ++ svfloat32_t z4 = svmul_x (ptrue, z2, z2); ++ svfloat32_t z8 = svmul_x (ptrue, z4, z4); ++ ++ svfloat32_t odd_coeffs = svld1rq (ptrue, &d->c1); ++ ++ svfloat32_t p01 = svmla_lane (sv_f32 (d->c0), z2, odd_coeffs, 0); ++ svfloat32_t p23 = svmla_lane (sv_f32 (d->c2), z2, odd_coeffs, 1); ++ svfloat32_t p45 = svmla_lane (sv_f32 (d->c4), z2, odd_coeffs, 2); ++ svfloat32_t p67 = svmla_lane (sv_f32 (d->c6), z2, odd_coeffs, 3); ++ ++ svfloat32_t p03 = svmla_x (pg, p01, z4, p23); ++ svfloat32_t p47 = svmla_x (pg, p45, z4, p67); ++ ++ svfloat32_t y = svmla_x (pg, p03, z8, p47); ++ ++ /* shift + z + z^3 * P(z^2). */ ++ shift = svadd_m (red, z, shift); ++ return svmla_x (pg, shift, z3, y); + } diff --git a/glibc-upstream-2.39-215.patch b/glibc-upstream-2.39-215.patch new file mode 100644 index 0000000..75c81e8 --- /dev/null +++ b/glibc-upstream-2.39-215.patch @@ -0,0 +1,135 @@ +commit 392e6cf1e86e29fe155c21351cd7b7a0fd371f5b +Author: Luna Lamb +Date: Thu May 29 15:22:51 2025 +0000 + + AArch64: Improve codegen in SVE log1p + + Improves memory access, reformat evaluation scheme to pack coefficients. + 5% improvement in throughput microbenchmark on Neoverse V1. + + Reviewed-by: Wilco Dijkstra + (cherry picked from commit da196e6134ede64728006518352d75b6c3902fec) + +diff --git a/sysdeps/aarch64/fpu/log1p_sve.c b/sysdeps/aarch64/fpu/log1p_sve.c +index 04f7e5720e13c371..5251f3c07566eec3 100644 +--- a/sysdeps/aarch64/fpu/log1p_sve.c ++++ b/sysdeps/aarch64/fpu/log1p_sve.c +@@ -22,19 +22,33 @@ + + static const struct data + { +- double poly[19]; ++ float64_t c0, c2, c4, c6, c8, c10, c12, c14, c16; ++ float64_t c1, c3, c5, c7, c9, c11, c13, c15, c17, c18; + double ln2_hi, ln2_lo; + uint64_t hfrt2_top, onemhfrt2_top, inf, mone; + } data = { + /* Generated using Remez in [ sqrt(2)/2 - 1, sqrt(2) - 1]. Order 20 +- polynomial, however first 2 coefficients are 0 and 1 so are not stored. */ +- .poly = { -0x1.ffffffffffffbp-2, 0x1.55555555551a9p-2, -0x1.00000000008e3p-2, +- 0x1.9999999a32797p-3, -0x1.555555552fecfp-3, 0x1.249248e071e5ap-3, +- -0x1.ffffff8bf8482p-4, 0x1.c71c8f07da57ap-4, -0x1.9999ca4ccb617p-4, +- 0x1.7459ad2e1dfa3p-4, -0x1.554d2680a3ff2p-4, 0x1.3b4c54d487455p-4, +- -0x1.2548a9ffe80e6p-4, 0x1.0f389a24b2e07p-4, -0x1.eee4db15db335p-5, +- 0x1.e95b494d4a5ddp-5, -0x1.15fdf07cb7c73p-4, 0x1.0310b70800fcfp-4, +- -0x1.cfa7385bdb37ep-6, }, ++ polynomial, however first 2 coefficients are 0 and 1 so are not ++ stored. */ ++ .c0 = -0x1.ffffffffffffbp-2, ++ .c1 = 0x1.55555555551a9p-2, ++ .c2 = -0x1.00000000008e3p-2, ++ .c3 = 0x1.9999999a32797p-3, ++ .c4 = -0x1.555555552fecfp-3, ++ .c5 = 0x1.249248e071e5ap-3, ++ .c6 = -0x1.ffffff8bf8482p-4, ++ .c7 = 0x1.c71c8f07da57ap-4, ++ .c8 = -0x1.9999ca4ccb617p-4, ++ .c9 = 0x1.7459ad2e1dfa3p-4, ++ .c10 = -0x1.554d2680a3ff2p-4, ++ .c11 = 0x1.3b4c54d487455p-4, ++ .c12 = -0x1.2548a9ffe80e6p-4, ++ .c13 = 0x1.0f389a24b2e07p-4, ++ .c14 = -0x1.eee4db15db335p-5, ++ .c15 = 0x1.e95b494d4a5ddp-5, ++ .c16 = -0x1.15fdf07cb7c73p-4, ++ .c17 = 0x1.0310b70800fcfp-4, ++ .c18 = -0x1.cfa7385bdb37ep-6, + .ln2_hi = 0x1.62e42fefa3800p-1, + .ln2_lo = 0x1.ef35793c76730p-45, + /* top32(asuint64(sqrt(2)/2)) << 32. */ +@@ -49,7 +63,7 @@ static const struct data + #define BottomMask 0xffffffff + + static svfloat64_t NOINLINE +-special_case (svbool_t special, svfloat64_t x, svfloat64_t y) ++special_case (svfloat64_t x, svfloat64_t y, svbool_t special) + { + return sv_call_f64 (log1p, x, y, special); + } +@@ -91,8 +105,9 @@ svfloat64_t SV_NAME_D1 (log1p) (svfloat64_t x, svbool_t pg) + /* Reduce x to f in [sqrt(2)/2, sqrt(2)]. */ + svuint64_t utop + = svadd_x (pg, svand_x (pg, u, 0x000fffff00000000), d->hfrt2_top); +- svuint64_t u_red = svorr_x (pg, utop, svand_x (pg, mi, BottomMask)); +- svfloat64_t f = svsub_x (pg, svreinterpret_f64 (u_red), 1); ++ svuint64_t u_red ++ = svorr_x (pg, utop, svand_x (svptrue_b64 (), mi, BottomMask)); ++ svfloat64_t f = svsub_x (svptrue_b64 (), svreinterpret_f64 (u_red), 1); + + /* Correction term c/m. */ + svfloat64_t cm = svdiv_x (pg, svsub_x (pg, x, svsub_x (pg, m, 1)), m); +@@ -103,16 +118,47 @@ svfloat64_t SV_NAME_D1 (log1p) (svfloat64_t x, svbool_t pg) + Hence approximation has the form f + f^2 * P(f) + where P(x) = C0 + C1*x + C2x^2 + ... + Assembling this all correctly is dealt with at the final step. */ +- svfloat64_t f2 = svmul_x (pg, f, f), f4 = svmul_x (pg, f2, f2), +- f8 = svmul_x (pg, f4, f4), f16 = svmul_x (pg, f8, f8); +- svfloat64_t p = sv_estrin_18_f64_x (pg, f, f2, f4, f8, f16, d->poly); ++ svfloat64_t f2 = svmul_x (svptrue_b64 (), f, f), ++ f4 = svmul_x (svptrue_b64 (), f2, f2), ++ f8 = svmul_x (svptrue_b64 (), f4, f4), ++ f16 = svmul_x (svptrue_b64 (), f8, f8); ++ ++ svfloat64_t c13 = svld1rq (svptrue_b64 (), &d->c1); ++ svfloat64_t c57 = svld1rq (svptrue_b64 (), &d->c5); ++ svfloat64_t c911 = svld1rq (svptrue_b64 (), &d->c9); ++ svfloat64_t c1315 = svld1rq (svptrue_b64 (), &d->c13); ++ svfloat64_t c1718 = svld1rq (svptrue_b64 (), &d->c17); ++ ++ /* Order-18 Estrin scheme. */ ++ svfloat64_t p01 = svmla_lane (sv_f64 (d->c0), f, c13, 0); ++ svfloat64_t p23 = svmla_lane (sv_f64 (d->c2), f, c13, 1); ++ svfloat64_t p45 = svmla_lane (sv_f64 (d->c4), f, c57, 0); ++ svfloat64_t p67 = svmla_lane (sv_f64 (d->c6), f, c57, 1); ++ ++ svfloat64_t p03 = svmla_x (pg, p01, f2, p23); ++ svfloat64_t p47 = svmla_x (pg, p45, f2, p67); ++ svfloat64_t p07 = svmla_x (pg, p03, f4, p47); ++ ++ svfloat64_t p89 = svmla_lane (sv_f64 (d->c8), f, c911, 0); ++ svfloat64_t p1011 = svmla_lane (sv_f64 (d->c10), f, c911, 1); ++ svfloat64_t p1213 = svmla_lane (sv_f64 (d->c12), f, c1315, 0); ++ svfloat64_t p1415 = svmla_lane (sv_f64 (d->c14), f, c1315, 1); ++ ++ svfloat64_t p811 = svmla_x (pg, p89, f2, p1011); ++ svfloat64_t p1215 = svmla_x (pg, p1213, f2, p1415); ++ svfloat64_t p815 = svmla_x (pg, p811, f4, p1215); ++ ++ svfloat64_t p015 = svmla_x (pg, p07, f8, p815); ++ svfloat64_t p1617 = svmla_lane (sv_f64 (d->c16), f, c1718, 0); ++ svfloat64_t p1618 = svmla_lane (p1617, f2, c1718, 1); ++ svfloat64_t p = svmla_x (pg, p015, f16, p1618); + + svfloat64_t ylo = svmla_x (pg, cm, k, d->ln2_lo); + svfloat64_t yhi = svmla_x (pg, f, k, d->ln2_hi); +- svfloat64_t y = svmla_x (pg, svadd_x (pg, ylo, yhi), f2, p); + + if (__glibc_unlikely (svptest_any (pg, special))) +- return special_case (special, x, y); +- +- return y; ++ return special_case ( ++ x, svmla_x (svptrue_b64 (), svadd_x (svptrue_b64 (), ylo, yhi), f2, p), ++ special); ++ return svmla_x (svptrue_b64 (), svadd_x (svptrue_b64 (), ylo, yhi), f2, p); + } diff --git a/glibc-RHEL-104853-1.patch b/glibc-upstream-2.39-216.patch similarity index 99% rename from glibc-RHEL-104853-1.patch rename to glibc-upstream-2.39-216.patch index 980f6c6..027370d 100644 --- a/glibc-RHEL-104853-1.patch +++ b/glibc-upstream-2.39-216.patch @@ -62,7 +62,7 @@ Date: Thu Feb 22 10:42:55 2024 -0300 (cherry picked from commit f4c142bb9fe6b02c0af8cfca8a920091e2dba44b) diff --git a/elf/Makefile b/elf/Makefile -index 0d34de3b2c99e5bd..a8193a0d0b5b64a6 100644 +index 92da608da1ebc175..f5646c434f19a667 100644 --- a/elf/Makefile +++ b/elf/Makefile @@ -34,6 +34,7 @@ routines = \ diff --git a/glibc-RHEL-104853-2.patch b/glibc-upstream-2.39-217.patch similarity index 98% rename from glibc-RHEL-104853-2.patch rename to glibc-upstream-2.39-217.patch index b5d0aea..b185066 100644 --- a/glibc-RHEL-104853-2.patch +++ b/glibc-upstream-2.39-217.patch @@ -14,7 +14,7 @@ Date: Sat Feb 1 12:37:58 2025 +0100 (cherry picked from commit 96429bcc91a14f71b177ddc5e716de3069060f2c) diff --git a/elf/Makefile b/elf/Makefile -index a8193a0d0b5b64a6..0d34de3b2c99e5bd 100644 +index f5646c434f19a667..92da608da1ebc175 100644 --- a/elf/Makefile +++ b/elf/Makefile @@ -34,7 +34,6 @@ routines = \ diff --git a/glibc-RHEL-104853-3.patch b/glibc-upstream-2.39-218.patch similarity index 100% rename from glibc-RHEL-104853-3.patch rename to glibc-upstream-2.39-218.patch diff --git a/glibc-RHEL-104853-4.patch b/glibc-upstream-2.39-219.patch similarity index 99% rename from glibc-RHEL-104853-4.patch rename to glibc-upstream-2.39-219.patch index deb2456..f2ea96e 100644 --- a/glibc-RHEL-104853-4.patch +++ b/glibc-upstream-2.39-219.patch @@ -30,10 +30,10 @@ Date: Fri Aug 1 12:19:49 2025 +0200 (cherry picked from commit 20681be149b9eb1b6c1f4246bf4bd801221c86cd) diff --git a/elf/Makefile b/elf/Makefile -index 0d34de3b2c99e5bd..39aabe04a85f26f4 100644 +index 92da608da1ebc175..3085a0844c6604fe 100644 --- a/elf/Makefile +++ b/elf/Makefile -@@ -513,6 +513,8 @@ tests-internal += \ +@@ -514,6 +514,8 @@ tests-internal += \ tst-dl_find_object \ tst-dl_find_object-threads \ tst-dlmopen2 \ @@ -42,7 +42,7 @@ index 0d34de3b2c99e5bd..39aabe04a85f26f4 100644 tst-ptrguard1 \ tst-stackguard1 \ tst-tls-surplus \ -@@ -524,6 +526,10 @@ tests-internal += \ +@@ -525,6 +527,10 @@ tests-internal += \ unload2 \ # tests-internal diff --git a/glibc-upstream-2.39-220.patch b/glibc-upstream-2.39-220.patch new file mode 100644 index 0000000..d4cd8f9 --- /dev/null +++ b/glibc-upstream-2.39-220.patch @@ -0,0 +1,41 @@ +commit fca59375106e798911f3793768e94ee114542e3e +Author: Carlos O'Donell +Date: Thu Jun 8 06:43:44 2023 -0400 + + ctype: Reformat Makefile. + + Reflow and sort Makefile. + + Code generation changes present due to link order changes. + + No regressions on x86_64 and i686. + + (cherry picked from commit 12956e0a330e3d90fc196f7d7a047ce613f78920) + +diff --git a/ctype/Makefile b/ctype/Makefile +index 717d02012942e0b9..3e09938bd1bb1522 100644 +--- a/ctype/Makefile ++++ b/ctype/Makefile +@@ -24,9 +24,18 @@ include ../Makeconfig + + headers := ctype.h + +-routines := ctype ctype-c99 ctype-extn ctype-c99_l ctype_l isctype +-aux := ctype-info +- +-tests := test_ctype ++routines := \ ++ ctype \ ++ ctype-c99 \ ++ ctype-c99_l \ ++ ctype-extn \ ++ ctype_l \ ++ isctype \ ++ # routines ++aux := ctype-info ++ ++tests := \ ++ test_ctype \ ++ # tests + + include ../Rules diff --git a/glibc-upstream-2.39-221.patch b/glibc-upstream-2.39-221.patch new file mode 100644 index 0000000..e1b3b2e --- /dev/null +++ b/glibc-upstream-2.39-221.patch @@ -0,0 +1,296 @@ +commit fbdf9680cc67d5646607c3d6fdc146fedc383a2a +Author: Florian Weimer +Date: Fri May 16 19:53:09 2025 +0200 + + Remove + + Use __thread variables directly instead. The macros do not save any + typing. It seems unlikely that a future port will lack __thread + variable support. + + Some of the __libc_tsd_* variables are referenced from assembler + files, so keep their names. Previously, included + , which in turn included , so a few direct includes + of are now required. + + Reviewed-by: Frédéric Bérat + (cherry picked from commit 10a66a8e421b09682b774c795ef1da402235dddc) + +diff --git a/ctype/ctype-info.c b/ctype/ctype-info.c +index 9032547567b2c348..71d1c8e3b4660d54 100644 +--- a/ctype/ctype-info.c ++++ b/ctype/ctype-info.c +@@ -19,20 +19,20 @@ + #include + #include + +-__libc_tsd_define (, const uint16_t *, CTYPE_B) +-__libc_tsd_define (, const int32_t *, CTYPE_TOLOWER) +-__libc_tsd_define (, const int32_t *, CTYPE_TOUPPER) ++__thread const uint16_t * __libc_tsd_CTYPE_B; ++__thread const int32_t * __libc_tsd_CTYPE_TOLOWER; ++__thread const int32_t * __libc_tsd_CTYPE_TOUPPER; + + + void + __ctype_init (void) + { +- const uint16_t **bp = __libc_tsd_address (const uint16_t *, CTYPE_B); +- *bp = (const uint16_t *) _NL_CURRENT (LC_CTYPE, _NL_CTYPE_CLASS) + 128; +- const int32_t **up = __libc_tsd_address (const int32_t *, CTYPE_TOUPPER); +- *up = ((int32_t *) _NL_CURRENT (LC_CTYPE, _NL_CTYPE_TOUPPER) + 128); +- const int32_t **lp = __libc_tsd_address (const int32_t *, CTYPE_TOLOWER); +- *lp = ((int32_t *) _NL_CURRENT (LC_CTYPE, _NL_CTYPE_TOLOWER) + 128); ++ __libc_tsd_CTYPE_B ++ = ((const uint16_t *) _NL_CURRENT (LC_CTYPE, _NL_CTYPE_CLASS)) + 128; ++ __libc_tsd_CTYPE_TOUPPER ++ = ((const int32_t *) _NL_CURRENT (LC_CTYPE, _NL_CTYPE_TOUPPER)) + 128; ++ __libc_tsd_CTYPE_TOLOWER = ++ ((const int32_t *) _NL_CURRENT (LC_CTYPE, _NL_CTYPE_TOLOWER)) + 128; + } + libc_hidden_def (__ctype_init) + +diff --git a/include/ctype.h b/include/ctype.h +index 493a6f80ce8e8b8e..e993adc86da43b7c 100644 +--- a/include/ctype.h ++++ b/include/ctype.h +@@ -24,33 +24,32 @@ libc_hidden_proto (toupper) + NL_CURRENT_INDIRECT. */ + + # include "../locale/localeinfo.h" +-# include + + # ifndef CTYPE_EXTERN_INLINE /* Used by ctype/ctype-info.c, which see. */ + # define CTYPE_EXTERN_INLINE extern inline + # endif + +-__libc_tsd_define (extern, const uint16_t *, CTYPE_B) +-__libc_tsd_define (extern, const int32_t *, CTYPE_TOUPPER) +-__libc_tsd_define (extern, const int32_t *, CTYPE_TOLOWER) ++extern __thread const uint16_t * __libc_tsd_CTYPE_B; ++extern __thread const int32_t * __libc_tsd_CTYPE_TOUPPER; ++extern __thread const int32_t * __libc_tsd_CTYPE_TOLOWER; + + + CTYPE_EXTERN_INLINE const uint16_t ** __attribute__ ((const)) + __ctype_b_loc (void) + { +- return __libc_tsd_address (const uint16_t *, CTYPE_B); ++ return &__libc_tsd_CTYPE_B; + } + + CTYPE_EXTERN_INLINE const int32_t ** __attribute__ ((const)) + __ctype_toupper_loc (void) + { +- return __libc_tsd_address (const int32_t *, CTYPE_TOUPPER); ++ return &__libc_tsd_CTYPE_TOUPPER; + } + + CTYPE_EXTERN_INLINE const int32_t ** __attribute__ ((const)) + __ctype_tolower_loc (void) + { +- return __libc_tsd_address (const int32_t *, CTYPE_TOLOWER); ++ return &__libc_tsd_CTYPE_TOLOWER; + } + + # ifndef __NO_CTYPE +diff --git a/include/rpc/rpc.h b/include/rpc/rpc.h +index f5cee6caef6284d2..936ea3cebb8101e1 100644 +--- a/include/rpc/rpc.h ++++ b/include/rpc/rpc.h +@@ -3,8 +3,6 @@ + + # ifndef _ISOMAC + +-#include +- + /* Now define the internal interfaces. */ + extern unsigned long _create_xid (void); + +@@ -47,7 +45,7 @@ extern void __rpc_thread_key_cleanup (void) attribute_hidden; + + extern void __rpc_thread_destroy (void) attribute_hidden; + +-__libc_tsd_define (extern, struct rpc_thread_variables *, RPC_VARS) ++extern __thread struct rpc_thread_variables *__libc_tsd_RPC_VARS; + + #define RPC_THREAD_VARIABLE(x) (__rpc_thread_variables()->x) + +diff --git a/locale/lc-ctype.c b/locale/lc-ctype.c +index c77ec51cb89b839d..70556acaf0dc69bb 100644 +--- a/locale/lc-ctype.c ++++ b/locale/lc-ctype.c +@@ -64,12 +64,9 @@ _nl_postload_ctype (void) + in fact using the global locale. */ + if (_NL_CURRENT_LOCALE == &_nl_global_locale) + { +- __libc_tsd_set (const uint16_t *, CTYPE_B, +- (void *) _nl_global_locale.__ctype_b); +- __libc_tsd_set (const int32_t *, CTYPE_TOUPPER, +- (void *) _nl_global_locale.__ctype_toupper); +- __libc_tsd_set (const int32_t *, CTYPE_TOLOWER, +- (void *) _nl_global_locale.__ctype_tolower); ++ __libc_tsd_CTYPE_B = _nl_global_locale.__ctype_b; ++ __libc_tsd_CTYPE_TOUPPER = _nl_global_locale.__ctype_toupper; ++ __libc_tsd_CTYPE_TOLOWER = _nl_global_locale.__ctype_tolower; + } + + #include +diff --git a/locale/localeinfo.h b/locale/localeinfo.h +index ed698faef1b38003..bc8e92e4dca80d62 100644 +--- a/locale/localeinfo.h ++++ b/locale/localeinfo.h +@@ -236,10 +236,8 @@ extern struct __locale_struct _nl_global_locale attribute_hidden; + + /* This fetches the thread-local locale_t pointer, either one set with + uselocale or &_nl_global_locale. */ +-#define _NL_CURRENT_LOCALE (__libc_tsd_get (locale_t, LOCALE)) +-#include +-__libc_tsd_define (extern, locale_t, LOCALE) +- ++#define _NL_CURRENT_LOCALE __libc_tsd_LOCALE ++extern __thread locale_t __libc_tsd_LOCALE; + + /* For static linking it is desireable to avoid always linking in the code + and data for every category when we can tell at link time that they are +diff --git a/locale/uselocale.c b/locale/uselocale.c +index 8136caf61b4673fb..0b247a77d5f47f81 100644 +--- a/locale/uselocale.c ++++ b/locale/uselocale.c +@@ -34,7 +34,7 @@ __uselocale (locale_t newloc) + { + const locale_t locobj + = newloc == LC_GLOBAL_LOCALE ? &_nl_global_locale : newloc; +- __libc_tsd_set (locale_t, LOCALE, locobj); ++ __libc_tsd_LOCALE = locobj; + + #ifdef NL_CURRENT_INDIRECT + /* Now we must update all the per-category thread-local variables to +@@ -62,11 +62,9 @@ __uselocale (locale_t newloc) + #endif + + /* Update the special tsd cache of some locale data. */ +- __libc_tsd_set (const uint16_t *, CTYPE_B, (void *) locobj->__ctype_b); +- __libc_tsd_set (const int32_t *, CTYPE_TOLOWER, +- (void *) locobj->__ctype_tolower); +- __libc_tsd_set (const int32_t *, CTYPE_TOUPPER, +- (void *) locobj->__ctype_toupper); ++ __libc_tsd_CTYPE_B = locobj->__ctype_b; ++ __libc_tsd_CTYPE_TOLOWER = locobj->__ctype_tolower; ++ __libc_tsd_CTYPE_TOUPPER = locobj->__ctype_toupper; + } + + return oldloc == &_nl_global_locale ? LC_GLOBAL_LOCALE : oldloc; +diff --git a/stdio-common/printf-parsemb.c b/stdio-common/printf-parsemb.c +index ab9fafb5ecb12f16..8db18f11b32c9433 100644 +--- a/stdio-common/printf-parsemb.c ++++ b/stdio-common/printf-parsemb.c +@@ -17,6 +17,7 @@ + . */ + + #include ++#include + #include + #include + #include +diff --git a/string/strerror.c b/string/strerror.c +index 107d9d39c287bed4..efa4e903ead00a47 100644 +--- a/string/strerror.c ++++ b/string/strerror.c +@@ -21,5 +21,5 @@ + char * + strerror (int errnum) + { +- return __strerror_l (errnum, __libc_tsd_get (locale_t, LOCALE)); ++ return __strerror_l (errnum, __libc_tsd_LOCALE); + } +diff --git a/sunrpc/rpc_thread.c b/sunrpc/rpc_thread.c +index a04b7ec47fa4760c..e20f0a62302eb675 100644 +--- a/sunrpc/rpc_thread.c ++++ b/sunrpc/rpc_thread.c +@@ -3,7 +3,6 @@ + #include + + #include +-#include + #include + #include + +diff --git a/sysdeps/generic/libc-tsd.h b/sysdeps/generic/libc-tsd.h +deleted file mode 100644 +index ac0e99e14b1bcb90..0000000000000000 +--- a/sysdeps/generic/libc-tsd.h ++++ /dev/null +@@ -1,60 +0,0 @@ +-/* libc-internal interface for thread-specific data. Stub or TLS version. +- Copyright (C) 1998-2024 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 +- . */ +- +-#ifndef _GENERIC_LIBC_TSD_H +-#define _GENERIC_LIBC_TSD_H 1 +- +-/* This file defines the following macros for accessing a small fixed +- set of thread-specific `void *' data used only internally by libc. +- +- __libc_tsd_define(CLASS, TYPE, KEY) -- Define or declare a datum with TYPE +- for KEY. CLASS can be `static' for +- keys used in only one source file, +- empty for global definitions, or +- `extern' for global declarations. +- __libc_tsd_address(TYPE, KEY) -- Return the `TYPE *' pointing to +- the current thread's datum for KEY. +- __libc_tsd_get(TYPE, KEY) -- Return the `TYPE' datum for KEY. +- __libc_tsd_set(TYPE, KEY, VALUE) -- Set the datum for KEY to VALUE. +- +- The set of available KEY's will usually be provided as an enum, +- and contains (at least): +- _LIBC_TSD_KEY_MALLOC +- _LIBC_TSD_KEY_DL_ERROR +- _LIBC_TSD_KEY_RPC_VARS +- All uses must be the literal _LIBC_TSD_* name in the __libc_tsd_* macros. +- Some implementations may not provide any enum at all and instead +- using string pasting in the macros. */ +- +-#include +- +-/* When full support for __thread variables is available, this interface is +- just a trivial wrapper for it. Without TLS, this is the generic/stub +- implementation for wholly single-threaded systems. +- +- We don't define an enum for the possible key values, because the KEYs +- translate directly into variables by macro magic. */ +- +-#define __libc_tsd_define(CLASS, TYPE, KEY) \ +- CLASS __thread TYPE __libc_tsd_##KEY attribute_tls_model_ie; +- +-#define __libc_tsd_address(TYPE, KEY) (&__libc_tsd_##KEY) +-#define __libc_tsd_get(TYPE, KEY) (__libc_tsd_##KEY) +-#define __libc_tsd_set(TYPE, KEY, VALUE) (__libc_tsd_##KEY = (VALUE)) +- +-#endif /* libc-tsd.h */ +diff --git a/time/strftime_l.c b/time/strftime_l.c +index 77adec905007d53a..066c839c2feccdc1 100644 +--- a/time/strftime_l.c ++++ b/time/strftime_l.c +@@ -40,6 +40,7 @@ + #endif + + #include ++#include + #include /* Some systems define `time_t' here. */ + + #ifdef TIME_WITH_SYS_TIME diff --git a/glibc-upstream-2.39-222.patch b/glibc-upstream-2.39-222.patch new file mode 100644 index 0000000..ad625e7 --- /dev/null +++ b/glibc-upstream-2.39-222.patch @@ -0,0 +1,67 @@ +commit 25c537c3b3933663642874e332c73c6f65e3ddea +Author: Florian Weimer +Date: Fri May 16 19:53:09 2025 +0200 + + Use proper extern declaration for _nl_C_LC_CTYPE_{class,toupper,tolower} + + The existing initializers already contain explicit casts. Keep them + due to int/uint32_t mismatch. + + Reviewed-by: Frédéric Bérat + (cherry picked from commit e0c0f856f58ceb68800a964c36c15c606e7a8c4c) + +diff --git a/ctype/ctype-info.c b/ctype/ctype-info.c +index 71d1c8e3b4660d54..94e312d91ff76323 100644 +--- a/ctype/ctype-info.c ++++ b/ctype/ctype-info.c +@@ -41,10 +41,7 @@ libc_hidden_def (__ctype_init) + #if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_3) + + /* Defined in locale/C-ctype.c. */ +-extern const char _nl_C_LC_CTYPE_class[] attribute_hidden; + extern const char _nl_C_LC_CTYPE_class32[] attribute_hidden; +-extern const char _nl_C_LC_CTYPE_toupper[] attribute_hidden; +-extern const char _nl_C_LC_CTYPE_tolower[] attribute_hidden; + extern const char _nl_C_LC_CTYPE_class_upper[] attribute_hidden; + extern const char _nl_C_LC_CTYPE_class_lower[] attribute_hidden; + extern const char _nl_C_LC_CTYPE_class_alpha[] attribute_hidden; +diff --git a/include/ctype.h b/include/ctype.h +index e993adc86da43b7c..ae078a63d355af61 100644 +--- a/include/ctype.h ++++ b/include/ctype.h +@@ -63,6 +63,11 @@ __ctype_tolower_loc (void) + # define __isdigit_l(c, l) ({ int __c = (c); __c >= '0' && __c <= '9'; }) + # endif /* Not __NO_CTYPE. */ + ++/* For use in initializers. */ ++extern const char _nl_C_LC_CTYPE_class[] attribute_hidden; ++extern const uint32_t _nl_C_LC_CTYPE_toupper[] attribute_hidden; ++extern const uint32_t _nl_C_LC_CTYPE_tolower[] attribute_hidden; ++ + # endif /* IS_IN (libc). */ + #endif /* Not _ISOMAC. */ + +diff --git a/locale/xlocale.c b/locale/xlocale.c +index f2b9d03303e6653d..d11c1cbf8c65ad54 100644 +--- a/locale/xlocale.c ++++ b/locale/xlocale.c +@@ -18,18 +18,13 @@ + + #include + #include "localeinfo.h" ++#include + + #define DEFINE_CATEGORY(category, category_name, items, a) \ + extern struct __locale_data _nl_C_##category; + #include "categories.def" + #undef DEFINE_CATEGORY + +-/* Defined in locale/C-ctype.c. */ +-extern const char _nl_C_LC_CTYPE_class[] attribute_hidden; +-extern const char _nl_C_LC_CTYPE_toupper[] attribute_hidden; +-extern const char _nl_C_LC_CTYPE_tolower[] attribute_hidden; +- +- + const struct __locale_struct _nl_C_locobj attribute_hidden = + { + .__locales = diff --git a/glibc-upstream-2.39-223.patch b/glibc-upstream-2.39-223.patch new file mode 100644 index 0000000..7cbb71b --- /dev/null +++ b/glibc-upstream-2.39-223.patch @@ -0,0 +1,198 @@ +commit c11950503fbb8b5885a0400d1a7ba83a80878e53 +Author: Florian Weimer +Date: Fri May 16 19:53:09 2025 +0200 + + ctype: Fallback initialization of TLS using relocations (bug 19341, bug 32483) + + This ensures that the ctype data pointers in TLS are valid + in secondary namespaces even without initialization via + __ctype_init. + + Reviewed-by: Frédéric Bérat + (cherry picked from commit 2745db8dd3ec31045acd761b612516490085bc20) + +diff --git a/ctype/Makefile b/ctype/Makefile +index 3e09938bd1bb1522..b7cd5f2282b4511c 100644 +--- a/ctype/Makefile ++++ b/ctype/Makefile +@@ -36,6 +36,23 @@ aux := ctype-info + + tests := \ + test_ctype \ ++ tst-ctype-tls-dlmopen \ ++ tst-ctype-tls-dlopen-static \ + # tests + ++tests-static := \ ++ tst-ctype-tls-dlopen-static \ ++ # tests-static ++ ++modules-names := \ ++ tst-ctype-tls-mod \ ++ # modules-names ++ + include ../Rules ++ ++$(objpfx)tst-ctype-tls-dlmopen: $(shared-thread-library) ++$(objpfx)tst-ctype-tls-dlmopen.out: $(objpfx)tst-ctype-tls-mod.so ++$(objpfx)tst-ctype-tls-dlopen-static: $(static-thread-library) ++$(objpfx)tst-ctype-tls-dlopen-static.out: $(objpfx)tst-ctype-tls-mod.so ++tst-ctype-tls-dlopen-static-ENV = \ ++ LD_LIBRARY_PATH=$(ld-library-path):$(common-objpfx):$(common-objpfx)elf +diff --git a/ctype/ctype-info.c b/ctype/ctype-info.c +index 94e312d91ff76323..621bd4239c8b4c21 100644 +--- a/ctype/ctype-info.c ++++ b/ctype/ctype-info.c +@@ -19,9 +19,17 @@ + #include + #include + +-__thread const uint16_t * __libc_tsd_CTYPE_B; +-__thread const int32_t * __libc_tsd_CTYPE_TOLOWER; +-__thread const int32_t * __libc_tsd_CTYPE_TOUPPER; ++/* Fallback initialization using relocations. See the _nl_C_locobj ++ initializers in locale/xlocale.c. Usually, this is overwritten by ++ __ctype_init before user code runs, but this does not happen for ++ threads in secondary namespaces. With the initializers, secondary ++ namespaces at least get locale data from the C locale. */ ++__thread const uint16_t * __libc_tsd_CTYPE_B ++ = (const uint16_t *) _nl_C_LC_CTYPE_class + 128; ++__thread const int32_t * __libc_tsd_CTYPE_TOLOWER ++ = (const int32_t *) _nl_C_LC_CTYPE_tolower + 128; ++__thread const int32_t * __libc_tsd_CTYPE_TOUPPER ++ = (const int32_t *) _nl_C_LC_CTYPE_toupper + 128; + + + void +diff --git a/ctype/tst-ctype-tls-dlmopen.c b/ctype/tst-ctype-tls-dlmopen.c +new file mode 100644 +index 0000000000000000..f7eeb65551344b72 +--- /dev/null ++++ b/ctype/tst-ctype-tls-dlmopen.c +@@ -0,0 +1,2 @@ ++#define DO_STATIC_TEST 0 ++#include "tst-ctype-tls-skeleton.c" +diff --git a/ctype/tst-ctype-tls-dlopen-static.c b/ctype/tst-ctype-tls-dlopen-static.c +new file mode 100644 +index 0000000000000000..c2c09c362cc95906 +--- /dev/null ++++ b/ctype/tst-ctype-tls-dlopen-static.c +@@ -0,0 +1,2 @@ ++#define DO_STATIC_TEST 1 ++#include "tst-ctype-tls-skeleton.c" +diff --git a/ctype/tst-ctype-tls-mod.c b/ctype/tst-ctype-tls-mod.c +new file mode 100644 +index 0000000000000000..52cbb9dcb67e1800 +--- /dev/null ++++ b/ctype/tst-ctype-tls-mod.c +@@ -0,0 +1,37 @@ ++/* Wrappers for macros in a secondary namespace. ++ Copyright (C) 2025 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 ++ . */ ++ ++#include ++ ++int ++my_isalpha (int ch) ++{ ++ return isalpha (ch); ++} ++ ++int ++my_toupper (int ch) ++{ ++ return toupper (ch); ++} ++ ++int ++my_tolower (int ch) ++{ ++ return tolower (ch); ++} +diff --git a/ctype/tst-ctype-tls-skeleton.c b/ctype/tst-ctype-tls-skeleton.c +new file mode 100644 +index 0000000000000000..8c53e35899f12b8f +--- /dev/null ++++ b/ctype/tst-ctype-tls-skeleton.c +@@ -0,0 +1,67 @@ ++/* Test that in a secondary namespace works. ++ Copyright (C) 2025 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 ++ . */ ++ ++/* Before this file is included, define DO_STATIC_TEST to 0 or 1. ++ With 0, dlmopen is used for the test. With 1, dlopen is used. */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static int (*my_isalpha) (int); ++static int (*my_toupper) (int); ++static int (*my_tolower) (int); ++ ++static void * ++checks (void *ignore) ++{ ++ TEST_VERIFY (my_isalpha ('a')); ++ TEST_VERIFY (!my_isalpha ('0')); ++ TEST_COMPARE (my_toupper ('a'), 'A'); ++ TEST_COMPARE (my_toupper ('A'), 'A'); ++ TEST_COMPARE (my_tolower ('a'), 'a'); ++ TEST_COMPARE (my_tolower ('A'), 'a'); ++ return NULL; ++} ++ ++static int ++do_test (void) ++{ ++ char *dso = xasprintf ("%s/ctype/tst-ctype-tls-mod.so", support_objdir_root); ++#if DO_STATIC_TEST ++ void *handle = xdlopen (dso, RTLD_LAZY); ++#else ++ void *handle = xdlmopen (LM_ID_NEWLM, dso, RTLD_LAZY); ++#endif ++ my_isalpha = xdlsym (handle, "my_isalpha"); ++ my_toupper = xdlsym (handle, "my_toupper"); ++ my_tolower = xdlsym (handle, "my_tolower"); ++ ++ checks (NULL); ++ xpthread_join (xpthread_create (NULL, checks, NULL)); ++ ++ xdlclose (handle); ++ free (dso); ++ ++ return 0; ++} ++ ++#include diff --git a/glibc-upstream-2.39-224.patch b/glibc-upstream-2.39-224.patch new file mode 100644 index 0000000..9b9edbd --- /dev/null +++ b/glibc-upstream-2.39-224.patch @@ -0,0 +1,40 @@ +commit 20d2d69a2fcb3357127bea4536c8c85b183dc3b9 +Author: Jens Remus +Date: Fri Jul 25 15:40:03 2025 +0200 + + Use TLS initial-exec model for __libc_tsd_CTYPE_* thread variables [BZ #33234] + + Commit 10a66a8e421b ("Remove ") removed the TLS initial-exec + (IE) model attribute from the __libc_tsd_CTYPE_* thread variable declarations + and definitions. Commit a894f04d8776 ("Optimize __libc_tsd_* thread + variable access") restored it on declarations. + + Restore the TLS initial-exec model attribute on __libc_tsd_CTYPE_* thread + variable definitions. + + This resolves test tst-locale1 failure on s390 32-bit, when using a + GNU linker without the fix from GNU binutils commit aefebe82dc89 + ("IBM zSystems: Fix offset relative to static TLS"). + + Reviewed-by: Florian Weimer + (cherry picked from commit e5363e6f460c2d58809bf10fc96d70fd1ef8b5b2) + +diff --git a/ctype/ctype-info.c b/ctype/ctype-info.c +index 621bd4239c8b4c21..b6cdf7eb667a7118 100644 +--- a/ctype/ctype-info.c ++++ b/ctype/ctype-info.c +@@ -24,11 +24,11 @@ + __ctype_init before user code runs, but this does not happen for + threads in secondary namespaces. With the initializers, secondary + namespaces at least get locale data from the C locale. */ +-__thread const uint16_t * __libc_tsd_CTYPE_B ++__thread const uint16_t * __libc_tsd_CTYPE_B attribute_tls_model_ie + = (const uint16_t *) _nl_C_LC_CTYPE_class + 128; +-__thread const int32_t * __libc_tsd_CTYPE_TOLOWER ++__thread const int32_t * __libc_tsd_CTYPE_TOLOWER attribute_tls_model_ie + = (const int32_t *) _nl_C_LC_CTYPE_tolower + 128; +-__thread const int32_t * __libc_tsd_CTYPE_TOUPPER ++__thread const int32_t * __libc_tsd_CTYPE_TOUPPER attribute_tls_model_ie + = (const int32_t *) _nl_C_LC_CTYPE_toupper + 128; + + diff --git a/glibc-upstream-2.39-225.patch b/glibc-upstream-2.39-225.patch new file mode 100644 index 0000000..fa133fa --- /dev/null +++ b/glibc-upstream-2.39-225.patch @@ -0,0 +1,544 @@ +commit d1c1f78e9eb9ff5e8eeae21ec9a879b7d0095c2e +Author: Joe Ramsay +Date: Fri Jan 3 19:13:36 2025 +0000 + + math: Remove no-mathvec flag + + More routines are to follow, some of which hit many failures in the + current testsuite due to wrong sign of zero (mathvec routines are not + required to get this right). Instead of disabling a large number of + tests, change the failure condition such that, for vector routines, + tests pass as long as computed == expected == 0.0, regardless of sign. + + Affected tests (vector tests for expm1, log1p, sin, tan and tanh) all + still pass. + + (cherry picked from commit 939e770e0196ebd763cacc602421b76d62df0798) + +diff --git a/math/auto-libm-test-in b/math/auto-libm-test-in +index d728f9777015d3b9..5a690023e9a675cb 100644 +--- a/math/auto-libm-test-in ++++ b/math/auto-libm-test-in +@@ -5354,7 +5354,7 @@ exp2 -0x4.8ce878p-4 + exp2 0xf.93d18bf7be8d272p-4 + + expm1 0 +-expm1 -0 no-mathvec ++expm1 -0 + expm1 1 + expm1 0.75 + expm1 2 +@@ -5419,7 +5419,7 @@ expm1 -0x1p-100 + expm1 0x1p-600 + expm1 -0x1p-600 + expm1 0x1p-10000 +-expm1 -0x1p-10000 no-mathvec ++expm1 -0x1p-10000 + expm1 0xe.4152ac57cd1ea7ap-60 + expm1 0x6.660247486aed8p-4 + expm1 0x6.289a78p-4 +@@ -6577,7 +6577,7 @@ log10 0xf.bf1b2p-4 + log10 0x1.6b5f7ap+96 + + log1p 0 +-log1p -0 no-mathvec ++log1p -0 + log1p e-1 + log1p -0.25 + log1p -0.875 +@@ -7318,7 +7318,7 @@ pow 0x1.7ac7cp+5 23 + pow -0x1.7ac7cp+5 23 + + sin 0 +-sin -0 no-mathvec ++sin -0 + sin pi/6 + sin -pi/6 + sin pi/2 +@@ -7655,7 +7655,7 @@ sqrt min + sqrt min_subnorm + + tan 0 +-tan -0 no-mathvec ++tan -0 + tan pi/4 + tan pi/2 + tan -pi/2 +diff --git a/math/auto-libm-test-out-expm1 b/math/auto-libm-test-out-expm1 +index 91da41b7f604a5a1..8483455801221aac 100644 +--- a/math/auto-libm-test-out-expm1 ++++ b/math/auto-libm-test-out-expm1 +@@ -23,31 +23,31 @@ expm1 0 + = expm1 tonearest ibm128 0x0p+0 : 0x0p+0 : inexact-ok + = expm1 towardzero ibm128 0x0p+0 : 0x0p+0 : inexact-ok + = expm1 upward ibm128 0x0p+0 : 0x0p+0 : inexact-ok +-expm1 -0 no-mathvec +-= expm1 downward binary32 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= expm1 tonearest binary32 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= expm1 towardzero binary32 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= expm1 upward binary32 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= expm1 downward binary64 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= expm1 tonearest binary64 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= expm1 towardzero binary64 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= expm1 upward binary64 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= expm1 downward intel96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= expm1 tonearest intel96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= expm1 towardzero intel96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= expm1 upward intel96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= expm1 downward m68k96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= expm1 tonearest m68k96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= expm1 towardzero m68k96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= expm1 upward m68k96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= expm1 downward binary128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= expm1 tonearest binary128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= expm1 towardzero binary128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= expm1 upward binary128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= expm1 downward ibm128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= expm1 tonearest ibm128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= expm1 towardzero ibm128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= expm1 upward ibm128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok ++expm1 -0 ++= expm1 downward binary32 -0x0p+0 : -0x0p+0 : inexact-ok ++= expm1 tonearest binary32 -0x0p+0 : -0x0p+0 : inexact-ok ++= expm1 towardzero binary32 -0x0p+0 : -0x0p+0 : inexact-ok ++= expm1 upward binary32 -0x0p+0 : -0x0p+0 : inexact-ok ++= expm1 downward binary64 -0x0p+0 : -0x0p+0 : inexact-ok ++= expm1 tonearest binary64 -0x0p+0 : -0x0p+0 : inexact-ok ++= expm1 towardzero binary64 -0x0p+0 : -0x0p+0 : inexact-ok ++= expm1 upward binary64 -0x0p+0 : -0x0p+0 : inexact-ok ++= expm1 downward intel96 -0x0p+0 : -0x0p+0 : inexact-ok ++= expm1 tonearest intel96 -0x0p+0 : -0x0p+0 : inexact-ok ++= expm1 towardzero intel96 -0x0p+0 : -0x0p+0 : inexact-ok ++= expm1 upward intel96 -0x0p+0 : -0x0p+0 : inexact-ok ++= expm1 downward m68k96 -0x0p+0 : -0x0p+0 : inexact-ok ++= expm1 tonearest m68k96 -0x0p+0 : -0x0p+0 : inexact-ok ++= expm1 towardzero m68k96 -0x0p+0 : -0x0p+0 : inexact-ok ++= expm1 upward m68k96 -0x0p+0 : -0x0p+0 : inexact-ok ++= expm1 downward binary128 -0x0p+0 : -0x0p+0 : inexact-ok ++= expm1 tonearest binary128 -0x0p+0 : -0x0p+0 : inexact-ok ++= expm1 towardzero binary128 -0x0p+0 : -0x0p+0 : inexact-ok ++= expm1 upward binary128 -0x0p+0 : -0x0p+0 : inexact-ok ++= expm1 downward ibm128 -0x0p+0 : -0x0p+0 : inexact-ok ++= expm1 tonearest ibm128 -0x0p+0 : -0x0p+0 : inexact-ok ++= expm1 towardzero ibm128 -0x0p+0 : -0x0p+0 : inexact-ok ++= expm1 upward ibm128 -0x0p+0 : -0x0p+0 : inexact-ok + expm1 1 + = expm1 downward binary32 0x1p+0 : 0x1.b7e15p+0 : inexact-ok + = expm1 tonearest binary32 0x1p+0 : 0x1.b7e152p+0 : inexact-ok +@@ -1880,87 +1880,87 @@ expm1 0x1p-10000 + = expm1 tonearest binary128 0x1p-10000 : 0x1p-10000 : inexact-ok + = expm1 towardzero binary128 0x1p-10000 : 0x1p-10000 : inexact-ok + = expm1 upward binary128 0x1p-10000 : 0x1.0000000000000000000000000001p-10000 : inexact-ok +-expm1 -0x1p-10000 no-mathvec +-= expm1 downward binary32 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= expm1 tonearest binary32 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= expm1 towardzero binary32 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= expm1 upward binary32 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= expm1 downward binary64 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= expm1 tonearest binary64 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= expm1 towardzero binary64 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= expm1 upward binary64 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= expm1 downward intel96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= expm1 tonearest intel96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= expm1 towardzero intel96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= expm1 upward intel96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= expm1 downward m68k96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= expm1 tonearest m68k96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= expm1 towardzero m68k96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= expm1 upward m68k96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= expm1 downward binary128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= expm1 tonearest binary128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= expm1 towardzero binary128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= expm1 upward binary128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= expm1 downward ibm128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= expm1 tonearest ibm128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= expm1 towardzero ibm128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= expm1 upward ibm128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= expm1 downward binary32 -0x8p-152 : -0x8p-152 : no-mathvec inexact-ok underflow errno-erange-ok +-= expm1 tonearest binary32 -0x8p-152 : -0x8p-152 : no-mathvec inexact-ok underflow errno-erange-ok +-= expm1 towardzero binary32 -0x8p-152 : -0x0p+0 : no-mathvec inexact-ok underflow errno-erange-ok +-= expm1 upward binary32 -0x8p-152 : -0x0p+0 : no-mathvec inexact-ok underflow errno-erange-ok +-= expm1 downward binary64 -0x8p-152 : -0x8p-152 : no-mathvec inexact-ok +-= expm1 tonearest binary64 -0x8p-152 : -0x8p-152 : no-mathvec inexact-ok +-= expm1 towardzero binary64 -0x8p-152 : -0x7.ffffffffffffcp-152 : no-mathvec inexact-ok +-= expm1 upward binary64 -0x8p-152 : -0x7.ffffffffffffcp-152 : no-mathvec inexact-ok +-= expm1 downward intel96 -0x8p-152 : -0x8p-152 : no-mathvec inexact-ok +-= expm1 tonearest intel96 -0x8p-152 : -0x8p-152 : no-mathvec inexact-ok +-= expm1 towardzero intel96 -0x8p-152 : -0x7.fffffffffffffff8p-152 : no-mathvec inexact-ok +-= expm1 upward intel96 -0x8p-152 : -0x7.fffffffffffffff8p-152 : no-mathvec inexact-ok +-= expm1 downward m68k96 -0x8p-152 : -0x8p-152 : no-mathvec inexact-ok +-= expm1 tonearest m68k96 -0x8p-152 : -0x8p-152 : no-mathvec inexact-ok +-= expm1 towardzero m68k96 -0x8p-152 : -0x7.fffffffffffffff8p-152 : no-mathvec inexact-ok +-= expm1 upward m68k96 -0x8p-152 : -0x7.fffffffffffffff8p-152 : no-mathvec inexact-ok +-= expm1 downward binary128 -0x8p-152 : -0x8p-152 : no-mathvec inexact-ok +-= expm1 tonearest binary128 -0x8p-152 : -0x8p-152 : no-mathvec inexact-ok +-= expm1 towardzero binary128 -0x8p-152 : -0x7.fffffffffffffffffffffffffffcp-152 : no-mathvec inexact-ok +-= expm1 upward binary128 -0x8p-152 : -0x7.fffffffffffffffffffffffffffcp-152 : no-mathvec inexact-ok +-= expm1 downward ibm128 -0x8p-152 : -0x8p-152 : no-mathvec inexact-ok +-= expm1 tonearest ibm128 -0x8p-152 : -0x8p-152 : no-mathvec inexact-ok +-= expm1 towardzero ibm128 -0x8p-152 : -0x7.fffffffffffffffffffffffffep-152 : no-mathvec inexact-ok +-= expm1 upward ibm128 -0x8p-152 : -0x7.fffffffffffffffffffffffffep-152 : no-mathvec inexact-ok +-= expm1 downward binary64 -0x4p-1076 : -0x4p-1076 : no-mathvec inexact-ok underflow errno-erange-ok +-= expm1 tonearest binary64 -0x4p-1076 : -0x4p-1076 : no-mathvec inexact-ok underflow errno-erange-ok +-= expm1 towardzero binary64 -0x4p-1076 : -0x0p+0 : no-mathvec inexact-ok underflow errno-erange-ok +-= expm1 upward binary64 -0x4p-1076 : -0x0p+0 : no-mathvec inexact-ok underflow errno-erange-ok +-= expm1 downward intel96 -0x4p-1076 : -0x4p-1076 : no-mathvec inexact-ok +-= expm1 tonearest intel96 -0x4p-1076 : -0x4p-1076 : no-mathvec inexact-ok +-= expm1 towardzero intel96 -0x4p-1076 : -0x3.fffffffffffffffcp-1076 : no-mathvec inexact-ok +-= expm1 upward intel96 -0x4p-1076 : -0x3.fffffffffffffffcp-1076 : no-mathvec inexact-ok +-= expm1 downward m68k96 -0x4p-1076 : -0x4p-1076 : no-mathvec inexact-ok +-= expm1 tonearest m68k96 -0x4p-1076 : -0x4p-1076 : no-mathvec inexact-ok +-= expm1 towardzero m68k96 -0x4p-1076 : -0x3.fffffffffffffffcp-1076 : no-mathvec inexact-ok +-= expm1 upward m68k96 -0x4p-1076 : -0x3.fffffffffffffffcp-1076 : no-mathvec inexact-ok +-= expm1 downward binary128 -0x4p-1076 : -0x4p-1076 : no-mathvec inexact-ok +-= expm1 tonearest binary128 -0x4p-1076 : -0x4p-1076 : no-mathvec inexact-ok +-= expm1 towardzero binary128 -0x4p-1076 : -0x3.fffffffffffffffffffffffffffep-1076 : no-mathvec inexact-ok +-= expm1 upward binary128 -0x4p-1076 : -0x3.fffffffffffffffffffffffffffep-1076 : no-mathvec inexact-ok +-= expm1 downward ibm128 -0x4p-1076 : -0x4p-1076 : no-mathvec xfail:ibm128-libgcc inexact-ok underflow errno-erange-ok +-= expm1 tonearest ibm128 -0x4p-1076 : -0x4p-1076 : no-mathvec inexact-ok underflow errno-erange-ok +-= expm1 towardzero ibm128 -0x4p-1076 : -0x0p+0 : no-mathvec xfail:ibm128-libgcc inexact-ok underflow errno-erange-ok +-= expm1 upward ibm128 -0x4p-1076 : -0x0p+0 : no-mathvec xfail:ibm128-libgcc inexact-ok underflow errno-erange-ok +-= expm1 downward intel96 -0x1p-10000 : -0x1p-10000 : no-mathvec inexact-ok +-= expm1 tonearest intel96 -0x1p-10000 : -0x1p-10000 : no-mathvec inexact-ok +-= expm1 towardzero intel96 -0x1p-10000 : -0xf.fffffffffffffffp-10004 : no-mathvec inexact-ok +-= expm1 upward intel96 -0x1p-10000 : -0xf.fffffffffffffffp-10004 : no-mathvec inexact-ok +-= expm1 downward m68k96 -0x1p-10000 : -0x1p-10000 : no-mathvec inexact-ok +-= expm1 tonearest m68k96 -0x1p-10000 : -0x1p-10000 : no-mathvec inexact-ok +-= expm1 towardzero m68k96 -0x1p-10000 : -0xf.fffffffffffffffp-10004 : no-mathvec inexact-ok +-= expm1 upward m68k96 -0x1p-10000 : -0xf.fffffffffffffffp-10004 : no-mathvec inexact-ok +-= expm1 downward binary128 -0x1p-10000 : -0x1p-10000 : no-mathvec inexact-ok +-= expm1 tonearest binary128 -0x1p-10000 : -0x1p-10000 : no-mathvec inexact-ok +-= expm1 towardzero binary128 -0x1p-10000 : -0xf.fffffffffffffffffffffffffff8p-10004 : no-mathvec inexact-ok +-= expm1 upward binary128 -0x1p-10000 : -0xf.fffffffffffffffffffffffffff8p-10004 : no-mathvec inexact-ok ++expm1 -0x1p-10000 ++= expm1 downward binary32 -0x0p+0 : -0x0p+0 : inexact-ok ++= expm1 tonearest binary32 -0x0p+0 : -0x0p+0 : inexact-ok ++= expm1 towardzero binary32 -0x0p+0 : -0x0p+0 : inexact-ok ++= expm1 upward binary32 -0x0p+0 : -0x0p+0 : inexact-ok ++= expm1 downward binary64 -0x0p+0 : -0x0p+0 : inexact-ok ++= expm1 tonearest binary64 -0x0p+0 : -0x0p+0 : inexact-ok ++= expm1 towardzero binary64 -0x0p+0 : -0x0p+0 : inexact-ok ++= expm1 upward binary64 -0x0p+0 : -0x0p+0 : inexact-ok ++= expm1 downward intel96 -0x0p+0 : -0x0p+0 : inexact-ok ++= expm1 tonearest intel96 -0x0p+0 : -0x0p+0 : inexact-ok ++= expm1 towardzero intel96 -0x0p+0 : -0x0p+0 : inexact-ok ++= expm1 upward intel96 -0x0p+0 : -0x0p+0 : inexact-ok ++= expm1 downward m68k96 -0x0p+0 : -0x0p+0 : inexact-ok ++= expm1 tonearest m68k96 -0x0p+0 : -0x0p+0 : inexact-ok ++= expm1 towardzero m68k96 -0x0p+0 : -0x0p+0 : inexact-ok ++= expm1 upward m68k96 -0x0p+0 : -0x0p+0 : inexact-ok ++= expm1 downward binary128 -0x0p+0 : -0x0p+0 : inexact-ok ++= expm1 tonearest binary128 -0x0p+0 : -0x0p+0 : inexact-ok ++= expm1 towardzero binary128 -0x0p+0 : -0x0p+0 : inexact-ok ++= expm1 upward binary128 -0x0p+0 : -0x0p+0 : inexact-ok ++= expm1 downward ibm128 -0x0p+0 : -0x0p+0 : inexact-ok ++= expm1 tonearest ibm128 -0x0p+0 : -0x0p+0 : inexact-ok ++= expm1 towardzero ibm128 -0x0p+0 : -0x0p+0 : inexact-ok ++= expm1 upward ibm128 -0x0p+0 : -0x0p+0 : inexact-ok ++= expm1 downward binary32 -0x8p-152 : -0x8p-152 : inexact-ok underflow errno-erange-ok ++= expm1 tonearest binary32 -0x8p-152 : -0x8p-152 : inexact-ok underflow errno-erange-ok ++= expm1 towardzero binary32 -0x8p-152 : -0x0p+0 : inexact-ok underflow errno-erange-ok ++= expm1 upward binary32 -0x8p-152 : -0x0p+0 : inexact-ok underflow errno-erange-ok ++= expm1 downward binary64 -0x8p-152 : -0x8p-152 : inexact-ok ++= expm1 tonearest binary64 -0x8p-152 : -0x8p-152 : inexact-ok ++= expm1 towardzero binary64 -0x8p-152 : -0x7.ffffffffffffcp-152 : inexact-ok ++= expm1 upward binary64 -0x8p-152 : -0x7.ffffffffffffcp-152 : inexact-ok ++= expm1 downward intel96 -0x8p-152 : -0x8p-152 : inexact-ok ++= expm1 tonearest intel96 -0x8p-152 : -0x8p-152 : inexact-ok ++= expm1 towardzero intel96 -0x8p-152 : -0x7.fffffffffffffff8p-152 : inexact-ok ++= expm1 upward intel96 -0x8p-152 : -0x7.fffffffffffffff8p-152 : inexact-ok ++= expm1 downward m68k96 -0x8p-152 : -0x8p-152 : inexact-ok ++= expm1 tonearest m68k96 -0x8p-152 : -0x8p-152 : inexact-ok ++= expm1 towardzero m68k96 -0x8p-152 : -0x7.fffffffffffffff8p-152 : inexact-ok ++= expm1 upward m68k96 -0x8p-152 : -0x7.fffffffffffffff8p-152 : inexact-ok ++= expm1 downward binary128 -0x8p-152 : -0x8p-152 : inexact-ok ++= expm1 tonearest binary128 -0x8p-152 : -0x8p-152 : inexact-ok ++= expm1 towardzero binary128 -0x8p-152 : -0x7.fffffffffffffffffffffffffffcp-152 : inexact-ok ++= expm1 upward binary128 -0x8p-152 : -0x7.fffffffffffffffffffffffffffcp-152 : inexact-ok ++= expm1 downward ibm128 -0x8p-152 : -0x8p-152 : inexact-ok ++= expm1 tonearest ibm128 -0x8p-152 : -0x8p-152 : inexact-ok ++= expm1 towardzero ibm128 -0x8p-152 : -0x7.fffffffffffffffffffffffffep-152 : inexact-ok ++= expm1 upward ibm128 -0x8p-152 : -0x7.fffffffffffffffffffffffffep-152 : inexact-ok ++= expm1 downward binary64 -0x4p-1076 : -0x4p-1076 : inexact-ok underflow errno-erange-ok ++= expm1 tonearest binary64 -0x4p-1076 : -0x4p-1076 : inexact-ok underflow errno-erange-ok ++= expm1 towardzero binary64 -0x4p-1076 : -0x0p+0 : inexact-ok underflow errno-erange-ok ++= expm1 upward binary64 -0x4p-1076 : -0x0p+0 : inexact-ok underflow errno-erange-ok ++= expm1 downward intel96 -0x4p-1076 : -0x4p-1076 : inexact-ok ++= expm1 tonearest intel96 -0x4p-1076 : -0x4p-1076 : inexact-ok ++= expm1 towardzero intel96 -0x4p-1076 : -0x3.fffffffffffffffcp-1076 : inexact-ok ++= expm1 upward intel96 -0x4p-1076 : -0x3.fffffffffffffffcp-1076 : inexact-ok ++= expm1 downward m68k96 -0x4p-1076 : -0x4p-1076 : inexact-ok ++= expm1 tonearest m68k96 -0x4p-1076 : -0x4p-1076 : inexact-ok ++= expm1 towardzero m68k96 -0x4p-1076 : -0x3.fffffffffffffffcp-1076 : inexact-ok ++= expm1 upward m68k96 -0x4p-1076 : -0x3.fffffffffffffffcp-1076 : inexact-ok ++= expm1 downward binary128 -0x4p-1076 : -0x4p-1076 : inexact-ok ++= expm1 tonearest binary128 -0x4p-1076 : -0x4p-1076 : inexact-ok ++= expm1 towardzero binary128 -0x4p-1076 : -0x3.fffffffffffffffffffffffffffep-1076 : inexact-ok ++= expm1 upward binary128 -0x4p-1076 : -0x3.fffffffffffffffffffffffffffep-1076 : inexact-ok ++= expm1 downward ibm128 -0x4p-1076 : -0x4p-1076 : xfail:ibm128-libgcc inexact-ok underflow errno-erange-ok ++= expm1 tonearest ibm128 -0x4p-1076 : -0x4p-1076 : inexact-ok underflow errno-erange-ok ++= expm1 towardzero ibm128 -0x4p-1076 : -0x0p+0 : xfail:ibm128-libgcc inexact-ok underflow errno-erange-ok ++= expm1 upward ibm128 -0x4p-1076 : -0x0p+0 : xfail:ibm128-libgcc inexact-ok underflow errno-erange-ok ++= expm1 downward intel96 -0x1p-10000 : -0x1p-10000 : inexact-ok ++= expm1 tonearest intel96 -0x1p-10000 : -0x1p-10000 : inexact-ok ++= expm1 towardzero intel96 -0x1p-10000 : -0xf.fffffffffffffffp-10004 : inexact-ok ++= expm1 upward intel96 -0x1p-10000 : -0xf.fffffffffffffffp-10004 : inexact-ok ++= expm1 downward m68k96 -0x1p-10000 : -0x1p-10000 : inexact-ok ++= expm1 tonearest m68k96 -0x1p-10000 : -0x1p-10000 : inexact-ok ++= expm1 towardzero m68k96 -0x1p-10000 : -0xf.fffffffffffffffp-10004 : inexact-ok ++= expm1 upward m68k96 -0x1p-10000 : -0xf.fffffffffffffffp-10004 : inexact-ok ++= expm1 downward binary128 -0x1p-10000 : -0x1p-10000 : inexact-ok ++= expm1 tonearest binary128 -0x1p-10000 : -0x1p-10000 : inexact-ok ++= expm1 towardzero binary128 -0x1p-10000 : -0xf.fffffffffffffffffffffffffff8p-10004 : inexact-ok ++= expm1 upward binary128 -0x1p-10000 : -0xf.fffffffffffffffffffffffffff8p-10004 : inexact-ok + expm1 0xe.4152ac57cd1ea7ap-60 + = expm1 downward binary32 0xe.4152bp-60 : 0xe.4152bp-60 : inexact-ok + = expm1 tonearest binary32 0xe.4152bp-60 : 0xe.4152bp-60 : inexact-ok +diff --git a/math/auto-libm-test-out-log1p b/math/auto-libm-test-out-log1p +index f83241f51ad9db8b..f7d3b35e6d4465c4 100644 +--- a/math/auto-libm-test-out-log1p ++++ b/math/auto-libm-test-out-log1p +@@ -23,31 +23,31 @@ log1p 0 + = log1p tonearest ibm128 0x0p+0 : 0x0p+0 : inexact-ok + = log1p towardzero ibm128 0x0p+0 : 0x0p+0 : inexact-ok + = log1p upward ibm128 0x0p+0 : 0x0p+0 : inexact-ok +-log1p -0 no-mathvec +-= log1p downward binary32 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= log1p tonearest binary32 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= log1p towardzero binary32 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= log1p upward binary32 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= log1p downward binary64 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= log1p tonearest binary64 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= log1p towardzero binary64 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= log1p upward binary64 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= log1p downward intel96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= log1p tonearest intel96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= log1p towardzero intel96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= log1p upward intel96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= log1p downward m68k96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= log1p tonearest m68k96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= log1p towardzero m68k96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= log1p upward m68k96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= log1p downward binary128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= log1p tonearest binary128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= log1p towardzero binary128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= log1p upward binary128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= log1p downward ibm128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= log1p tonearest ibm128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= log1p towardzero ibm128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= log1p upward ibm128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok ++log1p -0 ++= log1p downward binary32 -0x0p+0 : -0x0p+0 : inexact-ok ++= log1p tonearest binary32 -0x0p+0 : -0x0p+0 : inexact-ok ++= log1p towardzero binary32 -0x0p+0 : -0x0p+0 : inexact-ok ++= log1p upward binary32 -0x0p+0 : -0x0p+0 : inexact-ok ++= log1p downward binary64 -0x0p+0 : -0x0p+0 : inexact-ok ++= log1p tonearest binary64 -0x0p+0 : -0x0p+0 : inexact-ok ++= log1p towardzero binary64 -0x0p+0 : -0x0p+0 : inexact-ok ++= log1p upward binary64 -0x0p+0 : -0x0p+0 : inexact-ok ++= log1p downward intel96 -0x0p+0 : -0x0p+0 : inexact-ok ++= log1p tonearest intel96 -0x0p+0 : -0x0p+0 : inexact-ok ++= log1p towardzero intel96 -0x0p+0 : -0x0p+0 : inexact-ok ++= log1p upward intel96 -0x0p+0 : -0x0p+0 : inexact-ok ++= log1p downward m68k96 -0x0p+0 : -0x0p+0 : inexact-ok ++= log1p tonearest m68k96 -0x0p+0 : -0x0p+0 : inexact-ok ++= log1p towardzero m68k96 -0x0p+0 : -0x0p+0 : inexact-ok ++= log1p upward m68k96 -0x0p+0 : -0x0p+0 : inexact-ok ++= log1p downward binary128 -0x0p+0 : -0x0p+0 : inexact-ok ++= log1p tonearest binary128 -0x0p+0 : -0x0p+0 : inexact-ok ++= log1p towardzero binary128 -0x0p+0 : -0x0p+0 : inexact-ok ++= log1p upward binary128 -0x0p+0 : -0x0p+0 : inexact-ok ++= log1p downward ibm128 -0x0p+0 : -0x0p+0 : inexact-ok ++= log1p tonearest ibm128 -0x0p+0 : -0x0p+0 : inexact-ok ++= log1p towardzero ibm128 -0x0p+0 : -0x0p+0 : inexact-ok ++= log1p upward ibm128 -0x0p+0 : -0x0p+0 : inexact-ok + log1p e-1 + = log1p downward binary32 0x1.b7e152p+0 : 0x1p+0 : inexact-ok + = log1p tonearest binary32 0x1.b7e152p+0 : 0x1p+0 : inexact-ok +diff --git a/math/auto-libm-test-out-sin b/math/auto-libm-test-out-sin +index e1f684528316dde5..f1d21b179c955eb7 100644 +--- a/math/auto-libm-test-out-sin ++++ b/math/auto-libm-test-out-sin +@@ -23,31 +23,31 @@ sin 0 + = sin tonearest ibm128 0x0p+0 : 0x0p+0 : inexact-ok + = sin towardzero ibm128 0x0p+0 : 0x0p+0 : inexact-ok + = sin upward ibm128 0x0p+0 : 0x0p+0 : inexact-ok +-sin -0 no-mathvec +-= sin downward binary32 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= sin tonearest binary32 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= sin towardzero binary32 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= sin upward binary32 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= sin downward binary64 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= sin tonearest binary64 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= sin towardzero binary64 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= sin upward binary64 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= sin downward intel96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= sin tonearest intel96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= sin towardzero intel96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= sin upward intel96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= sin downward m68k96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= sin tonearest m68k96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= sin towardzero m68k96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= sin upward m68k96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= sin downward binary128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= sin tonearest binary128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= sin towardzero binary128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= sin upward binary128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= sin downward ibm128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= sin tonearest ibm128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= sin towardzero ibm128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= sin upward ibm128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok ++sin -0 ++= sin downward binary32 -0x0p+0 : -0x0p+0 : inexact-ok ++= sin tonearest binary32 -0x0p+0 : -0x0p+0 : inexact-ok ++= sin towardzero binary32 -0x0p+0 : -0x0p+0 : inexact-ok ++= sin upward binary32 -0x0p+0 : -0x0p+0 : inexact-ok ++= sin downward binary64 -0x0p+0 : -0x0p+0 : inexact-ok ++= sin tonearest binary64 -0x0p+0 : -0x0p+0 : inexact-ok ++= sin towardzero binary64 -0x0p+0 : -0x0p+0 : inexact-ok ++= sin upward binary64 -0x0p+0 : -0x0p+0 : inexact-ok ++= sin downward intel96 -0x0p+0 : -0x0p+0 : inexact-ok ++= sin tonearest intel96 -0x0p+0 : -0x0p+0 : inexact-ok ++= sin towardzero intel96 -0x0p+0 : -0x0p+0 : inexact-ok ++= sin upward intel96 -0x0p+0 : -0x0p+0 : inexact-ok ++= sin downward m68k96 -0x0p+0 : -0x0p+0 : inexact-ok ++= sin tonearest m68k96 -0x0p+0 : -0x0p+0 : inexact-ok ++= sin towardzero m68k96 -0x0p+0 : -0x0p+0 : inexact-ok ++= sin upward m68k96 -0x0p+0 : -0x0p+0 : inexact-ok ++= sin downward binary128 -0x0p+0 : -0x0p+0 : inexact-ok ++= sin tonearest binary128 -0x0p+0 : -0x0p+0 : inexact-ok ++= sin towardzero binary128 -0x0p+0 : -0x0p+0 : inexact-ok ++= sin upward binary128 -0x0p+0 : -0x0p+0 : inexact-ok ++= sin downward ibm128 -0x0p+0 : -0x0p+0 : inexact-ok ++= sin tonearest ibm128 -0x0p+0 : -0x0p+0 : inexact-ok ++= sin towardzero ibm128 -0x0p+0 : -0x0p+0 : inexact-ok ++= sin upward ibm128 -0x0p+0 : -0x0p+0 : inexact-ok + sin pi/6 + = sin downward binary32 0x8.60a92p-4 : 0x8p-4 : inexact-ok + = sin tonearest binary32 0x8.60a92p-4 : 0x8p-4 : inexact-ok +diff --git a/math/auto-libm-test-out-tan b/math/auto-libm-test-out-tan +index f46fdc7ec62075f2..7d00d03e1da81b18 100644 +--- a/math/auto-libm-test-out-tan ++++ b/math/auto-libm-test-out-tan +@@ -23,31 +23,31 @@ tan 0 + = tan tonearest ibm128 0x0p+0 : 0x0p+0 : inexact-ok + = tan towardzero ibm128 0x0p+0 : 0x0p+0 : inexact-ok + = tan upward ibm128 0x0p+0 : 0x0p+0 : inexact-ok +-tan -0 no-mathvec +-= tan downward binary32 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= tan tonearest binary32 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= tan towardzero binary32 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= tan upward binary32 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= tan downward binary64 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= tan tonearest binary64 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= tan towardzero binary64 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= tan upward binary64 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= tan downward intel96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= tan tonearest intel96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= tan towardzero intel96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= tan upward intel96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= tan downward m68k96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= tan tonearest m68k96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= tan towardzero m68k96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= tan upward m68k96 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= tan downward binary128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= tan tonearest binary128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= tan towardzero binary128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= tan upward binary128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= tan downward ibm128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= tan tonearest ibm128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= tan towardzero ibm128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok +-= tan upward ibm128 -0x0p+0 : -0x0p+0 : no-mathvec inexact-ok ++tan -0 ++= tan downward binary32 -0x0p+0 : -0x0p+0 : inexact-ok ++= tan tonearest binary32 -0x0p+0 : -0x0p+0 : inexact-ok ++= tan towardzero binary32 -0x0p+0 : -0x0p+0 : inexact-ok ++= tan upward binary32 -0x0p+0 : -0x0p+0 : inexact-ok ++= tan downward binary64 -0x0p+0 : -0x0p+0 : inexact-ok ++= tan tonearest binary64 -0x0p+0 : -0x0p+0 : inexact-ok ++= tan towardzero binary64 -0x0p+0 : -0x0p+0 : inexact-ok ++= tan upward binary64 -0x0p+0 : -0x0p+0 : inexact-ok ++= tan downward intel96 -0x0p+0 : -0x0p+0 : inexact-ok ++= tan tonearest intel96 -0x0p+0 : -0x0p+0 : inexact-ok ++= tan towardzero intel96 -0x0p+0 : -0x0p+0 : inexact-ok ++= tan upward intel96 -0x0p+0 : -0x0p+0 : inexact-ok ++= tan downward m68k96 -0x0p+0 : -0x0p+0 : inexact-ok ++= tan tonearest m68k96 -0x0p+0 : -0x0p+0 : inexact-ok ++= tan towardzero m68k96 -0x0p+0 : -0x0p+0 : inexact-ok ++= tan upward m68k96 -0x0p+0 : -0x0p+0 : inexact-ok ++= tan downward binary128 -0x0p+0 : -0x0p+0 : inexact-ok ++= tan tonearest binary128 -0x0p+0 : -0x0p+0 : inexact-ok ++= tan towardzero binary128 -0x0p+0 : -0x0p+0 : inexact-ok ++= tan upward binary128 -0x0p+0 : -0x0p+0 : inexact-ok ++= tan downward ibm128 -0x0p+0 : -0x0p+0 : inexact-ok ++= tan tonearest ibm128 -0x0p+0 : -0x0p+0 : inexact-ok ++= tan towardzero ibm128 -0x0p+0 : -0x0p+0 : inexact-ok ++= tan upward ibm128 -0x0p+0 : -0x0p+0 : inexact-ok + tan pi/4 + = tan downward binary32 0xc.90fdbp-4 : 0x1p+0 : inexact-ok + = tan tonearest binary32 0xc.90fdbp-4 : 0x1p+0 : inexact-ok +diff --git a/math/gen-auto-libm-tests.c b/math/gen-auto-libm-tests.c +index c35242b356821eed..48227248e4aebc90 100644 +--- a/math/gen-auto-libm-tests.c ++++ b/math/gen-auto-libm-tests.c +@@ -96,8 +96,7 @@ + zero and infinite results should be ignored; "xfail" indicates the + test is disabled as expected to produce incorrect results, + "xfail-rounding" indicates the test is disabled only in rounding +- modes other than round-to-nearest; "no-mathvec" indicates the test +- is disabled in vector math libraries. Otherwise, test flags are of ++ modes other than round-to-nearest. Otherwise, test flags are of + the form "spurious-" and "missing-", for any + exception ("overflow", "underflow", "inexact", "invalid", + "divbyzero"), "spurious-errno" and "missing-errno", to indicate +@@ -353,7 +352,6 @@ typedef enum + flag_missing_overflow, + flag_missing_underflow, + flag_missing_errno, +- flag_no_mathvec, + num_input_flag_types, + flag_first_flag = 0, + flag_spurious_first = flag_spurious_divbyzero, +@@ -379,7 +377,6 @@ static const char *const input_flags[num_input_flag_types] = + "missing-overflow", + "missing-underflow", + "missing-errno", +- "no-mathvec", + }; + + /* An input flag, possibly conditional. */ +@@ -2052,7 +2049,6 @@ output_for_one_input_case (FILE *fp, const char *filename, test_function *tf, + { + case flag_ignore_zero_inf_sign: + case flag_xfail: +- case flag_no_mathvec: + if (fprintf (fp, " %s%s", + input_flags[it->flags[i].type], + (it->flags[i].cond +diff --git a/math/gen-libm-test.py b/math/gen-libm-test.py +index 397dbd325930841f..6e8bb564379e2117 100755 +--- a/math/gen-libm-test.py ++++ b/math/gen-libm-test.py +@@ -93,8 +93,7 @@ BEAUTIFY_MAP = {'minus_zero': '-0', + + # Flags in auto-libm-test-out that map directly to C flags. + FLAGS_SIMPLE = {'ignore-zero-inf-sign': 'IGNORE_ZERO_INF_SIGN', +- 'xfail': 'XFAIL_TEST', +- 'no-mathvec': 'NO_TEST_MATHVEC'} ++ 'xfail': 'XFAIL_TEST'} + + # Exceptions in auto-libm-test-out, and their corresponding C flags + # for being required, OK or required to be absent. +diff --git a/math/libm-test-support.c b/math/libm-test-support.c +index 0796f9d4956e3818..3fecd87064666f94 100644 +--- a/math/libm-test-support.c ++++ b/math/libm-test-support.c +@@ -776,7 +776,7 @@ check_float_internal (const char *test_name, FLOAT computed, FLOAT expected, + ulps = ULPDIFF (computed, expected); + set_max_error (ulps, curr_max_error); + print_diff = 1; +- if ((exceptions & IGNORE_ZERO_INF_SIGN) == 0 ++ if (((exceptions & IGNORE_ZERO_INF_SIGN) == 0) && !flag_test_mathvec + && computed == 0.0 && expected == 0.0 + && signbit(computed) != signbit (expected)) + ok = 0; diff --git a/glibc-RHEL-110535-1.patch b/glibc-upstream-2.39-228.patch similarity index 100% rename from glibc-RHEL-110535-1.patch rename to glibc-upstream-2.39-228.patch diff --git a/glibc-RHEL-110949-1.patch b/glibc-upstream-2.39-229.patch similarity index 100% rename from glibc-RHEL-110949-1.patch rename to glibc-upstream-2.39-229.patch diff --git a/glibc-upstream-2.39-230.patch b/glibc-upstream-2.39-230.patch new file mode 100644 index 0000000..20ab345 --- /dev/null +++ b/glibc-upstream-2.39-230.patch @@ -0,0 +1,103 @@ +commit 9fa7cc6a0b388ed16cf8a8976de5f5882882d503 +Author: Adam Sampson +Date: Mon May 6 18:16:32 2024 +0100 + + ldconfig: Move endswithn into a new header file + + is_gdb_python_file is doing a similar test, so it can use this helper + function as well. + + Signed-off-by: Adam Sampson + Reviewed-by: Adhemerval Zanella + (cherry picked from commit ed2b8d3a866eb37e069f6a71bdf10421cd4c5e54) + +diff --git a/elf/endswith.h b/elf/endswith.h +new file mode 100644 +index 0000000000000000..c6430c48be0c1071 +--- /dev/null ++++ b/elf/endswith.h +@@ -0,0 +1,33 @@ ++/* Copyright (C) 2023-2024 Free Software Foundation, Inc. ++ This file is part of the GNU C Library. ++ ++ This program is free software; you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published ++ by the Free Software Foundation; version 2 of the License, or ++ (at your option) any later version. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program; if not, see . */ ++ ++#ifndef _ENDSWITH_H ++#define _ENDSWITH_H ++ ++#include ++ ++/* Return true if the N bytes at NAME end with with the characters in ++ the string SUFFIX. (NAME[N + 1] does not have to be a null byte.) ++ Expected to be called with a string literal for SUFFIX. */ ++static inline bool ++endswithn (const char *name, size_t n, const char *suffix) ++{ ++ return (n >= strlen (suffix) ++ && memcmp (name + n - strlen (suffix), suffix, ++ strlen (suffix)) == 0); ++} ++ ++#endif /* _ENDSWITH_H */ +diff --git a/elf/ldconfig.c b/elf/ldconfig.c +index b64c54b53e1aa5bf..0f3ef707dd2f721d 100644 +--- a/elf/ldconfig.c ++++ b/elf/ldconfig.c +@@ -40,6 +40,7 @@ + #include + + #include ++#include + #include + #include + #include +@@ -661,17 +662,6 @@ struct dlib_entry + struct dlib_entry *next; + }; + +-/* Return true if the N bytes at NAME end with with the characters in +- the string SUFFIX. (NAME[N + 1] does not have to be a null byte.) +- Expected to be called with a string literal for SUFFIX. */ +-static inline bool +-endswithn (const char *name, size_t n, const char *suffix) +-{ +- return (n >= strlen (suffix) +- && memcmp (name + n - strlen (suffix), suffix, +- strlen (suffix)) == 0); +-} +- + /* Skip some temporary DSO files. These files may be partially written + and lead to ldconfig crashes when examined. */ + static bool +diff --git a/elf/readlib.c b/elf/readlib.c +index 4d67c7413649be30..32e8b8eb2298c9dd 100644 +--- a/elf/readlib.c ++++ b/elf/readlib.c +@@ -33,6 +33,7 @@ + #include + + #include ++#include + + #define Elf32_CLASS ELFCLASS32 + #define Elf64_CLASS ELFCLASS64 +@@ -48,7 +49,7 @@ static bool + is_gdb_python_file (const char *name) + { + size_t len = strlen (name); +- return len > 7 && strcmp (name + len - 7, "-gdb.py") == 0; ++ return endswithn (name, len, "-gdb.py"); + } + + /* Returns 0 if everything is ok, != 0 in case of error. */ diff --git a/glibc-upstream-2.39-231.patch b/glibc-upstream-2.39-231.patch new file mode 100644 index 0000000..328ae5c --- /dev/null +++ b/glibc-upstream-2.39-231.patch @@ -0,0 +1,242 @@ +commit 6917fde6f9623d0521a9f16c8f10c94ab0f2e4ba +Author: Florian Weimer +Date: Fri Oct 25 16:50:10 2024 +0200 + + elf: Run constructors on cyclic recursive dlopen (bug 31986) + + This is conceptually similar to the reported bug, but does not + depend on auditing. The fix is simple: just complete execution + of the constructors. This exposed the fact that the link map + for statically linked executables does not have l_init_called + set, even though constructors have run. + + Reviewed-by: Adhemerval Zanella + (cherry picked from commit 9897ced8e78db5d813166a7ccccfd5a42c69ef20) + +diff --git a/elf/Makefile b/elf/Makefile +index 3085a0844c6604fe..7690ee9edc0b0c9a 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -414,6 +414,7 @@ tests += \ + tst-dlmopen1 \ + tst-dlmopen3 \ + tst-dlmopen4 \ ++ tst-dlopen-recurse \ + tst-dlopen-self \ + tst-dlopen-tlsmodid \ + tst-dlopen-tlsreinit1 \ +@@ -858,6 +859,8 @@ modules-names += \ + tst-dlmopen-twice-mod1 \ + tst-dlmopen-twice-mod2 \ + tst-dlmopen1mod \ ++ tst-dlopen-recursemod1 \ ++ tst-dlopen-recursemod2 \ + tst-dlopen-sgid-mod \ + tst-dlopen-tlsreinitmod1 \ + tst-dlopen-tlsreinitmod2 \ +@@ -3145,3 +3148,6 @@ $(objpfx)tst-dlopen-tlsreinit4.out: $(objpfx)tst-auditmod1.so + tst-dlopen-tlsreinit4-ENV = LD_AUDIT=$(objpfx)tst-auditmod1.so + + $(objpfx)tst-dlopen-sgid.out: $(objpfx)tst-dlopen-sgid-mod.so ++ ++$(objpfx)tst-dlopen-recurse.out: $(objpfx)tst-dlopen-recursemod1.so ++$(objpfx)tst-dlopen-recursemod1.so: $(objpfx)tst-dlopen-recursemod2.so +diff --git a/elf/dl-open.c b/elf/dl-open.c +index 8556e7bd2fb0b40e..5139d276e04a5d85 100644 +--- a/elf/dl-open.c ++++ b/elf/dl-open.c +@@ -601,6 +601,14 @@ dl_open_worker_begin (void *a) + = _dl_debug_update (args->nsid)->r_state; + assert (r_state == RT_CONSISTENT); + ++ /* Do not return without calling the (supposedly new) map's ++ constructor. This case occurs if a dependency of a directly ++ opened map has a constructor that calls dlopen again on the ++ initially opened map. The new map is initialized last, so ++ checking only it is enough. */ ++ if (!new->l_init_called) ++ _dl_catch_exception (NULL, call_dl_init, args); ++ + return; + } + +diff --git a/elf/dl-support.c b/elf/dl-support.c +index 451932dd03e971b8..94e8197c632c11c8 100644 +--- a/elf/dl-support.c ++++ b/elf/dl-support.c +@@ -99,6 +99,7 @@ static struct link_map _dl_main_map = + .l_used = 1, + .l_tls_offset = NO_TLS_OFFSET, + .l_serial = 1, ++ .l_init_called = 1, + }; + + /* Namespace information. */ +diff --git a/elf/tst-dlopen-recurse.c b/elf/tst-dlopen-recurse.c +new file mode 100644 +index 0000000000000000..c7fb379d373c6e77 +--- /dev/null ++++ b/elf/tst-dlopen-recurse.c +@@ -0,0 +1,34 @@ ++/* Test that recursive dlopen runs constructors before return (bug 31986). ++ Copyright (C) 2024 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 ++ . */ ++ ++#include ++#include ++#include ++ ++static int ++do_test (void) ++{ ++ void *handle = xdlopen ("tst-dlopen-recursemod1.so", RTLD_NOW); ++ int *status = dlsym (handle, "recursemod1_status"); ++ printf ("info: recursemod1_status == %d (from main)\n", *status); ++ TEST_COMPARE (*status, 2); ++ xdlclose (handle); ++ return 0; ++} ++ ++#include +diff --git a/elf/tst-dlopen-recursemod1.c b/elf/tst-dlopen-recursemod1.c +new file mode 100644 +index 0000000000000000..5e0cc0eb8c32d6d4 +--- /dev/null ++++ b/elf/tst-dlopen-recursemod1.c +@@ -0,0 +1,50 @@ ++/* Directly opened test module that gets recursively opened again. ++ Copyright (C) 2024 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 ++ . */ ++ ++#include ++#include ++#include ++ ++int recursemod1_status; ++ ++/* Force linking against st-dlopen-recursemod2.so. Also allows ++ checking for relocation. */ ++extern int recursemod2_status; ++int *force_recursemod2_reference = &recursemod2_status; ++ ++static void __attribute__ ((constructor)) ++init (void) ++{ ++ ++recursemod1_status; ++ printf ("info: tst-dlopen-recursemod1.so constructor called (status %d)\n", ++ recursemod1_status); ++} ++ ++static void __attribute__ ((destructor)) ++fini (void) ++{ ++ /* The recursemod1_status variable was incremented in the ++ tst-dlopen-recursemod2.so constructor. */ ++ printf ("info: tst-dlopen-recursemod1.so destructor called (status %d)\n", ++ recursemod1_status); ++ if (recursemod1_status != 2) ++ { ++ puts ("error: recursemod1_status == 2 expected"); ++ exit (1); ++ } ++} +diff --git a/elf/tst-dlopen-recursemod2.c b/elf/tst-dlopen-recursemod2.c +new file mode 100644 +index 0000000000000000..edd2f2526b877810 +--- /dev/null ++++ b/elf/tst-dlopen-recursemod2.c +@@ -0,0 +1,66 @@ ++/* Indirectly opened module that recursively opens the directly opened module. ++ Copyright (C) 2024 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 ++ . */ ++ ++#include ++#include ++#include ++ ++int recursemod2_status; ++ ++static void __attribute__ ((constructor)) ++init (void) ++{ ++ ++recursemod2_status; ++ printf ("info: tst-dlopen-recursemod2.so constructor called (status %d)\n", ++ recursemod2_status); ++ void *handle = dlopen ("tst-dlopen-recursemod1.so", RTLD_NOW); ++ if (handle == NULL) ++ { ++ printf ("error: dlopen: %s\n", dlerror ()); ++ exit (1); ++ } ++ int *status = dlsym (handle, "recursemod1_status"); ++ if (status == NULL) ++ { ++ printf ("error: dlsym: %s\n", dlerror ()); ++ exit (1); ++ } ++ printf ("info: recursemod1_status == %d\n", *status); ++ if (*status != 1) ++ { ++ puts ("error: recursemod1_status == 1 expected"); ++ exit (1); ++ } ++ ++*status; ++ printf ("info: recursemod1_status == %d\n", *status); ++ ++ int **mod2_status = dlsym (handle, "force_recursemod2_reference"); ++ if (mod2_status == NULL || *mod2_status != &recursemod2_status) ++ { ++ puts ("error: invalid recursemod2_status address in" ++ " tst-dlopen-recursemod1.so"); ++ exit (1); ++ } ++} ++ ++static void __attribute__ ((destructor)) ++fini (void) ++{ ++ printf ("info: tst-dlopen-recursemod2.so destructor called (status %d)\n", ++ recursemod2_status); ++} diff --git a/glibc-upstream-2.39-232.patch b/glibc-upstream-2.39-232.patch new file mode 100644 index 0000000..2b9f507 --- /dev/null +++ b/glibc-upstream-2.39-232.patch @@ -0,0 +1,97 @@ +commit d6cc325fcf3d5a4ceeabfee465e6f90be1f72e8b +Author: Florian Weimer +Date: Fri Oct 25 16:50:10 2024 +0200 + + elf: Signal LA_ACT_CONSISTENT to auditors after RT_CONSISTENT switch + + Auditors can call into the dynamic loader again if + LA_ACT_CONSISTENT, and those recursive calls could observe + r_state != RT_CONSISTENT. + + We should consider failing dlopen/dlmopen/dlclose if + r_state != RT_CONSISTENT. The dynamic linker is probably not + in a state in which it can handle reentrant calls. This + needs further investigation. + + Reviewed-by: Adhemerval Zanella + (cherry picked from commit e096b7a1896886eb7dd2732ccbf1184b0eec9a63) + +diff --git a/elf/dl-close.c b/elf/dl-close.c +index 88226245eb4b7a81..b6f4daac792b8a90 100644 +--- a/elf/dl-close.c ++++ b/elf/dl-close.c +@@ -723,6 +723,11 @@ _dl_close_worker (struct link_map *map, bool force) + /* TLS is cleaned up for the unloaded modules. */ + __rtld_lock_unlock_recursive (GL(dl_load_tls_lock)); + ++ /* Notify the debugger those objects are finalized and gone. */ ++ r->r_state = RT_CONSISTENT; ++ _dl_debug_state (); ++ LIBC_PROBE (unmap_complete, 2, nsid, r); ++ + #ifdef SHARED + /* Auditing checkpoint: we have deleted all objects. Also, do not notify + auditors of the cleanup of a failed audit module loading attempt. */ +@@ -735,11 +740,6 @@ _dl_close_worker (struct link_map *map, bool force) + --GL(dl_nns); + while (GL(dl_ns)[GL(dl_nns) - 1]._ns_loaded == NULL); + +- /* Notify the debugger those objects are finalized and gone. */ +- r->r_state = RT_CONSISTENT; +- _dl_debug_state (); +- LIBC_PROBE (unmap_complete, 2, nsid, r); +- + /* Recheck if we need to retry, release the lock. */ + out: + if (dl_close_state == rerun) +diff --git a/elf/dl-open.c b/elf/dl-open.c +index 5139d276e04a5d85..5a30a57ee1487b31 100644 +--- a/elf/dl-open.c ++++ b/elf/dl-open.c +@@ -639,17 +639,17 @@ dl_open_worker_begin (void *a) + #endif + } + +-#ifdef SHARED +- /* Auditing checkpoint: we have added all objects. */ +- _dl_audit_activity_nsid (new->l_ns, LA_ACT_CONSISTENT); +-#endif +- + /* Notify the debugger all new objects are now ready to go. */ + struct r_debug *r = _dl_debug_update (args->nsid); + r->r_state = RT_CONSISTENT; + _dl_debug_state (); + LIBC_PROBE (map_complete, 3, args->nsid, r, new); + ++#ifdef SHARED ++ /* Auditing checkpoint: we have added all objects. */ ++ _dl_audit_activity_nsid (new->l_ns, LA_ACT_CONSISTENT); ++#endif ++ + _dl_open_check (new); + + /* Print scope information. */ +diff --git a/elf/rtld.c b/elf/rtld.c +index 4760633866cf9159..b308f7c9577b4bb3 100644 +--- a/elf/rtld.c ++++ b/elf/rtld.c +@@ -2416,9 +2416,6 @@ dl_main (const ElfW(Phdr) *phdr, + _dl_relocate_object might need to call `mprotect' for DT_TEXTREL. */ + _dl_sysdep_start_cleanup (); + +- /* Auditing checkpoint: we have added all objects. */ +- _dl_audit_activity_nsid (LM_ID_BASE, LA_ACT_CONSISTENT); +- + /* Notify the debugger all new objects are now ready to go. We must re-get + the address since by now the variable might be in another object. */ + r = _dl_debug_update (LM_ID_BASE); +@@ -2426,6 +2423,9 @@ dl_main (const ElfW(Phdr) *phdr, + _dl_debug_state (); + LIBC_PROBE (init_complete, 2, LM_ID_BASE, r); + ++ /* Auditing checkpoint: we have added all objects. */ ++ _dl_audit_activity_nsid (LM_ID_BASE, LA_ACT_CONSISTENT); ++ + #if defined USE_LDCONFIG && !defined MAP_COPY + /* We must munmap() the cache file. */ + _dl_unload_cache (); diff --git a/glibc-upstream-2.39-233.patch b/glibc-upstream-2.39-233.patch new file mode 100644 index 0000000..d3aee3f --- /dev/null +++ b/glibc-upstream-2.39-233.patch @@ -0,0 +1,337 @@ +commit 5f225025db0f5df9912893d4b399d9e640b84814 +Author: Florian Weimer +Date: Fri Oct 25 16:50:10 2024 +0200 + + elf: Signal RT_CONSISTENT after relocation processing in dlopen (bug 31986) + + Previously, a la_activity audit event was generated before + relocation processing completed. This does did not match what + happened during initial startup in elf/rtld.c (towards the end + of dl_main). It also caused various problems if an auditor + tried to open the same shared object again using dlmopen: + If it was the directly loaded object, it had a search scope + associated with it, so the early exit in dl_open_worker_begin + was taken even though the object was unrelocated. This caused + the r_state == RT_CONSISTENT assert to fail. Avoidance of the + assert also depends on reversing the order of r_state update + and auditor event (already implemented in a previous commit). + + At the later point, args->map can be NULL due to failure, + so use the assigned namespace ID instead if that is available. + + Reviewed-by: Adhemerval Zanella + (cherry picked from commit 43db5e2c0672cae7edea7c9685b22317eae25471) + +diff --git a/elf/Makefile b/elf/Makefile +index 7690ee9edc0b0c9a..0f1125cb634d7184 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -414,6 +414,7 @@ tests += \ + tst-dlmopen1 \ + tst-dlmopen3 \ + tst-dlmopen4 \ ++ tst-dlopen-auditdup \ + tst-dlopen-recurse \ + tst-dlopen-self \ + tst-dlopen-tlsmodid \ +@@ -859,6 +860,8 @@ modules-names += \ + tst-dlmopen-twice-mod1 \ + tst-dlmopen-twice-mod2 \ + tst-dlmopen1mod \ ++ tst-dlopen-auditdup-auditmod \ ++ tst-dlopen-auditdupmod \ + tst-dlopen-recursemod1 \ + tst-dlopen-recursemod2 \ + tst-dlopen-sgid-mod \ +@@ -3151,3 +3154,6 @@ $(objpfx)tst-dlopen-sgid.out: $(objpfx)tst-dlopen-sgid-mod.so + + $(objpfx)tst-dlopen-recurse.out: $(objpfx)tst-dlopen-recursemod1.so + $(objpfx)tst-dlopen-recursemod1.so: $(objpfx)tst-dlopen-recursemod2.so ++tst-dlopen-auditdup-ENV = LD_AUDIT=$(objpfx)tst-dlopen-auditdup-auditmod.so ++$(objpfx)tst-dlopen-auditdup.out: \ ++ $(objpfx)tst-dlopen-auditdupmod.so $(objpfx)tst-dlopen-auditdup-auditmod.so +diff --git a/elf/dl-open.c b/elf/dl-open.c +index 5a30a57ee1487b31..88e8ad8d3abcdd44 100644 +--- a/elf/dl-open.c ++++ b/elf/dl-open.c +@@ -576,6 +576,14 @@ dl_open_worker_begin (void *a) + _dl_debug_printf ("opening file=%s [%lu]; direct_opencount=%u\n\n", + new->l_name, new->l_ns, new->l_direct_opencount); + ++#ifdef SHARED ++ /* No relocation processing on this execution path. But ++ relocation has not been performed for static ++ position-dependent executables, so disable the assert for ++ static linking. */ ++ assert (new->l_relocated); ++#endif ++ + /* If the user requested the object to be in the global + namespace but it is not so far, prepare to add it now. This + can raise an exception to do a malloc failure. */ +@@ -597,10 +605,6 @@ dl_open_worker_begin (void *a) + if ((mode & RTLD_GLOBAL) && new->l_global == 0) + add_to_global_update (new); + +- const int r_state __attribute__ ((unused)) +- = _dl_debug_update (args->nsid)->r_state; +- assert (r_state == RT_CONSISTENT); +- + /* Do not return without calling the (supposedly new) map's + constructor. This case occurs if a dependency of a directly + opened map has a constructor that calls dlopen again on the +@@ -639,17 +643,6 @@ dl_open_worker_begin (void *a) + #endif + } + +- /* Notify the debugger all new objects are now ready to go. */ +- struct r_debug *r = _dl_debug_update (args->nsid); +- r->r_state = RT_CONSISTENT; +- _dl_debug_state (); +- LIBC_PROBE (map_complete, 3, args->nsid, r, new); +- +-#ifdef SHARED +- /* Auditing checkpoint: we have added all objects. */ +- _dl_audit_activity_nsid (new->l_ns, LA_ACT_CONSISTENT); +-#endif +- + _dl_open_check (new); + + /* Print scope information. */ +@@ -696,6 +689,7 @@ dl_open_worker_begin (void *a) + created dlmopen namespaces. Do not do this for static dlopen + because libc has relocations against ld.so, which may not have + been relocated at this point. */ ++ struct r_debug *r = _dl_debug_update (args->nsid); + #ifdef SHARED + if (GL(dl_ns)[args->nsid].libc_map != NULL) + _dl_open_relocate_one_object (args, r, GL(dl_ns)[args->nsid].libc_map, +@@ -787,6 +781,26 @@ dl_open_worker (void *a) + + __rtld_lock_unlock_recursive (GL(dl_load_tls_lock)); + ++ /* Auditing checkpoint and debugger signalling. Do this even on ++ error, so that dlopen exists with consistent state. */ ++ if (args->nsid >= 0 || args->map != NULL) ++ { ++ Lmid_t nsid = args->map != NULL ? args->map->l_ns : args->nsid; ++ struct r_debug *r = _dl_debug_update (nsid); ++#ifdef SHARED ++ bool was_not_consistent = r->r_state != RT_CONSISTENT; ++#endif ++ r->r_state = RT_CONSISTENT; ++ _dl_debug_state (); ++ LIBC_PROBE (map_complete, 3, nsid, r, new); ++ ++#ifdef SHARED ++ if (was_not_consistent) ++ /* Avoid redudant/recursive signalling. */ ++ _dl_audit_activity_nsid (nsid, LA_ACT_CONSISTENT); ++#endif ++ } ++ + if (__glibc_unlikely (ex.errstring != NULL)) + /* Reraise the error. */ + _dl_signal_exception (err, &ex, NULL); +diff --git a/elf/tst-dlopen-auditdup-auditmod.c b/elf/tst-dlopen-auditdup-auditmod.c +new file mode 100644 +index 0000000000000000..9b67295e94d03e7a +--- /dev/null ++++ b/elf/tst-dlopen-auditdup-auditmod.c +@@ -0,0 +1,100 @@ ++/* Auditor that opens again an object that just has been opened. ++ Copyright (C) 2024 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++unsigned int ++la_version (unsigned int v) ++{ ++ return LAV_CURRENT; ++} ++ ++static bool trigger_on_la_activity; ++ ++unsigned int ++la_objopen (struct link_map *map, Lmid_t lmid, uintptr_t *cookie) ++{ ++ printf ("info: la_objopen: \"%s\"\n", map->l_name); ++ if (strstr (map->l_name, "/tst-dlopen-auditdupmod.so") != NULL) ++ trigger_on_la_activity = true; ++ return 0; ++} ++ ++void ++la_activity (uintptr_t *cookie, unsigned int flag) ++{ ++ static unsigned int calls; ++ ++calls; ++ printf ("info: la_activity: call %u (flag %u)\n", calls, flag); ++ fflush (stdout); ++ if (trigger_on_la_activity) ++ { ++ /* Avoid triggering on the dlmopen call below. */ ++ static bool recursion; ++ if (recursion) ++ return; ++ recursion = true; ++ ++ puts ("info: about to dlmopen tst-dlopen-auditdupmod.so"); ++ fflush (stdout); ++ void *handle = dlmopen (LM_ID_BASE, "tst-dlopen-auditdupmod.so", ++ RTLD_NOW); ++ if (handle == NULL) ++ { ++ printf ("error: dlmopen: %s\n", dlerror ()); ++ fflush (stdout); ++ _exit (1); ++ } ++ ++ /* Check that the constructor has run. */ ++ int *status = dlsym (handle, "auditdupmod_status"); ++ if (status == NULL) ++ { ++ printf ("error: dlsym: %s\n", dlerror ()); ++ fflush (stdout); ++ _exit (1); ++ } ++ printf ("info: auditdupmod_status == %d\n", *status); ++ if (*status != 1) ++ { ++ puts ("error: auditdupmod_status == 1 expected"); ++ fflush (stdout); ++ _exit (1); ++ } ++ /* Checked in the destructor and the main program. */ ++ ++*status; ++ printf ("info: auditdupmod_status == %d\n", *status); ++ ++ /* Check that the module has been relocated. */ ++ int **status_address = dlsym (handle, "auditdupmod_status_address"); ++ if (status_address == NULL || *status_address != status) ++ { ++ puts ("error: invalid auditdupmod_status address in" ++ " tst-dlopen-auditdupmod.so"); ++ fflush (stdout); ++ _exit (1); ++ } ++ ++ fflush (stdout); ++ } ++} +diff --git a/elf/tst-dlopen-auditdup.c b/elf/tst-dlopen-auditdup.c +new file mode 100644 +index 0000000000000000..d022c58ae3091da1 +--- /dev/null ++++ b/elf/tst-dlopen-auditdup.c +@@ -0,0 +1,36 @@ ++/* Test that recursive dlopen from auditor works (bug 31986). ++ Copyright (C) 2024 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 ++ . */ ++ ++#include ++#include ++#include ++ ++static int ++do_test (void) ++{ ++ puts ("info: about to dlopen tst-dlopen-auditdupmod.so"); ++ fflush (stdout); ++ void *handle = xdlopen ("tst-dlopen-auditdupmod.so", RTLD_NOW); ++ int *status = xdlsym (handle, "auditdupmod_status"); ++ printf ("info: auditdupmod_status == %d (from main)\n", *status); ++ TEST_COMPARE (*status, 2); ++ xdlclose (handle); ++ return 0; ++} ++ ++#include +diff --git a/elf/tst-dlopen-auditdupmod.c b/elf/tst-dlopen-auditdupmod.c +new file mode 100644 +index 0000000000000000..59b7e21daa8212df +--- /dev/null ++++ b/elf/tst-dlopen-auditdupmod.c +@@ -0,0 +1,48 @@ ++/* Directly opened test module that gets reopened from the auditor. ++ Copyright (C) 2024 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 ++ . */ ++ ++#include ++#include ++#include ++ ++int auditdupmod_status; ++ ++/* Used to check for successful relocation processing. */ ++int *auditdupmod_status_address = &auditdupmod_status; ++ ++static void __attribute__ ((constructor)) ++init (void) ++{ ++ ++auditdupmod_status; ++ printf ("info: tst-dlopen-auditdupmod.so constructor called (status %d)\n", ++ auditdupmod_status); ++} ++ ++static void __attribute__ ((destructor)) ++fini (void) ++{ ++ /* The tst-dlopen-auditdup-auditmod.so auditor incremented ++ auditdupmod_status. */ ++ printf ("info: tst-dlopen-auditdupmod.so destructor called (status %d)\n", ++ auditdupmod_status); ++ if (auditdupmod_status != 2) ++ { ++ puts ("error: auditdupmod_status == 2 expected"); ++ exit (1); ++ } ++} diff --git a/glibc-upstream-2.39-234.patch b/glibc-upstream-2.39-234.patch new file mode 100644 index 0000000..fccdb50 --- /dev/null +++ b/glibc-upstream-2.39-234.patch @@ -0,0 +1,26 @@ +commit 46e3ecad27f65dd239d6d3568b81338f4525585f +Author: Florian Weimer +Date: Fri Oct 25 17:41:53 2024 +0200 + + elf: Fix map_complete Systemtap probe in dl_open_worker + + The refactoring did not take the change of variable into account. + Fixes commit 43db5e2c0672cae7edea7c9685b22317eae25471 + ("elf: Signal RT_CONSISTENT after relocation processing in dlopen + (bug 31986)"). + + (cherry picked from commit ac73067cb7a328bf106ecd041c020fc61be7e087) + +diff --git a/elf/dl-open.c b/elf/dl-open.c +index 88e8ad8d3abcdd44..bd15f5f6a446115d 100644 +--- a/elf/dl-open.c ++++ b/elf/dl-open.c +@@ -792,7 +792,7 @@ dl_open_worker (void *a) + #endif + r->r_state = RT_CONSISTENT; + _dl_debug_state (); +- LIBC_PROBE (map_complete, 3, nsid, r, new); ++ LIBC_PROBE (map_complete, 3, nsid, r, args->map); + + #ifdef SHARED + if (was_not_consistent) diff --git a/glibc-upstream-2.39-235.patch b/glibc-upstream-2.39-235.patch new file mode 100644 index 0000000..829d052 --- /dev/null +++ b/glibc-upstream-2.39-235.patch @@ -0,0 +1,271 @@ +commit 2b89de7c91e5e71732a32efef94075d9edbff95e +Author: Florian Weimer +Date: Mon Oct 28 14:45:30 2024 +0100 + + Revert "elf: Run constructors on cyclic recursive dlopen (bug 31986)" + + This reverts commit 9897ced8e78db5d813166a7ccccfd5a42c69ef20. + + Adjust the test expectations in elf/tst-dlopen-auditdup-auditmod.c + accordingly. + + (cherry picked from commit 95129e6b8fabdaa8cd8a4a5cc20be0f4cb0ba59f) + +diff --git a/elf/Makefile b/elf/Makefile +index 0f1125cb634d7184..479ef766c8f955f2 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -415,7 +415,6 @@ tests += \ + tst-dlmopen3 \ + tst-dlmopen4 \ + tst-dlopen-auditdup \ +- tst-dlopen-recurse \ + tst-dlopen-self \ + tst-dlopen-tlsmodid \ + tst-dlopen-tlsreinit1 \ +@@ -862,8 +861,6 @@ modules-names += \ + tst-dlmopen1mod \ + tst-dlopen-auditdup-auditmod \ + tst-dlopen-auditdupmod \ +- tst-dlopen-recursemod1 \ +- tst-dlopen-recursemod2 \ + tst-dlopen-sgid-mod \ + tst-dlopen-tlsreinitmod1 \ + tst-dlopen-tlsreinitmod2 \ +@@ -3152,8 +3149,6 @@ tst-dlopen-tlsreinit4-ENV = LD_AUDIT=$(objpfx)tst-auditmod1.so + + $(objpfx)tst-dlopen-sgid.out: $(objpfx)tst-dlopen-sgid-mod.so + +-$(objpfx)tst-dlopen-recurse.out: $(objpfx)tst-dlopen-recursemod1.so +-$(objpfx)tst-dlopen-recursemod1.so: $(objpfx)tst-dlopen-recursemod2.so + tst-dlopen-auditdup-ENV = LD_AUDIT=$(objpfx)tst-dlopen-auditdup-auditmod.so + $(objpfx)tst-dlopen-auditdup.out: \ + $(objpfx)tst-dlopen-auditdupmod.so $(objpfx)tst-dlopen-auditdup-auditmod.so +diff --git a/elf/dl-open.c b/elf/dl-open.c +index bd15f5f6a446115d..b00f283c42d19adb 100644 +--- a/elf/dl-open.c ++++ b/elf/dl-open.c +@@ -605,14 +605,6 @@ dl_open_worker_begin (void *a) + if ((mode & RTLD_GLOBAL) && new->l_global == 0) + add_to_global_update (new); + +- /* Do not return without calling the (supposedly new) map's +- constructor. This case occurs if a dependency of a directly +- opened map has a constructor that calls dlopen again on the +- initially opened map. The new map is initialized last, so +- checking only it is enough. */ +- if (!new->l_init_called) +- _dl_catch_exception (NULL, call_dl_init, args); +- + return; + } + +diff --git a/elf/dl-support.c b/elf/dl-support.c +index 94e8197c632c11c8..451932dd03e971b8 100644 +--- a/elf/dl-support.c ++++ b/elf/dl-support.c +@@ -99,7 +99,6 @@ static struct link_map _dl_main_map = + .l_used = 1, + .l_tls_offset = NO_TLS_OFFSET, + .l_serial = 1, +- .l_init_called = 1, + }; + + /* Namespace information. */ +diff --git a/elf/tst-dlopen-auditdup-auditmod.c b/elf/tst-dlopen-auditdup-auditmod.c +index 9b67295e94d03e7a..270a595ec4de1439 100644 +--- a/elf/tst-dlopen-auditdup-auditmod.c ++++ b/elf/tst-dlopen-auditdup-auditmod.c +@@ -66,7 +66,11 @@ la_activity (uintptr_t *cookie, unsigned int flag) + _exit (1); + } + +- /* Check that the constructor has run. */ ++ /* Check that the constructor has not run. Running the ++ constructor would require constructing its dependencies, but ++ the constructor call that triggered this auditing activity ++ has not completed, and constructors among the dependencies ++ may not be able to deal with that. */ + int *status = dlsym (handle, "auditdupmod_status"); + if (status == NULL) + { +@@ -75,9 +79,9 @@ la_activity (uintptr_t *cookie, unsigned int flag) + _exit (1); + } + printf ("info: auditdupmod_status == %d\n", *status); +- if (*status != 1) ++ if (*status != 0) + { +- puts ("error: auditdupmod_status == 1 expected"); ++ puts ("error: auditdupmod_status == 0 expected"); + fflush (stdout); + _exit (1); + } +diff --git a/elf/tst-dlopen-recurse.c b/elf/tst-dlopen-recurse.c +deleted file mode 100644 +index c7fb379d373c6e77..0000000000000000 +--- a/elf/tst-dlopen-recurse.c ++++ /dev/null +@@ -1,34 +0,0 @@ +-/* Test that recursive dlopen runs constructors before return (bug 31986). +- Copyright (C) 2024 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 +- . */ +- +-#include +-#include +-#include +- +-static int +-do_test (void) +-{ +- void *handle = xdlopen ("tst-dlopen-recursemod1.so", RTLD_NOW); +- int *status = dlsym (handle, "recursemod1_status"); +- printf ("info: recursemod1_status == %d (from main)\n", *status); +- TEST_COMPARE (*status, 2); +- xdlclose (handle); +- return 0; +-} +- +-#include +diff --git a/elf/tst-dlopen-recursemod1.c b/elf/tst-dlopen-recursemod1.c +deleted file mode 100644 +index 5e0cc0eb8c32d6d4..0000000000000000 +--- a/elf/tst-dlopen-recursemod1.c ++++ /dev/null +@@ -1,50 +0,0 @@ +-/* Directly opened test module that gets recursively opened again. +- Copyright (C) 2024 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 +- . */ +- +-#include +-#include +-#include +- +-int recursemod1_status; +- +-/* Force linking against st-dlopen-recursemod2.so. Also allows +- checking for relocation. */ +-extern int recursemod2_status; +-int *force_recursemod2_reference = &recursemod2_status; +- +-static void __attribute__ ((constructor)) +-init (void) +-{ +- ++recursemod1_status; +- printf ("info: tst-dlopen-recursemod1.so constructor called (status %d)\n", +- recursemod1_status); +-} +- +-static void __attribute__ ((destructor)) +-fini (void) +-{ +- /* The recursemod1_status variable was incremented in the +- tst-dlopen-recursemod2.so constructor. */ +- printf ("info: tst-dlopen-recursemod1.so destructor called (status %d)\n", +- recursemod1_status); +- if (recursemod1_status != 2) +- { +- puts ("error: recursemod1_status == 2 expected"); +- exit (1); +- } +-} +diff --git a/elf/tst-dlopen-recursemod2.c b/elf/tst-dlopen-recursemod2.c +deleted file mode 100644 +index edd2f2526b877810..0000000000000000 +--- a/elf/tst-dlopen-recursemod2.c ++++ /dev/null +@@ -1,66 +0,0 @@ +-/* Indirectly opened module that recursively opens the directly opened module. +- Copyright (C) 2024 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 +- . */ +- +-#include +-#include +-#include +- +-int recursemod2_status; +- +-static void __attribute__ ((constructor)) +-init (void) +-{ +- ++recursemod2_status; +- printf ("info: tst-dlopen-recursemod2.so constructor called (status %d)\n", +- recursemod2_status); +- void *handle = dlopen ("tst-dlopen-recursemod1.so", RTLD_NOW); +- if (handle == NULL) +- { +- printf ("error: dlopen: %s\n", dlerror ()); +- exit (1); +- } +- int *status = dlsym (handle, "recursemod1_status"); +- if (status == NULL) +- { +- printf ("error: dlsym: %s\n", dlerror ()); +- exit (1); +- } +- printf ("info: recursemod1_status == %d\n", *status); +- if (*status != 1) +- { +- puts ("error: recursemod1_status == 1 expected"); +- exit (1); +- } +- ++*status; +- printf ("info: recursemod1_status == %d\n", *status); +- +- int **mod2_status = dlsym (handle, "force_recursemod2_reference"); +- if (mod2_status == NULL || *mod2_status != &recursemod2_status) +- { +- puts ("error: invalid recursemod2_status address in" +- " tst-dlopen-recursemod1.so"); +- exit (1); +- } +-} +- +-static void __attribute__ ((destructor)) +-fini (void) +-{ +- printf ("info: tst-dlopen-recursemod2.so destructor called (status %d)\n", +- recursemod2_status); +-} diff --git a/glibc-upstream-2.39-236.patch b/glibc-upstream-2.39-236.patch new file mode 100644 index 0000000..f6bc066 --- /dev/null +++ b/glibc-upstream-2.39-236.patch @@ -0,0 +1,147 @@ +commit b2d8c6cbe70bbafb2238f0595c36fbedf64d00c2 +Author: Florian Weimer +Date: Wed Nov 6 10:33:44 2024 +0100 + + elf: rtld_multiple_ref is always true + + For a long time, libc.so.6 has dependend on ld.so, which + means that there is a reference to ld.so in all processes, + and rtld_multiple_ref is always true. In fact, if + rtld_multiple_ref were false, some of the ld.so setup code + would not run. + + Reviewed-by: DJ Delorie + (cherry picked from commit 8f8dd904c4a2207699bb666f30acceb5209c8d3f) + +diff --git a/elf/rtld.c b/elf/rtld.c +index b308f7c9577b4bb3..41f8c329772b2b7a 100644 +--- a/elf/rtld.c ++++ b/elf/rtld.c +@@ -2010,43 +2010,37 @@ dl_main (const ElfW(Phdr) *phdr, + if (main_map->l_searchlist.r_list[i] == &GL(dl_rtld_map)) + break; + +- bool rtld_multiple_ref = false; +- if (__glibc_likely (i < main_map->l_searchlist.r_nlist)) +- { +- /* Some DT_NEEDED entry referred to the interpreter object itself, so +- put it back in the list of visible objects. We insert it into the +- chain in symbol search order because gdb uses the chain's order as +- its symbol search order. */ +- rtld_multiple_ref = true; ++ /* Insert the link map for the dynamic loader into the chain in ++ symbol search order because gdb uses the chain's order as its ++ symbol search order. */ + +- GL(dl_rtld_map).l_prev = main_map->l_searchlist.r_list[i - 1]; +- if (__glibc_likely (state.mode == rtld_mode_normal)) +- { +- GL(dl_rtld_map).l_next = (i + 1 < main_map->l_searchlist.r_nlist +- ? main_map->l_searchlist.r_list[i + 1] +- : NULL); ++ GL(dl_rtld_map).l_prev = main_map->l_searchlist.r_list[i - 1]; ++ if (__glibc_likely (state.mode == rtld_mode_normal)) ++ { ++ GL(dl_rtld_map).l_next = (i + 1 < main_map->l_searchlist.r_nlist ++ ? main_map->l_searchlist.r_list[i + 1] ++ : NULL); + #ifdef NEED_DL_SYSINFO_DSO +- if (GLRO(dl_sysinfo_map) != NULL +- && GL(dl_rtld_map).l_prev->l_next == GLRO(dl_sysinfo_map) +- && GL(dl_rtld_map).l_next != GLRO(dl_sysinfo_map)) +- GL(dl_rtld_map).l_prev = GLRO(dl_sysinfo_map); ++ if (GLRO(dl_sysinfo_map) != NULL ++ && GL(dl_rtld_map).l_prev->l_next == GLRO(dl_sysinfo_map) ++ && GL(dl_rtld_map).l_next != GLRO(dl_sysinfo_map)) ++ GL(dl_rtld_map).l_prev = GLRO(dl_sysinfo_map); + #endif +- } +- else +- /* In trace mode there might be an invisible object (which we +- could not find) after the previous one in the search list. +- In this case it doesn't matter much where we put the +- interpreter object, so we just initialize the list pointer so +- that the assertion below holds. */ +- GL(dl_rtld_map).l_next = GL(dl_rtld_map).l_prev->l_next; +- +- assert (GL(dl_rtld_map).l_prev->l_next == GL(dl_rtld_map).l_next); +- GL(dl_rtld_map).l_prev->l_next = &GL(dl_rtld_map); +- if (GL(dl_rtld_map).l_next != NULL) +- { +- assert (GL(dl_rtld_map).l_next->l_prev == GL(dl_rtld_map).l_prev); +- GL(dl_rtld_map).l_next->l_prev = &GL(dl_rtld_map); +- } ++ } ++ else ++ /* In trace mode there might be an invisible object (which we ++ could not find) after the previous one in the search list. ++ In this case it doesn't matter much where we put the ++ interpreter object, so we just initialize the list pointer so ++ that the assertion below holds. */ ++ GL(dl_rtld_map).l_next = GL(dl_rtld_map).l_prev->l_next; ++ ++ assert (GL(dl_rtld_map).l_prev->l_next == GL(dl_rtld_map).l_next); ++ GL(dl_rtld_map).l_prev->l_next = &GL(dl_rtld_map); ++ if (GL(dl_rtld_map).l_next != NULL) ++ { ++ assert (GL(dl_rtld_map).l_next->l_prev == GL(dl_rtld_map).l_prev); ++ GL(dl_rtld_map).l_next->l_prev = &GL(dl_rtld_map); + } + + /* Now let us see whether all libraries are available in the +@@ -2374,35 +2368,33 @@ dl_main (const ElfW(Phdr) *phdr, + /* Make sure no new search directories have been added. */ + assert (GLRO(dl_init_all_dirs) == GL(dl_all_dirs)); + +- if (rtld_multiple_ref) +- { +- /* There was an explicit ref to the dynamic linker as a shared lib. +- Re-relocate ourselves with user-controlled symbol definitions. ++ /* Re-relocate ourselves with user-controlled symbol definitions. + +- We must do this after TLS initialization in case after this +- re-relocation, we might call a user-supplied function +- (e.g. calloc from _dl_relocate_object) that uses TLS data. */ ++ We must do this after TLS initialization in case after this ++ re-relocation, we might call a user-supplied function ++ (e.g. calloc from _dl_relocate_object) that uses TLS data. */ + +- /* Set up the object lookup structures. */ +- _dl_find_object_init (); ++ /* Set up the object lookup structures. */ ++ _dl_find_object_init (); + +- /* The malloc implementation has been relocated, so resolving +- its symbols (and potentially calling IFUNC resolvers) is safe +- at this point. */ +- __rtld_malloc_init_real (main_map); ++ /* The malloc implementation has been relocated, so resolving ++ its symbols (and potentially calling IFUNC resolvers) is safe ++ at this point. */ ++ __rtld_malloc_init_real (main_map); + +- /* Likewise for the locking implementation. */ +- __rtld_mutex_init (); ++ /* Likewise for the locking implementation. */ ++ __rtld_mutex_init (); + +- RTLD_TIMING_VAR (start); +- rtld_timer_start (&start); ++ { ++ RTLD_TIMING_VAR (start); ++ rtld_timer_start (&start); + +- /* Mark the link map as not yet relocated again. */ +- GL(dl_rtld_map).l_relocated = 0; +- _dl_relocate_object (&GL(dl_rtld_map), main_map->l_scope, 0, 0); ++ /* Mark the link map as not yet relocated again. */ ++ GL(dl_rtld_map).l_relocated = 0; ++ _dl_relocate_object (&GL(dl_rtld_map), main_map->l_scope, 0, 0); + +- rtld_timer_accum (&relocate_time, start); +- } ++ rtld_timer_accum (&relocate_time, start); ++ } + + /* Relocation is complete. Perform early libc initialization. This + is the initial libc, even if audit modules have been loaded with diff --git a/glibc-upstream-2.39-237.patch b/glibc-upstream-2.39-237.patch new file mode 100644 index 0000000..89b9b06 --- /dev/null +++ b/glibc-upstream-2.39-237.patch @@ -0,0 +1,53 @@ +commit 5434cc2c4152dddcfb2a6f6cb39b6ff33099a193 +Author: Florian Weimer +Date: Wed Nov 6 10:33:44 2024 +0100 + + elf: Do not define consider_profiling, consider_symbind as macros + + This avoids surprises when refactoring the code if these identifiers + are re-used later in the file. + + Reviewed-by: DJ Delorie + (cherry picked from commit a79642204537dec8a1e1c58d1e0a074b3c624f46) + +diff --git a/elf/dl-reloc.c b/elf/dl-reloc.c +index 4bf7aec88b844bc7..b2c1627ceb847486 100644 +--- a/elf/dl-reloc.c ++++ b/elf/dl-reloc.c +@@ -220,8 +220,8 @@ _dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[], + int lazy = reloc_mode & RTLD_LAZY; + int skip_ifunc = reloc_mode & __RTLD_NOIFUNC; + +-#ifdef SHARED + bool consider_symbind = false; ++#ifdef SHARED + /* If we are auditing, install the same handlers we need for profiling. */ + if ((reloc_mode & __RTLD_AUDIT) == 0) + { +@@ -240,9 +240,7 @@ _dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[], + } + #elif defined PROF + /* Never use dynamic linker profiling for gprof profiling code. */ +-# define consider_profiling 0 +-#else +-# define consider_symbind 0 ++ consider_profiling = 0; + #endif + + /* If DT_BIND_NOW is set relocate all references in this object. We +@@ -300,7 +298,6 @@ _dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[], + + ELF_DYNAMIC_RELOCATE (l, scope, lazy, consider_profiling, skip_ifunc); + +-#ifndef PROF + if ((consider_profiling || consider_symbind) + && l->l_info[DT_PLTRELSZ] != NULL) + { +@@ -321,7 +318,6 @@ _dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[], + _dl_fatal_printf (errstring, RTLD_PROGNAME, l->l_name); + } + } +-#endif + } + + /* Mark the object so we know this work has been done. */ diff --git a/glibc-upstream-2.39-238.patch b/glibc-upstream-2.39-238.patch new file mode 100644 index 0000000..7045d70 --- /dev/null +++ b/glibc-upstream-2.39-238.patch @@ -0,0 +1,78 @@ +commit 65d86471cee80144aee1829b191cd23dd9683497 +Author: Florian Weimer +Date: Wed Nov 6 10:33:44 2024 +0100 + + elf: Introduce _dl_relocate_object_no_relro + + And make _dl_protect_relro apply RELRO conditionally. + + Reviewed-by: DJ Delorie + (cherry picked from commit f2326c2ec0a0a8db7bc7f4db8cce3002768fc3b6) + +diff --git a/elf/dl-reloc.c b/elf/dl-reloc.c +index b2c1627ceb847486..76d14830ddda83b7 100644 +--- a/elf/dl-reloc.c ++++ b/elf/dl-reloc.c +@@ -202,12 +202,9 @@ resolve_map (lookup_t l, struct r_scope_elem *scope[], const ElfW(Sym) **ref, + #include "dynamic-link.h" + + void +-_dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[], +- int reloc_mode, int consider_profiling) ++_dl_relocate_object_no_relro (struct link_map *l, struct r_scope_elem *scope[], ++ int reloc_mode, int consider_profiling) + { +- if (l->l_relocated) +- return; +- + struct textrels + { + caddr_t start; +@@ -338,17 +335,24 @@ _dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[], + + textrels = textrels->next; + } +- +- /* In case we can protect the data now that the relocations are +- done, do it. */ +- if (l->l_relro_size != 0) +- _dl_protect_relro (l); + } + ++void ++_dl_relocate_object (struct link_map *l, struct r_scope_elem *scope[], ++ int reloc_mode, int consider_profiling) ++{ ++ if (l->l_relocated) ++ return; ++ _dl_relocate_object_no_relro (l, scope, reloc_mode, consider_profiling); ++ _dl_protect_relro (l); ++} + + void + _dl_protect_relro (struct link_map *l) + { ++ if (l->l_relro_size == 0) ++ return; ++ + ElfW(Addr) start = ALIGN_DOWN((l->l_addr + + l->l_relro_addr), + GLRO(dl_pagesize)); +diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h +index 259ce2e7d6e8ff31..91447a5e77c2466d 100644 +--- a/sysdeps/generic/ldsodefs.h ++++ b/sysdeps/generic/ldsodefs.h +@@ -1014,6 +1014,13 @@ extern void _dl_relocate_object (struct link_map *map, + int reloc_mode, int consider_profiling) + attribute_hidden; + ++/* Perform relocation, but do not apply RELRO. Does not check ++ L->relocated. Otherwise the same as _dl_relocate_object. */ ++void _dl_relocate_object_no_relro (struct link_map *map, ++ struct r_scope_elem *scope[], ++ int reloc_mode, int consider_profiling) ++ attribute_hidden; ++ + /* Protect PT_GNU_RELRO area. */ + extern void _dl_protect_relro (struct link_map *map) attribute_hidden; + diff --git a/glibc-upstream-2.39-239.patch b/glibc-upstream-2.39-239.patch new file mode 100644 index 0000000..03526bf --- /dev/null +++ b/glibc-upstream-2.39-239.patch @@ -0,0 +1,204 @@ +commit 4f145bb35d5aed0cb102ba2a7b05aec1cf980672 +Author: Florian Weimer +Date: Wed Nov 6 10:33:44 2024 +0100 + + elf: Switch to main malloc after final ld.so self-relocation + + Before commit ee1ada1bdb8074de6e1bdc956ab19aef7b6a7872 + ("elf: Rework exception handling in the dynamic loader + [BZ #25486]"), the previous order called the main calloc + to allocate a shadow GOT/PLT array for auditing support. + This happened before libc.so.6 ELF constructors were run, so + a user malloc could run without libc.so.6 having been + initialized fully. One observable effect was that + environ was NULL at this point. + + It does not seem to be possible at present to trigger such + an allocation, but it seems more robust to delay switching + to main malloc after ld.so self-relocation is complete. + The elf/tst-rtld-no-malloc-audit test case fails with a + 2.34-era glibc that does not have this fix. + + Reviewed-by: DJ Delorie + (cherry picked from commit c1560f3f75c0e892b5522c16f91b4e303f677094) + +diff --git a/elf/Makefile b/elf/Makefile +index 479ef766c8f955f2..91fd05c9c0e6084a 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -453,6 +453,9 @@ tests += \ + tst-recursive-tls \ + tst-relsort1 \ + tst-ro-dynamic \ ++ tst-rtld-no-malloc \ ++ tst-rtld-no-malloc-audit \ ++ tst-rtld-no-malloc-preload \ + tst-rtld-run-static \ + tst-single_threaded \ + tst-single_threaded-pthread \ +@@ -3152,3 +3155,9 @@ $(objpfx)tst-dlopen-sgid.out: $(objpfx)tst-dlopen-sgid-mod.so + tst-dlopen-auditdup-ENV = LD_AUDIT=$(objpfx)tst-dlopen-auditdup-auditmod.so + $(objpfx)tst-dlopen-auditdup.out: \ + $(objpfx)tst-dlopen-auditdupmod.so $(objpfx)tst-dlopen-auditdup-auditmod.so ++ ++# Reuse an audit module which provides ample debug logging. ++tst-rtld-no-malloc-audit-ENV = LD_AUDIT=$(objpfx)tst-auditmod1.so ++ ++# Any shared object should do. ++tst-rtld-no-malloc-preload-ENV = LD_PRELOAD=$(objpfx)tst-auditmod1.so +diff --git a/elf/dl-support.c b/elf/dl-support.c +index 451932dd03e971b8..ee590edf93824d9b 100644 +--- a/elf/dl-support.c ++++ b/elf/dl-support.c +@@ -338,8 +338,7 @@ _dl_non_dynamic_init (void) + call_function_static_weak (_dl_find_object_init); + + /* Setup relro on the binary itself. */ +- if (_dl_main_map.l_relro_size != 0) +- _dl_protect_relro (&_dl_main_map); ++ _dl_protect_relro (&_dl_main_map); + } + + #ifdef DL_SYSINFO_IMPLEMENTATION +diff --git a/elf/rtld.c b/elf/rtld.c +index 41f8c329772b2b7a..ff938186738e8a87 100644 +--- a/elf/rtld.c ++++ b/elf/rtld.c +@@ -2368,30 +2368,27 @@ dl_main (const ElfW(Phdr) *phdr, + /* Make sure no new search directories have been added. */ + assert (GLRO(dl_init_all_dirs) == GL(dl_all_dirs)); + +- /* Re-relocate ourselves with user-controlled symbol definitions. +- +- We must do this after TLS initialization in case after this +- re-relocation, we might call a user-supplied function +- (e.g. calloc from _dl_relocate_object) that uses TLS data. */ +- + /* Set up the object lookup structures. */ + _dl_find_object_init (); + +- /* The malloc implementation has been relocated, so resolving +- its symbols (and potentially calling IFUNC resolvers) is safe +- at this point. */ +- __rtld_malloc_init_real (main_map); +- + /* Likewise for the locking implementation. */ + __rtld_mutex_init (); + ++ /* Re-relocate ourselves with user-controlled symbol definitions. */ ++ + { + RTLD_TIMING_VAR (start); + rtld_timer_start (&start); + +- /* Mark the link map as not yet relocated again. */ +- GL(dl_rtld_map).l_relocated = 0; +- _dl_relocate_object (&GL(dl_rtld_map), main_map->l_scope, 0, 0); ++ _dl_relocate_object_no_relro (&GL(dl_rtld_map), main_map->l_scope, 0, 0); ++ ++ /* The malloc implementation has been relocated, so resolving ++ its symbols (and potentially calling IFUNC resolvers) is safe ++ at this point. */ ++ __rtld_malloc_init_real (main_map); ++ ++ if (GL(dl_rtld_map).l_relro_size != 0) ++ _dl_protect_relro (&GL(dl_rtld_map)); + + rtld_timer_accum (&relocate_time, start); + } +diff --git a/elf/tst-rtld-no-malloc-audit.c b/elf/tst-rtld-no-malloc-audit.c +new file mode 100644 +index 0000000000000000..a028377ad1fea027 +--- /dev/null ++++ b/elf/tst-rtld-no-malloc-audit.c +@@ -0,0 +1 @@ ++#include "tst-rtld-no-malloc.c" +diff --git a/elf/tst-rtld-no-malloc-preload.c b/elf/tst-rtld-no-malloc-preload.c +new file mode 100644 +index 0000000000000000..a028377ad1fea027 +--- /dev/null ++++ b/elf/tst-rtld-no-malloc-preload.c +@@ -0,0 +1 @@ ++#include "tst-rtld-no-malloc.c" +diff --git a/elf/tst-rtld-no-malloc.c b/elf/tst-rtld-no-malloc.c +new file mode 100644 +index 0000000000000000..5f24d4bd72c4af0c +--- /dev/null ++++ b/elf/tst-rtld-no-malloc.c +@@ -0,0 +1,76 @@ ++/* Test that program loading does not call malloc. ++ Copyright (C) 2024 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 ++ . */ ++ ++ ++#include ++#include ++ ++static void ++print (const char *s) ++{ ++ const char *end = s + strlen (s); ++ while (s < end) ++ { ++ ssize_t ret = write (STDOUT_FILENO, s, end - s); ++ if (ret <= 0) ++ _exit (2); ++ s += ret; ++ } ++} ++ ++static void __attribute__ ((noreturn)) ++unexpected_call (const char *function) ++{ ++ print ("error: unexpected call to "); ++ print (function); ++ print ("\n"); ++ _exit (1); ++} ++ ++/* These are the malloc functions implement in elf/dl-minimal.c. */ ++ ++void ++free (void *ignored) ++{ ++ unexpected_call ("free"); ++} ++ ++void * ++calloc (size_t ignored1, size_t ignored2) ++{ ++ unexpected_call ("calloc"); ++} ++ ++void * ++malloc (size_t ignored) ++{ ++ unexpected_call ("malloc"); ++} ++ ++void * ++realloc (void *ignored1, size_t ignored2) ++{ ++ unexpected_call ("realloc"); ++} ++ ++int ++main (void) ++{ ++ /* Do not use the test wrapper, to avoid spurious malloc calls from it. */ ++ return 0; ++} diff --git a/glibc-upstream-2.39-240.patch b/glibc-upstream-2.39-240.patch new file mode 100644 index 0000000..aea3c22 --- /dev/null +++ b/glibc-upstream-2.39-240.patch @@ -0,0 +1,77 @@ +commit d21a217fa0199fed74f975b498408abb7606f6fe +Author: Florian Weimer +Date: Tue Sep 3 17:52:47 2024 +0200 + + elf: Update DSO list, write audit log to elf/tst-audit23.out + + After commit 1d5024f4f052c12e404d42d3b5bfe9c3e9fd27c4 + ("support: Build with exceptions and asynchronous unwind tables + [BZ #30587]"), libgcc_s is expected to show up in the DSO + list on 32-bit Arm. Do not update max_objs because vdso is not + tracked (and which is the reason why the test currently passes + even with libgcc_s present). + + Also write the log output from the auditor to standard output, + for easier test debugging. + + Reviewed-by: Adhemerval Zanella + (cherry picked from commit 4a50fdf8b2c1106b50cd9056b4c6f3a72cdeed5f) + +diff --git a/elf/tst-audit23.c b/elf/tst-audit23.c +index 32e7c8b2a3129c51..dada6bb1f8dabab5 100644 +--- a/elf/tst-audit23.c ++++ b/elf/tst-audit23.c +@@ -85,13 +85,28 @@ do_test (int argc, char *argv[]) + = support_capture_subprogram (spargv[0], spargv); + support_capture_subprocess_check (&result, "tst-audit22", 0, sc_allow_stderr); + ++ { ++ FILE *fp = fmemopen (result.err.buffer, result.err.length, "r"); ++ TEST_VERIFY (fp != NULL); ++ unsigned int line = 0; ++ char *buffer = NULL; ++ size_t buffer_length = 0; ++ puts ("info: *** audit log start ***"); ++ while (xgetline (&buffer, &buffer_length, fp)) ++ printf ("%6u\t%s", ++line, buffer); ++ puts ("info: *** audit log end ***"); ++ free (buffer); ++ xfclose (fp); ++ } ++ + /* The expected la_objopen/la_objclose: + 1. executable + 2. loader + 3. libc.so +- 4. tst-audit23mod.so +- 5. libc.so (LM_ID_NEWLM). +- 6. vdso (optional and ignored). */ ++ 4. libgcc_s.so (one some architectures, for libsupport) ++ 5. tst-audit23mod.so ++ 6. libc.so (LM_ID_NEWLM). ++ vdso (optional and ignored). */ + enum { max_objs = 6 }; + struct la_obj_t + { +@@ -115,8 +130,10 @@ do_test (int argc, char *argv[]) + TEST_VERIFY (out != NULL); + char *buffer = NULL; + size_t buffer_length = 0; ++ unsigned int line = 0; + while (xgetline (&buffer, &buffer_length, out)) + { ++ ++line; + if (startswith (buffer, "la_activity: ")) + { + uintptr_t cookie; +@@ -174,8 +191,8 @@ do_test (int argc, char *argv[]) + if (is_vdso (lname)) + continue; + if (nobjs == max_objs) +- FAIL_EXIT1 ("non expected la_objopen: %s %"PRIxPTR" %ld", +- lname, laddr, lmid); ++ FAIL_EXIT1 ("(line %u) non expected la_objopen: %s %"PRIxPTR" %ld", ++ line, lname, laddr, lmid); + objs[nobjs].lname = lname; + objs[nobjs].laddr = laddr; + objs[nobjs].lmid = lmid; diff --git a/glibc-upstream-2.39-241.patch b/glibc-upstream-2.39-241.patch new file mode 100644 index 0000000..ecdd6c9 --- /dev/null +++ b/glibc-upstream-2.39-241.patch @@ -0,0 +1,35 @@ +commit fef226255dda886d74dc72c5e43dbdde231cc74e +Author: Florian Weimer +Date: Fri Nov 29 15:36:40 2024 +0100 + + elf: Add the endswith function to + + And include for a definition of bool. + + Reviewed-by: Adhemerval Zanella + (cherry picked from commit a20bc2f6233a726c7df8eaa332b6e498bd59321f) + +diff --git a/elf/endswith.h b/elf/endswith.h +index c6430c48be0c1071..3954e57f8eff0faa 100644 +--- a/elf/endswith.h ++++ b/elf/endswith.h +@@ -17,6 +17,7 @@ + #ifndef _ENDSWITH_H + #define _ENDSWITH_H + ++#include + #include + + /* Return true if the N bytes at NAME end with with the characters in +@@ -30,4 +31,11 @@ endswithn (const char *name, size_t n, const char *suffix) + strlen (suffix)) == 0); + } + ++/* Same as endswithn, but uses the entire SUBJECT for matching. */ ++static inline bool ++endswith (const char *subject, const char *suffix) ++{ ++ return endswithn (subject, strlen (subject), suffix); ++} ++ + #endif /* _ENDSWITH_H */ diff --git a/glibc-upstream-2.39-242.patch b/glibc-upstream-2.39-242.patch new file mode 100644 index 0000000..e735d12 --- /dev/null +++ b/glibc-upstream-2.39-242.patch @@ -0,0 +1,132 @@ +commit e27601b385fba1f3598168136021764166b819cf +Author: Florian Weimer +Date: Fri Aug 9 15:31:18 2024 +0200 + + elf: Signal la_objopen for the proxy link map in dlmopen (bug 31985) + + Previously, the ld.so link map was silently added to the namespace. + This change produces an auditing event for it. + + Reviewed-by: Adhemerval Zanella + (cherry picked from commit 8f36b1469677afe37168f9af1b77402d7a70c673) + +diff --git a/elf/dl-load.c b/elf/dl-load.c +index ce8fdea3024359b0..75a7187c649e0202 100644 +--- a/elf/dl-load.c ++++ b/elf/dl-load.c +@@ -929,6 +929,37 @@ _dl_process_pt_gnu_property (struct link_map *l, int fd, const ElfW(Phdr) *ph) + } + } + ++static void ++_dl_notify_new_object (int mode, Lmid_t nsid, struct link_map *l) ++{ ++ /* Signal that we are going to add new objects. */ ++ struct r_debug *r = _dl_debug_update (nsid); ++ if (r->r_state == RT_CONSISTENT) ++ { ++#ifdef SHARED ++ /* Auditing checkpoint: we are going to add new objects. Since this ++ is called after _dl_add_to_namespace_list the namespace is guaranteed ++ to not be empty. */ ++ if ((mode & __RTLD_AUDIT) == 0) ++ _dl_audit_activity_nsid (nsid, LA_ACT_ADD); ++#endif ++ ++ /* Notify the debugger we have added some objects. We need to ++ call _dl_debug_initialize in a static program in case dynamic ++ linking has not been used before. */ ++ r->r_state = RT_ADD; ++ _dl_debug_state (); ++ LIBC_PROBE (map_start, 2, nsid, r); ++ } ++ else ++ assert (r->r_state == RT_ADD); ++ ++#ifdef SHARED ++ /* Auditing checkpoint: we have a new object. */ ++ if (!GL(dl_ns)[l->l_ns]._ns_loaded->l_auditing) ++ _dl_audit_objopen (l, nsid); ++#endif ++} + + /* Map in the shared object NAME, actually located in REALNAME, and already + opened on FD. */ +@@ -1029,6 +1060,8 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd, + /* Add the map for the mirrored object to the object list. */ + _dl_add_to_namespace_list (l, nsid); + ++ _dl_notify_new_object (mode, nsid, l); ++ + return l; + } + #endif +@@ -1487,33 +1520,7 @@ cannot enable executable stack as shared object requires"); + if (mode & __RTLD_SPROF) + return l; + +- /* Signal that we are going to add new objects. */ +- struct r_debug *r = _dl_debug_update (nsid); +- if (r->r_state == RT_CONSISTENT) +- { +-#ifdef SHARED +- /* Auditing checkpoint: we are going to add new objects. Since this +- is called after _dl_add_to_namespace_list the namespace is guaranteed +- to not be empty. */ +- if ((mode & __RTLD_AUDIT) == 0) +- _dl_audit_activity_nsid (nsid, LA_ACT_ADD); +-#endif +- +- /* Notify the debugger we have added some objects. We need to +- call _dl_debug_initialize in a static program in case dynamic +- linking has not been used before. */ +- r->r_state = RT_ADD; +- _dl_debug_state (); +- LIBC_PROBE (map_start, 2, nsid, r); +- } +- else +- assert (r->r_state == RT_ADD); +- +-#ifdef SHARED +- /* Auditing checkpoint: we have a new object. */ +- if (!GL(dl_ns)[l->l_ns]._ns_loaded->l_auditing) +- _dl_audit_objopen (l, nsid); +-#endif ++ _dl_notify_new_object (mode, nsid, l); + + return l; + } +diff --git a/elf/tst-audit23.c b/elf/tst-audit23.c +index dada6bb1f8dabab5..32759f956a4b3c58 100644 +--- a/elf/tst-audit23.c ++++ b/elf/tst-audit23.c +@@ -17,6 +17,7 @@ + . */ + + #include ++#include + #include + #include + #include +@@ -106,8 +107,9 @@ do_test (int argc, char *argv[]) + 4. libgcc_s.so (one some architectures, for libsupport) + 5. tst-audit23mod.so + 6. libc.so (LM_ID_NEWLM). ++ 7. loader (proxy link map in new namespace) + vdso (optional and ignored). */ +- enum { max_objs = 6 }; ++ enum { max_objs = 7 }; + struct la_obj_t + { + char *lname; +@@ -236,7 +238,9 @@ do_test (int argc, char *argv[]) + + for (size_t i = 0; i < nobjs; i++) + { +- TEST_COMPARE (objs[i].closed, true); ++ /* This subtest currently does not pass because of bug 32065. */ ++ if (! (endswith (objs[i].lname, LD_SO) && objs[i].lmid != LM_ID_BASE)) ++ TEST_COMPARE (objs[i].closed, true); + free (objs[i].lname); + } + diff --git a/glibc-upstream-2.39-243.patch b/glibc-upstream-2.39-243.patch new file mode 100644 index 0000000..277509b --- /dev/null +++ b/glibc-upstream-2.39-243.patch @@ -0,0 +1,77 @@ +commit f407a14ff7788cb6158d91d2cd9850f218e796d3 +Author: Florian Weimer +Date: Fri Aug 9 16:06:40 2024 +0200 + + elf: Call la_objclose for proxy link maps in _dl_fini (bug 32065) + + Reviewed-by: Adhemerval Zanella + (cherry picked from commit c4b160744cb39eca20dc36b39c7fa6e10352706c) + +diff --git a/elf/dl-fini.c b/elf/dl-fini.c +index db996270de65e86a..a1a4c25829471510 100644 +--- a/elf/dl-fini.c ++++ b/elf/dl-fini.c +@@ -69,6 +69,7 @@ _dl_fini (void) + + unsigned int i; + struct link_map *l; ++ struct link_map *proxy_link_map = NULL; + assert (nloaded != 0 || GL(dl_ns)[ns]._ns_loaded == NULL); + for (l = GL(dl_ns)[ns]._ns_loaded, i = 0; l != NULL; l = l->l_next) + /* Do not handle ld.so in secondary namespaces. */ +@@ -84,6 +85,11 @@ _dl_fini (void) + are not dlclose()ed from underneath us. */ + ++l->l_direct_opencount; + } ++ else ++ /* Used below to call la_objclose for the ld.so proxy ++ link map. */ ++ proxy_link_map = l; ++ + assert (ns != LM_ID_BASE || i == nloaded); + assert (ns == LM_ID_BASE || i == nloaded || i == nloaded - 1); + unsigned int nmaps = i; +@@ -122,6 +128,9 @@ _dl_fini (void) + --l->l_direct_opencount; + } + ++ if (proxy_link_map != NULL) ++ _dl_audit_objclose (proxy_link_map); ++ + #ifdef SHARED + _dl_audit_activity_nsid (ns, LA_ACT_CONSISTENT); + #endif +diff --git a/elf/tst-audit23.c b/elf/tst-audit23.c +index 32759f956a4b3c58..78b4ee384cfb0fe9 100644 +--- a/elf/tst-audit23.c ++++ b/elf/tst-audit23.c +@@ -236,13 +236,26 @@ do_test (int argc, char *argv[]) + } + } + ++ Lmid_t lmid_other = LM_ID_NEWLM; ++ unsigned int other_namespace_count = 0; + for (size_t i = 0; i < nobjs; i++) + { +- /* This subtest currently does not pass because of bug 32065. */ +- if (! (endswith (objs[i].lname, LD_SO) && objs[i].lmid != LM_ID_BASE)) +- TEST_COMPARE (objs[i].closed, true); ++ if (objs[i].lmid != LM_ID_BASE) ++ { ++ if (lmid_other == LM_ID_NEWLM) ++ lmid_other = objs[i].lmid; ++ TEST_COMPARE (objs[i].lmid, lmid_other); ++ ++other_namespace_count; ++ if (!(endswith (objs[i].lname, "/" LIBC_SO) ++ || endswith (objs[i].lname, "/" LD_SO))) ++ FAIL ("unexpected object in secondary namespace: %s", ++ objs[i].lname); ++ } ++ TEST_COMPARE (objs[i].closed, true); + free (objs[i].lname); + } ++ /* Both libc.so and ld.so should be present. */ ++ TEST_COMPARE (other_namespace_count, 2); + + /* la_activity(LA_ACT_CONSISTENT) should be the last callback received. + Since only one link map may be not-CONSISTENT at a time, this also diff --git a/glibc-upstream-2.39-244.patch b/glibc-upstream-2.39-244.patch new file mode 100644 index 0000000..8bae168 --- /dev/null +++ b/glibc-upstream-2.39-244.patch @@ -0,0 +1,141 @@ +commit 4c9b1877fde6535efb8bd3ba1888d1ef82c9a663 +Author: Florian Weimer +Date: Tue Sep 3 17:57:46 2024 +0200 + + elf: Reorder audit events in dlcose to match _dl_fini (bug 32066) + + This was discovered after extending elf/tst-audit23 to cover + dlclose of the dlmopen namespace. + + Auditors already experience the new order during process + shutdown (_dl_fini), so no LAV_CURRENT bump or backwards + compatibility code seems necessary. + + Reviewed-by: Adhemerval Zanella + (cherry picked from commit 495b96e064da605630a23092d1e484ade4bdc093) + +diff --git a/elf/dl-close.c b/elf/dl-close.c +index b6f4daac792b8a90..4c963097f4dc8d79 100644 +--- a/elf/dl-close.c ++++ b/elf/dl-close.c +@@ -264,6 +264,12 @@ _dl_close_worker (struct link_map *map, bool force) + _dl_catch_exception (NULL, _dl_call_fini, imap); + + #ifdef SHARED ++ /* Auditing checkpoint: we will start deleting objects. ++ This is supposed to happen before la_objclose (see _dl_fini), ++ but only once per non-recursive dlclose call. */ ++ if (!unload_any) ++ _dl_audit_activity_nsid (nsid, LA_ACT_DELETE); ++ + /* Auditing checkpoint: we remove an object. */ + _dl_audit_objclose (imap); + #endif +@@ -424,12 +430,8 @@ _dl_close_worker (struct link_map *map, bool force) + if (!unload_any) + goto out; + +-#ifdef SHARED +- /* Auditing checkpoint: we will start deleting objects. */ +- _dl_audit_activity_nsid (nsid, LA_ACT_DELETE); +-#endif +- +- /* Notify the debugger we are about to remove some loaded objects. */ ++ /* Notify the debugger we are about to remove some loaded objects. ++ LA_ACT_DELETE has already been signalled above for !unload_any. */ + struct r_debug *r = _dl_debug_update (nsid); + r->r_state = RT_DELETE; + _dl_debug_state (); +diff --git a/elf/tst-audit23.c b/elf/tst-audit23.c +index 78b4ee384cfb0fe9..1b76336595fcd301 100644 +--- a/elf/tst-audit23.c ++++ b/elf/tst-audit23.c +@@ -31,16 +31,21 @@ + #include + #include + #include ++#include + + static int restart; ++static int do_dlclose; + #define CMDLINE_OPTIONS \ +- { "restart", no_argument, &restart, 1 }, ++ { "restart", no_argument, &restart, 1 }, \ ++ { "dlclose", no_argument, &do_dlclose, 1 }, \ + + static int + handle_restart (void) + { + xdlopen ("tst-audit23mod.so", RTLD_NOW); +- xdlmopen (LM_ID_NEWLM, LIBC_SO, RTLD_NOW); ++ void *handle = xdlmopen (LM_ID_NEWLM, LIBC_SO, RTLD_NOW); ++ if (do_dlclose) ++ xdlclose (handle); + + return 0; + } +@@ -60,8 +65,8 @@ is_vdso (const char *str) + || startswith (str, "linux-vdso"); + } + +-static int +-do_test (int argc, char *argv[]) ++static void ++do_one_test (int argc, char *argv[], bool pass_dlclose_flag) + { + /* We must have either: + - One or four parameters left if called initially: +@@ -69,16 +74,15 @@ do_test (int argc, char *argv[]) + + "--library-path" optional + + the library path optional + + the application name */ +- if (restart) +- return handle_restart (); +- +- char *spargv[9]; ++ char *spargv[10]; + TEST_VERIFY_EXIT (((argc - 1) + 3) < array_length (spargv)); + int i = 0; + for (; i < argc - 1; i++) + spargv[i] = argv[i + 1]; + spargv[i++] = (char *) "--direct"; + spargv[i++] = (char *) "--restart"; ++ if (pass_dlclose_flag) ++ spargv[i++] = (char *) "--dlclose"; + spargv[i] = NULL; + + setenv ("LD_AUDIT", "tst-auditmod23.so", 0); +@@ -146,8 +150,14 @@ do_test (int argc, char *argv[]) + + /* The cookie identifies the object at the head of the link map, + so we only add a new namespace if it changes from the previous +- one. This works since dlmopen is the last in the test body. */ +- if (cookie != last_act_cookie && last_act_cookie != -1) ++ one. This works since dlmopen is the last in the test body. ++ ++ Currently, this does not work as expected because there ++ is no head link map if a namespace is completely deleted. ++ No LA_ACT_CONSISTENT event is generated in that case. ++ See the comment in _dl_audit_activity_nsid and bug 32068. */ ++ if (cookie != last_act_cookie && last_act_cookie != -1 ++ && !pass_dlclose_flag) + TEST_COMPARE (last_act, LA_ACT_CONSISTENT); + + if (this_act == LA_ACT_ADD && acts[nacts] != cookie) +@@ -265,7 +275,16 @@ do_test (int argc, char *argv[]) + + free (buffer); + xfclose (out); ++} ++ ++static int ++do_test (int argc, char *argv[]) ++{ ++ if (restart) ++ return handle_restart (); + ++ do_one_test (argc, argv, false); ++ do_one_test (argc, argv, true); + return 0; + } + diff --git a/glibc-upstream-2.39-245.patch b/glibc-upstream-2.39-245.patch new file mode 100644 index 0000000..79fca89 --- /dev/null +++ b/glibc-upstream-2.39-245.patch @@ -0,0 +1,223 @@ +commit 5f5c411132676d4c5eb171354c51b62baea27493 +Author: Florian Weimer +Date: Tue Jan 7 09:18:07 2025 +0100 + + elf: Second ld.so relocation only if libc.so has been loaded + + Commit 8f8dd904c4a2207699bb666f30acceb5209c8d3f (“elf: + rtld_multiple_ref is always true”) removed some code that happened + to enable compatibility with programs that do not link against + libc.so. Such programs cannot call dlopen or any dynamic linker + functions (except __tls_get_addr), so this is not really useful. + Still ld.so should not crash with a null-pointer dereference + or undefined symbol reference in these cases. + + In the main relocation loop, call _dl_relocate_object unconditionally + because it already checks if the object has been relocated. + + If libc.so was loaded, self-relocate ld.so against it and call + __rtld_mutex_init and __rtld_malloc_init_real to activate the full + implementations. Those are available only if libc.so is there, + so skip these initialization steps if libc.so is absent. Without + libc.so, the global scope can be completely empty. This can cause + ld.so self-relocation to fail because if it uses symbol-based + relocations, which is why the second ld.so self-relocation is not + performed if libc.so is missing. + + The previous concern regarding GOT updates through self-relocation + no longer applies because function pointers are updated + explicitly through __rtld_mutex_init and __rtld_malloc_init_real, + and not through relocation. However, the second ld.so self-relocation + is still delayed, in case there are other symbols being used. + + Fixes commit 8f8dd904c4a2207699bb666f30acceb5209c8d3f (“elf: + rtld_multiple_ref is always true”). + + Reviewed-by: Adhemerval Zanella + (cherry picked from commit 706209867f1ba89c458033408d419e92d8055f58) + +diff --git a/elf/Makefile b/elf/Makefile +index 91fd05c9c0e6084a..59de78a5d45bced4 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -3161,3 +3161,20 @@ tst-rtld-no-malloc-audit-ENV = LD_AUDIT=$(objpfx)tst-auditmod1.so + + # Any shared object should do. + tst-rtld-no-malloc-preload-ENV = LD_PRELOAD=$(objpfx)tst-auditmod1.so ++ ++# These rules link and run the special elf/tst-nolink-libc-* tests if ++# a port adds them to the tests variables. Neither test variant is ++# linked against libc.so, but tst-nolink-libc-1 is linked against ++# ld.so. The test is always run directly, not under the dynamic ++# linker. ++CFLAGS-tst-nolink-libc.c += $(no-stack-protector) ++$(objpfx)tst-nolink-libc-1: $(objpfx)tst-nolink-libc.o $(objpfx)ld.so ++ $(LINK.o) -nostdlib -nostartfiles -o $@ $< \ ++ -Wl,--dynamic-linker=$(objpfx)ld.so,--no-as-needed $(objpfx)ld.so ++$(objpfx)tst-nolink-libc-1.out: $(objpfx)tst-nolink-libc-1 $(objpfx)ld.so ++ $< > $@ 2>&1; $(evaluate-test) ++$(objpfx)tst-nolink-libc-2: $(objpfx)tst-nolink-libc.o ++ $(LINK.o) -nostdlib -nostartfiles -o $@ $< \ ++ -Wl,--dynamic-linker=$(objpfx)ld.so ++$(objpfx)tst-nolink-libc-2.out: $(objpfx)tst-nolink-libc-2 $(objpfx)ld.so ++ $< > $@ 2>&1; $(evaluate-test) +diff --git a/elf/rtld.c b/elf/rtld.c +index ff938186738e8a87..809fc807989b285e 100644 +--- a/elf/rtld.c ++++ b/elf/rtld.c +@@ -2290,25 +2290,25 @@ dl_main (const ElfW(Phdr) *phdr, + + _rtld_main_check (main_map, _dl_argv[0]); + +- /* Now we have all the objects loaded. Relocate them all except for +- the dynamic linker itself. We do this in reverse order so that copy +- relocs of earlier objects overwrite the data written by later +- objects. We do not re-relocate the dynamic linker itself in this +- loop because that could result in the GOT entries for functions we +- call being changed, and that would break us. It is safe to relocate +- the dynamic linker out of order because it has no copy relocations. +- Likewise for libc, which is relocated early to ensure that IFUNC +- resolvers in libc work. */ ++ /* Now we have all the objects loaded. */ + + int consider_profiling = GLRO(dl_profile) != NULL; + + /* If we are profiling we also must do lazy reloaction. */ + GLRO(dl_lazy) |= consider_profiling; + ++ /* If libc.so has been loaded, relocate it early, after the dynamic ++ loader itself. The initial self-relocation of ld.so should be ++ sufficient for IFUNC resolvers in libc.so. */ + if (GL(dl_ns)[LM_ID_BASE].libc_map != NULL) +- _dl_relocate_object (GL(dl_ns)[LM_ID_BASE].libc_map, +- GL(dl_ns)[LM_ID_BASE].libc_map->l_scope, +- GLRO(dl_lazy) ? RTLD_LAZY : 0, consider_profiling); ++ { ++ RTLD_TIMING_VAR (start); ++ rtld_timer_start (&start); ++ _dl_relocate_object (GL(dl_ns)[LM_ID_BASE].libc_map, ++ GL(dl_ns)[LM_ID_BASE].libc_map->l_scope, ++ GLRO(dl_lazy) ? RTLD_LAZY : 0, consider_profiling); ++ rtld_timer_accum (&relocate_time, start); ++ } + + RTLD_TIMING_VAR (start); + rtld_timer_start (&start); +@@ -2331,9 +2331,8 @@ dl_main (const ElfW(Phdr) *phdr, + /* Also allocated with the fake malloc(). */ + l->l_free_initfini = 0; + +- if (l != &GL(dl_rtld_map)) +- _dl_relocate_object (l, l->l_scope, GLRO(dl_lazy) ? RTLD_LAZY : 0, +- consider_profiling); ++ _dl_relocate_object (l, l->l_scope, GLRO(dl_lazy) ? RTLD_LAZY : 0, ++ consider_profiling); + + /* Add object to slot information data if necessasy. */ + if (l->l_tls_blocksize != 0 && __rtld_tls_init_tp_called) +@@ -2371,27 +2370,22 @@ dl_main (const ElfW(Phdr) *phdr, + /* Set up the object lookup structures. */ + _dl_find_object_init (); + +- /* Likewise for the locking implementation. */ +- __rtld_mutex_init (); +- +- /* Re-relocate ourselves with user-controlled symbol definitions. */ +- +- { +- RTLD_TIMING_VAR (start); +- rtld_timer_start (&start); +- +- _dl_relocate_object_no_relro (&GL(dl_rtld_map), main_map->l_scope, 0, 0); +- +- /* The malloc implementation has been relocated, so resolving +- its symbols (and potentially calling IFUNC resolvers) is safe +- at this point. */ +- __rtld_malloc_init_real (main_map); ++ /* If libc.so was loaded, relocate ld.so against it. Complete ld.so ++ initialization with mutex symbols from libc.so and malloc symbols ++ from the global scope. */ ++ if (GL(dl_ns)[LM_ID_BASE].libc_map != NULL) ++ { ++ RTLD_TIMING_VAR (start); ++ rtld_timer_start (&start); ++ _dl_relocate_object_no_relro (&GL(dl_rtld_map), main_map->l_scope, 0, 0); ++ rtld_timer_accum (&relocate_time, start); + +- if (GL(dl_rtld_map).l_relro_size != 0) +- _dl_protect_relro (&GL(dl_rtld_map)); ++ __rtld_mutex_init (); ++ __rtld_malloc_init_real (main_map); ++ } + +- rtld_timer_accum (&relocate_time, start); +- } ++ /* All ld.so initialization is complete. Apply RELRO. */ ++ _dl_protect_relro (&GL(dl_rtld_map)); + + /* Relocation is complete. Perform early libc initialization. This + is the initial libc, even if audit modules have been loaded with +diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile +index b0daa44b95db3b72..a4b692febb3e87d9 100644 +--- a/sysdeps/unix/sysv/linux/Makefile ++++ b/sysdeps/unix/sysv/linux/Makefile +@@ -657,7 +657,15 @@ install-bin += \ + # install-bin + + $(objpfx)pldd: $(objpfx)xmalloc.o ++ ++test-internal-extras += tst-nolink-libc ++ifeq ($(run-built-tests),yes) ++tests-special += \ ++ $(objpfx)tst-nolink-libc-1.out \ ++ $(objpfx)tst-nolink-libc-2.out \ ++ # tests-special + endif ++endif # $(subdir) == elf + + ifeq ($(subdir),rt) + CFLAGS-mq_send.c += -fexceptions +diff --git a/sysdeps/unix/sysv/linux/arm/Makefile b/sysdeps/unix/sysv/linux/arm/Makefile +index a73c897f43c9a206..e73ce4f81114e789 100644 +--- a/sysdeps/unix/sysv/linux/arm/Makefile ++++ b/sysdeps/unix/sysv/linux/arm/Makefile +@@ -1,5 +1,8 @@ + ifeq ($(subdir),elf) + sysdep-rtld-routines += aeabi_read_tp libc-do-syscall ++# The test uses INTERNAL_SYSCALL_CALL. In thumb mode, this uses ++# an undefined reference to __libc_do_syscall. ++CFLAGS-tst-nolink-libc.c += -marm + endif + + ifeq ($(subdir),misc) +diff --git a/sysdeps/unix/sysv/linux/tst-nolink-libc.c b/sysdeps/unix/sysv/linux/tst-nolink-libc.c +new file mode 100644 +index 0000000000000000..817f37784b4080f9 +--- /dev/null ++++ b/sysdeps/unix/sysv/linux/tst-nolink-libc.c +@@ -0,0 +1,25 @@ ++/* Test program not linked against libc.so and not using any glibc functions. ++ Copyright (C) 2024 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 ++ . */ ++ ++#include ++ ++void ++_start (void) ++{ ++ INTERNAL_SYSCALL_CALL (exit_group, 0); ++} diff --git a/glibc-upstream-2.39-246.patch b/glibc-upstream-2.39-246.patch new file mode 100644 index 0000000..ef0e216 --- /dev/null +++ b/glibc-upstream-2.39-246.patch @@ -0,0 +1,283 @@ +commit 79d84b5da58ee989fdabf34767e1501a4b222194 +Author: Florian Weimer +Date: Fri Mar 7 17:37:50 2025 +0100 + + elf: Fix handling of symbol versions which hash to zero (bug 29190) + + This was found through code inspection. No application impact is + known. + + Reviewed-by: Adhemerval Zanella + (cherry picked from commit 46d31980943d8be2f421c1e3276b265c7552636e) + +diff --git a/elf/Makefile b/elf/Makefile +index 59de78a5d45bced4..10c54be629124a17 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -488,6 +488,7 @@ tests += \ + tst-unique2 \ + tst-unwind-ctor \ + tst-unwind-main \ ++ tst-version-hash-zero \ + unload3 \ + unload4 \ + unload5 \ +@@ -979,6 +980,9 @@ modules-names += \ + tst-unique2mod1 \ + tst-unique2mod2 \ + tst-unwind-ctor-lib \ ++ tst-version-hash-zero-linkmod \ ++ tst-version-hash-zero-mod \ ++ tst-version-hash-zero-refmod \ + unload2dep \ + unload2mod \ + unload3mod1 \ +@@ -3178,3 +3182,20 @@ $(objpfx)tst-nolink-libc-2: $(objpfx)tst-nolink-libc.o + -Wl,--dynamic-linker=$(objpfx)ld.so + $(objpfx)tst-nolink-libc-2.out: $(objpfx)tst-nolink-libc-2 $(objpfx)ld.so + $< > $@ 2>&1; $(evaluate-test) ++ ++$(objpfx)tst-version-hash-zero.out: \ ++ $(objpfx)tst-version-hash-zero-mod.so \ ++ $(objpfx)tst-version-hash-zero-refmod.so ++LDFLAGS-tst-version-hash-zero-mod.so = \ ++ -Wl,--version-script=tst-version-hash-zero-mod.map ++# The run-time test module tst-version-hash-zero-refmod.so is linked ++# to a stub module, tst-version-hash-zero-linkmod.so, to produce an ++# expected relocation error. ++$(objpfx)tst-version-hash-zero-refmod.so: \ ++ $(objpfx)tst-version-hash-zero-linkmod.so ++LDFLAGS-tst-version-hash-zero-linkmod.so = \ ++ -Wl,--version-script=tst-version-hash-zero-linkmod.map \ ++ -Wl,--soname=tst-version-hash-zero-mod.so ++$(objpfx)tst-version-hash-zero-refmod.so: \ ++ $(objpfx)tst-version-hash-zero-linkmod.so ++tst-version-hash-zero-refmod.so-no-z-defs = yes +diff --git a/elf/dl-lookup.c b/elf/dl-lookup.c +index 19ad2a25c5f70326..7a70f1df2d6cf839 100644 +--- a/elf/dl-lookup.c ++++ b/elf/dl-lookup.c +@@ -113,12 +113,22 @@ check_match (const char *const undef_name, + /* We can match the version information or use the + default one if it is not hidden. */ + ElfW(Half) ndx = verstab[symidx] & 0x7fff; +- if ((map->l_versions[ndx].hash != version->hash +- || strcmp (map->l_versions[ndx].name, version->name)) +- && (version->hidden || map->l_versions[ndx].hash +- || (verstab[symidx] & 0x8000))) +- /* It's not the version we want. */ +- return NULL; ++ if (map->l_versions[ndx].hash == version->hash ++ && strcmp (map->l_versions[ndx].name, version->name) == 0) ++ /* This is an exact version match. Return the symbol below. */ ++ ; ++ else ++ { ++ if (!version->hidden ++ && map->l_versions[ndx].name[0] == '\0' ++ && (verstab[symidx] & 0x8000) == 0 ++ && (*num_versions)++ == 0) ++ /* This is the global default version. Store it as a ++ fallback match. */ ++ *versioned_sym = sym; ++ ++ return NULL; ++ } + } + } + else +diff --git a/elf/dl-version.c b/elf/dl-version.c +index 8966d612cc79f0f1..708b1c94ea47d147 100644 +--- a/elf/dl-version.c ++++ b/elf/dl-version.c +@@ -357,6 +357,13 @@ _dl_check_map_versions (struct link_map *map, int verbose, int trace_mode) + ent = (ElfW(Verdef) *) ((char *) ent + ent->vd_next); + } + } ++ ++ /* The empty string has ELF hash zero. This avoids a NULL check ++ before the version string comparison in check_match in ++ dl-lookup.c. */ ++ for (unsigned int i = 0; i < map->l_nversions; ++i) ++ if (map->l_versions[i].name == NULL) ++ map->l_versions[i].name = ""; + } + + /* When there is a DT_VERNEED entry with libc.so on DT_NEEDED, issue +diff --git a/elf/tst-version-hash-zero-linkmod.c b/elf/tst-version-hash-zero-linkmod.c +new file mode 100644 +index 0000000000000000..15e2506d0111bc7e +--- /dev/null ++++ b/elf/tst-version-hash-zero-linkmod.c +@@ -0,0 +1,22 @@ ++/* Stub module for linking tst-version-hash-zero-refmod.so. ++ Copyright (C) 2025 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; see the file COPYING.LIB. If ++ not, see . */ ++ ++/* The version script assigns a different symbol version for the stub ++ module. Loading the module with the incorrect version is expected ++ to fail. */ ++#include "tst-version-hash-zero-mod.c" +diff --git a/elf/tst-version-hash-zero-linkmod.map b/elf/tst-version-hash-zero-linkmod.map +new file mode 100644 +index 0000000000000000..2dba7c22d7ea7d09 +--- /dev/null ++++ b/elf/tst-version-hash-zero-linkmod.map +@@ -0,0 +1,7 @@ ++Base { ++ local: *; ++}; ++ ++OTHER_VERSION { ++ global: global_variable; ++} Base; +diff --git a/elf/tst-version-hash-zero-mod.c b/elf/tst-version-hash-zero-mod.c +new file mode 100644 +index 0000000000000000..ac6b0dc4a57b5775 +--- /dev/null ++++ b/elf/tst-version-hash-zero-mod.c +@@ -0,0 +1,20 @@ ++/* Test module with a zero version symbol hash. ++ Copyright (C) 2025 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; see the file COPYING.LIB. If ++ not, see . */ ++ ++/* The symbol version is assigned by version script. */ ++int global_variable; +diff --git a/elf/tst-version-hash-zero-mod.map b/elf/tst-version-hash-zero-mod.map +new file mode 100644 +index 0000000000000000..41eaff79147a8fcd +--- /dev/null ++++ b/elf/tst-version-hash-zero-mod.map +@@ -0,0 +1,13 @@ ++Base { ++ local: *; ++}; ++ ++/* Define the version so that tst-version-hash-zero-refmod.so passes ++ the initial symbol version check. */ ++OTHER_VERSION { ++} Base; ++ ++/* This version string hashes to zero. */ ++PPPPPPPPPPPP { ++ global: global_variable; ++} Base; +diff --git a/elf/tst-version-hash-zero-refmod.c b/elf/tst-version-hash-zero-refmod.c +new file mode 100644 +index 0000000000000000..cd8b3dcef5b82012 +--- /dev/null ++++ b/elf/tst-version-hash-zero-refmod.c +@@ -0,0 +1,23 @@ ++/* Test module that triggers a relocation failure in tst-version-hash-zero. ++ Copyright (C) 2025 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; see the file COPYING.LIB. If ++ not, see . */ ++ ++/* This is bound to global_variable@@OTHER_VERSION via ++ tst-version-hash-zero-linkmod.so, but at run time, only ++ global_variable@PPPPPPPPPPPP exists. */ ++extern int global_variable; ++int *pointer_variable = &global_variable; +diff --git a/elf/tst-version-hash-zero.c b/elf/tst-version-hash-zero.c +new file mode 100644 +index 0000000000000000..66a0db4f51fa0e10 +--- /dev/null ++++ b/elf/tst-version-hash-zero.c +@@ -0,0 +1,56 @@ ++/* Symbols with version hash zero should not match any version (bug 29190). ++ Copyright (C) 2025 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; see the file COPYING.LIB. If ++ not, see . */ ++ ++#include ++#include ++#include ++#include ++ ++static int ++do_test (void) ++{ ++ void *handle = xdlopen ("tst-version-hash-zero-mod.so", RTLD_NOW); ++ ++ /* This used to crash because some struct r_found_version entries ++ with hash zero did not have valid version strings. */ ++ TEST_VERIFY (xdlvsym (handle, "global_variable", "PPPPPPPPPPPP") != NULL); ++ ++ /* Consistency check. */ ++ TEST_VERIFY (xdlsym (handle, "global_variable") ++ == xdlvsym (handle, "global_variable", "PPPPPPPPPPPP")); ++ ++ /* This symbol version is supposed to be missing. */ ++ TEST_VERIFY (dlvsym (handle, "global_variable", "OTHER_VERSION") == NULL); ++ ++ /* tst-version-hash-zero-refmod.so references ++ global_variable@@OTHER_VERSION and is expected to fail to load. ++ dlvsym sets the hidden flag during lookup. Relocation does not, ++ so this exercises a different failure case. */ ++ TEST_VERIFY_EXIT (dlopen ("tst-version-hash-zero-refmod.so", RTLD_NOW) ++ == NULL); ++ const char *message = dlerror (); ++ if (strstr (message, ++ ": undefined symbol: global_variable, version OTHER_VERSION") ++ == NULL) ++ FAIL_EXIT1 ("unexpected dlopen failure: %s", message); ++ ++ xdlclose (handle); ++ return 0; ++} ++ ++#include diff --git a/glibc-upstream-2.39-247.patch b/glibc-upstream-2.39-247.patch new file mode 100644 index 0000000..c179dc4 --- /dev/null +++ b/glibc-upstream-2.39-247.patch @@ -0,0 +1,217 @@ +commit 24c94ea84e9323dc24ce11f34368531f75eb9a72 +Author: Florian Weimer +Date: Tue Mar 11 15:30:52 2025 +0100 + + elf: Test dlopen (NULL, RTLD_LAZY) from an ELF constructor + + This call must not complete initialization of all shared objects + in the global scope because the ELF constructor which makes the call + likely has not finished initialization. Calling more constructors + at this point would expose those to a partially constructed + dependency. + + This completes the revert of commit 9897ced8e78db5d813166a7ccccfd5a + ("elf: Run constructors on cyclic recursive dlopen (bug 31986)"). + + (cherry picked from commit d604f9c500570e80febfcc6a52b63a002b466f35) + +diff --git a/elf/Makefile b/elf/Makefile +index 10c54be629124a17..a102373793fd16bd 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -415,6 +415,7 @@ tests += \ + tst-dlmopen3 \ + tst-dlmopen4 \ + tst-dlopen-auditdup \ ++ tst-dlopen-constructor-null \ + tst-dlopen-self \ + tst-dlopen-tlsmodid \ + tst-dlopen-tlsreinit1 \ +@@ -865,6 +866,8 @@ modules-names += \ + tst-dlmopen1mod \ + tst-dlopen-auditdup-auditmod \ + tst-dlopen-auditdupmod \ ++ tst-dlopen-constructor-null-mod1 \ ++ tst-dlopen-constructor-null-mod2 \ + tst-dlopen-sgid-mod \ + tst-dlopen-tlsreinitmod1 \ + tst-dlopen-tlsreinitmod2 \ +@@ -3199,3 +3202,9 @@ LDFLAGS-tst-version-hash-zero-linkmod.so = \ + $(objpfx)tst-version-hash-zero-refmod.so: \ + $(objpfx)tst-version-hash-zero-linkmod.so + tst-version-hash-zero-refmod.so-no-z-defs = yes ++ ++$(objpfx)tst-dlopen-constructor-null: \ ++ $(objpfx)tst-dlopen-constructor-null-mod1.so \ ++ $(objpfx)tst-dlopen-constructor-null-mod2.so ++$(objpfx)tst-dlopen-constructor-null-mod2.so: \ ++ $(objpfx)tst-dlopen-constructor-null-mod1.so +diff --git a/elf/dl-open.c b/elf/dl-open.c +index b00f283c42d19adb..80f084d5c838fc1c 100644 +--- a/elf/dl-open.c ++++ b/elf/dl-open.c +@@ -605,6 +605,16 @@ dl_open_worker_begin (void *a) + if ((mode & RTLD_GLOBAL) && new->l_global == 0) + add_to_global_update (new); + ++ /* It is not possible to run the ELF constructor for the new ++ link map if it has not executed yet: If this dlopen call came ++ from an ELF constructor that has not put that object into a ++ consistent state, completing initialization for the entire ++ scope will expose objects that have this partially ++ constructed object among its dependencies to this ++ inconsistent state. This could happen even with a benign ++ dlopen (NULL, RTLD_LAZY) call from a constructor of an ++ initially loaded shared object. */ ++ + return; + } + +diff --git a/elf/tst-dlopen-constructor-null-mod1.c b/elf/tst-dlopen-constructor-null-mod1.c +new file mode 100644 +index 0000000000000000..70a7a0ad46a1a666 +--- /dev/null ++++ b/elf/tst-dlopen-constructor-null-mod1.c +@@ -0,0 +1,55 @@ ++/* Module calling dlopen (NULL, RTLD_LAZY) to obtain the global scope. ++ Copyright (C) 2024 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++ ++int mod1_status; ++ ++static void __attribute__ ((constructor)) ++init (void) ++{ ++ puts ("info: tst-dlopen-constructor-null-mod1.so constructor"); ++ ++ void *handle = dlopen (NULL, RTLD_LAZY); ++ if (handle == NULL) ++ { ++ printf ("error: %s\n", dlerror ()); ++ exit (1); ++ } ++ puts ("info: dlopen returned"); ++ if (dlsym (handle, "malloc") != malloc) ++ { ++ puts ("error: dlsym did not produce expected result"); ++ exit (1); ++ } ++ dlclose (handle); ++ ++ /* Check that the second module's constructor has not executed. */ ++ if (getenv ("mod2_status") != NULL) ++ { ++ printf ("error: mod2_status environment variable set: %s\n", ++ getenv ("mod2_status")); ++ exit (1); ++ } ++ ++ /* Communicate to the second module that the constructor executed. */ ++ mod1_status = 1; ++} +diff --git a/elf/tst-dlopen-constructor-null-mod2.c b/elf/tst-dlopen-constructor-null-mod2.c +new file mode 100644 +index 0000000000000000..d6e945beaec04815 +--- /dev/null ++++ b/elf/tst-dlopen-constructor-null-mod2.c +@@ -0,0 +1,37 @@ ++/* Module whose constructor should not be invoked by dlopen (NULL, RTLD_LAZY). ++ Copyright (C) 2024 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 ++ . */ ++ ++#include ++#include ++ ++extern int mod1_status; ++int mod2_status; ++ ++static void __attribute__ ((constructor)) ++init (void) ++{ ++ printf ("info: tst-dlopen-constructor-null-mod2.so constructor" ++ " (mod1_status=%d)", mod1_status); ++ if (!(mod1_status == 1 && mod2_status == 0)) ++ { ++ puts ("error: mod1_status == 1 && mod2_status == 0 expected"); ++ exit (1); ++ } ++ setenv ("mod2_status", "constructed", 1); ++ mod2_status = 1; ++} +diff --git a/elf/tst-dlopen-constructor-null.c b/elf/tst-dlopen-constructor-null.c +new file mode 100644 +index 0000000000000000..db90643325c5235f +--- /dev/null ++++ b/elf/tst-dlopen-constructor-null.c +@@ -0,0 +1,38 @@ ++/* Verify that dlopen (NULL, RTLD_LAZY) does not complete initialization. ++ Copyright (C) 2024 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 ++ . */ ++ ++/* This test mimics what the glvndSetupPthreads function in libglvnd ++ does. */ ++ ++#include ++#include ++ ++/* Defined and initialized in the shared objects. */ ++extern int mod1_status; ++extern int mod2_status; ++ ++static int ++do_test (void) ++{ ++ TEST_COMPARE (mod1_status, 1); ++ TEST_COMPARE (mod2_status, 1); ++ TEST_COMPARE_STRING (getenv ("mod2_status"), "constructed"); ++ return 0; ++} ++ ++#include diff --git a/glibc-upstream-2.39-248.patch b/glibc-upstream-2.39-248.patch new file mode 100644 index 0000000..b270bf2 --- /dev/null +++ b/glibc-upstream-2.39-248.patch @@ -0,0 +1,159 @@ +commit 5601ad79b75f03db3e30fc3358e63c1122985f95 +Author: Florian Weimer +Date: Fri Jul 4 21:46:05 2025 +0200 + + elf: Introduce separate _r_debug_array variable + + It replaces the ns_debug member of the namespaces. Previously, + the base namespace had an unused ns_debug member. + + This change also fixes a concurrency issue: Now _dl_debug_initialize + only updates r_next of the previous namespace's r_debug after the new + r_debug is initialized, so that only the initialized version is + observed. (Client code accessing _r_debug will benefit from load + dependency tracking in CPUs even without explicit barriers.) + + Reviewed-by: H.J. Lu + (cherry picked from commit 7278d11f3a0cd528188c719bab75575b0aea2c6e) + +diff --git a/elf/dl-debug.c b/elf/dl-debug.c +index ef56de7a29565652..5c49fa847e91bd81 100644 +--- a/elf/dl-debug.c ++++ b/elf/dl-debug.c +@@ -30,17 +30,37 @@ extern const int verify_link_map_members[(VERIFY_MEMBER (l_addr) + && VERIFY_MEMBER (l_prev)) + ? 1 : -1]; + ++#ifdef SHARED ++/* r_debug structs for secondary namespaces. The first namespace is ++ handled separately because its r_debug structure must overlap with ++ the public _r_debug symbol, so the first array element corresponds ++ to LM_ID_BASE + 1. See elf/dl-debug-symbols.S. */ ++struct r_debug_extended _r_debug_array[DL_NNS - 1]; ++ ++/* Return the r_debug object for the namespace NS. */ ++static inline struct r_debug_extended * ++get_rdebug (Lmid_t ns) ++{ ++ if (ns == LM_ID_BASE) ++ return &_r_debug_extended; ++ else ++ return &_r_debug_array[ns - 1]; ++} ++#else /* !SHARED */ ++static inline struct r_debug_extended * ++get_rdebug (Lmid_t ns) ++{ ++ return &_r_debug_extended; /* There is just one namespace. */ ++} ++#endif /* !SHARED */ ++ + /* Update the `r_map' member and return the address of `struct r_debug' + of the namespace NS. */ + + struct r_debug * + _dl_debug_update (Lmid_t ns) + { +- struct r_debug_extended *r; +- if (ns == LM_ID_BASE) +- r = &_r_debug_extended; +- else +- r = &GL(dl_ns)[ns]._ns_debug; ++ struct r_debug_extended *r = get_rdebug (ns); + if (r->base.r_map == NULL) + atomic_store_release (&r->base.r_map, + (void *) GL(dl_ns)[ns]._ns_loaded); +@@ -54,34 +74,7 @@ _dl_debug_update (Lmid_t ns) + struct r_debug * + _dl_debug_initialize (ElfW(Addr) ldbase, Lmid_t ns) + { +- struct r_debug_extended *r, **pp = NULL; +- +- if (ns == LM_ID_BASE) +- { +- r = &_r_debug_extended; +- /* Initialize r_version to 1. */ +- if (_r_debug_extended.base.r_version == 0) +- _r_debug_extended.base.r_version = 1; +- } +- else if (DL_NNS > 1) +- { +- r = &GL(dl_ns)[ns]._ns_debug; +- if (r->base.r_brk == 0) +- { +- /* Add the new namespace to the linked list. After a namespace +- is initialized, r_brk becomes non-zero. A namespace becomes +- empty (r_map == NULL) when it is unused. But it is never +- removed from the linked list. */ +- struct r_debug_extended *p; +- for (pp = &_r_debug_extended.r_next; +- (p = *pp) != NULL; +- pp = &p->r_next) +- ; +- +- r->base.r_version = 2; +- } +- } +- ++ struct r_debug_extended *r = get_rdebug (ns); + if (r->base.r_brk == 0) + { + /* Tell the debugger where to find the map of loaded objects. +@@ -89,20 +82,36 @@ _dl_debug_initialize (ElfW(Addr) ldbase, Lmid_t ns) + only once. */ + r->base.r_ldbase = ldbase ?: _r_debug_extended.base.r_ldbase; + r->base.r_brk = (ElfW(Addr)) &_dl_debug_state; +- r->r_next = NULL; ++ ++#ifdef SHARED ++ /* Add the new namespace to the linked list. This assumes that ++ namespaces are allocated in increasing order. After a ++ namespace is initialized, r_brk becomes non-zero. A ++ namespace becomes empty (r_map == NULL) when it is unused. ++ But it is never removed from the linked list. */ ++ ++ if (ns != LM_ID_BASE) ++ { ++ r->base.r_version = 2; ++ if (ns - 1 == LM_ID_BASE) ++ { ++ atomic_store_release (&_r_debug_extended.r_next, r); ++ /* Now there are multiple namespaces. */ ++ atomic_store_release (&_r_debug_extended.base.r_version, 2); ++ } ++ else ++ /* Update r_debug_extended of the previous namespace. */ ++ atomic_store_release (&_r_debug_array[ns - 2].r_next, r); ++ } ++ else ++#endif /* SHARED */ ++ r->base.r_version = 1; + } + + if (r->base.r_map == NULL) + atomic_store_release (&r->base.r_map, + (void *) GL(dl_ns)[ns]._ns_loaded); + +- if (pp != NULL) +- { +- atomic_store_release (pp, r); +- /* Bump r_version to 2 for the new namespace. */ +- atomic_store_release (&_r_debug_extended.base.r_version, 2); +- } +- + return &r->base; + } + +diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h +index 91447a5e77c2466d..8b9ae3783056a29f 100644 +--- a/sysdeps/generic/ldsodefs.h ++++ b/sysdeps/generic/ldsodefs.h +@@ -350,8 +350,6 @@ struct rtld_global + size_t n_elements; + void (*free) (void *); + } _ns_unique_sym_table; +- /* Keep track of changes to each namespace' list. */ +- struct r_debug_extended _ns_debug; + } _dl_ns[DL_NNS]; + /* One higher than index of last used namespace. */ + EXTERN size_t _dl_nns; diff --git a/glibc-upstream-2.39-249.patch b/glibc-upstream-2.39-249.patch new file mode 100644 index 0000000..fdfb7a2 --- /dev/null +++ b/glibc-upstream-2.39-249.patch @@ -0,0 +1,149 @@ +commit 97017da5ef946c6d38c252f56c8cb7c205b732fa +Author: Florian Weimer +Date: Fri Jul 4 21:46:16 2025 +0200 + + elf: Introduce _dl_debug_change_state + + It combines updating r_state with the debugger notification. + + The second change to _dl_open introduces an additional debugger + notification for dlmopen, but debuggers are expected to ignore it. + + Reviewed-by: H.J. Lu + (cherry picked from commit 8329939a37f483a16013dd8af8303cbcb86d92cb) + +diff --git a/elf/dl-close.c b/elf/dl-close.c +index 4c963097f4dc8d79..fb27a1231c1c5b66 100644 +--- a/elf/dl-close.c ++++ b/elf/dl-close.c +@@ -433,8 +433,7 @@ _dl_close_worker (struct link_map *map, bool force) + /* Notify the debugger we are about to remove some loaded objects. + LA_ACT_DELETE has already been signalled above for !unload_any. */ + struct r_debug *r = _dl_debug_update (nsid); +- r->r_state = RT_DELETE; +- _dl_debug_state (); ++ _dl_debug_change_state (r, RT_DELETE); + LIBC_PROBE (unmap_start, 2, nsid, r); + + if (unload_global) +@@ -726,8 +725,7 @@ _dl_close_worker (struct link_map *map, bool force) + __rtld_lock_unlock_recursive (GL(dl_load_tls_lock)); + + /* Notify the debugger those objects are finalized and gone. */ +- r->r_state = RT_CONSISTENT; +- _dl_debug_state (); ++ _dl_debug_change_state (r, RT_CONSISTENT); + LIBC_PROBE (unmap_complete, 2, nsid, r); + + #ifdef SHARED +diff --git a/elf/dl-debug.c b/elf/dl-debug.c +index 5c49fa847e91bd81..b3777ffc136469cf 100644 +--- a/elf/dl-debug.c ++++ b/elf/dl-debug.c +@@ -67,6 +67,13 @@ _dl_debug_update (Lmid_t ns) + return &r->base; + } + ++void ++_dl_debug_change_state (struct r_debug *r, int state) ++{ ++ atomic_store_release (&r->r_state, state); ++ _dl_debug_state (); ++} ++ + /* Initialize _r_debug_extended for the namespace NS. LDBASE is the + run-time load address of the dynamic linker, to be put in + _r_debug_extended.r_ldbase. Return the address of _r_debug. */ +diff --git a/elf/dl-load.c b/elf/dl-load.c +index 75a7187c649e0202..8b0890499d66f67a 100644 +--- a/elf/dl-load.c ++++ b/elf/dl-load.c +@@ -947,8 +947,7 @@ _dl_notify_new_object (int mode, Lmid_t nsid, struct link_map *l) + /* Notify the debugger we have added some objects. We need to + call _dl_debug_initialize in a static program in case dynamic + linking has not been used before. */ +- r->r_state = RT_ADD; +- _dl_debug_state (); ++ _dl_debug_change_state (r, RT_ADD); + LIBC_PROBE (map_start, 2, nsid, r); + } + else +diff --git a/elf/dl-open.c b/elf/dl-open.c +index 80f084d5c838fc1c..6f6d3ddbf94c764c 100644 +--- a/elf/dl-open.c ++++ b/elf/dl-open.c +@@ -792,8 +792,7 @@ dl_open_worker (void *a) + #ifdef SHARED + bool was_not_consistent = r->r_state != RT_CONSISTENT; + #endif +- r->r_state = RT_CONSISTENT; +- _dl_debug_state (); ++ _dl_debug_change_state (r, RT_CONSISTENT); + LIBC_PROBE (map_complete, 3, nsid, r, args->map); + + #ifdef SHARED +@@ -871,7 +870,7 @@ no more namespaces available for dlmopen()")); + } + + GL(dl_ns)[nsid].libc_map = NULL; +- _dl_debug_update (nsid)->r_state = RT_CONSISTENT; ++ _dl_debug_change_state (_dl_debug_update (nsid), RT_CONSISTENT); + } + /* Never allow loading a DSO in a namespace which is empty. Such + direct placements is only causing problems. Also don't allow +diff --git a/elf/rtld.c b/elf/rtld.c +index 809fc807989b285e..43bfc7378afc6cc7 100644 +--- a/elf/rtld.c ++++ b/elf/rtld.c +@@ -1850,8 +1850,7 @@ dl_main (const ElfW(Phdr) *phdr, + elf_setup_debug_entry (main_map, r); + + /* We start adding objects. */ +- r->r_state = RT_ADD; +- _dl_debug_state (); ++ _dl_debug_change_state (r, RT_ADD); + LIBC_PROBE (init_start, 2, LM_ID_BASE, r); + + /* Auditing checkpoint: we are ready to signal that the initial map +@@ -2402,8 +2401,7 @@ dl_main (const ElfW(Phdr) *phdr, + /* Notify the debugger all new objects are now ready to go. We must re-get + the address since by now the variable might be in another object. */ + r = _dl_debug_update (LM_ID_BASE); +- r->r_state = RT_CONSISTENT; +- _dl_debug_state (); ++ _dl_debug_change_state (r, RT_CONSISTENT); + LIBC_PROBE (init_complete, 2, LM_ID_BASE, r); + + /* Auditing checkpoint: we have added all objects. */ +diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h +index 8b9ae3783056a29f..017406e7fa93c941 100644 +--- a/sysdeps/generic/ldsodefs.h ++++ b/sysdeps/generic/ldsodefs.h +@@ -1067,8 +1067,14 @@ extern void _dl_debug_state (void); + rtld_hidden_proto (_dl_debug_state) + + /* Initialize `struct r_debug_extended' for the namespace NS. LDBASE +- is the run-time load address of the dynamic linker, to be put in the +- `r_ldbase' member. Return the address of the structure. */ ++ is the run-time load address of the dynamic linker, to be put in ++ the `r_ldbase' member. ++ ++ Return the address of the r_debug structure for the namespace. ++ This is not merely a convenience or optimization, but it is ++ necessary for the LIBC_PROBE Systemtap/debugger probes to work ++ reliably: direct variable access can create probes that tools ++ cannot consume. */ + extern struct r_debug *_dl_debug_initialize (ElfW(Addr) ldbase, Lmid_t ns) + attribute_hidden; + +@@ -1076,6 +1082,10 @@ extern struct r_debug *_dl_debug_initialize (ElfW(Addr) ldbase, Lmid_t ns) + of the namespace NS. */ + extern struct r_debug *_dl_debug_update (Lmid_t ns) attribute_hidden; + ++/* Update R->r_state to STATE and notify the debugger by calling ++ _dl_debug_state. */ ++void _dl_debug_change_state (struct r_debug *r, int state) attribute_hidden; ++ + /* Initialize the basic data structure for the search paths. SOURCE + is either "LD_LIBRARY_PATH" or "--library-path". + GLIBC_HWCAPS_PREPEND adds additional glibc-hwcaps subdirectories to diff --git a/glibc-upstream-2.39-250.patch b/glibc-upstream-2.39-250.patch new file mode 100644 index 0000000..bede83b --- /dev/null +++ b/glibc-upstream-2.39-250.patch @@ -0,0 +1,252 @@ +commit 5cd1f4b1a1eaf7774821d81bbd0222d80a927db2 +Author: Florian Weimer +Date: Fri Jul 4 21:46:30 2025 +0200 + + elf: Restore support for _r_debug interpositions and copy relocations + + The changes in commit a93d9e03a31ec14405cb3a09aa95413b67067380 + ("Extend struct r_debug to support multiple namespaces [BZ #15971]") + break the dyninst dynamic instrumentation tool. It brings its + own definition of _r_debug (rather than a declaration). + + Furthermore, it turns out it is rather hard to use the proposed + handshake for accessing _r_debug via DT_DEBUG. If applications want + to access _r_debug, they can do so directly if the relevant code has + been built as PIC. To protect against harm from accidental copy + relocations due to linker relaxations, this commit restores copy + relocation support by adjusting both copies if interposition or + copy relocations are in play. Therefore, it is possible to + use a hidden reference in ld.so to access _r_debug. + + Only perform the copy relocation initialization if libc has been + loaded. Otherwise, the ld.so search scope can be empty, and the + lookup of the _r_debug symbol mail fail. + + Reviewed-by: H.J. Lu + (cherry picked from commit ea85e7d55087075376a29261e722e4fae14ecbe7) + +diff --git a/elf/Makefile b/elf/Makefile +index a102373793fd16bd..34933bb15f2d8228 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -414,6 +414,8 @@ tests += \ + tst-dlmopen1 \ + tst-dlmopen3 \ + tst-dlmopen4 \ ++ tst-dlmopen4-nonpic \ ++ tst-dlmopen4-pic \ + tst-dlopen-auditdup \ + tst-dlopen-constructor-null \ + tst-dlopen-self \ +@@ -2062,6 +2064,13 @@ $(objpfx)tst-dlmopen3.out: $(objpfx)tst-dlmopen1mod.so + + $(objpfx)tst-dlmopen4.out: $(objpfx)tst-dlmopen1mod.so + ++CFLAGS-tst-dlmopen4-pic.c += -fPIC ++$(objpfx)tst-dlmopen4-pic.out: $(objpfx)tst-dlmopen1mod.so ++ ++CFLAGS-tst-dlmopen4-nonpic.c += -fno-pie ++tst-dlmopen4-nonpic-no-pie = yes ++$(objpfx)tst-dlmopen4-nonpic.out: $(objpfx)tst-dlmopen1mod.so ++ + $(objpfx)tst-audit1.out: $(objpfx)tst-auditmod1.so + tst-audit1-ENV = LD_AUDIT=$(objpfx)tst-auditmod1.so + +diff --git a/elf/dl-debug-symbols.S b/elf/dl-debug-symbols.S +index 4e35adef5de5db33..33f0fc77de503aea 100644 +--- a/elf/dl-debug-symbols.S ++++ b/elf/dl-debug-symbols.S +@@ -38,3 +38,4 @@ + _r_debug: + _r_debug_extended: + .zero R_DEBUG_EXTENDED_SIZE ++rtld_hidden_def (_r_debug) +diff --git a/elf/dl-debug.c b/elf/dl-debug.c +index b3777ffc136469cf..8b513323091402db 100644 +--- a/elf/dl-debug.c ++++ b/elf/dl-debug.c +@@ -16,6 +16,7 @@ + License along with the GNU C Library; if not, see + . */ + ++#include + #include + + +@@ -37,6 +38,37 @@ extern const int verify_link_map_members[(VERIFY_MEMBER (l_addr) + to LM_ID_BASE + 1. See elf/dl-debug-symbols.S. */ + struct r_debug_extended _r_debug_array[DL_NNS - 1]; + ++/* If not null, pointer to the _r_debug in the main executable. */ ++static struct r_debug *_r_debug_main; ++ ++void ++_dl_debug_post_relocate (struct link_map *main_map) ++{ ++ /* Perform a full symbol search in all objects, to maintain ++ compatibility if interposed _r_debug definitions. The lookup ++ cannot fail because there is a definition in ld.so, and this ++ function is only called if the ld.so search scope is not empty. */ ++ const ElfW(Sym) *sym = NULL; ++ lookup_t result =_dl_lookup_symbol_x ("_r_debug", main_map, &sym, ++ main_map->l_scope, NULL, 0, 0, NULL); ++ if (sym->st_size >= sizeof (struct r_debug)) ++ { ++ struct r_debug *main_r_debug = DL_SYMBOL_ADDRESS (result, sym); ++ if (main_r_debug != &_r_debug_extended.base) ++ { ++ /* The extended version of the struct is not available in ++ the main executable because a copy relocation has been ++ used. r_map etc. have already been copied as part of the ++ copy relocation processing. */ ++ main_r_debug->r_version = 1; ++ ++ /* Record that dual updates of the initial link map are ++ required. */ ++ _r_debug_main = main_r_debug; ++ } ++ } ++} ++ + /* Return the r_debug object for the namespace NS. */ + static inline struct r_debug_extended * + get_rdebug (Lmid_t ns) +@@ -71,6 +103,11 @@ void + _dl_debug_change_state (struct r_debug *r, int state) + { + atomic_store_release (&r->r_state, state); ++#ifdef SHARED ++ if (r == &_r_debug_extended.base && _r_debug_main != NULL) ++ /* Update the copy-relocation of _r_debug. */ ++ atomic_store_release (&_r_debug_main->r_state, state); ++#endif + _dl_debug_state (); + } + +@@ -103,7 +140,9 @@ _dl_debug_initialize (ElfW(Addr) ldbase, Lmid_t ns) + if (ns - 1 == LM_ID_BASE) + { + atomic_store_release (&_r_debug_extended.r_next, r); +- /* Now there are multiple namespaces. */ ++ /* Now there are multiple namespaces. Note that this ++ deliberately does not update the copy in the main ++ executable (if it exists). */ + atomic_store_release (&_r_debug_extended.base.r_version, 2); + } + else +@@ -116,8 +155,15 @@ _dl_debug_initialize (ElfW(Addr) ldbase, Lmid_t ns) + } + + if (r->base.r_map == NULL) +- atomic_store_release (&r->base.r_map, +- (void *) GL(dl_ns)[ns]._ns_loaded); ++ { ++ struct link_map_public *l = (void *) GL(dl_ns)[ns]._ns_loaded; ++ atomic_store_release (&r->base.r_map, l); ++#ifdef SHARED ++ if (ns == LM_ID_BASE && _r_debug_main != NULL) ++ /* Update the copy-relocation of _r_debug. */ ++ atomic_store_release (&_r_debug_main->r_map, l); ++#endif ++ } + + return &r->base; + } +diff --git a/elf/rtld.c b/elf/rtld.c +index 43bfc7378afc6cc7..cd790e37f2a323a4 100644 +--- a/elf/rtld.c ++++ b/elf/rtld.c +@@ -2381,6 +2381,9 @@ dl_main (const ElfW(Phdr) *phdr, + + __rtld_mutex_init (); + __rtld_malloc_init_real (main_map); ++ ++ /* Update copy-relocated _r_debug if necessary. */ ++ _dl_debug_post_relocate (main_map); + } + + /* All ld.so initialization is complete. Apply RELRO. */ +diff --git a/elf/tst-dlmopen4-nonpic.c b/elf/tst-dlmopen4-nonpic.c +new file mode 100644 +index 0000000000000000..ad4e40995337f4f9 +--- /dev/null ++++ b/elf/tst-dlmopen4-nonpic.c +@@ -0,0 +1,2 @@ ++#define BUILD_FOR_NONPIC ++#include "tst-dlmopen4.c" +diff --git a/elf/tst-dlmopen4-pic.c b/elf/tst-dlmopen4-pic.c +new file mode 100644 +index 0000000000000000..919fa85c2579fb5d +--- /dev/null ++++ b/elf/tst-dlmopen4-pic.c +@@ -0,0 +1,2 @@ ++#define BUILD_FOR_PIC ++#include "tst-dlmopen4.c" +diff --git a/elf/tst-dlmopen4.c b/elf/tst-dlmopen4.c +index b1c5502621ed433d..9e053fbc59c531ae 100644 +--- a/elf/tst-dlmopen4.c ++++ b/elf/tst-dlmopen4.c +@@ -46,6 +46,15 @@ do_test (void) + TEST_COMPARE (debug->base.r_version, 1); + TEST_VERIFY_EXIT (debug->r_next == NULL); + ++#ifdef BUILD_FOR_PIC ++ /* In a PIC build, using _r_debug directly should give us the same ++ object. */ ++ TEST_VERIFY (&_r_debug == &debug->base); ++#endif ++#ifdef BUILD_FOR_NONPIC ++ TEST_COMPARE (_r_debug.r_version, 1); ++#endif ++ + void *h = xdlmopen (LM_ID_NEWLM, "$ORIGIN/tst-dlmopen1mod.so", + RTLD_LAZY); + +@@ -57,6 +66,19 @@ do_test (void) + const char *name = basename (debug->r_next->base.r_map->l_name); + TEST_COMPARE_STRING (name, "tst-dlmopen1mod.so"); + ++#ifdef BUILD_FOR_NONPIC ++ /* If a copy relocation is used, it must be at version 1. */ ++ if (&_r_debug != &debug->base) ++ { ++ TEST_COMPARE (_r_debug.r_version, 1); ++ TEST_COMPARE ((uintptr_t) _r_debug.r_map, ++ (uintptr_t) debug->base.r_map); ++ TEST_COMPARE (_r_debug.r_brk, debug->base.r_brk); ++ TEST_COMPARE (_r_debug.r_state, debug->base.r_state); ++ TEST_COMPARE (_r_debug.r_ldbase, debug->base.r_ldbase); ++ } ++#endif ++ + xdlclose (h); + + return 0; +diff --git a/include/link.h b/include/link.h +index 5ed445d5a6cdf12d..7ca305f7804442f5 100644 +--- a/include/link.h ++++ b/include/link.h +@@ -365,6 +365,8 @@ struct auditstate + dynamic linker. */ + extern struct r_debug_extended _r_debug_extended attribute_hidden; + ++rtld_hidden_proto (_r_debug) ++ + #if __ELF_NATIVE_CLASS == 32 + # define symbind symbind32 + # define LA_SYMBIND "la_symbind32" +diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h +index 017406e7fa93c941..043abd369700ad58 100644 +--- a/sysdeps/generic/ldsodefs.h ++++ b/sysdeps/generic/ldsodefs.h +@@ -1078,6 +1078,10 @@ rtld_hidden_proto (_dl_debug_state) + extern struct r_debug *_dl_debug_initialize (ElfW(Addr) ldbase, Lmid_t ns) + attribute_hidden; + ++/* This is called after relocation processing to handle a potential ++ copy relocation for _r_debug. */ ++void _dl_debug_post_relocate (struct link_map *main_map) attribute_hidden; ++ + /* Update the `r_map' member and return the address of `struct r_debug' + of the namespace NS. */ + extern struct r_debug *_dl_debug_update (Lmid_t ns) attribute_hidden; diff --git a/glibc-upstream-2.39-251.patch b/glibc-upstream-2.39-251.patch new file mode 100644 index 0000000..ede1711 --- /dev/null +++ b/glibc-upstream-2.39-251.patch @@ -0,0 +1,81 @@ +commit cf0e7d512d3c5a5d46da50c0aa023a7f8dc0d560 +Author: Florian Weimer +Date: Mon Jul 28 14:16:52 2025 +0200 + + elf: Compile _dl_debug_state separately (bug 33224) + + This ensures that the compiler will not inline it, so that + debuggers which do not use the Systemtap probes can reliably + set a breakpoint on it. + + Reviewed-by: Andreas K. Huettel + Tested-by: Andreas K. Huettel + (cherry picked from commit 620f0730f311635cd0e175a3ae4d0fc700c76366) + +diff --git a/elf/Makefile b/elf/Makefile +index 34933bb15f2d8228..57726b1034046433 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -57,6 +57,7 @@ dl-routines = \ + dl-close \ + dl-debug \ + dl-debug-symbols \ ++ dl-debug_state \ + dl-deps \ + dl-exception \ + dl-execstack \ +diff --git a/elf/dl-debug.c b/elf/dl-debug.c +index 8b513323091402db..df36d61dcb66dd0f 100644 +--- a/elf/dl-debug.c ++++ b/elf/dl-debug.c +@@ -167,14 +167,3 @@ _dl_debug_initialize (ElfW(Addr) ldbase, Lmid_t ns) + + return &r->base; + } +- +- +-/* This function exists solely to have a breakpoint set on it by the +- debugger. The debugger is supposed to find this function's address by +- examining the r_brk member of struct r_debug, but GDB 4.15 in fact looks +- for this particular symbol name in the PT_INTERP file. */ +-void +-_dl_debug_state (void) +-{ +-} +-rtld_hidden_def (_dl_debug_state) +diff --git a/elf/dl-debug_state.c b/elf/dl-debug_state.c +new file mode 100644 +index 0000000000000000..40c134a49e2455f3 +--- /dev/null ++++ b/elf/dl-debug_state.c +@@ -0,0 +1,30 @@ ++/* Debugger hook called after dynamic linker updates. ++ Copyright (C) 1996-2025 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 ++ . */ ++ ++#include ++ ++/* This function exists solely to have a breakpoint set on it by the ++ debugger. The debugger is supposed to find this function's address by ++ examining the r_brk member of struct r_debug, but GDB 4.15 in fact looks ++ for this particular symbol name in the PT_INTERP file. Therefore, ++ this function must not be inlined. */ ++void ++_dl_debug_state (void) ++{ ++} ++rtld_hidden_def (_dl_debug_state) diff --git a/glibc-upstream-2.39-252.patch b/glibc-upstream-2.39-252.patch new file mode 100644 index 0000000..9ef5193 --- /dev/null +++ b/glibc-upstream-2.39-252.patch @@ -0,0 +1,23 @@ +commit 4c2509882fd9768a067ce8cb7cb40394e1cf3862 +Author: Florian Weimer +Date: Mon Aug 18 13:52:02 2025 +0200 + + elf: Preserve _rtld_global layout for the release branch + + Backporting commit 97017da5ef946c6d38c252f56c8cb7c205b732fa + ("elf: Introduce _dl_debug_change_state") removed the + _ns_debug member. Keep it to preseve struct layout. + +diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h +index 043abd369700ad58..b4c6e6d2ca7a1fec 100644 +--- a/sysdeps/generic/ldsodefs.h ++++ b/sysdeps/generic/ldsodefs.h +@@ -350,6 +350,8 @@ struct rtld_global + size_t n_elements; + void (*free) (void *); + } _ns_unique_sym_table; ++ /* Keep track of changes to each namespace' list. */ ++ struct r_debug_extended _ns_debug_unused; + } _dl_ns[DL_NNS]; + /* One higher than index of last used namespace. */ + EXTERN size_t _dl_nns; diff --git a/glibc-upstream-2.39-253.patch b/glibc-upstream-2.39-253.patch new file mode 100644 index 0000000..19ae42a --- /dev/null +++ b/glibc-upstream-2.39-253.patch @@ -0,0 +1,1149 @@ +commit 89596f46e3113bd9643e7d5a90e6f7db11259086 +Author: H.J. Lu +Date: Mon Jun 9 05:22:10 2025 +0800 + + i386: Update ___tls_get_addr to preserve vector registers + + Compiler generates the following instruction sequence for dynamic TLS + access: + + leal tls_var@tlsgd(,%ebx,1), %eax + call ___tls_get_addr@PLT + + CALL instruction is transparent to compiler which assumes all registers, + except for EFLAGS, AX, CX, and DX, are unchanged after CALL. But + ___tls_get_addr is a normal function which doesn't preserve any vector + registers. + + 1. Rename the generic __tls_get_addr function to ___tls_get_addr_internal. + 2. Change ___tls_get_addr to a wrapper function with implementations for + FNSAVE, FXSAVE, XSAVE and XSAVEC to save and restore all vector registers. + 3. dl-tlsdesc-dynamic.h has: + + _dl_tlsdesc_dynamic: + /* Like all TLS resolvers, preserve call-clobbered registers. + We need two scratch regs anyway. */ + subl $32, %esp + cfi_adjust_cfa_offset (32) + + It is wrong to use + + movl %ebx, -28(%esp) + movl %esp, %ebx + cfi_def_cfa_register(%ebx) + ... + mov %ebx, %esp + cfi_def_cfa_register(%esp) + movl -28(%esp), %ebx + + to preserve EBX on stack. Fix it with: + + movl %ebx, 28(%esp) + movl %esp, %ebx + cfi_def_cfa_register(%ebx) + ... + mov %ebx, %esp + cfi_def_cfa_register(%esp) + movl 28(%esp), %ebx + + 4. Update _dl_tlsdesc_dynamic to call ___tls_get_addr_internal directly. + 5. Add have-test-mtls-traditional to compile tst-tls23-mod.c with + traditional TLS variant to verify the fix. + 6. Define DL_RUNTIME_RESOLVE_REALIGN_STACK in sysdeps/x86/sysdep.h. + + This fixes BZ #32996. + + Co-Authored-By: Adhemerval Zanella + Signed-off-by: H.J. Lu + Reviewed-by: Adhemerval Zanella + (cherry picked from commit 848f0e46f03f22404ed9a8aabf3fd5ce8809a1be) + +diff --git a/configure b/configure +index c25b93dd0b317e4e..36a492ab5053486e 100755 +--- a/configure ++++ b/configure +@@ -4778,6 +4778,9 @@ with_fp_cond=1 + # A preconfigure script may define another name to TLS descriptor variant + mtls_descriptor=gnu2 + ++# A preconfigure script may define another name to traditional TLS variant ++mtls_traditional=gnu ++ + if frags=`ls -d $srcdir/sysdeps/*/preconfigure 2> /dev/null` + then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for sysdeps preconfigure fragments" >&5 +@@ -7057,6 +7060,39 @@ printf "%s\n" "$libc_cv_mtls_descriptor" >&6; } + config_vars="$config_vars + have-mtls-descriptor = $libc_cv_mtls_descriptor" + ++{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for traditional tls support" >&5 ++printf %s "checking for traditional tls support... " >&6; } ++if test ${libc_cv_test_mtls_traditional+y} ++then : ++ printf %s "(cached) " >&6 ++else case e in #( ++ e) cat > conftest.c <&5 ++ (eval $ac_try) 2>&5 ++ ac_status=$? ++ printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 ++ test $ac_status = 0; }; } ++then ++ libc_cv_test_mtls_traditional=$mtls_traditional ++else ++ libc_cv_test_mtls_traditional=no ++fi ++rm -f conftest* ;; ++esac ++fi ++{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $libc_cv_test_mtls_traditional" >&5 ++printf "%s\n" "$libc_cv_test_mtls_traditional" >&6; } ++config_vars="$config_vars ++have-test-mtls-traditional = $libc_cv_test_mtls_traditional" ++ + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if -Wno-ignored-attributes is required for aliases" >&5 + printf %s "checking if -Wno-ignored-attributes is required for aliases... " >&6; } + if test ${libc_cv_wno_ignored_attributes+y} +diff --git a/configure.ac b/configure.ac +index f00fc36f387af09d..c9eb28f7dc8950cc 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -454,6 +454,9 @@ with_fp_cond=1 + # A preconfigure script may define another name to TLS descriptor variant + mtls_descriptor=gnu2 + ++# A preconfigure script may define another name to traditional TLS variant ++mtls_traditional=gnu ++ + dnl Let sysdeps/*/preconfigure act here. + LIBC_PRECONFIGURE([$srcdir], [for sysdeps]) + +@@ -1319,6 +1322,28 @@ rm -f conftest*]) + AC_SUBST(libc_cv_mtls_descriptor) + LIBC_CONFIG_VAR([have-mtls-descriptor], [$libc_cv_mtls_descriptor]) + ++dnl Check if CC supports traditional tls. ++AC_CACHE_CHECK([for traditional tls support], ++ libc_cv_test_mtls_traditional, ++[dnl ++cat > conftest.c <&AS_MESSAGE_LOG_FD]) ++then ++ libc_cv_test_mtls_traditional=$mtls_traditional ++else ++ libc_cv_test_mtls_traditional=no ++fi ++rm -f conftest*]) ++LIBC_CONFIG_VAR([have-test-mtls-traditional], ++ [$libc_cv_test_mtls_traditional]) ++ + dnl clang emits an warning for a double alias redirection, to warn the + dnl original symbol is sed even when weak definition overrides it. + dnl It is a usual pattern for weak_alias, where multiple alias point to +diff --git a/elf/Makefile b/elf/Makefile +index 57726b1034046433..fb35102f827b96cd 100644 +--- a/elf/Makefile ++++ b/elf/Makefile +@@ -485,6 +485,7 @@ tests += \ + tst-tls19 \ + tst-tls20 \ + tst-tls21 \ ++ tst-tls23 \ + tst-tlsalign \ + tst-tlsalign-extern \ + tst-tlsgap \ +@@ -956,6 +957,7 @@ modules-names += \ + tst-tls19mod3 \ + tst-tls20mod-bad \ + tst-tls21mod \ ++ tst-tls23-mod \ + tst-tlsalign-lib \ + tst-tlsgap-mod0 \ + tst-tlsgap-mod1 \ +@@ -3136,6 +3138,13 @@ CFLAGS-tst-gnu2-tls2mod1.c += -mtls-dialect=$(have-mtls-descriptor) + CFLAGS-tst-gnu2-tls2mod2.c += -mtls-dialect=$(have-mtls-descriptor) + endif + ++$(objpfx)tst-tls23: $(shared-thread-library) ++$(objpfx)tst-tls23.out: $(objpfx)tst-tls23-mod.so ++ ++ifneq (no,$(have-test-mtls-traditional)) ++CFLAGS-tst-tls23-mod.c += -mtls-dialect=$(have-test-mtls-traditional) ++endif ++ + $(objpfx)tst-recursive-tls: $(objpfx)tst-recursive-tlsmallocmod.so + # More objects than DTV_SURPLUS, to trigger DTV reallocation. + $(objpfx)tst-recursive-tls.out: \ +diff --git a/elf/tst-tls23-mod.c b/elf/tst-tls23-mod.c +new file mode 100644 +index 0000000000000000..3ee4c70e40b3fdc6 +--- /dev/null ++++ b/elf/tst-tls23-mod.c +@@ -0,0 +1,32 @@ ++/* DSO used by tst-tls23. ++ Copyright (C) 2025 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 ++ . */ ++ ++#include ++ ++__thread struct tls tls_var0 __attribute__ ((visibility ("hidden"))); ++ ++struct tls * ++apply_tls (struct tls *p) ++{ ++ INIT_TLS_CALL (); ++ BEFORE_TLS_CALL (); ++ tls_var0 = *p; ++ struct tls *ret = &tls_var0; ++ AFTER_TLS_CALL (); ++ return ret; ++} +diff --git a/elf/tst-tls23.c b/elf/tst-tls23.c +new file mode 100644 +index 0000000000000000..afe594c067331019 +--- /dev/null ++++ b/elf/tst-tls23.c +@@ -0,0 +1,106 @@ ++/* Test that __tls_get_addr preserves caller-saved registers. ++ Copyright (C) 2025 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#ifndef IS_SUPPORTED ++# define IS_SUPPORTED() true ++#endif ++ ++/* An architecture can define it to clobber caller-saved registers in ++ malloc below to verify that __tls_get_addr won't change caller-saved ++ registers. */ ++#ifndef PREPARE_MALLOC ++# define PREPARE_MALLOC() ++#endif ++ ++extern void * __libc_malloc (size_t); ++ ++size_t malloc_counter = 0; ++ ++void * ++malloc (size_t n) ++{ ++ PREPARE_MALLOC (); ++ malloc_counter++; ++ return __libc_malloc (n); ++} ++ ++static void *mod; ++static const char *modname = "tst-tls23-mod.so"; ++ ++static void ++open_mod (void) ++{ ++ mod = xdlopen (modname, RTLD_LAZY); ++ printf ("open %s\n", modname); ++} ++ ++static void ++close_mod (void) ++{ ++ xdlclose (mod); ++ mod = NULL; ++ printf ("close %s\n", modname); ++} ++ ++static void ++access_mod (const char *sym) ++{ ++ struct tls var = { -4, -4, -4, -4 }; ++ struct tls *(*f) (struct tls *) = xdlsym (mod, sym); ++ /* Check that our malloc is called. */ ++ malloc_counter = 0; ++ struct tls *p = f (&var); ++ TEST_VERIFY (malloc_counter != 0); ++ printf ("access %s: %s() = %p\n", modname, sym, p); ++ TEST_VERIFY_EXIT (memcmp (p, &var, sizeof (var)) == 0); ++ ++(p->a); ++} ++ ++static void * ++start (void *arg) ++{ ++ access_mod ("apply_tls"); ++ return arg; ++} ++ ++static int ++do_test (void) ++{ ++ if (!IS_SUPPORTED ()) ++ return EXIT_UNSUPPORTED; ++ ++ open_mod (); ++ pthread_t t = xpthread_create (NULL, start, NULL); ++ xpthread_join (t); ++ close_mod (); ++ ++ return 0; ++} ++ ++#include +diff --git a/sysdeps/x86_64/dl-trampoline-save.h b/elf/tst-tls23.h +similarity index 52% +rename from sysdeps/x86_64/dl-trampoline-save.h +rename to elf/tst-tls23.h +index 84eac4a8ac13ad86..d0e734569c60a47d 100644 +--- a/sysdeps/x86_64/dl-trampoline-save.h ++++ b/elf/tst-tls23.h +@@ -1,5 +1,5 @@ +-/* x86-64 PLT trampoline register save macros. +- Copyright (C) 2024 Free Software Foundation, Inc. ++/* Test that __tls_get_addr preserves caller-saved registers. ++ Copyright (C) 2025 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 +@@ -16,19 +16,25 @@ + License along with the GNU C Library; if not, see + . */ + +-#ifndef DL_STACK_ALIGNMENT +-/* Due to GCC bug: ++#include + +- https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58066 ++struct tls ++{ ++ int64_t a, b, c, d; ++}; + +- __tls_get_addr may be called with 8-byte stack alignment. Although +- this bug has been fixed in GCC 4.9.4, 5.3 and 6, we can't assume +- that stack will be always aligned at 16 bytes. */ +-# define DL_STACK_ALIGNMENT 8 ++extern struct tls *apply_tls (struct tls *); ++ ++/* An architecture can define them to verify that caller-saved registers ++ aren't changed by __tls_get_addr. */ ++#ifndef INIT_TLS_CALL ++# define INIT_TLS_CALL() ++#endif ++ ++#ifndef BEFORE_TLS_CALL ++# define BEFORE_TLS_CALL() + #endif + +-/* True if _dl_runtime_resolve should align stack for STATE_SAVE or align +- stack to 16 bytes before calling _dl_fixup. */ +-#define DL_RUNTIME_RESOLVE_REALIGN_STACK \ +- (STATE_SAVE_ALIGNMENT > DL_STACK_ALIGNMENT \ +- || 16 > DL_STACK_ALIGNMENT) ++#ifndef AFTER_TLS_CALL ++# define AFTER_TLS_CALL() ++#endif +diff --git a/sysdeps/aarch64/preconfigure b/sysdeps/aarch64/preconfigure +index 19657b627bc84c4e..e1b772c58600c0f2 100644 +--- a/sysdeps/aarch64/preconfigure ++++ b/sysdeps/aarch64/preconfigure +@@ -3,5 +3,6 @@ aarch64*) + base_machine=aarch64 + machine=aarch64 + mtls_descriptor=desc ++ mtls_traditional=trad + ;; + esac +diff --git a/sysdeps/i386/Makefile b/sysdeps/i386/Makefile +index a2e8c0b12822be0b..ee6470d78e856315 100644 +--- a/sysdeps/i386/Makefile ++++ b/sysdeps/i386/Makefile +@@ -30,7 +30,9 @@ stack-align-test-flags += -malign-double + endif + + ifeq ($(subdir),elf) +-sysdep-dl-routines += tlsdesc dl-tlsdesc ++sysdep-dl-routines += \ ++ dl-tls-get-addr \ ++# sysdep-dl-routines + + tests += tst-audit3 + modules-names += tst-auditmod3a tst-auditmod3b +diff --git a/sysdeps/i386/dl-tls-get-addr.c b/sysdeps/i386/dl-tls-get-addr.c +new file mode 100644 +index 0000000000000000..c97e5c57beca8caa +--- /dev/null ++++ b/sysdeps/i386/dl-tls-get-addr.c +@@ -0,0 +1,68 @@ ++/* Ifunc selector for ___tls_get_addr. ++ Copyright (C) 2025 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 ++ . */ ++ ++#ifdef SHARED ++# define ___tls_get_addr __redirect____tls_get_addr ++# include ++# undef ___tls_get_addr ++# undef __tls_get_addr ++ ++# define SYMBOL_NAME ___tls_get_addr ++# include ++ ++extern __typeof (REDIRECT_NAME) OPTIMIZE (fnsave) attribute_hidden; ++extern __typeof (REDIRECT_NAME) OPTIMIZE (fxsave) attribute_hidden; ++extern __typeof (REDIRECT_NAME) OPTIMIZE (xsave) attribute_hidden; ++extern __typeof (REDIRECT_NAME) OPTIMIZE (xsavec) attribute_hidden; ++ ++static inline void * ++IFUNC_SELECTOR (void) ++{ ++ const struct cpu_features* cpu_features = __get_cpu_features (); ++ ++ if (cpu_features->xsave_state_size != 0) ++ { ++ if (CPU_FEATURE_USABLE_P (cpu_features, XSAVEC)) ++ return OPTIMIZE (xsavec); ++ else ++ return OPTIMIZE (xsave); ++ } ++ else if (CPU_FEATURE_USABLE_P (cpu_features, FXSR)) ++ return OPTIMIZE (fxsave); ++ return OPTIMIZE (fnsave); ++} ++ ++libc_ifunc_redirected (__redirect____tls_get_addr, ___tls_get_addr, ++ IFUNC_SELECTOR ()); ++ ++/* The special thing about the x86 TLS ABI is that we have two ++ variants of the __tls_get_addr function with different calling ++ conventions. The GNU version, which we are mostly concerned here, ++ takes the parameter in a register. The name is changed by adding ++ an additional underscore at the beginning. The Sun version uses ++ the normal calling convention. */ ++ ++rtld_hidden_proto (___tls_get_addr) ++rtld_hidden_def (___tls_get_addr) ++ ++void * ++__tls_get_addr (tls_index *ti) ++{ ++ return ___tls_get_addr (ti); ++} ++#endif +diff --git a/sysdeps/i386/dl-tls.h b/sysdeps/i386/dl-tls.h +index f17286703d9270ac..2380ec1bd4391de0 100644 +--- a/sysdeps/i386/dl-tls.h ++++ b/sysdeps/i386/dl-tls.h +@@ -29,33 +29,13 @@ typedef struct dl_tls_index + /* This is the prototype for the GNU version. */ + extern void *___tls_get_addr (tls_index *ti) + __attribute__ ((__regparm__ (1))); +-extern void *___tls_get_addr_internal (tls_index *ti) +- __attribute__ ((__regparm__ (1))) attribute_hidden; +- + # if IS_IN (rtld) +-/* The special thing about the x86 TLS ABI is that we have two +- variants of the __tls_get_addr function with different calling +- conventions. The GNU version, which we are mostly concerned here, +- takes the parameter in a register. The name is changed by adding +- an additional underscore at the beginning. The Sun version uses +- the normal calling convention. */ +-void * +-__tls_get_addr (tls_index *ti) +-{ +- return ___tls_get_addr_internal (ti); +-} +- +- + /* Prepare using the definition of __tls_get_addr in the generic + version of this file. */ +-# define __tls_get_addr __attribute__ ((__regparm__ (1))) ___tls_get_addr +-strong_alias (___tls_get_addr, ___tls_get_addr_internal) +-rtld_hidden_proto (___tls_get_addr) +-rtld_hidden_def (___tls_get_addr) +-#else +- ++# define __tls_get_addr \ ++ __attribute__ ((__regparm__ (1))) ___tls_get_addr_internal ++# else + /* Users should get the better interface. */ +-# define __tls_get_addr ___tls_get_addr +- ++# define __tls_get_addr ___tls_get_addr + # endif + #endif +diff --git a/sysdeps/i386/dl-tlsdesc-dynamic.h b/sysdeps/i386/dl-tlsdesc-dynamic.h +index 36270285775016ff..8a5952421e76d52a 100644 +--- a/sysdeps/i386/dl-tlsdesc-dynamic.h ++++ b/sysdeps/i386/dl-tlsdesc-dynamic.h +@@ -16,34 +16,6 @@ + License along with the GNU C Library; if not, see + . */ + +-#undef REGISTER_SAVE_AREA +- +-#if !defined USE_FNSAVE && (STATE_SAVE_ALIGNMENT % 16) != 0 +-# error STATE_SAVE_ALIGNMENT must be multiple of 16 +-#endif +- +-#if DL_RUNTIME_RESOLVE_REALIGN_STACK +-# ifdef USE_FNSAVE +-# error USE_FNSAVE shouldn't be defined +-# endif +-# ifdef USE_FXSAVE +-/* Use fxsave to save all registers. */ +-# define REGISTER_SAVE_AREA 512 +-# endif +-#else +-# ifdef USE_FNSAVE +-/* Use fnsave to save x87 FPU stack registers. */ +-# define REGISTER_SAVE_AREA 108 +-# else +-# ifndef USE_FXSAVE +-# error USE_FXSAVE must be defined +-# endif +-/* Use fxsave to save all registers. Add 12 bytes to align the stack +- to 16 bytes. */ +-# define REGISTER_SAVE_AREA (512 + 12) +-# endif +-#endif +- + .hidden _dl_tlsdesc_dynamic + .global _dl_tlsdesc_dynamic + .type _dl_tlsdesc_dynamic,@function +@@ -104,85 +76,7 @@ _dl_tlsdesc_dynamic: + ret + .p2align 4,,7 + 2: +- cfi_adjust_cfa_offset (32) +-#if DL_RUNTIME_RESOLVE_REALIGN_STACK +- movl %ebx, -28(%esp) +- movl %esp, %ebx +- cfi_def_cfa_register(%ebx) +- and $-STATE_SAVE_ALIGNMENT, %esp +-#endif +-#ifdef REGISTER_SAVE_AREA +- subl $REGISTER_SAVE_AREA, %esp +-# if !DL_RUNTIME_RESOLVE_REALIGN_STACK +- cfi_adjust_cfa_offset(REGISTER_SAVE_AREA) +-# endif +-#else +-# if !DL_RUNTIME_RESOLVE_REALIGN_STACK +-# error DL_RUNTIME_RESOLVE_REALIGN_STACK must be true +-# endif +- /* Allocate stack space of the required size to save the state. */ +- LOAD_PIC_REG (cx) +- subl RTLD_GLOBAL_RO_DL_X86_CPU_FEATURES_OFFSET+XSAVE_STATE_SIZE_OFFSET+_rtld_local_ro@GOTOFF(%ecx), %esp +-#endif +-#ifdef USE_FNSAVE +- fnsave (%esp) +-#elif defined USE_FXSAVE +- fxsave (%esp) +-#else +- /* Save the argument for ___tls_get_addr in EAX. */ +- movl %eax, %ecx +- movl $TLSDESC_CALL_STATE_SAVE_MASK, %eax +- xorl %edx, %edx +- /* Clear the XSAVE Header. */ +-# ifdef USE_XSAVE +- movl %edx, (512)(%esp) +- movl %edx, (512 + 4 * 1)(%esp) +- movl %edx, (512 + 4 * 2)(%esp) +- movl %edx, (512 + 4 * 3)(%esp) +-# endif +- movl %edx, (512 + 4 * 4)(%esp) +- movl %edx, (512 + 4 * 5)(%esp) +- movl %edx, (512 + 4 * 6)(%esp) +- movl %edx, (512 + 4 * 7)(%esp) +- movl %edx, (512 + 4 * 8)(%esp) +- movl %edx, (512 + 4 * 9)(%esp) +- movl %edx, (512 + 4 * 10)(%esp) +- movl %edx, (512 + 4 * 11)(%esp) +- movl %edx, (512 + 4 * 12)(%esp) +- movl %edx, (512 + 4 * 13)(%esp) +- movl %edx, (512 + 4 * 14)(%esp) +- movl %edx, (512 + 4 * 15)(%esp) +-# ifdef USE_XSAVE +- xsave (%esp) +-# else +- xsavec (%esp) +-# endif +- /* Restore the argument for ___tls_get_addr in EAX. */ +- movl %ecx, %eax +-#endif +- call HIDDEN_JUMPTARGET (___tls_get_addr) +- /* Get register content back. */ +-#ifdef USE_FNSAVE +- frstor (%esp) +-#elif defined USE_FXSAVE +- fxrstor (%esp) +-#else +- /* Save and retore ___tls_get_addr return value stored in EAX. */ +- movl %eax, %ecx +- movl $TLSDESC_CALL_STATE_SAVE_MASK, %eax +- xorl %edx, %edx +- xrstor (%esp) +- movl %ecx, %eax +-#endif +-#if DL_RUNTIME_RESOLVE_REALIGN_STACK +- mov %ebx, %esp +- cfi_def_cfa_register(%esp) +- movl -28(%esp), %ebx +- cfi_restore(%ebx) +-#else +- addl $REGISTER_SAVE_AREA, %esp +- cfi_adjust_cfa_offset(-REGISTER_SAVE_AREA) +-#endif ++#include "tls-get-addr-wrapper.h" + jmp 1b + cfi_endproc + .size _dl_tlsdesc_dynamic, .-_dl_tlsdesc_dynamic +diff --git a/sysdeps/i386/dl-tlsdesc.S b/sysdeps/i386/dl-tlsdesc.S +index f002feee56e43f71..dec7049911d65f7d 100644 +--- a/sysdeps/i386/dl-tlsdesc.S ++++ b/sysdeps/i386/dl-tlsdesc.S +@@ -22,23 +22,6 @@ + #include + #include "tlsdesc.h" + +-#ifndef DL_STACK_ALIGNMENT +-/* Due to GCC bug: +- +- https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58066 +- +- __tls_get_addr may be called with 4-byte stack alignment. Although +- this bug has been fixed in GCC 4.9.4, 5.3 and 6, we can't assume +- that stack will be always aligned at 16 bytes. */ +-# define DL_STACK_ALIGNMENT 4 +-#endif +- +-/* True if _dl_tlsdesc_dynamic should align stack for STATE_SAVE or align +- stack to MINIMUM_ALIGNMENT bytes before calling ___tls_get_addr. */ +-#define DL_RUNTIME_RESOLVE_REALIGN_STACK \ +- (STATE_SAVE_ALIGNMENT > DL_STACK_ALIGNMENT \ +- || MINIMUM_ALIGNMENT > DL_STACK_ALIGNMENT) +- + .text + + /* This function is used to compute the TP offset for symbols in +diff --git a/sysdeps/i386/tls-get-addr-wrapper.h b/sysdeps/i386/tls-get-addr-wrapper.h +new file mode 100644 +index 0000000000000000..0708e5ad1dc9d8ec +--- /dev/null ++++ b/sysdeps/i386/tls-get-addr-wrapper.h +@@ -0,0 +1,127 @@ ++/* Wrapper of i386 ___tls_get_addr to save and restore vector registers. ++ Copyright (C) 2025 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 ++ . */ ++ ++#undef REGISTER_SAVE_AREA ++ ++#if !defined USE_FNSAVE && (STATE_SAVE_ALIGNMENT % 16) != 0 ++# error STATE_SAVE_ALIGNMENT must be multiple of 16 ++#endif ++ ++#if DL_RUNTIME_RESOLVE_REALIGN_STACK ++# ifdef USE_FNSAVE ++# error USE_FNSAVE shouldn't be defined ++# endif ++# ifdef USE_FXSAVE ++/* Use fxsave to save all registers. */ ++# define REGISTER_SAVE_AREA 512 ++# endif ++#else ++# ifdef USE_FNSAVE ++/* Use fnsave to save x87 FPU stack registers. */ ++# define REGISTER_SAVE_AREA 108 ++# else ++# ifndef USE_FXSAVE ++# error USE_FXSAVE must be defined ++# endif ++/* Use fxsave to save all registers. Add 12 bytes to align the stack ++ to 16 bytes. */ ++# define REGISTER_SAVE_AREA (512 + 12) ++# endif ++#endif ++ ++#if DL_RUNTIME_RESOLVE_REALIGN_STACK ++ movl %ebx, 28(%esp) ++ movl %esp, %ebx ++ cfi_def_cfa_register(%ebx) ++ and $-STATE_SAVE_ALIGNMENT, %esp ++#endif ++#ifdef REGISTER_SAVE_AREA ++ subl $REGISTER_SAVE_AREA, %esp ++# if !DL_RUNTIME_RESOLVE_REALIGN_STACK ++ cfi_adjust_cfa_offset(REGISTER_SAVE_AREA) ++# endif ++#else ++# if !DL_RUNTIME_RESOLVE_REALIGN_STACK ++# error DL_RUNTIME_RESOLVE_REALIGN_STACK must be true ++# endif ++ /* Allocate stack space of the required size to save the state. */ ++ LOAD_PIC_REG (cx) ++ subl RTLD_GLOBAL_RO_DL_X86_CPU_FEATURES_OFFSET \ ++ +XSAVE_STATE_SIZE_OFFSET+_rtld_local_ro@GOTOFF(%ecx), %esp ++#endif ++#ifdef USE_FNSAVE ++ fnsave (%esp) ++#elif defined USE_FXSAVE ++ fxsave (%esp) ++#else ++ /* Save the argument for ___tls_get_addr in EAX. */ ++ movl %eax, %ecx ++ movl $TLSDESC_CALL_STATE_SAVE_MASK, %eax ++ xorl %edx, %edx ++ /* Clear the XSAVE Header. */ ++# ifdef USE_XSAVE ++ movl %edx, (512)(%esp) ++ movl %edx, (512 + 4 * 1)(%esp) ++ movl %edx, (512 + 4 * 2)(%esp) ++ movl %edx, (512 + 4 * 3)(%esp) ++# endif ++ movl %edx, (512 + 4 * 4)(%esp) ++ movl %edx, (512 + 4 * 5)(%esp) ++ movl %edx, (512 + 4 * 6)(%esp) ++ movl %edx, (512 + 4 * 7)(%esp) ++ movl %edx, (512 + 4 * 8)(%esp) ++ movl %edx, (512 + 4 * 9)(%esp) ++ movl %edx, (512 + 4 * 10)(%esp) ++ movl %edx, (512 + 4 * 11)(%esp) ++ movl %edx, (512 + 4 * 12)(%esp) ++ movl %edx, (512 + 4 * 13)(%esp) ++ movl %edx, (512 + 4 * 14)(%esp) ++ movl %edx, (512 + 4 * 15)(%esp) ++# ifdef USE_XSAVE ++ xsave (%esp) ++# else ++ xsavec (%esp) ++# endif ++ /* Restore the argument for ___tls_get_addr in EAX. */ ++ movl %ecx, %eax ++#endif ++ call ___tls_get_addr_internal ++ /* Get register content back. */ ++#ifdef USE_FNSAVE ++ frstor (%esp) ++#elif defined USE_FXSAVE ++ fxrstor (%esp) ++#else ++ /* Save and retore ___tls_get_addr return value stored in EAX. */ ++ movl %eax, %ecx ++ movl $TLSDESC_CALL_STATE_SAVE_MASK, %eax ++ xorl %edx, %edx ++ xrstor (%esp) ++ movl %ecx, %eax ++#endif ++#if DL_RUNTIME_RESOLVE_REALIGN_STACK ++ mov %ebx, %esp ++ cfi_def_cfa_register(%esp) ++ movl 28(%esp), %ebx ++ cfi_restore(%ebx) ++#else ++ addl $REGISTER_SAVE_AREA, %esp ++ cfi_adjust_cfa_offset(-REGISTER_SAVE_AREA) ++#endif ++ ++#undef STATE_SAVE_ALIGNMENT +diff --git a/sysdeps/i386/tls_get_addr.S b/sysdeps/i386/tls_get_addr.S +new file mode 100644 +index 0000000000000000..7d143d8a23b06884 +--- /dev/null ++++ b/sysdeps/i386/tls_get_addr.S +@@ -0,0 +1,57 @@ ++/* Thread-local storage handling in the ELF dynamic linker. i386 version. ++ Copyright (C) 2025 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++ ++ .text ++#ifdef SHARED ++# define USE_FNSAVE ++# define MINIMUM_ALIGNMENT 4 ++# define STATE_SAVE_ALIGNMENT 4 ++# define ___tls_get_addr _____tls_get_addr_fnsave ++# include "tls_get_addr.h" ++# undef ___tls_get_addr ++# undef MINIMUM_ALIGNMENT ++# undef USE_FNSAVE ++ ++# define MINIMUM_ALIGNMENT 16 ++ ++# define USE_FXSAVE ++# define STATE_SAVE_ALIGNMENT 16 ++# define ___tls_get_addr _____tls_get_addr_fxsave ++# include "tls_get_addr.h" ++# undef ___tls_get_addr ++# undef USE_FXSAVE ++ ++# define USE_XSAVE ++# define STATE_SAVE_ALIGNMENT 64 ++# define ___tls_get_addr _____tls_get_addr_xsave ++# include "tls_get_addr.h" ++# undef ___tls_get_addr ++# undef USE_XSAVE ++ ++# define USE_XSAVEC ++# define STATE_SAVE_ALIGNMENT 64 ++# define ___tls_get_addr _____tls_get_addr_xsavec ++# include "tls_get_addr.h" ++# undef ___tls_get_addr ++# undef USE_XSAVEC ++#endif /* SHARED */ +diff --git a/sysdeps/i386/tls_get_addr.h b/sysdeps/i386/tls_get_addr.h +new file mode 100644 +index 0000000000000000..182579872407cefe +--- /dev/null ++++ b/sysdeps/i386/tls_get_addr.h +@@ -0,0 +1,42 @@ ++/* Thread-local storage handling in the ELF dynamic linker. i386 version. ++ Copyright (C) 2025 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 ++ . */ ++ ++ .hidden ___tls_get_addr ++ .global ___tls_get_addr ++ .type ___tls_get_addr,@function ++ ++ /* This function is a wrapper of ___tls_get_addr_internal to ++ preserve caller-saved vector registers. */ ++ ++ cfi_startproc ++ .align 16 ++___tls_get_addr: ++ /* Like all TLS resolvers, preserve call-clobbered registers. ++ We need two scratch regs anyway. */ ++ subl $32, %esp ++ cfi_adjust_cfa_offset (32) ++ movl %ecx, 20(%esp) ++ movl %edx, 24(%esp) ++#include "tls-get-addr-wrapper.h" ++ movl 20(%esp), %ecx ++ movl 24(%esp), %edx ++ addl $32, %esp ++ cfi_adjust_cfa_offset (-32) ++ ret ++ cfi_endproc ++ .size ___tls_get_addr, .-___tls_get_addr +diff --git a/sysdeps/loongarch/preconfigure b/sysdeps/loongarch/preconfigure +index dfc7ecfd9e529710..6b015ae5dc649630 100644 +--- a/sysdeps/loongarch/preconfigure ++++ b/sysdeps/loongarch/preconfigure +@@ -43,6 +43,7 @@ loongarch*) + + + base_machine=loongarch ++ mtls_traditional=trad + ;; + esac + +diff --git a/sysdeps/loongarch/preconfigure.ac b/sysdeps/loongarch/preconfigure.ac +index 67e4357013675645..31e9579e63d8255a 100644 +--- a/sysdeps/loongarch/preconfigure.ac ++++ b/sysdeps/loongarch/preconfigure.ac +@@ -41,6 +41,7 @@ loongarch*) + AC_DEFINE_UNQUOTED([LOONGARCH_ABI_FRLEN], [$abi_flen]) + + base_machine=loongarch ++ mtls_traditional=trad + ;; + esac + +diff --git a/sysdeps/powerpc/Makefile b/sysdeps/powerpc/Makefile +index 5e6cb07ce66decfa..5cdb64f29bac34f3 100644 +--- a/sysdeps/powerpc/Makefile ++++ b/sysdeps/powerpc/Makefile +@@ -28,6 +28,11 @@ tst-cache-ppc-static-dlopen-ENV = LD_LIBRARY_PATH=$(objpfx):$(common-objpfx):$(c + $(objpfx)tst-cache-ppc-static-dlopen.out: $(objpfx)mod-cache-ppc.so + + $(objpfx)tst-cache-ppc: $(objpfx)mod-cache-ppc.so ++ ++# The test checks if the __tls_get_addr does not clobber caller-saved ++# register, so disable the powerpc specific optimization to force a ++# __tls_get_addr call. ++LDFLAGS-tst-tls23-mod.so = -Wl,--no-tls-get-addr-optimize + endif + + ifneq (no,$(multi-arch)) +diff --git a/sysdeps/x86/Makefile b/sysdeps/x86/Makefile +index 01b0192ddf5e23ca..f64cee3cd9a13c3e 100644 +--- a/sysdeps/x86/Makefile ++++ b/sysdeps/x86/Makefile +@@ -4,7 +4,13 @@ endif + + ifeq ($(subdir),elf) + sysdep_routines += get-cpuid-feature-leaf +-sysdep-dl-routines += dl-get-cpu-features ++sysdep-dl-routines += \ ++ dl-get-cpu-features \ ++ dl-tlsdesc \ ++ tls_get_addr \ ++ tlsdesc \ ++# sysdep-dl-routines ++ + sysdep_headers += \ + bits/platform/features.h \ + bits/platform/x86.h \ +@@ -113,6 +119,14 @@ $(objpfx)tst-gnu2-tls2-x86-noxsavexsavec.out: \ + $(objpfx)tst-gnu2-tls2mod0.so \ + $(objpfx)tst-gnu2-tls2mod1.so \ + $(objpfx)tst-gnu2-tls2mod2.so ++ ++CFLAGS-tst-tls23.c += -msse2 ++CFLAGS-tst-tls23-mod.c += -msse2 -mtune=haswell ++ ++LDFLAGS-tst-tls23 += -rdynamic ++tst-tls23-mod.so-no-z-defs = yes ++ ++$(objpfx)tst-tls23-mod.so: $(libsupport) + endif + + ifeq ($(subdir),math) +diff --git a/sysdeps/x86/sysdep.h b/sysdeps/x86/sysdep.h +index 1d6cabd816bf84cc..d5f5ec0eccd242ab 100644 +--- a/sysdeps/x86/sysdep.h ++++ b/sysdeps/x86/sysdep.h +@@ -183,6 +183,29 @@ + + #define atom_text_section .section ".text.atom", "ax" + ++#ifndef DL_STACK_ALIGNMENT ++/* Due to GCC bug: ++ ++ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58066 ++ ++ __tls_get_addr may be called with 8-byte/4-byte stack alignment. ++ Although this bug has been fixed in GCC 4.9.4, 5.3 and 6, we can't ++ assume that stack will be always aligned at 16 bytes. */ ++# ifdef __x86_64__ ++# define DL_STACK_ALIGNMENT 8 ++# define MINIMUM_ALIGNMENT 16 ++# else ++# define DL_STACK_ALIGNMENT 4 ++# endif ++#endif ++ ++/* True if _dl_runtime_resolve/_dl_tlsdesc_dynamic should align stack for ++ STATE_SAVE or align stack to MINIMUM_ALIGNMENT bytes before calling ++ _dl_fixup/__tls_get_addr. */ ++#define DL_RUNTIME_RESOLVE_REALIGN_STACK \ ++ (STATE_SAVE_ALIGNMENT > DL_STACK_ALIGNMENT \ ++ || MINIMUM_ALIGNMENT > DL_STACK_ALIGNMENT) ++ + #endif /* __ASSEMBLER__ */ + + #endif /* _X86_SYSDEP_H */ +diff --git a/sysdeps/x86/tst-tls23.c b/sysdeps/x86/tst-tls23.c +new file mode 100644 +index 0000000000000000..6130d91cf88030dc +--- /dev/null ++++ b/sysdeps/x86/tst-tls23.c +@@ -0,0 +1,22 @@ ++#ifndef __x86_64__ ++#include ++ ++#define IS_SUPPORTED() CPU_FEATURE_ACTIVE (SSE2) ++#endif ++ ++/* Set XMM0...XMM7 to all 1s. */ ++#define PREPARE_MALLOC() \ ++{ \ ++ asm volatile ("pcmpeqd %%xmm0, %%xmm0" : : : "xmm0" ); \ ++ asm volatile ("pcmpeqd %%xmm1, %%xmm1" : : : "xmm1" ); \ ++ asm volatile ("pcmpeqd %%xmm2, %%xmm2" : : : "xmm2" ); \ ++ asm volatile ("pcmpeqd %%xmm3, %%xmm3" : : : "xmm3" ); \ ++ asm volatile ("pcmpeqd %%xmm4, %%xmm4" : : : "xmm4" ); \ ++ asm volatile ("pcmpeqd %%xmm5, %%xmm5" : : : "xmm5" ); \ ++ asm volatile ("pcmpeqd %%xmm6, %%xmm6" : : : "xmm6" ); \ ++ asm volatile ("pcmpeqd %%xmm7, %%xmm7" : : : "xmm7" ); \ ++} ++ ++#include ++ ++v2di v1, v2, v3; +diff --git a/sysdeps/x86/tst-tls23.h b/sysdeps/x86/tst-tls23.h +new file mode 100644 +index 0000000000000000..21cee4ca0761967c +--- /dev/null ++++ b/sysdeps/x86/tst-tls23.h +@@ -0,0 +1,35 @@ ++/* Test that __tls_get_addr preserves XMM registers. ++ Copyright (C) 2025 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 ++ . */ ++ ++#include ++ ++typedef long long v2di __attribute__((vector_size(16))); ++extern v2di v1, v2, v3; ++ ++#define BEFORE_TLS_CALL() \ ++ v1 = __extension__(v2di){0, 0}; \ ++ v2 = __extension__(v2di){0, 0}; ++ ++#define AFTER_TLS_CALL() \ ++ v3 = __extension__(v2di){0, 0}; \ ++ asm volatile ("" : "+x" (v3)); \ ++ union { v2di x; long long a[2]; } u; \ ++ u.x = v3; \ ++ TEST_VERIFY_EXIT (u.a[0] == 0 && u.a[1] == 0); ++ ++#include +diff --git a/sysdeps/x86_64/Makefile b/sysdeps/x86_64/Makefile +index 579bb33ada0e5f16..a738e0178220d9ca 100644 +--- a/sysdeps/x86_64/Makefile ++++ b/sysdeps/x86_64/Makefile +@@ -41,9 +41,6 @@ ifeq ($(subdir),elf) + CFLAGS-.os += $(if $(filter $(@F),$(patsubst %,%.os,$(all-rtld-routines))),\ + -mno-mmx) + +-sysdep-dl-routines += tlsdesc dl-tlsdesc tls_get_addr +- +-tests += ifuncmain8 + modules-names += ifuncmod8 + + $(objpfx)ifuncmain8: $(objpfx)ifuncmod8.so +diff --git a/sysdeps/x86_64/dl-tlsdesc.S b/sysdeps/x86_64/dl-tlsdesc.S +index 057a10862afd6208..586079291af71811 100644 +--- a/sysdeps/x86_64/dl-tlsdesc.S ++++ b/sysdeps/x86_64/dl-tlsdesc.S +@@ -22,7 +22,6 @@ + #include + #include + #include "tlsdesc.h" +-#include "dl-trampoline-save.h" + + /* Area on stack to save and restore registers used for parameter + passing when calling _dl_tlsdesc_dynamic. */ +diff --git a/sysdeps/x86_64/dl-trampoline.S b/sysdeps/x86_64/dl-trampoline.S +index 87c5137837f01a63..4c11fcf032c6544b 100644 +--- a/sysdeps/x86_64/dl-trampoline.S ++++ b/sysdeps/x86_64/dl-trampoline.S +@@ -22,7 +22,6 @@ + #include + #include + #include +-#include "dl-trampoline-save.h" + + /* Area on stack to save and restore registers used for parameter + passing when calling _dl_fixup. */ diff --git a/glibc-RHEL-110535-2.patch b/glibc-upstream-2.39-256.patch similarity index 86% rename from glibc-RHEL-110535-2.patch rename to glibc-upstream-2.39-256.patch index 91b33ad..8226a1c 100644 --- a/glibc-RHEL-110535-2.patch +++ b/glibc-upstream-2.39-256.patch @@ -18,19 +18,14 @@ Date: Mon Aug 18 09:06:48 2025 -0700 Reviewed-by: Sam James (cherry picked from commit bd4628f3f18ac312408782eea450429c6f044860) - -Conflicts: - sysdeps/x86/Makefile - (adjust for context differences) - diff --git a/sysdeps/x86/Makefile b/sysdeps/x86/Makefile -index 01b0192ddf5e23ca..73bfaaf393775dda 100644 +index f64cee3cd9a13c3e..c814060e08b3ceeb 100644 --- a/sysdeps/x86/Makefile +++ b/sysdeps/x86/Makefile -@@ -113,6 +113,15 @@ $(objpfx)tst-gnu2-tls2-x86-noxsavexsavec.out: \ - $(objpfx)tst-gnu2-tls2mod0.so \ - $(objpfx)tst-gnu2-tls2mod1.so \ - $(objpfx)tst-gnu2-tls2mod2.so +@@ -127,6 +127,15 @@ LDFLAGS-tst-tls23 += -rdynamic + tst-tls23-mod.so-no-z-defs = yes + + $(objpfx)tst-tls23-mod.so: $(libsupport) + +tests-special += $(objpfx)check-gnu2-tls.out + @@ -58,10 +53,10 @@ index 33dbd67b64c3ab5e..06f414bc148340bd 100644 + } } diff --git a/sysdeps/x86_64/Makefile b/sysdeps/x86_64/Makefile -index 579bb33ada0e5f16..06d8c27473c22a0e 100644 +index a738e0178220d9ca..c97b3ac13af248c0 100644 --- a/sysdeps/x86_64/Makefile +++ b/sysdeps/x86_64/Makefile -@@ -218,15 +218,6 @@ $(objpfx)check-dt-x86-64-plt.out: $(common-objpfx)libc.so +@@ -215,15 +215,6 @@ $(objpfx)check-dt-x86-64-plt.out: $(common-objpfx)libc.so | grep GLIBC_ABI_DT_X86_64_PLT > $@; \ $(evaluate-test) generated += check-dt-x86-64-plt.out diff --git a/glibc-RHEL-110535-3.patch b/glibc-upstream-2.39-257.patch similarity index 94% rename from glibc-RHEL-110535-3.patch rename to glibc-upstream-2.39-257.patch index 8cf612a..01f5fcd 100644 --- a/glibc-RHEL-110535-3.patch +++ b/glibc-upstream-2.39-257.patch @@ -23,10 +23,10 @@ Date: Mon Jul 28 12:16:11 2025 -0700 (cherry picked from commit ed1b7a5a489ab555a27fad9c101ebe2e1c1ba881) diff --git a/sysdeps/i386/Makefile b/sysdeps/i386/Makefile -index a2e8c0b12822be0b..7d799454e0b4e990 100644 +index ee6470d78e856315..c0c017b899ebccbe 100644 --- a/sysdeps/i386/Makefile +++ b/sysdeps/i386/Makefile -@@ -58,6 +58,15 @@ $(objpfx)tst-ld-sse-use.out: ../sysdeps/i386/tst-ld-sse-use.sh $(objpfx)ld.so +@@ -60,6 +60,15 @@ $(objpfx)tst-ld-sse-use.out: ../sysdeps/i386/tst-ld-sse-use.sh $(objpfx)ld.so @echo "Checking ld.so for SSE register use. This will take a few seconds..." $(BASH) $< $(objpfx) '$(NM)' '$(OBJDUMP)' '$(READELF)' > $@; \ $(evaluate-test) diff --git a/glibc-upstream-2.39-258.patch b/glibc-upstream-2.39-258.patch new file mode 100644 index 0000000..52a8a0f --- /dev/null +++ b/glibc-upstream-2.39-258.patch @@ -0,0 +1,61 @@ +commit fffc2df8a3e2c8cda2991063d23086360268b777 +Author: Florian Weimer +Date: Fri May 16 19:53:09 2025 +0200 + + Optimize __libc_tsd_* thread variable access + + These variables are not exported, and libc.so TLS is initial-exec + anyway. Declare these variables as hidden and use the initial-exec + TLS model. + + Reviewed-by: Frédéric Bérat + (cherry picked from commit a894f04d877653bea1639fc9a4adf73bd9347bf4) + +diff --git a/include/ctype.h b/include/ctype.h +index ae078a63d355af61..a15e5b66781535d4 100644 +--- a/include/ctype.h ++++ b/include/ctype.h +@@ -29,9 +29,12 @@ libc_hidden_proto (toupper) + # define CTYPE_EXTERN_INLINE extern inline + # endif + +-extern __thread const uint16_t * __libc_tsd_CTYPE_B; +-extern __thread const int32_t * __libc_tsd_CTYPE_TOUPPER; +-extern __thread const int32_t * __libc_tsd_CTYPE_TOLOWER; ++extern __thread const uint16_t * __libc_tsd_CTYPE_B ++ attribute_hidden attribute_tls_model_ie; ++extern __thread const int32_t * __libc_tsd_CTYPE_TOUPPER ++ attribute_hidden attribute_tls_model_ie; ++extern __thread const int32_t * __libc_tsd_CTYPE_TOLOWER ++ attribute_hidden attribute_tls_model_ie; + + + CTYPE_EXTERN_INLINE const uint16_t ** __attribute__ ((const)) +diff --git a/include/rpc/rpc.h b/include/rpc/rpc.h +index 936ea3cebb8101e1..ba967833ad8d8ac3 100644 +--- a/include/rpc/rpc.h ++++ b/include/rpc/rpc.h +@@ -45,7 +45,8 @@ extern void __rpc_thread_key_cleanup (void) attribute_hidden; + + extern void __rpc_thread_destroy (void) attribute_hidden; + +-extern __thread struct rpc_thread_variables *__libc_tsd_RPC_VARS; ++extern __thread struct rpc_thread_variables *__libc_tsd_RPC_VARS ++ attribute_hidden attribute_tls_model_ie; + + #define RPC_THREAD_VARIABLE(x) (__rpc_thread_variables()->x) + +diff --git a/locale/localeinfo.h b/locale/localeinfo.h +index bc8e92e4dca80d62..c3249d371537ad7d 100644 +--- a/locale/localeinfo.h ++++ b/locale/localeinfo.h +@@ -237,7 +237,8 @@ extern struct __locale_struct _nl_global_locale attribute_hidden; + /* This fetches the thread-local locale_t pointer, either one set with + uselocale or &_nl_global_locale. */ + #define _NL_CURRENT_LOCALE __libc_tsd_LOCALE +-extern __thread locale_t __libc_tsd_LOCALE; ++extern __thread locale_t __libc_tsd_LOCALE ++ attribute_hidden attribute_tls_model_ie; + + /* For static linking it is desireable to avoid always linking in the code + and data for every category when we can tell at link time that they are diff --git a/glibc.spec b/glibc.spec index a643d4f..7d67aa6 100644 --- a/glibc.spec +++ b/glibc.spec @@ -80,6 +80,8 @@ # glibc_shell_* below. %undefine _auto_set_build_flags +%define man_pages_version 6.06-3.el10 + ############################################################################## # Utility functions for pre/post scripts. Stick them at the beginning of # any lua %pre, %post, %postun, etc. sections to have them expand into @@ -138,7 +140,7 @@ end} Summary: The GNU libc libraries Name: glibc Version: %{glibcversion} -Release: 46%{?dist}.4.alma.1 +Release: 58%{?dist}.2.alma.1 # Licenses: # @@ -203,6 +205,12 @@ Source10: wrap-find-debuginfo.sh Source11: parse-SUPPORTED.py # Include in the source RPM for reference. Source12: ChangeLog.old +Source13: verify-ld-so-abi.sh +Source14: ld-so-abi-aarch64.baseline +Source15: ld-so-abi-ppc64le.baseline +Source16: ld-so-abi-riscv64.baseline +Source17: ld-so-abi-s390x.baseline +Source18: ld-so-abi-x86_64.baseline # glibc_ldso: ABI-specific program interpreter name. Used for debuginfo # extraction (wrap-find-debuginfo.sh) and smoke testing ($run_ldso below). @@ -572,16 +580,166 @@ Patch262: glibc-RHEL-104151.patch Patch263: glibc-RHEL-95246-1.patch Patch264: glibc-RHEL-95246-2.patch Patch265: glibc-RHEL-105324.patch -Patch266: glibc-RHEL-104853-1.patch -Patch267: glibc-RHEL-104853-2.patch -Patch268: glibc-RHEL-104853-3.patch -Patch269: glibc-RHEL-104853-4.patch -Patch270: glibc-RHEL-110535-1.patch -Patch271: glibc-RHEL-110949-1.patch -Patch272: glibc-RHEL-110535-2.patch -Patch273: glibc-RHEL-110535-3.patch -Patch274: glibc-RHEL-110949-2.patch -Patch275: glibc-RHEL-114263.patch +Patch266: glibc-RHEL-72564-1.patch +Patch267: glibc-RHEL-72564-2.patch +Patch268: glibc-RHEL-107540-1.patch +Patch269: glibc-RHEL-107540-2.patch +Patch270: glibc-RHEL-107540-3.patch +Patch271: glibc-RHEL-106562-1.patch +Patch272: glibc-RHEL-106562-2.patch +Patch273: glibc-RHEL-106562-3.patch +Patch274: glibc-RHEL-106562-4.patch +Patch275: glibc-RHEL-106562-5.patch +Patch276: glibc-RHEL-106562-6.patch +Patch277: glibc-RHEL-106562-7.patch +Patch278: glibc-RHEL-106562-8.patch +Patch279: glibc-RHEL-106562-9.patch +Patch280: glibc-RHEL-106562-10.patch +Patch281: glibc-RHEL-106562-11.patch +Patch282: glibc-RHEL-106562-12.patch +Patch283: glibc-RHEL-106562-13.patch +Patch284: glibc-RHEL-106562-14.patch +Patch285: glibc-RHEL-106562-15.patch +Patch286: glibc-RHEL-106562-16.patch +Patch287: glibc-RHEL-106562-17.patch +Patch288: glibc-RHEL-106562-18.patch +Patch289: glibc-RHEL-106562-19.patch +Patch290: glibc-RHEL-106562-20.patch +Patch291: glibc-RHEL-106562-21.patch +Patch292: glibc-RHEL-106562-22.patch +Patch293: glibc-RHEL-106562-23.patch +Patch294: glibc-RHEL-106562-24.patch +Patch295: glibc-RHEL-107861-1.patch +Patch296: glibc-RHEL-107861-2.patch +Patch297: glibc-RHEL-58357-1.patch +Patch298: glibc-RHEL-58357-2.patch +Patch299: glibc-RHEL-58357-3.patch +Patch300: glibc-RHEL-58357-4.patch +Patch301: glibc-RHEL-58357-5.patch +Patch302: glibc-RHEL-58357-6.patch +Patch303: glibc-RHEL-58357-7.patch +Patch304: glibc-RHEL-58357-8.patch +Patch305: glibc-RHEL-58357-9.patch +Patch306: glibc-RHEL-58357-10.patch +Patch307: glibc-RHEL-58357-11.patch +Patch308: glibc-RHEL-107695-1.patch +Patch309: glibc-RHEL-107695-2.patch +Patch310: glibc-RHEL-107695-3.patch +Patch311: glibc-RHEL-107695-4.patch +Patch312: glibc-RHEL-107695-5.patch +Patch313: glibc-RHEL-107695-6.patch +Patch314: glibc-RHEL-107695-7.patch +Patch315: glibc-RHEL-107695-8.patch +Patch316: glibc-RHEL-107695-9.patch +Patch317: glibc-RHEL-107695-10.patch +Patch318: glibc-RHEL-107695-11.patch +Patch319: glibc-RHEL-107695-12.patch +Patch320: glibc-RHEL-107695-13.patch +Patch321: glibc-RHEL-107695-14.patch +Patch322: glibc-RHEL-107695-15.patch +Patch323: glibc-RHEL-107695-16.patch +Patch324: glibc-RHEL-107695-17.patch +Patch325: glibc-RHEL-107695-18.patch +Patch326: glibc-RHEL-107695-19.patch +Patch327: glibc-RHEL-108475-1.patch +Patch328: glibc-RHEL-108475-2.patch +Patch329: glibc-RHEL-108974-1.patch +Patch330: glibc-RHEL-108974-2.patch +Patch331: glibc-RHEL-108974-3.patch +Patch332: glibc-RHEL-108974-4.patch +Patch333: glibc-RHEL-108974-5.patch +Patch334: glibc-RHEL-108974-6.patch +Patch335: glibc-RHEL-108974-7.patch +Patch336: glibc-RHEL-108974-8.patch +Patch337: glibc-RHEL-108974-9.patch +Patch338: glibc-RHEL-108974-10.patch +Patch339: glibc-RHEL-108974-11.patch +Patch340: glibc-RHEL-108974-12.patch +Patch341: glibc-RHEL-108974-13.patch +Patch342: glibc-RHEL-108974-14.patch +Patch343: glibc-RHEL-108974-15.patch +Patch344: glibc-RHEL-108974-16.patch +Patch345: glibc-RHEL-108974-17.patch +Patch346: glibc-RHEL-108974-18.patch +Patch347: glibc-RHEL-108974-19.patch +Patch348: glibc-RHEL-108974-20.patch +Patch349: glibc-RHEL-108974-21.patch +Patch350: glibc-RHEL-108974-22.patch +Patch351: glibc-RHEL-108974-23.patch +Patch352: glibc-RHEL-108974-24.patch +Patch353: glibc-RHEL-108974-25.patch +Patch354: glibc-RHEL-108974-26.patch +Patch355: glibc-RHEL-108974-27.patch +Patch356: glibc-RHEL-108974-28.patch +Patch357: glibc-RHEL-108974-29.patch +Patch358: glibc-RHEL-108974-30.patch +Patch359: glibc-RHEL-108974-31.patch +Patch360: glibc-RHEL-108974-32.patch +Patch361: glibc-RHEL-108974-33.patch +Patch362: glibc-RHEL-108974-34.patch +Patch363: glibc-RHEL-108823-1.patch +Patch364: glibc-RHEL-108823-2.patch +Patch365: glibc-RHEL-108823-3.patch +Patch366: glibc-RHEL-108823-4.patch +Patch367: glibc-RHEL-108823-5.patch +Patch368: glibc-RHEL-108823-6.patch +Patch369: glibc-RHEL-108823-7.patch +Patch370: glibc-RHEL-108823-8.patch +Patch371: glibc-RHEL-108823-9.patch +Patch372: glibc-RHEL-108823-10.patch +Patch373: glibc-RHEL-108823-11.patch +Patch374: glibc-RHEL-108823-12.patch +Patch375: glibc-RHEL-108823-13.patch +Patch376: glibc-RHEL-108823-14.patch +# glibc-2.39-212-gb027d5b145 is glibc-RHEL-105324.patch. +Patch377: glibc-upstream-2.39-213.patch +Patch378: glibc-upstream-2.39-214.patch +Patch379: glibc-upstream-2.39-215.patch +Patch380: glibc-upstream-2.39-216.patch +Patch381: glibc-upstream-2.39-217.patch +Patch382: glibc-upstream-2.39-218.patch +Patch383: glibc-upstream-2.39-219.patch +Patch384: glibc-upstream-2.39-220.patch +Patch385: glibc-upstream-2.39-221.patch +Patch386: glibc-upstream-2.39-222.patch +Patch387: glibc-upstream-2.39-223.patch +Patch388: glibc-upstream-2.39-224.patch +Patch389: glibc-upstream-2.39-225.patch +# glibc-2.39-226-g42a8cb7560 is glibc-RHEL-108475-1.patch. +# glibc-2.39-227-gf0e8d04eef is glibc-RHEL-108475-2.patch. +Patch390: glibc-upstream-2.39-228.patch +Patch391: glibc-upstream-2.39-229.patch +Patch392: glibc-upstream-2.39-230.patch +Patch393: glibc-upstream-2.39-231.patch +Patch394: glibc-upstream-2.39-232.patch +Patch395: glibc-upstream-2.39-233.patch +Patch396: glibc-upstream-2.39-234.patch +Patch397: glibc-upstream-2.39-235.patch +Patch398: glibc-upstream-2.39-236.patch +Patch399: glibc-upstream-2.39-237.patch +Patch400: glibc-upstream-2.39-238.patch +Patch401: glibc-upstream-2.39-239.patch +Patch402: glibc-upstream-2.39-240.patch +Patch403: glibc-upstream-2.39-241.patch +Patch404: glibc-upstream-2.39-242.patch +Patch405: glibc-upstream-2.39-243.patch +Patch406: glibc-upstream-2.39-244.patch +Patch407: glibc-upstream-2.39-245.patch +Patch408: glibc-upstream-2.39-246.patch +Patch409: glibc-upstream-2.39-247.patch +Patch410: glibc-upstream-2.39-248.patch +Patch411: glibc-upstream-2.39-249.patch +Patch412: glibc-upstream-2.39-250.patch +Patch413: glibc-upstream-2.39-251.patch +Patch414: glibc-upstream-2.39-252.patch +Patch415: glibc-upstream-2.39-253.patch +# glibc-2.39-254-g3b6c8ea878 is glibc-RHEL-106562-16.patch. +# glibc-2.39-255-g1f17635507 is glibc-RHEL-106562-17.patch. +Patch416: glibc-upstream-2.39-256.patch +Patch417: glibc-upstream-2.39-257.patch +Patch418: glibc-upstream-2.39-258.patch +Patch419: glibc-RHEL-114264.patch +Patch420: glibc-RHEL-113196.patch ############################################################################## # Continued list of core "glibc" package information: @@ -643,6 +801,10 @@ BuildRequires: audit-libs-devel >= 1.1.3, sed >= 3.95, libcap-devel, gettext BuildRequires: procps-ng, util-linux, gawk BuildRequires: systemtap-sdt-devel +%if %{with testsuite} +BuildRequires: gdb +%endif + %if %{with valgrind} # Require valgrind for smoke testing the dynamic loader to make sure we # have not broken valgrind. @@ -1431,6 +1593,12 @@ diff -u \ --label "glibc localedata/SUPPORTED" localedata/SUPPORTED.glibc rm localedata/SUPPORTED.spec localedata/SUPPORTED.glibc +# Prepare for ld.so ABI check +cp %{SOURCE13} . +chmod +x verify-ld-so-abi.sh + +cp %{_sourcedir}/*.baseline . + ############################################################################## # Build glibc... ############################################################################## @@ -1593,6 +1761,7 @@ build() %ifarch aarch64 --enable-memory-tagging \ %endif + --with-man-pages=%{man_pages_version} \ --disable-crypt \ --disable-build-nscd \ --disable-nscd \ @@ -2211,6 +2380,11 @@ $run_ldso /usr/bin/valgrind --error-exitcode=1 \ %endif %endif +# Verify ld.so ABI. +if test -f "ld-so-abi-%{_arch}.baseline" ; then + ./verify-ld-so-abi.sh %{_arch} %{glibc_sysroot}%{_prefix}%{glibc_ldso} +fi + %endif @@ -2588,22 +2762,68 @@ update_gconv_modules_cache () %endif %changelog -* Wed Nov 05 2025 Eduard Abdullin - 2.39-46.4.alma.1 +* Tue Nov 11 2025 Eduard Abdullin - 2.39-58.2.alma.1 - Overwrite target for x86_64_v2 - Add /usr/lib64/lp64d to ricv64 -* Mon Sep 22 2025 Arjun Shankar - 2.39-46.4 -- nss: Fix incorrect/empty results when merging groups (RHEL-114263) +* Tue Sep 23 2025 Frédéric Bérat - 2.39-58.2 +- x86-64: Unconditionally run elf/check-dt-x86-64-plt ABI test (RHEL-113196) -* Fri Sep 05 2025 Arjun Shankar - 2.39-46.3 -- x86-64: Provide GLIBC_ABI_GNU2_TLS symbol version (RHEL-110535) -- x86-64: Provide GLIBC_ABI_DT_X86_64_PLT symbol version (RHEL-110949) +* Mon Sep 22 2025 Arjun Shankar - 2.39-58.1 +- nss: Fix incorrect/empty results when merging groups (RHEL-114264) -* Wed Sep 03 2025 Arjun Shankar - 2.39-46.2 -- Handle load segment gaps in _dl_find_object (RHEL-104853) +* Thu Aug 21 2025 Florian Weimer - 2.39-58 +- Use Requires(pre): libgcc%{_isa} to break libgcc cycle (RHEL-110559) -* Mon Aug 25 2025 Patsy Griffin - 2.39-46.1 -- Use Requires(pre): libgcc%%{_isa} to break libgcc cycle (RHEL-110560) +* Thu Aug 21 2025 Arjun Shankar - 2.39-57 +- Sync with upstream branch release/2.39/master (RHEL-109536) +- Upstream commit: fffc2df8a3e2c8cda2991063d23086360268b777 +- Extend struct r_debug to support multiple namespaces (RHEL-101985) +- Fix a potential crash in the dynamic loader when processing specific + symbol versions (RHEL-109683) +- Signal la_objopen for ld.so with dlmopen (RHEL-109693) +- Switch to main malloc after final ld.so self-relocation (RHEL-109703) +- Prevent ld.so from asserting and crashing during audited library loads + (RHEL-109702) +- x86-64: Provide GLIBC_ABI_DT_X86_64_PLT symbol version (RHEL-109621) +- x86-64: Provide GLIBC_ABI_GNU2_TLS symbol version (RHEL-109625) +- Ensure fallback initialization of ctype TLS data pointers to fix segfaults in + programs using dlmopen or auditors (RHEL-72018) +- Handle load segment gaps in _dl_find_object (RHEL-104854) +- AArch64: Improve codegen in SVE log1p +- AArch64: Optimize inverse trig functions +- AArch64: Avoid memset ifunc in cpu-features.c [BZ #33112] + +* Tue Aug 19 2025 Arjun Shankar - 2.39-56 +- Add FUSE based tests for fchmod, lstat, and mkstemp (RHEL-108823) + +* Wed Aug 13 2025 Arjun Shankar - 2.39-55 +- Various updates to the manual from upstream (RHEL-108974) + +* Mon Aug 11 2025 Frédéric Bérat - 2.39-54 +- Fix memory leak after fdopen seek failure (RHEL-108475) + +* Wed Aug 06 2025 Frédéric Bérat - 2.39-53 +- Updated glibc to support Linux 6.15 kernel system calls and constants. + (RHEL-107695) + +* Wed Aug 06 2025 Frédéric Bérat - 2.39-52 +- Add `sched_setattr` and `sched_getattr` functions (RHEL-58357) + +* Wed Aug 06 2025 Frédéric Bérat - 2.39-51 +- Enhanced glibc documentation for core descriptor APIs. (RHEL-107861) + +* Wed Aug 06 2025 Arjun Shankar - 2.39-50 +- Improve test coverage (RHEL-106562) + +* Tue Aug 05 2025 Florian Weimer - 2.39-49 +- x86_64, aarch64: More CPU output in ld.so --list-diagnostics (RHEL-107540) + +* Thu Jul 31 2025 Frédéric Bérat - 2.39-48 +- Add support for new IBM Z17 hardware in glibc (RHEL-72564) + +* Tue Jul 29 2025 Frédéric Bérat - 2.39-47 +- Add ld-so-abi-check * Thu Jul 24 2025 Florian Weimer - 2.39-46 - CVE-2025-8058: Double free in regcomp (RHEL-105324) diff --git a/ld-so-abi-aarch64.baseline b/ld-so-abi-aarch64.baseline new file mode 100644 index 0000000..f851c7b --- /dev/null +++ b/ld-so-abi-aarch64.baseline @@ -0,0 +1,545 @@ +--- _rtld_global_ro --- +/* offset | size */ type = struct rtld_global_ro { +/* 0 | 4 */ int _dl_debug_mask; +/* XXX 4-byte hole */ +/* 8 | 8 */ const char *_dl_platform; +/* 16 | 8 */ size_t _dl_platformlen; +/* 24 | 8 */ size_t _dl_pagesize; +/* 32 | 8 */ size_t _dl_minsigstacksize; +/* 40 | 4 */ int _dl_inhibit_cache; +/* XXX 4-byte hole */ +/* 48 | 16 */ struct r_scope_elem { +/* 48 | 8 */ struct link_map **r_list; +/* 56 | 4 */ unsigned int r_nlist; +/* XXX 4-byte padding */ + + /* total size (bytes): 16 */ + } _dl_initial_searchlist; +/* 64 | 4 */ int _dl_clktck; +/* 68 | 4 */ int _dl_verbose; +/* 72 | 4 */ int _dl_debug_fd; +/* 76 | 4 */ int _dl_lazy; +/* 80 | 4 */ int _dl_bind_not; +/* 84 | 4 */ int _dl_dynamic_weak; +/* 88 | 4 */ fpu_control_t _dl_fpu_control; +/* XXX 4-byte hole */ +/* 96 | 8 */ uint64_t _dl_hwcap; +/* 104 | 8 */ Elf64_auxv_t *_dl_auxv; +/* 112 | 24 */ struct cpu_features { +/* 112 | 8 */ uint64_t midr_el1; +/* 120 | 4 */ unsigned int zva_size; +/* 124 | 1 */ _Bool bti; +/* 125 | 1 */ uint8_t mte_state; +/* 126 | 1 */ _Bool sve; +/* 127 | 1 */ _Bool prefer_sve_ifuncs; +/* 128 | 1 */ _Bool mops; +/* XXX 7-byte padding */ + + /* total size (bytes): 24 */ + } _dl_aarch64_cpu_features; +/* 136 | 320 */ const char _dl_aarch64_cap_flags[32][10]; +/* 456 | 8 */ const char *_dl_inhibit_rpath; +/* 464 | 8 */ const char *_dl_origin_path; +/* 472 | 8 */ size_t _dl_tls_static_size; +/* 480 | 8 */ size_t _dl_tls_static_align; +/* 488 | 8 */ size_t _dl_tls_static_surplus; +/* 496 | 8 */ const char *_dl_profile; +/* 504 | 8 */ const char *_dl_profile_output; +/* 512 | 8 */ struct r_search_path_elem *_dl_init_all_dirs; +/* 520 | 8 */ const Elf64_Ehdr *_dl_sysinfo_dso; +/* 528 | 8 */ struct link_map *_dl_sysinfo_map; +/* 536 | 8 */ int (*_dl_vdso_clock_gettime64)(clockid_t, struct timespec *); +/* 544 | 8 */ int (*_dl_vdso_gettimeofday)(struct timeval *, void *); +/* 552 | 8 */ int (*_dl_vdso_clock_getres_time64)(clockid_t, struct timespec *); +/* 560 | 8 */ ssize_t (*_dl_vdso_getrandom)(void *, size_t, unsigned int, void *, size_t); +/* 568 | 8 */ uint64_t _dl_hwcap2; +/* 576 | 8 */ uint64_t _dl_hwcap3; +/* 584 | 8 */ uint64_t _dl_hwcap4; +/* 592 | 4 */ enum dso_sort_algorithm _dl_dso_sort_algo; +/* XXX 4-byte hole */ +/* 600 | 8 */ void (*_dl_debug_printf)(const char *, ...); +/* 608 | 8 */ void (*_dl_mcount)(Elf64_Addr, Elf64_Addr); +/* 616 | 8 */ lookup_t (*_dl_lookup_symbol_x)(const char *, struct link_map *, const Elf64_Sym **, struct r_scope_elem **, const struct r_found_version *, int, int, struct link_map *); +/* 624 | 8 */ void *(*_dl_open)(const char *, int, const void *, Lmid_t, int, char **, char **); +/* 632 | 8 */ void (*_dl_close)(void *); +/* 640 | 8 */ int (*_dl_catch_error)(const char **, const char **, _Bool *, void (*)(void *), void *); +/* 648 | 8 */ void (*_dl_error_free)(void *); +/* 656 | 8 */ void *(*_dl_tls_get_addr_soft)(struct link_map *); +/* 664 | 8 */ void (*_dl_libc_freeres)(void); +/* 672 | 8 */ int (*_dl_find_object)(void *, struct dl_find_object *); +/* 680 | 8 */ const struct dlfcn_hook *_dl_dlfcn_hook; +/* 688 | 8 */ struct audit_ifaces *_dl_audit; +/* 696 | 4 */ unsigned int _dl_naudit; +/* XXX 4-byte padding */ + + /* total size (bytes): 704 */ + } +--- _rtld_global --- +/* offset | size */ type = struct rtld_global { +/* 0 | 2688 */ struct link_namespaces _dl_ns[16]; +/* 2688 | 8 */ size_t _dl_nns; +/* 2696 | 48 */ __rtld_lock_recursive_t _dl_load_lock; +/* 2744 | 48 */ __rtld_lock_recursive_t _dl_load_write_lock; +/* 2792 | 48 */ __rtld_lock_recursive_t _dl_load_tls_lock; +/* 2840 | 8 */ unsigned long long _dl_load_adds; +/* 2848 | 8 */ struct link_map *_dl_initfirst; +/* 2856 | 8 */ struct link_map *_dl_profile_map; +/* 2864 | 8 */ unsigned long _dl_num_relocations; +/* 2872 | 8 */ unsigned long _dl_num_cache_relocations; +/* 2880 | 8 */ struct r_search_path_elem *_dl_all_dirs; +/* 2888 | 1216 */ struct link_map { +/* 2888 | 8 */ Elf64_Addr l_addr; +/* 2896 | 8 */ char *l_name; +/* 2904 | 8 */ Elf64_Dyn *l_ld; +/* 2912 | 8 */ struct link_map *l_next; +/* 2920 | 8 */ struct link_map *l_prev; +/* 2928 | 8 */ struct link_map *l_real; +/* 2936 | 8 */ Lmid_t l_ns; +/* 2944 | 8 */ struct libname_list *l_libname; +/* 2952 | 688 */ Elf64_Dyn *l_info[86]; +/* 3640 | 8 */ const Elf64_Phdr *l_phdr; +/* 3648 | 8 */ Elf64_Addr l_entry; +/* 3656 | 2 */ Elf64_Half l_phnum; +/* 3658 | 2 */ Elf64_Half l_ldnum; +/* XXX 4-byte hole */ +/* 3664 | 16 */ struct r_scope_elem { +/* 3664 | 8 */ struct link_map **r_list; +/* 3672 | 4 */ unsigned int r_nlist; +/* XXX 4-byte padding */ + + /* total size (bytes): 16 */ + } l_searchlist; +/* 3680 | 16 */ struct r_scope_elem { +/* 3680 | 8 */ struct link_map **r_list; +/* 3688 | 4 */ unsigned int r_nlist; +/* XXX 4-byte padding */ + + /* total size (bytes): 16 */ + } l_symbolic_searchlist; +/* 3696 | 8 */ struct link_map *l_loader; +/* 3704 | 8 */ struct r_found_version *l_versions; +/* 3712 | 4 */ unsigned int l_nversions; +/* 3716 | 4 */ Elf_Symndx l_nbuckets; +/* 3720 | 4 */ Elf32_Word l_gnu_bitmask_idxbits; +/* 3724 | 4 */ Elf32_Word l_gnu_shift; +/* 3728 | 8 */ const Elf64_Addr *l_gnu_bitmask; +/* 3736 | 8 */ union { +/* 8 */ const Elf32_Word *l_gnu_buckets; +/* 8 */ const Elf_Symndx *l_chain; + + /* total size (bytes): 8 */ + }; +/* 3744 | 8 */ union { +/* 8 */ const Elf32_Word *l_gnu_chain_zero; +/* 8 */ const Elf_Symndx *l_buckets; + + /* total size (bytes): 8 */ + }; +/* 3752 | 4 */ unsigned int l_direct_opencount; +/* 3756: 0 | 4 */ enum {lt_executable, lt_library, lt_loaded} l_type : 2; +/* 3756: 2 | 4 */ unsigned int l_dt_relr_ref : 1; +/* 3756: 3 | 4 */ unsigned int l_relocated : 1; +/* 3756: 4 | 4 */ unsigned int l_init_called : 1; +/* 3756: 5 | 4 */ unsigned int l_global : 1; +/* 3756: 6 | 4 */ unsigned int l_reserved : 2; +/* 3757: 0 | 4 */ unsigned int l_main_map : 1; +/* 3757: 1 | 4 */ unsigned int l_visited : 1; +/* 3757: 2 | 4 */ unsigned int l_map_used : 1; +/* 3757: 3 | 4 */ unsigned int l_map_done : 1; +/* 3757: 4 | 4 */ unsigned int l_phdr_allocated : 1; +/* 3757: 5 | 4 */ unsigned int l_soname_added : 1; +/* 3757: 6 | 4 */ unsigned int l_faked : 1; +/* 3757: 7 | 4 */ unsigned int l_need_tls_init : 1; +/* 3758: 0 | 4 */ unsigned int l_auditing : 1; +/* 3758: 1 | 4 */ unsigned int l_audit_any_plt : 1; +/* 3758: 2 | 4 */ unsigned int l_removed : 1; +/* 3758: 3 | 4 */ unsigned int l_contiguous : 1; +/* 3758: 4 | 4 */ unsigned int l_free_initfini : 1; +/* 3758: 5 | 4 */ unsigned int l_ld_readonly : 1; +/* 3758: 6 | 4 */ unsigned int l_find_object_processed : 1; +/* 3758: 7 | 4 */ unsigned int l_tls_in_slotinfo : 1; +/* 3759 | 1 */ _Bool l_nodelete_active; +/* 3760 | 1 */ _Bool l_nodelete_pending; +/* XXX 3-byte hole */ +/* 3764 | 4 */ unsigned int l_1_needed; +/* 3768 | 16 */ struct r_search_path_struct { +/* 3768 | 8 */ struct r_search_path_elem **dirs; +/* 3776 | 4 */ int malloced; +/* XXX 4-byte padding */ + + /* total size (bytes): 16 */ + } l_rpath_dirs; +/* 3784 | 8 */ struct reloc_result *l_reloc_result; +/* 3792 | 8 */ Elf64_Versym *l_versyms; +/* 3800 | 8 */ const char *l_origin; +/* 3808 | 8 */ Elf64_Addr l_map_start; +/* 3816 | 8 */ Elf64_Addr l_map_end; +/* 3824 | 32 */ struct r_scope_elem *l_scope_mem[4]; +/* 3856 | 8 */ size_t l_scope_max; +/* 3864 | 8 */ struct r_scope_elem **l_scope; +/* 3872 | 16 */ struct r_scope_elem *l_local_scope[2]; +/* 3888 | 16 */ struct r_file_id { +/* 3888 | 8 */ dev_t dev; +/* 3896 | 8 */ ino64_t ino; + + /* total size (bytes): 16 */ + } l_file_id; +/* 3904 | 16 */ struct r_search_path_struct { +/* 3904 | 8 */ struct r_search_path_elem **dirs; +/* 3912 | 4 */ int malloced; +/* XXX 4-byte padding */ + + /* total size (bytes): 16 */ + } l_runpath_dirs; +/* 3920 | 8 */ struct link_map **l_initfini; +/* 3928 | 8 */ struct link_map_reldeps *l_reldeps; +/* 3936 | 4 */ unsigned int l_reldepsmax; +/* 3940 | 4 */ unsigned int l_used; +/* 3944 | 4 */ Elf64_Word l_feature_1; +/* 3948 | 4 */ Elf64_Word l_flags_1; +/* 3952 | 4 */ Elf64_Word l_flags; +/* 3956 | 4 */ int l_idx; +/* 3960 | 24 */ struct link_map_machine { +/* 3960 | 8 */ Elf64_Addr plt; +/* 3968 | 8 */ void *tlsdesc_table; +/* 3976 | 1 */ _Bool bti_fail; +/* XXX 7-byte padding */ + + /* total size (bytes): 24 */ + } l_mach; +/* 3984 | 32 */ struct { +/* 3984 | 8 */ const Elf64_Sym *sym; +/* 3992 | 4 */ int type_class; +/* XXX 4-byte hole */ +/* 4000 | 8 */ struct link_map *value; +/* 4008 | 8 */ const Elf64_Sym *ret; + + /* total size (bytes): 32 */ + } l_lookup_cache; +/* 4016 | 8 */ void *l_tls_initimage; +/* 4024 | 8 */ size_t l_tls_initimage_size; +/* 4032 | 8 */ size_t l_tls_blocksize; +/* 4040 | 8 */ size_t l_tls_align; +/* 4048 | 8 */ size_t l_tls_firstbyte_offset; +/* 4056 | 8 */ ptrdiff_t l_tls_offset; +/* 4064 | 8 */ size_t l_tls_modid; +/* 4072 | 8 */ size_t l_tls_dtor_count; +/* 4080 | 8 */ Elf64_Addr l_relro_addr; +/* 4088 | 8 */ size_t l_relro_size; +/* 4096 | 8 */ unsigned long long l_serial; + + /* total size (bytes): 1216 */ + } _dl_rtld_map; +/* 4104 | 256 */ struct auditstate _dl_rtld_auditstate[16]; +/* 4360 | 4 */ Elf64_Word _dl_stack_flags; +/* 4364 | 1 */ _Bool _dl_tls_dtv_gaps; +/* XXX 3-byte hole */ +/* 4368 | 8 */ size_t _dl_tls_max_dtv_idx; +/* 4376 | 8 */ struct dtv_slotinfo_list *_dl_tls_dtv_slotinfo_list; +/* 4384 | 8 */ size_t _dl_tls_static_nelem; +/* 4392 | 8 */ size_t _dl_tls_static_used; +/* 4400 | 8 */ size_t _dl_tls_static_optional; +/* 4408 | 8 */ void *_dl_initial_dtv; +/* 4416 | 8 */ size_t _dl_tls_generation; +/* 4424 | 8 */ struct dl_scope_free_list *_dl_scope_free_list; +/* 4432 | 16 */ list_t _dl_stack_used; +/* 4448 | 16 */ list_t _dl_stack_user; +/* 4464 | 16 */ list_t _dl_stack_cache; +/* 4480 | 8 */ size_t _dl_stack_cache_actsize; +/* 4488 | 8 */ uintptr_t _dl_in_flight_stack; +/* 4496 | 4 */ int _dl_stack_cache_lock; +/* XXX 4-byte padding */ + + /* total size (bytes): 4504 */ + } +--- struct link_map --- +/* offset | size */ type = struct link_map { +/* 0 | 8 */ Elf64_Addr l_addr; +/* 8 | 8 */ char *l_name; +/* 16 | 8 */ Elf64_Dyn *l_ld; +/* 24 | 8 */ struct link_map *l_next; +/* 32 | 8 */ struct link_map *l_prev; +/* 40 | 8 */ struct link_map *l_real; +/* 48 | 8 */ Lmid_t l_ns; +/* 56 | 8 */ struct libname_list *l_libname; +/* 64 | 688 */ Elf64_Dyn *l_info[86]; +/* 752 | 8 */ const Elf64_Phdr *l_phdr; +/* 760 | 8 */ Elf64_Addr l_entry; +/* 768 | 2 */ Elf64_Half l_phnum; +/* 770 | 2 */ Elf64_Half l_ldnum; +/* XXX 4-byte hole */ +/* 776 | 16 */ struct r_scope_elem { +/* 776 | 8 */ struct link_map **r_list; +/* 784 | 4 */ unsigned int r_nlist; +/* XXX 4-byte padding */ + + /* total size (bytes): 16 */ + } l_searchlist; +/* 792 | 16 */ struct r_scope_elem { +/* 792 | 8 */ struct link_map **r_list; +/* 800 | 4 */ unsigned int r_nlist; +/* XXX 4-byte padding */ + + /* total size (bytes): 16 */ + } l_symbolic_searchlist; +/* 808 | 8 */ struct link_map *l_loader; +/* 816 | 8 */ struct r_found_version *l_versions; +/* 824 | 4 */ unsigned int l_nversions; +/* 828 | 4 */ Elf_Symndx l_nbuckets; +/* 832 | 4 */ Elf32_Word l_gnu_bitmask_idxbits; +/* 836 | 4 */ Elf32_Word l_gnu_shift; +/* 840 | 8 */ const Elf64_Addr *l_gnu_bitmask; +/* 848 | 8 */ union { +/* 8 */ const Elf32_Word *l_gnu_buckets; +/* 8 */ const Elf_Symndx *l_chain; + + /* total size (bytes): 8 */ + }; +/* 856 | 8 */ union { +/* 8 */ const Elf32_Word *l_gnu_chain_zero; +/* 8 */ const Elf_Symndx *l_buckets; + + /* total size (bytes): 8 */ + }; +/* 864 | 4 */ unsigned int l_direct_opencount; +/* 868: 0 | 4 */ enum {lt_executable, lt_library, lt_loaded} l_type : 2; +/* 868: 2 | 4 */ unsigned int l_dt_relr_ref : 1; +/* 868: 3 | 4 */ unsigned int l_relocated : 1; +/* 868: 4 | 4 */ unsigned int l_init_called : 1; +/* 868: 5 | 4 */ unsigned int l_global : 1; +/* 868: 6 | 4 */ unsigned int l_reserved : 2; +/* 869: 0 | 4 */ unsigned int l_main_map : 1; +/* 869: 1 | 4 */ unsigned int l_visited : 1; +/* 869: 2 | 4 */ unsigned int l_map_used : 1; +/* 869: 3 | 4 */ unsigned int l_map_done : 1; +/* 869: 4 | 4 */ unsigned int l_phdr_allocated : 1; +/* 869: 5 | 4 */ unsigned int l_soname_added : 1; +/* 869: 6 | 4 */ unsigned int l_faked : 1; +/* 869: 7 | 4 */ unsigned int l_need_tls_init : 1; +/* 870: 0 | 4 */ unsigned int l_auditing : 1; +/* 870: 1 | 4 */ unsigned int l_audit_any_plt : 1; +/* 870: 2 | 4 */ unsigned int l_removed : 1; +/* 870: 3 | 4 */ unsigned int l_contiguous : 1; +/* 870: 4 | 4 */ unsigned int l_free_initfini : 1; +/* 870: 5 | 4 */ unsigned int l_ld_readonly : 1; +/* 870: 6 | 4 */ unsigned int l_find_object_processed : 1; +/* 870: 7 | 4 */ unsigned int l_tls_in_slotinfo : 1; +/* 871 | 1 */ _Bool l_nodelete_active; +/* 872 | 1 */ _Bool l_nodelete_pending; +/* XXX 3-byte hole */ +/* 876 | 4 */ unsigned int l_1_needed; +/* 880 | 16 */ struct r_search_path_struct { +/* 880 | 8 */ struct r_search_path_elem **dirs; +/* 888 | 4 */ int malloced; +/* XXX 4-byte padding */ + + /* total size (bytes): 16 */ + } l_rpath_dirs; +/* 896 | 8 */ struct reloc_result *l_reloc_result; +/* 904 | 8 */ Elf64_Versym *l_versyms; +/* 912 | 8 */ const char *l_origin; +/* 920 | 8 */ Elf64_Addr l_map_start; +/* 928 | 8 */ Elf64_Addr l_map_end; +/* 936 | 32 */ struct r_scope_elem *l_scope_mem[4]; +/* 968 | 8 */ size_t l_scope_max; +/* 976 | 8 */ struct r_scope_elem **l_scope; +/* 984 | 16 */ struct r_scope_elem *l_local_scope[2]; +/* 1000 | 16 */ struct r_file_id { +/* 1000 | 8 */ dev_t dev; +/* 1008 | 8 */ ino64_t ino; + + /* total size (bytes): 16 */ + } l_file_id; +/* 1016 | 16 */ struct r_search_path_struct { +/* 1016 | 8 */ struct r_search_path_elem **dirs; +/* 1024 | 4 */ int malloced; +/* XXX 4-byte padding */ + + /* total size (bytes): 16 */ + } l_runpath_dirs; +/* 1032 | 8 */ struct link_map **l_initfini; +/* 1040 | 8 */ struct link_map_reldeps *l_reldeps; +/* 1048 | 4 */ unsigned int l_reldepsmax; +/* 1052 | 4 */ unsigned int l_used; +/* 1056 | 4 */ Elf64_Word l_feature_1; +/* 1060 | 4 */ Elf64_Word l_flags_1; +/* 1064 | 4 */ Elf64_Word l_flags; +/* 1068 | 4 */ int l_idx; +/* 1072 | 24 */ struct link_map_machine { +/* 1072 | 8 */ Elf64_Addr plt; +/* 1080 | 8 */ void *tlsdesc_table; +/* 1088 | 1 */ _Bool bti_fail; +/* XXX 7-byte padding */ + + /* total size (bytes): 24 */ + } l_mach; +/* 1096 | 32 */ struct { +/* 1096 | 8 */ const Elf64_Sym *sym; +/* 1104 | 4 */ int type_class; +/* XXX 4-byte hole */ +/* 1112 | 8 */ struct link_map *value; +/* 1120 | 8 */ const Elf64_Sym *ret; + + /* total size (bytes): 32 */ + } l_lookup_cache; +/* 1128 | 8 */ void *l_tls_initimage; +/* 1136 | 8 */ size_t l_tls_initimage_size; +/* 1144 | 8 */ size_t l_tls_blocksize; +/* 1152 | 8 */ size_t l_tls_align; +/* 1160 | 8 */ size_t l_tls_firstbyte_offset; +/* 1168 | 8 */ ptrdiff_t l_tls_offset; +/* 1176 | 8 */ size_t l_tls_modid; +/* 1184 | 8 */ size_t l_tls_dtor_count; +/* 1192 | 8 */ Elf64_Addr l_relro_addr; +/* 1200 | 8 */ size_t l_relro_size; +/* 1208 | 8 */ unsigned long long l_serial; + + /* total size (bytes): 1216 */ + } +--- struct pthread --- +/* offset | size */ type = struct pthread { +/* 0 | 192 */ union { +/* 8 */ struct { +/* 0 | 4 */ int multiple_threads; +/* 4 | 4 */ int gscope_flag; + + /* total size (bytes): 8 */ + } header; +/* 192 */ void *__padding[24]; + + /* total size (bytes): 192 */ + }; +/* 192 | 16 */ list_t list; +/* 208 | 4 */ pid_t tid; +/* XXX 4-byte hole */ +/* 216 | 8 */ void *robust_prev; +/* 224 | 24 */ struct robust_list_head { +/* 224 | 8 */ void *list; +/* 232 | 8 */ long futex_offset; +/* 240 | 8 */ void *list_op_pending; + + /* total size (bytes): 24 */ + } robust_head; +/* 248 | 8 */ struct _pthread_cleanup_buffer *cleanup; +/* 256 | 8 */ struct pthread_unwind_buf *cleanup_jmp_buf; +/* 264 | 4 */ int cancelhandling; +/* 268 | 4 */ int flags; +/* 272 | 512 */ struct pthread_key_data specific_1stblock[32]; +/* 784 | 256 */ struct pthread_key_data *specific[32]; +/* 1040 | 1 */ _Bool specific_used; +/* 1041 | 1 */ _Bool report_events; +/* 1042 | 1 */ _Bool user_stack; +/* 1043 | 1 */ _Bool stopped_start; +/* 1044 | 4 */ int setup_failed; +/* 1048 | 4 */ int lock; +/* 1052 | 4 */ unsigned int setxid_futex; +/* 1056 | 8 */ struct pthread *joinid; +/* 1064 | 8 */ void *result; +/* 1072 | 4 */ struct sched_param { +/* 1072 | 4 */ int sched_priority; + + /* total size (bytes): 4 */ + } schedparam; +/* 1076 | 4 */ int schedpolicy; +/* 1080 | 8 */ void *(*start_routine)(void *); +/* 1088 | 8 */ void *arg; +/* 1096 | 24 */ td_eventbuf_t eventbuf; +/* 1120 | 8 */ struct pthread *nextevent; +/* XXX 8-byte hole */ +/* 1136 | 32 */ struct _Unwind_Exception { +/* 1136 | 32 */ union { +/* 32 */ struct { +/* 1136 | 8 */ _Unwind_Exception_Class exception_class; +/* 1144 | 8 */ _Unwind_Exception_Cleanup_Fn exception_cleanup; +/* 1152 | 8 */ _Unwind_Word private_1; +/* 1160 | 8 */ _Unwind_Word private_2; + + /* total size (bytes): 32 */ + }; +/* 16 */ _Unwind_Word unwind_exception_align[2]; + + /* total size (bytes): 32 */ + }; + + /* total size (bytes): 32 */ + } exc; +/* 1168 | 8 */ void *stackblock; +/* 1176 | 8 */ size_t stackblock_size; +/* 1184 | 8 */ size_t guardsize; +/* 1192 | 8 */ size_t reported_guardsize; +/* 1200 | 8 */ struct priority_protection_data *tpp; +/* 1208 | 568 */ struct __res_state { +/* 1208 | 4 */ int retrans; +/* 1212 | 4 */ int retry; +/* 1216 | 8 */ unsigned long options; +/* 1224 | 4 */ int nscount; +/* 1228 | 48 */ struct sockaddr_in nsaddr_list[3]; +/* 1276 | 2 */ unsigned short id; +/* XXX 2-byte hole */ +/* 1280 | 56 */ char *dnsrch[7]; +/* 1336 | 256 */ char defdname[256]; +/* 1592 | 8 */ unsigned long pfcode; +/* 1600: 0 | 4 */ unsigned int ndots : 4; +/* 1600: 4 | 4 */ unsigned int nsort : 4; +/* 1601: 0 | 4 */ unsigned int ipv6_unavail : 1; +/* 1601: 1 | 4 */ unsigned int unused : 23; +/* 1604 | 80 */ struct { +/* 0 | 4 */ struct in_addr addr; +/* 4 | 4 */ uint32_t mask; + } sort_list[10]; +/* XXX 4-byte hole */ +/* 1688 | 8 */ void *__glibc_unused_qhook; +/* 1696 | 8 */ void *__glibc_unused_rhook; +/* 1704 | 4 */ int res_h_errno; +/* 1708 | 4 */ int _vcsock; +/* 1712 | 4 */ unsigned int _flags; +/* XXX 4-byte hole */ +/* 1720 | 56 */ union { +/* 52 */ char pad[52]; +/* 56 */ struct { +/* 1720 | 2 */ uint16_t nscount; +/* 1722 | 6 */ uint16_t nsmap[3]; +/* 1728 | 12 */ int nssocks[3]; +/* 1740 | 2 */ uint16_t nscount6; +/* 1742 | 2 */ uint16_t nsinit; +/* 1744 | 24 */ struct sockaddr_in6 *nsaddrs[3]; +/* 1768 | 8 */ unsigned long long __glibc_extension_index; + + /* total size (bytes): 56 */ + } _ext; + + /* total size (bytes): 56 */ + } _u; + + /* total size (bytes): 568 */ + } res; +/* 1776 | 8 */ internal_sigset_t sigmask; +/* 1784 | 8 */ struct rtld_catch *rtld_catch; +/* 1792 | 1 */ _Bool c11; +/* 1793 | 1 */ _Bool exiting; +/* XXX 2-byte hole */ +/* 1796 | 4 */ int exit_lock; +/* 1800 | 16 */ struct tls_internal_t { +/* 1800 | 8 */ char *strsignal_buf; +/* 1808 | 8 */ char *strerror_l_buf; + + /* total size (bytes): 16 */ + } tls_state; +/* 1816 | 8 */ void *getrandom_buf; +/* 1824 | 32 */ union { +/* 24 */ struct { +/* 1824 | 4 */ uint32_t cpu_id_start; +/* 1828 | 4 */ uint32_t cpu_id; +/* 1832 | 8 */ uint64_t rseq_cs; +/* 1840 | 4 */ uint32_t flags; +/* XXX 4-byte padding */ + + /* total size (bytes): 24 */ + }; +/* 32 */ char pad[32]; + + /* total size (bytes): 32 */ + } rseq_area; + + /* total size (bytes): 1856 */ + } diff --git a/ld-so-abi-ppc64le.baseline b/ld-so-abi-ppc64le.baseline new file mode 100644 index 0000000..5b1daae --- /dev/null +++ b/ld-so-abi-ppc64le.baseline @@ -0,0 +1,542 @@ +--- _rtld_global_ro --- +/* offset | size */ type = struct rtld_global_ro { +/* 0 | 4 */ int _dl_debug_mask; +/* XXX 4-byte hole */ +/* 8 | 8 */ const char *_dl_platform; +/* 16 | 8 */ size_t _dl_platformlen; +/* 24 | 8 */ size_t _dl_pagesize; +/* 32 | 8 */ size_t _dl_minsigstacksize; +/* 40 | 4 */ int _dl_inhibit_cache; +/* XXX 4-byte hole */ +/* 48 | 16 */ struct r_scope_elem { +/* 48 | 8 */ struct link_map **r_list; +/* 56 | 4 */ unsigned int r_nlist; +/* XXX 4-byte padding */ + + /* total size (bytes): 16 */ + } _dl_initial_searchlist; +/* 64 | 4 */ int _dl_clktck; +/* 68 | 4 */ int _dl_verbose; +/* 72 | 4 */ int _dl_debug_fd; +/* 76 | 4 */ int _dl_lazy; +/* 80 | 4 */ int _dl_bind_not; +/* 84 | 4 */ int _dl_dynamic_weak; +/* 88 | 4 */ fpu_control_t _dl_fpu_control; +/* XXX 4-byte hole */ +/* 96 | 8 */ uint64_t _dl_hwcap; +/* 104 | 8 */ Elf64_auxv_t *_dl_auxv; +/* 112 | 40 */ struct cpu_features { +/* 112 | 1 */ _Bool use_cached_memopt; +/* XXX 7-byte hole */ +/* 120 | 8 */ unsigned long hwcap; +/* 128 | 8 */ unsigned long hwcap2; +/* 136 | 8 */ unsigned long hwcap3; +/* 144 | 8 */ unsigned long hwcap4; + + /* total size (bytes): 40 */ + } _dl_powerpc_cpu_features; +/* 152 | 1920 */ const char _dl_powerpc_cap_flags[128][15]; +/* 2072 | 4 */ int _dl_cache_line_size; +/* XXX 4-byte hole */ +/* 2080 | 8 */ const char *_dl_inhibit_rpath; +/* 2088 | 8 */ const char *_dl_origin_path; +/* 2096 | 8 */ size_t _dl_tls_static_size; +/* 2104 | 8 */ size_t _dl_tls_static_align; +/* 2112 | 8 */ size_t _dl_tls_static_surplus; +/* 2120 | 8 */ const char *_dl_profile; +/* 2128 | 8 */ const char *_dl_profile_output; +/* 2136 | 8 */ struct r_search_path_elem *_dl_init_all_dirs; +/* 2144 | 8 */ const Elf64_Ehdr *_dl_sysinfo_dso; +/* 2152 | 8 */ struct link_map *_dl_sysinfo_map; +/* 2160 | 8 */ int (*_dl_vdso_clock_gettime64)(clockid_t, struct timespec *); +/* 2168 | 8 */ int (*_dl_vdso_gettimeofday)(struct timeval *, void *); +/* 2176 | 8 */ time_t (*_dl_vdso_time)(time_t *); +/* 2184 | 8 */ int (*_dl_vdso_getcpu)(unsigned int *, unsigned int *, void *); +/* 2192 | 8 */ int (*_dl_vdso_clock_getres_time64)(clockid_t, struct timespec *); +/* 2200 | 8 */ ssize_t (*_dl_vdso_getrandom)(void *, size_t, unsigned int, void *, size_t); +/* 2208 | 8 */ uint64_t (*_dl_vdso_get_tbfreq)(void); +/* 2216 | 8 */ uint64_t _dl_hwcap2; +/* 2224 | 8 */ uint64_t _dl_hwcap3; +/* 2232 | 8 */ uint64_t _dl_hwcap4; +/* 2240 | 4 */ enum dso_sort_algorithm _dl_dso_sort_algo; +/* XXX 4-byte hole */ +/* 2248 | 8 */ void (*_dl_debug_printf)(const char *, ...); +/* 2256 | 8 */ void (*_dl_mcount)(Elf64_Addr, Elf64_Addr); +/* 2264 | 8 */ lookup_t (*_dl_lookup_symbol_x)(const char *, struct link_map *, const Elf64_Sym **, struct r_scope_elem **, const struct r_found_version *, int, int, struct link_map *); +/* 2272 | 8 */ void *(*_dl_open)(const char *, int, const void *, Lmid_t, int, char **, char **); +/* 2280 | 8 */ void (*_dl_close)(void *); +/* 2288 | 8 */ int (*_dl_catch_error)(const char **, const char **, _Bool *, void (*)(void *), void *); +/* 2296 | 8 */ void (*_dl_error_free)(void *); +/* 2304 | 8 */ void *(*_dl_tls_get_addr_soft)(struct link_map *); +/* 2312 | 8 */ void (*_dl_libc_freeres)(void); +/* 2320 | 8 */ int (*_dl_find_object)(void *, struct dl_find_object *); +/* 2328 | 8 */ const struct dlfcn_hook *_dl_dlfcn_hook; +/* 2336 | 8 */ struct audit_ifaces *_dl_audit; +/* 2344 | 4 */ unsigned int _dl_naudit; +/* XXX 4-byte padding */ + + /* total size (bytes): 2352 */ + } +--- _rtld_global --- +/* offset | size */ type = struct rtld_global { +/* 0 | 2560 */ struct link_namespaces _dl_ns[16]; +/* 2560 | 8 */ size_t _dl_nns; +/* 2568 | 40 */ __rtld_lock_recursive_t _dl_load_lock; +/* 2608 | 40 */ __rtld_lock_recursive_t _dl_load_write_lock; +/* 2648 | 40 */ __rtld_lock_recursive_t _dl_load_tls_lock; +/* 2688 | 8 */ unsigned long long _dl_load_adds; +/* 2696 | 8 */ struct link_map *_dl_initfirst; +/* 2704 | 8 */ struct link_map *_dl_profile_map; +/* 2712 | 8 */ unsigned long _dl_num_relocations; +/* 2720 | 8 */ unsigned long _dl_num_cache_relocations; +/* 2728 | 8 */ struct r_search_path_elem *_dl_all_dirs; +/* 2736 | 1176 */ struct link_map { +/* 2736 | 8 */ Elf64_Addr l_addr; +/* 2744 | 8 */ char *l_name; +/* 2752 | 8 */ Elf64_Dyn *l_ld; +/* 2760 | 8 */ struct link_map *l_next; +/* 2768 | 8 */ struct link_map *l_prev; +/* 2776 | 8 */ struct link_map *l_real; +/* 2784 | 8 */ Lmid_t l_ns; +/* 2792 | 8 */ struct libname_list *l_libname; +/* 2800 | 672 */ Elf64_Dyn *l_info[84]; +/* 3472 | 8 */ const Elf64_Phdr *l_phdr; +/* 3480 | 8 */ Elf64_Addr l_entry; +/* 3488 | 2 */ Elf64_Half l_phnum; +/* 3490 | 2 */ Elf64_Half l_ldnum; +/* XXX 4-byte hole */ +/* 3496 | 16 */ struct r_scope_elem { +/* 3496 | 8 */ struct link_map **r_list; +/* 3504 | 4 */ unsigned int r_nlist; +/* XXX 4-byte padding */ + + /* total size (bytes): 16 */ + } l_searchlist; +/* 3512 | 16 */ struct r_scope_elem { +/* 3512 | 8 */ struct link_map **r_list; +/* 3520 | 4 */ unsigned int r_nlist; +/* XXX 4-byte padding */ + + /* total size (bytes): 16 */ + } l_symbolic_searchlist; +/* 3528 | 8 */ struct link_map *l_loader; +/* 3536 | 8 */ struct r_found_version *l_versions; +/* 3544 | 4 */ unsigned int l_nversions; +/* 3548 | 4 */ Elf_Symndx l_nbuckets; +/* 3552 | 4 */ Elf32_Word l_gnu_bitmask_idxbits; +/* 3556 | 4 */ Elf32_Word l_gnu_shift; +/* 3560 | 8 */ const Elf64_Addr *l_gnu_bitmask; +/* 3568 | 8 */ union { +/* 8 */ const Elf32_Word *l_gnu_buckets; +/* 8 */ const Elf_Symndx *l_chain; + + /* total size (bytes): 8 */ + }; +/* 3576 | 8 */ union { +/* 8 */ const Elf32_Word *l_gnu_chain_zero; +/* 8 */ const Elf_Symndx *l_buckets; + + /* total size (bytes): 8 */ + }; +/* 3584 | 4 */ unsigned int l_direct_opencount; +/* 3588: 0 | 4 */ enum {lt_executable, lt_library, lt_loaded} l_type : 2; +/* 3588: 2 | 4 */ unsigned int l_dt_relr_ref : 1; +/* 3588: 3 | 4 */ unsigned int l_relocated : 1; +/* 3588: 4 | 4 */ unsigned int l_init_called : 1; +/* 3588: 5 | 4 */ unsigned int l_global : 1; +/* 3588: 6 | 4 */ unsigned int l_reserved : 2; +/* 3589: 0 | 4 */ unsigned int l_main_map : 1; +/* 3589: 1 | 4 */ unsigned int l_visited : 1; +/* 3589: 2 | 4 */ unsigned int l_map_used : 1; +/* 3589: 3 | 4 */ unsigned int l_map_done : 1; +/* 3589: 4 | 4 */ unsigned int l_phdr_allocated : 1; +/* 3589: 5 | 4 */ unsigned int l_soname_added : 1; +/* 3589: 6 | 4 */ unsigned int l_faked : 1; +/* 3589: 7 | 4 */ unsigned int l_need_tls_init : 1; +/* 3590: 0 | 4 */ unsigned int l_auditing : 1; +/* 3590: 1 | 4 */ unsigned int l_audit_any_plt : 1; +/* 3590: 2 | 4 */ unsigned int l_removed : 1; +/* 3590: 3 | 4 */ unsigned int l_contiguous : 1; +/* 3590: 4 | 4 */ unsigned int l_free_initfini : 1; +/* 3590: 5 | 4 */ unsigned int l_ld_readonly : 1; +/* 3590: 6 | 4 */ unsigned int l_find_object_processed : 1; +/* 3590: 7 | 4 */ unsigned int l_tls_in_slotinfo : 1; +/* 3591 | 1 */ _Bool l_nodelete_active; +/* 3592 | 1 */ _Bool l_nodelete_pending; +/* XXX 3-byte hole */ +/* 3596 | 4 */ unsigned int l_1_needed; +/* 3600 | 16 */ struct r_search_path_struct { +/* 3600 | 8 */ struct r_search_path_elem **dirs; +/* 3608 | 4 */ int malloced; +/* XXX 4-byte padding */ + + /* total size (bytes): 16 */ + } l_rpath_dirs; +/* 3616 | 8 */ struct reloc_result *l_reloc_result; +/* 3624 | 8 */ Elf64_Versym *l_versyms; +/* 3632 | 8 */ const char *l_origin; +/* 3640 | 8 */ Elf64_Addr l_map_start; +/* 3648 | 8 */ Elf64_Addr l_map_end; +/* 3656 | 32 */ struct r_scope_elem *l_scope_mem[4]; +/* 3688 | 8 */ size_t l_scope_max; +/* 3696 | 8 */ struct r_scope_elem **l_scope; +/* 3704 | 16 */ struct r_scope_elem *l_local_scope[2]; +/* 3720 | 16 */ struct r_file_id { +/* 3720 | 8 */ dev_t dev; +/* 3728 | 8 */ ino64_t ino; + + /* total size (bytes): 16 */ + } l_file_id; +/* 3736 | 16 */ struct r_search_path_struct { +/* 3736 | 8 */ struct r_search_path_elem **dirs; +/* 3744 | 4 */ int malloced; +/* XXX 4-byte padding */ + + /* total size (bytes): 16 */ + } l_runpath_dirs; +/* 3752 | 8 */ struct link_map **l_initfini; +/* 3760 | 8 */ struct link_map_reldeps *l_reldeps; +/* 3768 | 4 */ unsigned int l_reldepsmax; +/* 3772 | 4 */ unsigned int l_used; +/* 3776 | 4 */ Elf64_Word l_feature_1; +/* 3780 | 4 */ Elf64_Word l_flags_1; +/* 3784 | 4 */ Elf64_Word l_flags; +/* 3788 | 4 */ int l_idx; +/* 3792 | 0 */ struct link_map_machine { + + + /* total size (bytes): 0 */ + } l_mach; +/* 3792 | 32 */ struct { +/* 3792 | 8 */ const Elf64_Sym *sym; +/* 3800 | 4 */ int type_class; +/* XXX 4-byte hole */ +/* 3808 | 8 */ struct link_map *value; +/* 3816 | 8 */ const Elf64_Sym *ret; + + /* total size (bytes): 32 */ + } l_lookup_cache; +/* 3824 | 8 */ void *l_tls_initimage; +/* 3832 | 8 */ size_t l_tls_initimage_size; +/* 3840 | 8 */ size_t l_tls_blocksize; +/* 3848 | 8 */ size_t l_tls_align; +/* 3856 | 8 */ size_t l_tls_firstbyte_offset; +/* 3864 | 8 */ ptrdiff_t l_tls_offset; +/* 3872 | 8 */ size_t l_tls_modid; +/* 3880 | 8 */ size_t l_tls_dtor_count; +/* 3888 | 8 */ Elf64_Addr l_relro_addr; +/* 3896 | 8 */ size_t l_relro_size; +/* 3904 | 8 */ unsigned long long l_serial; + + /* total size (bytes): 1176 */ + } _dl_rtld_map; +/* 3912 | 256 */ struct auditstate _dl_rtld_auditstate[16]; +/* 4168 | 4 */ Elf64_Word _dl_stack_flags; +/* 4172 | 1 */ _Bool _dl_tls_dtv_gaps; +/* XXX 3-byte hole */ +/* 4176 | 8 */ size_t _dl_tls_max_dtv_idx; +/* 4184 | 8 */ struct dtv_slotinfo_list *_dl_tls_dtv_slotinfo_list; +/* 4192 | 8 */ size_t _dl_tls_static_nelem; +/* 4200 | 8 */ size_t _dl_tls_static_used; +/* 4208 | 8 */ size_t _dl_tls_static_optional; +/* 4216 | 8 */ void *_dl_initial_dtv; +/* 4224 | 8 */ size_t _dl_tls_generation; +/* 4232 | 8 */ struct dl_scope_free_list *_dl_scope_free_list; +/* 4240 | 16 */ list_t _dl_stack_used; +/* 4256 | 16 */ list_t _dl_stack_user; +/* 4272 | 16 */ list_t _dl_stack_cache; +/* 4288 | 8 */ size_t _dl_stack_cache_actsize; +/* 4296 | 8 */ uintptr_t _dl_in_flight_stack; +/* 4304 | 4 */ int _dl_stack_cache_lock; +/* XXX 4-byte padding */ + + /* total size (bytes): 4312 */ + } +--- struct link_map --- +/* offset | size */ type = struct link_map { +/* 0 | 8 */ Elf64_Addr l_addr; +/* 8 | 8 */ char *l_name; +/* 16 | 8 */ Elf64_Dyn *l_ld; +/* 24 | 8 */ struct link_map *l_next; +/* 32 | 8 */ struct link_map *l_prev; +/* 40 | 8 */ struct link_map *l_real; +/* 48 | 8 */ Lmid_t l_ns; +/* 56 | 8 */ struct libname_list *l_libname; +/* 64 | 672 */ Elf64_Dyn *l_info[84]; +/* 736 | 8 */ const Elf64_Phdr *l_phdr; +/* 744 | 8 */ Elf64_Addr l_entry; +/* 752 | 2 */ Elf64_Half l_phnum; +/* 754 | 2 */ Elf64_Half l_ldnum; +/* XXX 4-byte hole */ +/* 760 | 16 */ struct r_scope_elem { +/* 760 | 8 */ struct link_map **r_list; +/* 768 | 4 */ unsigned int r_nlist; +/* XXX 4-byte padding */ + + /* total size (bytes): 16 */ + } l_searchlist; +/* 776 | 16 */ struct r_scope_elem { +/* 776 | 8 */ struct link_map **r_list; +/* 784 | 4 */ unsigned int r_nlist; +/* XXX 4-byte padding */ + + /* total size (bytes): 16 */ + } l_symbolic_searchlist; +/* 792 | 8 */ struct link_map *l_loader; +/* 800 | 8 */ struct r_found_version *l_versions; +/* 808 | 4 */ unsigned int l_nversions; +/* 812 | 4 */ Elf_Symndx l_nbuckets; +/* 816 | 4 */ Elf32_Word l_gnu_bitmask_idxbits; +/* 820 | 4 */ Elf32_Word l_gnu_shift; +/* 824 | 8 */ const Elf64_Addr *l_gnu_bitmask; +/* 832 | 8 */ union { +/* 8 */ const Elf32_Word *l_gnu_buckets; +/* 8 */ const Elf_Symndx *l_chain; + + /* total size (bytes): 8 */ + }; +/* 840 | 8 */ union { +/* 8 */ const Elf32_Word *l_gnu_chain_zero; +/* 8 */ const Elf_Symndx *l_buckets; + + /* total size (bytes): 8 */ + }; +/* 848 | 4 */ unsigned int l_direct_opencount; +/* 852: 0 | 4 */ enum {lt_executable, lt_library, lt_loaded} l_type : 2; +/* 852: 2 | 4 */ unsigned int l_dt_relr_ref : 1; +/* 852: 3 | 4 */ unsigned int l_relocated : 1; +/* 852: 4 | 4 */ unsigned int l_init_called : 1; +/* 852: 5 | 4 */ unsigned int l_global : 1; +/* 852: 6 | 4 */ unsigned int l_reserved : 2; +/* 853: 0 | 4 */ unsigned int l_main_map : 1; +/* 853: 1 | 4 */ unsigned int l_visited : 1; +/* 853: 2 | 4 */ unsigned int l_map_used : 1; +/* 853: 3 | 4 */ unsigned int l_map_done : 1; +/* 853: 4 | 4 */ unsigned int l_phdr_allocated : 1; +/* 853: 5 | 4 */ unsigned int l_soname_added : 1; +/* 853: 6 | 4 */ unsigned int l_faked : 1; +/* 853: 7 | 4 */ unsigned int l_need_tls_init : 1; +/* 854: 0 | 4 */ unsigned int l_auditing : 1; +/* 854: 1 | 4 */ unsigned int l_audit_any_plt : 1; +/* 854: 2 | 4 */ unsigned int l_removed : 1; +/* 854: 3 | 4 */ unsigned int l_contiguous : 1; +/* 854: 4 | 4 */ unsigned int l_free_initfini : 1; +/* 854: 5 | 4 */ unsigned int l_ld_readonly : 1; +/* 854: 6 | 4 */ unsigned int l_find_object_processed : 1; +/* 854: 7 | 4 */ unsigned int l_tls_in_slotinfo : 1; +/* 855 | 1 */ _Bool l_nodelete_active; +/* 856 | 1 */ _Bool l_nodelete_pending; +/* XXX 3-byte hole */ +/* 860 | 4 */ unsigned int l_1_needed; +/* 864 | 16 */ struct r_search_path_struct { +/* 864 | 8 */ struct r_search_path_elem **dirs; +/* 872 | 4 */ int malloced; +/* XXX 4-byte padding */ + + /* total size (bytes): 16 */ + } l_rpath_dirs; +/* 880 | 8 */ struct reloc_result *l_reloc_result; +/* 888 | 8 */ Elf64_Versym *l_versyms; +/* 896 | 8 */ const char *l_origin; +/* 904 | 8 */ Elf64_Addr l_map_start; +/* 912 | 8 */ Elf64_Addr l_map_end; +/* 920 | 32 */ struct r_scope_elem *l_scope_mem[4]; +/* 952 | 8 */ size_t l_scope_max; +/* 960 | 8 */ struct r_scope_elem **l_scope; +/* 968 | 16 */ struct r_scope_elem *l_local_scope[2]; +/* 984 | 16 */ struct r_file_id { +/* 984 | 8 */ dev_t dev; +/* 992 | 8 */ ino64_t ino; + + /* total size (bytes): 16 */ + } l_file_id; +/* 1000 | 16 */ struct r_search_path_struct { +/* 1000 | 8 */ struct r_search_path_elem **dirs; +/* 1008 | 4 */ int malloced; +/* XXX 4-byte padding */ + + /* total size (bytes): 16 */ + } l_runpath_dirs; +/* 1016 | 8 */ struct link_map **l_initfini; +/* 1024 | 8 */ struct link_map_reldeps *l_reldeps; +/* 1032 | 4 */ unsigned int l_reldepsmax; +/* 1036 | 4 */ unsigned int l_used; +/* 1040 | 4 */ Elf64_Word l_feature_1; +/* 1044 | 4 */ Elf64_Word l_flags_1; +/* 1048 | 4 */ Elf64_Word l_flags; +/* 1052 | 4 */ int l_idx; +/* 1056 | 0 */ struct link_map_machine { + + + /* total size (bytes): 0 */ + } l_mach; +/* 1056 | 32 */ struct { +/* 1056 | 8 */ const Elf64_Sym *sym; +/* 1064 | 4 */ int type_class; +/* XXX 4-byte hole */ +/* 1072 | 8 */ struct link_map *value; +/* 1080 | 8 */ const Elf64_Sym *ret; + + /* total size (bytes): 32 */ + } l_lookup_cache; +/* 1088 | 8 */ void *l_tls_initimage; +/* 1096 | 8 */ size_t l_tls_initimage_size; +/* 1104 | 8 */ size_t l_tls_blocksize; +/* 1112 | 8 */ size_t l_tls_align; +/* 1120 | 8 */ size_t l_tls_firstbyte_offset; +/* 1128 | 8 */ ptrdiff_t l_tls_offset; +/* 1136 | 8 */ size_t l_tls_modid; +/* 1144 | 8 */ size_t l_tls_dtor_count; +/* 1152 | 8 */ Elf64_Addr l_relro_addr; +/* 1160 | 8 */ size_t l_relro_size; +/* 1168 | 8 */ unsigned long long l_serial; + + /* total size (bytes): 1176 */ + } +--- struct pthread --- +/* offset | size */ type = struct pthread { +/* 0 | 192 */ union { +/* 8 */ struct { +/* 0 | 4 */ int multiple_threads; +/* 4 | 4 */ int gscope_flag; + + /* total size (bytes): 8 */ + } header; +/* 192 */ void *__padding[24]; + + /* total size (bytes): 192 */ + }; +/* 192 | 16 */ list_t list; +/* 208 | 4 */ pid_t tid; +/* XXX 4-byte hole */ +/* 216 | 8 */ void *robust_prev; +/* 224 | 24 */ struct robust_list_head { +/* 224 | 8 */ void *list; +/* 232 | 8 */ long futex_offset; +/* 240 | 8 */ void *list_op_pending; + + /* total size (bytes): 24 */ + } robust_head; +/* 248 | 8 */ struct _pthread_cleanup_buffer *cleanup; +/* 256 | 8 */ struct pthread_unwind_buf *cleanup_jmp_buf; +/* 264 | 4 */ int cancelhandling; +/* 268 | 4 */ int flags; +/* 272 | 512 */ struct pthread_key_data specific_1stblock[32]; +/* 784 | 256 */ struct pthread_key_data *specific[32]; +/* 1040 | 1 */ _Bool specific_used; +/* 1041 | 1 */ _Bool report_events; +/* 1042 | 1 */ _Bool user_stack; +/* 1043 | 1 */ _Bool stopped_start; +/* 1044 | 4 */ int setup_failed; +/* 1048 | 4 */ int lock; +/* 1052 | 4 */ unsigned int setxid_futex; +/* 1056 | 8 */ struct pthread *joinid; +/* 1064 | 8 */ void *result; +/* 1072 | 4 */ struct sched_param { +/* 1072 | 4 */ int sched_priority; + + /* total size (bytes): 4 */ + } schedparam; +/* 1076 | 4 */ int schedpolicy; +/* 1080 | 8 */ void *(*start_routine)(void *); +/* 1088 | 8 */ void *arg; +/* 1096 | 24 */ td_eventbuf_t eventbuf; +/* 1120 | 8 */ struct pthread *nextevent; +/* XXX 8-byte hole */ +/* 1136 | 32 */ struct _Unwind_Exception { +/* 1136 | 32 */ union { +/* 32 */ struct { +/* 1136 | 8 */ _Unwind_Exception_Class exception_class; +/* 1144 | 8 */ _Unwind_Exception_Cleanup_Fn exception_cleanup; +/* 1152 | 8 */ _Unwind_Word private_1; +/* 1160 | 8 */ _Unwind_Word private_2; + + /* total size (bytes): 32 */ + }; +/* 16 */ _Unwind_Word unwind_exception_align[2]; + + /* total size (bytes): 32 */ + }; + + /* total size (bytes): 32 */ + } exc; +/* 1168 | 8 */ void *stackblock; +/* 1176 | 8 */ size_t stackblock_size; +/* 1184 | 8 */ size_t guardsize; +/* 1192 | 8 */ size_t reported_guardsize; +/* 1200 | 8 */ struct priority_protection_data *tpp; +/* 1208 | 568 */ struct __res_state { +/* 1208 | 4 */ int retrans; +/* 1212 | 4 */ int retry; +/* 1216 | 8 */ unsigned long options; +/* 1224 | 4 */ int nscount; +/* 1228 | 48 */ struct sockaddr_in nsaddr_list[3]; +/* 1276 | 2 */ unsigned short id; +/* XXX 2-byte hole */ +/* 1280 | 56 */ char *dnsrch[7]; +/* 1336 | 256 */ char defdname[256]; +/* 1592 | 8 */ unsigned long pfcode; +/* 1600: 0 | 4 */ unsigned int ndots : 4; +/* 1600: 4 | 4 */ unsigned int nsort : 4; +/* 1601: 0 | 4 */ unsigned int ipv6_unavail : 1; +/* 1601: 1 | 4 */ unsigned int unused : 23; +/* 1604 | 80 */ struct { +/* 0 | 4 */ struct in_addr addr; +/* 4 | 4 */ uint32_t mask; + } sort_list[10]; +/* XXX 4-byte hole */ +/* 1688 | 8 */ void *__glibc_unused_qhook; +/* 1696 | 8 */ void *__glibc_unused_rhook; +/* 1704 | 4 */ int res_h_errno; +/* 1708 | 4 */ int _vcsock; +/* 1712 | 4 */ unsigned int _flags; +/* XXX 4-byte hole */ +/* 1720 | 56 */ union { +/* 52 */ char pad[52]; +/* 56 */ struct { +/* 1720 | 2 */ uint16_t nscount; +/* 1722 | 6 */ uint16_t nsmap[3]; +/* 1728 | 12 */ int nssocks[3]; +/* 1740 | 2 */ uint16_t nscount6; +/* 1742 | 2 */ uint16_t nsinit; +/* 1744 | 24 */ struct sockaddr_in6 *nsaddrs[3]; +/* 1768 | 8 */ unsigned long long __glibc_extension_index; + + /* total size (bytes): 56 */ + } _ext; + + /* total size (bytes): 56 */ + } _u; + + /* total size (bytes): 568 */ + } res; +/* 1776 | 8 */ internal_sigset_t sigmask; +/* 1784 | 8 */ struct rtld_catch *rtld_catch; +/* 1792 | 1 */ _Bool c11; +/* 1793 | 1 */ _Bool exiting; +/* XXX 2-byte hole */ +/* 1796 | 4 */ int exit_lock; +/* 1800 | 16 */ struct tls_internal_t { +/* 1800 | 8 */ char *strsignal_buf; +/* 1808 | 8 */ char *strerror_l_buf; + + /* total size (bytes): 16 */ + } tls_state; +/* 1816 | 8 */ void *getrandom_buf; +/* 1824 | 32 */ union { +/* 24 */ struct { +/* 1824 | 4 */ uint32_t cpu_id_start; +/* 1828 | 4 */ uint32_t cpu_id; +/* 1832 | 8 */ uint64_t rseq_cs; +/* 1840 | 4 */ uint32_t flags; +/* XXX 4-byte padding */ + + /* total size (bytes): 24 */ + }; +/* 32 */ char pad[32]; + + /* total size (bytes): 32 */ + } rseq_area; + + /* total size (bytes): 1856 */ + } diff --git a/ld-so-abi-riscv64.baseline b/ld-so-abi-riscv64.baseline new file mode 100644 index 0000000..6595d04 --- /dev/null +++ b/ld-so-abi-riscv64.baseline @@ -0,0 +1,526 @@ +--- _rtld_global_ro --- +/* offset | size */ type = struct rtld_global_ro { +/* 0 | 4 */ int _dl_debug_mask; +/* XXX 4-byte hole */ +/* 8 | 8 */ const char *_dl_platform; +/* 16 | 8 */ size_t _dl_platformlen; +/* 24 | 8 */ size_t _dl_pagesize; +/* 32 | 8 */ size_t _dl_minsigstacksize; +/* 40 | 4 */ int _dl_inhibit_cache; +/* XXX 4-byte hole */ +/* 48 | 16 */ struct r_scope_elem { +/* 48 | 8 */ struct link_map **r_list; +/* 56 | 4 */ unsigned int r_nlist; +/* XXX 4-byte padding */ + + /* total size (bytes): 16 */ + } _dl_initial_searchlist; +/* 64 | 4 */ int _dl_clktck; +/* 68 | 4 */ int _dl_verbose; +/* 72 | 4 */ int _dl_debug_fd; +/* 76 | 4 */ int _dl_lazy; +/* 80 | 4 */ int _dl_bind_not; +/* 84 | 4 */ int _dl_dynamic_weak; +/* 88 | 4 */ fpu_control_t _dl_fpu_control; +/* XXX 4-byte hole */ +/* 96 | 8 */ uint64_t _dl_hwcap; +/* 104 | 8 */ Elf64_auxv_t *_dl_auxv; +/* 112 | 8 */ const char *_dl_inhibit_rpath; +/* 120 | 8 */ const char *_dl_origin_path; +/* 128 | 8 */ size_t _dl_tls_static_size; +/* 136 | 8 */ size_t _dl_tls_static_align; +/* 144 | 8 */ size_t _dl_tls_static_surplus; +/* 152 | 8 */ const char *_dl_profile; +/* 160 | 8 */ const char *_dl_profile_output; +/* 168 | 8 */ struct r_search_path_elem *_dl_init_all_dirs; +/* 176 | 8 */ const Elf64_Ehdr *_dl_sysinfo_dso; +/* 184 | 8 */ struct link_map *_dl_sysinfo_map; +/* 192 | 8 */ int (*_dl_vdso_clock_gettime64)(clockid_t, struct timespec *); +/* 200 | 8 */ int (*_dl_vdso_gettimeofday)(struct timeval *, void *); +/* 208 | 8 */ int (*_dl_vdso_getcpu)(unsigned int *, unsigned int *, void *); +/* 216 | 8 */ int (*_dl_vdso_clock_getres_time64)(clockid_t, struct timespec *); +/* 224 | 8 */ uint64_t _dl_hwcap2; +/* 232 | 8 */ uint64_t _dl_hwcap3; +/* 240 | 8 */ uint64_t _dl_hwcap4; +/* 248 | 4 */ enum dso_sort_algorithm _dl_dso_sort_algo; +/* XXX 4-byte hole */ +/* 256 | 8 */ void (*_dl_debug_printf)(const char *, ...); +/* 264 | 8 */ void (*_dl_mcount)(Elf64_Addr, Elf64_Addr); +/* 272 | 8 */ lookup_t (*_dl_lookup_symbol_x)(const char *, struct link_map *, const Elf64_Sym **, struct r_scope_elem **, const struct r_found_version *, int, int, struct link_map *); +/* 280 | 8 */ void *(*_dl_open)(const char *, int, const void *, Lmid_t, int, char **, char **); +/* 288 | 8 */ void (*_dl_close)(void *); +/* 296 | 8 */ int (*_dl_catch_error)(const char **, const char **, _Bool *, void (*)(void *), void *); +/* 304 | 8 */ void (*_dl_error_free)(void *); +/* 312 | 8 */ void *(*_dl_tls_get_addr_soft)(struct link_map *); +/* 320 | 8 */ void (*_dl_libc_freeres)(void); +/* 328 | 8 */ int (*_dl_find_object)(void *, struct dl_find_object *); +/* 336 | 8 */ const struct dlfcn_hook *_dl_dlfcn_hook; +/* 344 | 8 */ struct audit_ifaces *_dl_audit; +/* 352 | 4 */ unsigned int _dl_naudit; +/* XXX 4-byte padding */ + + /* total size (bytes): 360 */ + } +--- _rtld_global --- +/* offset | size */ type = struct rtld_global { +/* 0 | 2560 */ struct link_namespaces _dl_ns[16]; +/* 2560 | 8 */ size_t _dl_nns; +/* 2568 | 40 */ __rtld_lock_recursive_t _dl_load_lock; +/* 2608 | 40 */ __rtld_lock_recursive_t _dl_load_write_lock; +/* 2648 | 40 */ __rtld_lock_recursive_t _dl_load_tls_lock; +/* 2688 | 8 */ unsigned long long _dl_load_adds; +/* 2696 | 8 */ struct link_map *_dl_initfirst; +/* 2704 | 8 */ struct link_map *_dl_profile_map; +/* 2712 | 8 */ unsigned long _dl_num_relocations; +/* 2720 | 8 */ unsigned long _dl_num_cache_relocations; +/* 2728 | 8 */ struct r_search_path_elem *_dl_all_dirs; +/* 2736 | 1152 */ struct link_map { +/* 2736 | 8 */ Elf64_Addr l_addr; +/* 2744 | 8 */ char *l_name; +/* 2752 | 8 */ Elf64_Dyn *l_ld; +/* 2760 | 8 */ struct link_map *l_next; +/* 2768 | 8 */ struct link_map *l_prev; +/* 2776 | 8 */ struct link_map *l_real; +/* 2784 | 8 */ Lmid_t l_ns; +/* 2792 | 8 */ struct libname_list *l_libname; +/* 2800 | 640 */ Elf64_Dyn *l_info[80]; +/* 3440 | 8 */ const Elf64_Phdr *l_phdr; +/* 3448 | 8 */ Elf64_Addr l_entry; +/* 3456 | 2 */ Elf64_Half l_phnum; +/* 3458 | 2 */ Elf64_Half l_ldnum; +/* XXX 4-byte hole */ +/* 3464 | 16 */ struct r_scope_elem { +/* 3464 | 8 */ struct link_map **r_list; +/* 3472 | 4 */ unsigned int r_nlist; +/* XXX 4-byte padding */ + + /* total size (bytes): 16 */ + } l_searchlist; +/* 3480 | 16 */ struct r_scope_elem { +/* 3480 | 8 */ struct link_map **r_list; +/* 3488 | 4 */ unsigned int r_nlist; +/* XXX 4-byte padding */ + + /* total size (bytes): 16 */ + } l_symbolic_searchlist; +/* 3496 | 8 */ struct link_map *l_loader; +/* 3504 | 8 */ struct r_found_version *l_versions; +/* 3512 | 4 */ unsigned int l_nversions; +/* 3516 | 4 */ Elf_Symndx l_nbuckets; +/* 3520 | 4 */ Elf32_Word l_gnu_bitmask_idxbits; +/* 3524 | 4 */ Elf32_Word l_gnu_shift; +/* 3528 | 8 */ const Elf64_Addr *l_gnu_bitmask; +/* 3536 | 8 */ union { +/* 8 */ const Elf32_Word *l_gnu_buckets; +/* 8 */ const Elf_Symndx *l_chain; + + /* total size (bytes): 8 */ + }; +/* 3544 | 8 */ union { +/* 8 */ const Elf32_Word *l_gnu_chain_zero; +/* 8 */ const Elf_Symndx *l_buckets; + + /* total size (bytes): 8 */ + }; +/* 3552 | 4 */ unsigned int l_direct_opencount; +/* 3556: 0 | 4 */ enum {lt_executable, lt_library, lt_loaded} l_type : 2; +/* 3556: 2 | 4 */ unsigned int l_dt_relr_ref : 1; +/* 3556: 3 | 4 */ unsigned int l_relocated : 1; +/* 3556: 4 | 4 */ unsigned int l_init_called : 1; +/* 3556: 5 | 4 */ unsigned int l_global : 1; +/* 3556: 6 | 4 */ unsigned int l_reserved : 2; +/* 3557: 0 | 4 */ unsigned int l_main_map : 1; +/* 3557: 1 | 4 */ unsigned int l_visited : 1; +/* 3557: 2 | 4 */ unsigned int l_map_used : 1; +/* 3557: 3 | 4 */ unsigned int l_map_done : 1; +/* 3557: 4 | 4 */ unsigned int l_phdr_allocated : 1; +/* 3557: 5 | 4 */ unsigned int l_soname_added : 1; +/* 3557: 6 | 4 */ unsigned int l_faked : 1; +/* 3557: 7 | 4 */ unsigned int l_need_tls_init : 1; +/* 3558: 0 | 4 */ unsigned int l_auditing : 1; +/* 3558: 1 | 4 */ unsigned int l_audit_any_plt : 1; +/* 3558: 2 | 4 */ unsigned int l_removed : 1; +/* 3558: 3 | 4 */ unsigned int l_contiguous : 1; +/* 3558: 4 | 4 */ unsigned int l_free_initfini : 1; +/* 3558: 5 | 4 */ unsigned int l_ld_readonly : 1; +/* 3558: 6 | 4 */ unsigned int l_find_object_processed : 1; +/* 3558: 7 | 4 */ unsigned int l_tls_in_slotinfo : 1; +/* 3559 | 1 */ _Bool l_nodelete_active; +/* 3560 | 1 */ _Bool l_nodelete_pending; +/* XXX 3-byte hole */ +/* 3564 | 4 */ unsigned int l_1_needed; +/* 3568 | 16 */ struct r_search_path_struct { +/* 3568 | 8 */ struct r_search_path_elem **dirs; +/* 3576 | 4 */ int malloced; +/* XXX 4-byte padding */ + + /* total size (bytes): 16 */ + } l_rpath_dirs; +/* 3584 | 8 */ struct reloc_result *l_reloc_result; +/* 3592 | 8 */ Elf64_Versym *l_versyms; +/* 3600 | 8 */ const char *l_origin; +/* 3608 | 8 */ Elf64_Addr l_map_start; +/* 3616 | 8 */ Elf64_Addr l_map_end; +/* 3624 | 32 */ struct r_scope_elem *l_scope_mem[4]; +/* 3656 | 8 */ size_t l_scope_max; +/* 3664 | 8 */ struct r_scope_elem **l_scope; +/* 3672 | 16 */ struct r_scope_elem *l_local_scope[2]; +/* 3688 | 16 */ struct r_file_id { +/* 3688 | 8 */ dev_t dev; +/* 3696 | 8 */ ino64_t ino; + + /* total size (bytes): 16 */ + } l_file_id; +/* 3704 | 16 */ struct r_search_path_struct { +/* 3704 | 8 */ struct r_search_path_elem **dirs; +/* 3712 | 4 */ int malloced; +/* XXX 4-byte padding */ + + /* total size (bytes): 16 */ + } l_runpath_dirs; +/* 3720 | 8 */ struct link_map **l_initfini; +/* 3728 | 8 */ struct link_map_reldeps *l_reldeps; +/* 3736 | 4 */ unsigned int l_reldepsmax; +/* 3740 | 4 */ unsigned int l_used; +/* 3744 | 4 */ Elf64_Word l_feature_1; +/* 3748 | 4 */ Elf64_Word l_flags_1; +/* 3752 | 4 */ Elf64_Word l_flags; +/* 3756 | 4 */ int l_idx; +/* 3760 | 8 */ struct link_map_machine { +/* 3760 | 8 */ Elf64_Addr plt; + + /* total size (bytes): 8 */ + } l_mach; +/* 3768 | 32 */ struct { +/* 3768 | 8 */ const Elf64_Sym *sym; +/* 3776 | 4 */ int type_class; +/* XXX 4-byte hole */ +/* 3784 | 8 */ struct link_map *value; +/* 3792 | 8 */ const Elf64_Sym *ret; + + /* total size (bytes): 32 */ + } l_lookup_cache; +/* 3800 | 8 */ void *l_tls_initimage; +/* 3808 | 8 */ size_t l_tls_initimage_size; +/* 3816 | 8 */ size_t l_tls_blocksize; +/* 3824 | 8 */ size_t l_tls_align; +/* 3832 | 8 */ size_t l_tls_firstbyte_offset; +/* 3840 | 8 */ ptrdiff_t l_tls_offset; +/* 3848 | 8 */ size_t l_tls_modid; +/* 3856 | 8 */ size_t l_tls_dtor_count; +/* 3864 | 8 */ Elf64_Addr l_relro_addr; +/* 3872 | 8 */ size_t l_relro_size; +/* 3880 | 8 */ unsigned long long l_serial; + + /* total size (bytes): 1152 */ + } _dl_rtld_map; +/* 3888 | 256 */ struct auditstate _dl_rtld_auditstate[16]; +/* 4144 | 4 */ Elf64_Word _dl_stack_flags; +/* 4148 | 1 */ _Bool _dl_tls_dtv_gaps; +/* XXX 3-byte hole */ +/* 4152 | 8 */ size_t _dl_tls_max_dtv_idx; +/* 4160 | 8 */ struct dtv_slotinfo_list *_dl_tls_dtv_slotinfo_list; +/* 4168 | 8 */ size_t _dl_tls_static_nelem; +/* 4176 | 8 */ size_t _dl_tls_static_used; +/* 4184 | 8 */ size_t _dl_tls_static_optional; +/* 4192 | 8 */ void *_dl_initial_dtv; +/* 4200 | 8 */ size_t _dl_tls_generation; +/* 4208 | 8 */ struct dl_scope_free_list *_dl_scope_free_list; +/* 4216 | 16 */ list_t _dl_stack_used; +/* 4232 | 16 */ list_t _dl_stack_user; +/* 4248 | 16 */ list_t _dl_stack_cache; +/* 4264 | 8 */ size_t _dl_stack_cache_actsize; +/* 4272 | 8 */ uintptr_t _dl_in_flight_stack; +/* 4280 | 4 */ int _dl_stack_cache_lock; +/* XXX 4-byte padding */ + + /* total size (bytes): 4288 */ + } +--- struct link_map --- +/* offset | size */ type = struct link_map { +/* 0 | 8 */ Elf64_Addr l_addr; +/* 8 | 8 */ char *l_name; +/* 16 | 8 */ Elf64_Dyn *l_ld; +/* 24 | 8 */ struct link_map *l_next; +/* 32 | 8 */ struct link_map *l_prev; +/* 40 | 8 */ struct link_map *l_real; +/* 48 | 8 */ Lmid_t l_ns; +/* 56 | 8 */ struct libname_list *l_libname; +/* 64 | 640 */ Elf64_Dyn *l_info[80]; +/* 704 | 8 */ const Elf64_Phdr *l_phdr; +/* 712 | 8 */ Elf64_Addr l_entry; +/* 720 | 2 */ Elf64_Half l_phnum; +/* 722 | 2 */ Elf64_Half l_ldnum; +/* XXX 4-byte hole */ +/* 728 | 16 */ struct r_scope_elem { +/* 728 | 8 */ struct link_map **r_list; +/* 736 | 4 */ unsigned int r_nlist; +/* XXX 4-byte padding */ + + /* total size (bytes): 16 */ + } l_searchlist; +/* 744 | 16 */ struct r_scope_elem { +/* 744 | 8 */ struct link_map **r_list; +/* 752 | 4 */ unsigned int r_nlist; +/* XXX 4-byte padding */ + + /* total size (bytes): 16 */ + } l_symbolic_searchlist; +/* 760 | 8 */ struct link_map *l_loader; +/* 768 | 8 */ struct r_found_version *l_versions; +/* 776 | 4 */ unsigned int l_nversions; +/* 780 | 4 */ Elf_Symndx l_nbuckets; +/* 784 | 4 */ Elf32_Word l_gnu_bitmask_idxbits; +/* 788 | 4 */ Elf32_Word l_gnu_shift; +/* 792 | 8 */ const Elf64_Addr *l_gnu_bitmask; +/* 800 | 8 */ union { +/* 8 */ const Elf32_Word *l_gnu_buckets; +/* 8 */ const Elf_Symndx *l_chain; + + /* total size (bytes): 8 */ + }; +/* 808 | 8 */ union { +/* 8 */ const Elf32_Word *l_gnu_chain_zero; +/* 8 */ const Elf_Symndx *l_buckets; + + /* total size (bytes): 8 */ + }; +/* 816 | 4 */ unsigned int l_direct_opencount; +/* 820: 0 | 4 */ enum {lt_executable, lt_library, lt_loaded} l_type : 2; +/* 820: 2 | 4 */ unsigned int l_dt_relr_ref : 1; +/* 820: 3 | 4 */ unsigned int l_relocated : 1; +/* 820: 4 | 4 */ unsigned int l_init_called : 1; +/* 820: 5 | 4 */ unsigned int l_global : 1; +/* 820: 6 | 4 */ unsigned int l_reserved : 2; +/* 821: 0 | 4 */ unsigned int l_main_map : 1; +/* 821: 1 | 4 */ unsigned int l_visited : 1; +/* 821: 2 | 4 */ unsigned int l_map_used : 1; +/* 821: 3 | 4 */ unsigned int l_map_done : 1; +/* 821: 4 | 4 */ unsigned int l_phdr_allocated : 1; +/* 821: 5 | 4 */ unsigned int l_soname_added : 1; +/* 821: 6 | 4 */ unsigned int l_faked : 1; +/* 821: 7 | 4 */ unsigned int l_need_tls_init : 1; +/* 822: 0 | 4 */ unsigned int l_auditing : 1; +/* 822: 1 | 4 */ unsigned int l_audit_any_plt : 1; +/* 822: 2 | 4 */ unsigned int l_removed : 1; +/* 822: 3 | 4 */ unsigned int l_contiguous : 1; +/* 822: 4 | 4 */ unsigned int l_free_initfini : 1; +/* 822: 5 | 4 */ unsigned int l_ld_readonly : 1; +/* 822: 6 | 4 */ unsigned int l_find_object_processed : 1; +/* 822: 7 | 4 */ unsigned int l_tls_in_slotinfo : 1; +/* 823 | 1 */ _Bool l_nodelete_active; +/* 824 | 1 */ _Bool l_nodelete_pending; +/* XXX 3-byte hole */ +/* 828 | 4 */ unsigned int l_1_needed; +/* 832 | 16 */ struct r_search_path_struct { +/* 832 | 8 */ struct r_search_path_elem **dirs; +/* 840 | 4 */ int malloced; +/* XXX 4-byte padding */ + + /* total size (bytes): 16 */ + } l_rpath_dirs; +/* 848 | 8 */ struct reloc_result *l_reloc_result; +/* 856 | 8 */ Elf64_Versym *l_versyms; +/* 864 | 8 */ const char *l_origin; +/* 872 | 8 */ Elf64_Addr l_map_start; +/* 880 | 8 */ Elf64_Addr l_map_end; +/* 888 | 32 */ struct r_scope_elem *l_scope_mem[4]; +/* 920 | 8 */ size_t l_scope_max; +/* 928 | 8 */ struct r_scope_elem **l_scope; +/* 936 | 16 */ struct r_scope_elem *l_local_scope[2]; +/* 952 | 16 */ struct r_file_id { +/* 952 | 8 */ dev_t dev; +/* 960 | 8 */ ino64_t ino; + + /* total size (bytes): 16 */ + } l_file_id; +/* 968 | 16 */ struct r_search_path_struct { +/* 968 | 8 */ struct r_search_path_elem **dirs; +/* 976 | 4 */ int malloced; +/* XXX 4-byte padding */ + + /* total size (bytes): 16 */ + } l_runpath_dirs; +/* 984 | 8 */ struct link_map **l_initfini; +/* 992 | 8 */ struct link_map_reldeps *l_reldeps; +/* 1000 | 4 */ unsigned int l_reldepsmax; +/* 1004 | 4 */ unsigned int l_used; +/* 1008 | 4 */ Elf64_Word l_feature_1; +/* 1012 | 4 */ Elf64_Word l_flags_1; +/* 1016 | 4 */ Elf64_Word l_flags; +/* 1020 | 4 */ int l_idx; +/* 1024 | 8 */ struct link_map_machine { +/* 1024 | 8 */ Elf64_Addr plt; + + /* total size (bytes): 8 */ + } l_mach; +/* 1032 | 32 */ struct { +/* 1032 | 8 */ const Elf64_Sym *sym; +/* 1040 | 4 */ int type_class; +/* XXX 4-byte hole */ +/* 1048 | 8 */ struct link_map *value; +/* 1056 | 8 */ const Elf64_Sym *ret; + + /* total size (bytes): 32 */ + } l_lookup_cache; +/* 1064 | 8 */ void *l_tls_initimage; +/* 1072 | 8 */ size_t l_tls_initimage_size; +/* 1080 | 8 */ size_t l_tls_blocksize; +/* 1088 | 8 */ size_t l_tls_align; +/* 1096 | 8 */ size_t l_tls_firstbyte_offset; +/* 1104 | 8 */ ptrdiff_t l_tls_offset; +/* 1112 | 8 */ size_t l_tls_modid; +/* 1120 | 8 */ size_t l_tls_dtor_count; +/* 1128 | 8 */ Elf64_Addr l_relro_addr; +/* 1136 | 8 */ size_t l_relro_size; +/* 1144 | 8 */ unsigned long long l_serial; + + /* total size (bytes): 1152 */ + } +--- struct pthread --- +/* offset | size */ type = struct pthread { +/* 0 | 192 */ union { +/* 8 */ struct { +/* 0 | 4 */ int multiple_threads; +/* 4 | 4 */ int gscope_flag; + + /* total size (bytes): 8 */ + } header; +/* 192 */ void *__padding[24]; + + /* total size (bytes): 192 */ + }; +/* 192 | 16 */ list_t list; +/* 208 | 4 */ pid_t tid; +/* XXX 4-byte hole */ +/* 216 | 8 */ void *robust_prev; +/* 224 | 24 */ struct robust_list_head { +/* 224 | 8 */ void *list; +/* 232 | 8 */ long futex_offset; +/* 240 | 8 */ void *list_op_pending; + + /* total size (bytes): 24 */ + } robust_head; +/* 248 | 8 */ struct _pthread_cleanup_buffer *cleanup; +/* 256 | 8 */ struct pthread_unwind_buf *cleanup_jmp_buf; +/* 264 | 4 */ int cancelhandling; +/* 268 | 4 */ int flags; +/* 272 | 512 */ struct pthread_key_data specific_1stblock[32]; +/* 784 | 256 */ struct pthread_key_data *specific[32]; +/* 1040 | 1 */ _Bool specific_used; +/* 1041 | 1 */ _Bool report_events; +/* 1042 | 1 */ _Bool user_stack; +/* 1043 | 1 */ _Bool stopped_start; +/* 1044 | 4 */ int setup_failed; +/* 1048 | 4 */ int lock; +/* 1052 | 4 */ unsigned int setxid_futex; +/* 1056 | 8 */ struct pthread *joinid; +/* 1064 | 8 */ void *result; +/* 1072 | 4 */ struct sched_param { +/* 1072 | 4 */ int sched_priority; + + /* total size (bytes): 4 */ + } schedparam; +/* 1076 | 4 */ int schedpolicy; +/* 1080 | 8 */ void *(*start_routine)(void *); +/* 1088 | 8 */ void *arg; +/* 1096 | 24 */ td_eventbuf_t eventbuf; +/* 1120 | 8 */ struct pthread *nextevent; +/* XXX 8-byte hole */ +/* 1136 | 32 */ struct _Unwind_Exception { +/* 1136 | 32 */ union { +/* 32 */ struct { +/* 1136 | 8 */ _Unwind_Exception_Class exception_class; +/* 1144 | 8 */ _Unwind_Exception_Cleanup_Fn exception_cleanup; +/* 1152 | 8 */ _Unwind_Word private_1; +/* 1160 | 8 */ _Unwind_Word private_2; + + /* total size (bytes): 32 */ + }; +/* 16 */ _Unwind_Word unwind_exception_align[2]; + + /* total size (bytes): 32 */ + }; + + /* total size (bytes): 32 */ + } exc; +/* 1168 | 8 */ void *stackblock; +/* 1176 | 8 */ size_t stackblock_size; +/* 1184 | 8 */ size_t guardsize; +/* 1192 | 8 */ size_t reported_guardsize; +/* 1200 | 8 */ struct priority_protection_data *tpp; +/* 1208 | 568 */ struct __res_state { +/* 1208 | 4 */ int retrans; +/* 1212 | 4 */ int retry; +/* 1216 | 8 */ unsigned long options; +/* 1224 | 4 */ int nscount; +/* 1228 | 48 */ struct sockaddr_in nsaddr_list[3]; +/* 1276 | 2 */ unsigned short id; +/* XXX 2-byte hole */ +/* 1280 | 56 */ char *dnsrch[7]; +/* 1336 | 256 */ char defdname[256]; +/* 1592 | 8 */ unsigned long pfcode; +/* 1600: 0 | 4 */ unsigned int ndots : 4; +/* 1600: 4 | 4 */ unsigned int nsort : 4; +/* 1601: 0 | 4 */ unsigned int ipv6_unavail : 1; +/* 1601: 1 | 4 */ unsigned int unused : 23; +/* 1604 | 80 */ struct { +/* 0 | 4 */ struct in_addr addr; +/* 4 | 4 */ uint32_t mask; + } sort_list[10]; +/* XXX 4-byte hole */ +/* 1688 | 8 */ void *__glibc_unused_qhook; +/* 1696 | 8 */ void *__glibc_unused_rhook; +/* 1704 | 4 */ int res_h_errno; +/* 1708 | 4 */ int _vcsock; +/* 1712 | 4 */ unsigned int _flags; +/* XXX 4-byte hole */ +/* 1720 | 56 */ union { +/* 52 */ char pad[52]; +/* 56 */ struct { +/* 1720 | 2 */ uint16_t nscount; +/* 1722 | 6 */ uint16_t nsmap[3]; +/* 1728 | 12 */ int nssocks[3]; +/* 1740 | 2 */ uint16_t nscount6; +/* 1742 | 2 */ uint16_t nsinit; +/* 1744 | 24 */ struct sockaddr_in6 *nsaddrs[3]; +/* 1768 | 8 */ unsigned long long __glibc_extension_index; + + /* total size (bytes): 56 */ + } _ext; + + /* total size (bytes): 56 */ + } _u; + + /* total size (bytes): 568 */ + } res; +/* 1776 | 8 */ internal_sigset_t sigmask; +/* 1784 | 8 */ struct rtld_catch *rtld_catch; +/* 1792 | 1 */ _Bool c11; +/* 1793 | 1 */ _Bool exiting; +/* XXX 2-byte hole */ +/* 1796 | 4 */ int exit_lock; +/* 1800 | 16 */ struct tls_internal_t { +/* 1800 | 8 */ char *strsignal_buf; +/* 1808 | 8 */ char *strerror_l_buf; + + /* total size (bytes): 16 */ + } tls_state; +/* 1816 | 8 */ void *getrandom_buf; +/* 1824 | 32 */ union { +/* 24 */ struct { +/* 1824 | 4 */ uint32_t cpu_id_start; +/* 1828 | 4 */ uint32_t cpu_id; +/* 1832 | 8 */ uint64_t rseq_cs; +/* 1840 | 4 */ uint32_t flags; +/* XXX 4-byte padding */ + + /* total size (bytes): 24 */ + }; +/* 32 */ char pad[32]; + + /* total size (bytes): 32 */ + } rseq_area; + + /* total size (bytes): 1856 */ + } diff --git a/ld-so-abi-s390x.baseline b/ld-so-abi-s390x.baseline new file mode 100644 index 0000000..5928157 --- /dev/null +++ b/ld-so-abi-s390x.baseline @@ -0,0 +1,536 @@ +--- _rtld_global_ro --- +/* offset | size */ type = struct rtld_global_ro { +/* 0 | 4 */ int _dl_debug_mask; +/* XXX 4-byte hole */ +/* 8 | 8 */ const char *_dl_platform; +/* 16 | 8 */ size_t _dl_platformlen; +/* 24 | 8 */ size_t _dl_pagesize; +/* 32 | 8 */ size_t _dl_minsigstacksize; +/* 40 | 4 */ int _dl_inhibit_cache; +/* XXX 4-byte hole */ +/* 48 | 16 */ struct r_scope_elem { +/* 48 | 8 */ struct link_map **r_list; +/* 56 | 4 */ unsigned int r_nlist; +/* XXX 4-byte padding */ + + /* total size (bytes): 16 */ + } _dl_initial_searchlist; +/* 64 | 4 */ int _dl_clktck; +/* 68 | 4 */ int _dl_verbose; +/* 72 | 4 */ int _dl_debug_fd; +/* 76 | 4 */ int _dl_lazy; +/* 80 | 4 */ int _dl_bind_not; +/* 84 | 4 */ int _dl_dynamic_weak; +/* 88 | 4 */ fpu_control_t _dl_fpu_control; +/* XXX 4-byte hole */ +/* 96 | 8 */ uint64_t _dl_hwcap; +/* 104 | 8 */ Elf64_auxv_t *_dl_auxv; +/* 112 | 128 */ struct cpu_features { +/* 112 | 8 */ unsigned long hwcap; +/* 120 | 8 */ unsigned long __reserved_hwcap2; +/* 128 | 8 */ unsigned long long __reserved; +/* 136 | 8 */ unsigned long long stfle_orig; +/* 144 | 8 */ unsigned long long stfle_filtered; +/* 152 | 88 */ unsigned long long __reserved2[11]; + + /* total size (bytes): 128 */ + } _dl_s390_cpu_features; +/* 240 | 8 */ const char *_dl_inhibit_rpath; +/* 248 | 8 */ const char *_dl_origin_path; +/* 256 | 8 */ size_t _dl_tls_static_size; +/* 264 | 8 */ size_t _dl_tls_static_align; +/* 272 | 8 */ size_t _dl_tls_static_surplus; +/* 280 | 8 */ const char *_dl_profile; +/* 288 | 8 */ const char *_dl_profile_output; +/* 296 | 8 */ struct r_search_path_elem *_dl_init_all_dirs; +/* 304 | 8 */ const Elf64_Ehdr *_dl_sysinfo_dso; +/* 312 | 8 */ struct link_map *_dl_sysinfo_map; +/* 320 | 8 */ int (*_dl_vdso_clock_gettime64)(clockid_t, struct timespec *); +/* 328 | 8 */ int (*_dl_vdso_gettimeofday)(struct timeval *, void *); +/* 336 | 8 */ int (*_dl_vdso_getcpu)(unsigned int *, unsigned int *, void *); +/* 344 | 8 */ int (*_dl_vdso_clock_getres_time64)(clockid_t, struct timespec *); +/* 352 | 8 */ ssize_t (*_dl_vdso_getrandom)(void *, size_t, unsigned int, void *, size_t); +/* 360 | 8 */ uint64_t _dl_hwcap2; +/* 368 | 8 */ uint64_t _dl_hwcap3; +/* 376 | 8 */ uint64_t _dl_hwcap4; +/* 384 | 4 */ enum dso_sort_algorithm _dl_dso_sort_algo; +/* XXX 4-byte hole */ +/* 392 | 8 */ void (*_dl_debug_printf)(const char *, ...); +/* 400 | 8 */ void (*_dl_mcount)(Elf64_Addr, Elf64_Addr); +/* 408 | 8 */ lookup_t (*_dl_lookup_symbol_x)(const char *, struct link_map *, const Elf64_Sym **, struct r_scope_elem **, const struct r_found_version *, int, int, struct link_map *); +/* 416 | 8 */ void *(*_dl_open)(const char *, int, const void *, Lmid_t, int, char **, char **); +/* 424 | 8 */ void (*_dl_close)(void *); +/* 432 | 8 */ int (*_dl_catch_error)(const char **, const char **, _Bool *, void (*)(void *), void *); +/* 440 | 8 */ void (*_dl_error_free)(void *); +/* 448 | 8 */ void *(*_dl_tls_get_addr_soft)(struct link_map *); +/* 456 | 8 */ void (*_dl_libc_freeres)(void); +/* 464 | 8 */ int (*_dl_find_object)(void *, struct dl_find_object *); +/* 472 | 8 */ const struct dlfcn_hook *_dl_dlfcn_hook; +/* 480 | 8 */ struct audit_ifaces *_dl_audit; +/* 488 | 4 */ unsigned int _dl_naudit; +/* XXX 4-byte padding */ + + /* total size (bytes): 496 */ + } +--- _rtld_global --- +/* offset | size */ type = struct rtld_global { +/* 0 | 2560 */ struct link_namespaces _dl_ns[16]; +/* 2560 | 8 */ size_t _dl_nns; +/* 2568 | 40 */ __rtld_lock_recursive_t _dl_load_lock; +/* 2608 | 40 */ __rtld_lock_recursive_t _dl_load_write_lock; +/* 2648 | 40 */ __rtld_lock_recursive_t _dl_load_tls_lock; +/* 2688 | 8 */ unsigned long long _dl_load_adds; +/* 2696 | 8 */ struct link_map *_dl_initfirst; +/* 2704 | 8 */ struct link_map *_dl_profile_map; +/* 2712 | 8 */ unsigned long _dl_num_relocations; +/* 2720 | 8 */ unsigned long _dl_num_cache_relocations; +/* 2728 | 8 */ struct r_search_path_elem *_dl_all_dirs; +/* 2736 | 1168 */ struct link_map { +/* 2736 | 8 */ Elf64_Addr l_addr; +/* 2744 | 8 */ char *l_name; +/* 2752 | 8 */ Elf64_Dyn *l_ld; +/* 2760 | 8 */ struct link_map *l_next; +/* 2768 | 8 */ struct link_map *l_prev; +/* 2776 | 8 */ struct link_map *l_real; +/* 2784 | 8 */ Lmid_t l_ns; +/* 2792 | 8 */ struct libname_list *l_libname; +/* 2800 | 640 */ Elf64_Dyn *l_info[80]; +/* 3440 | 8 */ const Elf64_Phdr *l_phdr; +/* 3448 | 8 */ Elf64_Addr l_entry; +/* 3456 | 2 */ Elf64_Half l_phnum; +/* 3458 | 2 */ Elf64_Half l_ldnum; +/* XXX 4-byte hole */ +/* 3464 | 16 */ struct r_scope_elem { +/* 3464 | 8 */ struct link_map **r_list; +/* 3472 | 4 */ unsigned int r_nlist; +/* XXX 4-byte padding */ + + /* total size (bytes): 16 */ + } l_searchlist; +/* 3480 | 16 */ struct r_scope_elem { +/* 3480 | 8 */ struct link_map **r_list; +/* 3488 | 4 */ unsigned int r_nlist; +/* XXX 4-byte padding */ + + /* total size (bytes): 16 */ + } l_symbolic_searchlist; +/* 3496 | 8 */ struct link_map *l_loader; +/* 3504 | 8 */ struct r_found_version *l_versions; +/* 3512 | 4 */ unsigned int l_nversions; +/* XXX 4-byte hole */ +/* 3520 | 8 */ Elf_Symndx l_nbuckets; +/* 3528 | 4 */ Elf32_Word l_gnu_bitmask_idxbits; +/* 3532 | 4 */ Elf32_Word l_gnu_shift; +/* 3536 | 8 */ const Elf64_Addr *l_gnu_bitmask; +/* 3544 | 8 */ union { +/* 8 */ const Elf32_Word *l_gnu_buckets; +/* 8 */ const Elf_Symndx *l_chain; + + /* total size (bytes): 8 */ + }; +/* 3552 | 8 */ union { +/* 8 */ const Elf32_Word *l_gnu_chain_zero; +/* 8 */ const Elf_Symndx *l_buckets; + + /* total size (bytes): 8 */ + }; +/* 3560 | 4 */ unsigned int l_direct_opencount; +/* 3564: 0 | 4 */ enum {lt_executable, lt_library, lt_loaded} l_type : 2; +/* 3564: 2 | 4 */ unsigned int l_dt_relr_ref : 1; +/* 3564: 3 | 4 */ unsigned int l_relocated : 1; +/* 3564: 4 | 4 */ unsigned int l_init_called : 1; +/* 3564: 5 | 4 */ unsigned int l_global : 1; +/* 3564: 6 | 4 */ unsigned int l_reserved : 2; +/* 3565: 0 | 4 */ unsigned int l_main_map : 1; +/* 3565: 1 | 4 */ unsigned int l_visited : 1; +/* 3565: 2 | 4 */ unsigned int l_map_used : 1; +/* 3565: 3 | 4 */ unsigned int l_map_done : 1; +/* 3565: 4 | 4 */ unsigned int l_phdr_allocated : 1; +/* 3565: 5 | 4 */ unsigned int l_soname_added : 1; +/* 3565: 6 | 4 */ unsigned int l_faked : 1; +/* 3565: 7 | 4 */ unsigned int l_need_tls_init : 1; +/* 3566: 0 | 4 */ unsigned int l_auditing : 1; +/* 3566: 1 | 4 */ unsigned int l_audit_any_plt : 1; +/* 3566: 2 | 4 */ unsigned int l_removed : 1; +/* 3566: 3 | 4 */ unsigned int l_contiguous : 1; +/* 3566: 4 | 4 */ unsigned int l_free_initfini : 1; +/* 3566: 5 | 4 */ unsigned int l_ld_readonly : 1; +/* 3566: 6 | 4 */ unsigned int l_find_object_processed : 1; +/* 3566: 7 | 4 */ unsigned int l_tls_in_slotinfo : 1; +/* 3567 | 1 */ _Bool l_nodelete_active; +/* 3568 | 1 */ _Bool l_nodelete_pending; +/* XXX 3-byte hole */ +/* 3572 | 4 */ unsigned int l_1_needed; +/* 3576 | 16 */ struct r_search_path_struct { +/* 3576 | 8 */ struct r_search_path_elem **dirs; +/* 3584 | 4 */ int malloced; +/* XXX 4-byte padding */ + + /* total size (bytes): 16 */ + } l_rpath_dirs; +/* 3592 | 8 */ struct reloc_result *l_reloc_result; +/* 3600 | 8 */ Elf64_Versym *l_versyms; +/* 3608 | 8 */ const char *l_origin; +/* 3616 | 8 */ Elf64_Addr l_map_start; +/* 3624 | 8 */ Elf64_Addr l_map_end; +/* 3632 | 32 */ struct r_scope_elem *l_scope_mem[4]; +/* 3664 | 8 */ size_t l_scope_max; +/* 3672 | 8 */ struct r_scope_elem **l_scope; +/* 3680 | 16 */ struct r_scope_elem *l_local_scope[2]; +/* 3696 | 16 */ struct r_file_id { +/* 3696 | 8 */ dev_t dev; +/* 3704 | 8 */ ino64_t ino; + + /* total size (bytes): 16 */ + } l_file_id; +/* 3712 | 16 */ struct r_search_path_struct { +/* 3712 | 8 */ struct r_search_path_elem **dirs; +/* 3720 | 4 */ int malloced; +/* XXX 4-byte padding */ + + /* total size (bytes): 16 */ + } l_runpath_dirs; +/* 3728 | 8 */ struct link_map **l_initfini; +/* 3736 | 8 */ struct link_map_reldeps *l_reldeps; +/* 3744 | 4 */ unsigned int l_reldepsmax; +/* 3748 | 4 */ unsigned int l_used; +/* 3752 | 4 */ Elf64_Word l_feature_1; +/* 3756 | 4 */ Elf64_Word l_flags_1; +/* 3760 | 4 */ Elf64_Word l_flags; +/* 3764 | 4 */ int l_idx; +/* 3768 | 16 */ struct link_map_machine { +/* 3768 | 8 */ Elf64_Addr plt; +/* 3776 | 8 */ const Elf64_Rela *jmprel; + + /* total size (bytes): 16 */ + } l_mach; +/* 3784 | 32 */ struct { +/* 3784 | 8 */ const Elf64_Sym *sym; +/* 3792 | 4 */ int type_class; +/* XXX 4-byte hole */ +/* 3800 | 8 */ struct link_map *value; +/* 3808 | 8 */ const Elf64_Sym *ret; + + /* total size (bytes): 32 */ + } l_lookup_cache; +/* 3816 | 8 */ void *l_tls_initimage; +/* 3824 | 8 */ size_t l_tls_initimage_size; +/* 3832 | 8 */ size_t l_tls_blocksize; +/* 3840 | 8 */ size_t l_tls_align; +/* 3848 | 8 */ size_t l_tls_firstbyte_offset; +/* 3856 | 8 */ ptrdiff_t l_tls_offset; +/* 3864 | 8 */ size_t l_tls_modid; +/* 3872 | 8 */ size_t l_tls_dtor_count; +/* 3880 | 8 */ Elf64_Addr l_relro_addr; +/* 3888 | 8 */ size_t l_relro_size; +/* 3896 | 8 */ unsigned long long l_serial; + + /* total size (bytes): 1168 */ + } _dl_rtld_map; +/* 3904 | 256 */ struct auditstate _dl_rtld_auditstate[16]; +/* 4160 | 4 */ Elf64_Word _dl_stack_flags; +/* 4164 | 1 */ _Bool _dl_tls_dtv_gaps; +/* XXX 3-byte hole */ +/* 4168 | 8 */ size_t _dl_tls_max_dtv_idx; +/* 4176 | 8 */ struct dtv_slotinfo_list *_dl_tls_dtv_slotinfo_list; +/* 4184 | 8 */ size_t _dl_tls_static_nelem; +/* 4192 | 8 */ size_t _dl_tls_static_used; +/* 4200 | 8 */ size_t _dl_tls_static_optional; +/* 4208 | 8 */ void *_dl_initial_dtv; +/* 4216 | 8 */ size_t _dl_tls_generation; +/* 4224 | 8 */ struct dl_scope_free_list *_dl_scope_free_list; +/* 4232 | 16 */ list_t _dl_stack_used; +/* 4248 | 16 */ list_t _dl_stack_user; +/* 4264 | 16 */ list_t _dl_stack_cache; +/* 4280 | 8 */ size_t _dl_stack_cache_actsize; +/* 4288 | 8 */ uintptr_t _dl_in_flight_stack; +/* 4296 | 4 */ int _dl_stack_cache_lock; +/* XXX 4-byte padding */ + + /* total size (bytes): 4304 */ + } +--- struct link_map --- +/* offset | size */ type = struct link_map { +/* 0 | 8 */ Elf64_Addr l_addr; +/* 8 | 8 */ char *l_name; +/* 16 | 8 */ Elf64_Dyn *l_ld; +/* 24 | 8 */ struct link_map *l_next; +/* 32 | 8 */ struct link_map *l_prev; +/* 40 | 8 */ struct link_map *l_real; +/* 48 | 8 */ Lmid_t l_ns; +/* 56 | 8 */ struct libname_list *l_libname; +/* 64 | 640 */ Elf64_Dyn *l_info[80]; +/* 704 | 8 */ const Elf64_Phdr *l_phdr; +/* 712 | 8 */ Elf64_Addr l_entry; +/* 720 | 2 */ Elf64_Half l_phnum; +/* 722 | 2 */ Elf64_Half l_ldnum; +/* XXX 4-byte hole */ +/* 728 | 16 */ struct r_scope_elem { +/* 728 | 8 */ struct link_map **r_list; +/* 736 | 4 */ unsigned int r_nlist; +/* XXX 4-byte padding */ + + /* total size (bytes): 16 */ + } l_searchlist; +/* 744 | 16 */ struct r_scope_elem { +/* 744 | 8 */ struct link_map **r_list; +/* 752 | 4 */ unsigned int r_nlist; +/* XXX 4-byte padding */ + + /* total size (bytes): 16 */ + } l_symbolic_searchlist; +/* 760 | 8 */ struct link_map *l_loader; +/* 768 | 8 */ struct r_found_version *l_versions; +/* 776 | 4 */ unsigned int l_nversions; +/* XXX 4-byte hole */ +/* 784 | 8 */ Elf_Symndx l_nbuckets; +/* 792 | 4 */ Elf32_Word l_gnu_bitmask_idxbits; +/* 796 | 4 */ Elf32_Word l_gnu_shift; +/* 800 | 8 */ const Elf64_Addr *l_gnu_bitmask; +/* 808 | 8 */ union { +/* 8 */ const Elf32_Word *l_gnu_buckets; +/* 8 */ const Elf_Symndx *l_chain; + + /* total size (bytes): 8 */ + }; +/* 816 | 8 */ union { +/* 8 */ const Elf32_Word *l_gnu_chain_zero; +/* 8 */ const Elf_Symndx *l_buckets; + + /* total size (bytes): 8 */ + }; +/* 824 | 4 */ unsigned int l_direct_opencount; +/* 828: 0 | 4 */ enum {lt_executable, lt_library, lt_loaded} l_type : 2; +/* 828: 2 | 4 */ unsigned int l_dt_relr_ref : 1; +/* 828: 3 | 4 */ unsigned int l_relocated : 1; +/* 828: 4 | 4 */ unsigned int l_init_called : 1; +/* 828: 5 | 4 */ unsigned int l_global : 1; +/* 828: 6 | 4 */ unsigned int l_reserved : 2; +/* 829: 0 | 4 */ unsigned int l_main_map : 1; +/* 829: 1 | 4 */ unsigned int l_visited : 1; +/* 829: 2 | 4 */ unsigned int l_map_used : 1; +/* 829: 3 | 4 */ unsigned int l_map_done : 1; +/* 829: 4 | 4 */ unsigned int l_phdr_allocated : 1; +/* 829: 5 | 4 */ unsigned int l_soname_added : 1; +/* 829: 6 | 4 */ unsigned int l_faked : 1; +/* 829: 7 | 4 */ unsigned int l_need_tls_init : 1; +/* 830: 0 | 4 */ unsigned int l_auditing : 1; +/* 830: 1 | 4 */ unsigned int l_audit_any_plt : 1; +/* 830: 2 | 4 */ unsigned int l_removed : 1; +/* 830: 3 | 4 */ unsigned int l_contiguous : 1; +/* 830: 4 | 4 */ unsigned int l_free_initfini : 1; +/* 830: 5 | 4 */ unsigned int l_ld_readonly : 1; +/* 830: 6 | 4 */ unsigned int l_find_object_processed : 1; +/* 830: 7 | 4 */ unsigned int l_tls_in_slotinfo : 1; +/* 831 | 1 */ _Bool l_nodelete_active; +/* 832 | 1 */ _Bool l_nodelete_pending; +/* XXX 3-byte hole */ +/* 836 | 4 */ unsigned int l_1_needed; +/* 840 | 16 */ struct r_search_path_struct { +/* 840 | 8 */ struct r_search_path_elem **dirs; +/* 848 | 4 */ int malloced; +/* XXX 4-byte padding */ + + /* total size (bytes): 16 */ + } l_rpath_dirs; +/* 856 | 8 */ struct reloc_result *l_reloc_result; +/* 864 | 8 */ Elf64_Versym *l_versyms; +/* 872 | 8 */ const char *l_origin; +/* 880 | 8 */ Elf64_Addr l_map_start; +/* 888 | 8 */ Elf64_Addr l_map_end; +/* 896 | 32 */ struct r_scope_elem *l_scope_mem[4]; +/* 928 | 8 */ size_t l_scope_max; +/* 936 | 8 */ struct r_scope_elem **l_scope; +/* 944 | 16 */ struct r_scope_elem *l_local_scope[2]; +/* 960 | 16 */ struct r_file_id { +/* 960 | 8 */ dev_t dev; +/* 968 | 8 */ ino64_t ino; + + /* total size (bytes): 16 */ + } l_file_id; +/* 976 | 16 */ struct r_search_path_struct { +/* 976 | 8 */ struct r_search_path_elem **dirs; +/* 984 | 4 */ int malloced; +/* XXX 4-byte padding */ + + /* total size (bytes): 16 */ + } l_runpath_dirs; +/* 992 | 8 */ struct link_map **l_initfini; +/* 1000 | 8 */ struct link_map_reldeps *l_reldeps; +/* 1008 | 4 */ unsigned int l_reldepsmax; +/* 1012 | 4 */ unsigned int l_used; +/* 1016 | 4 */ Elf64_Word l_feature_1; +/* 1020 | 4 */ Elf64_Word l_flags_1; +/* 1024 | 4 */ Elf64_Word l_flags; +/* 1028 | 4 */ int l_idx; +/* 1032 | 16 */ struct link_map_machine { +/* 1032 | 8 */ Elf64_Addr plt; +/* 1040 | 8 */ const Elf64_Rela *jmprel; + + /* total size (bytes): 16 */ + } l_mach; +/* 1048 | 32 */ struct { +/* 1048 | 8 */ const Elf64_Sym *sym; +/* 1056 | 4 */ int type_class; +/* XXX 4-byte hole */ +/* 1064 | 8 */ struct link_map *value; +/* 1072 | 8 */ const Elf64_Sym *ret; + + /* total size (bytes): 32 */ + } l_lookup_cache; +/* 1080 | 8 */ void *l_tls_initimage; +/* 1088 | 8 */ size_t l_tls_initimage_size; +/* 1096 | 8 */ size_t l_tls_blocksize; +/* 1104 | 8 */ size_t l_tls_align; +/* 1112 | 8 */ size_t l_tls_firstbyte_offset; +/* 1120 | 8 */ ptrdiff_t l_tls_offset; +/* 1128 | 8 */ size_t l_tls_modid; +/* 1136 | 8 */ size_t l_tls_dtor_count; +/* 1144 | 8 */ Elf64_Addr l_relro_addr; +/* 1152 | 8 */ size_t l_relro_size; +/* 1160 | 8 */ unsigned long long l_serial; + + /* total size (bytes): 1168 */ + } +--- struct pthread --- +/* offset | size */ type = struct pthread { +/* 0 | 192 */ union { +/* 64 */ tcbhead_t header; +/* 192 */ void *__padding[24]; + + /* total size (bytes): 192 */ + }; +/* 192 | 16 */ list_t list; +/* 208 | 4 */ pid_t tid; +/* XXX 4-byte hole */ +/* 216 | 8 */ void *robust_prev; +/* 224 | 24 */ struct robust_list_head { +/* 224 | 8 */ void *list; +/* 232 | 8 */ long futex_offset; +/* 240 | 8 */ void *list_op_pending; + + /* total size (bytes): 24 */ + } robust_head; +/* 248 | 8 */ struct _pthread_cleanup_buffer *cleanup; +/* 256 | 8 */ struct pthread_unwind_buf *cleanup_jmp_buf; +/* 264 | 4 */ int cancelhandling; +/* 268 | 4 */ int flags; +/* 272 | 512 */ struct pthread_key_data specific_1stblock[32]; +/* 784 | 256 */ struct pthread_key_data *specific[32]; +/* 1040 | 1 */ _Bool specific_used; +/* 1041 | 1 */ _Bool report_events; +/* 1042 | 1 */ _Bool user_stack; +/* 1043 | 1 */ _Bool stopped_start; +/* 1044 | 4 */ int setup_failed; +/* 1048 | 4 */ int lock; +/* 1052 | 4 */ unsigned int setxid_futex; +/* 1056 | 8 */ struct pthread *joinid; +/* 1064 | 8 */ void *result; +/* 1072 | 4 */ struct sched_param { +/* 1072 | 4 */ int sched_priority; + + /* total size (bytes): 4 */ + } schedparam; +/* 1076 | 4 */ int schedpolicy; +/* 1080 | 8 */ void *(*start_routine)(void *); +/* 1088 | 8 */ void *arg; +/* 1096 | 24 */ td_eventbuf_t eventbuf; +/* 1120 | 8 */ struct pthread *nextevent; +/* XXX 8-byte hole */ +/* 1136 | 32 */ struct _Unwind_Exception { +/* 1136 | 32 */ union { +/* 32 */ struct { +/* 1136 | 8 */ _Unwind_Exception_Class exception_class; +/* 1144 | 8 */ _Unwind_Exception_Cleanup_Fn exception_cleanup; +/* 1152 | 8 */ _Unwind_Word private_1; +/* 1160 | 8 */ _Unwind_Word private_2; + + /* total size (bytes): 32 */ + }; +/* 16 */ _Unwind_Word unwind_exception_align[2]; + + /* total size (bytes): 32 */ + }; + + /* total size (bytes): 32 */ + } exc; +/* 1168 | 8 */ void *stackblock; +/* 1176 | 8 */ size_t stackblock_size; +/* 1184 | 8 */ size_t guardsize; +/* 1192 | 8 */ size_t reported_guardsize; +/* 1200 | 8 */ struct priority_protection_data *tpp; +/* 1208 | 568 */ struct __res_state { +/* 1208 | 4 */ int retrans; +/* 1212 | 4 */ int retry; +/* 1216 | 8 */ unsigned long options; +/* 1224 | 4 */ int nscount; +/* 1228 | 48 */ struct sockaddr_in nsaddr_list[3]; +/* 1276 | 2 */ unsigned short id; +/* XXX 2-byte hole */ +/* 1280 | 56 */ char *dnsrch[7]; +/* 1336 | 256 */ char defdname[256]; +/* 1592 | 8 */ unsigned long pfcode; +/* 1600: 0 | 4 */ unsigned int ndots : 4; +/* 1600: 4 | 4 */ unsigned int nsort : 4; +/* 1601: 0 | 4 */ unsigned int ipv6_unavail : 1; +/* 1601: 1 | 4 */ unsigned int unused : 23; +/* 1604 | 80 */ struct { +/* 0 | 4 */ struct in_addr addr; +/* 4 | 4 */ uint32_t mask; + } sort_list[10]; +/* XXX 4-byte hole */ +/* 1688 | 8 */ void *__glibc_unused_qhook; +/* 1696 | 8 */ void *__glibc_unused_rhook; +/* 1704 | 4 */ int res_h_errno; +/* 1708 | 4 */ int _vcsock; +/* 1712 | 4 */ unsigned int _flags; +/* XXX 4-byte hole */ +/* 1720 | 56 */ union { +/* 52 */ char pad[52]; +/* 56 */ struct { +/* 1720 | 2 */ uint16_t nscount; +/* 1722 | 6 */ uint16_t nsmap[3]; +/* 1728 | 12 */ int nssocks[3]; +/* 1740 | 2 */ uint16_t nscount6; +/* 1742 | 2 */ uint16_t nsinit; +/* 1744 | 24 */ struct sockaddr_in6 *nsaddrs[3]; +/* 1768 | 8 */ unsigned long long __glibc_extension_index; + + /* total size (bytes): 56 */ + } _ext; + + /* total size (bytes): 56 */ + } _u; + + /* total size (bytes): 568 */ + } res; +/* 1776 | 8 */ internal_sigset_t sigmask; +/* 1784 | 8 */ struct rtld_catch *rtld_catch; +/* 1792 | 1 */ _Bool c11; +/* 1793 | 1 */ _Bool exiting; +/* XXX 2-byte hole */ +/* 1796 | 4 */ int exit_lock; +/* 1800 | 16 */ struct tls_internal_t { +/* 1800 | 8 */ char *strsignal_buf; +/* 1808 | 8 */ char *strerror_l_buf; + + /* total size (bytes): 16 */ + } tls_state; +/* 1816 | 8 */ void *getrandom_buf; +/* 1824 | 32 */ union { +/* 24 */ struct { +/* 1824 | 4 */ uint32_t cpu_id_start; +/* 1828 | 4 */ uint32_t cpu_id; +/* 1832 | 8 */ uint64_t rseq_cs; +/* 1840 | 4 */ uint32_t flags; +/* XXX 4-byte padding */ + + /* total size (bytes): 24 */ + }; +/* 32 */ char pad[32]; + + /* total size (bytes): 32 */ + } rseq_area; + + /* total size (bytes): 1856 */ + } diff --git a/ld-so-abi-x86_64.baseline b/ld-so-abi-x86_64.baseline new file mode 100644 index 0000000..855abc6 --- /dev/null +++ b/ld-so-abi-x86_64.baseline @@ -0,0 +1,591 @@ +--- _rtld_global_ro --- +/* offset | size */ type = struct rtld_global_ro { +/* 0 | 4 */ int _dl_debug_mask; +/* XXX 4-byte hole */ +/* 8 | 8 */ const char *_dl_platform; +/* 16 | 8 */ size_t _dl_platformlen; +/* 24 | 8 */ size_t _dl_pagesize; +/* 32 | 8 */ size_t _dl_minsigstacksize; +/* 40 | 4 */ int _dl_inhibit_cache; +/* XXX 4-byte hole */ +/* 48 | 16 */ struct r_scope_elem { +/* 48 | 8 */ struct link_map **r_list; +/* 56 | 4 */ unsigned int r_nlist; +/* XXX 4-byte padding */ + + /* total size (bytes): 16 */ + } _dl_initial_searchlist; +/* 64 | 4 */ int _dl_clktck; +/* 68 | 4 */ int _dl_verbose; +/* 72 | 4 */ int _dl_debug_fd; +/* 76 | 4 */ int _dl_lazy; +/* 80 | 4 */ int _dl_bind_not; +/* 84 | 4 */ int _dl_dynamic_weak; +/* 88 | 2 */ fpu_control_t _dl_fpu_control; +/* XXX 6-byte hole */ +/* 96 | 8 */ uint64_t _dl_hwcap; +/* 104 | 8 */ Elf64_auxv_t *_dl_auxv; +/* 112 | 520 */ struct cpu_features { +/* 112 | 20 */ struct cpu_features_basic { +/* 112 | 4 */ enum cpu_features_kind kind; +/* 116 | 4 */ int max_cpuid; +/* 120 | 4 */ unsigned int family; +/* 124 | 4 */ unsigned int model; +/* 128 | 4 */ unsigned int stepping; + + /* total size (bytes): 20 */ + } basic; +/* 132 | 320 */ struct cpuid_feature_internal features[10]; +/* 452 | 4 */ unsigned int preferred[1]; +/* 456 | 4 */ unsigned int isa_1; +/* XXX 4-byte hole */ +/* 464 | 8 */ unsigned long xsave_state_size; +/* 472 | 4 */ unsigned int xsave_state_full_size; +/* XXX 4-byte hole */ +/* 480 | 8 */ unsigned long data_cache_size; +/* 488 | 8 */ unsigned long shared_cache_size; +/* 496 | 8 */ unsigned long non_temporal_threshold; +/* 504 | 8 */ unsigned long rep_movsb_threshold; +/* 512 | 8 */ unsigned long rep_movsb_stop_threshold; +/* 520 | 8 */ unsigned long rep_stosb_threshold; +/* 528 | 8 */ unsigned long level1_icache_size; +/* 536 | 8 */ unsigned long level1_icache_linesize; +/* 544 | 8 */ unsigned long level1_dcache_size; +/* 552 | 8 */ unsigned long level1_dcache_assoc; +/* 560 | 8 */ unsigned long level1_dcache_linesize; +/* 568 | 8 */ unsigned long level2_cache_size; +/* 576 | 8 */ unsigned long level2_cache_assoc; +/* 584 | 8 */ unsigned long level2_cache_linesize; +/* 592 | 8 */ unsigned long level3_cache_size; +/* 600 | 8 */ unsigned long level3_cache_assoc; +/* 608 | 8 */ unsigned long level3_cache_linesize; +/* 616 | 8 */ unsigned long level4_cache_size; +/* 624 | 8 */ unsigned long cachesize_non_temporal_divisor; + + /* total size (bytes): 520 */ + } _dl_x86_cpu_features; +/* 632 | 27 */ const char _dl_x86_hwcap_flags[3][9]; +/* 659 | 36 */ const char _dl_x86_platforms[4][9]; +/* XXX 1-byte hole */ +/* 696 | 8 */ void *_dl_x86_tlsdesc_dynamic; +/* 704 | 8 */ void *_dl_x86_64_runtime_resolve; +/* 712 | 8 */ const char *_dl_inhibit_rpath; +/* 720 | 8 */ const char *_dl_origin_path; +/* 728 | 8 */ size_t _dl_tls_static_size; +/* 736 | 8 */ size_t _dl_tls_static_align; +/* 744 | 8 */ size_t _dl_tls_static_surplus; +/* 752 | 8 */ const char *_dl_profile; +/* 760 | 8 */ const char *_dl_profile_output; +/* 768 | 8 */ struct r_search_path_elem *_dl_init_all_dirs; +/* 776 | 8 */ const Elf64_Ehdr *_dl_sysinfo_dso; +/* 784 | 8 */ struct link_map *_dl_sysinfo_map; +/* 792 | 8 */ int (*_dl_vdso_clock_gettime64)(clockid_t, struct timespec *); +/* 800 | 8 */ int (*_dl_vdso_gettimeofday)(struct timeval *, void *); +/* 808 | 8 */ time_t (*_dl_vdso_time)(time_t *); +/* 816 | 8 */ int (*_dl_vdso_getcpu)(unsigned int *, unsigned int *, void *); +/* 824 | 8 */ int (*_dl_vdso_clock_getres_time64)(clockid_t, struct timespec *); +/* 832 | 8 */ ssize_t (*_dl_vdso_getrandom)(void *, size_t, unsigned int, void *, size_t); +/* 840 | 8 */ uint64_t _dl_hwcap2; +/* 848 | 8 */ uint64_t _dl_hwcap3; +/* 856 | 8 */ uint64_t _dl_hwcap4; +/* 864 | 4 */ enum dso_sort_algorithm _dl_dso_sort_algo; +/* XXX 4-byte hole */ +/* 872 | 8 */ void (*_dl_debug_printf)(const char *, ...); +/* 880 | 8 */ void (*_dl_mcount)(Elf64_Addr, Elf64_Addr); +/* 888 | 8 */ lookup_t (*_dl_lookup_symbol_x)(const char *, struct link_map *, const Elf64_Sym **, struct r_scope_elem **, const struct r_found_version *, int, int, struct link_map *); +/* 896 | 8 */ void *(*_dl_open)(const char *, int, const void *, Lmid_t, int, char **, char **); +/* 904 | 8 */ void (*_dl_close)(void *); +/* 912 | 8 */ int (*_dl_catch_error)(const char **, const char **, _Bool *, void (*)(void *), void *); +/* 920 | 8 */ void (*_dl_error_free)(void *); +/* 928 | 8 */ void *(*_dl_tls_get_addr_soft)(struct link_map *); +/* 936 | 8 */ void (*_dl_libc_freeres)(void); +/* 944 | 8 */ int (*_dl_find_object)(void *, struct dl_find_object *); +/* 952 | 8 */ const struct dlfcn_hook *_dl_dlfcn_hook; +/* 960 | 8 */ struct audit_ifaces *_dl_audit; +/* 968 | 4 */ unsigned int _dl_naudit; +/* XXX 4-byte padding */ + + /* total size (bytes): 976 */ + } +--- _rtld_global --- +/* offset | size */ type = struct rtld_global { +/* 0 | 2560 */ struct link_namespaces _dl_ns[16]; +/* 2560 | 8 */ size_t _dl_nns; +/* 2568 | 40 */ __rtld_lock_recursive_t _dl_load_lock; +/* 2608 | 40 */ __rtld_lock_recursive_t _dl_load_write_lock; +/* 2648 | 40 */ __rtld_lock_recursive_t _dl_load_tls_lock; +/* 2688 | 8 */ unsigned long long _dl_load_adds; +/* 2696 | 8 */ struct link_map *_dl_initfirst; +/* 2704 | 8 */ struct link_map *_dl_profile_map; +/* 2712 | 8 */ unsigned long _dl_num_relocations; +/* 2720 | 8 */ unsigned long _dl_num_cache_relocations; +/* 2728 | 8 */ struct r_search_path_elem *_dl_all_dirs; +/* 2736 | 1208 */ struct link_map { +/* 2736 | 8 */ Elf64_Addr l_addr; +/* 2744 | 8 */ char *l_name; +/* 2752 | 8 */ Elf64_Dyn *l_ld; +/* 2760 | 8 */ struct link_map *l_next; +/* 2768 | 8 */ struct link_map *l_prev; +/* 2776 | 8 */ struct link_map *l_real; +/* 2784 | 8 */ Lmid_t l_ns; +/* 2792 | 8 */ struct libname_list *l_libname; +/* 2800 | 672 */ Elf64_Dyn *l_info[84]; +/* 3472 | 8 */ const Elf64_Phdr *l_phdr; +/* 3480 | 8 */ Elf64_Addr l_entry; +/* 3488 | 2 */ Elf64_Half l_phnum; +/* 3490 | 2 */ Elf64_Half l_ldnum; +/* XXX 4-byte hole */ +/* 3496 | 16 */ struct r_scope_elem { +/* 3496 | 8 */ struct link_map **r_list; +/* 3504 | 4 */ unsigned int r_nlist; +/* XXX 4-byte padding */ + + /* total size (bytes): 16 */ + } l_searchlist; +/* 3512 | 16 */ struct r_scope_elem { +/* 3512 | 8 */ struct link_map **r_list; +/* 3520 | 4 */ unsigned int r_nlist; +/* XXX 4-byte padding */ + + /* total size (bytes): 16 */ + } l_symbolic_searchlist; +/* 3528 | 8 */ struct link_map *l_loader; +/* 3536 | 8 */ struct r_found_version *l_versions; +/* 3544 | 4 */ unsigned int l_nversions; +/* 3548 | 4 */ Elf_Symndx l_nbuckets; +/* 3552 | 4 */ Elf32_Word l_gnu_bitmask_idxbits; +/* 3556 | 4 */ Elf32_Word l_gnu_shift; +/* 3560 | 8 */ const Elf64_Addr *l_gnu_bitmask; +/* 3568 | 8 */ union { +/* 8 */ const Elf32_Word *l_gnu_buckets; +/* 8 */ const Elf_Symndx *l_chain; + + /* total size (bytes): 8 */ + }; +/* 3576 | 8 */ union { +/* 8 */ const Elf32_Word *l_gnu_chain_zero; +/* 8 */ const Elf_Symndx *l_buckets; + + /* total size (bytes): 8 */ + }; +/* 3584 | 4 */ unsigned int l_direct_opencount; +/* 3588: 0 | 4 */ enum {lt_executable, lt_library, lt_loaded} l_type : 2; +/* 3588: 2 | 4 */ unsigned int l_dt_relr_ref : 1; +/* 3588: 3 | 4 */ unsigned int l_relocated : 1; +/* 3588: 4 | 4 */ unsigned int l_init_called : 1; +/* 3588: 5 | 4 */ unsigned int l_global : 1; +/* 3588: 6 | 4 */ unsigned int l_reserved : 2; +/* 3589: 0 | 4 */ unsigned int l_main_map : 1; +/* 3589: 1 | 4 */ unsigned int l_visited : 1; +/* 3589: 2 | 4 */ unsigned int l_map_used : 1; +/* 3589: 3 | 4 */ unsigned int l_map_done : 1; +/* 3589: 4 | 4 */ unsigned int l_phdr_allocated : 1; +/* 3589: 5 | 4 */ unsigned int l_soname_added : 1; +/* 3589: 6 | 4 */ unsigned int l_faked : 1; +/* 3589: 7 | 4 */ unsigned int l_need_tls_init : 1; +/* 3590: 0 | 4 */ unsigned int l_auditing : 1; +/* 3590: 1 | 4 */ unsigned int l_audit_any_plt : 1; +/* 3590: 2 | 4 */ unsigned int l_removed : 1; +/* 3590: 3 | 4 */ unsigned int l_contiguous : 1; +/* 3590: 4 | 4 */ unsigned int l_free_initfini : 1; +/* 3590: 5 | 4 */ unsigned int l_ld_readonly : 1; +/* 3590: 6 | 4 */ unsigned int l_find_object_processed : 1; +/* 3590: 7 | 4 */ unsigned int l_tls_in_slotinfo : 1; +/* 3591 | 1 */ _Bool l_nodelete_active; +/* 3592 | 1 */ _Bool l_nodelete_pending; +/* 3593 | 1 */ _Bool l_has_jump_slot_reloc; +/* 3594: 0 | 4 */ enum {lc_property_unknown, lc_property_none, lc_property_valid} l_property : 2; +/* XXX 6-bit hole */ +/* XXX 1-byte hole */ +/* 3596 | 4 */ unsigned int l_x86_feature_1_and; +/* 3600 | 4 */ unsigned int l_x86_isa_1_needed; +/* 3604 | 4 */ unsigned int l_1_needed; +/* 3608 | 16 */ struct r_search_path_struct { +/* 3608 | 8 */ struct r_search_path_elem **dirs; +/* 3616 | 4 */ int malloced; +/* XXX 4-byte padding */ + + /* total size (bytes): 16 */ + } l_rpath_dirs; +/* 3624 | 8 */ struct reloc_result *l_reloc_result; +/* 3632 | 8 */ Elf64_Versym *l_versyms; +/* 3640 | 8 */ const char *l_origin; +/* 3648 | 8 */ Elf64_Addr l_map_start; +/* 3656 | 8 */ Elf64_Addr l_map_end; +/* 3664 | 32 */ struct r_scope_elem *l_scope_mem[4]; +/* 3696 | 8 */ size_t l_scope_max; +/* 3704 | 8 */ struct r_scope_elem **l_scope; +/* 3712 | 16 */ struct r_scope_elem *l_local_scope[2]; +/* 3728 | 16 */ struct r_file_id { +/* 3728 | 8 */ dev_t dev; +/* 3736 | 8 */ ino64_t ino; + + /* total size (bytes): 16 */ + } l_file_id; +/* 3744 | 16 */ struct r_search_path_struct { +/* 3744 | 8 */ struct r_search_path_elem **dirs; +/* 3752 | 4 */ int malloced; +/* XXX 4-byte padding */ + + /* total size (bytes): 16 */ + } l_runpath_dirs; +/* 3760 | 8 */ struct link_map **l_initfini; +/* 3768 | 8 */ struct link_map_reldeps *l_reldeps; +/* 3776 | 4 */ unsigned int l_reldepsmax; +/* 3780 | 4 */ unsigned int l_used; +/* 3784 | 4 */ Elf64_Word l_feature_1; +/* 3788 | 4 */ Elf64_Word l_flags_1; +/* 3792 | 4 */ Elf64_Word l_flags; +/* 3796 | 4 */ int l_idx; +/* 3800 | 24 */ struct link_map_machine { +/* 3800 | 8 */ Elf64_Addr plt; +/* 3808 | 8 */ Elf64_Addr gotplt; +/* 3816 | 8 */ void *tlsdesc_table; + + /* total size (bytes): 24 */ + } l_mach; +/* 3824 | 32 */ struct { +/* 3824 | 8 */ const Elf64_Sym *sym; +/* 3832 | 4 */ int type_class; +/* XXX 4-byte hole */ +/* 3840 | 8 */ struct link_map *value; +/* 3848 | 8 */ const Elf64_Sym *ret; + + /* total size (bytes): 32 */ + } l_lookup_cache; +/* 3856 | 8 */ void *l_tls_initimage; +/* 3864 | 8 */ size_t l_tls_initimage_size; +/* 3872 | 8 */ size_t l_tls_blocksize; +/* 3880 | 8 */ size_t l_tls_align; +/* 3888 | 8 */ size_t l_tls_firstbyte_offset; +/* 3896 | 8 */ ptrdiff_t l_tls_offset; +/* 3904 | 8 */ size_t l_tls_modid; +/* 3912 | 8 */ size_t l_tls_dtor_count; +/* 3920 | 8 */ Elf64_Addr l_relro_addr; +/* 3928 | 8 */ size_t l_relro_size; +/* 3936 | 8 */ unsigned long long l_serial; + + /* total size (bytes): 1208 */ + } _dl_rtld_map; +/* 3944 | 256 */ struct auditstate _dl_rtld_auditstate[16]; +/* 4200 | 4 */ unsigned int _dl_x86_feature_1; +/* 4204 | 4 */ struct dl_x86_feature_control { +/* 4204: 0 | 4 */ enum dl_x86_cet_control ibt : 2; +/* 4204: 2 | 4 */ enum dl_x86_cet_control shstk : 2; +/* 4204: 4 | 4 */ enum dl_plt_rewrite_control plt_rewrite : 2; +/* XXX 2-bit padding */ +/* XXX 3-byte padding */ + + /* total size (bytes): 4 */ + } _dl_x86_feature_control; +/* 4208 | 4 */ Elf64_Word _dl_stack_flags; +/* 4212 | 1 */ _Bool _dl_tls_dtv_gaps; +/* XXX 3-byte hole */ +/* 4216 | 8 */ size_t _dl_tls_max_dtv_idx; +/* 4224 | 8 */ struct dtv_slotinfo_list *_dl_tls_dtv_slotinfo_list; +/* 4232 | 8 */ size_t _dl_tls_static_nelem; +/* 4240 | 8 */ size_t _dl_tls_static_used; +/* 4248 | 8 */ size_t _dl_tls_static_optional; +/* 4256 | 8 */ void *_dl_initial_dtv; +/* 4264 | 8 */ size_t _dl_tls_generation; +/* 4272 | 8 */ struct dl_scope_free_list *_dl_scope_free_list; +/* 4280 | 16 */ list_t _dl_stack_used; +/* 4296 | 16 */ list_t _dl_stack_user; +/* 4312 | 16 */ list_t _dl_stack_cache; +/* 4328 | 8 */ size_t _dl_stack_cache_actsize; +/* 4336 | 8 */ uintptr_t _dl_in_flight_stack; +/* 4344 | 4 */ int _dl_stack_cache_lock; +/* XXX 4-byte padding */ + + /* total size (bytes): 4352 */ + } +--- struct link_map --- +/* offset | size */ type = struct link_map { +/* 0 | 8 */ Elf64_Addr l_addr; +/* 8 | 8 */ char *l_name; +/* 16 | 8 */ Elf64_Dyn *l_ld; +/* 24 | 8 */ struct link_map *l_next; +/* 32 | 8 */ struct link_map *l_prev; +/* 40 | 8 */ struct link_map *l_real; +/* 48 | 8 */ Lmid_t l_ns; +/* 56 | 8 */ struct libname_list *l_libname; +/* 64 | 672 */ Elf64_Dyn *l_info[84]; +/* 736 | 8 */ const Elf64_Phdr *l_phdr; +/* 744 | 8 */ Elf64_Addr l_entry; +/* 752 | 2 */ Elf64_Half l_phnum; +/* 754 | 2 */ Elf64_Half l_ldnum; +/* XXX 4-byte hole */ +/* 760 | 16 */ struct r_scope_elem { +/* 760 | 8 */ struct link_map **r_list; +/* 768 | 4 */ unsigned int r_nlist; +/* XXX 4-byte padding */ + + /* total size (bytes): 16 */ + } l_searchlist; +/* 776 | 16 */ struct r_scope_elem { +/* 776 | 8 */ struct link_map **r_list; +/* 784 | 4 */ unsigned int r_nlist; +/* XXX 4-byte padding */ + + /* total size (bytes): 16 */ + } l_symbolic_searchlist; +/* 792 | 8 */ struct link_map *l_loader; +/* 800 | 8 */ struct r_found_version *l_versions; +/* 808 | 4 */ unsigned int l_nversions; +/* 812 | 4 */ Elf_Symndx l_nbuckets; +/* 816 | 4 */ Elf32_Word l_gnu_bitmask_idxbits; +/* 820 | 4 */ Elf32_Word l_gnu_shift; +/* 824 | 8 */ const Elf64_Addr *l_gnu_bitmask; +/* 832 | 8 */ union { +/* 8 */ const Elf32_Word *l_gnu_buckets; +/* 8 */ const Elf_Symndx *l_chain; + + /* total size (bytes): 8 */ + }; +/* 840 | 8 */ union { +/* 8 */ const Elf32_Word *l_gnu_chain_zero; +/* 8 */ const Elf_Symndx *l_buckets; + + /* total size (bytes): 8 */ + }; +/* 848 | 4 */ unsigned int l_direct_opencount; +/* 852: 0 | 4 */ enum {lt_executable, lt_library, lt_loaded} l_type : 2; +/* 852: 2 | 4 */ unsigned int l_dt_relr_ref : 1; +/* 852: 3 | 4 */ unsigned int l_relocated : 1; +/* 852: 4 | 4 */ unsigned int l_init_called : 1; +/* 852: 5 | 4 */ unsigned int l_global : 1; +/* 852: 6 | 4 */ unsigned int l_reserved : 2; +/* 853: 0 | 4 */ unsigned int l_main_map : 1; +/* 853: 1 | 4 */ unsigned int l_visited : 1; +/* 853: 2 | 4 */ unsigned int l_map_used : 1; +/* 853: 3 | 4 */ unsigned int l_map_done : 1; +/* 853: 4 | 4 */ unsigned int l_phdr_allocated : 1; +/* 853: 5 | 4 */ unsigned int l_soname_added : 1; +/* 853: 6 | 4 */ unsigned int l_faked : 1; +/* 853: 7 | 4 */ unsigned int l_need_tls_init : 1; +/* 854: 0 | 4 */ unsigned int l_auditing : 1; +/* 854: 1 | 4 */ unsigned int l_audit_any_plt : 1; +/* 854: 2 | 4 */ unsigned int l_removed : 1; +/* 854: 3 | 4 */ unsigned int l_contiguous : 1; +/* 854: 4 | 4 */ unsigned int l_free_initfini : 1; +/* 854: 5 | 4 */ unsigned int l_ld_readonly : 1; +/* 854: 6 | 4 */ unsigned int l_find_object_processed : 1; +/* 854: 7 | 4 */ unsigned int l_tls_in_slotinfo : 1; +/* 855 | 1 */ _Bool l_nodelete_active; +/* 856 | 1 */ _Bool l_nodelete_pending; +/* 857 | 1 */ _Bool l_has_jump_slot_reloc; +/* 858: 0 | 4 */ enum {lc_property_unknown, lc_property_none, lc_property_valid} l_property : 2; +/* XXX 6-bit hole */ +/* XXX 1-byte hole */ +/* 860 | 4 */ unsigned int l_x86_feature_1_and; +/* 864 | 4 */ unsigned int l_x86_isa_1_needed; +/* 868 | 4 */ unsigned int l_1_needed; +/* 872 | 16 */ struct r_search_path_struct { +/* 872 | 8 */ struct r_search_path_elem **dirs; +/* 880 | 4 */ int malloced; +/* XXX 4-byte padding */ + + /* total size (bytes): 16 */ + } l_rpath_dirs; +/* 888 | 8 */ struct reloc_result *l_reloc_result; +/* 896 | 8 */ Elf64_Versym *l_versyms; +/* 904 | 8 */ const char *l_origin; +/* 912 | 8 */ Elf64_Addr l_map_start; +/* 920 | 8 */ Elf64_Addr l_map_end; +/* 928 | 32 */ struct r_scope_elem *l_scope_mem[4]; +/* 960 | 8 */ size_t l_scope_max; +/* 968 | 8 */ struct r_scope_elem **l_scope; +/* 976 | 16 */ struct r_scope_elem *l_local_scope[2]; +/* 992 | 16 */ struct r_file_id { +/* 992 | 8 */ dev_t dev; +/* 1000 | 8 */ ino64_t ino; + + /* total size (bytes): 16 */ + } l_file_id; +/* 1008 | 16 */ struct r_search_path_struct { +/* 1008 | 8 */ struct r_search_path_elem **dirs; +/* 1016 | 4 */ int malloced; +/* XXX 4-byte padding */ + + /* total size (bytes): 16 */ + } l_runpath_dirs; +/* 1024 | 8 */ struct link_map **l_initfini; +/* 1032 | 8 */ struct link_map_reldeps *l_reldeps; +/* 1040 | 4 */ unsigned int l_reldepsmax; +/* 1044 | 4 */ unsigned int l_used; +/* 1048 | 4 */ Elf64_Word l_feature_1; +/* 1052 | 4 */ Elf64_Word l_flags_1; +/* 1056 | 4 */ Elf64_Word l_flags; +/* 1060 | 4 */ int l_idx; +/* 1064 | 24 */ struct link_map_machine { +/* 1064 | 8 */ Elf64_Addr plt; +/* 1072 | 8 */ Elf64_Addr gotplt; +/* 1080 | 8 */ void *tlsdesc_table; + + /* total size (bytes): 24 */ + } l_mach; +/* 1088 | 32 */ struct { +/* 1088 | 8 */ const Elf64_Sym *sym; +/* 1096 | 4 */ int type_class; +/* XXX 4-byte hole */ +/* 1104 | 8 */ struct link_map *value; +/* 1112 | 8 */ const Elf64_Sym *ret; + + /* total size (bytes): 32 */ + } l_lookup_cache; +/* 1120 | 8 */ void *l_tls_initimage; +/* 1128 | 8 */ size_t l_tls_initimage_size; +/* 1136 | 8 */ size_t l_tls_blocksize; +/* 1144 | 8 */ size_t l_tls_align; +/* 1152 | 8 */ size_t l_tls_firstbyte_offset; +/* 1160 | 8 */ ptrdiff_t l_tls_offset; +/* 1168 | 8 */ size_t l_tls_modid; +/* 1176 | 8 */ size_t l_tls_dtor_count; +/* 1184 | 8 */ Elf64_Addr l_relro_addr; +/* 1192 | 8 */ size_t l_relro_size; +/* 1200 | 8 */ unsigned long long l_serial; + + /* total size (bytes): 1208 */ + } +--- struct pthread --- +/* offset | size */ type = struct pthread { +/* 0 | 704 */ union { +/* 704 */ tcbhead_t header; +/* 192 */ void *__padding[24]; + + /* total size (bytes): 704 */ + }; +/* 704 | 16 */ list_t list; +/* 720 | 4 */ pid_t tid; +/* XXX 4-byte hole */ +/* 728 | 8 */ void *robust_prev; +/* 736 | 24 */ struct robust_list_head { +/* 736 | 8 */ void *list; +/* 744 | 8 */ long futex_offset; +/* 752 | 8 */ void *list_op_pending; + + /* total size (bytes): 24 */ + } robust_head; +/* 760 | 8 */ struct _pthread_cleanup_buffer *cleanup; +/* 768 | 8 */ struct pthread_unwind_buf *cleanup_jmp_buf; +/* 776 | 4 */ int cancelhandling; +/* 780 | 4 */ int flags; +/* 784 | 512 */ struct pthread_key_data specific_1stblock[32]; +/* 1296 | 256 */ struct pthread_key_data *specific[32]; +/* 1552 | 1 */ _Bool specific_used; +/* 1553 | 1 */ _Bool report_events; +/* 1554 | 1 */ _Bool user_stack; +/* 1555 | 1 */ _Bool stopped_start; +/* 1556 | 4 */ int setup_failed; +/* 1560 | 4 */ int lock; +/* 1564 | 4 */ unsigned int setxid_futex; +/* 1568 | 8 */ struct pthread *joinid; +/* 1576 | 8 */ void *result; +/* 1584 | 4 */ struct sched_param { +/* 1584 | 4 */ int sched_priority; + + /* total size (bytes): 4 */ + } schedparam; +/* 1588 | 4 */ int schedpolicy; +/* 1592 | 8 */ void *(*start_routine)(void *); +/* 1600 | 8 */ void *arg; +/* 1608 | 24 */ td_eventbuf_t eventbuf; +/* 1632 | 8 */ struct pthread *nextevent; +/* XXX 8-byte hole */ +/* 1648 | 32 */ struct _Unwind_Exception { +/* 1648 | 32 */ union { +/* 32 */ struct { +/* 1648 | 8 */ _Unwind_Exception_Class exception_class; +/* 1656 | 8 */ _Unwind_Exception_Cleanup_Fn exception_cleanup; +/* 1664 | 8 */ _Unwind_Word private_1; +/* 1672 | 8 */ _Unwind_Word private_2; + + /* total size (bytes): 32 */ + }; +/* 16 */ _Unwind_Word unwind_exception_align[2]; + + /* total size (bytes): 32 */ + }; + + /* total size (bytes): 32 */ + } exc; +/* 1680 | 8 */ void *stackblock; +/* 1688 | 8 */ size_t stackblock_size; +/* 1696 | 8 */ size_t guardsize; +/* 1704 | 8 */ size_t reported_guardsize; +/* 1712 | 8 */ struct priority_protection_data *tpp; +/* 1720 | 568 */ struct __res_state { +/* 1720 | 4 */ int retrans; +/* 1724 | 4 */ int retry; +/* 1728 | 8 */ unsigned long options; +/* 1736 | 4 */ int nscount; +/* 1740 | 48 */ struct sockaddr_in nsaddr_list[3]; +/* 1788 | 2 */ unsigned short id; +/* XXX 2-byte hole */ +/* 1792 | 56 */ char *dnsrch[7]; +/* 1848 | 256 */ char defdname[256]; +/* 2104 | 8 */ unsigned long pfcode; +/* 2112: 0 | 4 */ unsigned int ndots : 4; +/* 2112: 4 | 4 */ unsigned int nsort : 4; +/* 2113: 0 | 4 */ unsigned int ipv6_unavail : 1; +/* 2113: 1 | 4 */ unsigned int unused : 23; +/* 2116 | 80 */ struct { +/* 0 | 4 */ struct in_addr addr; +/* 4 | 4 */ uint32_t mask; + } sort_list[10]; +/* XXX 4-byte hole */ +/* 2200 | 8 */ void *__glibc_unused_qhook; +/* 2208 | 8 */ void *__glibc_unused_rhook; +/* 2216 | 4 */ int res_h_errno; +/* 2220 | 4 */ int _vcsock; +/* 2224 | 4 */ unsigned int _flags; +/* XXX 4-byte hole */ +/* 2232 | 56 */ union { +/* 52 */ char pad[52]; +/* 56 */ struct { +/* 2232 | 2 */ uint16_t nscount; +/* 2234 | 6 */ uint16_t nsmap[3]; +/* 2240 | 12 */ int nssocks[3]; +/* 2252 | 2 */ uint16_t nscount6; +/* 2254 | 2 */ uint16_t nsinit; +/* 2256 | 24 */ struct sockaddr_in6 *nsaddrs[3]; +/* 2280 | 8 */ unsigned long long __glibc_extension_index; + + /* total size (bytes): 56 */ + } _ext; + + /* total size (bytes): 56 */ + } _u; + + /* total size (bytes): 568 */ + } res; +/* 2288 | 8 */ internal_sigset_t sigmask; +/* 2296 | 8 */ struct rtld_catch *rtld_catch; +/* 2304 | 1 */ _Bool c11; +/* 2305 | 1 */ _Bool exiting; +/* XXX 2-byte hole */ +/* 2308 | 4 */ int exit_lock; +/* 2312 | 16 */ struct tls_internal_t { +/* 2312 | 8 */ char *strsignal_buf; +/* 2320 | 8 */ char *strerror_l_buf; + + /* total size (bytes): 16 */ + } tls_state; +/* 2328 | 8 */ void *getrandom_buf; +/* 2336 | 32 */ union { +/* 24 */ struct { +/* 2336 | 4 */ uint32_t cpu_id_start; +/* 2340 | 4 */ uint32_t cpu_id; +/* 2344 | 8 */ uint64_t rseq_cs; +/* 2352 | 4 */ uint32_t flags; +/* XXX 4-byte padding */ + + /* total size (bytes): 24 */ + }; +/* 32 */ char pad[32]; + + /* total size (bytes): 32 */ + } rseq_area; + + /* total size (bytes): 2368 */ + } diff --git a/verify-ld-so-abi.sh b/verify-ld-so-abi.sh new file mode 100644 index 0000000..066847e --- /dev/null +++ b/verify-ld-so-abi.sh @@ -0,0 +1,101 @@ +#!/bin/bash +# +# This script verifies the ABI of ld.so by comparing the layout of +# critical data structures against a known baseline for a given architecture. +# +# This is useful to prevent unintentional ABI breaks between releases. +# +# Usage: ./elf/verify-ld-so-abi.sh [--generate-baseline] + +set -euo pipefail + +if [ "$#" -lt 2 ] || [ "$#" -gt 3 ]; then + echo "Usage: $0 [--generate-baseline]" + exit 1 +fi + +ARCH="$1" +LDSO_PATH="$2" +GENERATE_BASELINE=false +if [ "${3:-}" == "--generate-baseline" ]; then + GENERATE_BASELINE=true +fi + +# The script is expected to be in the 'elf' directory and run from the glibc root. +SCRIPT_DIR="$(dirname "$0")" +BASELINE_DIR="$SCRIPT_DIR" +BASELINE_FILE="$BASELINE_DIR/ld-so-abi-$ARCH.baseline" + +# List of structs and global variables to check in ld.so. +# These are critical for the dynamic linker's internal ABI. +SYMBOLS_TO_CHECK=( + "_rtld_global_ro" + "_rtld_global" + "struct link_map" + "struct pthread" +) + +# Check for dependencies. +if ! command -v gdb &> /dev/null; then + echo "Error: gdb is not installed. Please install it to continue." >&2 + exit 127 +fi + +if [ ! -f "$LDSO_PATH" ]; then + echo "Error: ld.so not found at '$LDSO_PATH'" >&2 + exit 1 +fi + +TEMP_FILE=$(mktemp) +# Ensure the temporary file is cleaned up on script exit. +trap 'rm -f "$TEMP_FILE"' EXIT + +echo "Generating current ABI layout for '$ARCH' from '$LDSO_PATH'..." + +for symbol in "${SYMBOLS_TO_CHECK[@]}"; do + echo "--- $symbol ---" >> "$TEMP_FILE" + # Use ptype/o to get the struct layout with offsets. + # If a symbol does not exist, GDB will exit with an error, which is + # caught by 'set -e'. + gdb -batch -ex "ptype/o $symbol" "$LDSO_PATH" >> "$TEMP_FILE" +done + +if [ "$GENERATE_BASELINE" = true ]; then + echo "Generating new baseline for '$ARCH'..." + mkdir -p "$BASELINE_DIR" + # Atomically move the new baseline into place. + mv "$TEMP_FILE" "$BASELINE_FILE" + echo "Baseline created at $BASELINE_FILE" + # The temp file has been moved, so disable the trap. + trap - EXIT + exit 0 +fi + +# --- Comparison Mode --- + +if [ ! -f "$BASELINE_FILE" ]; then + echo "Error: Baseline file for architecture '$ARCH' does not exist." >&2 + echo "Path: $BASELINE_FILE" >&2 + echo >&2 + echo "To generate a new baseline, run this command with the --generate-baseline flag:" >&2 + echo "$0 $ARCH '$LDSO_PATH' --generate-baseline" >&2 + exit 77 +fi + +echo "Comparing with baseline file: $BASELINE_FILE" + +# Compare the generated layout with the official baseline. +if ! diff -u "$BASELINE_FILE" "$TEMP_FILE"; then + echo >&2 + echo "Error: ABI layout mismatch for '$ARCH' has been detected." >&2 + echo "The layout of structs in '$LDSO_PATH' has changed." >&2 + echo >&2 + echo "If this change is intentional, update the baseline file by running:" >&2 + echo "$0 $ARCH '$LDSO_PATH' --generate-baseline" >&2 + echo "or apply the diff output using 'patch -R'" + exit 1 +else + echo "OK: ABI layout for '$ARCH' is consistent with the baseline." + exit 0 +fi +