GIT update of https://sourceware.org/git/glibc.git/release/2.31/master from glibc-2.31
GIT update of https://sourceware.org/git/glibc.git/release/2.31/master from glibc-2.31
Gbp-Pq: Name git-updates.diff
Please send GNU C library bug reports via <https://sourceware.org/bugzilla/>
using `glibc' in the "product" field.
\f
+Version 2.31.1
+
+The following bugs are resolved with this release:
+ [19519] iconv(1) with -c option hangs on illegal multi-byte sequences
+ (CVE-2016-10228)
+ [20019] NULL pointer dereference in libc.so.6 IFUNC due to uninitialized GOT
+ [20543] Please move from .gnu.linkonce to comdat
+ [23296] Data race in setting function descriptor during lazy binding
+ [24973] iconv encounters segmentation fault when converting 0x00 0xfe in
+ EUC-KR to UTF-8 (CVE-2019-25013)
+ [25487] sinl() stack corruption from crafted input (CVE-2020-10029)
+ [25523] MIPS/Linux inline syscall template is miscompiled
+ [25623] test-sysvmsg, test-sysvsem, test-sysvshm fail with 2.31 on 32 bit and
+ old kernel
+ [25635] arm: Wrong sysdep order selection for soft-fp
+ [25639] localedata: Some names of days and months wrongly spelt in
+ Occitan
+ [25715] system() returns wrong errors when posix_spawn fails
+ [25810] x32: Incorrect syscall entries with pointer, off_t and size_t
+ [25896] Incorrect prctl
+ [25902] Bad LOADARGS_N
+ [25933] Off by one error in __strncmp_avx2
+ [25966] Incorrect access of __x86_shared_non_temporal_threshold for x32
+ [25976] nss_compat: internal_end*ent may clobber errno, hiding ERANGE
+ [26224] iconv hangs when converting some invalid inputs from several IBM
+ character sets (CVE-2020-27618)
+ [26248] Incorrect argument types for INLINE_SETXID_SYSCALL
+ [26332] Incorrect cache line size load causes memory corruption in memset
+ [26383] bind_textdomain_codeset doesn't accept //TRANSLIT anymore
+ [26923] Assertion failure in iconv when converting invalid UCS4 (CVE-2020-29562)
+ [26932] libc: sh: Multiple floating point functions defined as stubs only
+ [27130] "rep movsb" performance issue
+ [27177] GLIBC_TUNABLES=glibc.cpu.x86_ibt=on:glibc.cpu.x86_shstk=on doesn't work
+
+Security related changes:
+
+ CVE-2016-10228: An infinite loop has been fixed in the iconv program when
+ invoked with the -c option and when processing invalid multi-byte input
+ sequences. Reported by Jan Engelhardt.
+
+ CVE-2020-10029: Trigonometric functions on x86 targets suffered from stack
+ corruption when they were passed a pseudo-zero argument. Reported by Guido
+ Vranken / ForAllSecure Mayhem.
+
+ CVE-2020-1751: A defect in the PowerPC backtrace function could cause an
+ out-of-bounds write when executed in a signal frame context.
+
+ CVE-2020-1752: A use-after-free vulnerability in the glob function when
+ expanding ~user has been fixed.
+
+ CVE-2020-6096: A signed comparison vulnerability in the ARMv7 memcpy and
+ memmove functions has been fixed. Discovered by Jason Royes and Samual
+ Dytrych of the Cisco Security Assessment and Penetration Team (See
+ TALOS-2020-1019).
+
+ CVE-2020-27618: An infinite loop has been fixed in the iconv program when
+ invoked with input containing redundant shift sequences in the IBM1364,
+ IBM1371, IBM1388, IBM1390, or IBM1399 character sets.
+
+ CVE-2020-29562: An assertion failure has been fixed in the iconv function
+ when invoked with UCS4 input containing an invalid character.
+\f
Version 2.31
Major new features:
else
tests: $(tests:%=$(objpfx)%.out) $(tests-internal:%=$(objpfx)%.out) \
$(tests-container:%=$(objpfx)%.out) \
+ $(tests-mcheck:%=$(objpfx)%-mcheck.out) \
$(tests-special) $(tests-printers-out)
xtests: tests $(xtests:%=$(objpfx)%.out) $(xtests-special)
endif
tests-expected =
else
tests-expected = $(tests) $(tests-internal) $(tests-printers) \
- $(tests-container)
+ $(tests-container) $(tests-mcheck:%=%-mcheck)
endif
tests:
$(..)scripts/merge-test-results.sh -s $(objpfx) $(subdir) \
binaries-pie-tests =
binaries-pie-notests =
endif
+binaries-mcheck-tests = $(tests-mcheck:%=%-mcheck)
else
binaries-all-notests =
binaries-all-tests = $(tests) $(tests-internal) $(xtests) $(test-srcs)
binaries-static =
binaries-pie-tests =
binaries-pie-notests =
+binaries-mcheck-tests =
endif
binaries-pie = $(binaries-pie-tests) $(binaries-pie-notests)
$(+link-tests)
endif
+ifneq "$(strip $(binaries-mcheck-tests))" ""
+$(addprefix $(objpfx),$(binaries-mcheck-tests)): %-mcheck: %.o \
+ $(link-extra-libs-tests) \
+ $(sort $(filter $(common-objpfx)lib%,$(link-libc))) \
+ $(addprefix $(csu-objpfx),start.o) $(+preinit) $(+postinit)
+ $(+link-tests)
+endif
+
ifneq "$(strip $(binaries-pie-tests))" ""
$(addprefix $(objpfx),$(binaries-pie-tests)): %: %.o \
$(link-extra-libs-tests) \
$(+link-static-tests)
endif
+# All mcheck tests will be run with MALLOC_CHECK_=3
+define mcheck-ENVS
+$(1)-mcheck-ENV = MALLOC_CHECK_=3
+endef
+$(foreach t,$(tests-mcheck),$(eval $(call mcheck-ENVS,$(t))))
+
ifneq "$(strip $(tests) $(tests-internal) $(xtests) $(test-srcs))" ""
# These are the implicit rules for making test outputs
# from the test programs and whatever input files are present.
-o conftest conftest.S 1>&5 2>&5; then
# Do a link to see if the backend supports IFUNC relocs.
$READELF -r conftest 1>&5
- LC_ALL=C $READELF -r conftest | grep 'no relocations' >/dev/null || {
+ LC_ALL=C $READELF -Wr conftest | grep -q 'IRELATIVE\|R_SPARC_JMP_IREL' && {
libc_cv_ld_gnu_indirect_function=yes
}
fi
-o conftest conftest.S 1>&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD; then
# Do a link to see if the backend supports IFUNC relocs.
$READELF -r conftest 1>&AS_MESSAGE_LOG_FD
- LC_ALL=C $READELF -r conftest | grep 'no relocations' >/dev/null || {
+ LC_ALL=C $READELF -Wr conftest | grep -q 'IRELATIVE\|R_SPARC_JMP_IREL' && {
libc_cv_ld_gnu_indirect_function=yes
}
fi
#include <gnu/lib-names.h>
#include <stdlib.h>
#include <unwind.h>
+#include <unwind-arch.h>
struct trace_arg
{
if (arg->cnt != -1)
{
arg->array[arg->cnt] = (void *) unwind_getip (ctx);
+ if (arg->cnt > 0)
+ arg->array[arg->cnt]
+ = unwind_arch_adjustment (arg->array[arg->cnt - 1],
+ arg->array[arg->cnt]);
/* Check whether we make any progress. */
_Unwind_Word cfa = unwind_getcfa (ctx);
CFLAGS-ifuncmain9pie.c += $(pie-ccflag)
CFLAGS-tst-ifunc-textrel.c += $(pic-ccflag)
+LDFLAGS-ifuncmain6pie = -Wl,-z,lazy
+
$(objpfx)ifuncmain1pie: $(objpfx)ifuncmod1.so
$(objpfx)ifuncmain1staticpie: $(objpfx)ifuncdep1pic.o
$(objpfx)ifuncmain1vispie: $(objpfx)ifuncmod1.so
tst-env-setuid-ENV = MALLOC_CHECK_=2 MALLOC_MMAP_THRESHOLD_=4096 \
LD_HWCAP_MASK=0x1
-tst-env-setuid-tunables-ENV = \
- GLIBC_TUNABLES=glibc.malloc.check=2:glibc.malloc.mmap_threshold=4096
$(objpfx)tst-debug1: $(libdl)
$(objpfx)tst-debug1.out: $(objpfx)tst-debug1mod1.so
return;
char *p = tunestr;
+ size_t off = 0;
while (true)
{
/* If we reach the end of the string before getting a valid name-value
pair, bail out. */
if (p[len] == '\0')
- return;
+ {
+ if (__libc_enable_secure)
+ tunestr[off] = '\0';
+ return;
+ }
/* We did not find a valid name-value pair before encountering the
colon. */
if (tunable_is_name (cur->name, name))
{
- /* If we are in a secure context (AT_SECURE) then ignore the tunable
- unless it is explicitly marked as secure. Tunable values take
- precendence over their envvar aliases. */
+ /* If we are in a secure context (AT_SECURE) then ignore the
+ tunable unless it is explicitly marked as secure. Tunable
+ values take precedence over their envvar aliases. We write
+ the tunables that are not SXID_ERASE back to TUNESTR, thus
+ dropping all SXID_ERASE tunables and any invalid or
+ unrecognized tunables. */
if (__libc_enable_secure)
{
- if (cur->security_level == TUNABLE_SECLEVEL_SXID_ERASE)
+ if (cur->security_level != TUNABLE_SECLEVEL_SXID_ERASE)
{
- if (p[len] == '\0')
- {
- /* Last tunable in the valstring. Null-terminate and
- return. */
- *name = '\0';
- return;
- }
- else
- {
- /* Remove the current tunable from the string. We do
- this by overwriting the string starting from NAME
- (which is where the current tunable begins) with
- the remainder of the string. We then have P point
- to NAME so that we continue in the correct
- position in the valstring. */
- char *q = &p[len + 1];
- p = name;
- while (*q != '\0')
- *name++ = *q++;
- name[0] = '\0';
- len = 0;
- }
+ if (off > 0)
+ tunestr[off++] = ':';
+
+ const char *n = cur->name;
+
+ while (*n != '\0')
+ tunestr[off++] = *n++;
+
+ tunestr[off++] = '=';
+
+ for (size_t j = 0; j < len; j++)
+ tunestr[off++] = value[j];
}
if (cur->security_level != TUNABLE_SECLEVEL_NONE)
}
}
- if (p[len] == '\0')
- return;
- else
+ if (p[len] != '\0')
p += len + 1;
}
}
#include "ifunc-sel.h"
typedef int (*foo_p) (void);
-extern foo_p foo_ptr;
static int
one (void)
}
extern int foo (void);
-extern foo_p get_foo (void);
+extern int call_foo (void);
extern foo_p get_foo_p (void);
-foo_p my_foo_ptr = foo;
+foo_p foo_ptr = foo;
int
main (void)
{
foo_p p;
- p = get_foo ();
- if (p != foo)
- abort ();
- if ((*p) () != -30)
+ if (call_foo () != -30)
abort ();
p = get_foo_p ();
if (foo_ptr != foo)
abort ();
- if (my_foo_ptr != foo)
- abort ();
if ((*foo_ptr) () != -30)
abort ();
- if ((*my_foo_ptr) () != -30)
- abort ();
if (foo () != -30)
abort ();
typedef int (*foo_p) (void);
-foo_p foo_ptr = foo;
+extern foo_p foo_ptr;
foo_p
get_foo_p (void)
return foo_ptr;
}
-foo_p
-get_foo (void)
+int
+call_foo (void)
{
- return foo;
+ return foo ();
}
#include "config.h"
#undef _LIBC
-#define test_parent test_parent_tunables
-#define test_child test_child_tunables
-
-static int test_child_tunables (void);
-static int test_parent_tunables (void);
-
-#include "tst-env-setuid.c"
-
-#define CHILD_VALSTRING_VALUE "glibc.malloc.mmap_threshold=4096"
-#define PARENT_VALSTRING_VALUE \
- "glibc.malloc.check=2:glibc.malloc.mmap_threshold=4096"
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <intprops.h>
+#include <array_length.h>
+
+#include <support/check.h>
+#include <support/support.h>
+#include <support/test-driver.h>
+#include <support/capture_subprocess.h>
+
+const char *teststrings[] =
+{
+ "glibc.malloc.check=2:glibc.malloc.mmap_threshold=4096",
+ "glibc.malloc.check=2:glibc.malloc.check=2:glibc.malloc.mmap_threshold=4096",
+ "glibc.malloc.check=2:glibc.malloc.mmap_threshold=4096:glibc.malloc.check=2",
+ "glibc.malloc.perturb=0x800",
+ "glibc.malloc.perturb=0x800:glibc.malloc.mmap_threshold=4096",
+ "glibc.malloc.perturb=0x800:not_valid.malloc.check=2:glibc.malloc.mmap_threshold=4096",
+ "glibc.not_valid.check=2:glibc.malloc.mmap_threshold=4096",
+ "not_valid.malloc.check=2:glibc.malloc.mmap_threshold=4096",
+ "glibc.malloc.garbage=2:glibc.maoc.mmap_threshold=4096:glibc.malloc.check=2",
+ "glibc.malloc.check=4:glibc.malloc.garbage=2:glibc.maoc.mmap_threshold=4096",
+ ":glibc.malloc.garbage=2:glibc.malloc.check=1",
+ "glibc.malloc.check=1:glibc.malloc.check=2",
+ "not_valid.malloc.check=2",
+ "glibc.not_valid.check=2",
+};
+
+const char *resultstrings[] =
+{
+ "glibc.malloc.mmap_threshold=4096",
+ "glibc.malloc.mmap_threshold=4096",
+ "glibc.malloc.mmap_threshold=4096",
+ "glibc.malloc.perturb=0x800",
+ "glibc.malloc.perturb=0x800:glibc.malloc.mmap_threshold=4096",
+ "glibc.malloc.perturb=0x800:glibc.malloc.mmap_threshold=4096",
+ "glibc.malloc.mmap_threshold=4096",
+ "glibc.malloc.mmap_threshold=4096",
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+};
static int
-test_child_tunables (void)
+test_child (int off)
{
const char *val = getenv ("GLIBC_TUNABLES");
#if HAVE_TUNABLES
- if (val != NULL && strcmp (val, CHILD_VALSTRING_VALUE) == 0)
+ if (val != NULL && strcmp (val, resultstrings[off]) == 0)
return 0;
if (val != NULL)
- printf ("Unexpected GLIBC_TUNABLES VALUE %s\n", val);
+ printf ("[%d] Unexpected GLIBC_TUNABLES VALUE %s\n", off, val);
return 1;
#else
if (val != NULL)
{
- printf ("GLIBC_TUNABLES not cleared\n");
+ printf ("[%d] GLIBC_TUNABLES not cleared\n", off);
return 1;
}
return 0;
}
static int
-test_parent_tunables (void)
+do_test (int argc, char **argv)
{
- const char *val = getenv ("GLIBC_TUNABLES");
+ /* Setgid child process. */
+ if (argc == 2)
+ {
+ if (getgid () == getegid ())
+ /* This can happen if the file system is mounted nosuid. */
+ FAIL_UNSUPPORTED ("SGID failed: GID and EGID match (%jd)\n",
+ (intmax_t) getgid ());
- if (val != NULL && strcmp (val, PARENT_VALSTRING_VALUE) == 0)
- return 0;
+ int ret = test_child (atoi (argv[1]));
- if (val != NULL)
- printf ("Unexpected GLIBC_TUNABLES VALUE %s\n", val);
+ if (ret != 0)
+ exit (1);
- return 1;
+ exit (EXIT_SUCCESS);
+ }
+ else
+ {
+ int ret = 0;
+
+ /* Spawn tests. */
+ for (int i = 0; i < array_length (teststrings); i++)
+ {
+ char buf[INT_BUFSIZE_BOUND (int)];
+
+ printf ("Spawned test for %s (%d)\n", teststrings[i], i);
+ snprintf (buf, sizeof (buf), "%d\n", i);
+ if (setenv ("GLIBC_TUNABLES", teststrings[i], 1) != 0)
+ exit (1);
+
+ int status = support_capture_subprogram_self_sgid (buf);
+
+ /* Bail out early if unsupported. */
+ if (WEXITSTATUS (status) == EXIT_UNSUPPORTED)
+ return EXIT_UNSUPPORTED;
+
+ ret |= status;
+ }
+ return ret;
+ }
}
+
+#define TEST_FUNCTION_ARGV do_test
+#include <support/test-driver.c>
#include <sys/wait.h>
#include <unistd.h>
+#include <support/check.h>
#include <support/support.h>
#include <support/test-driver.h>
+#include <support/capture_subprocess.h>
static char SETGID_CHILD[] = "setgid-child";
-#define CHILD_STATUS 42
-
-/* Return a GID which is not our current GID, but is present in the
- supplementary group list. */
-static gid_t
-choose_gid (void)
-{
- const int count = 64;
- gid_t groups[count];
- int ret = getgroups (count, groups);
- if (ret < 0)
- {
- printf ("getgroups: %m\n");
- exit (1);
- }
- gid_t current = getgid ();
- for (int i = 0; i < ret; ++i)
- {
- if (groups[i] != current)
- return groups[i];
- }
- return 0;
-}
-
-/* Spawn and execute a program and verify that it returns the CHILD_STATUS. */
-static pid_t
-do_execve (char **args)
-{
- pid_t kid = vfork ();
-
- if (kid < 0)
- {
- printf ("vfork: %m\n");
- return -1;
- }
-
- if (kid == 0)
- {
- /* Child process. */
- execve (args[0], args, environ);
- _exit (-errno);
- }
-
- if (kid < 0)
- return 1;
-
- int status;
-
- if (waitpid (kid, &status, 0) < 0)
- {
- printf ("waitpid: %m\n");
- return 1;
- }
-
- if (WEXITSTATUS (status) == EXIT_UNSUPPORTED)
- return EXIT_UNSUPPORTED;
-
- if (!WIFEXITED (status) || WEXITSTATUS (status) != CHILD_STATUS)
- {
- printf ("Unexpected exit status %d from child process\n",
- WEXITSTATUS (status));
- return 1;
- }
- return 0;
-}
-
-/* Copies the executable into a restricted directory, so that we can
- safely make it SGID with the TARGET group ID. Then runs the
- executable. */
-static int
-run_executable_sgid (gid_t target)
-{
- char *dirname = xasprintf ("%s/tst-tunables-setuid.%jd",
- test_dir, (intmax_t) getpid ());
- char *execname = xasprintf ("%s/bin", dirname);
- int infd = -1;
- int outfd = -1;
- int ret = 0;
- if (mkdir (dirname, 0700) < 0)
- {
- printf ("mkdir: %m\n");
- goto err;
- }
- infd = open ("/proc/self/exe", O_RDONLY);
- if (infd < 0)
- {
- printf ("open (/proc/self/exe): %m\n");
- goto err;
- }
- outfd = open (execname, O_WRONLY | O_CREAT | O_EXCL, 0700);
- if (outfd < 0)
- {
- printf ("open (%s): %m\n", execname);
- goto err;
- }
- char buf[4096];
- for (;;)
- {
- ssize_t rdcount = read (infd, buf, sizeof (buf));
- if (rdcount < 0)
- {
- printf ("read: %m\n");
- goto err;
- }
- if (rdcount == 0)
- break;
- char *p = buf;
- char *end = buf + rdcount;
- while (p != end)
- {
- ssize_t wrcount = write (outfd, buf, end - p);
- if (wrcount == 0)
- errno = ENOSPC;
- if (wrcount <= 0)
- {
- printf ("write: %m\n");
- goto err;
- }
- p += wrcount;
- }
- }
- if (fchown (outfd, getuid (), target) < 0)
- {
- printf ("fchown (%s): %m\n", execname);
- goto err;
- }
- if (fchmod (outfd, 02750) < 0)
- {
- printf ("fchmod (%s): %m\n", execname);
- goto err;
- }
- if (close (outfd) < 0)
- {
- printf ("close (outfd): %m\n");
- goto err;
- }
- if (close (infd) < 0)
- {
- printf ("close (infd): %m\n");
- goto err;
- }
-
- char *args[] = {execname, SETGID_CHILD, NULL};
-
- ret = do_execve (args);
-
-err:
- if (outfd >= 0)
- close (outfd);
- if (infd >= 0)
- close (infd);
- if (execname)
- {
- unlink (execname);
- free (execname);
- }
- if (dirname)
- {
- rmdir (dirname);
- free (dirname);
- }
- return ret;
-}
#ifndef test_child
static int
if (argc == 2 && strcmp (argv[1], SETGID_CHILD) == 0)
{
if (getgid () == getegid ())
- {
- /* This can happen if the file system is mounted nosuid. */
- fprintf (stderr, "SGID failed: GID and EGID match (%jd)\n",
- (intmax_t) getgid ());
- exit (EXIT_UNSUPPORTED);
- }
+ /* This can happen if the file system is mounted nosuid. */
+ FAIL_UNSUPPORTED ("SGID failed: GID and EGID match (%jd)\n",
+ (intmax_t) getgid ());
int ret = test_child ();
if (ret != 0)
exit (1);
- exit (CHILD_STATUS);
+ exit (EXIT_SUCCESS);
}
else
{
if (test_parent () != 0)
exit (1);
- /* Try running a setgid program. */
- gid_t target = choose_gid ();
- if (target == 0)
- {
- fprintf (stderr,
- "Could not find a suitable GID for user %jd, skipping test\n",
- (intmax_t) getuid ());
- exit (0);
- }
+ int status = support_capture_subprogram_self_sgid (SETGID_CHILD);
- return run_executable_sgid (target);
- }
+ if (WEXITSTATUS (status) == EXIT_UNSUPPORTED)
+ return EXIT_UNSUPPORTED;
+
+ if (!WIFEXITED (status))
+ FAIL_EXIT1 ("Unexpected exit status %d from child process\n", status);
- /* Something went wrong and our argv was corrupted. */
- _exit (1);
+ return 0;
+ }
}
#define TEST_FUNCTION_ARGV do_test
routines = iconv_open iconv iconv_close \
gconv_open gconv gconv_close gconv_db gconv_conf \
gconv_builtin gconv_simple gconv_trans gconv_cache
-routines += gconv_dl
+routines += gconv_dl gconv_charset
vpath %.c ../locale/programs ../intl
CFLAGS-simple-hash.c += -I../locale
tests = tst-iconv1 tst-iconv2 tst-iconv3 tst-iconv4 tst-iconv5 tst-iconv6 \
- tst-iconv7 tst-iconv-mt
+ tst-iconv7 tst-iconv8 tst-iconv-mt tst-iconv-opt
others = iconv_prog iconvconfig
install-others-programs = $(inst_bindir)/iconv
ifeq ($(run-built-tests),yes)
xtests-special += $(objpfx)test-iconvconfig.out
+tests-special += $(objpfx)tst-iconv_prog.out
endif
# Make a copy of the file because gconv module names are constructed
include ../Rules
+ifeq ($(run-built-tests),yes)
+LOCALES := en_US.UTF-8
+include ../gen-locales.mk
+
+$(objpfx)tst-iconv-opt.out: $(gen-locales)
+endif
+
$(inst_bindir)/iconv: $(objpfx)iconv_prog $(+force)
$(do-install-program)
cmp $$tmp $(inst_gconvdir)/gconv-modules.cache; \
rm -f $$tmp) > $@; \
$(evaluate-test)
+
+$(objpfx)tst-iconv_prog.out: tst-iconv_prog.sh $(objpfx)iconv_prog
+ $(BASH) $< $(common-objdir) '$(test-wrapper-env)' \
+ '$(run-program-env)' > $@; \
+ $(evaluate-test)
# functions shared with iconv program
__gconv_get_alias_db; __gconv_get_cache; __gconv_get_modules_db;
+ # functions used elsewhere in glibc
+ __gconv_open; __gconv_create_spec; __gconv_destroy_spec;
+
# function used by the gconv modules
__gconv_transliterate;
}
--- /dev/null
+/* Charset name normalization.
+ Copyright (C) 2020 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+
+#include <stdlib.h>
+#include <ctype.h>
+#include <locale.h>
+#include <stdbool.h>
+#include <string.h>
+#include <sys/stat.h>
+#include "gconv_int.h"
+#include "gconv_charset.h"
+
+
+/* This function returns a pointer to the last suffix in a conversion code
+ string. Valid suffixes matched by this function are of the form: '/' or ','
+ followed by arbitrary text that doesn't contain '/' or ','. It does not
+ edit the string in any way. The caller is expected to parse the suffix and
+ remove it (by e.g. truncating the string) before the next call. */
+static char *
+find_suffix (char *s)
+{
+ /* The conversion code is in the form of a triplet, separated by '/' chars.
+ The third component of the triplet contains suffixes. If we don't have two
+ slashes, we don't have a suffix. */
+
+ int slash_count = 0;
+ char *suffix_term = NULL;
+
+ for (int i = 0; s[i] != '\0'; i++)
+ switch (s[i])
+ {
+ case '/':
+ slash_count++;
+ /* Fallthrough */
+ case ',':
+ suffix_term = &s[i];
+ }
+
+ if (slash_count >= 2)
+ return suffix_term;
+
+ return NULL;
+}
+
+
+struct gconv_parsed_code
+{
+ char *code;
+ bool translit;
+ bool ignore;
+};
+
+
+/* This function parses an iconv_open encoding PC.CODE, strips any suffixes
+ (such as TRANSLIT or IGNORE) from it and sets corresponding flags in it. */
+static void
+gconv_parse_code (struct gconv_parsed_code *pc)
+{
+ pc->translit = false;
+ pc->ignore = false;
+
+ while (1)
+ {
+ /* First drop any trailing whitespaces and separators. */
+ size_t len = strlen (pc->code);
+ while ((len > 0)
+ && (isspace (pc->code[len - 1])
+ || pc->code[len - 1] == ','
+ || pc->code[len - 1] == '/'))
+ len--;
+
+ pc->code[len] = '\0';
+
+ if (len == 0)
+ return;
+
+ char * suffix = find_suffix (pc->code);
+ if (suffix == NULL)
+ {
+ /* At this point, we have processed and removed all suffixes from the
+ code and what remains of the code is suffix free. */
+ return;
+ }
+ else
+ {
+ /* A suffix is processed from the end of the code array going
+ backwards, one suffix at a time. The suffix is an index into the
+ code character array and points to: one past the end of the code
+ and any unprocessed suffixes, and to the beginning of the suffix
+ currently being processed during this iteration. We must process
+ this suffix and then drop it from the code by terminating the
+ preceding text with NULL.
+
+ We want to allow and recognize suffixes such as:
+
+ "/TRANSLIT" i.e. single suffix
+ "//TRANSLIT" i.e. single suffix and multiple separators
+ "//TRANSLIT/IGNORE" i.e. suffixes separated by "/"
+ "/TRANSLIT//IGNORE" i.e. suffixes separated by "//"
+ "//IGNORE,TRANSLIT" i.e. suffixes separated by ","
+ "//IGNORE," i.e. trailing ","
+ "//TRANSLIT/" i.e. trailing "/"
+ "//TRANSLIT//" i.e. trailing "//"
+ "/" i.e. empty suffix.
+
+ Unknown suffixes are silently discarded and ignored. */
+
+ if ((__strcasecmp_l (suffix,
+ GCONV_TRIPLE_SEPARATOR
+ GCONV_TRANSLIT_SUFFIX,
+ _nl_C_locobj_ptr) == 0)
+ || (__strcasecmp_l (suffix,
+ GCONV_SUFFIX_SEPARATOR
+ GCONV_TRANSLIT_SUFFIX,
+ _nl_C_locobj_ptr) == 0))
+ pc->translit = true;
+
+ if ((__strcasecmp_l (suffix,
+ GCONV_TRIPLE_SEPARATOR
+ GCONV_IGNORE_ERRORS_SUFFIX,
+ _nl_C_locobj_ptr) == 0)
+ || (__strcasecmp_l (suffix,
+ GCONV_SUFFIX_SEPARATOR
+ GCONV_IGNORE_ERRORS_SUFFIX,
+ _nl_C_locobj_ptr) == 0))
+ pc->ignore = true;
+
+ /* We just processed this suffix. We can now drop it from the
+ code string by truncating it at the suffix's position. */
+ suffix[0] = '\0';
+ }
+ }
+}
+
+
+/* This function accepts the charset names of the source and destination of the
+ conversion and populates *conv_spec with an equivalent conversion
+ specification that may later be used by __gconv_open. The charset names
+ might contain options in the form of suffixes that alter the conversion,
+ e.g. "ISO-10646/UTF-8/TRANSLIT". It processes the charset names, ignoring
+ and truncating any suffix options in fromcode, and processing and truncating
+ any suffix options in tocode. Supported suffix options ("TRANSLIT" or
+ "IGNORE") when found in tocode lead to the corresponding flag in *conv_spec
+ to be set to true. Unrecognized suffix options are silently discarded. If
+ the function succeeds, it returns conv_spec back to the caller. It returns
+ NULL upon failure. conv_spec must be allocated and freed by the caller. */
+struct gconv_spec *
+__gconv_create_spec (struct gconv_spec *conv_spec, const char *fromcode,
+ const char *tocode)
+{
+ struct gconv_parsed_code pfc, ptc;
+ struct gconv_spec *ret = NULL;
+
+ pfc.code = __strdup (fromcode);
+ ptc.code = __strdup (tocode);
+
+ if ((pfc.code == NULL)
+ || (ptc.code == NULL))
+ goto out;
+
+ gconv_parse_code (&pfc);
+ gconv_parse_code (&ptc);
+
+ /* We ignore suffixes in the fromcode because that is how the current
+ implementation has always handled them. Only suffixes in the tocode are
+ processed and handled. The reality is that invalid input in the input
+ character set should only be ignored if the fromcode specifies IGNORE.
+ The current implementation ignores invalid intput in the input character
+ set if the tocode contains IGNORE. We preserve this behavior for
+ backwards compatibility. In the future we may split the handling of
+ IGNORE to allow a finer grained specification of ignorning invalid input
+ and/or ignoring invalid output. */
+ conv_spec->translit = ptc.translit;
+ conv_spec->ignore = ptc.ignore;
+
+ /* 3 extra bytes because 1 extra for '\0', and 2 extra so strip might
+ be able to add one or two trailing '/' characters if necessary. */
+ conv_spec->fromcode = malloc (strlen (fromcode) + 3);
+ if (conv_spec->fromcode == NULL)
+ goto out;
+
+ conv_spec->tocode = malloc (strlen (tocode) + 3);
+ if (conv_spec->tocode == NULL)
+ {
+ free (conv_spec->fromcode);
+ conv_spec->fromcode = NULL;
+ goto out;
+ }
+
+ /* Strip unrecognized characters and ensure that the code has two '/'
+ characters as per conversion code triplet specification. */
+ strip (conv_spec->fromcode, pfc.code);
+ strip (conv_spec->tocode, ptc.code);
+ ret = conv_spec;
+
+out:
+ free (pfc.code);
+ free (ptc.code);
+
+ return ret;
+}
+libc_hidden_def (__gconv_create_spec)
+
+
+void
+__gconv_destroy_spec (struct gconv_spec *conv_spec)
+{
+ free (conv_spec->fromcode);
+ free (conv_spec->tocode);
+ return;
+}
+libc_hidden_def (__gconv_destroy_spec)
#include <ctype.h>
#include <locale.h>
+#include <stdbool.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+#include "gconv_int.h"
-static void
+/* An iconv encoding is in the form of a triplet, with parts separated by
+ a '/' character. The first part is the standard name, the second part is
+ the character set, and the third part is the error handler. If the first
+ part is sufficient to identify both the standard and the character set
+ then the second part can be empty e.g. UTF-8//. If the first part is not
+ sufficient to identify both the standard and the character set then the
+ second part is required e.g. ISO-10646/UTF8/. If neither the first or
+ second parts are provided e.g. //, then the current locale is used.
+ The actual values used in the first and second parts are not entirely
+ relevant to the implementation. The values themselves are used in a hash
+ table to lookup modules and so the naming convention of the first two parts
+ is somewhat arbitrary and only helps locate the entries in the cache.
+ The third part is the error handler and is comprised of a ',' or '/'
+ separated list of suffixes. Currently, we support "TRANSLIT" for
+ transliteration and "IGNORE" for ignoring conversion errors due to
+ unrecognized input characters. */
+#define GCONV_TRIPLE_SEPARATOR "/"
+#define GCONV_SUFFIX_SEPARATOR ","
+#define GCONV_TRANSLIT_SUFFIX "TRANSLIT"
+#define GCONV_IGNORE_ERRORS_SUFFIX "IGNORE"
+
+
+/* This function copies in-order, characters from the source 's' that are
+ either alpha-numeric or one in one of these: "_-.,:/" - into the destination
+ 'wp' while dropping all other characters. In the process, it converts all
+ alphabetical characters to upper case. It then appends up to two '/'
+ characters so that the total number of '/'es in the destination is 2. */
+static inline void __attribute__ ((unused, always_inline))
strip (char *wp, const char *s)
{
int slash_count = 0;
};
+/* The specification of the conversion that needs to be performed. */
+struct gconv_spec
+{
+ char *fromcode;
+ char *tocode;
+ bool translit;
+ bool ignore;
+};
+
/* Flags for `gconv_open'. */
enum
{
})
-/* Return in *HANDLE decriptor for transformation from FROMSET to TOSET. */
-extern int __gconv_open (const char *toset, const char *fromset,
- __gconv_t *handle, int flags)
- attribute_hidden;
+/* Return in *HANDLE, a decriptor for the transformation. The function expects
+ the specification of the transformation in the structure pointed to by
+ CONV_SPEC. It only reads *CONV_SPEC and does not take ownership of it. */
+extern int __gconv_open (struct gconv_spec *conv_spec,
+ __gconv_t *handle, int flags);
+libc_hidden_proto (__gconv_open)
+
+/* This function accepts the charset names of the source and destination of the
+ conversion and populates *conv_spec with an equivalent conversion
+ specification that may later be used by __gconv_open. The charset names
+ might contain options in the form of suffixes that alter the conversion,
+ e.g. "ISO-10646/UTF-8/TRANSLIT". It processes the charset names, ignoring
+ and truncating any suffix options in fromcode, and processing and truncating
+ any suffix options in tocode. Supported suffix options ("TRANSLIT" or
+ "IGNORE") when found in tocode lead to the corresponding flag in *conv_spec
+ to be set to true. Unrecognized suffix options are silently discarded. If
+ the function succeeds, it returns conv_spec back to the caller. It returns
+ NULL upon failure. */
+extern struct gconv_spec *
+__gconv_create_spec (struct gconv_spec *conv_spec, const char *fromcode,
+ const char *tocode);
+libc_hidden_proto (__gconv_create_spec)
+
+/* This function frees all heap memory allocated by __gconv_create_spec. */
+extern void
+__gconv_destroy_spec (struct gconv_spec *conv_spec);
+libc_hidden_proto (__gconv_destroy_spec)
/* Free resources associated with transformation descriptor CD. */
extern int __gconv_close (__gconv_t cd)
int
-__gconv_open (const char *toset, const char *fromset, __gconv_t *handle,
+__gconv_open (struct gconv_spec *conv_spec, __gconv_t *handle,
int flags)
{
struct __gconv_step *steps;
size_t cnt = 0;
int res;
int conv_flags = 0;
- const char *errhand;
- const char *ignore;
bool translit = false;
+ char *tocode, *fromcode;
/* Find out whether any error handling method is specified. */
- errhand = strchr (toset, '/');
- if (errhand != NULL)
- errhand = strchr (errhand + 1, '/');
- if (__glibc_likely (errhand != NULL))
- {
- if (*++errhand == '\0')
- errhand = NULL;
- else
- {
- /* Make copy without the error handling description. */
- char *newtoset = (char *) alloca (errhand - toset + 1);
- char *tok;
- char *ptr = NULL /* Work around a bogus warning */;
-
- newtoset[errhand - toset] = '\0';
- toset = memcpy (newtoset, toset, errhand - toset);
+ translit = conv_spec->translit;
- /* Find the appropriate transliteration handlers. */
- tok = strdupa (errhand);
+ if (conv_spec->ignore)
+ conv_flags |= __GCONV_IGNORE_ERRORS;
- tok = __strtok_r (tok, ",", &ptr);
- while (tok != NULL)
- {
- if (__strcasecmp_l (tok, "TRANSLIT", _nl_C_locobj_ptr) == 0)
- translit = true;
- else if (__strcasecmp_l (tok, "IGNORE", _nl_C_locobj_ptr) == 0)
- /* Set the flag to ignore all errors. */
- conv_flags |= __GCONV_IGNORE_ERRORS;
-
- tok = __strtok_r (NULL, ",", &ptr);
- }
- }
- }
-
- /* For the source character set we ignore the error handler specification.
- XXX Is this really always the best? */
- ignore = strchr (fromset, '/');
- if (ignore != NULL && (ignore = strchr (ignore + 1, '/')) != NULL
- && *++ignore != '\0')
- {
- char *newfromset = (char *) alloca (ignore - fromset + 1);
-
- newfromset[ignore - fromset] = '\0';
- fromset = memcpy (newfromset, fromset, ignore - fromset);
- }
+ tocode = conv_spec->tocode;
+ fromcode = conv_spec->fromcode;
/* If the string is empty define this to mean the charset of the
currently selected locale. */
- if (strcmp (toset, "//") == 0)
+ if (strcmp (tocode, "//") == 0)
{
const char *codeset = _NL_CURRENT (LC_CTYPE, CODESET);
size_t len = strlen (codeset);
char *dest;
- toset = dest = (char *) alloca (len + 3);
+ tocode = dest = (char *) alloca (len + 3);
memcpy (__mempcpy (dest, codeset, len), "//", 3);
}
- if (strcmp (fromset, "//") == 0)
+ if (strcmp (fromcode, "//") == 0)
{
const char *codeset = _NL_CURRENT (LC_CTYPE, CODESET);
size_t len = strlen (codeset);
char *dest;
- fromset = dest = (char *) alloca (len + 3);
+ fromcode = dest = (char *) alloca (len + 3);
memcpy (__mempcpy (dest, codeset, len), "//", 3);
}
- res = __gconv_find_transform (toset, fromset, &steps, &nsteps, flags);
+ res = __gconv_find_transform (tocode, fromcode, &steps, &nsteps, flags);
if (res == __GCONV_OK)
{
/* Allocate room for handle. */
*handle = result;
return res;
}
+libc_hidden_def (__gconv_open)
int flags = step_data->__flags;
const unsigned char *inptr = *inptrp;
unsigned char *outptr = *outptrp;
- size_t n_convert = MIN (inend - inptr, outend - outptr) / 4;
int result;
- size_t cnt;
- for (cnt = 0; cnt < n_convert; ++cnt, inptr += 4)
+ for (; inptr + 4 <= inend && outptr + 4 <= outend; inptr += 4)
{
uint32_t inval;
int flags = step_data->__flags;
const unsigned char *inptr = *inptrp;
unsigned char *outptr = *outptrp;
- size_t n_convert = MIN (inend - inptr, outend - outptr) / 4;
int result;
- size_t cnt;
- for (cnt = 0; cnt < n_convert; ++cnt, inptr += 4)
+ for (; inptr + 4 <= inend && outptr + 4 <= outend; inptr += 4)
{
if (__glibc_unlikely (inptr[0] > 0x80))
{
int flags = step_data->__flags;
const unsigned char *inptr = *inptrp;
unsigned char *outptr = *outptrp;
- size_t n_convert = MIN (inend - inptr, outend - outptr) / 4;
int result;
- size_t cnt;
- for (cnt = 0; cnt < n_convert; ++cnt, inptr += 4)
+ for (; inptr + 4 <= inend && outptr + 4 <= outend; inptr += 4)
{
uint32_t inval;
int flags = step_data->__flags;
const unsigned char *inptr = *inptrp;
unsigned char *outptr = *outptrp;
- size_t n_convert = MIN (inend - inptr, outend - outptr) / 4;
int result;
- size_t cnt;
- for (cnt = 0; cnt < n_convert; ++cnt, inptr += 4)
+ for (; inptr + 4 <= inend && outptr + 4 <= outend; inptr += 4)
{
if (__glibc_unlikely (inptr[3] > 0x80))
{
iconv_t
iconv_open (const char *tocode, const char *fromcode)
{
- /* Normalize the name. We remove all characters beside alpha-numeric,
- '_', '-', '/', '.', and ':'. */
- size_t tocode_len = strlen (tocode) + 3;
- char *tocode_conv;
- bool tocode_usealloca = __libc_use_alloca (tocode_len);
- if (tocode_usealloca)
- tocode_conv = (char *) alloca (tocode_len);
- else
- {
- tocode_conv = (char *) malloc (tocode_len);
- if (tocode_conv == NULL)
- return (iconv_t) -1;
- }
- strip (tocode_conv, tocode);
- tocode = (tocode_conv[2] == '\0' && tocode[0] != '\0'
- ? upstr (tocode_conv, tocode) : tocode_conv);
+ __gconv_t cd;
+ struct gconv_spec conv_spec;
- size_t fromcode_len = strlen (fromcode) + 3;
- char *fromcode_conv;
- bool fromcode_usealloca = __libc_use_alloca (fromcode_len);
- if (fromcode_usealloca)
- fromcode_conv = (char *) alloca (fromcode_len);
- else
- {
- fromcode_conv = (char *) malloc (fromcode_len);
- if (fromcode_conv == NULL)
- {
- if (! tocode_usealloca)
- free (tocode_conv);
- return (iconv_t) -1;
- }
- }
- strip (fromcode_conv, fromcode);
- fromcode = (fromcode_conv[2] == '\0' && fromcode[0] != '\0'
- ? upstr (fromcode_conv, fromcode) : fromcode_conv);
+ if (__gconv_create_spec (&conv_spec, fromcode, tocode) == NULL)
+ return (iconv_t) -1;
- __gconv_t cd;
- int res = __gconv_open (tocode, fromcode, &cd, 0);
+ int res = __gconv_open (&conv_spec, &cd, 0);
- if (! fromcode_usealloca)
- free (fromcode_conv);
- if (! tocode_usealloca)
- free (tocode_conv);
+ __gconv_destroy_spec (&conv_spec);
if (__builtin_expect (res, __GCONV_OK) != __GCONV_OK)
{
#include <gconv_int.h>
#include "iconv_prog.h"
#include "iconvconfig.h"
+#include "gconv_charset.h"
/* Get libc version number. */
#include "../version.h"
{
int status = EXIT_SUCCESS;
int remaining;
- iconv_t cd;
- const char *orig_to_code;
+ __gconv_t cd;
struct charmap_t *from_charmap = NULL;
struct charmap_t *to_charmap = NULL;
exit (EXIT_SUCCESS);
}
- /* If we have to ignore errors make sure we use the appropriate name for
- the to-character-set. */
- orig_to_code = to_code;
- if (omit_invalid)
- {
- const char *errhand = strchrnul (to_code, '/');
- int nslash = 2;
- char *newp;
- char *cp;
-
- if (*errhand == '/')
- {
- --nslash;
- errhand = strchrnul (errhand + 1, '/');
-
- if (*errhand == '/')
- {
- --nslash;
- errhand = strchr (errhand, '\0');
- }
- }
-
- newp = (char *) alloca (errhand - to_code + nslash + 7 + 1);
- cp = mempcpy (newp, to_code, errhand - to_code);
- while (nslash-- > 0)
- *cp++ = '/';
- if (cp[-1] != '/')
- *cp++ = ',';
- memcpy (cp, "IGNORE", sizeof ("IGNORE"));
-
- to_code = newp;
- }
-
/* POSIX 1003.2b introduces a silly thing: the arguments to -t anf -f
can be file names of charmaps. In this case iconv will have to read
those charmaps and use them to do the conversion. But there are
file. */
from_charmap = charmap_read (from_code, /*0, 1*/1, 0, 0, 0);
- if (strchr (orig_to_code, '/') != NULL)
+ if (strchr (to_code, '/') != NULL)
/* The to-name might be a charmap file name. Try reading the
file. */
- to_charmap = charmap_read (orig_to_code, /*0, 1,*/1, 0, 0, 0);
+ to_charmap = charmap_read (to_code, /*0, 1,*/1, 0, 0, 0);
/* At this point we have to handle two cases. The first one is
argc, remaining, argv, output_file);
else
{
+ struct gconv_spec conv_spec;
+ int res;
+
+ if (__gconv_create_spec (&conv_spec, from_code, to_code) == NULL)
+ {
+ error (EXIT_FAILURE, errno,
+ _("failed to start conversion processing"));
+ exit (1);
+ }
+
+ if (omit_invalid)
+ conv_spec.ignore = true;
+
/* Let's see whether we have these coded character sets. */
- cd = iconv_open (to_code, from_code);
- if (cd == (iconv_t) -1)
+ res = __gconv_open (&conv_spec, &cd, 0);
+
+ __gconv_destroy_spec (&conv_spec);
+
+ if (res != __GCONV_OK)
{
if (errno == EINVAL)
{
const char *from_pretty =
(from_code[0] ? from_code : nl_langinfo (CODESET));
const char *to_pretty =
- (orig_to_code[0] ? orig_to_code : nl_langinfo (CODESET));
+ (to_code[0] ? to_code : nl_langinfo (CODESET));
if (from_wrong)
{
--- /dev/null
+/* Test iconv's TRANSLIT and IGNORE option handling
+
+ Copyright (C) 2020 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/>. */
+
+
+#include <iconv.h>
+#include <locale.h>
+#include <errno.h>
+#include <string.h>
+#include <support/support.h>
+#include <support/check.h>
+
+
+/* Run one iconv test. Arguments:
+ to: destination character set and options
+ from: source character set
+ input: input string to be converted
+ exp_in: expected number of bytes consumed
+ exp_ret: expected return value (error or number of irreversible conversions)
+ exp_out: expected output string
+ exp_err: expected value of `errno' after iconv returns. */
+static void
+test_iconv (const char *to, const char *from, char *input, size_t exp_in,
+ size_t exp_ret, const char *exp_out, int exp_err)
+{
+ iconv_t cd;
+ char outbuf[500];
+ size_t inlen, outlen;
+ char *inptr, *outptr;
+ size_t n;
+
+ cd = iconv_open (to, from);
+ TEST_VERIFY (cd != (iconv_t) -1);
+
+ inlen = strlen (input);
+ outlen = sizeof (outbuf);
+ inptr = input;
+ outptr = outbuf;
+
+ errno = 0;
+ n = iconv (cd, &inptr, &inlen, &outptr, &outlen);
+
+ TEST_COMPARE (n, exp_ret);
+ TEST_VERIFY (inptr == input + exp_in);
+ TEST_COMPARE (errno, exp_err);
+ TEST_COMPARE_BLOB (outbuf, outptr - outbuf, exp_out, strlen (exp_out));
+ TEST_VERIFY (iconv_close (cd) == 0);
+}
+
+
+/* We test option parsing by converting UTF-8 inputs to ASCII under various
+ option combinations. The UTF-8 inputs fall into three categories:
+ - ASCII-only,
+ - non-ASCII,
+ - non-ASCII with invalid UTF-8 characters. */
+
+/* 1. */
+char ascii[] = "Just some ASCII text";
+
+/* 2. Valid UTF-8 input and some corresponding expected outputs with various
+ options. The two non-ASCII characters below are accented alphabets:
+ an `a' then an `o'. */
+char utf8[] = "UTF-8 text with \u00E1 couple \u00F3f non-ASCII characters";
+char u2a[] = "UTF-8 text with ";
+char u2a_translit[] = "UTF-8 text with a couple of non-ASCII characters";
+char u2a_ignore[] = "UTF-8 text with couple f non-ASCII characters";
+
+/* 3. Invalid UTF-8 input and some corresponding expected outputs. \xff is
+ invalid UTF-8. It's followed by some valid but non-ASCII UTF-8. */
+char iutf8[] = "Invalid UTF-8 \xff\u27E6text\u27E7";
+char iu2a[] = "Invalid UTF-8 ";
+char iu2a_ignore[] = "Invalid UTF-8 text";
+char iu2a_both[] = "Invalid UTF-8 [|text|]";
+
+/* 4. Another invalid UTF-8 input and corresponding expected outputs. This time
+ the valid non-ASCII UTF-8 characters appear before the invalid \xff. */
+char jutf8[] = "Invalid \u27E6UTF-8\u27E7 \xfftext";
+char ju2a[] = "Invalid ";
+char ju2a_translit[] = "Invalid [|UTF-8|] ";
+char ju2a_ignore[] = "Invalid UTF-8 text";
+char ju2a_both[] = "Invalid [|UTF-8|] text";
+
+/* We also test option handling for character set names that have the form
+ "A/B". In this test, we test conversions "ISO-10646/UTF-8", and either
+ ISO-8859-1 or ASCII. */
+
+/* 5. Accented 'A' and 'a' characters in ISO-8859-1 and UTF-8, and an
+ equivalent ASCII transliteration. */
+char iso8859_1_a[] = {0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, /* Accented A's. */
+ 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, /* Accented a's. */
+ 0x00};
+char utf8_a[] = "\u00C0\u00C1\u00C2\u00C3\u00C4\u00C5"
+ "\u00E0\u00E1\u00E2\u00E3\u00E4\u00E5";
+char ascii_a[] = "AAAAAAaaaaaa";
+
+/* 6. An invalid ASCII string where [0] is invalid and [1] is '~'. */
+char iascii [] = {0x80, '~', '\0'};
+char empty[] = "";
+char ia2u_ignore[] = "~";
+
+static int
+do_test (void)
+{
+ xsetlocale (LC_ALL, "en_US.UTF-8");
+
+
+ /* 0. iconv_open should gracefully fail for invalid character sets. */
+
+ TEST_VERIFY (iconv_open ("INVALID", "UTF-8") == (iconv_t) -1);
+ TEST_VERIFY (iconv_open ("UTF-8", "INVALID") == (iconv_t) -1);
+ TEST_VERIFY (iconv_open ("INVALID", "INVALID") == (iconv_t) -1);
+
+
+ /* 1. ASCII-only UTF-8 input should convert to ASCII with no changes: */
+
+ test_iconv ("ASCII", "UTF-8", ascii, strlen (ascii), 0, ascii, 0);
+ test_iconv ("ASCII//", "UTF-8", ascii, strlen (ascii), 0, ascii, 0);
+ test_iconv ("ASCII//TRANSLIT", "UTF-8", ascii, strlen (ascii), 0, ascii, 0);
+ test_iconv ("ASCII//TRANSLIT//", "UTF-8", ascii, strlen (ascii), 0, ascii,
+ 0);
+ test_iconv ("ASCII//IGNORE", "UTF-8", ascii, strlen (ascii), 0, ascii, 0);
+ test_iconv ("ASCII//IGNORE//", "UTF-8", ascii, strlen (ascii), 0, ascii, 0);
+
+
+ /* 2. Valid UTF-8 input with non-ASCII characters: */
+
+ /* EILSEQ when converted to ASCII. */
+ test_iconv ("ASCII", "UTF-8", utf8, strlen (u2a), (size_t) -1, u2a, EILSEQ);
+
+ /* Converted without error with TRANSLIT enabled. */
+ test_iconv ("ASCII//TRANSLIT", "UTF-8", utf8, strlen (utf8), 2, u2a_translit,
+ 0);
+
+ /* EILSEQ with IGNORE enabled. Non-ASCII chars dropped from output. */
+ test_iconv ("ASCII//IGNORE", "UTF-8", utf8, strlen (utf8), (size_t) -1,
+ u2a_ignore, EILSEQ);
+
+ /* With TRANSLIT and IGNORE enabled, transliterated without error. We test
+ four combinations. */
+
+ test_iconv ("ASCII//TRANSLIT,IGNORE", "UTF-8", utf8, strlen (utf8), 2,
+ u2a_translit, 0);
+ test_iconv ("ASCII//TRANSLIT//IGNORE", "UTF-8", utf8, strlen (utf8), 2,
+ u2a_translit, 0);
+ test_iconv ("ASCII//IGNORE,TRANSLIT", "UTF-8", utf8, strlen (utf8), 2,
+ u2a_translit, 0);
+ /* Due to bug 19519, iconv was ignoring TRANSLIT for the following input. */
+ test_iconv ("ASCII//IGNORE//TRANSLIT", "UTF-8", utf8, strlen (utf8), 2,
+ u2a_translit, 0);
+
+ /* Misspellings of TRANSLIT and IGNORE are ignored, but conversion still
+ works while respecting any other correctly spelled options. */
+
+ test_iconv ("ASCII//T", "UTF-8", utf8, strlen (u2a), (size_t) -1, u2a,
+ EILSEQ);
+ test_iconv ("ASCII//TRANSLITERATE", "UTF-8", utf8, strlen (u2a), (size_t) -1,
+ u2a, EILSEQ);
+ test_iconv ("ASCII//I", "UTF-8", utf8, strlen (u2a), (size_t) -1, u2a,
+ EILSEQ);
+ test_iconv ("ASCII//IGNORED", "UTF-8", utf8, strlen (u2a), (size_t) -1, u2a,
+ EILSEQ);
+ test_iconv ("ASCII//TRANSLITERATE//IGNORED", "UTF-8", utf8, strlen (u2a),
+ (size_t) -1, u2a, EILSEQ);
+ test_iconv ("ASCII//IGNORED,TRANSLITERATE", "UTF-8", utf8, strlen (u2a),
+ (size_t) -1, u2a, EILSEQ);
+ test_iconv ("ASCII//T//I", "UTF-8", utf8, strlen (u2a), (size_t) -1, u2a,
+ EILSEQ);
+
+ test_iconv ("ASCII//TRANSLIT//I", "UTF-8", utf8, strlen (utf8), 2,
+ u2a_translit, 0);
+ /* Due to bug 19519, iconv was ignoring TRANSLIT for the following input. */
+ test_iconv ("ASCII//I//TRANSLIT", "UTF-8", utf8, strlen (utf8), 2,
+ u2a_translit, 0);
+ test_iconv ("ASCII//IGNORED,TRANSLIT", "UTF-8", utf8, strlen (utf8), 2,
+ u2a_translit, 0);
+ test_iconv ("ASCII//TRANSLIT,IGNORED", "UTF-8", utf8, strlen (utf8), 2,
+ u2a_translit, 0);
+
+ test_iconv ("ASCII//IGNORE,T", "UTF-8", utf8, strlen (utf8), (size_t) -1,
+ u2a_ignore, EILSEQ);
+ test_iconv ("ASCII//T,IGNORE", "UTF-8", utf8, strlen (utf8), (size_t) -1,
+ u2a_ignore, EILSEQ);
+ /* Due to bug 19519, iconv was ignoring IGNORE for the following input. */
+ test_iconv ("ASCII//TRANSLITERATE//IGNORE", "UTF-8", utf8, strlen (utf8),
+ (size_t) -1, u2a_ignore, EILSEQ);
+ test_iconv ("ASCII//IGNORE//TRANSLITERATE", "UTF-8", utf8, strlen (utf8),
+ (size_t) -1, u2a_ignore, EILSEQ);
+
+
+ /* 3. Invalid UTF-8 followed by some valid non-ASCII UTF-8 characters: */
+
+ /* EILSEQ; output is truncated at the first invalid UTF-8 character. */
+ test_iconv ("ASCII", "UTF-8", iutf8, strlen (iu2a), (size_t) -1, iu2a,
+ EILSEQ);
+
+ /* With TRANSLIT enabled: EILSEQ; output still truncated at the first invalid
+ UTF-8 character. */
+ test_iconv ("ASCII//TRANSLIT", "UTF-8", iutf8, strlen (iu2a), (size_t) -1,
+ iu2a, EILSEQ);
+
+ /* With IGNORE enabled: EILSEQ; output omits invalid UTF-8 characters and
+ valid UTF-8 non-ASCII characters. */
+ test_iconv ("ASCII//IGNORE", "UTF-8", iutf8, strlen (iutf8), (size_t) -1,
+ iu2a_ignore, EILSEQ);
+
+ /* With TRANSLIT and IGNORE enabled, output omits only invalid UTF-8
+ characters and transliterates valid non-ASCII UTF-8 characters. We test
+ four combinations. */
+
+ test_iconv ("ASCII//TRANSLIT,IGNORE", "UTF-8", iutf8, strlen (iutf8), 2,
+ iu2a_both, 0);
+ /* Due to bug 19519, iconv was ignoring IGNORE for the following input. */
+ test_iconv ("ASCII//TRANSLIT//IGNORE", "UTF-8", iutf8, strlen (iutf8), 2,
+ iu2a_both, 0);
+ test_iconv ("ASCII//IGNORE,TRANSLIT", "UTF-8", iutf8, strlen (iutf8), 2,
+ iu2a_both, 0);
+ /* Due to bug 19519, iconv was ignoring TRANSLIT for the following input. */
+ test_iconv ("ASCII//IGNORE//TRANSLIT", "UTF-8", iutf8, strlen (iutf8), 2,
+ iu2a_both, 0);
+
+
+ /* 4. Invalid UTF-8 with valid non-ASCII UTF-8 chars appearing first: */
+
+ /* EILSEQ; output is truncated at the first non-ASCII character. */
+ test_iconv ("ASCII", "UTF-8", jutf8, strlen (ju2a), (size_t) -1, ju2a,
+ EILSEQ);
+
+ /* With TRANSLIT enabled: EILSEQ; output now truncated at the first invalid
+ UTF-8 character. */
+ test_iconv ("ASCII//TRANSLIT", "UTF-8", jutf8, strlen (jutf8) - 5,
+ (size_t) -1, ju2a_translit, EILSEQ);
+ test_iconv ("ASCII//translit", "UTF-8", jutf8, strlen (jutf8) - 5,
+ (size_t) -1, ju2a_translit, EILSEQ);
+
+ /* With IGNORE enabled: EILSEQ; output omits invalid UTF-8 characters and
+ valid UTF-8 non-ASCII characters. */
+ test_iconv ("ASCII//IGNORE", "UTF-8", jutf8, strlen (jutf8), (size_t) -1,
+ ju2a_ignore, EILSEQ);
+ test_iconv ("ASCII//ignore", "UTF-8", jutf8, strlen (jutf8), (size_t) -1,
+ ju2a_ignore, EILSEQ);
+
+ /* With TRANSLIT and IGNORE enabled, output omits only invalid UTF-8
+ characters and transliterates valid non-ASCII UTF-8 characters. We test
+ several combinations. */
+
+ test_iconv ("ASCII//TRANSLIT,IGNORE", "UTF-8", jutf8, strlen (jutf8), 2,
+ ju2a_both, 0);
+ /* Due to bug 19519, iconv was ignoring IGNORE for the following input. */
+ test_iconv ("ASCII//TRANSLIT//IGNORE", "UTF-8", jutf8, strlen (jutf8), 2,
+ ju2a_both, 0);
+ test_iconv ("ASCII//IGNORE,TRANSLIT", "UTF-8", jutf8, strlen (jutf8), 2,
+ ju2a_both, 0);
+ /* Due to bug 19519, iconv was ignoring TRANSLIT for the following input. */
+ test_iconv ("ASCII//IGNORE//TRANSLIT", "UTF-8", jutf8, strlen (jutf8), 2,
+ ju2a_both, 0);
+ test_iconv ("ASCII//translit,ignore", "UTF-8", jutf8, strlen (jutf8), 2,
+ ju2a_both, 0);
+ /* Trailing whitespace and separators should be ignored. */
+ test_iconv ("ASCII//IGNORE,TRANSLIT ", "UTF-8", jutf8, strlen (jutf8), 2,
+ ju2a_both, 0);
+ test_iconv ("ASCII//IGNORE,TRANSLIT/", "UTF-8", jutf8, strlen (jutf8), 2,
+ ju2a_both, 0);
+ test_iconv ("ASCII//IGNORE,TRANSLIT//", "UTF-8", jutf8, strlen (jutf8), 2,
+ ju2a_both, 0);
+ test_iconv ("ASCII//IGNORE,TRANSLIT,", "UTF-8", jutf8, strlen (jutf8), 2,
+ ju2a_both, 0);
+ test_iconv ("ASCII//IGNORE,TRANSLIT,,", "UTF-8", jutf8, strlen (jutf8), 2,
+ ju2a_both, 0);
+ test_iconv ("ASCII//IGNORE,TRANSLIT /,", "UTF-8", jutf8, strlen (jutf8), 2,
+ ju2a_both, 0);
+
+ /* TRANSLIT or IGNORE suffixes in fromcode should be ignored. */
+ test_iconv ("ASCII", "UTF-8//TRANSLIT", jutf8, strlen (ju2a), (size_t) -1,
+ ju2a, EILSEQ);
+ test_iconv ("ASCII", "UTF-8//IGNORE", jutf8, strlen (ju2a), (size_t) -1,
+ ju2a, EILSEQ);
+ test_iconv ("ASCII", "UTF-8//TRANSLIT,IGNORE", jutf8, strlen (ju2a),
+ (size_t) -1, ju2a, EILSEQ);
+
+
+ /* 5. Charset names of the form "A/B/": */
+
+ /* ISO-8859-1 is converted to UTF-8 without needing transliteration. */
+ test_iconv ("ISO-10646/UTF-8", "ISO-8859-1", iso8859_1_a,
+ strlen (iso8859_1_a), 0, utf8_a, 0);
+ test_iconv ("ISO-10646/UTF-8/", "ISO-8859-1", iso8859_1_a,
+ strlen (iso8859_1_a), 0, utf8_a, 0);
+ test_iconv ("ISO-10646/UTF-8/IGNORE", "ISO-8859-1", iso8859_1_a,
+ strlen (iso8859_1_a), 0, utf8_a, 0);
+ test_iconv ("ISO-10646/UTF-8//IGNORE", "ISO-8859-1", iso8859_1_a,
+ strlen (iso8859_1_a), 0, utf8_a, 0);
+ test_iconv ("ISO-10646/UTF-8/TRANSLIT", "ISO-8859-1", iso8859_1_a,
+ strlen (iso8859_1_a), 0, utf8_a, 0);
+ test_iconv ("ISO-10646/UTF-8//TRANSLIT", "ISO-8859-1", iso8859_1_a,
+ strlen (iso8859_1_a), 0, utf8_a, 0);
+ test_iconv ("ISO-10646/UTF-8//TRANSLIT/IGNORE", "ISO-8859-1", iso8859_1_a,
+ strlen (iso8859_1_a), 0, utf8_a, 0);
+ test_iconv ("ISO-10646/UTF-8//TRANSLIT//IGNORE", "ISO-8859-1", iso8859_1_a,
+ strlen (iso8859_1_a), 0, utf8_a, 0);
+ test_iconv ("ISO-10646/UTF-8/TRANSLIT,IGNORE", "ISO-8859-1", iso8859_1_a,
+ strlen (iso8859_1_a), 0, utf8_a, 0);
+
+ /* UTF-8 with accented A's is converted to ASCII with transliteration. */
+ test_iconv ("ASCII", "ISO-10646/UTF-8", utf8_a,
+ 0, (size_t) -1, empty, EILSEQ);
+ test_iconv ("ASCII//IGNORE", "ISO-10646/UTF-8", utf8_a,
+ strlen (utf8_a), (size_t) -1, empty, EILSEQ);
+ test_iconv ("ASCII//TRANSLIT", "ISO-10646/UTF-8", utf8_a,
+ strlen (utf8_a), 12, ascii_a, 0);
+
+ /* Invalid ASCII is converted to UTF-8 only with IGNORE. */
+ test_iconv ("ISO-10646/UTF-8", "ASCII", iascii, strlen (empty), (size_t) -1,
+ empty, EILSEQ);
+ test_iconv ("ISO-10646/UTF-8/TRANSLIT", "ASCII", iascii, strlen (empty),
+ (size_t) -1, empty, EILSEQ);
+ test_iconv ("ISO-10646/UTF-8/IGNORE", "ASCII", iascii, strlen (iascii),
+ (size_t) -1, ia2u_ignore, EILSEQ);
+ test_iconv ("ISO-10646/UTF-8/TRANSLIT,IGNORE", "ASCII", iascii,
+ strlen (iascii), (size_t) -1, ia2u_ignore, EILSEQ);
+ /* Due to bug 19519, iconv was ignoring IGNORE for the following three
+ inputs: */
+ test_iconv ("ISO-10646/UTF-8/TRANSLIT/IGNORE", "ASCII", iascii,
+ strlen (iascii), (size_t) -1, ia2u_ignore, EILSEQ);
+ test_iconv ("ISO-10646/UTF-8//TRANSLIT,IGNORE", "ASCII", iascii,
+ strlen (iascii), (size_t) -1, ia2u_ignore, EILSEQ);
+ test_iconv ("ISO-10646/UTF-8//TRANSLIT//IGNORE", "ASCII", iascii,
+ strlen (iascii), (size_t) -1, ia2u_ignore, EILSEQ);
+
+ return 0;
+}
+
+#include <support/test-driver.c>
--- /dev/null
+/* Test iconv behavior on UCS4 conversions with //IGNORE.
+ Copyright (C) 2020 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/>. */
+
+/* Derived from BZ #26923 */
+#include <errno.h>
+#include <iconv.h>
+#include <stdio.h>
+#include <support/check.h>
+
+static int
+do_test (void)
+{
+ iconv_t cd = iconv_open ("UTF-8//IGNORE", "ISO-10646/UCS4/");
+ TEST_VERIFY_EXIT (cd != (iconv_t) -1);
+
+ /*
+ * Convert sequence beginning with an irreversible character into buffer that
+ * is too small.
+ */
+ char input[12] = "\xe1\x80\xa1" "AAAAAAAAA";
+ char *inptr = input;
+ size_t insize = sizeof (input);
+ char output[6];
+ char *outptr = output;
+ size_t outsize = sizeof (output);
+
+ TEST_VERIFY (iconv (cd, &inptr, &insize, &outptr, &outsize) == -1);
+ TEST_VERIFY (errno == E2BIG);
+
+ TEST_VERIFY_EXIT (iconv_close (cd) != -1);
+
+ return 0;
+}
+
+#include <support/test-driver.c>
--- /dev/null
+#!/bin/bash
+# Test for some known iconv(1) hangs from bug 19519, and miscellaneous
+# iconv(1) program error conditions.
+# Copyright (C) 2020 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/>.
+
+codir=$1
+test_wrapper_env="$2"
+run_program_env="$3"
+
+# We have to have some directories in the library path.
+LIBPATH=$codir:$codir/iconvdata
+
+# How the start the iconv(1) program. $from is not defined/expanded yet.
+ICONV='
+$codir/elf/ld.so --library-path $LIBPATH --inhibit-rpath ${from}.so
+$codir/iconv/iconv_prog
+'
+ICONV="$test_wrapper_env $run_program_env $ICONV"
+
+# List of known hangs;
+# Gathered by running an exhaustive 2 byte input search against glibc-2.28
+hangarray=(
+"\x00\x23;-c;ANSI_X3.110;UTF-8//TRANSLIT//IGNORE"
+"\x00\xa1;-c;ARMSCII-8;UTF-8//TRANSLIT//IGNORE"
+"\x00\xa1;-c;ASMO_449;UTF-8//TRANSLIT//IGNORE"
+"\x00\x81;-c;BIG5;UTF-8//TRANSLIT//IGNORE"
+"\x00\xff;-c;BIG5HKSCS;UTF-8//TRANSLIT//IGNORE"
+"\x00\xff;-c;BRF;UTF-8//TRANSLIT//IGNORE"
+"\x00\xff;-c;BS_4730;UTF-8//TRANSLIT//IGNORE"
+"\x00\x81;-c;CP1250;UTF-8//TRANSLIT//IGNORE"
+"\x00\x98;-c;CP1251;UTF-8//TRANSLIT//IGNORE"
+"\x00\x81;-c;CP1252;UTF-8//TRANSLIT//IGNORE"
+"\x00\x81;-c;CP1253;UTF-8//TRANSLIT//IGNORE"
+"\x00\x81;-c;CP1254;UTF-8//TRANSLIT//IGNORE"
+"\x00\x81;-c;CP1255;UTF-8//TRANSLIT//IGNORE"
+"\x00\x81;-c;CP1257;UTF-8//TRANSLIT//IGNORE"
+"\x00\x81;-c;CP1258;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;CP932;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;CSA_Z243.4-1985-1;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;CSA_Z243.4-1985-2;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;DEC-MCS;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;DIN_66003;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;DS_2089;UTF-8//TRANSLIT//IGNORE"
+"\x00\x41;-c;EBCDIC-AT-DE;UTF-8//TRANSLIT//IGNORE"
+"\x00\x41;-c;EBCDIC-AT-DE-A;UTF-8//TRANSLIT//IGNORE"
+"\x00\x41;-c;EBCDIC-CA-FR;UTF-8//TRANSLIT//IGNORE"
+"\x00\x41;-c;EBCDIC-DK-NO;UTF-8//TRANSLIT//IGNORE"
+"\x00\x41;-c;EBCDIC-DK-NO-A;UTF-8//TRANSLIT//IGNORE"
+"\x00\x41;-c;EBCDIC-ES;UTF-8//TRANSLIT//IGNORE"
+"\x00\x41;-c;EBCDIC-ES-A;UTF-8//TRANSLIT//IGNORE"
+"\x00\x41;-c;EBCDIC-ES-S;UTF-8//TRANSLIT//IGNORE"
+"\x00\x41;-c;EBCDIC-FI-SE;UTF-8//TRANSLIT//IGNORE"
+"\x00\x41;-c;EBCDIC-FI-SE-A;UTF-8//TRANSLIT//IGNORE"
+"\x00\x41;-c;EBCDIC-FR;UTF-8//TRANSLIT//IGNORE"
+"\x00\x41;-c;EBCDIC-IS-FRISS;UTF-8//TRANSLIT//IGNORE"
+"\x00\x41;-c;EBCDIC-IT;UTF-8//TRANSLIT//IGNORE"
+"\x00\x41;-c;EBCDIC-PT;UTF-8//TRANSLIT//IGNORE"
+"\x00\x41;-c;EBCDIC-UK;UTF-8//TRANSLIT//IGNORE"
+"\x00\x41;-c;EBCDIC-US;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;ES;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;ES2;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;EUC-CN;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;EUC-JISX0213;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;EUC-JP;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;EUC-JP-MS;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;EUC-KR;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;EUC-TW;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;GB18030;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;GB_1988-80;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;GBK;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;GOST_19768-74;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;GREEK7;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;GREEK7-OLD;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;GREEK-CCITT;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;HP-GREEK8;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;HP-ROMAN8;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;HP-ROMAN9;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;HP-THAI8;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;HP-TURKISH8;UTF-8//TRANSLIT//IGNORE"
+"\x00\x41;-c;IBM038;UTF-8//TRANSLIT//IGNORE"
+"\x00\x80;-c;IBM1004;UTF-8//TRANSLIT//IGNORE"
+"\x00\xff;-c;IBM1008;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;IBM1046;UTF-8//TRANSLIT//IGNORE"
+"\x00\x51;-c;IBM1132;UTF-8//TRANSLIT//IGNORE"
+"\x00\xa0;-c;IBM1133;UTF-8//TRANSLIT//IGNORE"
+"\x00\xce;-c;IBM1137;UTF-8//TRANSLIT//IGNORE"
+"\x00\x80;-c;IBM1161;UTF-8//TRANSLIT//IGNORE"
+"\x00\xdb;-c;IBM1162;UTF-8//TRANSLIT//IGNORE"
+"\x00\x70;-c;IBM12712;UTF-8//TRANSLIT//IGNORE"
+"\x00\x0f;-c;IBM1364;UTF-8"
+"\x0e\x0e;-c;IBM1364;UTF-8"
+"\x00\x0f;-c;IBM1371;UTF-8"
+"\x0e\x0e;-c;IBM1371;UTF-8"
+"\x00\x0f;-c;IBM1388;UTF-8"
+"\x0e\x0e;-c;IBM1388;UTF-8"
+"\x00\x0f;-c;IBM1390;UTF-8"
+"\x0e\x0e;-c;IBM1390;UTF-8"
+"\x00\x0f;-c;IBM1399;UTF-8"
+"\x0e\x0e;-c;IBM1399;UTF-8"
+"\x00\x53;-c;IBM16804;UTF-8//TRANSLIT//IGNORE"
+"\x00\x41;-c;IBM274;UTF-8//TRANSLIT//IGNORE"
+"\x00\x41;-c;IBM275;UTF-8//TRANSLIT//IGNORE"
+"\x00\x41;-c;IBM281;UTF-8//TRANSLIT//IGNORE"
+"\x00\x57;-c;IBM290;UTF-8//TRANSLIT//IGNORE"
+"\x00\x45;-c;IBM420;UTF-8//TRANSLIT//IGNORE"
+"\x00\x68;-c;IBM423;UTF-8//TRANSLIT//IGNORE"
+"\x00\x70;-c;IBM424;UTF-8//TRANSLIT//IGNORE"
+"\x00\x53;-c;IBM4517;UTF-8//TRANSLIT//IGNORE"
+"\x00\x53;-c;IBM4899;UTF-8//TRANSLIT//IGNORE"
+"\x00\xa5;-c;IBM4909;UTF-8//TRANSLIT//IGNORE"
+"\x00\xdc;-c;IBM4971;UTF-8//TRANSLIT//IGNORE"
+"\x00\x41;-c;IBM803;UTF-8//TRANSLIT//IGNORE"
+"\x00\x91;-c;IBM851;UTF-8//TRANSLIT//IGNORE"
+"\x00\x9b;-c;IBM856;UTF-8//TRANSLIT//IGNORE"
+"\x00\xd5;-c;IBM857;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;IBM864;UTF-8//TRANSLIT//IGNORE"
+"\x00\x94;-c;IBM868;UTF-8//TRANSLIT//IGNORE"
+"\x00\x94;-c;IBM869;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;IBM874;UTF-8//TRANSLIT//IGNORE"
+"\x00\x6a;-c;IBM875;UTF-8//TRANSLIT//IGNORE"
+"\x00\x41;-c;IBM880;UTF-8//TRANSLIT//IGNORE"
+"\x00\x80;-c;IBM891;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;IBM903;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;IBM904;UTF-8//TRANSLIT//IGNORE"
+"\x00\x41;-c;IBM905;UTF-8//TRANSLIT//IGNORE"
+"\x00\x80;-c;IBM9066;UTF-8//TRANSLIT//IGNORE"
+"\x00\x48;-c;IBM918;UTF-8//TRANSLIT//IGNORE"
+"\x00\x57;-c;IBM930;UTF-8//TRANSLIT//IGNORE"
+"\x00\x80;-c;IBM932;UTF-8//TRANSLIT//IGNORE"
+"\x00\x41;-c;IBM933;UTF-8//TRANSLIT//IGNORE"
+"\x00\x41;-c;IBM935;UTF-8//TRANSLIT//IGNORE"
+"\x00\x41;-c;IBM937;UTF-8//TRANSLIT//IGNORE"
+"\x00\x41;-c;IBM939;UTF-8//TRANSLIT//IGNORE"
+"\x00\x80;-c;IBM943;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;INIS;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;INIS-8;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;INIS-CYRILLIC;UTF-8//TRANSLIT//IGNORE"
+"\x00\xec;-c;ISIRI-3342;UTF-8//TRANSLIT//IGNORE"
+"\x00\xec;-c;ISO_10367-BOX;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;ISO-2022-CN;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;ISO-2022-CN-EXT;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;ISO-2022-JP;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;ISO-2022-JP-2;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;ISO-2022-JP-3;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;ISO-2022-KR;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;ISO_2033;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;ISO_5427;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;ISO_5427-EXT;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;ISO_5428;UTF-8//TRANSLIT//IGNORE"
+"\x00\xa4;-c;ISO_6937;UTF-8//TRANSLIT//IGNORE"
+"\x00\xa0;-c;ISO_6937-2;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;ISO-8859-11;UTF-8//TRANSLIT//IGNORE"
+"\x00\xa5;-c;ISO-8859-3;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;ISO-8859-6;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;ISO-8859-7;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;ISO-8859-8;UTF-8//TRANSLIT//IGNORE"
+"\x00\x80;-c;ISO-IR-197;UTF-8//TRANSLIT//IGNORE"
+"\x00\x80;-c;ISO-IR-209;UTF-8//TRANSLIT//IGNORE"
+"\x00\x80;-c;IT;UTF-8//TRANSLIT//IGNORE"
+"\x00\x80;-c;JIS_C6220-1969-RO;UTF-8//TRANSLIT//IGNORE"
+"\x00\x80;-c;JIS_C6229-1984-B;UTF-8//TRANSLIT//IGNORE"
+"\x00\x80;-c;JOHAB;UTF-8//TRANSLIT//IGNORE"
+"\x00\x80;-c;JUS_I.B1.002;UTF-8//TRANSLIT//IGNORE"
+"\x00\x80;-c;KOI-8;UTF-8//TRANSLIT//IGNORE"
+"\x00\x88;-c;KOI8-T;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;KSC5636;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;LATIN-GREEK;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;LATIN-GREEK-1;UTF-8//TRANSLIT//IGNORE"
+"\x00\xf6;-c;MAC-IS;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;MSZ_7795.3;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;NATS-DANO;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;NATS-SEFI;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;NC_NC00-10;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;NF_Z_62-010;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;NF_Z_62-010_1973;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;NS_4551-1;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;NS_4551-2;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;PT;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;PT2;UTF-8//TRANSLIT//IGNORE"
+"\x00\x98;-c;RK1048;UTF-8//TRANSLIT//IGNORE"
+"\x00\x98;-c;SEN_850200_B;UTF-8//TRANSLIT//IGNORE"
+"\x00\x98;-c;SEN_850200_C;UTF-8//TRANSLIT//IGNORE"
+"\x00\x80;-c;Shift_JISX0213;UTF-8//TRANSLIT//IGNORE"
+"\x00\x80;-c;SJIS;UTF-8//TRANSLIT//IGNORE"
+"\x00\x23;-c;T.61-8BIT;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;TIS-620;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;TSCII;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;UHC;UTF-8//TRANSLIT//IGNORE"
+"\x00\xd8;-c;UNICODE;UTF-8//TRANSLIT//IGNORE"
+"\x00\xdc;-c;UTF-16;UTF-8//TRANSLIT//IGNORE"
+"\xdc\x00;-c;UTF-16BE;UTF-8//TRANSLIT//IGNORE"
+"\x00\xdc;-c;UTF-16LE;UTF-8//TRANSLIT//IGNORE"
+"\xff\xff;-c;UTF-7;UTF-8//TRANSLIT//IGNORE"
+"\x00\x81;-c;WIN-SAMI-2;UTF-8//TRANSLIT//IGNORE"
+)
+
+# List of option combinations that *should* lead to an error
+errorarray=(
+# Converting from/to invalid character sets should cause error
+"\x00\x00;;INVALID;INVALID"
+"\x00\x00;;INVALID;UTF-8"
+"\x00\x00;;UTF-8;INVALID"
+)
+
+# Requires $twobyte input, $c flag, $from, and $to to be set; sets $ret
+execute_test ()
+{
+ eval PROG=\"$ICONV\"
+ echo -en "$twobyte" \
+ | timeout -k 4 3 $PROG $c -f $from -t "$to" &>/dev/null
+ ret=$?
+}
+
+check_hangtest_result ()
+{
+ if [ "$ret" -eq "124" ] || [ "$ret" -eq "137" ]; then # timeout/hang
+ result="HANG"
+ else
+ if [ "$ret" -eq "139" ]; then # segfault
+ result="SEGFAULT"
+ else
+ if [ "$ret" -gt "127" ]; then # unexpected error
+ result="UNEXPECTED"
+ else
+ result="OK"
+ fi
+ fi
+ fi
+
+ echo -n "$result: from: \"$from\", to: \"$to\","
+ echo " input \"$twobyte\", flags \"$c\""
+
+ if [ "$result" != "OK" ]; then
+ exit 1
+ fi
+}
+
+for hangcommand in "${hangarray[@]}"; do
+ twobyte="$(echo "$hangcommand" | cut -d";" -f 1)"
+ c="$(echo "$hangcommand" | cut -d";" -f 2)"
+ from="$(echo "$hangcommand" | cut -d";" -f 3)"
+ to="$(echo "$hangcommand" | cut -d";" -f 4)"
+ execute_test
+ check_hangtest_result
+done
+
+check_errtest_result ()
+{
+ if [ "$ret" -eq "1" ]; then # we errored out as expected
+ result="PASS"
+ else
+ result="FAIL"
+ fi
+ echo -n "$result: from: \"$from\", to: \"$to\","
+ echo " input \"$twobyte\", flags \"$c\", return code $ret"
+
+ if [ "$result" != "PASS" ]; then
+ exit 1
+ fi
+}
+
+for errorcommand in "${errorarray[@]}"; do
+ twobyte="$(echo "$errorcommand" | cut -d";" -f 1)"
+ c="$(echo "$errorcommand" | cut -d";" -f 2)"
+ from="$(echo "$errorcommand" | cut -d";" -f 3)"
+ to="$(echo "$errorcommand" | cut -d";" -f 4)"
+ execute_test
+ check_errtest_result
+done
ifeq (yes,$(build-shared))
tests = bug-iconv1 bug-iconv2 tst-loading tst-e2big tst-iconv4 bug-iconv4 \
tst-iconv6 bug-iconv5 bug-iconv6 tst-iconv7 bug-iconv8 bug-iconv9 \
- bug-iconv10 bug-iconv11 bug-iconv12
+ bug-iconv10 bug-iconv11 bug-iconv12 bug-iconv13 bug-iconv14
ifeq ($(have-thread-library),yes)
tests += bug-iconv3
endif
$(addprefix $(objpfx),$(modules.so))
$(objpfx)bug-iconv12.out: $(objpfx)gconv-modules \
$(addprefix $(objpfx),$(modules.so))
+$(objpfx)bug-iconv14.out: $(objpfx)gconv-modules \
+ $(addprefix $(objpfx),$(modules.so))
$(objpfx)iconv-test.out: run-iconv-test.sh $(objpfx)gconv-modules \
$(addprefix $(objpfx),$(modules.so)) \
--- /dev/null
+/* bug 24973: Test EUC-KR module
+ Copyright (C) 2020 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/>. */
+
+#include <errno.h>
+#include <iconv.h>
+#include <stdio.h>
+#include <support/check.h>
+
+static int
+do_test (void)
+{
+ iconv_t cd = iconv_open ("UTF-8//IGNORE", "EUC-KR");
+ TEST_VERIFY_EXIT (cd != (iconv_t) -1);
+
+ /* 0xfe (->0x7e : row 94) and 0xc9 (->0x49 : row 41) are user-defined
+ areas, which are not allowed and should be skipped over due to
+ //IGNORE. The trailing 0xfe also is an incomplete sequence, which
+ should be checked first. */
+ char input[4] = { '\xc9', '\xa1', '\0', '\xfe' };
+ char *inptr = input;
+ size_t insize = sizeof (input);
+ char output[4];
+ char *outptr = output;
+ size_t outsize = sizeof (output);
+
+ /* This used to crash due to buffer overrun. */
+ TEST_VERIFY (iconv (cd, &inptr, &insize, &outptr, &outsize) == (size_t) -1);
+ TEST_VERIFY (errno == EINVAL);
+ /* The conversion should produce one character, the converted null
+ character. */
+ TEST_VERIFY (sizeof (output) - outsize == 1);
+
+ TEST_VERIFY_EXIT (iconv_close (cd) != -1);
+
+ return 0;
+}
+
+#include <support/test-driver.c>
--- /dev/null
+/* Assertion in ISO-2022-JP-3 due to two-character sequence (bug 27256).
+ Copyright (C) 2021 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/>. */
+
+#include <iconv.h>
+#include <string.h>
+#include <errno.h>
+#include <support/check.h>
+
+/* Use an escape sequence to return to the initial state. */
+static void
+with_escape_sequence (void)
+{
+ iconv_t c = iconv_open ("UTF-8", "ISO-2022-JP-3");
+ TEST_VERIFY_EXIT (c != (iconv_t) -1);
+
+ char in[] = "\e$(O+D\e(B";
+ char *inbuf = in;
+ size_t inleft = strlen (in);
+ char out[3]; /* Space for one output character. */
+ char *outbuf;
+ size_t outleft;
+
+ outbuf = out;
+ outleft = sizeof (out);
+ TEST_COMPARE (iconv (c, &inbuf, &inleft, &outbuf, &outleft), (size_t) -1);
+ TEST_COMPARE (errno, E2BIG);
+ TEST_COMPARE (inleft, 3);
+ TEST_COMPARE (inbuf - in, strlen (in) - 3);
+ TEST_COMPARE (outleft, sizeof (out) - 2);
+ TEST_COMPARE (outbuf - out, 2);
+ TEST_COMPARE (out[0] & 0xff, 0xc3);
+ TEST_COMPARE (out[1] & 0xff, 0xa6);
+
+ /* Return to the initial shift state, producing the pending
+ character. */
+ outbuf = out;
+ outleft = sizeof (out);
+ TEST_COMPARE (iconv (c, &inbuf, &inleft, &outbuf, &outleft), 0);
+ TEST_COMPARE (inleft, 0);
+ TEST_COMPARE (inbuf - in, strlen (in));
+ TEST_COMPARE (outleft, sizeof (out) - 2);
+ TEST_COMPARE (outbuf - out, 2);
+ TEST_COMPARE (out[0] & 0xff, 0xcc);
+ TEST_COMPARE (out[1] & 0xff, 0x80);
+
+ /* Nothing should be flushed the second time. */
+ outbuf = out;
+ outleft = sizeof (out);
+ TEST_COMPARE (iconv (c, NULL, 0, &outbuf, &outleft), 0);
+ TEST_COMPARE (outleft, sizeof (out));
+ TEST_COMPARE (outbuf - out, 0);
+ TEST_COMPARE (out[0] & 0xff, 0xcc);
+ TEST_COMPARE (out[1] & 0xff, 0x80);
+
+ TEST_COMPARE (iconv_close (c), 0);
+}
+
+/* Use an explicit flush to return to the initial state. */
+static void
+with_flush (void)
+{
+ iconv_t c = iconv_open ("UTF-8", "ISO-2022-JP-3");
+ TEST_VERIFY_EXIT (c != (iconv_t) -1);
+
+ char in[] = "\e$(O+D";
+ char *inbuf = in;
+ size_t inleft = strlen (in);
+ char out[3]; /* Space for one output character. */
+ char *outbuf;
+ size_t outleft;
+
+ outbuf = out;
+ outleft = sizeof (out);
+ TEST_COMPARE (iconv (c, &inbuf, &inleft, &outbuf, &outleft), (size_t) -1);
+ TEST_COMPARE (errno, E2BIG);
+ TEST_COMPARE (inleft, 0);
+ TEST_COMPARE (inbuf - in, strlen (in));
+ TEST_COMPARE (outleft, sizeof (out) - 2);
+ TEST_COMPARE (outbuf - out, 2);
+ TEST_COMPARE (out[0] & 0xff, 0xc3);
+ TEST_COMPARE (out[1] & 0xff, 0xa6);
+
+ /* Flush the pending character. */
+ outbuf = out;
+ outleft = sizeof (out);
+ TEST_COMPARE (iconv (c, NULL, 0, &outbuf, &outleft), 0);
+ TEST_COMPARE (outleft, sizeof (out) - 2);
+ TEST_COMPARE (outbuf - out, 2);
+ TEST_COMPARE (out[0] & 0xff, 0xcc);
+ TEST_COMPARE (out[1] & 0xff, 0x80);
+
+ /* Nothing should be flushed the second time. */
+ outbuf = out;
+ outleft = sizeof (out);
+ TEST_COMPARE (iconv (c, NULL, 0, &outbuf, &outleft), 0);
+ TEST_COMPARE (outleft, sizeof (out));
+ TEST_COMPARE (outbuf - out, 0);
+ TEST_COMPARE (out[0] & 0xff, 0xcc);
+ TEST_COMPARE (out[1] & 0xff, 0x80);
+
+ TEST_COMPARE (iconv_close (c), 0);
+}
+
+static int
+do_test (void)
+{
+ with_escape_sequence ();
+ with_flush ();
+ return 0;
+}
+
+#include <support/test-driver.c>
\
if (ch <= 0x9f) \
++inptr; \
- /* 0xfe(->0x7e : row 94) and 0xc9(->0x59 : row 41) are \
- user-defined areas. */ \
- else if (__builtin_expect (ch == 0xa0, 0) \
- || __builtin_expect (ch > 0xfe, 0) \
- || __builtin_expect (ch == 0xc9, 0)) \
+ else if (__glibc_unlikely (ch == 0xa0)) \
{ \
/* This is illegal. */ \
STANDARD_FROM_LOOP_ERR_HANDLER (1); \
\
if (__builtin_expect (ch, 0) == SO) \
{ \
- /* Shift OUT, change to DBCS converter. */ \
- if (curcs == db) \
- { \
- result = __GCONV_ILLEGAL_INPUT; \
- break; \
- } \
+ /* Shift OUT, change to DBCS converter (redundant escape okay). */ \
curcs = db; \
++inptr; \
continue; \
} \
if (__builtin_expect (ch, 0) == SI) \
{ \
- /* Shift IN, change to SBCS converter. */ \
- if (curcs == sb) \
- { \
- result = __GCONV_ILLEGAL_INPUT; \
- break; \
- } \
+ /* Shift IN, change to SBCS converter (redundant escape okay). */ \
curcs = sb; \
++inptr; \
continue; \
CURRENT_SEL_MASK = 7 << 3
};
-/* During UCS-4 to ISO-2022-JP-3 conversion, the COUNT element of the state
- also contains the last two bytes to be output, shifted by 6 bits, and a
- one-bit indicator whether they must be preceded by the shift sequence,
- in bit 22. */
+/* During UCS-4 to ISO-2022-JP-3 conversion, the COUNT element of the
+ state also contains the last two bytes to be output, shifted by 6
+ bits, and a one-bit indicator whether they must be preceded by the
+ shift sequence, in bit 22. During ISO-2022-JP-3 to UCS-4
+ conversion, COUNT may also contain a non-zero pending wide
+ character, shifted by six bits. This happens for certain inputs in
+ JISX0213_1_2004_set and JISX0213_2_set if the second wide character
+ in a combining sequence cannot be written because the buffer is
+ full. */
/* Since this is a stateful encoding we have to provide code which resets
the output state to the initial state. This has to be done during the
flushing. */
#define EMIT_SHIFT_TO_INIT \
- if ((data->__statep->__count & ~7) != ASCII_set) \
+ if (data->__statep->__count != ASCII_set) \
{ \
if (FROM_DIRECTION) \
{ \
- /* It's easy, we don't have to emit anything, we just reset the \
- state for the input. */ \
- data->__statep->__count &= 7; \
- data->__statep->__count |= ASCII_set; \
+ if (__glibc_likely (outbuf + 4 <= outend)) \
+ { \
+ /* Write out the last character. */ \
+ *((uint32_t *) outbuf) = data->__statep->__count >> 6; \
+ outbuf += sizeof (uint32_t); \
+ data->__statep->__count = ASCII_set; \
+ } \
+ else \
+ /* We don't have enough room in the output buffer. */ \
+ status = __GCONV_FULL_OUTPUT; \
} \
else \
{ \
#define LOOPFCT FROM_LOOP
#define BODY \
{ \
- uint32_t ch = *inptr; \
+ uint32_t ch; \
+ \
+ /* Output any pending character. */ \
+ ch = set >> 6; \
+ if (__glibc_unlikely (ch != 0)) \
+ { \
+ put32 (outptr, ch); \
+ outptr += 4; \
+ /* Remove the pending character, but preserve state bits. */ \
+ set &= (1 << 6) - 1; \
+ continue; \
+ } \
+ \
+ /* Otherwise read the next input byte. */ \
+ ch = *inptr; \
\
/* Recognize escape sequences. */ \
if (__glibc_unlikely (ch == ESC)) \
uint32_t u1 = __jisx0213_to_ucs_combining[ch - 1][0]; \
uint32_t u2 = __jisx0213_to_ucs_combining[ch - 1][1]; \
\
+ inptr += 2; \
+ \
+ put32 (outptr, u1); \
+ outptr += 4; \
+ \
/* See whether we have room for two characters. */ \
- if (outptr + 8 <= outend) \
+ if (outptr + 4 <= outend) \
{ \
- inptr += 2; \
- put32 (outptr, u1); \
- outptr += 4; \
put32 (outptr, u2); \
outptr += 4; \
continue; \
} \
- else \
- { \
- result = __GCONV_FULL_OUTPUT; \
- break; \
- } \
+ \
+ /* Otherwise store only the first character now, and \
+ put the second one into the queue. */ \
+ set |= u2 << 6; \
+ /* Tell the caller why we terminate the loop. */ \
+ result = __GCONV_FULL_OUTPUT; \
+ break; \
} \
\
inptr += 2; \
unsigned char ch2;
int idx;
+ if (avail < 2)
+ return 0;
+
/* row 94(0x7e) and row 41(0x49) are user-defined area in KS C 5601 */
if (ch < offset || (ch - offset) <= 0x20 || (ch - offset) >= 0x7e
|| (ch - offset) == 0x49)
return __UNKNOWN_10646_CHAR;
- if (avail < 2)
- return 0;
-
ch2 = (*s)[1];
if (ch2 < offset || (ch2 - offset) <= 0x20 || (ch2 - offset) >= 0x7f)
return __UNKNOWN_10646_CHAR;
# ifndef _ISOMAC
extern int __prctl (int __option, ...);
+libc_hidden_proto (__prctl)
# endif /* !_ISOMAC */
#endif
outcharset = encoding;
# ifdef _LIBC
+
+ struct gconv_spec conv_spec;
+
+ __gconv_create_spec (&conv_spec, charset, outcharset);
+
/* We always want to use transliteration. */
- outcharset = norm_add_slashes (outcharset, "TRANSLIT");
- charset = norm_add_slashes (charset, "");
- int r = __gconv_open (outcharset, charset, &convd->conv,
- GCONV_AVOID_NOCONV);
+ conv_spec.translit = true;
+
+ int r = __gconv_open (&conv_spec, &convd->conv,
+ GCONV_AVOID_NOCONV);
+
+ __gconv_destroy_spec (&conv_spec);
+
if (__builtin_expect (r != __GCONV_OK, 0))
{
/* If the output encoding is the same there is
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <support/check.h>
static int
do_test (void)
{
- char *s;
- int result = 0;
-
unsetenv ("LANGUAGE");
unsetenv ("OUTPUT_CHARSET");
setlocale (LC_ALL, "de_DE.ISO-8859-1");
bindtextdomain ("codeset", OBJPFX "domaindir");
/* Here we expect output in ISO-8859-1. */
- s = gettext ("cheese");
- if (strcmp (s, "K\344se"))
- {
- printf ("call 1 returned: %s\n", s);
- result = 1;
- }
+ TEST_COMPARE_STRING (gettext ("cheese"), "K\344se");
+ /* Here we expect output in UTF-8. */
bind_textdomain_codeset ("codeset", "UTF-8");
+ TEST_COMPARE_STRING (gettext ("cheese"), "K\303\244se");
- /* Here we expect output in UTF-8. */
- s = gettext ("cheese");
- if (strcmp (s, "K\303\244se"))
- {
- printf ("call 2 returned: %s\n", s);
- result = 1;
- }
-
- return result;
+ /* `a with umlaut' is transliterated to `ae'. */
+ bind_textdomain_codeset ("codeset", "ASCII//TRANSLIT");
+ TEST_COMPARE_STRING (gettext ("cheese"), "Kaese");
+
+ /* Transliteration also works by default even if not set. */
+ bind_textdomain_codeset ("codeset", "ASCII");
+ TEST_COMPARE_STRING (gettext ("cheese"), "Kaese");
+
+ return 0;
}
-#define TEST_FUNCTION do_test ()
-#include "../test-skeleton.c"
+#include <support/test-driver.c>
"diluns";/
"dimars";/
"dim<U00E8>cres";/
- "dij<U00F3>us";/
+ "dij<U00F2>us";/
"divendres";/
"dissabte"
abmon "gen.";/
alt_mon "geni<U00E8>r";/
"febri<U00E8>r";/
"mar<U00E7>";/
- "abrial";/
+ "abril";/
"mai";/
"junh";/
"julhet";/
mon "de geni<U00E8>r";/
"de febri<U00E8>r";/
"de mar<U00E7>";/
- "d<U2019>abrial";/
+ "d<U2019>abril";/
"de mai";/
"de junh";/
"de julhet";/
tests += $(tests-static)
test-srcs = tst-mtrace
+# These tests either are run with MALLOC_CHECK_=3 by default or do not work
+# with MALLOC_CHECK_=3 because they expect a specific failure.
+tests-exclude-mcheck = tst-mcheck tst-malloc-usable \
+ tst-interpose-nothread tst-interpose-static-nothread \
+ tst-interpose-static-thread tst-malloc-too-large \
+ tst-mxfast tst-safe-linking
+
+# Run all tests with MALLOC_CHECK_=3
+tests-mcheck = $(filter-out $(tests-exclude-mcheck),$(tests))
+
routines = malloc morecore mcheck mtrace obstack reallocarray \
scratch_buffer_grow scratch_buffer_grow_preserve \
scratch_buffer_set_array_size \
$(objpfx)tst-malloc-thread-fail: $(shared-thread-library)
$(objpfx)tst-malloc-fork-deadlock: $(shared-thread-library)
$(objpfx)tst-malloc-stats-cancellation: $(shared-thread-library)
+$(objpfx)tst-malloc-backtrace-mcheck: $(shared-thread-library)
+$(objpfx)tst-malloc-thread-exit-mcheck: $(shared-thread-library)
+$(objpfx)tst-malloc-thread-fail-mcheck: $(shared-thread-library)
+$(objpfx)tst-malloc-fork-deadlock-mcheck: $(shared-thread-library)
+$(objpfx)tst-malloc-stats-cancellation-mcheck: $(shared-thread-library)
# Export the __malloc_initialize_hook variable to libc.so.
LDFLAGS-tst-mallocstate = -rdynamic
$(objpfx)tst-interpose-nothread: $(objpfx)tst-interpose-aux-nothread.o
$(objpfx)tst-interpose-thread: \
$(objpfx)tst-interpose-aux-thread.o $(shared-thread-library)
+$(objpfx)tst-interpose-thread-mcheck: \
+ $(objpfx)tst-interpose-aux-thread.o $(shared-thread-library)
$(objpfx)tst-interpose-static-nothread: $(objpfx)tst-interpose-aux-nothread.o
$(objpfx)tst-interpose-static-thread: \
$(objpfx)tst-interpose-aux-thread.o $(static-thread-library)
$(objpfx)tst-malloc-tcache-leak: $(shared-thread-library)
$(objpfx)tst-malloc_info: $(shared-thread-library)
$(objpfx)tst-mallocfork2: $(shared-thread-library)
+$(objpfx)tst-malloc-tcache-leak-mcheck: $(shared-thread-library)
+$(objpfx)tst-malloc_info-mcheck: $(shared-thread-library)
+$(objpfx)tst-mallocfork2-mcheck: $(shared-thread-library)
progress. Checked by liveness_signal_handler. */
static volatile sig_atomic_t progress_indicator = 1;
+/* Set to 1 if an error occurs in the signal handler. */
+static volatile sig_atomic_t error_indicator = 0;
+
static void
sigusr1_handler (int signo)
{
if (pid == -1)
{
write_message ("error: fork\n");
- abort ();
+ error_indicator = 1;
+ return;
}
if (pid == 0)
_exit (0);
if (ret < 0)
{
write_message ("error: waitpid\n");
- abort ();
+ error_indicator = 1;
+ return;
}
if (status != 0)
{
write_message ("error: unexpected exit status from subprocess\n");
- abort ();
+ error_indicator = 1;
+ return;
}
}
}
}
+/* Children processes. */
+static pid_t sigusr1_sender_pids[5] = { 0 };
+static pid_t sigusr2_sender_pid = 0;
+
+static void
+kill_children (void)
+{
+ for (size_t i = 0; i < array_length (sigusr1_sender_pids); ++i)
+ if (sigusr1_sender_pids[i] > 0)
+ kill (sigusr1_sender_pids[i], SIGKILL);
+ if (sigusr2_sender_pid > 0)
+ kill (sigusr2_sender_pid, SIGKILL);
+}
+
static int
do_test (void)
{
+ atexit (kill_children);
+
/* shared->barrier is intialized along with sigusr1_sender_pids
below. */
shared = support_shared_allocate (sizeof (*shared));
return 1;
}
- pid_t sigusr2_sender_pid = xfork ();
+ sigusr2_sender_pid = xfork ();
if (sigusr2_sender_pid == 0)
signal_sender (SIGUSR2, true);
/* Send SIGUSR1 signals from several processes. Hopefully, one
signal will hit one of the ciritical functions. Use a barrier to
avoid sending signals while not running fork/free/malloc. */
- pid_t sigusr1_sender_pids[5];
{
pthread_barrierattr_t attr;
xpthread_barrierattr_init (&attr);
}
for (size_t i = 0; i < array_length (sigusr1_sender_pids); ++i)
{
- sigusr1_sender_pids[i] = fork ();
+ sigusr1_sender_pids[i] = xfork ();
if (sigusr1_sender_pids[i] == 0)
signal_sender (SIGUSR1, false);
}
++malloc_signals;
xpthread_barrier_wait (&shared->barrier);
- if (objects[slot] == NULL)
+ if (objects[slot] == NULL || error_indicator != 0)
{
printf ("error: malloc: %m\n");
for (size_t i = 0; i < array_length (sigusr1_sender_pids); ++i)
for (int slot = 0; slot < malloc_objects; ++slot)
free (objects[slot]);
- for (size_t i = 0; i < array_length (sigusr1_sender_pids); ++i)
- kill (sigusr1_sender_pids[i], SIGKILL);
- kill (sigusr2_sender_pid, SIGKILL);
-
printf ("info: signals received during fork: %u\n", fork_signals);
printf ("info: signals received during free: %u\n", free_signals);
printf ("info: signals received during malloc: %u\n", malloc_signals);
# We won't compile the `long double' code at all. Tell the `double' code
# to define aliases for the `FUNCl' names.
math-CPPFLAGS += -DNO_LONG_DOUBLE
+# GCC 10 diagnoses aliases with types conflicting with built-in
+# functions.
+CFLAGS-w_acos.c += -fno-builtin-acosl
+CFLAGS-w_acosh.c += -fno-builtin-acoshl
+CFLAGS-w_asin.c += -fno-builtin-asinl
+CFLAGS-s_asinh.c += -fno-builtin-asinhl
+CFLAGS-s_atan.c += -fno-builtin-atanl
+CFLAGS-w_atan2.c += -fno-builtin-atan2l
+CFLAGS-w_atanh.c += -fno-builtin-atanhl
+CFLAGS-s_cabs.c += -fno-builtin-cabsl
+CFLAGS-s_cacos.c += -fno-builtin-cacosl
+CFLAGS-s_cacosh.c += -fno-builtin-cacoshl
+CFLAGS-s_canonicalize.c += -fno-builtin-canonicalizel
+CFLAGS-s_carg.c += -fno-builtin-cargl
+CFLAGS-s_casin.c += -fno-builtin-casinl
+CFLAGS-s_casinh.c += -fno-builtin-casinhl
+CFLAGS-s_catan.c += -fno-builtin-catanl
+CFLAGS-s_catanh.c += -fno-builtin-catanhl
+CFLAGS-s_cbrt.c += -fno-builtin-cbrtl
+CFLAGS-s_ccos.c += -fno-builtin-ccosl
+CFLAGS-s_ccosh.c += -fno-builtin-ccoshl
+CFLAGS-s_ceil.c += -fno-builtin-ceill
+CFLAGS-s_cexp.c += -fno-builtin-cexpl
+CFLAGS-s_cimag.c += -fno-builtin-cimagl
+CFLAGS-s_clog.c += -fno-builtin-clogl
+CFLAGS-s_clog10.c += -fno-builtin-clog10l
+CFLAGS-s_conj.c += -fno-builtin-conjl
+CFLAGS-s_copysign.c += -fno-builtin-copysignl
+CFLAGS-s_cos.c += -fno-builtin-cosl
+CFLAGS-w_cosh.c += -fno-builtin-coshl
+CFLAGS-s_cpow.c += -fno-builtin-cpowl
+CFLAGS-s_cproj.c += -fno-builtin-cprojl
+CFLAGS-s_creal.c += -fno-builtin-creall
+CFLAGS-s_csin.c += -fno-builtin-csinl
+CFLAGS-s_csinh.c += -fno-builtin-csinhl
+CFLAGS-s_csqrt.c += -fno-builtin-csqrtl
+CFLAGS-s_ctan.c += -fno-builtin-ctanl
+CFLAGS-s_ctanh.c += -fno-builtin-ctanhl
+CFLAGS-s_dadd.c += -fno-builtin-daddl
+CFLAGS-s_ddiv.c += -fno-builtin-ddivl
+CFLAGS-s_dmul.c += -fno-builtin-dmull
+CFLAGS-s_dsub.c += -fno-builtin-dsubl
+CFLAGS-s_erf.c += -fno-builtin-erfl
+CFLAGS-s_erfc.c += -fno-builtin-erfcl
+CFLAGS-e_exp.c += -fno-builtin-expl
+CFLAGS-w_exp10.c += -fno-builtin-exp10l
+CFLAGS-e_exp2.c += -fno-builtin-exp2l
+CFLAGS-s_expm1.c += -fno-builtin-expm1l
+CFLAGS-s_fabs.c += -fno-builtin-fabsl
+CFLAGS-s_fadd.c += -fno-builtin-faddl
+CFLAGS-s_fdim.c += -fno-builtin-fdiml
+CFLAGS-s_fdiv.c += -fno-builtin-fdivl
+CFLAGS-s_finite.c += -fno-builtin-finitel
+CFLAGS-s_floor.c += -fno-builtin-floorl
+CFLAGS-s_fma.c += -fno-builtin-fmal
+CFLAGS-s_fmax.c += -fno-builtin-fmaxl
+CFLAGS-s_fmaxmag.c += -fno-builtin-fmaxmagl
+CFLAGS-s_fmin.c += -fno-builtin-fminl
+CFLAGS-s_fminmag.c += -fno-builtin-fminmagl
+CFLAGS-w_fmod.c += -fno-builtin-fmodl
+CFLAGS-s_fmul.c += -fno-builtin-fmull
+CFLAGS-s_frexp.c += -fno-builtin-frexpl
+CFLAGS-s_fromfp.c += -fno-builtin-fromfpl
+CFLAGS-s_fromfpx.c += -fno-builtin-fromfpxl
+CFLAGS-s_fsub.c += -fno-builtin-fsubl
+CFLAGS-s_gamma.c += -fno-builtin-gammal
+CFLAGS-s_getpayload.c += -fno-builtin-getpayloadl
+CFLAGS-w_hypot.c += -fno-builtin-hypotl
+CFLAGS-w_ilogb.c += -fno-builtin-ilogbl
+CFLAGS-s_isinf.c += -fno-builtin-isinfl
+CFLAGS-s_isnan.c += -fno-builtin-isnanl
+CFLAGS-w_j0.c += -fno-builtin-j0l
+CFLAGS-w_j1.c += -fno-builtin-j1l
+CFLAGS-w_jn.c += -fno-builtin-jnl
+CFLAGS-s_ldexp.c += -fno-builtin-ldexpl
+CFLAGS-w_lgamma.c += -fno-builtin-lgammal
+CFLAGS-w_lgamma_r.c += -fno-builtin-lgammal_r
+CFLAGS-w_llogb.c += -fno-builtin-llogbl
+CFLAGS-s_llrint.c += -fno-builtin-llrintl
+CFLAGS-s_llround.c += -fno-builtin-llroundl
+CFLAGS-e_log.c += -fno-builtin-logl
+CFLAGS-w_log10.c += -fno-builtin-log10l
+CFLAGS-w_log1p.c += -fno-builtin-log1pl
+CFLAGS-e_log2.c += -fno-builtin-log2l
+CFLAGS-s_logb.c += -fno-builtin-logbl
+CFLAGS-s_lrint.c += -fno-builtin-lrintl
+CFLAGS-s_lround.c += -fno-builtin-lroundl
+CFLAGS-s_modf.c += -fno-builtin-modfl
+CFLAGS-s_nan.c += -fno-builtin-nanl
+CFLAGS-s_nearbyint.c += -fno-builtin-nearbyintl
+CFLAGS-s_nextafter.c += -fno-builtin-nextafterl
+CFLAGS-s_nextdown.c += -fno-builtin-nextdownl
+CFLAGS-s_nexttoward.c += -fno-builtin-nexttoward -fno-builtin-nexttowardl
+CFLAGS-s_nexttowardf.c += -fno-builtin-nexttowardf
+CFLAGS-s_nextup.c += -fno-builtin-nextupl
+CFLAGS-e_pow.c += -fno-builtin-powl
+CFLAGS-w_remainder.c += -fno-builtin-remainderl -fno-builtin-dreml
+CFLAGS-s_remquo.c += -fno-builtin-remquol
+CFLAGS-s_rint.c += -fno-builtin-rintl
+CFLAGS-s_round.c += -fno-builtin-roundl
+CFLAGS-s_roundeven.c += -fno-builtin-roundevenl
+CFLAGS-w_scalb.c += -fno-builtin-scalbl
+CFLAGS-w_scalbln.c += -fno-builtin-scalblnl
+CFLAGS-s_scalbn.c += -fno-builtin-scalbnl
+CFLAGS-s_setpayload.c += -fno-builtin-setpayloadl
+CFLAGS-s_setpayloadsig.c += -fno-builtin-setpayloadsigl
+CFLAGS-s_significand.c += -fno-builtin-significandl
+CFLAGS-s_sin.c += -fno-builtin-sinl
+CFLAGS-s_sincos.c += -fno-builtin-sincosl
+CFLAGS-w_sinh.c += -fno-builtin-sinhl
+CFLAGS-w_sqrt.c += -fno-builtin-sqrtl
+CFLAGS-s_tan.c += -fno-builtin-tanl
+CFLAGS-s_tanh.c += -fno-builtin-tanhl
+CFLAGS-w_tgamma.c += -fno-builtin-tgammal
+CFLAGS-s_totalorder.c += -fno-builtin-totalorderl
+CFLAGS-s_totalordermag.c += -fno-builtin-totalordermagl
+CFLAGS-s_trunc.c += -fno-builtin-truncl
+CFLAGS-s_ufromfp.c += -fno-builtin-ufromfpl
+CFLAGS-s_ufromfpx.c += -fno-builtin-ufromfpxl
+CFLAGS-s_y0.c += -fno-builtin-y0l
+CFLAGS-s_y1.c += -fno-builtin-y1l
+CFLAGS-s_yn.c += -fno-builtin-ynl
endif
# These files quiet sNaNs in a way that is optimized away without
tst-preadvwritev tst-preadvwritev64 tst-makedev tst-empty \
tst-preadvwritev2 tst-preadvwritev64v2 tst-warn-wide \
tst-ldbl-warn tst-ldbl-error tst-dbl-efgcvt tst-ldbl-efgcvt \
- tst-mntent-autofs
+ tst-mntent-autofs tst-syscalls
# Tests which need libdl.
ifeq (yes,$(build-shared))
--- /dev/null
+/* Test for syscall interfaces.
+ Copyright (C) 2020 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/>. */
+
+/* This test verifies that the x32 system call handling zero-extends
+ unsigned 32-bit arguments to the 64-bit argument registers for
+ system calls (bug 25810). The bug is specific to x32, but the test
+ should pass on all architectures. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <support/check.h>
+#include <support/xunistd.h>
+
+/* On x32, this can be passed in a single 64-bit integer register. */
+struct Array
+{
+ size_t length;
+ void *ptr;
+};
+
+static int error_count;
+
+__attribute__ ((noclone, noinline))
+struct Array
+allocate (size_t bytes)
+{
+ if (!bytes)
+ return __extension__ (struct Array) {0, 0};
+
+ void *p = mmap (0x0, bytes, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANON, -1, 0);
+ if (p == MAP_FAILED)
+ return __extension__ (struct Array) {0, 0};
+
+ return __extension__ (struct Array) {bytes, p};
+}
+
+__attribute__ ((noclone, noinline))
+void
+deallocate (struct Array b)
+{
+ /* On x32, the 64-bit integer register containing `b' may be copied
+ to another 64-bit integer register to pass the second argument to
+ munmap. */
+ if (b.length && munmap (b.ptr, b.length))
+ {
+ printf ("munmap error: %m\n");
+ error_count++;
+ }
+}
+
+__attribute__ ((noclone, noinline))
+void *
+do_mmap (void *addr, size_t length)
+{
+ return mmap (addr, length, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANON, -1, 0);
+}
+
+__attribute__ ((noclone, noinline))
+void *
+reallocate (struct Array b)
+{
+ /* On x32, the 64-bit integer register containing `b' may be copied
+ to another 64-bit integer register to pass the second argument to
+ do_mmap. */
+ if (b.length)
+ return do_mmap (b.ptr, b.length);
+ return NULL;
+}
+
+__attribute__ ((noclone, noinline))
+void
+protect (struct Array b)
+{
+ if (b.length)
+ {
+ /* On x32, the 64-bit integer register containing `b' may be copied
+ to another 64-bit integer register to pass the second argument
+ to mprotect. */
+ if (mprotect (b.ptr, b.length,
+ PROT_READ | PROT_WRITE | PROT_EXEC))
+ {
+ printf ("mprotect error: %m\n");
+ error_count++;
+ }
+ }
+}
+
+__attribute__ ((noclone, noinline))
+ssize_t
+do_read (int fd, void *ptr, struct Array b)
+{
+ /* On x32, the 64-bit integer register containing `b' may be copied
+ to another 64-bit integer register to pass the second argument to
+ read. */
+ if (b.length)
+ return read (fd, ptr, b.length);
+ return 0;
+}
+
+__attribute__ ((noclone, noinline))
+ssize_t
+do_write (int fd, void *ptr, struct Array b)
+{
+ /* On x32, the 64-bit integer register containing `b' may be copied
+ to another 64-bit integer register to pass the second argument to
+ write. */
+ if (b.length)
+ return write (fd, ptr, b.length);
+ return 0;
+}
+
+static int
+do_test (void)
+{
+ struct Array array;
+
+ array = allocate (1);
+ protect (array);
+ deallocate (array);
+ void *p = reallocate (array);
+ if (p == MAP_FAILED)
+ {
+ printf ("mmap error: %m\n");
+ error_count++;
+ }
+ array.ptr = p;
+ protect (array);
+ deallocate (array);
+
+ int fd = xopen ("/dev/null", O_RDWR, 0);
+ char buf[2];
+ array.ptr = buf;
+ if (do_read (fd, array.ptr, array) == -1)
+ {
+ printf ("read error: %m\n");
+ error_count++;
+ }
+ if (do_write (fd, array.ptr, array) == -1)
+ {
+ printf ("write error: %m\n");
+ error_count++;
+ }
+ xclose (fd);
+
+ return error_count ? EXIT_FAILURE : EXIT_SUCCESS;
+}
+
+#include <support/test-driver.c>
tst-mutexpi8 tst-mutexpi8-static tst-cancel25
xtests = tst-setuid1 tst-setuid1-static tst-setuid2 \
- tst-mutexpp1 tst-mutexpp6 tst-mutexpp10
+ tst-mutexpp1 tst-mutexpp6 tst-mutexpp10 tst-setgroups
# This test can run into task limits because of a linux kernel bug
# and then cause the make process to fail too, see bug 24537.
struct xid_command
{
int syscall_no;
- long int id[3];
+ /* Enforce zero-extension for the pointer argument in
+
+ int setgroups (size_t size, const gid_t *list);
+
+ The kernel XID arguments are unsigned and do not require sign
+ extension. */
+ unsigned long int id[3];
volatile int cntr;
volatile int error; /* -1: no call yet, 0: success seen, >0: error seen. */
};
--- /dev/null
+/* Test setgroups as root and in the presence of threads (Bug 26248)
+ Copyright (C) 2020 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/>. */
+
+#include <stdlib.h>
+#include <limits.h>
+#include <grp.h>
+#include <errno.h>
+#include <error.h>
+#include <support/xthread.h>
+#include <support/support.h>
+#include <support/test-driver.h>
+#include <support/xunistd.h>
+
+/* The purpose of this test is to test the setgroups API as root and in
+ the presence of threads. Once we create a thread the setgroups
+ implementation must ensure that all threads are set to the same
+ group and this operation should not fail. Lastly we test setgroups
+ with a zero sized group and a bad address and verify we get EPERM. */
+
+static void *
+start_routine (void *args)
+{
+ return NULL;
+}
+
+static int
+do_test (void)
+{
+ int size;
+ /* NB: Stack address can be at 0xfffXXXXX on 32-bit OSes. */
+ gid_t list[NGROUPS_MAX];
+ int status = EXIT_SUCCESS;
+
+ pthread_t thread = xpthread_create (NULL, start_routine, NULL);
+
+ size = getgroups (sizeof (list) / sizeof (list[0]), list);
+ if (size < 0)
+ {
+ status = EXIT_FAILURE;
+ error (0, errno, "getgroups failed");
+ }
+ if (setgroups (size, list) < 0)
+ {
+ if (errno == EPERM)
+ status = EXIT_UNSUPPORTED;
+ else
+ {
+ status = EXIT_FAILURE;
+ error (0, errno, "setgroups failed");
+ }
+ }
+
+ if (status == EXIT_SUCCESS && setgroups (0, list) < 0)
+ {
+ status = EXIT_FAILURE;
+ error (0, errno, "setgroups failed");
+ }
+
+ xpthread_join (thread);
+
+ return status;
+}
+
+#include <support/test-driver.c>
: NULL);
ndomain = (ndomain ? newbuf + ndomaindiff
: NULL);
- buffer = newbuf;
+ *tofreep = buffer = newbuf;
}
nhost = memcpy (buffer + bufused,
else if (status == NSS_STATUS_TRYAGAIN && e == ERANGE)
{
buflen *= 2;
- buffer = xrealloc (buffer, buflen);
+ *tofreep = buffer = xrealloc (buffer, buflen);
}
else if (status == NSS_STATUS_RETURN
|| status == NSS_STATUS_NOTFOUND
#ifdef HAVE_LIBAUDIT
# include <libaudit.h>
#endif
+#include <libc-diag.h>
#include "dbg_log.h"
#include "selinux.h"
}
+/* avc_init (along with several other symbols) was marked as deprecated by the
+ SELinux API starting from version 3.1. We use it here, but should
+ eventually switch to the newer API. */
+DIAG_PUSH_NEEDS_COMMENT
+DIAG_IGNORE_NEEDS_COMMENT (10, "-Wdeprecated-declarations");
+
/* Initialize the user space access vector cache (AVC) for NSCD along with
log/thread/lock callbacks. */
void
audit_init ();
#endif
}
+DIAG_POP_NEEDS_COMMENT
+
+/* security_context_t and sidput (along with several other symbols) were marked
+ as deprecated by the SELinux API starting from version 3.1. We use them
+ here, but should eventually switch to the newer API. */
+DIAG_PUSH_NEEDS_COMMENT
+DIAG_IGNORE_NEEDS_COMMENT (10, "-Wdeprecated-declarations");
/* Check the permission from the caller (via getpeercon) to nscd.
Returns 0 if access is allowed, 1 if denied, and -1 on error.
return rc;
}
+DIAG_POP_NEEDS_COMMENT
/* Wrapper to get AVC statistics. */
#include <sys/stat.h>
#include <sys/uio.h>
#include "nss_db/nss_db.h"
+#include <libc-diag.h>
/* Get libc version number. */
#include "../version.h"
#ifdef HAVE_SELINUX
+
+/* security_context_t and matchpathcon (along with several other symbols) were
+ marked as deprecated by the SELinux API starting from version 3.1. We use
+ them here, but should eventually switch to the newer API. */
+DIAG_PUSH_NEEDS_COMMENT
+DIAG_IGNORE_NEEDS_COMMENT (10, "-Wdeprecated-declarations");
+
static void
set_file_creation_context (const char *outname, mode_t mode)
{
freecon (ctx);
}
}
+DIAG_POP_NEEDS_COMMENT
static void
reset_file_creation_context (void)
}
-static enum nss_status
+static enum nss_status __attribute_warn_unused_result__
internal_endgrent (ent_t *ent)
{
if (ent->stream != NULL)
return NSS_STATUS_SUCCESS;
}
+/* Like internal_endgrent, but preserve errno in all cases. */
+static void
+internal_endgrent_noerror (ent_t *ent)
+{
+ int saved_errno = errno;
+ enum nss_status unused __attribute__ ((unused)) = internal_endgrent (ent);
+ __set_errno (saved_errno);
+}
+
enum nss_status
_nss_compat_endgrent (void)
{
if (result == NSS_STATUS_SUCCESS)
result = internal_getgrnam_r (name, grp, &ent, buffer, buflen, errnop);
- internal_endgrent (&ent);
+ internal_endgrent_noerror (&ent);
return result;
}
if (result == NSS_STATUS_SUCCESS)
result = internal_getgrgid_r (gid, grp, &ent, buffer, buflen, errnop);
- internal_endgrent (&ent);
+ internal_endgrent_noerror (&ent);
return result;
}
}
-static enum nss_status
+static enum nss_status __attribute_warn_unused_result__
internal_endgrent (ent_t *ent)
{
if (ent->stream != NULL)
return NSS_STATUS_SUCCESS;
}
+/* Like internal_endgrent, but preserve errno in all cases. */
+static void
+internal_endgrent_noerror (ent_t *ent)
+{
+ int saved_errno = errno;
+ enum nss_status unused __attribute__ ((unused)) = internal_endgrent (ent);
+ __set_errno (saved_errno);
+}
+
/* Add new group record. */
static void
add_group (long int *start, long int *size, gid_t **groupsp, long int limit,
done:
scratch_buffer_free (&tmpbuf);
- internal_endgrent (&intern);
+ internal_endgrent_noerror (&intern);
return status;
}
}
-static enum nss_status
+static enum nss_status __attribute_warn_unused_result__
internal_endpwent (ent_t *ent)
{
if (ent->stream != NULL)
return NSS_STATUS_SUCCESS;
}
+/* Like internal_endpwent, but preserve errno in all cases. */
+static void
+internal_endpwent_noerror (ent_t *ent)
+{
+ int saved_errno = errno;
+ enum nss_status unused __attribute__ ((unused)) = internal_endpwent (ent);
+ __set_errno (saved_errno);
+}
+
enum nss_status
_nss_compat_endpwent (void)
{
if (result == NSS_STATUS_SUCCESS)
result = internal_getpwnam_r (name, pwd, &ent, buffer, buflen, errnop);
- internal_endpwent (&ent);
+ internal_endpwent_noerror (&ent);
return result;
}
if (result == NSS_STATUS_SUCCESS)
result = internal_getpwuid_r (uid, pwd, &ent, buffer, buflen, errnop);
- internal_endpwent (&ent);
+ internal_endpwent_noerror (&ent);
return result;
}
}
-static enum nss_status
+static enum nss_status __attribute_warn_unused_result__
internal_endspent (ent_t *ent)
{
if (ent->stream != NULL)
return NSS_STATUS_SUCCESS;
}
+/* Like internal_endspent, but preserve errno in all cases. */
+static void
+internal_endspent_noerror (ent_t *ent)
+{
+ int saved_errno = errno;
+ enum nss_status unused __attribute__ ((unused)) = internal_endspent (ent);
+ __set_errno (saved_errno);
+}
+
enum nss_status
_nss_compat_endspent (void)
{
return result;
}
-
static enum nss_status
getspent_next_nss_netgr (const char *name, struct spwd *result, ent_t *ent,
char *group, char *buffer, size_t buflen,
if (result == NSS_STATUS_SUCCESS)
result = internal_getspnam_r (name, pwd, &ent, buffer, buflen, errnop);
- internal_endspent (&ent);
+ internal_endspent_noerror (&ent);
return result;
}
{
size_t home_len = strlen (p->pw_dir);
size_t rest_len = end_name == NULL ? 0 : strlen (end_name);
- char *d;
+ char *d, *newp;
+ bool use_alloca = glob_use_alloca (alloca_used,
+ home_len + rest_len + 1);
- if (__glibc_unlikely (malloc_dirname))
- free (dirname);
- malloc_dirname = 0;
-
- if (glob_use_alloca (alloca_used, home_len + rest_len + 1))
- dirname = alloca_account (home_len + rest_len + 1,
- alloca_used);
+ if (use_alloca)
+ newp = alloca_account (home_len + rest_len + 1, alloca_used);
else
{
- dirname = malloc (home_len + rest_len + 1);
- if (dirname == NULL)
+ newp = malloc (home_len + rest_len + 1);
+ if (newp == NULL)
{
scratch_buffer_free (&pwtmpbuf);
retval = GLOB_NOSPACE;
goto out;
}
- malloc_dirname = 1;
}
- d = mempcpy (dirname, p->pw_dir, home_len);
+ d = mempcpy (newp, p->pw_dir, home_len);
if (end_name != NULL)
d = mempcpy (d, end_name, rest_len);
*d = '\0';
+ if (__glibc_unlikely (malloc_dirname))
+ free (dirname);
+ dirname = newp;
+ malloc_dirname = !use_alloca;
+
dirlen = home_len + rest_len;
dirname_modified = 1;
}
test-canon test-canon2 tst-strtoll tst-environ \
tst-xpg-basename tst-random tst-random2 tst-bsearch \
tst-limits tst-rand48 bug-strtod tst-setcontext \
- tst-setcontext2 test-a64l tst-qsort tst-system testmb2 \
+ tst-setcontext2 test-a64l tst-qsort testmb2 \
bug-strtod2 tst-atof1 tst-atof2 tst-strtod2 \
tst-rand48-2 tst-makecontext tst-strtod5 \
tst-qsort2 tst-makecontext2 tst-strtod6 tst-unsetenv1 \
tests-internal := tst-strtod1i tst-strtod3 tst-strtod4 tst-strtod5i \
tst-tls-atexit tst-tls-atexit-nodelete
tests-static := tst-secure-getenv
+tests-container := tst-system
ifeq ($(build-hardcoded-path-in-tests),yes)
tests += tst-empty-env
#include <sys/wait.h>
#include <unistd.h>
+#include <support/check.h>
#include <support/support.h>
+#include <support/capture_subprocess.h>
#include <support/test-driver.h>
static char MAGIC_ARGUMENT[] = "run-actual-test";
-#define MAGIC_STATUS 19
-
-/* Return a GID which is not our current GID, but is present in the
- supplementary group list. */
-static gid_t
-choose_gid (void)
-{
- int count = getgroups (0, NULL);
- if (count < 0)
- {
- printf ("getgroups: %m\n");
- exit (1);
- }
- gid_t *groups;
- groups = xcalloc (count, sizeof (*groups));
- int ret = getgroups (count, groups);
- if (ret < 0)
- {
- printf ("getgroups: %m\n");
- exit (1);
- }
- gid_t current = getgid ();
- gid_t not_current = 0;
- for (int i = 0; i < ret; ++i)
- {
- if (groups[i] != current)
- {
- not_current = groups[i];
- break;
- }
- }
- free (groups);
- return not_current;
-}
-
-
-/* Copies the executable into a restricted directory, so that we can
- safely make it SGID with the TARGET group ID. Then runs the
- executable. */
-static int
-run_executable_sgid (gid_t target)
-{
- char *dirname = xasprintf ("%s/secure-getenv.%jd",
- test_dir, (intmax_t) getpid ());
- char *execname = xasprintf ("%s/bin", dirname);
- int infd = -1;
- int outfd = -1;
- int ret = -1;
- if (mkdir (dirname, 0700) < 0)
- {
- printf ("mkdir: %m\n");
- goto err;
- }
- infd = open ("/proc/self/exe", O_RDONLY);
- if (infd < 0)
- {
- printf ("open (/proc/self/exe): %m\n");
- goto err;
- }
- outfd = open (execname, O_WRONLY | O_CREAT | O_EXCL, 0700);
- if (outfd < 0)
- {
- printf ("open (%s): %m\n", execname);
- goto err;
- }
- char buf[4096];
- for (;;)
- {
- ssize_t rdcount = read (infd, buf, sizeof (buf));
- if (rdcount < 0)
- {
- printf ("read: %m\n");
- goto err;
- }
- if (rdcount == 0)
- break;
- char *p = buf;
- char *end = buf + rdcount;
- while (p != end)
- {
- ssize_t wrcount = write (outfd, buf, end - p);
- if (wrcount == 0)
- errno = ENOSPC;
- if (wrcount <= 0)
- {
- printf ("write: %m\n");
- goto err;
- }
- p += wrcount;
- }
- }
- if (fchown (outfd, getuid (), target) < 0)
- {
- printf ("fchown (%s): %m\n", execname);
- goto err;
- }
- if (fchmod (outfd, 02750) < 0)
- {
- printf ("fchmod (%s): %m\n", execname);
- goto err;
- }
- if (close (outfd) < 0)
- {
- printf ("close (outfd): %m\n");
- goto err;
- }
- if (close (infd) < 0)
- {
- printf ("close (infd): %m\n");
- goto err;
- }
-
- int kid = fork ();
- if (kid < 0)
- {
- printf ("fork: %m\n");
- goto err;
- }
- if (kid == 0)
- {
- /* Child process. */
- char *args[] = { execname, MAGIC_ARGUMENT, NULL };
- execve (execname, args, environ);
- printf ("execve (%s): %m\n", execname);
- _exit (1);
- }
- int status;
- if (waitpid (kid, &status, 0) < 0)
- {
- printf ("waitpid: %m\n");
- goto err;
- }
- if (!WIFEXITED (status) || WEXITSTATUS (status) != MAGIC_STATUS)
- {
- printf ("Unexpected exit status %d from child process\n",
- status);
- goto err;
- }
- ret = 0;
-
-err:
- if (outfd >= 0)
- close (outfd);
- if (infd >= 0)
- close (infd);
- if (execname)
- {
- unlink (execname);
- free (execname);
- }
- if (dirname)
- {
- rmdir (dirname);
- free (dirname);
- }
- return ret;
-}
static int
do_test (void)
exit (1);
}
- gid_t target = choose_gid ();
- if (target == 0)
- {
- fprintf (stderr,
- "Could not find a suitable GID for user %jd, skipping test\n",
- (intmax_t) getuid ());
- exit (0);
- }
- return run_executable_sgid (target);
+ int status = support_capture_subprogram_self_sgid (MAGIC_ARGUMENT);
+
+ if (WEXITSTATUS (status) == EXIT_UNSUPPORTED)
+ return EXIT_UNSUPPORTED;
+
+ if (!WIFEXITED (status))
+ FAIL_EXIT1 ("Unexpected exit status %d from child process\n", status);
+
+ return 0;
}
static void
if (argc == 2 && strcmp (argv[1], MAGIC_ARGUMENT) == 0)
{
if (getgid () == getegid ())
- {
- /* This can happen if the file system is mounted nosuid. */
- fprintf (stderr, "SGID failed: GID and EGID match (%jd)\n",
- (intmax_t) getgid ());
- exit (MAGIC_STATUS);
- }
+ /* This can happen if the file system is mounted nosuid. */
+ FAIL_UNSUPPORTED ("SGID failed: GID and EGID match (%jd)\n",
+ (intmax_t) getgid ());
if (getenv ("PATH") == NULL)
- {
- printf ("PATH variable not present\n");
- exit (3);
- }
+ FAIL_EXIT (3, "PATH variable not present\n");
if (secure_getenv ("PATH") != NULL)
- {
- printf ("PATH variable not filtered out\n");
- exit (4);
- }
- exit (MAGIC_STATUS);
+ FAIL_EXIT (4, "PATH variable not filtered out\n");
+
+ exit (EXIT_SUCCESS);
}
}
<https://www.gnu.org/licenses/>. */
#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <signal.h>
+#include <paths.h>
+#include <support/capture_subprocess.h>
+#include <support/check.h>
+#include <support/temp_file.h>
+#include <support/support.h>
+
+static char *tmpdir;
+static long int namemax;
+
+static void
+do_prepare (int argc, char *argv[])
+{
+ tmpdir = support_create_temp_directory ("tst-system-");
+ /* Include the last '/0'. */
+ namemax = pathconf (tmpdir, _PC_NAME_MAX) + 1;
+ TEST_VERIFY_EXIT (namemax != -1);
+}
+#define PREPARE do_prepare
+
+struct args
+{
+ const char *command;
+ int exit_status;
+ int term_sig;
+ const char *path;
+};
+
+static void
+call_system (void *closure)
+{
+ struct args *args = (struct args *) closure;
+ int ret;
+
+ if (args->path != NULL)
+ TEST_COMPARE (setenv ("PATH", args->path, 1), 0);
+ ret = system (args->command);
+ if (args->term_sig == 0)
+ {
+ /* Expect regular termination. */
+ TEST_VERIFY (WIFEXITED (ret) != 0);
+ TEST_COMPARE (WEXITSTATUS (ret), args->exit_status);
+ }
+ else
+ {
+ /* status_or_signal < 0. Expect termination by signal. */
+ TEST_VERIFY (WIFSIGNALED (ret) != 0);
+ TEST_COMPARE (WTERMSIG (ret), args->term_sig);
+ }
+}
static int
do_test (void)
{
- return system (":");
-}
+ TEST_VERIFY (system (NULL) != 0);
+ {
+ char cmd[namemax];
+ memset (cmd, 'a', sizeof(cmd));
+ cmd[sizeof(cmd) - 1] = '\0';
+
+ struct support_capture_subprocess result;
+ result = support_capture_subprocess (call_system,
+ &(struct args) {
+ cmd, 127, 0, tmpdir
+ });
+ support_capture_subprocess_check (&result, "system", 0, sc_allow_stderr);
+
+ char *returnerr = xasprintf ("%s: execing %s failed: "
+ "No such file or directory",
+ basename(_PATH_BSHELL), cmd);
+ TEST_COMPARE_STRING (result.err.buffer, returnerr);
+ free (returnerr);
+ }
+
+ {
+ char cmd[namemax + 1];
+ memset (cmd, 'a', sizeof(cmd));
+ cmd[sizeof(cmd) - 1] = '\0';
+
+ struct support_capture_subprocess result;
+ result = support_capture_subprocess (call_system,
+ &(struct args) {
+ cmd, 127, 0, tmpdir
+ });
+ support_capture_subprocess_check (&result, "system", 0, sc_allow_stderr);
+
+ char *returnerr = xasprintf ("%s: execing %s failed: "
+ "File name too long",
+ basename(_PATH_BSHELL), cmd);
+ TEST_COMPARE_STRING (result.err.buffer, returnerr);
+ free (returnerr);
+ }
+
+ {
+ struct support_capture_subprocess result;
+ result = support_capture_subprocess (call_system,
+ &(struct args) {
+ "kill $$", 0, SIGTERM
+ });
+ support_capture_subprocess_check (&result, "system", 0, sc_allow_none);
+ }
+
+ {
+ struct support_capture_subprocess result;
+ result = support_capture_subprocess (call_system,
+ &(struct args) { "echo ...", 0 });
+ support_capture_subprocess_check (&result, "system", 0, sc_allow_stdout);
+ TEST_COMPARE_STRING (result.out.buffer, "...\n");
+ }
+
+ {
+ struct support_capture_subprocess result;
+ result = support_capture_subprocess (call_system,
+ &(struct args) { "exit 1", 1 });
+ support_capture_subprocess_check (&result, "system", 0, sc_allow_none);
+ }
+
+ TEST_COMPARE (system (""), 0);
+
+ return 0;
+}
-#define TEST_FUNCTION do_test ()
-#include "../test-skeleton.c"
+#include <support/test-driver.c>
struct support_capture_subprocess support_capture_subprogram
(const char *file, char *const argv[]);
+/* Copy the running program into a setgid binary and run it with CHILD_ID
+ argument. If execution is successful, return the exit status of the child
+ program, otherwise return a non-zero failure exit code. */
+int support_capture_subprogram_self_sgid
+ (char *child_id);
+
/* Deallocate the subprocess data captured by
support_capture_subprocess. */
void support_capture_subprocess_free (struct support_capture_subprocess *);
}
+/* Emulate the 'exit' builtin. The exit value is optional. */
+static int
+exit_func (char **argv)
+{
+ int exit_val = 0;
+
+ if (argv[0] != 0)
+ exit_val = atoi (argv[0]) & 0xff;
+ exit (exit_val);
+ return 0;
+}
+
+/* Emulate the "/bin/kill" command. Options are ignored. */
+static int
+kill_func (char **argv)
+{
+ int signum = SIGTERM;
+ int i;
+
+ for (i = 0; argv[i]; i++)
+ {
+ pid_t pid;
+ if (strcmp (argv[i], "$$") == 0)
+ pid = getpid ();
+ else
+ pid = atoi (argv[i]);
+ kill (pid, signum);
+ }
+ return 0;
+}
+
/* This is a list of all the built-in commands we understand. */
static struct {
const char *name;
{ "true", true_func },
{ "echo", echo_func },
{ "cp", copy_func },
+ { "exit", exit_func },
+ { "kill", kill_func },
{ NULL, NULL }
};
fprintf (stderr, "sh: execing %s failed: %s",
argv[0], strerror (errno));
- exit (1);
+ exit (127);
}
waitpid (pid, &status, 0);
if (rv)
exit (rv);
}
+ else if (WIFSIGNALED (status))
+ {
+ int sig = WTERMSIG (status);
+ raise (sig);
+ }
else
exit (1);
}
struct support_subprocess support_subprogram
(const char *file, char *const argv[]);
+/* Invoke program FILE with ARGV arguments by using posix_spawn and wait for it
+ to complete. Return program exit status. */
+int support_subprogram_wait
+ (const char *file, char *const argv[]);
+
/* Wait for the subprocess indicated by PROC::PID. Return the status
indicate by waitpid call. */
int support_process_wait (struct support_subprocess *proc);
#include <support/capture_subprocess.h>
#include <errno.h>
+#include <fcntl.h>
#include <stdlib.h>
#include <support/check.h>
#include <support/xunistd.h>
#include <support/xsocket.h>
#include <support/xspawn.h>
+#include <support/support.h>
+#include <support/test-driver.h>
static void
transfer (const char *what, struct pollfd *pfd, struct xmemstream *stream)
if (ret < 0)
{
support_record_failure ();
- printf ("error: reading from subprocess %s: %m", what);
+ printf ("error: reading from subprocess %s: %m\n", what);
pfd->events = 0;
pfd->revents = 0;
}
return result;
}
+/* Copies the executable into a restricted directory, so that we can
+ safely make it SGID with the TARGET group ID. Then runs the
+ executable. */
+static int
+copy_and_spawn_sgid (char *child_id, gid_t gid)
+{
+ char *dirname = xasprintf ("%s/tst-tunables-setuid.%jd",
+ test_dir, (intmax_t) getpid ());
+ char *execname = xasprintf ("%s/bin", dirname);
+ int infd = -1;
+ int outfd = -1;
+ int ret = 1, status = 1;
+
+ TEST_VERIFY (mkdir (dirname, 0700) == 0);
+ if (support_record_failure_is_failed ())
+ goto err;
+
+ infd = open ("/proc/self/exe", O_RDONLY);
+ if (infd < 0)
+ FAIL_UNSUPPORTED ("unsupported: Cannot read binary from procfs\n");
+
+ outfd = open (execname, O_WRONLY | O_CREAT | O_EXCL, 0700);
+ TEST_VERIFY (outfd >= 0);
+ if (support_record_failure_is_failed ())
+ goto err;
+
+ char buf[4096];
+ for (;;)
+ {
+ ssize_t rdcount = read (infd, buf, sizeof (buf));
+ TEST_VERIFY (rdcount >= 0);
+ if (support_record_failure_is_failed ())
+ goto err;
+ if (rdcount == 0)
+ break;
+ char *p = buf;
+ char *end = buf + rdcount;
+ while (p != end)
+ {
+ ssize_t wrcount = write (outfd, buf, end - p);
+ if (wrcount == 0)
+ errno = ENOSPC;
+ TEST_VERIFY (wrcount > 0);
+ if (support_record_failure_is_failed ())
+ goto err;
+ p += wrcount;
+ }
+ }
+ TEST_VERIFY (fchown (outfd, getuid (), gid) == 0);
+ if (support_record_failure_is_failed ())
+ goto err;
+ TEST_VERIFY (fchmod (outfd, 02750) == 0);
+ if (support_record_failure_is_failed ())
+ goto err;
+ TEST_VERIFY (close (outfd) == 0);
+ if (support_record_failure_is_failed ())
+ goto err;
+ TEST_VERIFY (close (infd) == 0);
+ if (support_record_failure_is_failed ())
+ goto err;
+
+ /* We have the binary, now spawn the subprocess. Avoid using
+ support_subprogram because we only want the program exit status, not the
+ contents. */
+ ret = 0;
+
+ char * const args[] = {execname, child_id, NULL};
+
+ status = support_subprogram_wait (args[0], args);
+
+err:
+ if (outfd >= 0)
+ close (outfd);
+ if (infd >= 0)
+ close (infd);
+ if (execname != NULL)
+ {
+ unlink (execname);
+ free (execname);
+ }
+ if (dirname != NULL)
+ {
+ rmdir (dirname);
+ free (dirname);
+ }
+
+ if (ret != 0)
+ FAIL_EXIT1("Failed to make sgid executable for test\n");
+
+ return status;
+}
+
+int
+support_capture_subprogram_self_sgid (char *child_id)
+{
+ gid_t target = 0;
+ const int count = 64;
+ gid_t groups[count];
+
+ /* Get a GID which is not our current GID, but is present in the
+ supplementary group list. */
+ int ret = getgroups (count, groups);
+ if (ret < 0)
+ FAIL_UNSUPPORTED("Could not get group list for user %jd\n",
+ (intmax_t) getuid ());
+
+ gid_t current = getgid ();
+ for (int i = 0; i < ret; ++i)
+ {
+ if (groups[i] != current)
+ {
+ target = groups[i];
+ break;
+ }
+ }
+
+ if (target == 0)
+ FAIL_UNSUPPORTED("Could not find a suitable GID for user %jd\n",
+ (intmax_t) getuid ());
+
+ return copy_and_spawn_sgid (child_id, target);
+}
+
void
support_capture_subprocess_free (struct support_capture_subprocess *p)
{
#include <support/subprocess.h>
static struct support_subprocess
-support_suprocess_init (void)
+support_subprocess_init (void)
{
struct support_subprocess result;
struct support_subprocess
support_subprocess (void (*callback) (void *), void *closure)
{
- struct support_subprocess result = support_suprocess_init ();
+ struct support_subprocess result = support_subprocess_init ();
result.pid = xfork ();
if (result.pid == 0)
struct support_subprocess
support_subprogram (const char *file, char *const argv[])
{
- struct support_subprocess result = support_suprocess_init ();
+ struct support_subprocess result = support_subprocess_init ();
posix_spawn_file_actions_t fa;
/* posix_spawn_file_actions_init does not fail. */
xposix_spawn_file_actions_addclose (&fa, result.stdout_pipe[1]);
xposix_spawn_file_actions_addclose (&fa, result.stderr_pipe[1]);
- result.pid = xposix_spawn (file, &fa, NULL, argv, NULL);
+ result.pid = xposix_spawn (file, &fa, NULL, argv, environ);
xclose (result.stdout_pipe[1]);
xclose (result.stderr_pipe[1]);
return result;
}
+int
+support_subprogram_wait (const char *file, char *const argv[])
+{
+ posix_spawn_file_actions_t fa;
+
+ posix_spawn_file_actions_init (&fa);
+ struct support_subprocess res = support_subprocess_init ();
+
+ res.pid = xposix_spawn (file, &fa, NULL, argv, environ);
+
+ return support_process_wait (&res);
+}
+
int
support_process_wait (struct support_subprocess *proc)
{
/* Check for unexpected PLT reloc type. */
if (__builtin_expect (r_type == AARCH64_R(JUMP_SLOT), 1))
{
- if (map->l_mach.plt == 0)
- {
- /* Prelinking. */
- *reloc_addr += l_addr;
- return;
- }
-
if (__glibc_unlikely (map->l_info[DT_AARCH64 (VARIANT_PCS)] != NULL))
{
/* Check the symbol table for variant PCS symbols. */
}
}
- *reloc_addr = map->l_mach.plt;
+ if (map->l_mach.plt == 0)
+ *reloc_addr += l_addr;
+ else
+ *reloc_addr = map->l_mach.plt;
}
else if (__builtin_expect (r_type == AARCH64_R(TLSDESC), 1))
{
#define A_l x6
#define A_lw w6
#define A_h x7
-#define A_hw w7
#define B_l x8
#define B_lw w8
#define B_h x9
#define C_l x10
+#define C_lw w10
#define C_h x11
#define D_l x12
#define D_h x13
#define H_h srcend
#define tmp1 x14
-/* Copies are split into 3 main cases: small copies of up to 32 bytes,
- medium copies of 33..128 bytes which are fully unrolled. Large copies
- of more than 128 bytes align the destination and use an unrolled loop
- processing 64 bytes per iteration.
- In order to share code with memmove, small and medium copies read all
- data before writing, allowing any kind of overlap. So small, medium
- and large backwards memmoves are handled by falling through into memcpy.
- Overlapping large forward memmoves use a loop that copies backwards.
-*/
-
#ifndef MEMMOVE
# define MEMMOVE memmove
#endif
# define MEMCPY memcpy
#endif
-ENTRY_ALIGN (MEMMOVE, 6)
+/* This implementation supports both memcpy and memmove and shares most code.
+ It uses unaligned accesses and branchless sequences to keep the code small,
+ simple and improve performance.
- DELOUSE (0)
- DELOUSE (1)
- DELOUSE (2)
+ Copies are split into 3 main cases: small copies of up to 32 bytes, medium
+ copies of up to 128 bytes, and large copies. The overhead of the overlap
+ check in memmove is negligible since it is only required for large copies.
- sub tmp1, dstin, src
- cmp count, 128
- ccmp tmp1, count, 2, hi
- b.lo L(move_long)
-
- /* Common case falls through into memcpy. */
-END (MEMMOVE)
-libc_hidden_builtin_def (MEMMOVE)
-ENTRY (MEMCPY)
+ Large copies use a software pipelined loop processing 64 bytes per
+ iteration. The destination pointer is 16-byte aligned to minimize
+ unaligned accesses. The loop tail is handled by always copying 64 bytes
+ from the end.
+*/
+ENTRY_ALIGN (MEMCPY, 6)
DELOUSE (0)
DELOUSE (1)
DELOUSE (2)
- prfm PLDL1KEEP, [src]
add srcend, src, count
add dstend, dstin, count
- cmp count, 32
- b.ls L(copy32)
cmp count, 128
b.hi L(copy_long)
+ cmp count, 32
+ b.hi L(copy32_128)
- /* Medium copies: 33..128 bytes. */
+ /* Small copies: 0..32 bytes. */
+ cmp count, 16
+ b.lo L(copy16)
ldp A_l, A_h, [src]
- ldp B_l, B_h, [src, 16]
- ldp C_l, C_h, [srcend, -32]
ldp D_l, D_h, [srcend, -16]
- cmp count, 64
- b.hi L(copy128)
stp A_l, A_h, [dstin]
- stp B_l, B_h, [dstin, 16]
- stp C_l, C_h, [dstend, -32]
stp D_l, D_h, [dstend, -16]
ret
- .p2align 4
- /* Small copies: 0..32 bytes. */
-L(copy32):
- /* 16-32 bytes. */
- cmp count, 16
- b.lo 1f
- ldp A_l, A_h, [src]
- ldp B_l, B_h, [srcend, -16]
- stp A_l, A_h, [dstin]
- stp B_l, B_h, [dstend, -16]
- ret
- .p2align 4
-1:
- /* 8-15 bytes. */
- tbz count, 3, 1f
+ /* Copy 8-15 bytes. */
+L(copy16):
+ tbz count, 3, L(copy8)
ldr A_l, [src]
ldr A_h, [srcend, -8]
str A_l, [dstin]
str A_h, [dstend, -8]
ret
- .p2align 4
-1:
- /* 4-7 bytes. */
- tbz count, 2, 1f
+
+ .p2align 3
+ /* Copy 4-7 bytes. */
+L(copy8):
+ tbz count, 2, L(copy4)
ldr A_lw, [src]
- ldr A_hw, [srcend, -4]
+ ldr B_lw, [srcend, -4]
str A_lw, [dstin]
- str A_hw, [dstend, -4]
+ str B_lw, [dstend, -4]
ret
- /* Copy 0..3 bytes. Use a branchless sequence that copies the same
- byte 3 times if count==1, or the 2nd byte twice if count==2. */
-1:
- cbz count, 2f
+ /* Copy 0..3 bytes using a branchless sequence. */
+L(copy4):
+ cbz count, L(copy0)
lsr tmp1, count, 1
ldrb A_lw, [src]
- ldrb A_hw, [srcend, -1]
+ ldrb C_lw, [srcend, -1]
ldrb B_lw, [src, tmp1]
strb A_lw, [dstin]
strb B_lw, [dstin, tmp1]
- strb A_hw, [dstend, -1]
-2: ret
+ strb C_lw, [dstend, -1]
+L(copy0):
+ ret
+
+ .p2align 4
+ /* Medium copies: 33..128 bytes. */
+L(copy32_128):
+ ldp A_l, A_h, [src]
+ ldp B_l, B_h, [src, 16]
+ ldp C_l, C_h, [srcend, -32]
+ ldp D_l, D_h, [srcend, -16]
+ cmp count, 64
+ b.hi L(copy128)
+ stp A_l, A_h, [dstin]
+ stp B_l, B_h, [dstin, 16]
+ stp C_l, C_h, [dstend, -32]
+ stp D_l, D_h, [dstend, -16]
+ ret
.p2align 4
- /* Copy 65..128 bytes. Copy 64 bytes from the start and
- 64 bytes from the end. */
+ /* Copy 65..128 bytes. */
L(copy128):
ldp E_l, E_h, [src, 32]
ldp F_l, F_h, [src, 48]
+ cmp count, 96
+ b.ls L(copy96)
ldp G_l, G_h, [srcend, -64]
ldp H_l, H_h, [srcend, -48]
+ stp G_l, G_h, [dstend, -64]
+ stp H_l, H_h, [dstend, -48]
+L(copy96):
stp A_l, A_h, [dstin]
stp B_l, B_h, [dstin, 16]
stp E_l, E_h, [dstin, 32]
stp F_l, F_h, [dstin, 48]
- stp G_l, G_h, [dstend, -64]
- stp H_l, H_h, [dstend, -48]
stp C_l, C_h, [dstend, -32]
stp D_l, D_h, [dstend, -16]
ret
- /* Align DST to 16 byte alignment so that we don't cross cache line
- boundaries on both loads and stores. There are at least 128 bytes
- to copy, so copy 16 bytes unaligned and then align. The loop
- copies 64 bytes per iteration and prefetches one iteration ahead. */
-
.p2align 4
+ /* Copy more than 128 bytes. */
L(copy_long):
+ /* Copy 16 bytes and then align dst to 16-byte alignment. */
+ ldp D_l, D_h, [src]
and tmp1, dstin, 15
bic dst, dstin, 15
- ldp D_l, D_h, [src]
sub src, src, tmp1
add count, count, tmp1 /* Count is now 16 too large. */
ldp A_l, A_h, [src, 16]
ldp C_l, C_h, [src, 48]
ldp D_l, D_h, [src, 64]!
subs count, count, 128 + 16 /* Test and readjust count. */
- b.ls L(last64)
+ b.ls L(copy64_from_end)
+
L(loop64):
stp A_l, A_h, [dst, 16]
ldp A_l, A_h, [src, 16]
subs count, count, 64
b.hi L(loop64)
- /* Write the last full set of 64 bytes. The remainder is at most 64
- bytes, so it is safe to always copy 64 bytes from the end even if
- there is just 1 byte left. */
-L(last64):
+ /* Write the last iteration and copy 64 bytes from the end. */
+L(copy64_from_end):
ldp E_l, E_h, [srcend, -64]
stp A_l, A_h, [dst, 16]
ldp A_l, A_h, [srcend, -48]
stp C_l, C_h, [dstend, -16]
ret
- .p2align 4
-L(move_long):
- cbz tmp1, 3f
+END (MEMCPY)
+libc_hidden_builtin_def (MEMCPY)
+
+ENTRY_ALIGN (MEMMOVE, 4)
+ DELOUSE (0)
+ DELOUSE (1)
+ DELOUSE (2)
add srcend, src, count
add dstend, dstin, count
+ cmp count, 128
+ b.hi L(move_long)
+ cmp count, 32
+ b.hi L(copy32_128)
- /* Align dstend to 16 byte alignment so that we don't cross cache line
- boundaries on both loads and stores. There are at least 128 bytes
- to copy, so copy 16 bytes unaligned and then align. The loop
- copies 64 bytes per iteration and prefetches one iteration ahead. */
+ /* Small copies: 0..32 bytes. */
+ cmp count, 16
+ b.lo L(copy16)
+ ldp A_l, A_h, [src]
+ ldp D_l, D_h, [srcend, -16]
+ stp A_l, A_h, [dstin]
+ stp D_l, D_h, [dstend, -16]
+ ret
- and tmp1, dstend, 15
+ .p2align 4
+L(move_long):
+ /* Only use backward copy if there is an overlap. */
+ sub tmp1, dstin, src
+ cbz tmp1, L(copy0)
+ cmp tmp1, count
+ b.hs L(copy_long)
+
+ /* Large backwards copy for overlapping copies.
+ Copy 16 bytes and then align dst to 16-byte alignment. */
ldp D_l, D_h, [srcend, -16]
+ and tmp1, dstend, 15
sub srcend, srcend, tmp1
sub count, count, tmp1
ldp A_l, A_h, [srcend, -16]
ldp D_l, D_h, [srcend, -64]!
sub dstend, dstend, tmp1
subs count, count, 128
- b.ls 2f
+ b.ls L(copy64_from_start)
- nop
-1:
+L(loop64_backwards):
stp A_l, A_h, [dstend, -16]
ldp A_l, A_h, [srcend, -16]
stp B_l, B_h, [dstend, -32]
stp D_l, D_h, [dstend, -64]!
ldp D_l, D_h, [srcend, -64]!
subs count, count, 64
- b.hi 1b
+ b.hi L(loop64_backwards)
- /* Write the last full set of 64 bytes. The remainder is at most 64
- bytes, so it is safe to always copy 64 bytes from the start even if
- there is just 1 byte left. */
-2:
+ /* Write the last iteration and copy 64 bytes from the start. */
+L(copy64_from_start):
ldp G_l, G_h, [src, 48]
stp A_l, A_h, [dstend, -16]
ldp A_l, A_h, [src, 32]
stp A_l, A_h, [dstin, 32]
stp B_l, B_h, [dstin, 16]
stp C_l, C_h, [dstin]
-3: ret
+ ret
-END (MEMCPY)
-libc_hidden_builtin_def (MEMCPY)
+END (MEMMOVE)
+libc_hidden_builtin_def (MEMMOVE)
ifeq ($(subdir),string)
-sysdep_routines += memcpy_generic memcpy_thunderx memcpy_thunderx2 \
+sysdep_routines += memcpy_generic memcpy_advsimd memcpy_thunderx memcpy_thunderx2 \
memcpy_falkor memmove_falkor \
memset_generic memset_falkor memset_emag memset_kunpeng \
memchr_generic memchr_nosimd \
IFUNC_IMPL_ADD (array, i, memcpy, 1, __memcpy_thunderx)
IFUNC_IMPL_ADD (array, i, memcpy, 1, __memcpy_thunderx2)
IFUNC_IMPL_ADD (array, i, memcpy, 1, __memcpy_falkor)
+ IFUNC_IMPL_ADD (array, i, memcpy, 1, __memcpy_simd)
IFUNC_IMPL_ADD (array, i, memcpy, 1, __memcpy_generic))
IFUNC_IMPL (i, name, memmove,
IFUNC_IMPL_ADD (array, i, memmove, 1, __memmove_thunderx)
IFUNC_IMPL_ADD (array, i, memmove, 1, __memmove_thunderx2)
IFUNC_IMPL_ADD (array, i, memmove, 1, __memmove_falkor)
+ IFUNC_IMPL_ADD (array, i, memmove, 1, __memmove_simd)
IFUNC_IMPL_ADD (array, i, memmove, 1, __memmove_generic))
IFUNC_IMPL (i, name, memset,
/* Enable this on non-falkor processors too so that other cores
extern __typeof (__redirect_memcpy) __libc_memcpy;
extern __typeof (__redirect_memcpy) __memcpy_generic attribute_hidden;
+extern __typeof (__redirect_memcpy) __memcpy_simd attribute_hidden;
extern __typeof (__redirect_memcpy) __memcpy_thunderx attribute_hidden;
extern __typeof (__redirect_memcpy) __memcpy_thunderx2 attribute_hidden;
extern __typeof (__redirect_memcpy) __memcpy_falkor attribute_hidden;
libc_ifunc (__libc_memcpy,
(IS_THUNDERX (midr)
? __memcpy_thunderx
- : (IS_FALKOR (midr) || IS_PHECDA (midr) || IS_ARES (midr) || IS_KUNPENG920 (midr)
+ : (IS_FALKOR (midr) || IS_PHECDA (midr) || IS_KUNPENG920 (midr)
? __memcpy_falkor
: (IS_THUNDERX2 (midr) || IS_THUNDERX2PA (midr)
? __memcpy_thunderx2
- : __memcpy_generic))));
+ : (IS_NEOVERSE_N1 (midr) || IS_NEOVERSE_N2 (midr)
+ || IS_NEOVERSE_V1 (midr)
+ ? __memcpy_simd
+ : __memcpy_generic)))));
# undef memcpy
strong_alias (__libc_memcpy, memcpy);
--- /dev/null
+/* Generic optimized memcpy using SIMD.
+ Copyright (C) 2020 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/>. */
+
+#include <sysdep.h>
+
+/* Assumptions:
+ *
+ * ARMv8-a, AArch64, Advanced SIMD, unaligned accesses.
+ *
+ */
+
+#define dstin x0
+#define src x1
+#define count x2
+#define dst x3
+#define srcend x4
+#define dstend x5
+#define A_l x6
+#define A_lw w6
+#define A_h x7
+#define B_l x8
+#define B_lw w8
+#define B_h x9
+#define C_lw w10
+#define tmp1 x14
+
+#define A_q q0
+#define B_q q1
+#define C_q q2
+#define D_q q3
+#define E_q q4
+#define F_q q5
+#define G_q q6
+#define H_q q7
+
+
+/* This implementation supports both memcpy and memmove and shares most code.
+ It uses unaligned accesses and branchless sequences to keep the code small,
+ simple and improve performance.
+
+ Copies are split into 3 main cases: small copies of up to 32 bytes, medium
+ copies of up to 128 bytes, and large copies. The overhead of the overlap
+ check in memmove is negligible since it is only required for large copies.
+
+ Large copies use a software pipelined loop processing 64 bytes per
+ iteration. The destination pointer is 16-byte aligned to minimize
+ unaligned accesses. The loop tail is handled by always copying 64 bytes
+ from the end. */
+
+ENTRY (__memcpy_simd)
+ DELOUSE (0)
+ DELOUSE (1)
+ DELOUSE (2)
+
+ add srcend, src, count
+ add dstend, dstin, count
+ cmp count, 128
+ b.hi L(copy_long)
+ cmp count, 32
+ b.hi L(copy32_128)
+
+ /* Small copies: 0..32 bytes. */
+ cmp count, 16
+ b.lo L(copy16)
+ ldr A_q, [src]
+ ldr B_q, [srcend, -16]
+ str A_q, [dstin]
+ str B_q, [dstend, -16]
+ ret
+
+ /* Copy 8-15 bytes. */
+L(copy16):
+ tbz count, 3, L(copy8)
+ ldr A_l, [src]
+ ldr A_h, [srcend, -8]
+ str A_l, [dstin]
+ str A_h, [dstend, -8]
+ ret
+
+ /* Copy 4-7 bytes. */
+L(copy8):
+ tbz count, 2, L(copy4)
+ ldr A_lw, [src]
+ ldr B_lw, [srcend, -4]
+ str A_lw, [dstin]
+ str B_lw, [dstend, -4]
+ ret
+
+ /* Copy 0..3 bytes using a branchless sequence. */
+L(copy4):
+ cbz count, L(copy0)
+ lsr tmp1, count, 1
+ ldrb A_lw, [src]
+ ldrb C_lw, [srcend, -1]
+ ldrb B_lw, [src, tmp1]
+ strb A_lw, [dstin]
+ strb B_lw, [dstin, tmp1]
+ strb C_lw, [dstend, -1]
+L(copy0):
+ ret
+
+ .p2align 4
+ /* Medium copies: 33..128 bytes. */
+L(copy32_128):
+ ldp A_q, B_q, [src]
+ ldp C_q, D_q, [srcend, -32]
+ cmp count, 64
+ b.hi L(copy128)
+ stp A_q, B_q, [dstin]
+ stp C_q, D_q, [dstend, -32]
+ ret
+
+ .p2align 4
+ /* Copy 65..128 bytes. */
+L(copy128):
+ ldp E_q, F_q, [src, 32]
+ cmp count, 96
+ b.ls L(copy96)
+ ldp G_q, H_q, [srcend, -64]
+ stp G_q, H_q, [dstend, -64]
+L(copy96):
+ stp A_q, B_q, [dstin]
+ stp E_q, F_q, [dstin, 32]
+ stp C_q, D_q, [dstend, -32]
+ ret
+
+ /* Align loop64 below to 16 bytes. */
+ nop
+
+ /* Copy more than 128 bytes. */
+L(copy_long):
+ /* Copy 16 bytes and then align src to 16-byte alignment. */
+ ldr D_q, [src]
+ and tmp1, src, 15
+ bic src, src, 15
+ sub dst, dstin, tmp1
+ add count, count, tmp1 /* Count is now 16 too large. */
+ ldp A_q, B_q, [src, 16]
+ str D_q, [dstin]
+ ldp C_q, D_q, [src, 48]
+ subs count, count, 128 + 16 /* Test and readjust count. */
+ b.ls L(copy64_from_end)
+L(loop64):
+ stp A_q, B_q, [dst, 16]
+ ldp A_q, B_q, [src, 80]
+ stp C_q, D_q, [dst, 48]
+ ldp C_q, D_q, [src, 112]
+ add src, src, 64
+ add dst, dst, 64
+ subs count, count, 64
+ b.hi L(loop64)
+
+ /* Write the last iteration and copy 64 bytes from the end. */
+L(copy64_from_end):
+ ldp E_q, F_q, [srcend, -64]
+ stp A_q, B_q, [dst, 16]
+ ldp A_q, B_q, [srcend, -32]
+ stp C_q, D_q, [dst, 48]
+ stp E_q, F_q, [dstend, -64]
+ stp A_q, B_q, [dstend, -32]
+ ret
+
+END (__memcpy_simd)
+libc_hidden_builtin_def (__memcpy_simd)
+
+
+ENTRY (__memmove_simd)
+ DELOUSE (0)
+ DELOUSE (1)
+ DELOUSE (2)
+
+ add srcend, src, count
+ add dstend, dstin, count
+ cmp count, 128
+ b.hi L(move_long)
+ cmp count, 32
+ b.hi L(copy32_128)
+
+ /* Small moves: 0..32 bytes. */
+ cmp count, 16
+ b.lo L(copy16)
+ ldr A_q, [src]
+ ldr B_q, [srcend, -16]
+ str A_q, [dstin]
+ str B_q, [dstend, -16]
+ ret
+
+L(move_long):
+ /* Only use backward copy if there is an overlap. */
+ sub tmp1, dstin, src
+ cbz tmp1, L(move0)
+ cmp tmp1, count
+ b.hs L(copy_long)
+
+ /* Large backwards copy for overlapping copies.
+ Copy 16 bytes and then align srcend to 16-byte alignment. */
+L(copy_long_backwards):
+ ldr D_q, [srcend, -16]
+ and tmp1, srcend, 15
+ bic srcend, srcend, 15
+ sub count, count, tmp1
+ ldp A_q, B_q, [srcend, -32]
+ str D_q, [dstend, -16]
+ ldp C_q, D_q, [srcend, -64]
+ sub dstend, dstend, tmp1
+ subs count, count, 128
+ b.ls L(copy64_from_start)
+
+L(loop64_backwards):
+ str B_q, [dstend, -16]
+ str A_q, [dstend, -32]
+ ldp A_q, B_q, [srcend, -96]
+ str D_q, [dstend, -48]
+ str C_q, [dstend, -64]!
+ ldp C_q, D_q, [srcend, -128]
+ sub srcend, srcend, 64
+ subs count, count, 64
+ b.hi L(loop64_backwards)
+
+ /* Write the last iteration and copy 64 bytes from the start. */
+L(copy64_from_start):
+ ldp E_q, F_q, [src, 32]
+ stp A_q, B_q, [dstend, -32]
+ ldp A_q, B_q, [src]
+ stp C_q, D_q, [dstend, -64]
+ stp E_q, F_q, [dstin, 32]
+ stp A_q, B_q, [dstin]
+L(move0):
+ ret
+
+END (__memmove_simd)
+libc_hidden_builtin_def (__memmove_simd)
extern __typeof (__redirect_memmove) __libc_memmove;
extern __typeof (__redirect_memmove) __memmove_generic attribute_hidden;
+extern __typeof (__redirect_memmove) __memmove_simd attribute_hidden;
extern __typeof (__redirect_memmove) __memmove_thunderx attribute_hidden;
extern __typeof (__redirect_memmove) __memmove_thunderx2 attribute_hidden;
extern __typeof (__redirect_memmove) __memmove_falkor attribute_hidden;
? __memmove_falkor
: (IS_THUNDERX2 (midr) || IS_THUNDERX2PA (midr)
? __memmove_thunderx2
- : __memmove_generic))));
+ : (IS_NEOVERSE_N1 (midr) || IS_NEOVERSE_N2 (midr)
+ || IS_NEOVERSE_V1 (midr)
+ ? __memmove_simd
+ : __memmove_generic)))));
# undef memmove
strong_alias (__libc_memmove, memmove);
#endif
/* calculate the loc value */
cmeq datav.16b, datav.16b, #0
+#ifdef __AARCH64EB__
+ mov data1, datav.d[1]
+ mov data2, datav.d[0]
+#else
mov data1, datav.d[0]
mov data2, datav.d[1]
+#endif
cmp data1, 0
csel data1, data1, data2, ne
mov pos, 8
byte. */
cmeq datav.16b, datav.16b, #0
+#ifdef __AARCH64EB__
+ mov data1, datav.d[1]
+ mov data2, datav.d[0]
+#else
mov data1, datav.d[0]
mov data2, datav.d[1]
+#endif
cmp data1, 0
csel data1, data1, data2, ne
sub len, src, srcin
#define ENTRY(name) \
.globl C_SYMBOL_NAME(name); \
.type C_SYMBOL_NAME(name),%function; \
- .align 4; \
+ .p2align 6; \
C_LABEL(name) \
cfi_startproc; \
CALL_MCOUNT
mov dst, dstin /* Preserve dstin, we need to return it. */
cmp count, #64
- bge .Lcpy_not_short
+ bhs .Lcpy_not_short
/* Deal with small copies quickly by dropping straight into the
exit block. */
1:
subs tmp2, count, #64 /* Use tmp2 for count. */
- blt .Ltail63aligned
+ blo .Ltail63aligned
cmp tmp2, #512
- bge .Lcpy_body_long
+ bhs .Lcpy_body_long
.Lcpy_body_medium: /* Count in tmp2. */
#ifdef USE_VFP
add src, src, #64
vstr d1, [dst, #56]
add dst, dst, #64
- bge 1b
+ bhs 1b
tst tmp2, #0x3f
beq .Ldone
ldrd A_l, A_h, [src, #64]!
strd A_l, A_h, [dst, #64]!
subs tmp2, tmp2, #64
- bge 1b
+ bhs 1b
tst tmp2, #0x3f
bne 1f
ldr tmp2,[sp], #FRAME_SIZE
add src, src, #32
subs tmp2, tmp2, #prefetch_lines * 64 * 2
- blt 2f
+ blo 2f
1:
cpy_line_vfp d3, 0
cpy_line_vfp d4, 64
add dst, dst, #2 * 64
add src, src, #2 * 64
subs tmp2, tmp2, #prefetch_lines * 64
- bge 1b
+ bhs 1b
2:
cpy_tail_vfp d3, 0
1:
pld [src, #(3 * 64)]
subs count, count, #64
- ldrmi tmp2, [sp], #FRAME_SIZE
- bmi .Ltail63unaligned
+ ldrlo tmp2, [sp], #FRAME_SIZE
+ blo .Ltail63unaligned
pld [src, #(4 * 64)]
#ifdef USE_NEON
neon_load_multi d0-d3, src
neon_load_multi d4-d7, src
subs count, count, #64
- bmi 2f
+ blo 2f
1:
pld [src, #(4 * 64)]
neon_store_multi d0-d3, dst
neon_store_multi d4-d7, dst
neon_load_multi d4-d7, src
subs count, count, #64
- bpl 1b
+ bhs 1b
2:
neon_store_multi d0-d3, dst
neon_store_multi d4-d7, dst
cfi_remember_state
subs r2, r2, #4
- blt 8f
+ blo 8f
ands ip, r0, #3
PLD( pld [r1, #0] )
bne 9f
cfi_rel_offset (r6, 4)
cfi_rel_offset (r7, 8)
cfi_rel_offset (r8, 12)
- blt 5f
+ blo 5f
CALGN( ands ip, r1, #31 )
CALGN( rsb r3, ip, #32 )
#endif
PLD( pld [r1, #0] )
-2: PLD( subs r2, r2, #96 )
+2: PLD( cmp r2, #96 )
PLD( pld [r1, #28] )
- PLD( blt 4f )
+ PLD( blo 4f )
PLD( pld [r1, #60] )
PLD( pld [r1, #92] )
4: ldmia r1!, {r3, r4, r5, r6, r7, r8, ip, lr}
subs r2, r2, #32
stmia r0!, {r3, r4, r5, r6, r7, r8, ip, lr}
- bge 3b
- PLD( cmn r2, #96 )
- PLD( bge 4b )
+ bhs 3b
5: ands ip, r2, #28
rsb ip, ip, #32
strbge r4, [r0], #1
subs r2, r2, ip
strb lr, [r0], #1
- blt 8b
+ blo 8b
ands ip, r1, #3
beq 1b
.macro forward_copy_shift pull push
subs r2, r2, #28
- blt 14f
+ blo 14f
CALGN( ands ip, r1, #31 )
CALGN( rsb ip, ip, #32 )
cfi_rel_offset (r10, 16)
PLD( pld [r1, #0] )
- PLD( subs r2, r2, #96 )
+ PLD( cmp r2, #96 )
PLD( pld [r1, #28] )
- PLD( blt 13f )
+ PLD( blo 13f )
PLD( pld [r1, #60] )
PLD( pld [r1, #92] )
mov ip, ip, PULL #\pull
orr ip, ip, lr, PUSH #\push
stmia r0!, {r3, r4, r5, r6, r7, r8, r10, ip}
- bge 12b
- PLD( cmn r2, #96 )
- PLD( bge 13b )
+ bhs 12b
pop {r5 - r8, r10}
cfi_adjust_cfa_offset (-20)
add r1, r1, r2
add r0, r0, r2
subs r2, r2, #4
- blt 8f
+ blo 8f
ands ip, r0, #3
PLD( pld [r1, #-4] )
bne 9f
cfi_rel_offset (r6, 4)
cfi_rel_offset (r7, 8)
cfi_rel_offset (r8, 12)
- blt 5f
+ blo 5f
CALGN( ands ip, r1, #31 )
CALGN( sbcsne r4, ip, r2 ) @ C is always set here
#endif
PLD( pld [r1, #-4] )
-2: PLD( subs r2, r2, #96 )
+2: PLD( cmp r2, #96 )
PLD( pld [r1, #-32] )
- PLD( blt 4f )
+ PLD( blo 4f )
PLD( pld [r1, #-64] )
PLD( pld [r1, #-96] )
4: ldmdb r1!, {r3, r4, r5, r6, r7, r8, ip, lr}
subs r2, r2, #32
stmdb r0!, {r3, r4, r5, r6, r7, r8, ip, lr}
- bge 3b
- PLD( cmn r2, #96 )
- PLD( bge 4b )
+ bhs 3b
5: ands ip, r2, #28
rsb ip, ip, #32
strbge r4, [r0, #-1]!
subs r2, r2, ip
strb lr, [r0, #-1]!
- blt 8b
+ blo 8b
ands ip, r1, #3
beq 1b
.macro backward_copy_shift push pull
subs r2, r2, #28
- blt 14f
+ blo 14f
CALGN( ands ip, r1, #31 )
CALGN( rsb ip, ip, #32 )
cfi_rel_offset (r10, 16)
PLD( pld [r1, #-4] )
- PLD( subs r2, r2, #96 )
+ PLD( cmp r2, #96 )
PLD( pld [r1, #-32] )
- PLD( blt 13f )
+ PLD( blo 13f )
PLD( pld [r1, #-64] )
PLD( pld [r1, #-96] )
mov r4, r4, PUSH #\push
orr r4, r4, r3, PULL #\pull
stmdb r0!, {r4 - r8, r10, ip, lr}
- bge 12b
- PLD( cmn r2, #96 )
- PLD( bge 13b )
+ bhs 12b
pop {r5 - r8, r10}
cfi_adjust_cfa_offset (-20)
--- /dev/null
+/* Return backtrace of current program state. Arch-specific bits.
+ Copyright (C) 2020 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/>. */
+
+#ifndef _UNWIND_ARCH_H
+#define _UNWIND_ARCH_H
+
+#include <unwind.h>
+
+static inline void *
+unwind_arch_adjustment (void *prev, void *addr)
+{
+ return addr;
+}
+
+#endif
}
install:
- fdesc->ip = ip;
fdesc->gp = gp;
+ fdesc->ip = ip;
return (ElfW(Addr)) fdesc;
}
_dl_lookup_address (const void *address)
{
ElfW(Addr) addr = (ElfW(Addr)) address;
- unsigned int *desc, *gptr;
+ ElfW(Word) reloc_arg;
+ volatile unsigned int *desc;
+ unsigned int *gptr;
/* Return ADDR if the least-significant two bits of ADDR are not consistent
with ADDR being a linker defined function pointer. The normal value for
if (!_dl_read_access_allowed (desc))
return addr;
- /* Load first word of candidate descriptor. It should be a pointer
+ /* First load the relocation offset. */
+ reloc_arg = (ElfW(Word)) desc[1];
+ atomic_full_barrier();
+
+ /* Then load first word of candidate descriptor. It should be a pointer
with word alignment and point to memory that can be read. */
gptr = (unsigned int *) desc[0];
if (((unsigned int) gptr & 3) != 0
/* See if descriptor requires resolution. The following trampoline is
used in each global offset table for function resolution:
- ldw 0(r20),r22
- bv r0(r22)
+ ldw 0(r20),r21
+ bv r0(r21)
ldw 4(r20),r21
tramp: b,l .-12,r20
depwi 0,31,2,r20
if (gptr[0] == 0xea9f1fdd /* b,l .-12,r20 */
&& gptr[1] == 0xd6801c1e /* depwi 0,31,2,r20 */
&& (ElfW(Addr)) gptr[2] == elf_machine_resolve ())
- _dl_fixup ((struct link_map *) gptr[5], (ElfW(Word)) desc[1]);
+ {
+ struct link_map *l = (struct link_map *) gptr[5];
+
+ /* If gp has been resolved, we need to hunt for relocation offset. */
+ if (!(reloc_arg & PA_GP_RELOC))
+ reloc_arg = _dl_fix_reloc_arg (addr, l);
+
+ _dl_fixup (l, reloc_arg);
+ }
return (ElfW(Addr)) desc[0];
}
#define GOT_FROM_PLT_STUB (4*4)
#define PLT_ENTRY_SIZE (2*4)
+/* The gp slot in the function descriptor contains the relocation offset
+ before resolution. To distinguish between a resolved gp value and an
+ unresolved relocation offset we set an unused bit in the relocation
+ offset. This would allow us to do a synchronzied two word update
+ using this bit (interlocked update), but instead of waiting for the
+ update we simply recompute the gp value given that we know the ip. */
+#define PA_GP_RELOC 1
+
/* Initialize the function descriptor table before relocations */
static inline void
__hppa_init_bootstrap_fdesc_table (struct link_map *map)
volatile Elf32_Addr *rfdesc = reloc_addr;
/* map is the link_map for the caller, t is the link_map for the object
being called */
- rfdesc[1] = value.gp;
- /* Need to ensure that the gp is visible before the code
- entry point is updated */
- rfdesc[0] = value.ip;
+
+ /* We would like the function descriptor to be double word aligned. This
+ helps performance (ip and gp then reside on the same cache line) and
+ we can update the pair atomically with a single store. The linker
+ now ensures this alignment but we still have to handle old code. */
+ if ((unsigned int)reloc_addr & 7)
+ {
+ /* Need to ensure that the gp is visible before the code
+ entry point is updated */
+ rfdesc[1] = value.gp;
+ atomic_full_barrier();
+ rfdesc[0] = value.ip;
+ }
+ else
+ {
+ /* Update pair atomically with floating point store. */
+ union { ElfW(Word) v[2]; double d; } u;
+
+ u.v[0] = value.ip;
+ u.v[1] = value.gp;
+ *(volatile double *)rfdesc = u.d;
+ }
return value;
}
here. The trampoline code will load the proper
LTP and pass the reloc offset to the fixup
function. */
- fptr->gp = iplt - jmprel;
+ fptr->gp = (iplt - jmprel) | PA_GP_RELOC;
} /* r_sym != 0 */
else
{
--- /dev/null
+/* On-demand PLT fixup for shared objects. HPPA version.
+ Copyright (C) 2019 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, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+/* Clear PA_GP_RELOC bit in relocation offset. */
+#define reloc_offset (reloc_arg & ~PA_GP_RELOC)
+#define reloc_index (reloc_arg & ~PA_GP_RELOC) / sizeof (PLTREL)
+
+#include <elf/dl-runtime.c>
+
+/* The caller has encountered a partially relocated function descriptor.
+ The gp of the descriptor has been updated, but not the ip. We find
+ the function descriptor again and compute the relocation offset and
+ return that to the caller. The caller will continue on to call
+ _dl_fixup with the relocation offset. */
+
+ElfW(Word)
+attribute_hidden __attribute ((noinline)) ARCH_FIXUP_ATTRIBUTE
+_dl_fix_reloc_arg (struct fdesc *fptr, struct link_map *l)
+{
+ Elf32_Addr l_addr, iplt, jmprel, end_jmprel, r_type;
+ const Elf32_Rela *reloc;
+
+ l_addr = l->l_addr;
+ jmprel = D_PTR(l, l_info[DT_JMPREL]);
+ end_jmprel = jmprel + l->l_info[DT_PLTRELSZ]->d_un.d_val;
+
+ /* Look for the entry... */
+ for (iplt = jmprel; iplt < end_jmprel; iplt += sizeof (Elf32_Rela))
+ {
+ reloc = (const Elf32_Rela *) iplt;
+ r_type = ELF32_R_TYPE (reloc->r_info);
+
+ if (__builtin_expect (r_type == R_PARISC_IPLT, 1)
+ && fptr == (struct fdesc *) (reloc->r_offset + l_addr))
+ /* Found entry. Return the reloc offset. */
+ return iplt - jmprel;
+ }
+
+ /* Crash if we weren't passed a valid function pointer. */
+ ABORT_INSTRUCTION;
+ return 0;
+}
slow down __cffc when it attempts to call fixup to resolve function
descriptor references. Please refer to gcc/gcc/config/pa/fptr.c
- Enter with r19 = reloc offset, r20 = got-8, r21 = fixup ltp. */
+ Enter with r19 = reloc offset, r20 = got-8, r21 = fixup ltp, r22 = fp. */
/* RELOCATION MARKER: bl to provide gcc's __cffc with fixup loc. */
.text
copy %sp, %r1 /* Copy previous sp */
/* Save function result address (on entry) */
stwm %r28,128(%sp)
- /* Fillin some frame info to follow ABI */
+ /* Fill in some frame info to follow ABI */
stw %r1,-4(%sp) /* Previous sp */
stw %r21,-32(%sp) /* PIC register value */
/* Save input floating point registers. This must be done
in the new frame since the previous frame doesn't have
enough space */
- ldo -56(%sp),%r1
+ ldo -64(%sp),%r1
fstd,ma %fr4,-8(%r1)
fstd,ma %fr5,-8(%r1)
fstd,ma %fr6,-8(%r1)
+
+ /* Test PA_GP_RELOC bit. */
+ bb,>= %r19,31,2f /* branch if not reloc offset */
fstd,ma %fr7,-8(%r1)
/* Set up args to fixup func, needs only two arguments */
copy %r19,%r25 /* (2) reloc offset */
/* Call the real address resolver. */
- bl _dl_fixup,%rp
+3: bl _dl_fixup,%rp
copy %r21,%r19 /* set fixup func ltp */
/* While the linker will set a function pointer to NULL when it
copy %r29, %r19
/* Reload arguments fp args */
- ldo -56(%sp),%r1
+ ldo -64(%sp),%r1
fldd,ma -8(%r1),%fr4
fldd,ma -8(%r1),%fr5
fldd,ma -8(%r1),%fr6
bv %r0(%rp)
ldo -128(%sp),%sp
+2:
+ /* Set up args for _dl_fix_reloc_arg. */
+ copy %r22,%r26 /* (1) function pointer */
+ depi 0,31,2,%r26 /* clear least significant bits */
+ ldw 8+4(%r20),%r25 /* (2) got[1] == struct link_map */
+
+ /* Save ltp and link map arg for _dl_fixup. */
+ stw %r21,-56(%sp) /* ltp */
+ stw %r25,-60(%sp) /* struct link map */
+
+ /* Find reloc offset. */
+ bl _dl_fix_reloc_arg,%rp
+ copy %r21,%r19 /* set func ltp */
+
+ /* Set up args for _dl_fixup. */
+ ldw -56(%sp),%r21 /* ltp */
+ ldw -60(%sp),%r26 /* (1) struct link map */
+ b 3b
+ copy %ret0,%r25 /* (2) reloc offset */
.EXIT
.PROCEND
cfi_endproc
copy %sp, %r1 /* Copy previous sp */
/* Save function result address (on entry) */
stwm %r28,192(%sp)
- /* Fillin some frame info to follow ABI */
+ /* Fill in some frame info to follow ABI */
stw %r1,-4(%sp) /* Previous sp */
stw %r21,-32(%sp) /* PIC register value */
fstd,ma %fr5,8(%r1)
fstd,ma %fr6,8(%r1)
fstd,ma %fr7,8(%r1)
- /* 32-bit stack pointer and return register */
- stw %sp,-56(%sp)
- stw %r2,-52(%sp)
+ /* Test PA_GP_RELOC bit. */
+ bb,>= %r19,31,2f /* branch if not reloc offset */
+ /* 32-bit stack pointer */
+ stw %sp,-56(%sp)
/* Set up args to fixup func, needs five arguments */
ldw 8+4(%r20),%r26 /* (1) got[1] == struct link_map */
stw %r1, -52(%sp) /* (5) long int *framesizep */
/* Call the real address resolver. */
- bl _dl_profile_fixup,%rp
+3: bl _dl_profile_fixup,%rp
copy %r21,%r19 /* set fixup func ltp */
/* Load up the returned function descriptor */
fldd,ma 8(%r1),%fr5
fldd,ma 8(%r1),%fr6
fldd,ma 8(%r1),%fr7
- ldw -52(%sp),%rp
+
+ /* Reload rp register -(192+20) without adjusting stack */
+ ldw -212(%sp),%rp
/* Reload static link register -(192+16) without adjusting stack */
ldw -208(%sp),%r29
ldw -20(%sp),%rp
/* Return */
bv,n 0(%r2)
+
+2:
+ /* Set up args for _dl_fix_reloc_arg. */
+ copy %r22,%r26 /* (1) function pointer */
+ depi 0,31,2,%r26 /* clear least significant bits */
+ ldw 8+4(%r20),%r25 /* (2) got[1] == struct link_map */
+
+ /* Save ltp and link map arg for _dl_fixup. */
+ stw %r21,-92(%sp) /* ltp */
+ stw %r25,-116(%sp) /* struct link map */
+
+ /* Find reloc offset. */
+ bl _dl_fix_reloc_arg,%rp
+ copy %r21,%r19 /* set func ltp */
+
+ /* Restore fixup ltp. */
+ ldw -92(%sp),%r21 /* ltp */
+
+ /* Set up args to fixup func, needs five arguments */
+ ldw -116(%sp),%r26 /* (1) struct link map */
+ copy %ret0,%r25 /* (2) reloc offset */
+ stw %r25,-120(%sp) /* Save reloc offset */
+ ldw -212(%sp),%r24 /* (3) profile_fixup needs rp */
+ ldo -56(%sp),%r23 /* (4) La_hppa_regs */
+ ldo -112(%sp), %r1
+ b 3b
+ stw %r1, -52(%sp) /* (5) long int *framesizep */
.EXIT
.PROCEND
cfi_endproc
{
# ifndef RTLD_BOOTSTRAP
if (sym_map != map
- && sym_map->l_type != lt_executable
&& !sym_map->l_relocated)
{
const char *strtab
= (const char *) D_PTR (map, l_info[DT_STRTAB]);
- _dl_error_printf ("\
+ if (sym_map->l_type == lt_executable)
+ _dl_fatal_printf ("\
+%s: IFUNC symbol '%s' referenced in '%s' is defined in the executable \
+and creates an unsatisfiable circular dependency.\n",
+ RTLD_PROGNAME, strtab + refsym->st_name,
+ map->l_name);
+ else
+ _dl_error_printf ("\
%s: Relink `%s' with `%s' for IFUNC symbol `%s'\n",
- RTLD_PROGNAME, map->l_name,
- sym_map->l_name,
- strtab + refsym->st_name);
+ RTLD_PROGNAME, map->l_name,
+ sym_map->l_name,
+ strtab + refsym->st_name);
}
# endif
value = ((Elf32_Addr (*) (void)) value) ();
# define SETUP_PIC_REG(reg) \
.ifndef GET_PC_THUNK(reg); \
- .section .gnu.linkonce.t.GET_PC_THUNK(reg),"ax",@progbits; \
+ .section .text.GET_PC_THUNK(reg),"axG",@progbits,GET_PC_THUNK(reg),comdat; \
.globl GET_PC_THUNK(reg); \
.hidden GET_PC_THUNK(reg); \
.p2align 4; \
# define SETUP_PIC_REG_STR(reg) \
".ifndef " GET_PC_THUNK_STR (reg) "\n" \
- ".section .gnu.linkonce.t." GET_PC_THUNK_STR (reg) ",\"ax\",@progbits\n" \
+ ".section .text." GET_PC_THUNK_STR (reg) ",\"axG\",@progbits," \
+ GET_PC_THUNK_STR (reg) ",comdat\n" \
".globl " GET_PC_THUNK_STR (reg) "\n" \
".hidden " GET_PC_THUNK_STR (reg) "\n" \
".p2align 4\n" \
# <https://www.gnu.org/licenses/>.
ifeq ($(subdir),math)
-tests += test-canonical-ldbl-96 test-totalorderl-ldbl-96
+tests += test-canonical-ldbl-96 test-totalorderl-ldbl-96 test-sinl-pseudo
+ifeq ($(have-ssp),yes)
+CFLAGS-test-sinl-pseudo.c += -fstack-protector-all
endif
+endif # $(subdir) == math
return 0;
}
+ if ((i0 & 0x80000000) == 0)
+ {
+ /* Pseudo-zero and unnormal representations are not valid
+ representations of long double. We need to avoid stack
+ corruption in __kernel_rem_pio2, which expects input in a
+ particular normal form, but those representations do not need
+ to be consistently handled like any particular floating-point
+ value. */
+ y[1] = y[0] = __builtin_nanl ("");
+ return 0;
+ }
+
/* Split the 64 bits of the mantissa into three 24-bit integers
stored in a double array. */
exp = j0 - 23;
--- /dev/null
+/* Test sinl for pseudo-zeros and unnormals for ldbl-96 (bug 25487).
+ Copyright (C) 2020 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/>. */
+
+#include <math.h>
+#include <math_ldbl.h>
+#include <stdint.h>
+
+static int
+do_test (void)
+{
+ for (int i = 0; i < 64; i++)
+ {
+ uint64_t sig = i == 63 ? 0 : 1ULL << i;
+ long double ld;
+ SET_LDOUBLE_WORDS (ld, 0x4141,
+ sig >> 32, sig & 0xffffffffULL);
+ /* The requirement is that no stack overflow occurs when the
+ pseudo-zero or unnormal goes through range reduction. */
+ volatile long double ldr;
+ ldr = sinl (ld);
+ (void) ldr;
+ }
+ return 0;
+}
+
+#include <support/test-driver.c>
static int
do_system (const char *line)
{
- int status;
+ int status = -1;
+ int ret;
pid_t pid;
struct sigaction sa;
#ifndef _LIBC_REENTRANT
__posix_spawnattr_setflags (&spawn_attr,
POSIX_SPAWN_SETSIGDEF | POSIX_SPAWN_SETSIGMASK);
- status = __posix_spawn (&pid, SHELL_PATH, 0, &spawn_attr,
- (char *const[]){ (char*) SHELL_NAME,
- (char*) "-c",
- (char *) line, NULL },
- __environ);
+ ret = __posix_spawn (&pid, SHELL_PATH, 0, &spawn_attr,
+ (char *const[]){ (char *) SHELL_NAME,
+ (char *) "-c",
+ (char *) line, NULL },
+ __environ);
__posix_spawnattr_destroy (&spawn_attr);
- if (status == 0)
+ if (ret == 0)
{
/* Cancellation results in cleanup handlers running as exceptions in
the block where they were installed, so it is safe to reference
}
DO_UNLOCK ();
+ if (ret != 0)
+ __set_errno (ret);
+
return status;
}
#else
/* Position-dependent code does not require access to the GOT. */
# define __GLRO(rOUT, rGOT, member, offset) \
- lis rOUT,(member+LOWORD)@ha; \
- lwz rOUT,(member+LOWORD)@l(rOUT)
+ lis rOUT,(member)@ha; \
+ lwz rOUT,(member)@l(rOUT)
#endif /* PIC */
#endif /* __ASSEMBLER__ */
/* We don't care about the rest, since the IP value is at 'uc' field. */
};
+/* Test if the address match to the inside the trampoline code.
+ Up to and including kernel 5.8, returning from an interrupt or syscall to a
+ signal handler starts execution directly at the handler's entry point, with
+ LR set to address of the sigreturn trampoline (the vDSO symbol).
+ Newer kernels will branch to signal handler from the trampoline instead, so
+ checking the stacktrace against the vDSO entrypoint does not work in such
+ case.
+ The vDSO branches with a 'bctrl' instruction, so checking either the
+ vDSO address itself and the next instruction should cover all kernel
+ versions. */
static inline bool
is_sigtramp_address (void *nip)
{
#ifdef HAVE_SIGTRAMP_RT64
- if (nip == GLRO (dl_vdso_sigtramp_rt64))
+ if (nip == GLRO (dl_vdso_sigtramp_rt64) ||
+ nip == GLRO (dl_vdso_sigtramp_rt64) + 4)
return true;
#endif
return false;
__asm__ (".machine \"arch13\" \n\t"
".machinemode \"zarch_nohighgprs\" \n\t"
"lghi %%r0,16 \n\t"
- "mvcrl 0(%0),32(%0)" : : "a" (buf) : "memory", "r0");
+ "mvcrl 0(%0),32(%0) \n\t"
+ "vstrs %%v20,%%v20,%%v20,%%v20,0,2"
+ : : "a" (buf) : "memory", "r0");
}
EOF
if { ac_try='${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS --shared conftest.c
void testinsn (char *buf)
{
__asm__ ("lghi %%r0,16 \n\t"
- "mvcrl 0(%0),32(%0)" : : "a" (buf) : "memory", "r0");
+ "mvcrl 0(%0),32(%0) \n\t"
+ "vstrs %%v20,%%v20,%%v20,%%v20,0,2"
+ : : "a" (buf) : "memory", "r0");
}
EOF
if { ac_try='${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS --shared conftest.c
__asm__ (".machine \"arch13\" \n\t"
".machinemode \"zarch_nohighgprs\" \n\t"
"lghi %%r0,16 \n\t"
- "mvcrl 0(%0),32(%0)" : : "a" (buf) : "memory", "r0");
+ "mvcrl 0(%0),32(%0) \n\t"
+ "vstrs %%v20,%%v20,%%v20,%%v20,0,2"
+ : : "a" (buf) : "memory", "r0");
}
EOF
dnl test, if assembler supports S390 arch13 instructions
void testinsn (char *buf)
{
__asm__ ("lghi %%r0,16 \n\t"
- "mvcrl 0(%0),32(%0)" : : "a" (buf) : "memory", "r0");
+ "mvcrl 0(%0),32(%0) \n\t"
+ "vstrs %%v20,%%v20,%%v20,%%v20,0,2"
+ : : "a" (buf) : "memory", "r0");
}
EOF
dnl test, if assembler supports S390 arch13 zarch instructions as default
s390_libc_ifunc_expr (__redirect_memmove, memmove,
({
s390_libc_ifunc_expr_stfle_init ();
- (HAVE_MEMMOVE_ARCH13
+ (HAVE_MEMMOVE_ARCH13 && (hwcap & HWCAP_S390_VXRS_EXT2)
&& S390_IS_ARCH13_MIE3 (stfle_bits))
? MEMMOVE_ARCH13
: (HAVE_MEMMOVE_Z13 && (hwcap & HWCAP_S390_VX))
IFUNC_IMPL (i, name, memmove,
# if HAVE_MEMMOVE_ARCH13
IFUNC_IMPL_ADD (array, i, memmove,
- S390_IS_ARCH13_MIE3 (stfle_bits),
+ ((dl_hwcap & HWCAP_S390_VXRS_EXT2)
+ && S390_IS_ARCH13_MIE3 (stfle_bits)),
MEMMOVE_ARCH13)
# endif
# if HAVE_MEMMOVE_Z13
--- /dev/null
+sh/sh4/fpu
--- /dev/null
+sh/sh4/fpu
# P: optionally-NULL pointer to typed object (e.g., 3rd argument to sigaction)
# s: non-NULL string (e.g., 1st arg to open)
# S: optionally-NULL string (e.g., 1st arg to acct)
+# U: unsigned long int (32-bit types are zero-extended to 64-bit types)
# v: vararg scalar (e.g., optional 3rd arg to open)
# V: byte-per-page vector (3rd arg to mincore)
# W: wait status, optionally-NULL pointer to int (e.g., 2nd arg of wait4)
?:?????????) nargs=9;;
esac
+ # Derive the unsigned long int arguments from the argument signature
+ ulong_arg_1=0
+ ulong_arg_2=0
+ ulong_count=0
+ for U in $(echo $args | sed -e "s/.*:/:/" | grep -ob U)
+ do
+ ulong_count=$(expr $ulong_count + 1)
+ ulong_arg=$(echo $U | sed -e "s/:U//")
+ case $ulong_count in
+ 1)
+ ulong_arg_1=$ulong_arg
+ ;;
+ 2)
+ ulong_arg_2=$ulong_arg
+ ;;
+ *)
+ echo >&2 "$0: Too many unsigned long int arguments for syscall ($strong $weak)"
+ exit 2
+ esac
+ done
+
# Make sure only the first syscall rule is used, if multiple dirs
# define the same syscall.
echo ''
\$(make-target-directory)
(echo '#define SYSCALL_NAME $syscall'; \\
echo '#define SYSCALL_NARGS $nargs'; \\
+ echo '#define SYSCALL_ULONG_ARG_1 $ulong_arg_1'; \\
+ echo '#define SYSCALL_ULONG_ARG_2 $ulong_arg_2'; \\
echo '#define SYSCALL_SYMBOL $strong'; \\
echo '#define SYSCALL_NOERRNO $noerrno'; \\
echo '#define SYSCALL_ERRVAL $errval'; \\
defining a few macros:
SYSCALL_NAME syscall name
SYSCALL_NARGS number of arguments this call takes
+ SYSCALL_ULONG_ARG_1 the first unsigned long int argument this
+ call takes. 0 means that there are no
+ unsigned long int arguments.
+ SYSCALL_ULONG_ARG_2 the second unsigned long int argument this
+ call takes. 0 means that there is at most
+ one unsigned long int argument.
SYSCALL_SYMBOL primary symbol name
SYSCALL_NOERRNO 1 to define a no-errno version (see below)
SYSCALL_ERRVAL 1 to define an error-value version (see below)
/* This indirection is needed so that SYMBOL gets macro-expanded. */
#define syscall_hidden_def(SYMBOL) hidden_def (SYMBOL)
-#define T_PSEUDO(SYMBOL, NAME, N) PSEUDO (SYMBOL, NAME, N)
-#define T_PSEUDO_NOERRNO(SYMBOL, NAME, N) PSEUDO_NOERRNO (SYMBOL, NAME, N)
-#define T_PSEUDO_ERRVAL(SYMBOL, NAME, N) PSEUDO_ERRVAL (SYMBOL, NAME, N)
+/* If PSEUDOS_HAVE_ULONG_INDICES is defined, PSEUDO and T_PSEUDO macros
+ have 2 extra arguments for unsigned long int arguments:
+ Extra argument 1: Position of the first unsigned long int argument.
+ Extra argument 2: Position of the second unsigned long int argument.
+ */
+#ifndef PSEUDOS_HAVE_ULONG_INDICES
+# undef SYSCALL_ULONG_ARG_1
+# define SYSCALL_ULONG_ARG_1 0
+#endif
+
+#if SYSCALL_ULONG_ARG_1
+# define T_PSEUDO(SYMBOL, NAME, N, U1, U2) \
+ PSEUDO (SYMBOL, NAME, N, U1, U2)
+# define T_PSEUDO_NOERRNO(SYMBOL, NAME, N, U1, U2) \
+ PSEUDO_NOERRNO (SYMBOL, NAME, N, U1, U2)
+# define T_PSEUDO_ERRVAL(SYMBOL, NAME, N, U1, U2) \
+ PSEUDO_ERRVAL (SYMBOL, NAME, N, U1, U2)
+#else
+# define T_PSEUDO(SYMBOL, NAME, N) \
+ PSEUDO (SYMBOL, NAME, N)
+# define T_PSEUDO_NOERRNO(SYMBOL, NAME, N) \
+ PSEUDO_NOERRNO (SYMBOL, NAME, N)
+# define T_PSEUDO_ERRVAL(SYMBOL, NAME, N) \
+ PSEUDO_ERRVAL (SYMBOL, NAME, N)
+#endif
#define T_PSEUDO_END(SYMBOL) PSEUDO_END (SYMBOL)
#define T_PSEUDO_END_NOERRNO(SYMBOL) PSEUDO_END_NOERRNO (SYMBOL)
#define T_PSEUDO_END_ERRVAL(SYMBOL) PSEUDO_END_ERRVAL (SYMBOL)
/* This kind of system call stub never returns an error.
We return the return value register to the caller unexamined. */
+# if SYSCALL_ULONG_ARG_1
+T_PSEUDO_NOERRNO (SYSCALL_SYMBOL, SYSCALL_NAME, SYSCALL_NARGS,
+ SYSCALL_ULONG_ARG_1, SYSCALL_ULONG_ARG_2)
+# else
T_PSEUDO_NOERRNO (SYSCALL_SYMBOL, SYSCALL_NAME, SYSCALL_NARGS)
+# endif
ret_NOERRNO
T_PSEUDO_END_NOERRNO (SYSCALL_SYMBOL)
value, or zero for success. We may massage the kernel's return value
to meet that ABI, but we never set errno here. */
+# if SYSCALL_ULONG_ARG_1
+T_PSEUDO_ERRVAL (SYSCALL_SYMBOL, SYSCALL_NAME, SYSCALL_NARGS,
+ SYSCALL_ULONG_ARG_1, SYSCALL_ULONG_ARG_2)
+# else
T_PSEUDO_ERRVAL (SYSCALL_SYMBOL, SYSCALL_NAME, SYSCALL_NARGS)
+# endif
ret_ERRVAL
T_PSEUDO_END_ERRVAL (SYSCALL_SYMBOL)
/* This is a "normal" system call stub: if there is an error,
it returns -1 and sets errno. */
+# if SYSCALL_ULONG_ARG_1
+T_PSEUDO (SYSCALL_SYMBOL, SYSCALL_NAME, SYSCALL_NARGS,
+ SYSCALL_ULONG_ARG_1, SYSCALL_ULONG_ARG_2)
+# else
T_PSEUDO (SYSCALL_SYMBOL, SYSCALL_NAME, SYSCALL_NARGS)
+# endif
ret
T_PSEUDO_END (SYSCALL_SYMBOL)
link - link i:ss __link link
listen - listen i:ii __listen listen
lseek - lseek i:iii __libc_lseek __lseek lseek
-madvise - madvise i:pii __madvise madvise
+madvise - madvise i:pUi __madvise madvise
mkdir - mkdir i:si __mkdir mkdir
-mmap - mmap b:aniiii __mmap mmap
-mprotect - mprotect i:aii __mprotect mprotect
-munmap - munmap i:ai __munmap munmap
+mmap - mmap b:aUiiii __mmap mmap
+mprotect - mprotect i:aUi __mprotect mprotect
+munmap - munmap i:aU __munmap munmap
open - open Ci:siv __libc_open __open open
profil - profil i:piii __profil profil
ptrace - ptrace i:iiii ptrace
-read - read Ci:ibn __libc_read __read read
-readlink - readlink i:spi __readlink readlink
+read - read Ci:ibU __libc_read __read read
+readlink - readlink i:spU __readlink readlink
readv - readv Ci:ipi __readv readv
reboot - reboot i:i reboot
-recv - recv Ci:ibni __libc_recv recv
-recvfrom - recvfrom Ci:ibniBN __libc_recvfrom __recvfrom recvfrom
+recv - recv Ci:ibUi __libc_recv recv
+recvfrom - recvfrom Ci:ibUiBN __libc_recvfrom __recvfrom recvfrom
recvmsg - recvmsg Ci:ipi __libc_recvmsg __recvmsg recvmsg
rename - rename i:ss rename
rmdir - rmdir i:s __rmdir rmdir
select - select Ci:iPPPP __select __libc_select select
-send - send Ci:ibni __libc_send __send send
+send - send Ci:ibUi __libc_send __send send
sendmsg - sendmsg Ci:ipi __libc_sendmsg __sendmsg sendmsg
-sendto - sendto Ci:ibnibn __libc_sendto __sendto sendto
+sendto - sendto Ci:ibUibn __libc_sendto __sendto sendto
setdomain - setdomainname i:si setdomainname
setegid - setegid i:i __setegid setegid
seteuid - seteuid i:i __seteuid seteuid
unlink - unlink i:s __unlink unlink
utimes - utimes i:sp __utimes utimes
vhangup - vhangup i:i vhangup
-write - write Ci:ibn __libc_write __write write
+write - write Ci:ibU __libc_write __write write
writev - writev Ci:ipi __writev writev
setfsuid setfsgid epoll_pwait signalfd \
eventfd eventfd_read eventfd_write prlimit \
personality epoll_wait tee vmsplice splice \
- open_by_handle_at mlock2 pkey_mprotect pkey_set pkey_get
+ open_by_handle_at mlock2 pkey_mprotect pkey_set pkey_get \
+ prctl \
+ process_vm_readv process_vm_writev
CFLAGS-gethostid.c = -fexceptions
CFLAGS-tee.c = -fexceptions -fasynchronous-unwind-tables
#define __NR_clock_nanosleep 115
#define __NR_clock_settime 112
#define __NR_clone 220
+#define __NR_clone3 435
#define __NR_close 57
#define __NR_connect 203
#define __NR_copy_file_range 285
#define IS_PHECDA(midr) (MIDR_IMPLEMENTOR(midr) == 'h' \
&& MIDR_PARTNUM(midr) == 0x000)
-#define IS_ARES(midr) (MIDR_IMPLEMENTOR(midr) == 'A' \
- && MIDR_PARTNUM(midr) == 0xd0c)
+#define IS_NEOVERSE_N1(midr) (MIDR_IMPLEMENTOR(midr) == 'A' \
+ && MIDR_PARTNUM(midr) == 0xd0c)
+#define IS_NEOVERSE_N2(midr) (MIDR_IMPLEMENTOR(midr) == 'A' \
+ && MIDR_PARTNUM(midr) == 0xd49)
+#define IS_NEOVERSE_V1(midr) (MIDR_IMPLEMENTOR(midr) == 'A' \
+ && MIDR_PARTNUM(midr) == 0xd40)
#define IS_EMAG(midr) (MIDR_IMPLEMENTOR(midr) == 'P' \
&& MIDR_PARTNUM(midr) == 0x000)
libc.so: memalign
libc.so: realloc
libm.so: matherr
+# If outline atomics are used, libgcc (built outside of glibc) may
+# call __getauxval using the PLT.
+libc.so: __getauxval ?
# The dynamic loader needs __tls_get_addr for TLS.
ld.so: __tls_get_addr
# The main malloc is interposed into the dynamic linker, for
typedef intmax_t atomic_max_t;
typedef uintmax_t uatomic_max_t;
+#define atomic_full_barrier() __sync_synchronize ()
+
#define __HAVE_64B_ATOMICS 0
#define USE_ATOMIC_COMPILER_BUILTINS 0
+/* We use the compiler atomic load and store builtins as the generic
+ defines are not atomic. In particular, we need to use compare and
+ exchange for stores as the implementation is synthesized. */
+void __atomic_link_error (void);
+#define __atomic_check_size_ls(mem) \
+ if ((sizeof (*mem) != 1) && (sizeof (*mem) != 2) && sizeof (*mem) != 4) \
+ __atomic_link_error ();
+
+#define atomic_load_relaxed(mem) \
+ ({ __atomic_check_size_ls((mem)); \
+ __atomic_load_n ((mem), __ATOMIC_RELAXED); })
+#define atomic_load_acquire(mem) \
+ ({ __atomic_check_size_ls((mem)); \
+ __atomic_load_n ((mem), __ATOMIC_ACQUIRE); })
+
+#define atomic_store_relaxed(mem, val) \
+ do { \
+ __atomic_check_size_ls((mem)); \
+ __atomic_store_n ((mem), (val), __ATOMIC_RELAXED); \
+ } while (0)
+#define atomic_store_release(mem, val) \
+ do { \
+ __atomic_check_size_ls((mem)); \
+ __atomic_store_n ((mem), (val), __ATOMIC_RELEASE); \
+ } while (0)
+
/* XXX Is this actually correct? */
#define ATOMIC_EXCHANGE_USES_CAS 1
# define inline_syscall0(name,dummy) \
({ \
- register long __ret __asm__("r3"); \
- register long __r12 __asm__("r12") = name; \
+ register long int __ret __asm__("r3"); \
+ register long int __r12 __asm__("r12") = name; \
__asm__ __volatile__( "brki r14,8; nop;" \
: "=r"(__ret) \
: "r"(__r12) \
# define inline_syscall1(name,arg1) \
({ \
- register long __ret __asm__("r3"); \
- register long __r12 __asm__("r12") = name; \
- register long __r5 __asm__("r5") = (long)(arg1); \
+ long int __arg1 = (long int) (arg1); \
+ register long int __ret __asm__("r3"); \
+ register long int __r12 __asm__("r12") = name; \
+ register long int __r5 __asm__("r5") = __arg1; \
__asm__ __volatile__( "brki r14,8; nop;" \
: "=r"(__ret) \
: "r"(__r5), "r"(__r12) \
# define inline_syscall2(name,arg1,arg2) \
({ \
- register long __ret __asm__("r3"); \
- register long __r12 __asm__("r12") = name; \
- register long __r5 __asm__("r5") = (long)(arg1); \
- register long __r6 __asm__("r6") = (long)(arg2); \
+ long int __arg1 = (long int) (arg1); \
+ long int __arg2 = (long int) (arg2); \
+ register long int __ret __asm__("r3"); \
+ register long int __r12 __asm__("r12") = name; \
+ register long int __r5 __asm__("r5") = __arg1; \
+ register long int __r6 __asm__("r6") = __arg2; \
__asm__ __volatile__( "brki r14,8; nop;" \
: "=r"(__ret) \
: "r"(__r5), "r"(__r6), "r"(__r12) \
# define inline_syscall3(name,arg1,arg2,arg3) \
({ \
- register long __ret __asm__("r3"); \
- register long __r12 __asm__("r12") = name; \
- register long __r5 __asm__("r5") = (long)(arg1); \
- register long __r6 __asm__("r6") = (long)(arg2); \
- register long __r7 __asm__("r7") = (long)(arg3); \
+ long int __arg1 = (long int) (arg1); \
+ long int __arg2 = (long int) (arg2); \
+ long int __arg3 = (long int) (arg3); \
+ register long int __ret __asm__("r3"); \
+ register long int __r12 __asm__("r12") = name; \
+ register long int __r5 __asm__("r5") = __arg1; \
+ register long int __r6 __asm__("r6") = __arg2; \
+ register long int __r7 __asm__("r7") = __arg3; \
__asm__ __volatile__( "brki r14,8; nop;" \
: "=r"(__ret) \
: "r"(__r5), "r"(__r6), "r"(__r7), "r"(__r12) \
# define inline_syscall4(name,arg1,arg2,arg3,arg4) \
({ \
- register long __ret __asm__("r3"); \
- register long __r12 __asm__("r12") = name; \
- register long __r5 __asm__("r5") = (long)(arg1); \
- register long __r6 __asm__("r6") = (long)(arg2); \
- register long __r7 __asm__("r7") = (long)(arg3); \
- register long __r8 __asm__("r8") = (long)(arg4); \
+ long int __arg1 = (long int) (arg1); \
+ long int __arg2 = (long int) (arg2); \
+ long int __arg3 = (long int) (arg3); \
+ long int __arg4 = (long int) (arg4); \
+ register long int __ret __asm__("r3"); \
+ register long int __r12 __asm__("r12") = name; \
+ register long int __r5 __asm__("r5") = __arg1; \
+ register long int __r6 __asm__("r6") = __arg2; \
+ register long int __r7 __asm__("r7") = __arg3; \
+ register long int __r8 __asm__("r8") = __arg4; \
__asm__ __volatile__( "brki r14,8; nop;" \
: "=r"(__ret) \
: "r"(__r5), "r"(__r6), "r"(__r7), "r"(__r8),"r"(__r12) \
# define inline_syscall5(name,arg1,arg2,arg3,arg4,arg5) \
({ \
- register long __ret __asm__("r3"); \
- register long __r12 __asm__("r12") = name; \
- register long __r5 __asm__("r5") = (long)(arg1); \
- register long __r6 __asm__("r6") = (long)(arg2); \
- register long __r7 __asm__("r7") = (long)(arg3); \
- register long __r8 __asm__("r8") = (long)(arg4); \
- register long __r9 __asm__("r9") = (long)(arg5); \
+ long int __arg1 = (long int) (arg1); \
+ long int __arg2 = (long int) (arg2); \
+ long int __arg3 = (long int) (arg3); \
+ long int __arg4 = (long int) (arg4); \
+ long int __arg5 = (long int) (arg5); \
+ register long int __ret __asm__("r3"); \
+ register long int __r12 __asm__("r12") = name; \
+ register long int __r5 __asm__("r5") = __arg1; \
+ register long int __r6 __asm__("r6") = __arg2; \
+ register long int __r7 __asm__("r7") = __arg3; \
+ register long int __r8 __asm__("r8") = __arg4; \
+ register long int __r9 __asm__("r9") = __arg5; \
__asm__ __volatile__( "brki r14,8; nop;" \
: "=r"(__ret) \
: "r"(__r5), "r"(__r6), "r"(__r7), "r"(__r8),"r"(__r9), "r"(__r12) \
# define inline_syscall6(name,arg1,arg2,arg3,arg4,arg5,arg6) \
({ \
- register long __ret __asm__("r3"); \
- register long __r12 __asm__("r12") = name; \
- register long __r5 __asm__("r5") = (long)(arg1); \
- register long __r6 __asm__("r6") = (long)(arg2); \
- register long __r7 __asm__("r7") = (long)(arg3); \
- register long __r8 __asm__("r8") = (long)(arg4); \
- register long __r9 __asm__("r9") = (long)(arg5); \
- register long __r10 __asm__("r10") = (long)(arg6); \
+ long int __arg1 = (long int) (arg1); \
+ long int __arg2 = (long int) (arg2); \
+ long int __arg3 = (long int) (arg3); \
+ long int __arg4 = (long int) (arg4); \
+ long int __arg5 = (long int) (arg5); \
+ long int __arg6 = (long int) (arg6); \
+ register long int __ret __asm__("r3"); \
+ register long int __r12 __asm__("r12") = name; \
+ register long int __r5 __asm__("r5") = __arg1; \
+ register long int __r6 __asm__("r6") = __arg2; \
+ register long int __r7 __asm__("r7") = __arg3; \
+ register long int __r8 __asm__("r8") = __arg4; \
+ register long int __r9 __asm__("r9") = __arg5; \
+ register long int __r10 __asm__("r10") = __arg6; \
__asm__ __volatile__( "brki r14,8; nop;" \
: "=r"(__ret) \
: "r"(__r5), "r"(__r6), "r"(__r7), "r"(__r8),"r"(__r9), "r"(__r10), \
.text
.set nomips16
-/* long long __mips_syscall5 (long arg1, long arg2, long arg3, long arg4,
- long arg5,
- long number) */
+/* long long int __mips_syscall5 (long int arg1, long int arg2, long int arg3,
+ long int arg4, long int arg5,
+ long int number) */
ENTRY(__mips_syscall5)
lw v0, 20(sp)
.text
.set nomips16
-/* long long __mips_syscall6 (long arg1, long arg2, long arg3, long arg4,
- long arg5, long arg6,
- long number) */
+/* long long int __mips_syscall6 (long int arg1, long int arg2, long int arg3,
+ long int arg4, long int arg5, long int arg6,
+ long int number) */
ENTRY(__mips_syscall6)
lw v0, 24(sp)
.text
.set nomips16
-/* long long __mips_syscall7 (long arg1, long arg2, long arg3, long arg4,
- long arg5, long arg6, long arg7,
- long number) */
+/* long long int __mips_syscall7 (long int arg1, long int arg2, long int arg3,
+ long int arg4, long int arg5, long int arg6,
+ long int arg7,
+ long int number) */
ENTRY(__mips_syscall7)
lw v0, 28(sp)
#ifndef MIPS16_SYSCALL_H
#define MIPS16_SYSCALL_H 1
-long long __nomips16 __mips16_syscall0 (long number);
+long long int __nomips16 __mips16_syscall0 (long int number);
#define __mips16_syscall0(dummy, number) \
- __mips16_syscall0 ((long) (number))
+ __mips16_syscall0 ((long int) (number))
-long long __nomips16 __mips16_syscall1 (long a0,
- long number);
+long long int __nomips16 __mips16_syscall1 (long int a0,
+ long int number);
#define __mips16_syscall1(a0, number) \
- __mips16_syscall1 ((long) (a0), \
- (long) (number))
+ __mips16_syscall1 ((long int) (a0), \
+ (long int) (number))
-long long __nomips16 __mips16_syscall2 (long a0, long a1,
- long number);
+long long int __nomips16 __mips16_syscall2 (long int a0, long int a1,
+ long int number);
#define __mips16_syscall2(a0, a1, number) \
- __mips16_syscall2 ((long) (a0), (long) (a1), \
- (long) (number))
+ __mips16_syscall2 ((long int) (a0), (long int) (a1), \
+ (long int) (number))
-long long __nomips16 __mips16_syscall3 (long a0, long a1, long a2,
- long number);
+long long int __nomips16 __mips16_syscall3 (long int a0, long int a1,
+ long int a2,
+ long int number);
#define __mips16_syscall3(a0, a1, a2, number) \
- __mips16_syscall3 ((long) (a0), (long) (a1), (long) (a2), \
- (long) (number))
+ __mips16_syscall3 ((long int) (a0), (long int) (a1), \
+ (long int) (a2), \
+ (long int) (number))
-long long __nomips16 __mips16_syscall4 (long a0, long a1, long a2, long a3,
- long number);
+long long int __nomips16 __mips16_syscall4 (long int a0, long int a1,
+ long int a2, long int a3,
+ long int number);
#define __mips16_syscall4(a0, a1, a2, a3, number) \
- __mips16_syscall4 ((long) (a0), (long) (a1), (long) (a2), \
- (long) (a3), \
- (long) (number))
+ __mips16_syscall4 ((long int) (a0), (long int) (a1), \
+ (long int) (a2), (long int) (a3), \
+ (long int) (number))
/* The remaining ones use regular MIPS wrappers. */
#define __mips16_syscall5(a0, a1, a2, a3, a4, number) \
- __mips_syscall5 ((long) (a0), (long) (a1), (long) (a2), \
- (long) (a3), (long) (a4), \
- (long) (number))
+ __mips_syscall5 ((long int) (a0), (long int) (a1), \
+ (long int) (a2), (long int) (a3), \
+ (long int) (a4), \
+ (long int) (number))
#define __mips16_syscall6(a0, a1, a2, a3, a4, a5, number) \
- __mips_syscall6 ((long) (a0), (long) (a1), (long) (a2), \
- (long) (a3), (long) (a4), (long) (a5), \
- (long) (number))
+ __mips_syscall6 ((long int) (a0), (long int) (a1), \
+ (long int) (a2), (long int) (a3), \
+ (long int) (a4), (long int) (a5), \
+ (long int) (number))
#define __mips16_syscall7(a0, a1, a2, a3, a4, a5, a6, number) \
- __mips_syscall7 ((long) (a0), (long) (a1), (long) (a2), \
- (long) (a3), (long) (a4), (long) (a5), \
- (long) (a6), \
- (long) (number))
+ __mips_syscall7 ((long int) (a0), (long int) (a1), \
+ (long int) (a2), (long int) (a3), \
+ (long int) (a4), (long int) (a5), \
+ (long int) (a6), \
+ (long int) (number))
#endif
#undef __mips16_syscall0
-long long __nomips16
-__mips16_syscall0 (long number)
+long long int __nomips16
+__mips16_syscall0 (long int number)
{
union __mips_syscall_return ret;
ret.reg.v0 = INTERNAL_SYSCALL_MIPS16 (number, ret.reg.v1, 0);
#undef __mips16_syscall1
-long long __nomips16
-__mips16_syscall1 (long a0,
- long number)
+long long int __nomips16
+__mips16_syscall1 (long int a0,
+ long int number)
{
union __mips_syscall_return ret;
ret.reg.v0 = INTERNAL_SYSCALL_MIPS16 (number, ret.reg.v1, 1,
#undef __mips16_syscall2
-long long __nomips16
-__mips16_syscall2 (long a0, long a1,
- long number)
+long long int __nomips16
+__mips16_syscall2 (long int a0, long int a1,
+ long int number)
{
union __mips_syscall_return ret;
ret.reg.v0 = INTERNAL_SYSCALL_MIPS16 (number, ret.reg.v1, 2,
#undef __mips16_syscall3
-long long __nomips16
-__mips16_syscall3 (long a0, long a1, long a2,
- long number)
+long long int __nomips16
+__mips16_syscall3 (long int a0, long int a1, long int a2,
+ long int number)
{
union __mips_syscall_return ret;
ret.reg.v0 = INTERNAL_SYSCALL_MIPS16 (number, ret.reg.v1, 3,
#undef __mips16_syscall4
-long long __nomips16
-__mips16_syscall4 (long a0, long a1, long a2, long a3,
- long number)
+long long int __nomips16
+__mips16_syscall4 (long int a0, long int a1, long int a2, long int a3,
+ long int number)
{
union __mips_syscall_return ret;
ret.reg.v0 = INTERNAL_SYSCALL_MIPS16 (number, ret.reg.v1, 4,
#undef INLINE_SYSCALL
#define INLINE_SYSCALL(name, nr, args...) \
({ INTERNAL_SYSCALL_DECL (_sc_err); \
- long result_var = INTERNAL_SYSCALL (name, _sc_err, nr, args); \
+ long int result_var = INTERNAL_SYSCALL (name, _sc_err, nr, args); \
if ( INTERNAL_SYSCALL_ERROR_P (result_var, _sc_err) ) \
{ \
__set_errno (INTERNAL_SYSCALL_ERRNO (result_var, _sc_err)); \
result_var; })
#undef INTERNAL_SYSCALL_DECL
-#define INTERNAL_SYSCALL_DECL(err) long err __attribute__ ((unused))
+#define INTERNAL_SYSCALL_DECL(err) long int err __attribute__ ((unused))
#undef INTERNAL_SYSCALL_ERROR_P
-#define INTERNAL_SYSCALL_ERROR_P(val, err) ((void) (val), (long) (err))
+#define INTERNAL_SYSCALL_ERROR_P(val, err) ((void) (val), (long int) (err))
#undef INTERNAL_SYSCALL_ERRNO
#define INTERNAL_SYSCALL_ERRNO(val, err) ((void) (err), val)
union __mips_syscall_return
{
- long long val;
+ long long int val;
struct
{
- long v0;
- long v1;
+ long int v0;
+ long int v1;
}
reg;
};
#define internal_syscall0(v0_init, input, number, err, dummy...) \
({ \
- long _sys_result; \
+ long int _sys_result; \
\
{ \
- register long __s0 asm ("$16") __attribute__ ((unused)) \
+ register long int __s0 asm ("$16") __attribute__ ((unused)) \
= (number); \
- register long __v0 asm ("$2"); \
- register long __a3 asm ("$7"); \
+ register long int __v0 asm ("$2"); \
+ register long int __a3 asm ("$7"); \
__asm__ volatile ( \
".set\tnoreorder\n\t" \
v0_init \
#define internal_syscall1(v0_init, input, number, err, arg1) \
({ \
- long _sys_result; \
+ long int _sys_result; \
\
{ \
- register long __s0 asm ("$16") __attribute__ ((unused)) \
+ long int _arg1 = (long int) (arg1); \
+ register long int __s0 asm ("$16") __attribute__ ((unused)) \
= (number); \
- register long __v0 asm ("$2"); \
- register long __a0 asm ("$4") = (long) (arg1); \
- register long __a3 asm ("$7"); \
+ register long int __v0 asm ("$2"); \
+ register long int __a0 asm ("$4") = _arg1; \
+ register long int __a3 asm ("$7"); \
__asm__ volatile ( \
".set\tnoreorder\n\t" \
v0_init \
#define internal_syscall2(v0_init, input, number, err, arg1, arg2) \
({ \
- long _sys_result; \
+ long int _sys_result; \
\
{ \
- register long __s0 asm ("$16") __attribute__ ((unused)) \
+ long int _arg1 = (long int) (arg1); \
+ long int _arg2 = (long int) (arg2); \
+ register long int __s0 asm ("$16") __attribute__ ((unused)) \
= (number); \
- register long __v0 asm ("$2"); \
- register long __a0 asm ("$4") = (long) (arg1); \
- register long __a1 asm ("$5") = (long) (arg2); \
- register long __a3 asm ("$7"); \
+ register long int __v0 asm ("$2"); \
+ register long int __a0 asm ("$4") = _arg1; \
+ register long int __a1 asm ("$5") = _arg2; \
+ register long int __a3 asm ("$7"); \
__asm__ volatile ( \
".set\tnoreorder\n\t" \
v0_init \
#define internal_syscall3(v0_init, input, number, err, \
arg1, arg2, arg3) \
({ \
- long _sys_result; \
+ long int _sys_result; \
\
{ \
- register long __s0 asm ("$16") __attribute__ ((unused)) \
+ long int _arg1 = (long int) (arg1); \
+ long int _arg2 = (long int) (arg2); \
+ long int _arg3 = (long int) (arg3); \
+ register long int __s0 asm ("$16") __attribute__ ((unused)) \
= (number); \
- register long __v0 asm ("$2"); \
- register long __a0 asm ("$4") = (long) (arg1); \
- register long __a1 asm ("$5") = (long) (arg2); \
- register long __a2 asm ("$6") = (long) (arg3); \
- register long __a3 asm ("$7"); \
+ register long int __v0 asm ("$2"); \
+ register long int __a0 asm ("$4") = _arg1; \
+ register long int __a1 asm ("$5") = _arg2; \
+ register long int __a2 asm ("$6") = _arg3; \
+ register long int __a3 asm ("$7"); \
__asm__ volatile ( \
".set\tnoreorder\n\t" \
v0_init \
#define internal_syscall4(v0_init, input, number, err, \
arg1, arg2, arg3, arg4) \
({ \
- long _sys_result; \
+ long int _sys_result; \
\
{ \
- register long __s0 asm ("$16") __attribute__ ((unused)) \
+ long int _arg1 = (long int) (arg1); \
+ long int _arg2 = (long int) (arg2); \
+ long int _arg3 = (long int) (arg3); \
+ long int _arg4 = (long int) (arg4); \
+ register long int __s0 asm ("$16") __attribute__ ((unused)) \
= (number); \
- register long __v0 asm ("$2"); \
- register long __a0 asm ("$4") = (long) (arg1); \
- register long __a1 asm ("$5") = (long) (arg2); \
- register long __a2 asm ("$6") = (long) (arg3); \
- register long __a3 asm ("$7") = (long) (arg4); \
+ register long int __v0 asm ("$2"); \
+ register long int __a0 asm ("$4") = _arg1; \
+ register long int __a1 asm ("$5") = _arg2; \
+ register long int __a2 asm ("$6") = _arg3; \
+ register long int __a3 asm ("$7") = _arg4; \
__asm__ volatile ( \
".set\tnoreorder\n\t" \
v0_init \
compiler specifics required for the stack arguments to be pushed,
which would be the case if these syscalls were inlined. */
-long long __nomips16 __mips_syscall5 (long arg1, long arg2, long arg3,
- long arg4, long arg5,
- long number);
+long long int __nomips16 __mips_syscall5 (long int arg1, long int arg2,
+ long int arg3, long int arg4,
+ long int arg5,
+ long int number);
libc_hidden_proto (__mips_syscall5, nomips16)
#define internal_syscall5(v0_init, input, number, err, \
arg1, arg2, arg3, arg4, arg5) \
({ \
union __mips_syscall_return _sc_ret; \
- _sc_ret.val = __mips_syscall5 ((long) (arg1), \
- (long) (arg2), \
- (long) (arg3), \
- (long) (arg4), \
- (long) (arg5), \
- (long) (number)); \
+ _sc_ret.val = __mips_syscall5 ((long int) (arg1), \
+ (long int) (arg2), \
+ (long int) (arg3), \
+ (long int) (arg4), \
+ (long int) (arg5), \
+ (long int) (number)); \
err = _sc_ret.reg.v1; \
_sc_ret.reg.v0; \
})
-long long __nomips16 __mips_syscall6 (long arg1, long arg2, long arg3,
- long arg4, long arg5, long arg6,
- long number);
+long long int __nomips16 __mips_syscall6 (long int arg1, long int arg2,
+ long int arg3, long int arg4,
+ long int arg5, long int arg6,
+ long int number);
libc_hidden_proto (__mips_syscall6, nomips16)
#define internal_syscall6(v0_init, input, number, err, \
arg1, arg2, arg3, arg4, arg5, arg6) \
({ \
union __mips_syscall_return _sc_ret; \
- _sc_ret.val = __mips_syscall6 ((long) (arg1), \
- (long) (arg2), \
- (long) (arg3), \
- (long) (arg4), \
- (long) (arg5), \
- (long) (arg6), \
- (long) (number)); \
+ _sc_ret.val = __mips_syscall6 ((long int) (arg1), \
+ (long int) (arg2), \
+ (long int) (arg3), \
+ (long int) (arg4), \
+ (long int) (arg5), \
+ (long int) (arg6), \
+ (long int) (number)); \
err = _sc_ret.reg.v1; \
_sc_ret.reg.v0; \
})
-long long __nomips16 __mips_syscall7 (long arg1, long arg2, long arg3,
- long arg4, long arg5, long arg6,
- long arg7,
- long number);
+long long int __nomips16 __mips_syscall7 (long int arg1, long int arg2,
+ long int arg3, long int arg4,
+ long int arg5, long int arg6,
+ long int arg7,
+ long int number);
libc_hidden_proto (__mips_syscall7, nomips16)
#define internal_syscall7(v0_init, input, number, err, \
arg1, arg2, arg3, arg4, arg5, arg6, arg7) \
({ \
union __mips_syscall_return _sc_ret; \
- _sc_ret.val = __mips_syscall7 ((long) (arg1), \
- (long) (arg2), \
- (long) (arg3), \
- (long) (arg4), \
- (long) (arg5), \
- (long) (arg6), \
- (long) (arg7), \
- (long) (number)); \
+ _sc_ret.val = __mips_syscall7 ((long int) (arg1), \
+ (long int) (arg2), \
+ (long int) (arg3), \
+ (long int) (arg4), \
+ (long int) (arg5), \
+ (long int) (arg6), \
+ (long int) (arg7), \
+ (long int) (number)); \
err = _sc_ret.reg.v1; \
_sc_ret.reg.v0; \
})
/* Convert X to a long long, without losing any bits if it is one
already or warning if it is a 32-bit pointer. */
-#define ARGIFY(X) ((long long) (__typeof__ ((X) - (X))) (X))
+#define ARGIFY(X) ((long long int) (__typeof__ ((X) - (X))) (X))
/* Define a macro which expands into the inline wrapper code for a system
call. */
#undef INLINE_SYSCALL
#define INLINE_SYSCALL(name, nr, args...) \
({ INTERNAL_SYSCALL_DECL (_sc_err); \
- long result_var = INTERNAL_SYSCALL (name, _sc_err, nr, args); \
+ long int result_var = INTERNAL_SYSCALL (name, _sc_err, nr, args); \
if ( INTERNAL_SYSCALL_ERROR_P (result_var, _sc_err) ) \
{ \
__set_errno (INTERNAL_SYSCALL_ERRNO (result_var, _sc_err)); \
result_var; })
#undef INTERNAL_SYSCALL_DECL
-#define INTERNAL_SYSCALL_DECL(err) long err __attribute__ ((unused))
+#define INTERNAL_SYSCALL_DECL(err) long int err __attribute__ ((unused))
#undef INTERNAL_SYSCALL_ERROR_P
-#define INTERNAL_SYSCALL_ERROR_P(val, err) ((void) (val), (long) (err))
+#define INTERNAL_SYSCALL_ERROR_P(val, err) ((void) (val), (long int) (err))
#undef INTERNAL_SYSCALL_ERRNO
#define INTERNAL_SYSCALL_ERRNO(val, err) ((void) (err), val)
#define internal_syscall0(v0_init, input, number, err, dummy...) \
({ \
- long _sys_result; \
+ long int _sys_result; \
\
{ \
- register long long __s0 asm ("$16") __attribute__ ((unused)) \
+ register long long int __s0 asm ("$16") __attribute__ ((unused))\
= (number); \
- register long long __v0 asm ("$2"); \
- register long long __a3 asm ("$7"); \
+ register long long int __v0 asm ("$2"); \
+ register long long int __a3 asm ("$7"); \
__asm__ volatile ( \
".set\tnoreorder\n\t" \
v0_init \
#define internal_syscall1(v0_init, input, number, err, arg1) \
({ \
- long _sys_result; \
+ long int _sys_result; \
\
{ \
- register long long __s0 asm ("$16") __attribute__ ((unused)) \
+ long long int _arg1 = ARGIFY (arg1); \
+ register long long int __s0 asm ("$16") __attribute__ ((unused))\
= (number); \
- register long long __v0 asm ("$2"); \
- register long long __a0 asm ("$4") = ARGIFY (arg1); \
- register long long __a3 asm ("$7"); \
+ register long long int __v0 asm ("$2"); \
+ register long long int __a0 asm ("$4") = _arg1; \
+ register long long int __a3 asm ("$7"); \
__asm__ volatile ( \
".set\tnoreorder\n\t" \
v0_init \
#define internal_syscall2(v0_init, input, number, err, arg1, arg2) \
({ \
- long _sys_result; \
+ long int _sys_result; \
\
{ \
- register long long __s0 asm ("$16") __attribute__ ((unused)) \
+ long long int _arg1 = ARGIFY (arg1); \
+ long long int _arg2 = ARGIFY (arg2); \
+ register long long int __s0 asm ("$16") __attribute__ ((unused))\
= (number); \
- register long long __v0 asm ("$2"); \
- register long long __a0 asm ("$4") = ARGIFY (arg1); \
- register long long __a1 asm ("$5") = ARGIFY (arg2); \
- register long long __a3 asm ("$7"); \
+ register long long int __v0 asm ("$2"); \
+ register long long int __a0 asm ("$4") = _arg1; \
+ register long long int __a1 asm ("$5") = _arg2; \
+ register long long int __a3 asm ("$7"); \
__asm__ volatile ( \
".set\tnoreorder\n\t" \
v0_init \
#define internal_syscall3(v0_init, input, number, err, \
arg1, arg2, arg3) \
({ \
- long _sys_result; \
+ long int _sys_result; \
\
{ \
- register long long __s0 asm ("$16") __attribute__ ((unused)) \
+ long long int _arg1 = ARGIFY (arg1); \
+ long long int _arg2 = ARGIFY (arg2); \
+ long long int _arg3 = ARGIFY (arg3); \
+ register long long int __s0 asm ("$16") __attribute__ ((unused))\
= (number); \
- register long long __v0 asm ("$2"); \
- register long long __a0 asm ("$4") = ARGIFY (arg1); \
- register long long __a1 asm ("$5") = ARGIFY (arg2); \
- register long long __a2 asm ("$6") = ARGIFY (arg3); \
- register long long __a3 asm ("$7"); \
+ register long long int __v0 asm ("$2"); \
+ register long long int __a0 asm ("$4") = _arg1; \
+ register long long int __a1 asm ("$5") = _arg2; \
+ register long long int __a2 asm ("$6") = _arg3; \
+ register long long int __a3 asm ("$7"); \
__asm__ volatile ( \
".set\tnoreorder\n\t" \
v0_init \
#define internal_syscall4(v0_init, input, number, err, \
arg1, arg2, arg3, arg4) \
({ \
- long _sys_result; \
+ long int _sys_result; \
\
{ \
- register long long __s0 asm ("$16") __attribute__ ((unused)) \
+ long long int _arg1 = ARGIFY (arg1); \
+ long long int _arg2 = ARGIFY (arg2); \
+ long long int _arg3 = ARGIFY (arg3); \
+ long long int _arg4 = ARGIFY (arg4); \
+ register long long int __s0 asm ("$16") __attribute__ ((unused))\
= (number); \
- register long long __v0 asm ("$2"); \
- register long long __a0 asm ("$4") = ARGIFY (arg1); \
- register long long __a1 asm ("$5") = ARGIFY (arg2); \
- register long long __a2 asm ("$6") = ARGIFY (arg3); \
- register long long __a3 asm ("$7") = ARGIFY (arg4); \
+ register long long int __v0 asm ("$2"); \
+ register long long int __a0 asm ("$4") = _arg1; \
+ register long long int __a1 asm ("$5") = _arg2; \
+ register long long int __a2 asm ("$6") = _arg3; \
+ register long long int __a3 asm ("$7") = _arg4; \
__asm__ volatile ( \
".set\tnoreorder\n\t" \
v0_init \
#define internal_syscall5(v0_init, input, number, err, \
arg1, arg2, arg3, arg4, arg5) \
({ \
- long _sys_result; \
+ long int _sys_result; \
\
{ \
- register long long __s0 asm ("$16") __attribute__ ((unused)) \
+ long long int _arg1 = ARGIFY (arg1); \
+ long long int _arg2 = ARGIFY (arg2); \
+ long long int _arg3 = ARGIFY (arg3); \
+ long long int _arg4 = ARGIFY (arg4); \
+ long long int _arg5 = ARGIFY (arg5); \
+ register long long int __s0 asm ("$16") __attribute__ ((unused))\
= (number); \
- register long long __v0 asm ("$2"); \
- register long long __a0 asm ("$4") = ARGIFY (arg1); \
- register long long __a1 asm ("$5") = ARGIFY (arg2); \
- register long long __a2 asm ("$6") = ARGIFY (arg3); \
- register long long __a3 asm ("$7") = ARGIFY (arg4); \
- register long long __a4 asm ("$8") = ARGIFY (arg5); \
+ register long long int __v0 asm ("$2"); \
+ register long long int __a0 asm ("$4") = _arg1; \
+ register long long int __a1 asm ("$5") = _arg2; \
+ register long long int __a2 asm ("$6") = _arg3; \
+ register long long int __a3 asm ("$7") = _arg4; \
+ register long long int __a4 asm ("$8") = _arg5; \
__asm__ volatile ( \
".set\tnoreorder\n\t" \
v0_init \
#define internal_syscall6(v0_init, input, number, err, \
arg1, arg2, arg3, arg4, arg5, arg6) \
({ \
- long _sys_result; \
+ long int _sys_result; \
\
{ \
- register long long __s0 asm ("$16") __attribute__ ((unused)) \
+ long long int _arg1 = ARGIFY (arg1); \
+ long long int _arg2 = ARGIFY (arg2); \
+ long long int _arg3 = ARGIFY (arg3); \
+ long long int _arg4 = ARGIFY (arg4); \
+ long long int _arg5 = ARGIFY (arg5); \
+ long long int _arg6 = ARGIFY (arg6); \
+ register long long int __s0 asm ("$16") __attribute__ ((unused))\
= (number); \
- register long long __v0 asm ("$2"); \
- register long long __a0 asm ("$4") = ARGIFY (arg1); \
- register long long __a1 asm ("$5") = ARGIFY (arg2); \
- register long long __a2 asm ("$6") = ARGIFY (arg3); \
- register long long __a3 asm ("$7") = ARGIFY (arg4); \
- register long long __a4 asm ("$8") = ARGIFY (arg5); \
- register long long __a5 asm ("$9") = ARGIFY (arg6); \
+ register long long int __v0 asm ("$2"); \
+ register long long int __a0 asm ("$4") = _arg1; \
+ register long long int __a1 asm ("$5") = _arg2; \
+ register long long int __a2 asm ("$6") = _arg3; \
+ register long long int __a3 asm ("$7") = _arg4; \
+ register long long int __a4 asm ("$8") = _arg5; \
+ register long long int __a5 asm ("$9") = _arg6; \
__asm__ volatile ( \
".set\tnoreorder\n\t" \
v0_init \
#undef INLINE_SYSCALL
#define INLINE_SYSCALL(name, nr, args...) \
({ INTERNAL_SYSCALL_DECL (_sc_err); \
- long result_var = INTERNAL_SYSCALL (name, _sc_err, nr, args); \
+ long int result_var = INTERNAL_SYSCALL (name, _sc_err, nr, args); \
if ( INTERNAL_SYSCALL_ERROR_P (result_var, _sc_err) ) \
{ \
__set_errno (INTERNAL_SYSCALL_ERRNO (result_var, _sc_err)); \
result_var; })
#undef INTERNAL_SYSCALL_DECL
-#define INTERNAL_SYSCALL_DECL(err) long err __attribute__ ((unused))
+#define INTERNAL_SYSCALL_DECL(err) long int err __attribute__ ((unused))
#undef INTERNAL_SYSCALL_ERROR_P
-#define INTERNAL_SYSCALL_ERROR_P(val, err) ((void) (val), (long) (err))
+#define INTERNAL_SYSCALL_ERROR_P(val, err) ((void) (val), (long int) (err))
#undef INTERNAL_SYSCALL_ERRNO
#define INTERNAL_SYSCALL_ERRNO(val, err) ((void) (err), val)
#define internal_syscall0(v0_init, input, number, err, dummy...) \
({ \
- long _sys_result; \
+ long int _sys_result; \
\
{ \
- register long __s0 asm ("$16") __attribute__ ((unused)) \
+ register long int __s0 asm ("$16") __attribute__ ((unused)) \
= (number); \
- register long __v0 asm ("$2"); \
- register long __a3 asm ("$7"); \
+ register long int __v0 asm ("$2"); \
+ register long int __a3 asm ("$7"); \
__asm__ volatile ( \
".set\tnoreorder\n\t" \
v0_init \
#define internal_syscall1(v0_init, input, number, err, arg1) \
({ \
- long _sys_result; \
+ long int _sys_result; \
\
{ \
- register long __s0 asm ("$16") __attribute__ ((unused)) \
+ long int _arg1 = (long int) (arg1); \
+ register long int __s0 asm ("$16") __attribute__ ((unused)) \
= (number); \
- register long __v0 asm ("$2"); \
- register long __a0 asm ("$4") = (long) (arg1); \
- register long __a3 asm ("$7"); \
+ register long int __v0 asm ("$2"); \
+ register long int __a0 asm ("$4") = _arg1; \
+ register long int __a3 asm ("$7"); \
__asm__ volatile ( \
".set\tnoreorder\n\t" \
v0_init \
#define internal_syscall2(v0_init, input, number, err, arg1, arg2) \
({ \
- long _sys_result; \
+ long int _sys_result; \
\
{ \
- register long __s0 asm ("$16") __attribute__ ((unused)) \
+ long int _arg1 = (long int) (arg1); \
+ long int _arg2 = (long int) (arg2); \
+ register long int __s0 asm ("$16") __attribute__ ((unused)) \
= (number); \
- register long __v0 asm ("$2"); \
- register long __a0 asm ("$4") = (long) (arg1); \
- register long __a1 asm ("$5") = (long) (arg2); \
- register long __a3 asm ("$7"); \
+ register long int __v0 asm ("$2"); \
+ register long int __a0 asm ("$4") = _arg1; \
+ register long int __a1 asm ("$5") = _arg2; \
+ register long int __a3 asm ("$7"); \
__asm__ volatile ( \
".set\tnoreorder\n\t" \
v0_init \
#define internal_syscall3(v0_init, input, number, err, \
arg1, arg2, arg3) \
({ \
- long _sys_result; \
+ long int _sys_result; \
\
{ \
- register long __s0 asm ("$16") __attribute__ ((unused)) \
+ long int _arg1 = (long int) (arg1); \
+ long int _arg2 = (long int) (arg2); \
+ long int _arg3 = (long int) (arg3); \
+ register long int __s0 asm ("$16") __attribute__ ((unused)) \
= (number); \
- register long __v0 asm ("$2"); \
- register long __a0 asm ("$4") = (long) (arg1); \
- register long __a1 asm ("$5") = (long) (arg2); \
- register long __a2 asm ("$6") = (long) (arg3); \
- register long __a3 asm ("$7"); \
+ register long int __v0 asm ("$2"); \
+ register long int __a0 asm ("$4") = _arg1; \
+ register long int __a1 asm ("$5") = _arg2; \
+ register long int __a2 asm ("$6") = _arg3; \
+ register long int __a3 asm ("$7"); \
__asm__ volatile ( \
".set\tnoreorder\n\t" \
v0_init \
#define internal_syscall4(v0_init, input, number, err, \
arg1, arg2, arg3, arg4) \
({ \
- long _sys_result; \
+ long int _sys_result; \
\
{ \
- register long __s0 asm ("$16") __attribute__ ((unused)) \
+ long int _arg1 = (long int) (arg1); \
+ long int _arg2 = (long int) (arg2); \
+ long int _arg3 = (long int) (arg3); \
+ long int _arg4 = (long int) (arg4); \
+ register long int __s0 asm ("$16") __attribute__ ((unused)) \
= (number); \
- register long __v0 asm ("$2"); \
- register long __a0 asm ("$4") = (long) (arg1); \
- register long __a1 asm ("$5") = (long) (arg2); \
- register long __a2 asm ("$6") = (long) (arg3); \
- register long __a3 asm ("$7") = (long) (arg4); \
+ register long int __v0 asm ("$2"); \
+ register long int __a0 asm ("$4") = _arg1; \
+ register long int __a1 asm ("$5") = _arg2; \
+ register long int __a2 asm ("$6") = _arg3; \
+ register long int __a3 asm ("$7") = _arg4; \
__asm__ volatile ( \
".set\tnoreorder\n\t" \
v0_init \
#define internal_syscall5(v0_init, input, number, err, \
arg1, arg2, arg3, arg4, arg5) \
({ \
- long _sys_result; \
+ long int _sys_result; \
\
{ \
- register long __s0 asm ("$16") __attribute__ ((unused)) \
+ long int _arg1 = (long int) (arg1); \
+ long int _arg2 = (long int) (arg2); \
+ long int _arg3 = (long int) (arg3); \
+ long int _arg4 = (long int) (arg4); \
+ long int _arg5 = (long int) (arg5); \
+ register long int __s0 asm ("$16") __attribute__ ((unused)) \
= (number); \
- register long __v0 asm ("$2"); \
- register long __a0 asm ("$4") = (long) (arg1); \
- register long __a1 asm ("$5") = (long) (arg2); \
- register long __a2 asm ("$6") = (long) (arg3); \
- register long __a3 asm ("$7") = (long) (arg4); \
- register long __a4 asm ("$8") = (long) (arg5); \
+ register long int __v0 asm ("$2"); \
+ register long int __a0 asm ("$4") = _arg1; \
+ register long int __a1 asm ("$5") = _arg2; \
+ register long int __a2 asm ("$6") = _arg3; \
+ register long int __a3 asm ("$7") = _arg4; \
+ register long int __a4 asm ("$8") = _arg5; \
__asm__ volatile ( \
".set\tnoreorder\n\t" \
v0_init \
#define internal_syscall6(v0_init, input, number, err, \
arg1, arg2, arg3, arg4, arg5, arg6) \
({ \
- long _sys_result; \
+ long int _sys_result; \
\
{ \
- register long __s0 asm ("$16") __attribute__ ((unused)) \
+ long int _arg1 = (long int) (arg1); \
+ long int _arg2 = (long int) (arg2); \
+ long int _arg3 = (long int) (arg3); \
+ long int _arg4 = (long int) (arg4); \
+ long int _arg5 = (long int) (arg5); \
+ long int _arg6 = (long int) (arg6); \
+ register long int __s0 asm ("$16") __attribute__ ((unused)) \
= (number); \
- register long __v0 asm ("$2"); \
- register long __a0 asm ("$4") = (long) (arg1); \
- register long __a1 asm ("$5") = (long) (arg2); \
- register long __a2 asm ("$6") = (long) (arg3); \
- register long __a3 asm ("$7") = (long) (arg4); \
- register long __a4 asm ("$8") = (long) (arg5); \
- register long __a5 asm ("$9") = (long) (arg6); \
+ register long int __v0 asm ("$2"); \
+ register long int __a0 asm ("$4") = _arg1; \
+ register long int __a1 asm ("$5") = _arg2; \
+ register long int __a2 asm ("$6") = _arg3; \
+ register long int __a3 asm ("$7") = _arg4; \
+ register long int __a4 asm ("$8") = _arg5; \
+ register long int __a5 asm ("$9") = _arg6; \
__asm__ volatile ( \
".set\tnoreorder\n\t" \
v0_init \
#include <sys/asm.h>
/* Usage:
- long syscall (syscall_number, arg1, arg2, arg3, arg4, arg5, arg6, arg7)
+ long int syscall (syscall_number, arg1, arg2, arg3, arg4, arg5, arg6, arg7)
We need to do some arg shifting, syscall_number will be in v0. */
the INTERNAL_SYSCALL_{ERROR_P,ERRNO} macros work correctly. */
#define INTERNAL_VSYSCALL_CALL(funcptr, err, nr, args...) \
({ \
- long _ret = funcptr (args); \
- err = ((unsigned long) (_ret) >= (unsigned long) -4095L); \
+ long int _ret = funcptr (args); \
+ err = ((unsigned long int) (_ret) >= (unsigned long int) -4095L); \
if (err) \
_ret = -_ret; \
_ret; \
--- /dev/null
+/* Return backtrace of current program state. Arch-specific bits.
+ Copyright (C) 2020 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/>. */
+
+#ifndef _UNWIND_ARCH_H
+#define _UNWIND_ARCH_H
+
+#include <stdint.h>
+
+/* MIPS fallback code handle a frame where its FDE can not be obtained
+ (for instance a signal frame) by reading the kernel allocated signal frame
+ and adding '2' to the value of 'sc_pc' [1]. The added value is used to
+ recognize an end of an EH region on mips16 [2].
+
+ The idea here is to adjust the obtained signal frame ADDR value and remove
+ the libgcc added value by checking if the previous frame is a signal frame
+ one.
+
+ [1] libgcc/config/mips/linux-unwind.h from gcc code.
+ [2] gcc/config/mips/mips.h from gcc code. */
+
+static inline void *
+unwind_arch_adjustment (void *prev, void *addr)
+{
+ uint32_t *pc = (uint32_t *) prev;
+
+ if (pc == NULL)
+ return addr;
+
+ /* For MIPS16 or microMIPS frame libgcc makes no adjustment. */
+ if ((uintptr_t) pc & 0x3)
+ return addr;
+
+ /* The vDSO containes either
+
+ 24021061 li v0, 0x1061 (rt_sigreturn)
+ 0000000c syscall
+ or
+ 24021017 li v0, 0x1017 (sigreturn)
+ 0000000c syscall */
+ if (pc[1] != 0x0000000c)
+ return addr;
+#if _MIPS_SIM == _ABIO32
+ if (pc[0] == (0x24020000 | __NR_sigreturn))
+ return (void *) ((uintptr_t) addr - 2);
+#endif
+ if (pc[0] == (0x24020000 | __NR_rt_sigreturn))
+ return (void *) ((uintptr_t) addr - 2);
+
+ return addr;
+}
+
+#endif
#include <sysdep.h>
#include <shlib-compat.h>
#include <errno.h>
+#include <linux/posix_types.h> /* For __kernel_mode_t. */
#ifndef DEFAULT_VERSION
# ifndef __ASSUME_SYSVIPC_BROKEN_MODE_T
int ret = msgctl_syscall (msqid, cmd, buf);
-#ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T
if (ret >= 0)
{
switch (cmd)
case IPC_STAT:
case MSG_STAT:
case MSG_STAT_ANY:
+#ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T
buf->msg_perm.mode >>= 16;
+#else
+ /* Old Linux kernel versions might not clear the mode padding. */
+ if (sizeof ((struct msqid_ds){0}.msg_perm.mode)
+ != sizeof (__kernel_mode_t))
+ buf->msg_perm.mode &= 0xFFFF;
+#endif
}
}
-#endif
return ret;
}
+++ /dev/null
-/* Set flags signalling availability of kernel features based on given
- kernel version number. NIOS2 version.
- Copyright (C) 2019-2020 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/>. */
-
-#include_next <kernel-features.h>
-
-#undef __ASSUME_SYSVIPC_DEFAULT_IPC_64
# define LOADARGS_0(name, dummy) \
r0 = name
# define LOADARGS_1(name, __arg1) \
- long int arg1 = (long int) (__arg1); \
+ long int _arg1 = (long int) (__arg1); \
LOADARGS_0(name, 0); \
extern void __illegally_sized_syscall_arg1 (void); \
if (__builtin_classify_type (__arg1) != 5 && sizeof (__arg1) > 4) \
__illegally_sized_syscall_arg1 (); \
- r3 = arg1
+ r3 = _arg1
# define LOADARGS_2(name, __arg1, __arg2) \
- long int arg2 = (long int) (__arg2); \
+ long int _arg2 = (long int) (__arg2); \
LOADARGS_1(name, __arg1); \
extern void __illegally_sized_syscall_arg2 (void); \
if (__builtin_classify_type (__arg2) != 5 && sizeof (__arg2) > 4) \
__illegally_sized_syscall_arg2 (); \
- r4 = arg2
+ r4 = _arg2
# define LOADARGS_3(name, __arg1, __arg2, __arg3) \
- long int arg3 = (long int) (__arg3); \
+ long int _arg3 = (long int) (__arg3); \
LOADARGS_2(name, __arg1, __arg2); \
extern void __illegally_sized_syscall_arg3 (void); \
if (__builtin_classify_type (__arg3) != 5 && sizeof (__arg3) > 4) \
__illegally_sized_syscall_arg3 (); \
- r5 = arg3
+ r5 = _arg3
# define LOADARGS_4(name, __arg1, __arg2, __arg3, __arg4) \
- long int arg4 = (long int) (__arg4); \
+ long int _arg4 = (long int) (__arg4); \
LOADARGS_3(name, __arg1, __arg2, __arg3); \
extern void __illegally_sized_syscall_arg4 (void); \
if (__builtin_classify_type (__arg4) != 5 && sizeof (__arg4) > 4) \
__illegally_sized_syscall_arg4 (); \
- r6 = arg4
+ r6 = _arg4
# define LOADARGS_5(name, __arg1, __arg2, __arg3, __arg4, __arg5) \
- long int arg5 = (long int) (__arg5); \
+ long int _arg5 = (long int) (__arg5); \
LOADARGS_4(name, __arg1, __arg2, __arg3, __arg4); \
extern void __illegally_sized_syscall_arg5 (void); \
if (__builtin_classify_type (__arg5) != 5 && sizeof (__arg5) > 4) \
__illegally_sized_syscall_arg5 (); \
- r7 = arg5
+ r7 = _arg5
# define LOADARGS_6(name, __arg1, __arg2, __arg3, __arg4, __arg5, __arg6) \
- long int arg6 = (long int) (__arg6); \
+ long int _arg6 = (long int) (__arg6); \
LOADARGS_5(name, __arg1, __arg2, __arg3, __arg4, __arg5); \
extern void __illegally_sized_syscall_arg6 (void); \
if (__builtin_classify_type (__arg6) != 5 && sizeof (__arg6) > 4) \
__illegally_sized_syscall_arg6 (); \
- r8 = arg6
+ r8 = _arg6
# define ASM_INPUT_0 "0" (r0)
# define ASM_INPUT_1 ASM_INPUT_0, "1" (r3)
#define LOADARGS_0(name, dummy) \
r0 = name
#define LOADARGS_1(name, __arg1) \
- long int arg1 = (long int) (__arg1); \
+ long int _arg1 = (long int) (__arg1); \
LOADARGS_0(name, 0); \
extern void __illegally_sized_syscall_arg1 (void); \
if (__builtin_classify_type (__arg1) != 5 && sizeof (__arg1) > 8) \
__illegally_sized_syscall_arg1 (); \
- r3 = arg1
+ r3 = _arg1
#define LOADARGS_2(name, __arg1, __arg2) \
- long int arg2 = (long int) (__arg2); \
+ long int _arg2 = (long int) (__arg2); \
LOADARGS_1(name, __arg1); \
extern void __illegally_sized_syscall_arg2 (void); \
if (__builtin_classify_type (__arg2) != 5 && sizeof (__arg2) > 8) \
__illegally_sized_syscall_arg2 (); \
- r4 = arg2
+ r4 = _arg2
#define LOADARGS_3(name, __arg1, __arg2, __arg3) \
- long int arg3 = (long int) (__arg3); \
+ long int _arg3 = (long int) (__arg3); \
LOADARGS_2(name, __arg1, __arg2); \
extern void __illegally_sized_syscall_arg3 (void); \
if (__builtin_classify_type (__arg3) != 5 && sizeof (__arg3) > 8) \
__illegally_sized_syscall_arg3 (); \
- r5 = arg3
+ r5 = _arg3
#define LOADARGS_4(name, __arg1, __arg2, __arg3, __arg4) \
- long int arg4 = (long int) (__arg4); \
+ long int _arg4 = (long int) (__arg4); \
LOADARGS_3(name, __arg1, __arg2, __arg3); \
extern void __illegally_sized_syscall_arg4 (void); \
if (__builtin_classify_type (__arg4) != 5 && sizeof (__arg4) > 8) \
__illegally_sized_syscall_arg4 (); \
- r6 = arg4
+ r6 = _arg4
#define LOADARGS_5(name, __arg1, __arg2, __arg3, __arg4, __arg5) \
- long int arg5 = (long int) (__arg5); \
+ long int _arg5 = (long int) (__arg5); \
LOADARGS_4(name, __arg1, __arg2, __arg3, __arg4); \
extern void __illegally_sized_syscall_arg5 (void); \
if (__builtin_classify_type (__arg5) != 5 && sizeof (__arg5) > 8) \
__illegally_sized_syscall_arg5 (); \
- r7 = arg5
+ r7 = _arg5
#define LOADARGS_6(name, __arg1, __arg2, __arg3, __arg4, __arg5, __arg6) \
- long int arg6 = (long int) (__arg6); \
+ long int _arg6 = (long int) (__arg6); \
LOADARGS_5(name, __arg1, __arg2, __arg3, __arg4, __arg5); \
extern void __illegally_sized_syscall_arg6 (void); \
if (__builtin_classify_type (__arg6) != 5 && sizeof (__arg6) > 8) \
__illegally_sized_syscall_arg6 (); \
- r8 = arg6
+ r8 = _arg6
#define ASM_INPUT_0 "0" (r0)
#define ASM_INPUT_1 ASM_INPUT_0, "1" (r3)
--- /dev/null
+/* prctl - Linux specific syscall.
+ Copyright (C) 2020 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/>. */
+
+#include <sysdep.h>
+#include <stdarg.h>
+#include <sys/prctl.h>
+
+/* Unconditionally read all potential arguments. This may pass
+ garbage values to the kernel, but avoids the need for teaching
+ glibc the argument counts of individual options (including ones
+ that are added to the kernel in the future). */
+
+int
+__prctl (int option, ...)
+{
+ va_list arg;
+ va_start (arg, option);
+ unsigned long int arg2 = va_arg (arg, unsigned long int);
+ unsigned long int arg3 = va_arg (arg, unsigned long int);
+ unsigned long int arg4 = va_arg (arg, unsigned long int);
+ unsigned long int arg5 = va_arg (arg, unsigned long int);
+ va_end (arg);
+ return INLINE_SYSCALL_CALL (prctl, option, arg2, arg3, arg4, arg5);
+}
+
+libc_hidden_def (__prctl)
+weak_alias (__prctl, prctl)
--- /dev/null
+/* process_vm_readv - Linux specific syscall.
+ Copyright (C) 2020 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/>. */
+
+#include <unistd.h>
+#include <sysdep.h>
+#include <errno.h>
+#include <sys/uio.h>
+
+ssize_t
+process_vm_readv (pid_t pid, const struct iovec *local_iov,
+ unsigned long int liovcnt,
+ const struct iovec *remote_iov,
+ unsigned long int riovcnt, unsigned long int flags)
+{
+ return INLINE_SYSCALL_CALL (process_vm_readv, pid, local_iov,
+ liovcnt, remote_iov, riovcnt, flags);
+}
--- /dev/null
+/* process_vm_writev - Linux specific syscall.
+ Copyright (C) 2020 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/>. */
+
+#include <unistd.h>
+#include <sysdep.h>
+#include <errno.h>
+#include <sys/uio.h>
+
+ssize_t
+process_vm_writev (pid_t pid, const struct iovec *local_iov,
+ unsigned long int liovcnt,
+ const struct iovec *remote_iov,
+ unsigned long int riovcnt, unsigned long int flags)
+{
+ return INLINE_SYSCALL_CALL (process_vm_writev, pid, local_iov,
+ liovcnt, remote_iov, riovcnt, flags);
+}
# define internal_syscall1(number, err, arg0) \
({ \
long int _sys_result; \
+ long int _arg0 = (long int) (arg0); \
\
{ \
register long int __a7 asm ("a7") = number; \
- register long int __a0 asm ("a0") = (long int) (arg0); \
+ register long int __a0 asm ("a0") = _arg0; \
__asm__ volatile ( \
"scall\n\t" \
: "+r" (__a0) \
# define internal_syscall2(number, err, arg0, arg1) \
({ \
long int _sys_result; \
+ long int _arg0 = (long int) (arg0); \
+ long int _arg1 = (long int) (arg1); \
\
{ \
register long int __a7 asm ("a7") = number; \
- register long int __a0 asm ("a0") = (long int) (arg0); \
- register long int __a1 asm ("a1") = (long int) (arg1); \
+ register long int __a0 asm ("a0") = _arg0; \
+ register long int __a1 asm ("a1") = _arg1; \
__asm__ volatile ( \
"scall\n\t" \
: "+r" (__a0) \
# define internal_syscall3(number, err, arg0, arg1, arg2) \
({ \
long int _sys_result; \
+ long int _arg0 = (long int) (arg0); \
+ long int _arg1 = (long int) (arg1); \
+ long int _arg2 = (long int) (arg2); \
\
{ \
register long int __a7 asm ("a7") = number; \
- register long int __a0 asm ("a0") = (long int) (arg0); \
- register long int __a1 asm ("a1") = (long int) (arg1); \
- register long int __a2 asm ("a2") = (long int) (arg2); \
+ register long int __a0 asm ("a0") = _arg0; \
+ register long int __a1 asm ("a1") = _arg1; \
+ register long int __a2 asm ("a2") = _arg2; \
__asm__ volatile ( \
"scall\n\t" \
: "+r" (__a0) \
# define internal_syscall4(number, err, arg0, arg1, arg2, arg3) \
({ \
long int _sys_result; \
+ long int _arg0 = (long int) (arg0); \
+ long int _arg1 = (long int) (arg1); \
+ long int _arg2 = (long int) (arg2); \
+ long int _arg3 = (long int) (arg3); \
\
{ \
register long int __a7 asm ("a7") = number; \
- register long int __a0 asm ("a0") = (long int) (arg0); \
- register long int __a1 asm ("a1") = (long int) (arg1); \
- register long int __a2 asm ("a2") = (long int) (arg2); \
- register long int __a3 asm ("a3") = (long int) (arg3); \
+ register long int __a0 asm ("a0") = _arg0; \
+ register long int __a1 asm ("a1") = _arg1; \
+ register long int __a2 asm ("a2") = _arg2; \
+ register long int __a3 asm ("a3") = _arg3; \
__asm__ volatile ( \
"scall\n\t" \
: "+r" (__a0) \
# define internal_syscall5(number, err, arg0, arg1, arg2, arg3, arg4) \
({ \
long int _sys_result; \
+ long int _arg0 = (long int) (arg0); \
+ long int _arg1 = (long int) (arg1); \
+ long int _arg2 = (long int) (arg2); \
+ long int _arg3 = (long int) (arg3); \
+ long int _arg4 = (long int) (arg4); \
\
{ \
register long int __a7 asm ("a7") = number; \
- register long int __a0 asm ("a0") = (long int) (arg0); \
- register long int __a1 asm ("a1") = (long int) (arg1); \
- register long int __a2 asm ("a2") = (long int) (arg2); \
- register long int __a3 asm ("a3") = (long int) (arg3); \
- register long int __a4 asm ("a4") = (long int) (arg4); \
+ register long int __a0 asm ("a0") = _arg0; \
+ register long int __a1 asm ("a1") = _arg1; \
+ register long int __a2 asm ("a2") = _arg2; \
+ register long int __a3 asm ("a3") = _arg3; \
+ register long int __a4 asm ("a4") = _arg4; \
__asm__ volatile ( \
"scall\n\t" \
: "+r" (__a0) \
# define internal_syscall6(number, err, arg0, arg1, arg2, arg3, arg4, arg5) \
({ \
long int _sys_result; \
+ long int _arg0 = (long int) (arg0); \
+ long int _arg1 = (long int) (arg1); \
+ long int _arg2 = (long int) (arg2); \
+ long int _arg3 = (long int) (arg3); \
+ long int _arg4 = (long int) (arg4); \
+ long int _arg5 = (long int) (arg5); \
\
{ \
register long int __a7 asm ("a7") = number; \
- register long int __a0 asm ("a0") = (long int) (arg0); \
- register long int __a1 asm ("a1") = (long int) (arg1); \
- register long int __a2 asm ("a2") = (long int) (arg2); \
- register long int __a3 asm ("a3") = (long int) (arg3); \
- register long int __a4 asm ("a4") = (long int) (arg4); \
- register long int __a5 asm ("a5") = (long int) (arg5); \
+ register long int __a0 asm ("a0") = _arg0; \
+ register long int __a1 asm ("a1") = _arg1; \
+ register long int __a2 asm ("a2") = _arg2; \
+ register long int __a3 asm ("a3") = _arg3; \
+ register long int __a4 asm ("a4") = _arg4; \
+ register long int __a5 asm ("a5") = _arg5; \
__asm__ volatile ( \
"scall\n\t" \
: "+r" (__a0) \
# define internal_syscall7(number, err, arg0, arg1, arg2, arg3, arg4, arg5, arg6) \
({ \
long int _sys_result; \
+ long int _arg0 = (long int) (arg0); \
+ long int _arg1 = (long int) (arg1); \
+ long int _arg2 = (long int) (arg2); \
+ long int _arg3 = (long int) (arg3); \
+ long int _arg4 = (long int) (arg4); \
+ long int _arg5 = (long int) (arg5); \
+ long int _arg6 = (long int) (arg6); \
\
{ \
register long int __a7 asm ("a7") = number; \
- register long int __a0 asm ("a0") = (long int) (arg0); \
- register long int __a1 asm ("a1") = (long int) (arg1); \
- register long int __a2 asm ("a2") = (long int) (arg2); \
- register long int __a3 asm ("a3") = (long int) (arg3); \
- register long int __a4 asm ("a4") = (long int) (arg4); \
- register long int __a5 asm ("a5") = (long int) (arg5); \
- register long int __a6 asm ("a6") = (long int) (arg6); \
+ register long int __a0 asm ("a0") = _arg0; \
+ register long int __a1 asm ("a1") = _arg1; \
+ register long int __a2 asm ("a2") = _arg2; \
+ register long int __a3 asm ("a3") = _arg3; \
+ register long int __a4 asm ("a4") = _arg4; \
+ register long int __a5 asm ("a5") = _arg5; \
+ register long int __a6 asm ("a6") = _arg6; \
__asm__ volatile ( \
"scall\n\t" \
: "+r" (__a0) \
#include <sysdep.h>
#include <shlib-compat.h>
#include <errno.h>
+#include <linux/posix_types.h> /* For __kernel_mode_t. */
/* Define a `union semun' suitable for Linux here. */
union semun
int ret = semctl_syscall (semid, semnum, cmd, arg);
-#ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T
if (ret >= 0)
{
switch (cmd)
case IPC_STAT:
case SEM_STAT:
case SEM_STAT_ANY:
+#ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T
arg.buf->sem_perm.mode >>= 16;
+#else
+ /* Old Linux kernel versions might not clear the mode padding. */
+ if (sizeof ((struct semid_ds){0}.sem_perm.mode)
+ != sizeof (__kernel_mode_t))
+ arg.buf->sem_perm.mode &= 0xFFFF;
+#endif
}
}
-#endif
return ret;
}
--- /dev/null
+unix/sysv/linux/sh/sh4/fpu
--- /dev/null
+unix/sysv/linux/sh/sh4/fpu
#include <sysdep.h>
#include <shlib-compat.h>
#include <errno.h>
+#include <linux/posix_types.h> /* For __kernel_mode_t. */
#ifndef DEFAULT_VERSION
# ifndef __ASSUME_SYSVIPC_BROKEN_MODE_T
int ret = shmctl_syscall (shmid, cmd, buf);
-#ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T
if (ret >= 0)
{
switch (cmd)
case IPC_STAT:
case SHM_STAT:
case SHM_STAT_ANY:
+#ifdef __ASSUME_SYSVIPC_BROKEN_MODE_T
buf->shm_perm.mode >>= 16;
+#else
+ /* Old Linux kernel versions might not clear the mode padding. */
+ if (sizeof ((struct shmid_ds){0}.shm_perm.mode)
+ != sizeof (__kernel_mode_t))
+ buf->shm_perm.mode &= 0xFFFF;
+#endif
}
}
-#endif
return ret;
}
sysdep_routines += getshmlba
endif
+ifeq ($(subdir),signal)
+sysdep_routines += sigreturn_stub
+endif
+
ifeq ($(subdir),nptl)
# pull in __syscall_error routine
-libpthread-routines += sysdep
-libpthread-shared-only-routines += sysdep
+libpthread-routines += sysdep sigreturn_stub
+libpthread-shared-only-routines += sysdep sigreturn_stub
endif
#include <kernel_sigaction.h>
#include <sysdep.h>
-static void __rt_sigreturn_stub (void);
-static void __sigreturn_stub (void);
+void __rt_sigreturn_stub (void);
+void __sigreturn_stub (void);
#define STUB(act, sigsetsize) \
(act) ? ((unsigned long)((act->sa_flags & SA_SIGINFO) \
(sigsetsize)
#include <sysdeps/unix/sysv/linux/sigaction.c>
-
-static
-inhibit_stack_protector
-void
-__rt_sigreturn_stub (void)
-{
- __asm__ ("mov %0, %%g1\n\t"
- "ta 0x10\n\t"
- : /* no outputs */
- : "i" (__NR_rt_sigreturn));
-}
-
-static
-inhibit_stack_protector
-void
-__sigreturn_stub (void)
-{
- __asm__ ("mov %0, %%g1\n\t"
- "ta 0x10\n\t"
- : /* no outputs */
- : "i" (__NR_sigreturn));
-}
--- /dev/null
+/* Sigreturn stub function used on sa_restore field.
+ Copyright (C) 2020 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/>. */
+
+#include <sysdep.h>
+
+/* These functions must not change the register window or the stack
+ pointer [1].
+
+ [1] https://lkml.org/lkml/2016/5/27/465 */
+
+ENTRY (__rt_sigreturn_stub)
+ mov __NR_rt_sigreturn, %g1
+ ta 0x10
+END (__rt_sigreturn_stub)
+
+ENTRY (__sigreturn_stub)
+ mov __NR_sigreturn, %g1
+ ta 0x10
+END (__sigreturn_stub)
#include <syscall.h>
#include <sysdep.h>
-static void __rt_sigreturn_stub (void);
+/* Defined on sigreturn_stub.S. */
+void __rt_sigreturn_stub (void);
#define STUB(act, sigsetsize) \
(((unsigned long) &__rt_sigreturn_stub) - 8), \
(sigsetsize)
#include <sysdeps/unix/sysv/linux/sigaction.c>
-
-static
-inhibit_stack_protector
-void
-__rt_sigreturn_stub (void)
-{
- __asm__ ("mov %0, %%g1\n\t"
- "ta 0x6d\n\t"
- : /* no outputs */
- : "i" (__NR_rt_sigreturn));
-}
--- /dev/null
+/* Sigreturn stub function used on sa_restore field.
+ Copyright (C) 2020 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/>. */
+
+#include <sysdep.h>
+
+/* This function must not change the register window or the stack
+ pointer [1].
+
+ [1] https://lkml.org/lkml/2016/5/27/465 */
+
+ENTRY (__rt_sigreturn_stub)
+ mov __NR_rt_sigreturn, %g1
+ ta 0x6d
+END (__rt_sigreturn_stub)
# This file can list all potential system calls. The names are only
# used if the installed kernel headers also provide them.
-# The list of system calls is current as of Linux 5.4.
-kernel 5.4
+# The list of system calls is current as of Linux 5.5.
+kernel 5.5
FAST_atomic_update
FAST_cmpxchg
inotify_init EXTRA inotify_init i: inotify_init
inotify_init1 EXTRA inotify_init1 i:I inotify_init1
inotify_rm_watch EXTRA inotify_rm_watch i:ii inotify_rm_watch
-ioperm - ioperm i:iii ioperm
+ioperm - ioperm i:UUi ioperm
iopl - iopl i:i iopl
klogctl EXTRA syslog i:isi klogctl
lchown - lchown i:sii __lchown lchown
-mincore - mincore i:anV mincore
-mlock - mlock i:bn mlock
+mincore - mincore i:aUV mincore
+mlock - mlock i:bU mlock
mlockall - mlockall i:i mlockall
-mount EXTRA mount i:sssip __mount mount
-mremap EXTRA mremap b:ainip __mremap mremap
-munlock - munlock i:ai munlock
+mount EXTRA mount i:sssUp __mount mount
+mremap EXTRA mremap b:aUUip __mremap mremap
+munlock - munlock i:aU munlock
munlockall - munlockall i: munlockall
nfsservctl EXTRA nfsservctl i:ipp __compat_nfsservctl nfsservctl@GLIBC_2.0:GLIBC_2.28
pipe - pipe i:f __pipe pipe
pipe2 - pipe2 i:fi __pipe2 pipe2
pivot_root EXTRA pivot_root i:ss pivot_root
-prctl EXTRA prctl i:iiiii __prctl prctl
query_module EXTRA query_module i:sipip __compat_query_module query_module@GLIBC_2.0:GLIBC_2.23
quotactl EXTRA quotactl i:isip quotactl
-remap_file_pages - remap_file_pages i:piiii __remap_file_pages remap_file_pages
+remap_file_pages - remap_file_pages i:pUiUi __remap_file_pages remap_file_pages
sched_getp - sched_getparam i:ip __sched_getparam sched_getparam
sched_gets - sched_getscheduler i:i __sched_getscheduler sched_getscheduler
sched_primax - sched_get_priority_max i:i __sched_get_priority_max sched_get_priority_max
sched_setp - sched_setparam i:ip __sched_setparam sched_setparam
sched_sets - sched_setscheduler i:iip __sched_setscheduler sched_setscheduler
sched_yield - sched_yield i: __sched_yield sched_yield
-sendfile - sendfile i:iipi sendfile
-sendfile64 - sendfile64 i:iipi sendfile64
+sendfile - sendfile i:iipU sendfile
+sendfile64 - sendfile64 i:iipU sendfile64
setfsgid EXTRA setfsgid i:i setfsgid
setfsuid EXTRA setfsuid i:i setfsuid
setpgid - setpgid i:ii __setpgid setpgid
fchownat - fchownat i:isiii fchownat
linkat - linkat i:isisi linkat
mkdirat - mkdirat i:isi mkdirat
-readlinkat - readlinkat i:issi readlinkat
+readlinkat - readlinkat i:issU readlinkat
symlinkat - symlinkat i:sis symlinkat
unlinkat - unlinkat i:isi unlinkat
-setxattr - setxattr i:sspii setxattr
-lsetxattr - lsetxattr i:sspii lsetxattr
-fsetxattr - fsetxattr i:ispii fsetxattr
-getxattr - getxattr i:sspi getxattr
-lgetxattr - lgetxattr i:sspi lgetxattr
-fgetxattr - fgetxattr i:ispi fgetxattr
-listxattr - listxattr i:ssi listxattr
-llistxattr - llistxattr i:ssi llistxattr
-flistxattr - flistxattr i:isi flistxattr
+setxattr - setxattr i:sspUi setxattr
+lsetxattr - lsetxattr i:sspUi lsetxattr
+fsetxattr - fsetxattr i:ispUi fsetxattr
+getxattr - getxattr i:sspU getxattr
+lgetxattr - lgetxattr i:sspU lgetxattr
+fgetxattr - fgetxattr i:ispU fgetxattr
+listxattr - listxattr i:ssU listxattr
+llistxattr - llistxattr i:ssU llistxattr
+flistxattr - flistxattr i:isU flistxattr
removexattr - removexattr i:ss removexattr
lremovexattr - lremovexattr i:ss lremovexattr
fremovexattr - fremovexattr i:is fremovexattr
setns EXTRA setns i:ii setns
-process_vm_readv EXTRA process_vm_readv i:ipipii process_vm_readv
-process_vm_writev EXTRA process_vm_writev i:ipipii process_vm_writev
memfd_create EXTRA memfd_create i:si memfd_create
pkey_alloc EXTRA pkey_alloc i:ii pkey_alloc
pkey_free EXTRA pkey_free i:i pkey_free
# define SYSCALL_ERROR_LABEL syscall_error
# endif
+/* PSEUDO and T_PSEUDO macros have 2 extra arguments for unsigned long
+ int arguments. */
+# define PSEUDOS_HAVE_ULONG_INDICES 1
+
+# ifndef SYSCALL_ULONG_ARG_1
+# define SYSCALL_ULONG_ARG_1 0
+# define SYSCALL_ULONG_ARG_2 0
+# endif
+
# undef PSEUDO
-# define PSEUDO(name, syscall_name, args) \
- .text; \
- ENTRY (name) \
- DO_CALL (syscall_name, args); \
- cmpq $-4095, %rax; \
+# if SYSCALL_ULONG_ARG_1
+# define PSEUDO(name, syscall_name, args, ulong_arg_1, ulong_arg_2) \
+ .text; \
+ ENTRY (name) \
+ DO_CALL (syscall_name, args, ulong_arg_1, ulong_arg_2); \
+ cmpq $-4095, %rax; \
jae SYSCALL_ERROR_LABEL
+# else
+# define PSEUDO(name, syscall_name, args) \
+ .text; \
+ ENTRY (name) \
+ DO_CALL (syscall_name, args, 0, 0); \
+ cmpq $-4095, %rax; \
+ jae SYSCALL_ERROR_LABEL
+# endif
# undef PSEUDO_END
# define PSEUDO_END(name) \
END (name)
# undef PSEUDO_NOERRNO
-# define PSEUDO_NOERRNO(name, syscall_name, args) \
- .text; \
- ENTRY (name) \
- DO_CALL (syscall_name, args)
+# if SYSCALL_ULONG_ARG_1
+# define PSEUDO_NOERRNO(name, syscall_name, args, ulong_arg_1, ulong_arg_2) \
+ .text; \
+ ENTRY (name) \
+ DO_CALL (syscall_name, args, ulong_arg_1, ulong_arg_2)
+# else
+# define PSEUDO_NOERRNO(name, syscall_name, args) \
+ .text; \
+ ENTRY (name) \
+ DO_CALL (syscall_name, args, 0, 0)
+# endif
# undef PSEUDO_END_NOERRNO
# define PSEUDO_END_NOERRNO(name) \
# define ret_NOERRNO ret
# undef PSEUDO_ERRVAL
-# define PSEUDO_ERRVAL(name, syscall_name, args) \
- .text; \
- ENTRY (name) \
- DO_CALL (syscall_name, args); \
+# if SYSCALL_ULONG_ARG_1
+# define PSEUDO_ERRVAL(name, syscall_name, args, ulong_arg_1, ulong_arg_2) \
+ .text; \
+ ENTRY (name) \
+ DO_CALL (syscall_name, args, ulong_arg_1, ulong_arg_2); \
+ negq %rax
+# else
+# define PSEUDO_ERRVAL(name, syscall_name, args) \
+ .text; \
+ ENTRY (name) \
+ DO_CALL (syscall_name, args, 0, 0); \
negq %rax
+# endif
# undef PSEUDO_END_ERRVAL
# define PSEUDO_END_ERRVAL(name) \
Syscalls of more than 6 arguments are not supported. */
# undef DO_CALL
-# define DO_CALL(syscall_name, args) \
+# define DO_CALL(syscall_name, args, ulong_arg_1, ulong_arg_2) \
DOARGS_##args \
+ ZERO_EXTEND_##ulong_arg_1 \
+ ZERO_EXTEND_##ulong_arg_2 \
movl $SYS_ify (syscall_name), %eax; \
syscall;
# define DOARGS_5 DOARGS_4
# define DOARGS_6 DOARGS_5
+# define ZERO_EXTEND_0 /* nothing */
+# define ZERO_EXTEND_1 /* nothing */
+# define ZERO_EXTEND_2 /* nothing */
+# define ZERO_EXTEND_3 /* nothing */
+# define ZERO_EXTEND_4 /* nothing */
+# define ZERO_EXTEND_5 /* nothing */
+# define ZERO_EXTEND_6 /* nothing */
+
#else /* !__ASSEMBLER__ */
/* Define a macro which expands inline into the wrapper code for a system
call. */
/* Registers clobbered by syscall. */
# define REGISTERS_CLOBBERED_BY_SYSCALL "cc", "r11", "cx"
-/* Create a variable 'name' based on type 'X' to avoid explicit types.
- This is mainly used set use 64-bits arguments in x32. */
-#define TYPEFY(X, name) __typeof__ ((X) - (X)) name
-/* Explicit cast the argument to avoid integer from pointer warning on
- x32. */
-#define ARGIFY(X) ((__typeof__ ((X) - (X))) (X))
+/* NB: This also works when X is an array. For an array X, type of
+ (X) - (X) is ptrdiff_t, which is signed, since size of ptrdiff_t
+ == size of pointer, cast is a NOP. */
+#define TYPEFY1(X) __typeof__ ((X) - (X))
+/* Explicit cast the argument. */
+#define ARGIFY(X) ((TYPEFY1 (X)) (X))
+/* Create a variable 'name' based on type of variable 'X' to avoid
+ explicit types. */
+#define TYPEFY(X, name) __typeof__ (ARGIFY (X)) name
#undef INTERNAL_SYSCALL
#define INTERNAL_SYSCALL(name, err, nr, args...) \
#undef LO_HI_LONG
#define LO_HI_LONG(val) (val)
+#ifdef __ASSEMBLER__
+/* Zero-extend 32-bit unsigned long int arguments to 64 bits. */
+# undef ZERO_EXTEND_1
+# define ZERO_EXTEND_1 movl %edi, %edi;
+# undef ZERO_EXTEND_2
+# define ZERO_EXTEND_2 movl %esi, %esi;
+# undef ZERO_EXTEND_3
+# define ZERO_EXTEND_3 movl %edx, %edx;
+# if SYSCALL_ULONG_ARG_1 == 4 || SYSCALL_ULONG_ARG_2 == 4
+# undef DOARGS_4
+# define DOARGS_4 movl %ecx, %r10d;
+# else
+# undef ZERO_EXTEND_4
+# define ZERO_EXTEND_4 movl %r10d, %r10d;
+# endif
+# undef ZERO_EXTEND_5
+# define ZERO_EXTEND_5 movl %r8d, %r8d;
+# undef ZERO_EXTEND_6
+# define ZERO_EXTEND_6 movl %r9d, %r9d;
+#else /* !__ASSEMBLER__ */
+# undef ARGIFY
+/* Enforce zero-extension for pointers and array system call arguments.
+ For integer types, extend to int64_t (the full register) using a
+ regular cast, resulting in zero or sign extension based on the
+ signedness of the original type. */
+# define ARGIFY(X) \
+ ({ \
+ _Pragma ("GCC diagnostic push"); \
+ _Pragma ("GCC diagnostic ignored \"-Wpointer-to-int-cast\""); \
+ (__builtin_classify_type (X) == 5 \
+ ? (uintptr_t) (X) : (int64_t) (X)); \
+ _Pragma ("GCC diagnostic pop"); \
+ })
+#endif /* __ASSEMBLER__ */
+
#endif /* linux/x86_64/x32/sysdep.h */
ifeq ($(subdir),setjmp)
gen-as-const-headers += jmp_buf-ssp.sym
sysdep_routines += __longjmp_cancel
+ifneq ($(enable-cet),no)
+ifneq ($(have-tunables),no)
+tests += tst-setjmp-cet
+tst-setjmp-cet-ENV = GLIBC_TUNABLES=glibc.cpu.x86_ibt=on:glibc.cpu.x86_shstk=on
+endif
+endif
endif
ifeq ($(enable-cet),yes)
threads = 1 << ((ecx >> 12) & 0x0f);
}
- if (threads == 0)
+ if (threads == 0 || cpu_features->basic.family >= 0x17)
{
/* If APIC ID width is not available, use logical
processor count. */
if (threads > 0)
shared /= threads;
- /* Account for exclusive L2 and L3 caches. */
- shared += core;
+ /* Get shared cache per ccx for Zen architectures. */
+ if (cpu_features->basic.family >= 0x17)
+ {
+ unsigned int eax;
+
+ /* Get number of threads share the L3 cache in CCX. */
+ __cpuid_count (0x8000001D, 0x3, eax, ebx, ecx, edx);
+
+ unsigned int threads_per_ccx = ((eax >> 14) & 0xfff) + 1;
+ shared *= threads_per_ccx;
+ }
+ else
+ {
+ /* Account for exclusive L2 and L3 caches. */
+ shared += core;
+ }
}
#ifndef DISABLE_PREFETCHW
__x86_shared_cache_size = shared;
}
- /* The large memcpy micro benchmark in glibc shows that 6 times of
- shared cache size is the approximate value above which non-temporal
- store becomes faster on a 8-core processor. This is the 3/4 of the
- total shared cache size. */
+ /* The default setting for the non_temporal threshold is 3/4 of one
+ thread's share of the chip's cache. For most Intel and AMD processors
+ with an initial release date between 2017 and 2020, a thread's typical
+ share of the cache is from 500 KBytes to 2 MBytes. Using the 3/4
+ threshold leaves 125 KBytes to 500 KBytes of the thread's data
+ in cache after a maximum temporal copy, which will maintain
+ in cache a reasonable portion of the thread's stack and other
+ active data. If the threshold is set higher than one thread's
+ share of the cache, it has a substantial risk of negatively
+ impacting the performance of other threads running on the chip. */
__x86_shared_non_temporal_threshold
= (cpu_features->non_temporal_threshold != 0
? cpu_features->non_temporal_threshold
- : __x86_shared_cache_size * threads * 3 / 4);
+ : __x86_shared_cache_size * 3 / 4);
}
#endif
/* No legacy object check if both IBT and SHSTK are always on. */
if (enable_ibt_type == CET_ALWAYS_ON
&& enable_shstk_type == CET_ALWAYS_ON)
- return;
+ {
+ THREAD_SETMEM (THREAD_SELF, header.feature_1,
+ GL(dl_x86_feature_1)[0]);
+ return;
+ }
/* Check if IBT is enabled by kernel. */
bool ibt_enabled
--- /dev/null
+#include <setjmp/tst-setjmp.c>
{
# ifndef RTLD_BOOTSTRAP
if (sym_map != map
- && sym_map->l_type != lt_executable
&& !sym_map->l_relocated)
{
const char *strtab
= (const char *) D_PTR (map, l_info[DT_STRTAB]);
- _dl_error_printf ("\
+ if (sym_map->l_type == lt_executable)
+ _dl_fatal_printf ("\
+%s: IFUNC symbol '%s' referenced in '%s' is defined in the executable \
+and creates an unsatisfiable circular dependency.\n",
+ RTLD_PROGNAME, strtab + refsym->st_name,
+ map->l_name);
+ else
+ _dl_error_printf ("\
%s: Relink `%s' with `%s' for IFUNC symbol `%s'\n",
- RTLD_PROGNAME, map->l_name,
- sym_map->l_name,
- strtab + refsym->st_name);
+ RTLD_PROGNAME, map->l_name,
+ sym_map->l_name,
+ strtab + refsym->st_name);
}
# endif
value = ((ElfW(Addr) (*) (void)) value) ();
# define REP_MOVSB_THRESHOLD (2048 * (VEC_SIZE / 16))
#endif
+/* Avoid short distance rep movsb only with non-SSE vector. */
+#ifndef AVOID_SHORT_DISTANCE_REP_MOVSB
+# define AVOID_SHORT_DISTANCE_REP_MOVSB (VEC_SIZE > 16)
+#else
+# define AVOID_SHORT_DISTANCE_REP_MOVSB 0
+#endif
+
#ifndef PREFETCH
# define PREFETCH(addr) prefetcht0 addr
#endif
ret
L(movsb):
- cmpq __x86_shared_non_temporal_threshold(%rip), %rdx
+ cmp __x86_shared_non_temporal_threshold(%rip), %RDX_LP
jae L(more_8x_vec)
cmpq %rsi, %rdi
jb 1f
# error Unsupported REP_MOVSB_THRESHOLD and VEC_SIZE!
# endif
jb L(more_8x_vec_backward)
+# if AVOID_SHORT_DISTANCE_REP_MOVSB
+ movq %rdi, %rcx
+ subq %rsi, %rcx
+ jmp 2f
+# endif
1:
+# if AVOID_SHORT_DISTANCE_REP_MOVSB
+ movq %rsi, %rcx
+ subq %rdi, %rcx
+2:
+/* Avoid "rep movsb" if RCX, the distance between source and destination,
+ is N*4GB + [1..63] with N >= 0. */
+ cmpl $63, %ecx
+ jbe L(more_2x_vec) /* Avoid "rep movsb" if ECX <= 63. */
+# endif
mov %RDX_LP, %RCX_LP
rep movsb
L(nop):
addq %r8, %rdx
#if (defined USE_MULTIARCH || VEC_SIZE == 16) && IS_IN (libc)
/* Check non-temporal store threshold. */
- cmpq __x86_shared_non_temporal_threshold(%rip), %rdx
+ cmp __x86_shared_non_temporal_threshold(%rip), %RDX_LP
ja L(large_forward)
#endif
L(loop_4x_vec_forward):
subq %r8, %rdx
#if (defined USE_MULTIARCH || VEC_SIZE == 16) && IS_IN (libc)
/* Check non-temporal store threshold. */
- cmpq __x86_shared_non_temporal_threshold(%rip), %rdx
+ cmp __x86_shared_non_temporal_threshold(%rip), %RDX_LP
ja L(large_backward)
#endif
L(loop_4x_vec_backward):
movl $(PAGE_SIZE / (VEC_SIZE * 4) - 1), %esi
testq %rdi, %rdi
+# ifdef USE_AS_STRNCMP
+ /* At this point, if %rdi value is 0, it already tested
+ VEC_SIZE*4+%r10 byte starting from %rax. This label
+ checks whether strncmp maximum offset reached or not. */
+ je L(string_nbyte_offset_check)
+# else
je L(back_to_loop)
+# endif
tzcntq %rdi, %rcx
addq %r10, %rcx
/* Adjust for number of bytes skipped. */
VZEROUPPER
ret
+# ifdef USE_AS_STRNCMP
+L(string_nbyte_offset_check):
+ leaq (VEC_SIZE * 4)(%r10), %r10
+ cmpq %r10, %r11
+ jbe L(zero)
+ jmp L(back_to_loop)
+# endif
+
.p2align 4
L(cross_page_loop):
/* Check one byte/dword at a time. */