import glibc-2.28-220.el8

This commit is contained in:
CentOS Sources 2022-11-15 18:11:37 +00:00 committed by Stepan Oksanichenko
parent ee9c4ccfc2
commit cc1cae06b4
27 changed files with 6006 additions and 1 deletions

View File

@ -0,0 +1,27 @@
commit 97f8225d22ef727ae9935cc231643efdc430d530
Author: Zack Weinberg <zackw@panix.com>
Date: Thu Mar 14 09:44:22 2019 -0400
scripts/check-obsolete-constructs.py: Process all headers as UTF-8.
A few of our installed headers contain UTF-8 in comments.
check-obsolete-constructs opened files without explicitly specifying
their encoding, so it would barf on these headers if “make check” was
run in a non-UTF-8 locale.
* scripts/check-obsolete-constructs.py (HeaderChecker.check):
Specify encoding="utf-8" when opening headers to check.
diff --git a/scripts/check-obsolete-constructs.py b/scripts/check-obsolete-constructs.py
index ce5c72251f4d7cc0..89d21dea6e788783 100755
--- a/scripts/check-obsolete-constructs.py
+++ b/scripts/check-obsolete-constructs.py
@@ -437,7 +437,7 @@ class HeaderChecker:
def check(self, fname):
self.fname = fname
try:
- with open(fname, "rt") as fp:
+ with open(fname, "rt", encoding="utf-8") as fp:
contents = fp.read()
except OSError as e:
sys.stderr.write("{}: {}\n".format(fname, e.strerror))

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,409 @@
commit 198abcbb94618730dae1b3f4393efaa49e0ec8c7
Author: Florian Weimer <fweimer@redhat.com>
Date: Mon Apr 11 11:30:31 2022 +0200
Default to --with-default-link=no (bug 25812)
This is necessary to place the libio vtables into the RELRO segment.
New tests elf/tst-relro-ldso and elf/tst-relro-libc are added to
verify that this is what actually happens.
The new tests fail on ia64 due to lack of (default) RELRO support
inbutils, so they are XFAILed there.
Conflicts:
elf/Makefile
(missing valgrind smoke test)
diff --git a/INSTALL b/INSTALL
index b3a4370f592c5047..b69672b283c0b774 100644
--- a/INSTALL
+++ b/INSTALL
@@ -90,6 +90,12 @@ if 'CFLAGS' is specified it must enable optimization. For example:
library will still be usable, but functionality may be lost--for
example, you can't build a shared libc with old binutils.
+'--with-default-link=FLAG'
+ With '--with-default-link=yes', the build system does not use a
+ custom linker script for linking shared objects. The default for
+ FLAG is the opposite, 'no', because the custom linker script is
+ needed for full RELRO protection.
+
'--with-nonshared-cflags=CFLAGS'
Use additional compiler flags CFLAGS to build the parts of the
library which are always statically linked into applications and
diff --git a/configure b/configure
index 8b3681d2e28310c8..c794cea4359b3da3 100755
--- a/configure
+++ b/configure
@@ -3339,7 +3339,7 @@ fi
if test "${with_default_link+set}" = set; then :
withval=$with_default_link; use_default_link=$withval
else
- use_default_link=default
+ use_default_link=no
fi
@@ -5965,69 +5965,6 @@ fi
$as_echo "$libc_cv_hashstyle" >&6; }
-# The linker's default -shared behavior is good enough if it
-# does these things that our custom linker scripts ensure that
-# all allocated NOTE sections come first.
-if test "$use_default_link" = default; then
- { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sufficient default -shared layout" >&5
-$as_echo_n "checking for sufficient default -shared layout... " >&6; }
-if ${libc_cv_use_default_link+:} false; then :
- $as_echo_n "(cached) " >&6
-else
- libc_cv_use_default_link=no
- cat > conftest.s <<\EOF
- .section .note.a,"a",%note
- .balign 4
- .long 4,4,9
- .string "GNU"
- .string "foo"
- .section .note.b,"a",%note
- .balign 4
- .long 4,4,9
- .string "GNU"
- .string "bar"
-EOF
- if { ac_try=' ${CC-cc} $ASFLAGS -shared -o conftest.so conftest.s 1>&5'
- { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
- (eval $ac_try) 2>&5
- ac_status=$?
- $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
- test $ac_status = 0; }; } &&
- ac_try=`$READELF -S conftest.so | sed -n \
- '${x;p;}
- s/^ *\[ *[1-9][0-9]*\] *\([^ ][^ ]*\) *\([^ ][^ ]*\) .*$/\2 \1/
- t a
- b
- : a
- H'`
- then
- libc_seen_a=no libc_seen_b=no
- set -- $ac_try
- while test $# -ge 2 -a "$1" = NOTE; do
- case "$2" in
- .note.a) libc_seen_a=yes ;;
- .note.b) libc_seen_b=yes ;;
- esac
- shift 2
- done
- case "$libc_seen_a$libc_seen_b" in
- yesyes)
- libc_cv_use_default_link=yes
- ;;
- *)
- echo >&5 "\
-$libc_seen_a$libc_seen_b from:
-$ac_try"
- ;;
- esac
- fi
- rm -f conftest*
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_use_default_link" >&5
-$as_echo "$libc_cv_use_default_link" >&6; }
- use_default_link=$libc_cv_use_default_link
-fi
-
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for GLOB_DAT reloc" >&5
$as_echo_n "checking for GLOB_DAT reloc... " >&6; }
if ${libc_cv_has_glob_dat+:} false; then :
diff --git a/configure.ac b/configure.ac
index 82d9ab2fb67145bb..52429d82344954b3 100644
--- a/configure.ac
+++ b/configure.ac
@@ -152,7 +152,7 @@ AC_ARG_WITH([default-link],
AC_HELP_STRING([--with-default-link],
[do not use explicit linker scripts]),
[use_default_link=$withval],
- [use_default_link=default])
+ [use_default_link=no])
dnl Additional build flags injection.
AC_ARG_WITH([nonshared-cflags],
@@ -1352,59 +1352,6 @@ fi
rm -f conftest*])
AC_SUBST(libc_cv_hashstyle)
-# The linker's default -shared behavior is good enough if it
-# does these things that our custom linker scripts ensure that
-# all allocated NOTE sections come first.
-if test "$use_default_link" = default; then
- AC_CACHE_CHECK([for sufficient default -shared layout],
- libc_cv_use_default_link, [dnl
- libc_cv_use_default_link=no
- cat > conftest.s <<\EOF
- .section .note.a,"a",%note
- .balign 4
- .long 4,4,9
- .string "GNU"
- .string "foo"
- .section .note.b,"a",%note
- .balign 4
- .long 4,4,9
- .string "GNU"
- .string "bar"
-EOF
- if AC_TRY_COMMAND([dnl
- ${CC-cc} $ASFLAGS -shared -o conftest.so conftest.s 1>&AS_MESSAGE_LOG_FD]) &&
- ac_try=`$READELF -S conftest.so | sed -n \
- ['${x;p;}
- s/^ *\[ *[1-9][0-9]*\] *\([^ ][^ ]*\) *\([^ ][^ ]*\) .*$/\2 \1/
- t a
- b
- : a
- H']`
- then
- libc_seen_a=no libc_seen_b=no
- set -- $ac_try
- while test $# -ge 2 -a "$1" = NOTE; do
- case "$2" in
- .note.a) libc_seen_a=yes ;;
- .note.b) libc_seen_b=yes ;;
- esac
- shift 2
- done
- case "$libc_seen_a$libc_seen_b" in
- yesyes)
- libc_cv_use_default_link=yes
- ;;
- *)
- echo >&AS_MESSAGE_LOG_FD "\
-$libc_seen_a$libc_seen_b from:
-$ac_try"
- ;;
- esac
- fi
- rm -f conftest*])
- use_default_link=$libc_cv_use_default_link
-fi
-
AC_CACHE_CHECK(for GLOB_DAT reloc,
libc_cv_has_glob_dat, [dnl
cat > conftest.c <<EOF
diff --git a/elf/Makefile b/elf/Makefile
index 89ce4f5196e5eb39..1fdf40cbd49e233e 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -477,6 +477,40 @@ tests-execstack-yes = \
# tests-execstack-yes
endif
endif
+
+tests-special += $(objpfx)tst-relro-ldso.out $(objpfx)tst-relro-libc.out
+$(objpfx)tst-relro-ldso.out: tst-relro-symbols.py $(..)/scripts/glibcelf.py \
+ $(objpfx)ld.so
+ $(PYTHON) tst-relro-symbols.py $(objpfx)ld.so \
+ --required=_rtld_global_ro \
+ > $@ 2>&1; $(evaluate-test)
+# The optional symbols are present in libc only if the architecture has
+# the GLIBC_2.0 symbol set in libc.
+$(objpfx)tst-relro-libc.out: tst-relro-symbols.py $(..)/scripts/glibcelf.py \
+ $(common-objpfx)libc.so
+ $(PYTHON) tst-relro-symbols.py $(common-objpfx)libc.so \
+ --required=_IO_cookie_jumps \
+ --required=_IO_file_jumps \
+ --required=_IO_file_jumps_maybe_mmap \
+ --required=_IO_file_jumps_mmap \
+ --required=_IO_helper_jumps \
+ --required=_IO_mem_jumps \
+ --required=_IO_obstack_jumps \
+ --required=_IO_proc_jumps \
+ --required=_IO_str_chk_jumps \
+ --required=_IO_str_jumps \
+ --required=_IO_strn_jumps \
+ --required=_IO_wfile_jumps \
+ --required=_IO_wfile_jumps_maybe_mmap \
+ --required=_IO_wfile_jumps_mmap \
+ --required=_IO_wmem_jumps \
+ --required=_IO_wstr_jumps \
+ --required=_IO_wstrn_jumps \
+ --optional=_IO_old_cookie_jumps \
+ --optional=_IO_old_file_jumps \
+ --optional=_IO_old_proc_jumps \
+ > $@ 2>&1; $(evaluate-test)
+
tests += $(tests-execstack-$(have-z-execstack))
ifeq ($(run-built-tests),yes)
tests-special += \
diff --git a/elf/tst-relro-symbols.py b/elf/tst-relro-symbols.py
new file mode 100644
index 0000000000000000..368ea3349f86bd81
--- /dev/null
+++ b/elf/tst-relro-symbols.py
@@ -0,0 +1,137 @@
+#!/usr/bin/python3
+# Verify that certain symbols are covered by RELRO.
+# Copyright (C) 2022 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
+# <https://www.gnu.org/licenses/>.
+
+"""Analyze a (shared) object to verify that certain symbols are
+present and covered by the PT_GNU_RELRO segment.
+
+"""
+
+import argparse
+import os.path
+import sys
+
+# Make available glibc Python modules.
+sys.path.append(os.path.join(
+ os.path.dirname(os.path.realpath(__file__)), os.path.pardir, 'scripts'))
+
+import glibcelf
+
+def find_relro(path: str, img: glibcelf.Image) -> (int, int):
+ """Discover the address range of the PT_GNU_RELRO segment."""
+ for phdr in img.phdrs():
+ if phdr.p_type == glibcelf.Pt.PT_GNU_RELRO:
+ # The computation is not entirely accurate because
+ # _dl_protect_relro in elf/dl-reloc.c rounds both the
+ # start end and downwards using the run-time page size.
+ return phdr.p_vaddr, phdr.p_vaddr + phdr.p_memsz
+ sys.stdout.write('{}: error: no PT_GNU_RELRO segment\n'.format(path))
+ sys.exit(1)
+
+def check_in_relro(kind, relro_begin, relro_end, name, start, size, error):
+ """Check if a section or symbol falls within in the RELRO segment."""
+ end = start + size - 1
+ if not (relro_begin <= start < end < relro_end):
+ error(
+ '{} {!r} of size {} at 0x{:x} is not in RELRO range [0x{:x}, 0x{:x})'.format(
+ kind, name.decode('UTF-8'), start, size,
+ relro_begin, relro_end))
+
+def get_parser():
+ """Return an argument parser for this script."""
+ parser = argparse.ArgumentParser(description=__doc__)
+ parser.add_argument('object', help='path to object file to check')
+ parser.add_argument('--required', metavar='NAME', default=(),
+ help='required symbol names', nargs='*')
+ parser.add_argument('--optional', metavar='NAME', default=(),
+ help='required symbol names', nargs='*')
+ return parser
+
+def main(argv):
+ """The main entry point."""
+ parser = get_parser()
+ opts = parser.parse_args(argv)
+ img = glibcelf.Image.readfile(opts.object)
+
+ required_symbols = frozenset([sym.encode('UTF-8')
+ for sym in opts.required])
+ optional_symbols = frozenset([sym.encode('UTF-8')
+ for sym in opts.optional])
+ check_symbols = required_symbols | optional_symbols
+
+ # Tracks the symbols in check_symbols that have been found.
+ symbols_found = set()
+
+ # Discover the extent of the RELRO segment.
+ relro_begin, relro_end = find_relro(opts.object, img)
+ symbol_table_found = False
+
+ errors = False
+ def error(msg: str) -> None:
+ """Record an error condition and write a message to standard output."""
+ nonlocal errors
+ errors = True
+ sys.stdout.write('{}: error: {}\n'.format(opts.object, msg))
+
+ # Iterate over section headers to find the symbol table.
+ for shdr in img.shdrs():
+ if shdr.sh_type == glibcelf.Sht.SHT_SYMTAB:
+ symbol_table_found = True
+ for sym in img.syms(shdr):
+ if sym.st_name in check_symbols:
+ symbols_found.add(sym.st_name)
+
+ # Validate symbol type, section, and size.
+ if sym.st_info.type != glibcelf.Stt.STT_OBJECT:
+ error('symbol {!r} has wrong type {}'.format(
+ sym.st_name.decode('UTF-8'), sym.st_info.type))
+ if sym.st_shndx in glibcelf.Shn:
+ error('symbol {!r} has reserved section {}'.format(
+ sym.st_name.decode('UTF-8'), sym.st_shndx))
+ continue
+ if sym.st_size == 0:
+ error('symbol {!r} has size zero'.format(
+ sym.st_name.decode('UTF-8')))
+ continue
+
+ check_in_relro('symbol', relro_begin, relro_end,
+ sym.st_name, sym.st_value, sym.st_size,
+ error)
+ continue # SHT_SYMTAB
+ if shdr.sh_name == b'.data.rel.ro' \
+ or shdr.sh_name.startswith(b'.data.rel.ro.'):
+ check_in_relro('section', relro_begin, relro_end,
+ shdr.sh_name, shdr.sh_addr, shdr.sh_size,
+ error)
+ continue
+
+ if required_symbols - symbols_found:
+ for sym in sorted(required_symbols - symbols_found):
+ error('symbol {!r} not found'.format(sym.decode('UTF-8')))
+
+ if errors:
+ sys.exit(1)
+
+ if not symbol_table_found:
+ sys.stdout.write(
+ '{}: warning: no symbol table found (stripped object)\n'.format(
+ opts.object))
+ sys.exit(77)
+
+if __name__ == '__main__':
+ main(sys.argv[1:])
diff --git a/manual/install.texi b/manual/install.texi
index c262fd56d0cef67b..a2c43bd692de7825 100644
--- a/manual/install.texi
+++ b/manual/install.texi
@@ -117,6 +117,12 @@ problem and suppress these constructs, so that the library will still be
usable, but functionality may be lost---for example, you can't build a
shared libc with old binutils.
+@item --with-default-link=@var{FLAG}
+With @code{--with-default-link=yes}, the build system does not use a
+custom linker script for linking shared objects. The default for
+@var{FLAG} is the opposite, @samp{no}, because the custom linker script
+is needed for full RELRO protection.
+
@item --with-nonshared-cflags=@var{cflags}
Use additional compiler flags @var{cflags} to build the parts of the
library which are always statically linked into applications and
diff --git a/sysdeps/unix/sysv/linux/ia64/Makefile b/sysdeps/unix/sysv/linux/ia64/Makefile
index 97fc7df0b122d6a0..b1ad1ab7b1efa34c 100644
--- a/sysdeps/unix/sysv/linux/ia64/Makefile
+++ b/sysdeps/unix/sysv/linux/ia64/Makefile
@@ -1,3 +1,9 @@
+ifeq ($(subdir),elf)
+# ia64 does not support PT_GNU_RELRO.
+test-xfail-tst-relro-ldso = yes
+test-xfail-tst-relro-libc = yes
+endif
+
ifeq ($(subdir),misc)
sysdep_headers += sys/rse.h
endif

View File

@ -0,0 +1,26 @@
commit b571f3adffdcbed23f35ea39b0ca43809dbb4f5b
Author: Florian Weimer <fweimer@redhat.com>
Date: Fri Apr 22 19:34:52 2022 +0200
scripts/glibcelf.py: Mark as UNSUPPORTED on Python 3.5 and earlier
enum.IntFlag and enum.EnumMeta._missing_ support are not part of
earlier Python versions.
diff --git a/scripts/glibcelf.py b/scripts/glibcelf.py
index 8f7d0ca184845714..da0d5380f33a195e 100644
--- a/scripts/glibcelf.py
+++ b/scripts/glibcelf.py
@@ -28,6 +28,12 @@ import collections
import enum
import struct
+if not hasattr(enum, 'IntFlag'):
+ import sys
+ sys.stdout.write(
+ 'warning: glibcelf.py needs Python 3.6 for enum support\n')
+ sys.exit(77)
+
class _OpenIntEnum(enum.IntEnum):
"""Integer enumeration that supports arbitrary int values."""
@classmethod

View File

@ -0,0 +1,30 @@
Partial backport of the scripts/glibcelf.py part of:
commit 4610b24f5e4e6d2c4b769594efa6d460943163bb
Author: H.J. Lu <hjl.tools@gmail.com>
Date: Tue Mar 29 14:08:54 2022 -0700
elf: Define DT_RELR related macros and types
diff --git a/scripts/glibcelf.py b/scripts/glibcelf.py
index da0d5380f33a195e..f847b36c55c15b8a 100644
--- a/scripts/glibcelf.py
+++ b/scripts/glibcelf.py
@@ -304,6 +304,7 @@ class Sht(_OpenIntEnum):
SHT_PREINIT_ARRAY = 16
SHT_GROUP = 17
SHT_SYMTAB_SHNDX = 18
+ SHT_RELR = 19
SHT_GNU_ATTRIBUTES = 0x6ffffff5
SHT_GNU_HASH = 0x6ffffff6
SHT_GNU_LIBLIST = 0x6ffffff7
@@ -593,6 +594,9 @@ class Dt(_OpenIntEnum):
DT_PREINIT_ARRAY = 32
DT_PREINIT_ARRAYSZ = 33
DT_SYMTAB_SHNDX = 34
+ DT_RELRSZ = 35
+ DT_RELR = 36
+ DT_RELRENT = 37
DT_GNU_PRELINKED = 0x6ffffdf5
DT_GNU_CONFLICTSZ = 0x6ffffdf6
DT_GNU_LIBLISTSZ = 0x6ffffdf7

View File

@ -0,0 +1,50 @@
commit d055481ce39d03652ac60de5078889e15b6917ff
Author: Florian Weimer <fweimer@redhat.com>
Date: Mon May 16 21:59:24 2022 +0200
scripts/glibcelf.py: Add *T_RISCV_* constants
SHT_RISCV_ATTRIBUTES, PT_RISCV_ATTRIBUTES, DT_RISCV_VARIANT_CC were
added in commit 0b6c6750732483b4d59c2fcb45484079cd84157d
("Update RISC-V specific ELF definitions"). This caused the
elf/tst-glibcelf consistency check to fail.
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
diff --git a/scripts/glibcelf.py b/scripts/glibcelf.py
index f847b36c55c15b8a..07bef940433b4c99 100644
--- a/scripts/glibcelf.py
+++ b/scripts/glibcelf.py
@@ -385,6 +385,10 @@ class ShtPARISC(enum.Enum):
SHT_PARISC_UNWIND = 0x70000001
SHT_PARISC_DOC = 0x70000002
+class ShtRISCV(enum.Enum):
+ """Supplemental SHT_* constants for EM_RISCV."""
+ SHT_RISCV_ATTRIBUTES = 0x70000003
+
class Pf(enum.IntFlag):
"""Program header flags. Type of Phdr.p_flags values."""
PF_X = 1
@@ -558,6 +562,10 @@ class PtPARISC(enum.Enum):
PT_PARISC_ARCHEXT = 0x70000000
PT_PARISC_UNWIND = 0x70000001
+class PtRISCV(enum.Enum):
+ """Supplemental PT_* constants for EM_RISCV."""
+ PT_RISCV_ATTRIBUTES = 0x70000003
+
class Dt(_OpenIntEnum):
"""ELF dynamic segment tags. Type of Dyn.d_val."""
DT_NULL = 0
@@ -710,6 +718,10 @@ class DtPPC64(enum.Enum):
DT_PPC64_OPDSZ = 0x70000002
DT_PPC64_OPT = 0x70000003
+class DtRISCV(enum.Enum):
+ """Supplemental DT_* constants for EM_RISCV."""
+ DT_RISCV_VARIANT_CC = 0x70000001
+
class DtSPARC(enum.Enum):
"""Supplemental DT_* constants for EM_SPARC."""
DT_SPARC_REGISTER = 0x70000001

View File

@ -0,0 +1,26 @@
commit 8521001731d6539382fa875f1cac9864c466ef27
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Date: Mon Jun 6 14:41:24 2022 -0300
scripts/glibcelf.py: Add PT_AARCH64_MEMTAG_MTE constant
It was added in commit 603e5c8ba7257483c162cabb06eb6f79096429b6.
This caused the elf/tst-glibcelf consistency check to fail.
Reviewed-by: Florian Weimer <fweimer@redhat.com>
diff --git a/scripts/glibcelf.py b/scripts/glibcelf.py
index 07bef940433b4c99..47f95d07baefb4ae 100644
--- a/scripts/glibcelf.py
+++ b/scripts/glibcelf.py
@@ -523,6 +523,10 @@ class Pt(_OpenIntEnum):
PT_SUNWBSS = 0x6ffffffa
PT_SUNWSTACK = 0x6ffffffb
+class PtAARCH64(enum.Enum):
+ """Supplemental PT_* constants for EM_AARCH64."""
+ PT_AARCH64_MEMTAG_MTE = 0x70000002
+
class PtARM(enum.Enum):
"""Supplemental PT_* constants for EM_ARM."""
PT_ARM_EXIDX = 0x70000001

View File

@ -0,0 +1,22 @@
Partial backport of the scripts/glibcelf.py part of:
commit 2d83247d90c9f0bfee7f3f2505bc1b13b6f36c04
Author: caiyinyu <caiyinyu@loongson.cn>
Date: Tue Jul 19 09:20:45 2022 +0800
LoongArch: Add relocations and ELF flags to elf.h and scripts/glibcelf.py
diff --git a/scripts/glibcelf.py b/scripts/glibcelf.py
index 47f95d07baefb4ae..de0509130ed9ad47 100644
--- a/scripts/glibcelf.py
+++ b/scripts/glibcelf.py
@@ -252,7 +252,8 @@ class Machine(_OpenIntEnum):
EM_RISCV = 243
EM_BPF = 247
EM_CSKY = 252
- EM_NUM = 253
+ EM_LOONGARCH = 258
+ EM_NUM = 259
EM_ALPHA = 0x9026
class Et(_OpenIntEnum):

View File

@ -0,0 +1,78 @@
commit bd13cb19f5e15e9e9a92a536e755fd93a97a67f6
Author: Florian Weimer <fweimer@redhat.com>
Date: Fri Aug 19 11:16:32 2022 +0200
scripts/glibcelf.py: Add hashing support
ELF and GNU hashes can now be computed using the elf_hash and
gnu_hash functions.
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
Tested-by: Carlos O'Donell <carlos@redhat.com>
diff --git a/elf/tst-glibcelf.py b/elf/tst-glibcelf.py
index bf15a3bad4479e08..e5026e2289df206b 100644
--- a/elf/tst-glibcelf.py
+++ b/elf/tst-glibcelf.py
@@ -240,6 +240,24 @@ def check_constant_values(cc):
error('{}: glibcelf has {!r}, <elf.h> has {!r}'.format(
name, glibcelf_value, elf_h_value))
+def check_hashes():
+ for name, expected_elf, expected_gnu in (
+ ('', 0, 0x1505),
+ ('PPPPPPPPPPPP', 0, 0x9f105c45),
+ ('GLIBC_2.0', 0xd696910, 0xf66c3dd5),
+ ('GLIBC_2.34', 0x69691b4, 0xc3f3f90c),
+ ('GLIBC_PRIVATE', 0x963cf85, 0x692a260)):
+ for convert in (lambda x: x, lambda x: x.encode('UTF-8')):
+ name = convert(name)
+ actual_elf = glibcelf.elf_hash(name)
+ if actual_elf != expected_elf:
+ error('elf_hash({!r}): {:x} != 0x{:x}'.format(
+ name, actual_elf, expected_elf))
+ actual_gnu = glibcelf.gnu_hash(name)
+ if actual_gnu != expected_gnu:
+ error('gnu_hash({!r}): {:x} != 0x{:x}'.format(
+ name, actual_gnu, expected_gnu))
+
def main():
"""The main entry point."""
parser = argparse.ArgumentParser(
@@ -251,6 +269,7 @@ def main():
check_duplicates()
check_constant_prefixes()
check_constant_values(cc=args.cc)
+ check_hashes()
if errors_encountered > 0:
print("note: errors encountered:", errors_encountered)
diff --git a/scripts/glibcelf.py b/scripts/glibcelf.py
index de0509130ed9ad47..5c8f46f590722384 100644
--- a/scripts/glibcelf.py
+++ b/scripts/glibcelf.py
@@ -1158,5 +1158,24 @@ class Image:
self._stringtab[sh_link] = strtab
return strtab
+def elf_hash(s):
+ """Computes the ELF hash of the string."""
+ acc = 0
+ for ch in s:
+ if type(ch) is not int:
+ ch = ord(ch)
+ acc = ((acc << 4) + ch) & 0xffffffff
+ top = acc & 0xf0000000
+ acc = (acc ^ (top >> 24)) & ~top
+ return acc
+
+def gnu_hash(s):
+ """Computes the GNU hash of the string."""
+ h = 5381
+ for ch in s:
+ if type(ch) is not int:
+ ch = ord(ch)
+ h = (h * 33 + ch) & 0xffffffff
+ return h
__all__ = [name for name in dir() if name[0].isupper()]

View File

@ -0,0 +1,439 @@
commit f40c7887d3cc9bb0b56576ed9edbe505ff8058c0
Author: Florian Weimer <fweimer@redhat.com>
Date: Thu Sep 22 12:10:41 2022 +0200
scripts: Extract glibcpp.py from check-obsolete-constructs.py
The C tokenizer is useful separately.
Reviewed-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
diff --git a/scripts/check-obsolete-constructs.py b/scripts/check-obsolete-constructs.py
index 89d21dea6e788783..7c7a092e440a3258 100755
--- a/scripts/check-obsolete-constructs.py
+++ b/scripts/check-obsolete-constructs.py
@@ -24,193 +24,14 @@
"""
import argparse
-import collections
+import os
import re
import sys
-# Simplified lexical analyzer for C preprocessing tokens.
-# Does not implement trigraphs.
-# Does not implement backslash-newline in the middle of any lexical
-# item other than a string literal.
-# Does not implement universal-character-names in identifiers.
-# Treats prefixed strings (e.g. L"...") as two tokens (L and "...")
-# Accepts non-ASCII characters only within comments and strings.
-
-# Caution: The order of the outermost alternation matters.
-# STRING must be before BAD_STRING, CHARCONST before BAD_CHARCONST,
-# BLOCK_COMMENT before BAD_BLOCK_COM before PUNCTUATOR, and OTHER must
-# be last.
-# Caution: There should be no capturing groups other than the named
-# captures in the outermost alternation.
-
-# For reference, these are all of the C punctuators as of C11:
-# [ ] ( ) { } , ; ? ~
-# ! != * *= / /= ^ ^= = ==
-# # ##
-# % %= %> %: %:%:
-# & &= &&
-# | |= ||
-# + += ++
-# - -= -- ->
-# . ...
-# : :>
-# < <% <: << <<= <=
-# > >= >> >>=
-
-# The BAD_* tokens are not part of the official definition of pp-tokens;
-# they match unclosed strings, character constants, and block comments,
-# so that the regex engine doesn't have to backtrack all the way to the
-# beginning of a broken construct and then emit dozens of junk tokens.
-
-PP_TOKEN_RE_ = re.compile(r"""
- (?P<STRING> \"(?:[^\"\\\r\n]|\\(?:[\r\n -~]|\r\n))*\")
- |(?P<BAD_STRING> \"(?:[^\"\\\r\n]|\\[ -~])*)
- |(?P<CHARCONST> \'(?:[^\'\\\r\n]|\\(?:[\r\n -~]|\r\n))*\')
- |(?P<BAD_CHARCONST> \'(?:[^\'\\\r\n]|\\[ -~])*)
- |(?P<BLOCK_COMMENT> /\*(?:\*(?!/)|[^*])*\*/)
- |(?P<BAD_BLOCK_COM> /\*(?:\*(?!/)|[^*])*\*?)
- |(?P<LINE_COMMENT> //[^\r\n]*)
- |(?P<IDENT> [_a-zA-Z][_a-zA-Z0-9]*)
- |(?P<PP_NUMBER> \.?[0-9](?:[0-9a-df-oq-zA-DF-OQ-Z_.]|[eEpP][+-]?)*)
- |(?P<PUNCTUATOR>
- [,;?~(){}\[\]]
- | [!*/^=]=?
- | \#\#?
- | %(?:[=>]|:(?:%:)?)?
- | &[=&]?
- |\|[=|]?
- |\+[=+]?
- | -[=->]?
- |\.(?:\.\.)?
- | :>?
- | <(?:[%:]|<(?:=|<=?)?)?
- | >(?:=|>=?)?)
- |(?P<ESCNL> \\(?:\r|\n|\r\n))
- |(?P<WHITESPACE> [ \t\n\r\v\f]+)
- |(?P<OTHER> .)
-""", re.DOTALL | re.VERBOSE)
-
-HEADER_NAME_RE_ = re.compile(r"""
- < [^>\r\n]+ >
- | " [^"\r\n]+ "
-""", re.DOTALL | re.VERBOSE)
-
-ENDLINE_RE_ = re.compile(r"""\r|\n|\r\n""")
-
-# based on the sample code in the Python re documentation
-Token_ = collections.namedtuple("Token", (
- "kind", "text", "line", "column", "context"))
-Token_.__doc__ = """
- One C preprocessing token, comment, or chunk of whitespace.
- 'kind' identifies the token type, which will be one of:
- STRING, CHARCONST, BLOCK_COMMENT, LINE_COMMENT, IDENT,
- PP_NUMBER, PUNCTUATOR, ESCNL, WHITESPACE, HEADER_NAME,
- or OTHER. The BAD_* alternatives in PP_TOKEN_RE_ are
- handled within tokenize_c, below.
-
- 'text' is the sequence of source characters making up the token;
- no decoding whatsoever is performed.
-
- 'line' and 'column' give the position of the first character of the
- token within the source file. They are both 1-based.
-
- 'context' indicates whether or not this token occurred within a
- preprocessing directive; it will be None for running text,
- '<null>' for the leading '#' of a directive line (because '#'
- all by itself on a line is a "null directive"), or the name of
- the directive for tokens within a directive line, starting with
- the IDENT for the name itself.
-"""
-
-def tokenize_c(file_contents, reporter):
- """Yield a series of Token objects, one for each preprocessing
- token, comment, or chunk of whitespace within FILE_CONTENTS.
- The REPORTER object is expected to have one method,
- reporter.error(token, message), which will be called to
- indicate a lexical error at the position of TOKEN.
- If MESSAGE contains the four-character sequence '{!r}', that
- is expected to be replaced by repr(token.text).
- """
+# Make available glibc Python modules.
+sys.path.append(os.path.dirname(os.path.realpath(__file__)))
- Token = Token_
- PP_TOKEN_RE = PP_TOKEN_RE_
- ENDLINE_RE = ENDLINE_RE_
- HEADER_NAME_RE = HEADER_NAME_RE_
-
- line_num = 1
- line_start = 0
- pos = 0
- limit = len(file_contents)
- directive = None
- at_bol = True
- while pos < limit:
- if directive == "include":
- mo = HEADER_NAME_RE.match(file_contents, pos)
- if mo:
- kind = "HEADER_NAME"
- directive = "after_include"
- else:
- mo = PP_TOKEN_RE.match(file_contents, pos)
- kind = mo.lastgroup
- if kind != "WHITESPACE":
- directive = "after_include"
- else:
- mo = PP_TOKEN_RE.match(file_contents, pos)
- kind = mo.lastgroup
-
- text = mo.group()
- line = line_num
- column = mo.start() - line_start
- adj_line_start = 0
- # only these kinds can contain a newline
- if kind in ("WHITESPACE", "BLOCK_COMMENT", "LINE_COMMENT",
- "STRING", "CHARCONST", "BAD_BLOCK_COM", "ESCNL"):
- for tmo in ENDLINE_RE.finditer(text):
- line_num += 1
- adj_line_start = tmo.end()
- if adj_line_start:
- line_start = mo.start() + adj_line_start
-
- # Track whether or not we are scanning a preprocessing directive.
- if kind == "LINE_COMMENT" or (kind == "WHITESPACE" and adj_line_start):
- at_bol = True
- directive = None
- else:
- if kind == "PUNCTUATOR" and text == "#" and at_bol:
- directive = "<null>"
- elif kind == "IDENT" and directive == "<null>":
- directive = text
- at_bol = False
-
- # Report ill-formed tokens and rewrite them as their well-formed
- # equivalents, so downstream processing doesn't have to know about them.
- # (Rewriting instead of discarding provides better error recovery.)
- if kind == "BAD_BLOCK_COM":
- reporter.error(Token("BAD_BLOCK_COM", "", line, column+1, ""),
- "unclosed block comment")
- text += "*/"
- kind = "BLOCK_COMMENT"
- elif kind == "BAD_STRING":
- reporter.error(Token("BAD_STRING", "", line, column+1, ""),
- "unclosed string")
- text += "\""
- kind = "STRING"
- elif kind == "BAD_CHARCONST":
- reporter.error(Token("BAD_CHARCONST", "", line, column+1, ""),
- "unclosed char constant")
- text += "'"
- kind = "CHARCONST"
-
- tok = Token(kind, text, line, column+1,
- "include" if directive == "after_include" else directive)
- # Do not complain about OTHER tokens inside macro definitions.
- # $ and @ appear in macros defined by headers intended to be
- # included from assembly language, e.g. sysdeps/mips/sys/asm.h.
- if kind == "OTHER" and directive != "define":
- self.error(tok, "stray {!r} in program")
-
- yield tok
- pos = mo.end()
+import glibcpp
#
# Base and generic classes for individual checks.
@@ -446,7 +267,7 @@ class HeaderChecker:
typedef_checker = ObsoleteTypedefChecker(self, self.fname)
- for tok in tokenize_c(contents, self):
+ for tok in glibcpp.tokenize_c(contents, self):
typedef_checker.examine(tok)
def main():
diff --git a/scripts/glibcpp.py b/scripts/glibcpp.py
new file mode 100644
index 0000000000000000..b44c6a4392dde8ce
--- /dev/null
+++ b/scripts/glibcpp.py
@@ -0,0 +1,212 @@
+#! /usr/bin/python3
+# Approximation to C preprocessing.
+# Copyright (C) 2019-2022 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
+# <https://www.gnu.org/licenses/>.
+
+"""
+Simplified lexical analyzer for C preprocessing tokens.
+
+Does not implement trigraphs.
+
+Does not implement backslash-newline in the middle of any lexical
+item other than a string literal.
+
+Does not implement universal-character-names in identifiers.
+
+Treats prefixed strings (e.g. L"...") as two tokens (L and "...").
+
+Accepts non-ASCII characters only within comments and strings.
+"""
+
+import collections
+import re
+
+# Caution: The order of the outermost alternation matters.
+# STRING must be before BAD_STRING, CHARCONST before BAD_CHARCONST,
+# BLOCK_COMMENT before BAD_BLOCK_COM before PUNCTUATOR, and OTHER must
+# be last.
+# Caution: There should be no capturing groups other than the named
+# captures in the outermost alternation.
+
+# For reference, these are all of the C punctuators as of C11:
+# [ ] ( ) { } , ; ? ~
+# ! != * *= / /= ^ ^= = ==
+# # ##
+# % %= %> %: %:%:
+# & &= &&
+# | |= ||
+# + += ++
+# - -= -- ->
+# . ...
+# : :>
+# < <% <: << <<= <=
+# > >= >> >>=
+
+# The BAD_* tokens are not part of the official definition of pp-tokens;
+# they match unclosed strings, character constants, and block comments,
+# so that the regex engine doesn't have to backtrack all the way to the
+# beginning of a broken construct and then emit dozens of junk tokens.
+
+PP_TOKEN_RE_ = re.compile(r"""
+ (?P<STRING> \"(?:[^\"\\\r\n]|\\(?:[\r\n -~]|\r\n))*\")
+ |(?P<BAD_STRING> \"(?:[^\"\\\r\n]|\\[ -~])*)
+ |(?P<CHARCONST> \'(?:[^\'\\\r\n]|\\(?:[\r\n -~]|\r\n))*\')
+ |(?P<BAD_CHARCONST> \'(?:[^\'\\\r\n]|\\[ -~])*)
+ |(?P<BLOCK_COMMENT> /\*(?:\*(?!/)|[^*])*\*/)
+ |(?P<BAD_BLOCK_COM> /\*(?:\*(?!/)|[^*])*\*?)
+ |(?P<LINE_COMMENT> //[^\r\n]*)
+ |(?P<IDENT> [_a-zA-Z][_a-zA-Z0-9]*)
+ |(?P<PP_NUMBER> \.?[0-9](?:[0-9a-df-oq-zA-DF-OQ-Z_.]|[eEpP][+-]?)*)
+ |(?P<PUNCTUATOR>
+ [,;?~(){}\[\]]
+ | [!*/^=]=?
+ | \#\#?
+ | %(?:[=>]|:(?:%:)?)?
+ | &[=&]?
+ |\|[=|]?
+ |\+[=+]?
+ | -[=->]?
+ |\.(?:\.\.)?
+ | :>?
+ | <(?:[%:]|<(?:=|<=?)?)?
+ | >(?:=|>=?)?)
+ |(?P<ESCNL> \\(?:\r|\n|\r\n))
+ |(?P<WHITESPACE> [ \t\n\r\v\f]+)
+ |(?P<OTHER> .)
+""", re.DOTALL | re.VERBOSE)
+
+HEADER_NAME_RE_ = re.compile(r"""
+ < [^>\r\n]+ >
+ | " [^"\r\n]+ "
+""", re.DOTALL | re.VERBOSE)
+
+ENDLINE_RE_ = re.compile(r"""\r|\n|\r\n""")
+
+# based on the sample code in the Python re documentation
+Token_ = collections.namedtuple("Token", (
+ "kind", "text", "line", "column", "context"))
+Token_.__doc__ = """
+ One C preprocessing token, comment, or chunk of whitespace.
+ 'kind' identifies the token type, which will be one of:
+ STRING, CHARCONST, BLOCK_COMMENT, LINE_COMMENT, IDENT,
+ PP_NUMBER, PUNCTUATOR, ESCNL, WHITESPACE, HEADER_NAME,
+ or OTHER. The BAD_* alternatives in PP_TOKEN_RE_ are
+ handled within tokenize_c, below.
+
+ 'text' is the sequence of source characters making up the token;
+ no decoding whatsoever is performed.
+
+ 'line' and 'column' give the position of the first character of the
+ token within the source file. They are both 1-based.
+
+ 'context' indicates whether or not this token occurred within a
+ preprocessing directive; it will be None for running text,
+ '<null>' for the leading '#' of a directive line (because '#'
+ all by itself on a line is a "null directive"), or the name of
+ the directive for tokens within a directive line, starting with
+ the IDENT for the name itself.
+"""
+
+def tokenize_c(file_contents, reporter):
+ """Yield a series of Token objects, one for each preprocessing
+ token, comment, or chunk of whitespace within FILE_CONTENTS.
+ The REPORTER object is expected to have one method,
+ reporter.error(token, message), which will be called to
+ indicate a lexical error at the position of TOKEN.
+ If MESSAGE contains the four-character sequence '{!r}', that
+ is expected to be replaced by repr(token.text).
+ """
+
+ Token = Token_
+ PP_TOKEN_RE = PP_TOKEN_RE_
+ ENDLINE_RE = ENDLINE_RE_
+ HEADER_NAME_RE = HEADER_NAME_RE_
+
+ line_num = 1
+ line_start = 0
+ pos = 0
+ limit = len(file_contents)
+ directive = None
+ at_bol = True
+ while pos < limit:
+ if directive == "include":
+ mo = HEADER_NAME_RE.match(file_contents, pos)
+ if mo:
+ kind = "HEADER_NAME"
+ directive = "after_include"
+ else:
+ mo = PP_TOKEN_RE.match(file_contents, pos)
+ kind = mo.lastgroup
+ if kind != "WHITESPACE":
+ directive = "after_include"
+ else:
+ mo = PP_TOKEN_RE.match(file_contents, pos)
+ kind = mo.lastgroup
+
+ text = mo.group()
+ line = line_num
+ column = mo.start() - line_start
+ adj_line_start = 0
+ # only these kinds can contain a newline
+ if kind in ("WHITESPACE", "BLOCK_COMMENT", "LINE_COMMENT",
+ "STRING", "CHARCONST", "BAD_BLOCK_COM", "ESCNL"):
+ for tmo in ENDLINE_RE.finditer(text):
+ line_num += 1
+ adj_line_start = tmo.end()
+ if adj_line_start:
+ line_start = mo.start() + adj_line_start
+
+ # Track whether or not we are scanning a preprocessing directive.
+ if kind == "LINE_COMMENT" or (kind == "WHITESPACE" and adj_line_start):
+ at_bol = True
+ directive = None
+ else:
+ if kind == "PUNCTUATOR" and text == "#" and at_bol:
+ directive = "<null>"
+ elif kind == "IDENT" and directive == "<null>":
+ directive = text
+ at_bol = False
+
+ # Report ill-formed tokens and rewrite them as their well-formed
+ # equivalents, so downstream processing doesn't have to know about them.
+ # (Rewriting instead of discarding provides better error recovery.)
+ if kind == "BAD_BLOCK_COM":
+ reporter.error(Token("BAD_BLOCK_COM", "", line, column+1, ""),
+ "unclosed block comment")
+ text += "*/"
+ kind = "BLOCK_COMMENT"
+ elif kind == "BAD_STRING":
+ reporter.error(Token("BAD_STRING", "", line, column+1, ""),
+ "unclosed string")
+ text += "\""
+ kind = "STRING"
+ elif kind == "BAD_CHARCONST":
+ reporter.error(Token("BAD_CHARCONST", "", line, column+1, ""),
+ "unclosed char constant")
+ text += "'"
+ kind = "CHARCONST"
+
+ tok = Token(kind, text, line, column+1,
+ "include" if directive == "after_include" else directive)
+ # Do not complain about OTHER tokens inside macro definitions.
+ # $ and @ appear in macros defined by headers intended to be
+ # included from assembly language, e.g. sysdeps/mips/sys/asm.h.
+ if kind == "OTHER" and directive != "define":
+ self.error(tok, "stray {!r} in program")
+
+ yield tok
+ pos = mo.end()

View File

@ -0,0 +1,598 @@
commit e6e6184bed490403811771fa527eb95b4ae53c7c
Author: Florian Weimer <fweimer@redhat.com>
Date: Thu Sep 22 12:10:41 2022 +0200
scripts: Enhance glibcpp to do basic macro processing
Reviewed-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
Conflicts:
support/Makefile
(spurious tests sorting change upstream)
diff --git a/scripts/glibcpp.py b/scripts/glibcpp.py
index b44c6a4392dde8ce..455459a609eab120 100644
--- a/scripts/glibcpp.py
+++ b/scripts/glibcpp.py
@@ -33,7 +33,9 @@ Accepts non-ASCII characters only within comments and strings.
"""
import collections
+import operator
import re
+import sys
# Caution: The order of the outermost alternation matters.
# STRING must be before BAD_STRING, CHARCONST before BAD_CHARCONST,
@@ -210,3 +212,318 @@ def tokenize_c(file_contents, reporter):
yield tok
pos = mo.end()
+
+class MacroDefinition(collections.namedtuple('MacroDefinition',
+ 'name_token args body error')):
+ """A preprocessor macro definition.
+
+ name_token is the Token_ for the name.
+
+ args is None for a macro that is not function-like. Otherwise, it
+ is a tuple that contains the macro argument name tokens.
+
+ body is a tuple that contains the tokens that constitue the body
+ of the macro definition (excluding whitespace).
+
+ error is None if no error was detected, or otherwise a problem
+ description associated with this macro definition.
+
+ """
+
+ @property
+ def function(self):
+ """Return true if the macro is function-like."""
+ return self.args is not None
+
+ @property
+ def name(self):
+ """Return the name of the macro being defined."""
+ return self.name_token.text
+
+ @property
+ def line(self):
+ """Return the line number of the macro defintion."""
+ return self.name_token.line
+
+ @property
+ def args_lowered(self):
+ """Return the macro argument list as a list of strings"""
+ if self.function:
+ return [token.text for token in self.args]
+ else:
+ return None
+
+ @property
+ def body_lowered(self):
+ """Return the macro body as a list of strings."""
+ return [token.text for token in self.body]
+
+def macro_definitions(tokens):
+ """A generator for C macro definitions among tokens.
+
+ The generator yields MacroDefinition objects.
+
+ tokens must be iterable, yielding Token_ objects.
+
+ """
+
+ macro_name = None
+ macro_start = False # Set to false after macro name and one otken.
+ macro_args = None # Set to a list during the macro argument sequence.
+ in_macro_args = False # True while processing macro identifier-list.
+ error = None
+ body = []
+
+ for token in tokens:
+ if token.context == 'define' and macro_name is None \
+ and token.kind == 'IDENT':
+ # Starting up macro processing.
+ if macro_start:
+ # First identifier is the macro name.
+ macro_name = token
+ else:
+ # Next token is the name.
+ macro_start = True
+ continue
+
+ if macro_name is None:
+ # Drop tokens not in macro definitions.
+ continue
+
+ if token.context != 'define':
+ # End of the macro definition.
+ if in_macro_args and error is None:
+ error = 'macro definition ends in macro argument list'
+ yield MacroDefinition(macro_name, macro_args, tuple(body), error)
+ # No longer in a macro definition.
+ macro_name = None
+ macro_start = False
+ macro_args = None
+ in_macro_args = False
+ error = None
+ body.clear()
+ continue
+
+ if macro_start:
+ # First token after the macro name.
+ macro_start = False
+ if token.kind == 'PUNCTUATOR' and token.text == '(':
+ macro_args = []
+ in_macro_args = True
+ continue
+
+ if in_macro_args:
+ if token.kind == 'IDENT' \
+ or (token.kind == 'PUNCTUATOR' and token.text == '...'):
+ # Macro argument or ... placeholder.
+ macro_args.append(token)
+ if token.kind == 'PUNCTUATOR':
+ if token.text == ')':
+ macro_args = tuple(macro_args)
+ in_macro_args = False
+ elif token.text == ',':
+ pass # Skip. Not a full syntax check.
+ elif error is None:
+ error = 'invalid punctuator in macro argument list: ' \
+ + repr(token.text)
+ elif error is None:
+ error = 'invalid {} token in macro argument list'.format(
+ token.kind)
+ continue
+
+ if token.kind not in ('WHITESPACE', 'BLOCK_COMMENT'):
+ body.append(token)
+
+ # Emit the macro in case the last line does not end with a newline.
+ if macro_name is not None:
+ if in_macro_args and error is None:
+ error = 'macro definition ends in macro argument list'
+ yield MacroDefinition(macro_name, macro_args, tuple(body), error)
+
+# Used to split UL etc. suffixes from numbers such as 123UL.
+RE_SPLIT_INTEGER_SUFFIX = re.compile(r'([^ullULL]+)([ullULL]*)')
+
+BINARY_OPERATORS = {
+ '+': operator.add,
+ '<<': operator.lshift,
+}
+
+# Use the general-purpose dict type if it is order-preserving.
+if (sys.version_info[0], sys.version_info[1]) <= (3, 6):
+ OrderedDict = collections.OrderedDict
+else:
+ OrderedDict = dict
+
+def macro_eval(macro_defs, reporter):
+ """Compute macro values
+
+ macro_defs is the output from macro_definitions. reporter is an
+ object that accepts reporter.error(line_number, message) and
+ reporter.note(line_number, message) calls to report errors
+ and error context invocations.
+
+ The returned dict contains the values of macros which are not
+ function-like, pairing their names with their computed values.
+
+ The current implementation is incomplete. It is deliberately not
+ entirely faithful to C, even in the implemented parts. It checks
+ that macro replacements follow certain syntactic rules even if
+ they are never evaluated.
+
+ """
+
+ # Unevaluated macro definitions by name.
+ definitions = OrderedDict()
+ for md in macro_defs:
+ if md.name in definitions:
+ reporter.error(md.line, 'macro {} redefined'.format(md.name))
+ reporter.note(definitions[md.name].line,
+ 'location of previous definition')
+ else:
+ definitions[md.name] = md
+
+ # String to value mappings for fully evaluated macros.
+ evaluated = OrderedDict()
+
+ # String to macro definitions during evaluation. Nice error
+ # reporting relies on determinstic iteration order.
+ stack = OrderedDict()
+
+ def eval_token(current, token):
+ """Evaluate one macro token.
+
+ Integers and strings are returned as such (the latter still
+ quoted). Identifiers are expanded.
+
+ None indicates an empty expansion or an error.
+
+ """
+
+ if token.kind == 'PP_NUMBER':
+ value = None
+ m = RE_SPLIT_INTEGER_SUFFIX.match(token.text)
+ if m:
+ try:
+ value = int(m.group(1), 0)
+ except ValueError:
+ pass
+ if value is None:
+ reporter.error(token.line,
+ 'invalid number {!r} in definition of {}'.format(
+ token.text, current.name))
+ return value
+
+ if token.kind == 'STRING':
+ return token.text
+
+ if token.kind == 'CHARCONST' and len(token.text) == 3:
+ return ord(token.text[1])
+
+ if token.kind == 'IDENT':
+ name = token.text
+ result = eval1(current, name)
+ if name not in evaluated:
+ evaluated[name] = result
+ return result
+
+ reporter.error(token.line,
+ 'unrecognized {!r} in definition of {}'.format(
+ token.text, current.name))
+ return None
+
+
+ def eval1(current, name):
+ """Evaluate one name.
+
+ The name is looked up and the macro definition evaluated
+ recursively if necessary. The current argument is the macro
+ definition being evaluated.
+
+ None as a return value indicates an error.
+
+ """
+
+ # Fast path if the value has already been evaluated.
+ if name in evaluated:
+ return evaluated[name]
+
+ try:
+ md = definitions[name]
+ except KeyError:
+ reporter.error(current.line,
+ 'reference to undefined identifier {} in definition of {}'
+ .format(name, current.name))
+ return None
+
+ if md.name in stack:
+ # Recursive macro definition.
+ md = stack[name]
+ reporter.error(md.line,
+ 'macro definition {} refers to itself'.format(md.name))
+ for md1 in reversed(list(stack.values())):
+ if md1 is md:
+ break
+ reporter.note(md1.line,
+ 'evaluated from {}'.format(md1.name))
+ return None
+
+ stack[md.name] = md
+ if md.function:
+ reporter.error(current.line,
+ 'attempt to evaluate function-like macro {}'.format(name))
+ reporter.note(md.line, 'definition of {}'.format(md.name))
+ return None
+
+ try:
+ body = md.body
+ if len(body) == 0:
+ # Empty expansion.
+ return None
+
+ # Remove surrounding ().
+ if body[0].text == '(' and body[-1].text == ')':
+ body = body[1:-1]
+ had_parens = True
+ else:
+ had_parens = False
+
+ if len(body) == 1:
+ return eval_token(md, body[0])
+
+ # Minimal expression evaluator for binary operators.
+ op = body[1].text
+ if len(body) == 3 and op in BINARY_OPERATORS:
+ if not had_parens:
+ reporter.error(body[1].line,
+ 'missing parentheses around {} expression'.format(op))
+ reporter.note(md.line,
+ 'in definition of macro {}'.format(md.name))
+
+ left = eval_token(md, body[0])
+ right = eval_token(md, body[2])
+
+ if type(left) != type(1):
+ reporter.error(left.line,
+ 'left operand of {} is not an integer'.format(op))
+ reporter.note(md.line,
+ 'in definition of macro {}'.format(md.name))
+ if type(right) != type(1):
+ reporter.error(left.line,
+ 'right operand of {} is not an integer'.format(op))
+ reporter.note(md.line,
+ 'in definition of macro {}'.format(md.name))
+ return BINARY_OPERATORS[op](left, right)
+
+ reporter.error(md.line,
+ 'uninterpretable macro token sequence: {}'.format(
+ ' '.join(md.body_lowered)))
+ return None
+ finally:
+ del stack[md.name]
+
+ # Start of main body of macro_eval.
+ for md in definitions.values():
+ name = md.name
+ if name not in evaluated and not md.function:
+ evaluated[name] = eval1(md, name)
+ return evaluated
diff --git a/support/Makefile b/support/Makefile
index 09b41b0d57e9239a..7749ac24f1ac3622 100644
--- a/support/Makefile
+++ b/support/Makefile
@@ -223,11 +223,11 @@ $(objpfx)true-container : $(libsupport)
tests = \
README-testing \
tst-support-namespace \
+ tst-support-process_state \
tst-support_blob_repeat \
tst-support_capture_subprocess \
tst-support_descriptors \
tst-support_format_dns_packet \
- tst-support-process_state \
tst-support_quote_blob \
tst-support_quote_string \
tst-support_record_failure \
@@ -248,6 +248,12 @@ $(objpfx)tst-support_record_failure-2.out: tst-support_record_failure-2.sh \
$(evaluate-test)
endif
+tests-special += $(objpfx)tst-glibcpp.out
+
+$(objpfx)tst-glibcpp.out: tst-glibcpp.py $(..)scripts/glibcpp.py
+ PYTHONPATH=$(..)scripts $(PYTHON) tst-glibcpp.py > $@ 2>&1; \
+ $(evaluate-test)
+
$(objpfx)tst-support_format_dns_packet: $(common-objpfx)resolv/libresolv.so
tst-support_capture_subprocess-ARGS = -- $(host-test-program-cmd)
diff --git a/support/tst-glibcpp.py b/support/tst-glibcpp.py
new file mode 100644
index 0000000000000000..a2db1916ccfce3c3
--- /dev/null
+++ b/support/tst-glibcpp.py
@@ -0,0 +1,217 @@
+#! /usr/bin/python3
+# Tests for scripts/glibcpp.py
+# Copyright (C) 2022 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
+# <https://www.gnu.org/licenses/>.
+
+import inspect
+import sys
+
+import glibcpp
+
+# Error counter.
+errors = 0
+
+class TokenizerErrors:
+ """Used as the error reporter during tokenization."""
+
+ def __init__(self):
+ self.errors = []
+
+ def error(self, token, message):
+ self.errors.append((token, message))
+
+def check_macro_definitions(source, expected):
+ reporter = TokenizerErrors()
+ tokens = glibcpp.tokenize_c(source, reporter)
+
+ actual = []
+ for md in glibcpp.macro_definitions(tokens):
+ if md.function:
+ md_name = '{}({})'.format(md.name, ','.join(md.args_lowered))
+ else:
+ md_name = md.name
+ actual.append((md_name, md.body_lowered))
+
+ if actual != expected or reporter.errors:
+ global errors
+ errors += 1
+ # Obtain python source line information.
+ frame = inspect.stack(2)[1]
+ print('{}:{}: error: macro definition mismatch, actual definitions:'
+ .format(frame[1], frame[2]))
+ for md in actual:
+ print('note: {} {!r}'.format(md[0], md[1]))
+
+ if reporter.errors:
+ for err in reporter.errors:
+ print('note: tokenizer error: {}: {}'.format(
+ err[0].line, err[1]))
+
+def check_macro_eval(source, expected, expected_errors=''):
+ reporter = TokenizerErrors()
+ tokens = list(glibcpp.tokenize_c(source, reporter))
+
+ if reporter.errors:
+ # Obtain python source line information.
+ frame = inspect.stack(2)[1]
+ for err in reporter.errors:
+ print('{}:{}: tokenizer error: {}: {}'.format(
+ frame[1], frame[2], err[0].line, err[1]))
+ return
+
+ class EvalReporter:
+ """Used as the error reporter during evaluation."""
+
+ def __init__(self):
+ self.lines = []
+
+ def error(self, line, message):
+ self.lines.append('{}: error: {}\n'.format(line, message))
+
+ def note(self, line, message):
+ self.lines.append('{}: note: {}\n'.format(line, message))
+
+ reporter = EvalReporter()
+ actual = glibcpp.macro_eval(glibcpp.macro_definitions(tokens), reporter)
+ actual_errors = ''.join(reporter.lines)
+ if actual != expected or actual_errors != expected_errors:
+ global errors
+ errors += 1
+ # Obtain python source line information.
+ frame = inspect.stack(2)[1]
+ print('{}:{}: error: macro evaluation mismatch, actual results:'
+ .format(frame[1], frame[2]))
+ for k, v in actual.items():
+ print(' {}: {!r}'.format(k, v))
+ for msg in reporter.lines:
+ sys.stdout.write(' | ' + msg)
+
+# Individual test cases follow.
+
+check_macro_definitions('', [])
+check_macro_definitions('int main()\n{\n{\n', [])
+check_macro_definitions("""
+#define A 1
+#define B 2 /* ignored */
+#define C 3 // also ignored
+#define D \
+ 4
+#define STRING "string"
+#define FUNCLIKE(a, b) (a + b)
+#define FUNCLIKE2(a, b) (a + \
+ b)
+""", [('A', ['1']),
+ ('B', ['2']),
+ ('C', ['3']),
+ ('D', ['4']),
+ ('STRING', ['"string"']),
+ ('FUNCLIKE(a,b)', list('(a+b)')),
+ ('FUNCLIKE2(a,b)', list('(a+b)')),
+ ])
+check_macro_definitions('#define MACRO', [('MACRO', [])])
+check_macro_definitions('#define MACRO\n', [('MACRO', [])])
+check_macro_definitions('#define MACRO()', [('MACRO()', [])])
+check_macro_definitions('#define MACRO()\n', [('MACRO()', [])])
+
+check_macro_eval('#define A 1', {'A': 1})
+check_macro_eval('#define A (1)', {'A': 1})
+check_macro_eval('#define A (1 + 1)', {'A': 2})
+check_macro_eval('#define A (1U << 31)', {'A': 1 << 31})
+check_macro_eval('''\
+#define A (B + 1)
+#define B 10
+#define F(x) ignored
+#define C "not ignored"
+''', {
+ 'A': 11,
+ 'B': 10,
+ 'C': '"not ignored"',
+})
+
+# Checking for evaluation errors.
+check_macro_eval('''\
+#define A 1
+#define A 2
+''', {
+ 'A': 1,
+}, '''\
+2: error: macro A redefined
+1: note: location of previous definition
+''')
+
+check_macro_eval('''\
+#define A A
+#define B 1
+''', {
+ 'A': None,
+ 'B': 1,
+}, '''\
+1: error: macro definition A refers to itself
+''')
+
+check_macro_eval('''\
+#define A B
+#define B A
+''', {
+ 'A': None,
+ 'B': None,
+}, '''\
+1: error: macro definition A refers to itself
+2: note: evaluated from B
+''')
+
+check_macro_eval('''\
+#define A B
+#define B C
+#define C A
+''', {
+ 'A': None,
+ 'B': None,
+ 'C': None,
+}, '''\
+1: error: macro definition A refers to itself
+3: note: evaluated from C
+2: note: evaluated from B
+''')
+
+check_macro_eval('''\
+#define A 1 +
+''', {
+ 'A': None,
+}, '''\
+1: error: uninterpretable macro token sequence: 1 +
+''')
+
+check_macro_eval('''\
+#define A 3*5
+''', {
+ 'A': None,
+}, '''\
+1: error: uninterpretable macro token sequence: 3 * 5
+''')
+
+check_macro_eval('''\
+#define A 3 + 5
+''', {
+ 'A': 8,
+}, '''\
+1: error: missing parentheses around + expression
+1: note: in definition of macro A
+''')
+
+if errors:
+ sys.exit(1)

View File

@ -0,0 +1,208 @@
Partial backport of:
commit 7e1d42400c1b8f03316fe14176133c8853cd3bbe
Author: Joseph Myers <joseph@codesourcery.com>
Date: Fri Nov 30 15:20:41 2018 +0000
Replace gen-as-const.awk by gen-as-const.py.
This patch replaces gen-as-const.awk, and some fragments of the
Makefile code that used it, by a Python script. The point is not such
much that awk is problematic for this particular script, as that I'd
like to build up a general Python infrastructure for extracting
information from C headers, for use in writing tests of such headers.
Thus, although this patch does not set up such infrastructure, the
compute_c_consts function in gen-as-const.py might be moved to a
separate Python module in a subsequent patch as a starting point for
such infrastructure.
The general idea of the code is the same as in the awk version, but no
attempt is made to make the output files textually identical. When
generating a header, a dict of constant names and values is generated
internally then defines are printed in sorted order (rather than the
order in the .sym file, which would have been used before). When
generating a test that the values computed match those from a normal
header inclusion, the test code is made into a compilation test using
_Static_assert, where previously the comparisons were done only when
the test was executed. One fragment of test generation (converting
the previously generated header to use asconst_* prefixes on its macro
names) is still in awk code in the makefiles; only the .sym processing
and subsequent execution of the compiler to extract constants have
moved to the Python script.
Tested for x86_64, and with build-many-glibcs.py.
* scripts/gen-as-const.py: New file.
* scripts/gen-as-const.awk: Remove.
* Makerules ($(common-objpfx)%.h $(common-objpfx)%.h.d): Use
gen-as-const.py.
($(objpfx)test-as-const-%.c): Likewise.
In the downstream version, scripts/gen-as-const.awk is not removed and
still used in Makerules.
diff --git a/scripts/gen-as-const.py b/scripts/gen-as-const.py
new file mode 100644
index 0000000000000000..b7a5744bb192dd67
--- /dev/null
+++ b/scripts/gen-as-const.py
@@ -0,0 +1,159 @@
+#!/usr/bin/python3
+# Produce headers of assembly constants from C expressions.
+# Copyright (C) 2018 Free Software Foundation, Inc.
+# This file is part of the GNU C Library.
+#
+# The GNU C Library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# The GNU C Library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with the GNU C Library; if not, see
+# <http://www.gnu.org/licenses/>.
+
+# The input to this script looks like:
+# #cpp-directive ...
+# NAME1
+# NAME2 expression ...
+# A line giving just a name implies an expression consisting of just that name.
+
+import argparse
+import os.path
+import re
+import subprocess
+import tempfile
+
+
+def compute_c_consts(sym_data, cc):
+ """Compute the values of some C constants.
+
+ The first argument is a list whose elements are either strings
+ (preprocessor directives) or pairs of strings (a name and a C
+ expression for the corresponding value). Preprocessor directives
+ in the middle of the list may be used to select which constants
+ end up being evaluated using which expressions.
+
+ """
+ out_lines = []
+ started = False
+ for arg in sym_data:
+ if isinstance(arg, str):
+ out_lines.append(arg)
+ continue
+ name = arg[0]
+ value = arg[1]
+ if not started:
+ out_lines.append('void\ndummy (void)\n{')
+ started = True
+ out_lines.append('asm ("@@@name@@@%s@@@value@@@%%0@@@end@@@" '
+ ': : \"i\" ((long int) (%s)));'
+ % (name, value))
+ if started:
+ out_lines.append('}')
+ out_lines.append('')
+ out_text = '\n'.join(out_lines)
+ with tempfile.TemporaryDirectory() as temp_dir:
+ c_file_name = os.path.join(temp_dir, 'test.c')
+ s_file_name = os.path.join(temp_dir, 'test.s')
+ with open(c_file_name, 'w') as c_file:
+ c_file.write(out_text)
+ # Compilation has to be from stdin to avoid the temporary file
+ # name being written into the generated dependencies.
+ cmd = ('%s -S -o %s -x c - < %s' % (cc, s_file_name, c_file_name))
+ subprocess.check_call(cmd, shell=True)
+ consts = {}
+ with open(s_file_name, 'r') as s_file:
+ for line in s_file:
+ match = re.search('@@@name@@@([^@]*)'
+ '@@@value@@@[^0-9Xxa-fA-F-]*'
+ '([0-9Xxa-fA-F-]+).*@@@end@@@', line)
+ if match:
+ if (match.group(1) in consts
+ and match.group(2) != consts[match.group(1)]):
+ raise ValueError('duplicate constant %s'
+ % match.group(1))
+ consts[match.group(1)] = match.group(2)
+ return consts
+
+
+def gen_test(sym_data):
+ """Generate a test for the values of some C constants.
+
+ The first argument is as for compute_c_consts.
+
+ """
+ out_lines = []
+ started = False
+ for arg in sym_data:
+ if isinstance(arg, str):
+ out_lines.append(arg)
+ continue
+ name = arg[0]
+ value = arg[1]
+ if not started:
+ out_lines.append('#include <stdint.h>\n'
+ '#include <stdio.h>\n'
+ '#include <bits/wordsize.h>\n'
+ '#if __WORDSIZE == 64\n'
+ 'typedef uint64_t c_t;\n'
+ '# define U(n) UINT64_C (n)\n'
+ '#else\n'
+ 'typedef uint32_t c_t;\n'
+ '# define U(n) UINT32_C (n)\n'
+ '#endif\n'
+ 'static int\n'
+ 'do_test (void)\n'
+ '{\n'
+ # Compilation test only, using static assertions.
+ ' return 0;\n'
+ '}\n'
+ '#include <support/test-driver.c>')
+ started = True
+ out_lines.append('_Static_assert (U (asconst_%s) == (c_t) (%s), '
+ '"value of %s");'
+ % (name, value, name))
+ return '\n'.join(out_lines)
+
+
+def main():
+ """The main entry point."""
+ parser = argparse.ArgumentParser(
+ description='Produce headers of assembly constants.')
+ parser.add_argument('--cc', metavar='CC',
+ help='C compiler (including options) to use')
+ parser.add_argument('--test', action='store_true',
+ help='Generate test case instead of header')
+ parser.add_argument('sym_file',
+ help='.sym file to process')
+ args = parser.parse_args()
+ sym_data = []
+ with open(args.sym_file, 'r') as sym_file:
+ for line in sym_file:
+ line = line.strip()
+ if line == '':
+ continue
+ # Pass preprocessor directives through.
+ if line.startswith('#'):
+ sym_data.append(line)
+ continue
+ words = line.split(maxsplit=1)
+ # Separator.
+ if words[0] == '--':
+ continue
+ name = words[0]
+ value = words[1] if len(words) > 1 else words[0]
+ sym_data.append((name, value))
+ if args.test:
+ print(gen_test(sym_data))
+ else:
+ consts = compute_c_consts(sym_data, args.cc)
+ print('\n'.join('#define %s %s' % c for c in sorted(consts.items())))
+
+if __name__ == '__main__':
+ main()

View File

@ -0,0 +1,36 @@
commit 29eb7961197bee68470730aecfdda4d0e206812e
Author: Florian Weimer <fweimer@redhat.com>
Date: Mon Sep 5 12:11:19 2022 +0200
elf.h: Remove duplicate definition of VER_FLG_WEAK
This did not cause a warning before because the token sequence for
the two definitions was identical.
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
diff --git a/elf/elf.h b/elf/elf.h
index d6506ea1c7160dea..ec09040be639a52a 100644
--- a/elf/elf.h
+++ b/elf/elf.h
@@ -1027,7 +1027,8 @@ typedef struct
/* Legal values for vd_flags (version information flags). */
#define VER_FLG_BASE 0x1 /* Version definition of file itself */
-#define VER_FLG_WEAK 0x2 /* Weak version identifier */
+#define VER_FLG_WEAK 0x2 /* Weak version identifier. Also
+ used by vna_flags below. */
/* Versym symbol index values. */
#define VER_NDX_LOCAL 0 /* Symbol is local. */
@@ -1105,10 +1106,6 @@ typedef struct
} Elf64_Vernaux;
-/* Legal values for vna_flags. */
-#define VER_FLG_WEAK 0x2 /* Weak version identifier */
-
-
/* Auxiliary vector. */
/* This vector is normally only used by the program interpreter. The

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,34 @@
commit d33705c0b020632274318323931695a99753b5be
Author: Florian Weimer <fweimer@redhat.com>
Date: Thu Nov 3 12:24:17 2022 +0100
scripts/glibcelf.py: Properly report <elf.h> parsing failures
Without this change, parse failures result in an exception:
Traceback (most recent call last):
File "tst-glibcelf.py", line 23, in <module>
import glibcelf
File "/path/to/git/scripts/glibcelf.py", line 226, in <module>
_elf_h = _parse_elf_h()
File "/path/to/git/scripts/glibcelf.py", line 221, in _parse_elf_h
result = glibcpp.macro_eval(glibcpp.macro_definitions(tokens), reporter)
File "/path/to/git/scripts/glibcpp.py", line 379, in macro_eval
reporter.error(md.line, 'macro {} redefined'.format(md.name))
File "/path/to/git/scripts/glibcelf.py", line 214, in error
errors += 1
UnboundLocalError: local variable 'errors' referenced before assignment
diff --git a/scripts/glibcelf.py b/scripts/glibcelf.py
index 420cb21943b28bba..59aab56ecf9deb3e 100644
--- a/scripts/glibcelf.py
+++ b/scripts/glibcelf.py
@@ -211,7 +211,7 @@ def _parse_elf_h():
self.errors = 0
def error(self, line, message):
- errors += 1
+ self.errors += 1
print('{}:{}: error: {}'.format(path, line, message))
def note(self, line, message):

View File

@ -0,0 +1,108 @@
Downstream-only adjustments to scripts/glibcelf.py. We do not have
CSKY nor RISC-V constants in <elf.h>, so glibcelf cannot extract
those. PT_AARCH64_* constants are missing as well.
Adjust elf/tst-glibcelf.py to use PT_MIPS_OPTIONS instead of
PT_AARCH64_MEMTAG_MTE for testing. It has the same numeric value
(0x70000002).
diff --git a/elf/tst-glibcelf.py b/elf/tst-glibcelf.py
index a5bff45eae55edea..9cb0861589d6ae2e 100644
--- a/elf/tst-glibcelf.py
+++ b/elf/tst-glibcelf.py
@@ -75,15 +75,17 @@ def check_basic():
if repr(glibcelf.Pt(17609)) != 'Pt(17609)':
error('repr(Pt(17609))')
- if glibcelf.Pt('PT_AARCH64_MEMTAG_MTE') \
- is not glibcelf.Pt.PT_AARCH64_MEMTAG_MTE:
- error('PT_AARCH64_MEMTAG_MTE identity')
- if glibcelf.Pt(0x70000002) is glibcelf.Pt.PT_AARCH64_MEMTAG_MTE:
+ # Note: Upstream uses PT_AARCH64_MEMTAG_MTE instead of PT_MIPS_OPTIONS.
+ # PT_AARCH64_MEMTAG_MTE is not yet available downstream.
+ if glibcelf.Pt('PT_MIPS_OPTIONS') \
+ is not glibcelf.Pt.PT_MIPS_OPTIONS:
+ error('PT_MIPS_OPTIONS identity')
+ if glibcelf.Pt(0x70000002) is glibcelf.Pt.PT_MIPS_OPTIONS:
error('Pt(0x70000002) identity')
- if glibcelf.PtAARCH64(0x70000002) is not glibcelf.Pt.PT_AARCH64_MEMTAG_MTE:
- error('PtAARCH64(0x70000002) identity')
- if glibcelf.Pt.PT_AARCH64_MEMTAG_MTE.short_name != 'AARCH64_MEMTAG_MTE':
- error('PT_AARCH64_MEMTAG_MTE short name')
+ if glibcelf.PtMIPS(0x70000002) is not glibcelf.Pt.PT_MIPS_OPTIONS:
+ error('PtMIPS(0x70000002) identity')
+ if glibcelf.Pt.PT_MIPS_OPTIONS.short_name != 'MIPS_OPTIONS':
+ error('PT_MIPS_OPTIONS short name')
# Special cases for int-like Shn.
if glibcelf.Shn(32) == glibcelf.Shn.SHN_XINDEX:
diff --git a/scripts/glibcelf.py b/scripts/glibcelf.py
index 59aab56ecf9deb3e..5980d7cc906005e2 100644
--- a/scripts/glibcelf.py
+++ b/scripts/glibcelf.py
@@ -306,23 +306,17 @@ class ShtALPHA(Sht):
"""Supplemental SHT_* constants for EM_ALPHA."""
class ShtARM(Sht):
"""Supplemental SHT_* constants for EM_ARM."""
-class ShtCSKY(Sht):
- """Supplemental SHT_* constants for EM_CSKY."""
class ShtIA_64(Sht):
"""Supplemental SHT_* constants for EM_IA_64."""
class ShtMIPS(Sht):
"""Supplemental SHT_* constants for EM_MIPS."""
class ShtPARISC(Sht):
"""Supplemental SHT_* constants for EM_PARISC."""
-class ShtRISCV(Sht):
- """Supplemental SHT_* constants for EM_RISCV."""
_register_elf_h(ShtALPHA, prefix='SHT_ALPHA_', parent=Sht)
_register_elf_h(ShtARM, prefix='SHT_ARM_', parent=Sht)
-_register_elf_h(ShtCSKY, prefix='SHT_CSKY_', parent=Sht)
_register_elf_h(ShtIA_64, prefix='SHT_IA_64_', parent=Sht)
_register_elf_h(ShtMIPS, prefix='SHT_MIPS_', parent=Sht)
_register_elf_h(ShtPARISC, prefix='SHT_PARISC_', parent=Sht)
-_register_elf_h(ShtRISCV, prefix='SHT_RISCV_', parent=Sht)
_register_elf_h(Sht, ranges=True,
skip='SHT_LOSUNW SHT_HISUNW SHT_LOUSER SHT_HIUSER'.split())
@@ -392,8 +386,6 @@ _register_elf_h(Stt, ranges=True)
class Pt(_TypedConstant):
"""ELF program header types. Type of Phdr.p_type."""
prefix = 'PT_'
-class PtAARCH64(Pt):
- """Supplemental PT_* constants for EM_AARCH64."""
class PtARM(Pt):
"""Supplemental PT_* constants for EM_ARM."""
class PtHP(Pt):
@@ -404,15 +396,11 @@ class PtMIPS(Pt):
"""Supplemental PT_* constants for EM_MIPS."""
class PtPARISC(Pt):
"""Supplemental PT_* constants for EM_PARISC."""
-class PtRISCV(Pt):
- """Supplemental PT_* constants for EM_RISCV."""
-_register_elf_h(PtAARCH64, prefix='PT_AARCH64_', parent=Pt)
_register_elf_h(PtARM, prefix='PT_ARM_', parent=Pt)
_register_elf_h(PtHP, prefix='PT_HP_', parent=Pt)
_register_elf_h(PtIA_64, prefix='PT_IA_64_', parent=Pt)
_register_elf_h(PtMIPS, prefix='PT_MIPS_', parent=Pt)
_register_elf_h(PtPARISC, prefix='PT_PARISC_', parent=Pt)
-_register_elf_h(PtRISCV, prefix='PT_RISCV_', parent=Pt)
_register_elf_h(Pt, skip='PT_LOSUNW PT_HISUNW'.split(), ranges=True)
class Dt(_TypedConstant):
@@ -432,8 +420,6 @@ class DtPPC(Dt):
"""Supplemental DT_* constants for EM_PPC."""
class DtPPC64(Dt):
"""Supplemental DT_* constants for EM_PPC64."""
-class DtRISCV(Dt):
- """Supplemental DT_* constants for EM_RISCV."""
class DtSPARC(Dt):
"""Supplemental DT_* constants for EM_SPARC."""
_dt_skip = '''
@@ -456,7 +442,6 @@ _register_elf_h(DtIA_64, prefix='DT_IA_64_', skip=_dt_skip, parent=Dt)
_register_elf_h(DtMIPS, prefix='DT_MIPS_', skip=_dt_skip, parent=Dt)
_register_elf_h(DtPPC, prefix='DT_PPC_', skip=_dt_skip, parent=Dt)
_register_elf_h(DtPPC64, prefix='DT_PPC64_', skip=_dt_skip, parent=Dt)
-_register_elf_h(DtRISCV, prefix='DT_RISCV_', skip=_dt_skip, parent=Dt)
_register_elf_h(DtSPARC, prefix='DT_SPARC_', skip=_dt_skip, parent=Dt)
_register_elf_h(Dt, skip=_dt_skip, ranges=True)
del _dt_skip

View File

@ -0,0 +1,32 @@
commit 7b36d26b22d147ffc347f427f9fd584700578a94
Author: Samuel Thibault <samuel.thibault@ens-lyon.org>
Date: Mon Dec 3 14:40:48 2018 +0100
Fix test-as-const-jmp_buf-ssp.c generation on gnu-i386
hurd's jmp_buf-ssp.sym does not define any symbol.
scripts/gen-as-const.py currently was emitting an empty line in that
case, and the gawk invocation was prepending "asconst_" to it, ending up
with:
.../build/glibc/setjmp/test-as-const-jmp_buf-ssp.c:1:2: error: expected « = », « , », « ; », « asm » or
« __attribute__ » at end of input
1 | asconst_
| ^~~~~~~~
* scripts/gen-as-const.py (main): Avoid emitting empty line when
there is no element in `consts'.
diff --git a/scripts/gen-as-const.py b/scripts/gen-as-const.py
index b7a5744bb192dd67..cabf401ed15e8367 100644
--- a/scripts/gen-as-const.py
+++ b/scripts/gen-as-const.py
@@ -153,7 +153,7 @@ def main():
print(gen_test(sym_data))
else:
consts = compute_c_consts(sym_data, args.cc)
- print('\n'.join('#define %s %s' % c for c in sorted(consts.items())))
+ print(''.join('#define %s %s\n' % c for c in sorted(consts.items())), end='')
if __name__ == '__main__':
main()

View File

@ -0,0 +1,157 @@
commit 477a02f63751c4b759ddd9454d17f2a7ad120ee3
Author: Joseph Myers <joseph@codesourcery.com>
Date: Mon Dec 3 22:08:50 2018 +0000
Make gen-as-const.py handle '--' consistently with awk script.
It was reported in
<https://sourceware.org/ml/libc-alpha/2018-12/msg00045.html> that
gen-as-const.py fails to generate test code in the case where a .sym
file has no symbols in it, so resulting in a test failing to link for
Hurd.
The relevant difference from the old awk script is that the old script
treated '--' lines as indicating that the text to do at the start of
the test (or file used to compute constants) should be output at that
point if not already output, as well as treating lines with actual
entries for constants like that. This patch changes gen-as-const.py
accordingly, making it the sole responsibility of the code parsing
.sym files to determine when such text should be output and ensuring
it's always output at some point even if there are no symbols and no
'--' lines, since not outputting it means the test fails to link.
Handling '--' like that also avoids any problems that would arise if
the first entry for a symbol were inside #ifdef (since the text in
question must not be output inside #ifdef).
Tested for x86_64, and with build-many-glibcs.py for i686-gnu. Note
that there are still compilation test failures for i686-gnu
(linknamespace tests, possibly arising from recent posix_spawn-related
changes).
* scripts/gen-as-const.py (compute_c_consts): Take an argument
'START' to indicate that start text should be output.
(gen_test): Likewise.
(main): Generate 'START' for first symbol or '--' line, or at end
of input if not previously generated.
diff --git a/scripts/gen-as-const.py b/scripts/gen-as-const.py
index cabf401ed15e8367..eb85ef1aa0f4934d 100644
--- a/scripts/gen-as-const.py
+++ b/scripts/gen-as-const.py
@@ -34,28 +34,28 @@ def compute_c_consts(sym_data, cc):
"""Compute the values of some C constants.
The first argument is a list whose elements are either strings
- (preprocessor directives) or pairs of strings (a name and a C
+ (preprocessor directives, or the special string 'START' to
+ indicate this function should insert its initial boilerplate text
+ in the output there) or pairs of strings (a name and a C
expression for the corresponding value). Preprocessor directives
in the middle of the list may be used to select which constants
end up being evaluated using which expressions.
"""
out_lines = []
- started = False
for arg in sym_data:
if isinstance(arg, str):
- out_lines.append(arg)
+ if arg == 'START':
+ out_lines.append('void\ndummy (void)\n{')
+ else:
+ out_lines.append(arg)
continue
name = arg[0]
value = arg[1]
- if not started:
- out_lines.append('void\ndummy (void)\n{')
- started = True
out_lines.append('asm ("@@@name@@@%s@@@value@@@%%0@@@end@@@" '
': : \"i\" ((long int) (%s)));'
% (name, value))
- if started:
- out_lines.append('}')
+ out_lines.append('}')
out_lines.append('')
out_text = '\n'.join(out_lines)
with tempfile.TemporaryDirectory() as temp_dir:
@@ -89,32 +89,32 @@ def gen_test(sym_data):
"""
out_lines = []
- started = False
for arg in sym_data:
if isinstance(arg, str):
- out_lines.append(arg)
+ if arg == 'START':
+ out_lines.append('#include <stdint.h>\n'
+ '#include <stdio.h>\n'
+ '#include <bits/wordsize.h>\n'
+ '#if __WORDSIZE == 64\n'
+ 'typedef uint64_t c_t;\n'
+ '# define U(n) UINT64_C (n)\n'
+ '#else\n'
+ 'typedef uint32_t c_t;\n'
+ '# define U(n) UINT32_C (n)\n'
+ '#endif\n'
+ 'static int\n'
+ 'do_test (void)\n'
+ '{\n'
+ # Compilation test only, using static
+ # assertions.
+ ' return 0;\n'
+ '}\n'
+ '#include <support/test-driver.c>')
+ else:
+ out_lines.append(arg)
continue
name = arg[0]
value = arg[1]
- if not started:
- out_lines.append('#include <stdint.h>\n'
- '#include <stdio.h>\n'
- '#include <bits/wordsize.h>\n'
- '#if __WORDSIZE == 64\n'
- 'typedef uint64_t c_t;\n'
- '# define U(n) UINT64_C (n)\n'
- '#else\n'
- 'typedef uint32_t c_t;\n'
- '# define U(n) UINT32_C (n)\n'
- '#endif\n'
- 'static int\n'
- 'do_test (void)\n'
- '{\n'
- # Compilation test only, using static assertions.
- ' return 0;\n'
- '}\n'
- '#include <support/test-driver.c>')
- started = True
out_lines.append('_Static_assert (U (asconst_%s) == (c_t) (%s), '
'"value of %s");'
% (name, value, name))
@@ -134,6 +134,7 @@ def main():
args = parser.parse_args()
sym_data = []
with open(args.sym_file, 'r') as sym_file:
+ started = False
for line in sym_file:
line = line.strip()
if line == '':
@@ -143,12 +144,17 @@ def main():
sym_data.append(line)
continue
words = line.split(maxsplit=1)
+ if not started:
+ sym_data.append('START')
+ started = True
# Separator.
if words[0] == '--':
continue
name = words[0]
value = words[1] if len(words) > 1 else words[0]
sym_data.append((name, value))
+ if not started:
+ sym_data.append('START')
if args.test:
print(gen_test(sym_data))
else:

View File

@ -0,0 +1,483 @@
commit a8110b727e508f7ddf34f940af622e6f95435201
Author: Joseph Myers <joseph@codesourcery.com>
Date: Mon Dec 10 22:27:13 2018 +0000
Move tst-signal-numbers to Python.
This patch converts the tst-signal-numbers test from shell + awk to
Python.
As with gen-as-const, the point is not so much that shell and awk are
problematic for this code, as that it's useful to build up general
infrastructure in Python for use of a range of code involving
extracting values from C headers. This patch moves some code from
gen-as-const.py to a new glibcextract.py, which also gains functions
relating to listing macros, and comparing the values of a set of
macros from compiling two different pieces of code.
It's not just signal numbers that should have such tests; pretty much
any case where glibc copies constants from Linux kernel headers should
have such tests that the values and sets of constants agree except
where differences are known to be OK. Much the same also applies to
structure layouts (although testing those without hardcoding lists of
fields to test will be more complicated).
Given this patch, another test for a set of macros would essentially
be just a call to glibcextract.compare_macro_consts (plus boilerplate
code - and we could move to having separate text files defining such
tests, like the .sym inputs to gen-as-const, so that only a single
Python script is needed for most such tests). Some such tests would
of course need new features, e.g. where the set of macros changes in
new kernel versions (so you need to allow new macro names on the
kernel side if the kernel headers are newer than the version known to
glibc, and extra macros on the glibc side if the kernel headers are
older). tst-syscall-list.sh could become a Python script that uses
common code to generate lists of macros but does other things with its
own custom logic.
There are a few differences from the existing shell + awk test.
Because the new test evaluates constants using the compiler, no
special handling is needed any more for one signal name being defined
to another. Because asm/signal.h now needs to pass through the
compiler, not just the preprocessor, stddef.h is included as well
(given the asm/signal.h issue that it requires an externally provided
definition of size_t). The previous code defined __ASSEMBLER__ with
asm/signal.h; this is removed (__ASSEMBLY__, a different macro,
eliminates the requirement for stddef.h on some but not all
architectures).
Tested for x86_64, and with build-many-glibcs.py.
* scripts/glibcextract.py: New file.
* scripts/gen-as-const.py: Do not import os.path, re, subprocess
or tempfile. Import glibcexctract.
(compute_c_consts): Remove. Moved to glibcextract.py.
(gen_test): Update reference to compute_c_consts.
(main): Likewise.
* sysdeps/unix/sysv/linux/tst-signal-numbers.py: New file.
* sysdeps/unix/sysv/linux/tst-signal-numbers.sh: Remove.
* sysdeps/unix/sysv/linux/Makefile
($(objpfx)tst-signal-numbers.out): Use tst-signal-numbers.py.
Redirect stderr as well as stdout.
diff --git a/scripts/gen-as-const.py b/scripts/gen-as-const.py
index eb85ef1aa0f4934d..f85e359394acb1a4 100644
--- a/scripts/gen-as-const.py
+++ b/scripts/gen-as-const.py
@@ -24,68 +24,14 @@
# A line giving just a name implies an expression consisting of just that name.
import argparse
-import os.path
-import re
-import subprocess
-import tempfile
-
-def compute_c_consts(sym_data, cc):
- """Compute the values of some C constants.
-
- The first argument is a list whose elements are either strings
- (preprocessor directives, or the special string 'START' to
- indicate this function should insert its initial boilerplate text
- in the output there) or pairs of strings (a name and a C
- expression for the corresponding value). Preprocessor directives
- in the middle of the list may be used to select which constants
- end up being evaluated using which expressions.
-
- """
- out_lines = []
- for arg in sym_data:
- if isinstance(arg, str):
- if arg == 'START':
- out_lines.append('void\ndummy (void)\n{')
- else:
- out_lines.append(arg)
- continue
- name = arg[0]
- value = arg[1]
- out_lines.append('asm ("@@@name@@@%s@@@value@@@%%0@@@end@@@" '
- ': : \"i\" ((long int) (%s)));'
- % (name, value))
- out_lines.append('}')
- out_lines.append('')
- out_text = '\n'.join(out_lines)
- with tempfile.TemporaryDirectory() as temp_dir:
- c_file_name = os.path.join(temp_dir, 'test.c')
- s_file_name = os.path.join(temp_dir, 'test.s')
- with open(c_file_name, 'w') as c_file:
- c_file.write(out_text)
- # Compilation has to be from stdin to avoid the temporary file
- # name being written into the generated dependencies.
- cmd = ('%s -S -o %s -x c - < %s' % (cc, s_file_name, c_file_name))
- subprocess.check_call(cmd, shell=True)
- consts = {}
- with open(s_file_name, 'r') as s_file:
- for line in s_file:
- match = re.search('@@@name@@@([^@]*)'
- '@@@value@@@[^0-9Xxa-fA-F-]*'
- '([0-9Xxa-fA-F-]+).*@@@end@@@', line)
- if match:
- if (match.group(1) in consts
- and match.group(2) != consts[match.group(1)]):
- raise ValueError('duplicate constant %s'
- % match.group(1))
- consts[match.group(1)] = match.group(2)
- return consts
+import glibcextract
def gen_test(sym_data):
"""Generate a test for the values of some C constants.
- The first argument is as for compute_c_consts.
+ The first argument is as for glibcextract.compute_c_consts.
"""
out_lines = []
@@ -158,7 +104,7 @@ def main():
if args.test:
print(gen_test(sym_data))
else:
- consts = compute_c_consts(sym_data, args.cc)
+ consts = glibcextract.compute_c_consts(sym_data, args.cc)
print(''.join('#define %s %s\n' % c for c in sorted(consts.items())), end='')
if __name__ == '__main__':
diff --git a/scripts/glibcextract.py b/scripts/glibcextract.py
new file mode 100644
index 0000000000000000..ecc4d5b6cc387c7d
--- /dev/null
+++ b/scripts/glibcextract.py
@@ -0,0 +1,162 @@
+#!/usr/bin/python3
+# Extract information from C headers.
+# Copyright (C) 2018 Free Software Foundation, Inc.
+# This file is part of the GNU C Library.
+#
+# The GNU C Library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# The GNU C Library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with the GNU C Library; if not, see
+# <http://www.gnu.org/licenses/>.
+
+import os.path
+import re
+import subprocess
+import tempfile
+
+
+def compute_c_consts(sym_data, cc):
+ """Compute the values of some C constants.
+
+ The first argument is a list whose elements are either strings
+ (preprocessor directives, or the special string 'START' to
+ indicate this function should insert its initial boilerplate text
+ in the output there) or pairs of strings (a name and a C
+ expression for the corresponding value). Preprocessor directives
+ in the middle of the list may be used to select which constants
+ end up being evaluated using which expressions.
+
+ """
+ out_lines = []
+ for arg in sym_data:
+ if isinstance(arg, str):
+ if arg == 'START':
+ out_lines.append('void\ndummy (void)\n{')
+ else:
+ out_lines.append(arg)
+ continue
+ name = arg[0]
+ value = arg[1]
+ out_lines.append('asm ("@@@name@@@%s@@@value@@@%%0@@@end@@@" '
+ ': : \"i\" ((long int) (%s)));'
+ % (name, value))
+ out_lines.append('}')
+ out_lines.append('')
+ out_text = '\n'.join(out_lines)
+ with tempfile.TemporaryDirectory() as temp_dir:
+ c_file_name = os.path.join(temp_dir, 'test.c')
+ s_file_name = os.path.join(temp_dir, 'test.s')
+ with open(c_file_name, 'w') as c_file:
+ c_file.write(out_text)
+ # Compilation has to be from stdin to avoid the temporary file
+ # name being written into the generated dependencies.
+ cmd = ('%s -S -o %s -x c - < %s' % (cc, s_file_name, c_file_name))
+ subprocess.check_call(cmd, shell=True)
+ consts = {}
+ with open(s_file_name, 'r') as s_file:
+ for line in s_file:
+ match = re.search('@@@name@@@([^@]*)'
+ '@@@value@@@[^0-9Xxa-fA-F-]*'
+ '([0-9Xxa-fA-F-]+).*@@@end@@@', line)
+ if match:
+ if (match.group(1) in consts
+ and match.group(2) != consts[match.group(1)]):
+ raise ValueError('duplicate constant %s'
+ % match.group(1))
+ consts[match.group(1)] = match.group(2)
+ return consts
+
+
+def list_macros(source_text, cc):
+ """List the preprocessor macros defined by the given source code.
+
+ The return value is a pair of dicts, the first one mapping macro
+ names to their expansions and the second one mapping macro names
+ to lists of their arguments, or to None for object-like macros.
+
+ """
+ with tempfile.TemporaryDirectory() as temp_dir:
+ c_file_name = os.path.join(temp_dir, 'test.c')
+ i_file_name = os.path.join(temp_dir, 'test.i')
+ with open(c_file_name, 'w') as c_file:
+ c_file.write(source_text)
+ cmd = ('%s -E -dM -o %s %s' % (cc, i_file_name, c_file_name))
+ subprocess.check_call(cmd, shell=True)
+ macros_exp = {}
+ macros_args = {}
+ with open(i_file_name, 'r') as i_file:
+ for line in i_file:
+ match = re.fullmatch('#define ([0-9A-Za-z_]+)(.*)\n', line)
+ if not match:
+ raise ValueError('bad -dM output line: %s' % line)
+ name = match.group(1)
+ value = match.group(2)
+ if value.startswith(' '):
+ value = value[1:]
+ args = None
+ elif value.startswith('('):
+ match = re.fullmatch(r'\((.*?)\) (.*)', value)
+ if not match:
+ raise ValueError('bad -dM output line: %s' % line)
+ args = match.group(1).split(',')
+ value = match.group(2)
+ else:
+ raise ValueError('bad -dM output line: %s' % line)
+ if name in macros_exp:
+ raise ValueError('duplicate macro: %s' % line)
+ macros_exp[name] = value
+ macros_args[name] = args
+ return macros_exp, macros_args
+
+
+def compute_macro_consts(source_text, cc, macro_re, exclude_re=None):
+ """Compute the integer constant values of macros defined by source_text.
+
+ Macros must match the regular expression macro_re, and if
+ exclude_re is defined they must not match exclude_re. Values are
+ computed with compute_c_consts.
+
+ """
+ macros_exp, macros_args = list_macros(source_text, cc)
+ macros_set = {m for m in macros_exp
+ if (macros_args[m] is None
+ and re.fullmatch(macro_re, m)
+ and (exclude_re is None
+ or not re.fullmatch(exclude_re, m)))}
+ sym_data = [source_text, 'START']
+ sym_data.extend(sorted((m, m) for m in macros_set))
+ return compute_c_consts(sym_data, cc)
+
+
+def compare_macro_consts(source_1, source_2, cc, macro_re, exclude_re=None):
+ """Compare the values of macros defined by two different sources.
+
+ The sources would typically be includes of a glibc header and a
+ kernel header. Return 1 if there were any differences, 0 if the
+ macro values were the same.
+
+ """
+ macros_1 = compute_macro_consts(source_1, cc, macro_re, exclude_re)
+ macros_2 = compute_macro_consts(source_2, cc, macro_re, exclude_re)
+ if macros_1 == macros_2:
+ return 0
+ print('First source:\n%s\n' % source_1)
+ print('Second source:\n%s\n' % source_2)
+ for name, value in sorted(macros_1.items()):
+ if name not in macros_2:
+ print('Only in first source: %s' % name)
+ elif macros_1[name] != macros_2[name]:
+ print('Different values for %s: %s != %s'
+ % (name, macros_1[name], macros_2[name]))
+ for name in sorted(macros_2.keys()):
+ if name not in macros_1:
+ print('Only in second source: %s' % name)
+ return 1
diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile
index bb055f9d6b841ff5..9c10ee53b26e1b1b 100644
--- a/sysdeps/unix/sysv/linux/Makefile
+++ b/sysdeps/unix/sysv/linux/Makefile
@@ -113,11 +113,14 @@ tests-special += $(objpfx)tst-signal-numbers.out
# in this context, but signal.c includes signal.h and not much else so it'll
# be conservatively correct.
$(objpfx)tst-signal-numbers.out: \
- ../sysdeps/unix/sysv/linux/tst-signal-numbers.sh \
+ ../sysdeps/unix/sysv/linux/tst-signal-numbers.py \
$(objpfx)signal.o*
- AWK=$(AWK) $(SHELL) ../sysdeps/unix/sysv/linux/tst-signal-numbers.sh \
- $(CC) $(patsubst -DMODULE_NAME=%,-DMODULE_NAME=testsuite,$(CPPFLAGS)) \
- < /dev/null > $@; $(evaluate-test)
+ PYTHONPATH=../scripts \
+ $(PYTHON) ../sysdeps/unix/sysv/linux/tst-signal-numbers.py \
+ --cc="$(CC) $(patsubst -DMODULE_NAME=%, \
+ -DMODULE_NAME=testsuite, \
+ $(CPPFLAGS))" \
+ < /dev/null > $@ 2>&1; $(evaluate-test)
endif
ifeq ($(subdir),socket)
diff --git a/sysdeps/unix/sysv/linux/tst-signal-numbers.py b/sysdeps/unix/sysv/linux/tst-signal-numbers.py
new file mode 100644
index 0000000000000000..48c63d1218e8303d
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/tst-signal-numbers.py
@@ -0,0 +1,48 @@
+#!/usr/bin/python3
+# Test that glibc's signal numbers match the kernel's.
+# Copyright (C) 2018 Free Software Foundation, Inc.
+# This file is part of the GNU C Library.
+#
+# The GNU C Library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# The GNU C Library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with the GNU C Library; if not, see
+# <http://www.gnu.org/licenses/>.
+
+import argparse
+import sys
+
+import glibcextract
+
+
+def main():
+ """The main entry point."""
+ parser = argparse.ArgumentParser(
+ description="Test that glibc's signal numbers match the kernel's.")
+ parser.add_argument('--cc', metavar='CC',
+ help='C compiler (including options) to use')
+ args = parser.parse_args()
+ sys.exit(glibcextract.compare_macro_consts(
+ '#define _GNU_SOURCE 1\n'
+ '#include <signal.h>\n',
+ '#define _GNU_SOURCE 1\n'
+ '#include <stddef.h>\n'
+ '#include <asm/signal.h>\n',
+ args.cc,
+ # Filter out constants that aren't signal numbers.
+ 'SIG[A-Z]+',
+ # Discard obsolete signal numbers and unrelated constants:
+ # SIGCLD, SIGIOT, SIGSWI, SIGUNUSED.
+ # SIGSTKSZ, SIGRTMIN, SIGRTMAX.
+ 'SIG(CLD|IOT|RT(MIN|MAX)|STKSZ|SWI|UNUSED)'))
+
+if __name__ == '__main__':
+ main()
diff --git a/sysdeps/unix/sysv/linux/tst-signal-numbers.sh b/sysdeps/unix/sysv/linux/tst-signal-numbers.sh
deleted file mode 100644
index e1f7be0337c720a6..0000000000000000
--- a/sysdeps/unix/sysv/linux/tst-signal-numbers.sh
+++ /dev/null
@@ -1,86 +0,0 @@
-#! /bin/sh
-# Test that glibc's signal numbers match the kernel's.
-# Copyright (C) 2017-2018 Free Software Foundation, Inc.
-# This file is part of the GNU C Library.
-
-# The GNU C Library is free software; you can redistribute it and/or
-# modify it under the terms of the GNU Lesser General Public
-# License as published by the Free Software Foundation; either
-# version 2.1 of the License, or (at your option) any later version.
-
-# The GNU C Library is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# Lesser General Public License for more details.
-
-# You should have received a copy of the GNU Lesser General Public
-# License along with the GNU C Library; if not, see
-# <http://www.gnu.org/licenses/>.
-
-set -e
-if [ -n "$BASH_VERSION" ]; then set -o pipefail; fi
-LC_ALL=C; export LC_ALL
-
-# We cannot use Linux's asm/signal.h to define signal numbers, because
-# it isn't sufficiently namespace-clean. Instead, this test checks
-# that our signal numbers match the kernel's. This script expects
-# "$@" to be $(CC) $(CPPFLAGS) as set by glibc's Makefiles, and $AWK
-# to be set in the environment.
-
-# Before doing anything else, fail if the compiler doesn't work.
-"$@" -E -xc -dM - < /dev/null > /dev/null
-
-tmpG=`mktemp -t signums_glibc.XXXXXXXXX`
-tmpK=`mktemp -t signums_kernel.XXXXXXXXX`
-trap "rm -f '$tmpG' '$tmpK'" 0
-
-# Filter out constants that aren't signal numbers.
-# If SIGPOLL is defined as SIGIO, swap it around so SIGIO is defined as
-# SIGPOLL. Similarly for SIGABRT and SIGIOT.
-# Discard obsolete signal numbers and unrelated constants:
-# SIGCLD, SIGIOT, SIGSWI, SIGUNUSED.
-# SIGSTKSZ, SIGRTMIN, SIGRTMAX.
-# Then sort the list.
-filter_defines ()
-{
- $AWK '
-/^#define SIG[A-Z]+ ([0-9]+|SIG[A-Z0-9]+)$/ { signals[$2] = $3 }
-END {
- if ("SIGPOLL" in signals && "SIGIO" in signals &&
- signals["SIGPOLL"] == "SIGIO") {
- signals["SIGPOLL"] = signals["SIGIO"]
- signals["SIGIO"] = "SIGPOLL"
- }
- if ("SIGABRT" in signals && "SIGIOT" in signals &&
- signals["SIGABRT"] == "SIGIOT") {
- signals["SIGABRT"] = signals["SIGIOT"]
- signals["SIGIOT"] = "SIGABRT"
- }
- for (sig in signals) {
- if (sig !~ /^SIG(CLD|IOT|RT(MIN|MAX)|STKSZ|SWI|UNUSED)$/) {
- printf("#define %s %s\n", sig, signals[sig])
- }
- }
-}' | sort
-}
-
-# $CC may contain command-line switches, so it should be word-split.
-printf '%s' '#define _GNU_SOURCE 1
-#include <signal.h>
-' |
- "$@" -E -xc -dM - |
- filter_defines > "$tmpG"
-
-printf '%s' '#define _GNU_SOURCE 1
-#define __ASSEMBLER__ 1
-#include <asm/signal.h>
-' |
- "$@" -E -xc -dM - |
- filter_defines > "$tmpK"
-
-if cmp -s "$tmpG" "$tmpK"; then
- exit 0
-else
- diff -u "$tmpG" "$tmpK"
- exit 1
-fi

View File

@ -0,0 +1,98 @@
Partial backport of:
commit cb7be1590e9b18e272e72eb4e910a7ad06a53bd0
Author: Joseph Myers <joseph@codesourcery.com>
Date: Mon Dec 10 22:56:59 2018 +0000
Use gen-as-const.py to process .pysym files.
This patch eliminates the gen-py-const.awk variant of gen-as-const,
switching to use of gnu-as-const.py (with a new --python option) to
process .pysym files (i.e., to generate nptl_lock_constants.py), as
the syntax of those files is identical to that of .sym files.
Note that the generated nptl_lock_constants.py is *not* identical to
the version generated by the awk script. Apart from the trivial
changes (comment referencing the new script, and output being sorted),
the constant FUTEX_WAITERS, PTHREAD_MUTEXATTR_FLAG_BITS,
PTHREAD_MUTEXATTR_FLAG_PSHARED and PTHREAD_MUTEX_PRIO_CEILING_MASK are
now output as positive rather than negative constants (on x86_64
anyway; maybe not necessarily on 32-bit systems):
< FUTEX_WAITERS = -2147483648
---
> FUTEX_WAITERS = 2147483648
< PTHREAD_MUTEXATTR_FLAG_BITS = -251662336
< PTHREAD_MUTEXATTR_FLAG_PSHARED = -2147483648
---
> PTHREAD_MUTEXATTR_FLAG_BITS = 4043304960
> PTHREAD_MUTEXATTR_FLAG_PSHARED = 2147483648
< PTHREAD_MUTEX_PRIO_CEILING_MASK = -524288
---
> PTHREAD_MUTEX_PRIO_CEILING_MASK = 4294443008
This is because gen-as-const has a cast of the constant value to long
int, which gen-py-const lacks.
I think the positive values are more logically correct, since the
constants in question are in fact unsigned in C. But to reliably
produce gen-as-const.py output for constants that always (in C and
Python) reflects the signedness of values with the high bit of "long
int" set would mean more complicated logic needs to be used in
computing values.
The more correct positive values by themselves produce a failure of
nptl/test-mutexattr-printers, because masking with
~PTHREAD_MUTEXATTR_FLAG_BITS & ~PTHREAD_MUTEX_NO_ELISION_NP now leaves
a bit -1 << 32 in the Python value, resulting in a KeyError exception.
To avoid that, places masking with ~ of one of the constants in
question are changed to mask with 0xffffffff as well (this reflects
how ~ in Python applies to an infinite-precision integer whereas ~ in
C does not do any promotions beyond the width of int).
Tested for x86_64.
* scripts/gen-as-const.py (main): Handle --python option.
* scripts/gen-py-const.awk: Remove.
* Makerules (py-const-script): Use gen-as-const.py.
($(py-const)): Likewise.
* nptl/nptl-printers.py (MutexPrinter.read_status_no_robust): Mask
with 0xffffffff together with ~(PTHREAD_MUTEX_PRIO_CEILING_MASK).
(MutexAttributesPrinter.read_values): Mask with 0xffffffff
together with ~PTHREAD_MUTEXATTR_FLAG_BITS and
~PTHREAD_MUTEX_NO_ELISION_NP.
* manual/README.pretty-printers: Update reference to
gen-py-const.awk.
Only the gen-as-const.py changes are included downstream. We keep using
gen-py-const.awk for the build.
diff --git a/scripts/gen-as-const.py b/scripts/gen-as-const.py
index f85e359394acb1a4..2f1dff092b98e044 100644
--- a/scripts/gen-as-const.py
+++ b/scripts/gen-as-const.py
@@ -75,6 +75,8 @@ def main():
help='C compiler (including options) to use')
parser.add_argument('--test', action='store_true',
help='Generate test case instead of header')
+ parser.add_argument('--python', action='store_true',
+ help='Generate Python file instead of header')
parser.add_argument('sym_file',
help='.sym file to process')
args = parser.parse_args()
@@ -103,6 +105,13 @@ def main():
sym_data.append('START')
if args.test:
print(gen_test(sym_data))
+ elif args.python:
+ consts = glibcextract.compute_c_consts(sym_data, args.cc)
+ print('# GENERATED FILE\n'
+ '\n'
+ '# Constant definitions.\n'
+ '# See gen-as-const.py for details.\n')
+ print(''.join('%s = %s\n' % c for c in sorted(consts.items())), end='')
else:
consts = glibcextract.compute_c_consts(sym_data, args.cc)
print(''.join('#define %s %s\n' % c for c in sorted(consts.items())), end='')

View File

@ -0,0 +1,178 @@
commit df648905e7d8340bb3e78813fd25e2077b9685d9
Author: Joseph Myers <joseph@codesourcery.com>
Date: Mon Dec 17 18:29:36 2018 +0000
Add test that MAP_* constants agree with kernel.
Continuing the process of building up and using Python infrastructure
for extracting and using values in headers, this patch adds a test
that MAP_* constants from sys/mman.h agree with those in the Linux
kernel headers. (Other sys/mman.h constants could be added to the
test separately.)
This set of constants has grown over time, so the generic code is
enhanced to allow saying extra constants are OK on either side of the
comparison (where the caller sets those parameters based on the Linux
kernel headers version, compared with the version the headers were
last updated from). Although the test is a custom Python file, my
intention is to move in future to a single Python script for such
tests and text files it takes as inputs, once there are enough
examples to provide a guide to the common cases in such tests (I'd
like to end up with most or all such sets of constants copied from
kernel headers having such tests, and likewise for structure layouts
from the kernel).
The Makefile code is essentially the same as for tst-signal-numbers,
but I didn't try to find an object file to depend on to represent the
dependency on the headers used by the test (the conform/ tests don't
try to represent such header dependencies at all, for example).
Tested with build-many-glibcs.py, and also for x86_64 with older
kernel headers.
* scripts/glibcextract.py (compare_macro_consts): Take parameters
to allow extra macros from first or second sources.
* sysdeps/unix/sysv/linux/tst-mman-consts.py: New file.
* sysdeps/unix/sysv/linux/Makefile [$(subdir) = misc]
(tests-special): Add $(objpfx)tst-mman-consts.out.
($(objpfx)tst-mman-consts.out): New makefile target.
diff --git a/scripts/glibcextract.py b/scripts/glibcextract.py
index ecc4d5b6cc387c7d..06f712ad115e0f9e 100644
--- a/scripts/glibcextract.py
+++ b/scripts/glibcextract.py
@@ -136,12 +136,19 @@ def compute_macro_consts(source_text, cc, macro_re, exclude_re=None):
return compute_c_consts(sym_data, cc)
-def compare_macro_consts(source_1, source_2, cc, macro_re, exclude_re=None):
+def compare_macro_consts(source_1, source_2, cc, macro_re, exclude_re=None,
+ allow_extra_1=False, allow_extra_2=False):
"""Compare the values of macros defined by two different sources.
The sources would typically be includes of a glibc header and a
- kernel header. Return 1 if there were any differences, 0 if the
- macro values were the same.
+ kernel header. If allow_extra_1, the first source may define
+ extra macros (typically if the kernel headers are older than the
+ version glibc has taken definitions from); if allow_extra_2, the
+ second source may define extra macros (typically if the kernel
+ headers are newer than the version glibc has taken definitions
+ from). Return 1 if there were any differences other than those
+ allowed, 0 if the macro values were the same apart from any
+ allowed differences.
"""
macros_1 = compute_macro_consts(source_1, cc, macro_re, exclude_re)
@@ -150,13 +157,19 @@ def compare_macro_consts(source_1, source_2, cc, macro_re, exclude_re=None):
return 0
print('First source:\n%s\n' % source_1)
print('Second source:\n%s\n' % source_2)
+ ret = 0
for name, value in sorted(macros_1.items()):
if name not in macros_2:
print('Only in first source: %s' % name)
+ if not allow_extra_1:
+ ret = 1
elif macros_1[name] != macros_2[name]:
print('Different values for %s: %s != %s'
% (name, macros_1[name], macros_2[name]))
+ ret = 1
for name in sorted(macros_2.keys()):
if name not in macros_1:
print('Only in second source: %s' % name)
- return 1
+ if not allow_extra_2:
+ ret = 1
+ return ret
diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile
index 9c10ee53b26e1b1b..863ed80c2a2713d3 100644
--- a/sysdeps/unix/sysv/linux/Makefile
+++ b/sysdeps/unix/sysv/linux/Makefile
@@ -98,6 +98,15 @@ $(objpfx)tst-sysconf-iov_max: $(objpfx)tst-sysconf-iov_max-uapi.o
$(objpfx)tst-pkey: $(shared-thread-library)
+tests-special += $(objpfx)tst-mman-consts.out
+$(objpfx)tst-mman-consts.out: ../sysdeps/unix/sysv/linux/tst-mman-consts.py
+ PYTHONPATH=../scripts \
+ $(PYTHON) ../sysdeps/unix/sysv/linux/tst-mman-consts.py \
+ --cc="$(CC) $(patsubst -DMODULE_NAME=%, \
+ -DMODULE_NAME=testsuite, \
+ $(CPPFLAGS))" \
+ < /dev/null > $@ 2>&1; $(evaluate-test)
+
endif # $(subdir) == misc
ifeq ($(subdir),time)
diff --git a/sysdeps/unix/sysv/linux/tst-mman-consts.py b/sysdeps/unix/sysv/linux/tst-mman-consts.py
new file mode 100644
index 0000000000000000..1a613beec0da16fb
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/tst-mman-consts.py
@@ -0,0 +1,65 @@
+#!/usr/bin/python3
+# Test that glibc's sys/mman.h constants match the kernel's.
+# Copyright (C) 2018 Free Software Foundation, Inc.
+# This file is part of the GNU C Library.
+#
+# The GNU C Library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# The GNU C Library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with the GNU C Library; if not, see
+# <http://www.gnu.org/licenses/>.
+
+import argparse
+import sys
+
+import glibcextract
+
+
+def linux_kernel_version(cc):
+ """Return the (major, minor) version of the Linux kernel headers."""
+ sym_data = ['#include <linux/version.h>', 'START',
+ ('LINUX_VERSION_CODE', 'LINUX_VERSION_CODE')]
+ val = glibcextract.compute_c_consts(sym_data, cc)['LINUX_VERSION_CODE']
+ val = int(val)
+ return ((val & 0xff0000) >> 16, (val & 0xff00) >> 8)
+
+
+def main():
+ """The main entry point."""
+ parser = argparse.ArgumentParser(
+ description="Test that glibc's sys/mman.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 = linux_kernel_version(args.cc)
+ linux_version_glibc = (4, 19)
+ sys.exit(glibcextract.compare_macro_consts(
+ '#define _GNU_SOURCE 1\n'
+ '#include <sys/mman.h>\n',
+ '#define _GNU_SOURCE 1\n'
+ '#include <linux/mman.h>\n',
+ args.cc,
+ 'MAP_.*',
+ # A series of MAP_HUGE_<size> macros are defined by the kernel
+ # but not by glibc. MAP_UNINITIALIZED is kernel-only.
+ # 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
+ # MIPS, marked as "not used by linux"; SPARC has MAP_INHERIT
+ # in the kernel header, but does not use it.
+ 'MAP_HUGE_[0-9].*|MAP_UNINITIALIZED|MAP_FAILED|MAP_ANON'
+ '|MAP_RENAME|MAP_AUTOGROW|MAP_LOCAL|MAP_AUTORSRV|MAP_INHERIT',
+ linux_version_glibc > linux_version_headers,
+ linux_version_headers > linux_version_glibc))
+
+if __name__ == '__main__':
+ main()

View File

@ -0,0 +1,23 @@
commit 46baeb61e16511f26db1b255e19dc9163f590367
Author: Fangrui Song <maskray@google.com>
Date: Tue Oct 19 09:58:16 2021 -0700
glibcextract.py: Place un-assemblable @@@ in a comment
Unlike GCC, Clang parses asm statements and verifies they are valid
instructions/directives. Place the magic @@@ into a comment to avoid
a parse error.
diff --git a/scripts/glibcextract.py b/scripts/glibcextract.py
index 06f712ad115e0f9e..8f2246aae6a9dfb7 100644
--- a/scripts/glibcextract.py
+++ b/scripts/glibcextract.py
@@ -45,7 +45,7 @@ def compute_c_consts(sym_data, cc):
continue
name = arg[0]
value = arg[1]
- out_lines.append('asm ("@@@name@@@%s@@@value@@@%%0@@@end@@@" '
+ out_lines.append('asm ("/* @@@name@@@%s@@@value@@@%%0@@@end@@@ */" '
': : \"i\" ((long int) (%s)));'
% (name, value))
out_lines.append('}')

View File

@ -0,0 +1,45 @@
commit 841afa116e32b3c7195475769c26bf46fd870d32
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Date: Wed Aug 10 16:24:06 2022 -0300
glibcextract.py: Add compile_c_snippet
It might be used on tests to check if a snippet build with the provided
compiler and flags.
Reviewed-by: Florian Weimer <fweimer@redhat.com>
diff --git a/scripts/glibcextract.py b/scripts/glibcextract.py
index 8f2246aae6a9dfb7..0fb50dc8f9c4f7f9 100644
--- a/scripts/glibcextract.py
+++ b/scripts/glibcextract.py
@@ -17,6 +17,7 @@
# License along with the GNU C Library; if not, see
# <http://www.gnu.org/licenses/>.
+import collections
import os.path
import re
import subprocess
@@ -173,3 +174,21 @@ def compare_macro_consts(source_1, source_2, cc, macro_re, exclude_re=None,
if not allow_extra_2:
ret = 1
return ret
+
+CompileResult = collections.namedtuple("CompileResult", "returncode output")
+
+def compile_c_snippet(snippet, cc, extra_cc_args=''):
+ """Compile and return whether the SNIPPET can be build with CC along
+ EXTRA_CC_ARGS compiler flags. Return a CompileResult with RETURNCODE
+ being 0 for success, or the failure value and the compiler output.
+ """
+ with tempfile.TemporaryDirectory() as temp_dir:
+ c_file_name = os.path.join(temp_dir, 'test.c')
+ obj_file_name = os.path.join(temp_dir, 'test.o')
+ with open(c_file_name, 'w') as c_file:
+ c_file.write(snippet + '\n')
+ cmd = cc.split() + extra_cc_args.split() + ['-c', '-o', obj_file_name,
+ c_file_name]
+ r = subprocess.run(cmd, check=False, stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT)
+ return CompileResult(r.returncode, r.stdout)

View File

@ -0,0 +1,32 @@
commit acb55dcb892d4321ada6fd9b663b28fada432682
Author: Joseph Myers <joseph@codesourcery.com>
Date: Wed Jan 2 18:35:50 2019 +0000
Update Linux kernel version in tst-mman-consts.py.
This patch updates the Linux kernel version in tst-mman-consts.py to
4.20 (meaning that's the version for which glibc is expected to have
the same constants as the kernel, up to the exceptions listed in the
test). (Once we have more such tests sharing common infrastructure, I
expect the kernel version will be something set in the infrastructure
shared by all such tests, rather than something needing updating
separately for each test for each new kernel version.)
Tested with build-many-glibcs.py.
* sysdeps/unix/sysv/linux/tst-mman-consts.py (main): Expect
constants to match with Linux 4.20.
diff --git a/sysdeps/unix/sysv/linux/tst-mman-consts.py b/sysdeps/unix/sysv/linux/tst-mman-consts.py
index 1a613beec0da16fb..4a2ddd49c4c7282b 100644
--- a/sysdeps/unix/sysv/linux/tst-mman-consts.py
+++ b/sysdeps/unix/sysv/linux/tst-mman-consts.py
@@ -41,7 +41,7 @@ def main():
help='C compiler (including options) to use')
args = parser.parse_args()
linux_version_headers = linux_kernel_version(args.cc)
- linux_version_glibc = (4, 19)
+ linux_version_glibc = (4, 20)
sys.exit(glibcextract.compare_macro_consts(
'#define _GNU_SOURCE 1\n'
'#include <sys/mman.h>\n',

View File

@ -0,0 +1,31 @@
commit c7a26cba2ab949216ac9ef245ca78696815ea4c4
Author: Joseph Myers <joseph@codesourcery.com>
Date: Fri Aug 2 11:36:07 2019 +0000
Update Linux kernel version number in tst-mman-consts.py to 5.2.
The tst-mman-consts.py test includes a kernel version number, to avoid
failures because of newly added constants in the kernel (if kernel
headers are newer than this version of glibc) or missing constants in
the kernel (if kernel headers are older than this version of glibc).
This patch updates it to 5.2 to reflect that the MAP_* constants in
glibc are still current as of that kernel version.
Tested with build-many-glibcs.py.
* sysdeps/unix/sysv/linux/tst-mman-consts.py (main): Update Linux
kernel version number to 5.2.
diff --git a/sysdeps/unix/sysv/linux/tst-mman-consts.py b/sysdeps/unix/sysv/linux/tst-mman-consts.py
index 4a2ddd49c4c7282b..9e326b1f31799a72 100644
--- a/sysdeps/unix/sysv/linux/tst-mman-consts.py
+++ b/sysdeps/unix/sysv/linux/tst-mman-consts.py
@@ -41,7 +41,7 @@ def main():
help='C compiler (including options) to use')
args = parser.parse_args()
linux_version_headers = linux_kernel_version(args.cc)
- linux_version_glibc = (4, 20)
+ linux_version_glibc = (5, 2)
sys.exit(glibcextract.compare_macro_consts(
'#define _GNU_SOURCE 1\n'
'#include <sys/mman.h>\n',

View File

@ -0,0 +1,61 @@
commit 71bdf29ac1de04efcce96bc5ce50af3263851ac7
Author: Joseph Myers <joseph@codesourcery.com>
Date: Mon Sep 30 15:49:25 2019 +0000
Update bits/mman.h constants and tst-mman-consts.py for Linux 5.3.
The Linux 5.3 uapi headers have some rearrangement relating to MAP_*
constants, which includes the effect of adding definitions of MAP_SYNC
on powerpc and sparc. This patch updates the corresponding glibc
bits/mman.h headers accordingly, and updates the Linux kernel version
number in tst-mman-consts.py to reflect that these constants are now
current with that kernel version.
Tested with build-many-glibcs.py.
* sysdeps/unix/sysv/linux/powerpc/bits/mman.h [__USE_MISC]
(MAP_SYNC): New macro.
* sysdeps/unix/sysv/linux/sparc/bits/mman.h [__USE_MISC]
(MAP_SYNC): Likewise.
* sysdeps/unix/sysv/linux/tst-mman-consts.py (main): Update Linux
kernel version number to 5.3.
diff --git a/sysdeps/unix/sysv/linux/powerpc/bits/mman.h b/sysdeps/unix/sysv/linux/powerpc/bits/mman.h
index e652467c8c091381..0e7fa647793ed585 100644
--- a/sysdeps/unix/sysv/linux/powerpc/bits/mman.h
+++ b/sysdeps/unix/sysv/linux/powerpc/bits/mman.h
@@ -36,6 +36,8 @@
# define MAP_NONBLOCK 0x10000 /* Do not block on IO. */
# define MAP_STACK 0x20000 /* Allocation is for a stack. */
# define MAP_HUGETLB 0x40000 /* Create huge page mapping. */
+# define MAP_SYNC 0x80000 /* Perform synchronous page
+ faults for the mapping. */
# define MAP_FIXED_NOREPLACE 0x100000 /* MAP_FIXED but do not unmap
underlying mapping. */
#endif
diff --git a/sysdeps/unix/sysv/linux/sparc/bits/mman.h b/sysdeps/unix/sysv/linux/sparc/bits/mman.h
index 3a3ffb994631e2b6..03f6f732bb5efbe2 100644
--- a/sysdeps/unix/sysv/linux/sparc/bits/mman.h
+++ b/sysdeps/unix/sysv/linux/sparc/bits/mman.h
@@ -36,6 +36,8 @@
# define MAP_NONBLOCK 0x10000 /* Do not block on IO. */
# define MAP_STACK 0x20000 /* Allocation is for a stack. */
# define MAP_HUGETLB 0x40000 /* Create huge page mapping. */
+# define MAP_SYNC 0x80000 /* Perform synchronous page
+ faults for the mapping. */
# define MAP_FIXED_NOREPLACE 0x100000 /* MAP_FIXED but do not unmap
underlying mapping. */
#endif
diff --git a/sysdeps/unix/sysv/linux/tst-mman-consts.py b/sysdeps/unix/sysv/linux/tst-mman-consts.py
index 9e326b1f31799a72..42914e4e0ba84712 100644
--- a/sysdeps/unix/sysv/linux/tst-mman-consts.py
+++ b/sysdeps/unix/sysv/linux/tst-mman-consts.py
@@ -41,7 +41,7 @@ def main():
help='C compiler (including options) to use')
args = parser.parse_args()
linux_version_headers = linux_kernel_version(args.cc)
- linux_version_glibc = (5, 2)
+ linux_version_glibc = (5, 3)
sys.exit(glibcextract.compare_macro_consts(
'#define _GNU_SOURCE 1\n'
'#include <sys/mman.h>\n',

View File

@ -1,6 +1,6 @@
%define glibcsrcdir glibc-2.28
%define glibcversion 2.28
%define glibcrelease 219%{?dist}
%define glibcrelease 220%{?dist}
# Pre-release tarballs are pulled in from git using a command that is
# effectively:
#
@ -986,6 +986,32 @@ Patch793: glibc-rh2122501-5.patch
Patch794: glibc-rh2121746-1.patch
Patch795: glibc-rh2121746-2.patch
Patch796: glibc-rh2116938.patch
Patch797: glibc-rh2109510-1.patch
Patch798: glibc-rh2109510-2.patch
Patch799: glibc-rh2109510-3.patch
Patch800: glibc-rh2109510-4.patch
Patch801: glibc-rh2109510-5.patch
Patch802: glibc-rh2109510-6.patch
Patch803: glibc-rh2109510-7.patch
Patch804: glibc-rh2109510-8.patch
Patch805: glibc-rh2109510-9.patch
Patch806: glibc-rh2109510-10.patch
Patch807: glibc-rh2109510-11.patch
Patch808: glibc-rh2109510-12.patch
Patch809: glibc-rh2109510-13.patch
Patch810: glibc-rh2109510-14.patch
Patch811: glibc-rh2109510-15.patch
Patch812: glibc-rh2109510-16.patch
Patch813: glibc-rh2109510-17.patch
Patch814: glibc-rh2109510-18.patch
Patch815: glibc-rh2109510-19.patch
Patch816: glibc-rh2109510-20.patch
Patch817: glibc-rh2109510-21.patch
Patch818: glibc-rh2109510-22.patch
Patch819: glibc-rh2109510-23.patch
Patch820: glibc-rh2139875-1.patch
Patch821: glibc-rh2139875-2.patch
Patch822: glibc-rh2139875-3.patch
##############################################################################
# Continued list of core "glibc" package information:
@ -2816,6 +2842,10 @@ fi
%files -f compat-libpthread-nonshared.filelist -n compat-libpthread-nonshared
%changelog
* Thu Nov 3 2022 Florian Weimer <fweimer@redhat.com> - 2.28-220
- Explicitly switch to --with-default-link=no (#2109510)
- Define MAP_SYNC on ppc64le (#2139875)
* Mon Oct 24 2022 Arjun Shankar <arjun@redhat.com> - 2.28-219
- Fix -Wstrict-overflow warning when using CMSG_NXTHDR macro (#2116938)