From 9824e87bb3b0c85509776c01d76563fd1c5bbbf3 Mon Sep 17 00:00:00 2001
From: Sascha Wildner <saw@online.de>
Date: Sun, 26 Dec 2021 17:57:08 +0100
Subject: [PATCH 1/5] Add some printf tests for %b and %B.

---
 tools/regression/lib/libc/stdio/build.sh      |   1 +
 tools/regression/lib/libc/stdio/libc-diag.h   |  74 +++++++
 .../regression/lib/libc/stdio/support/check.h | 207 ++++++++++++++++++
 .../libc/stdio/support/support_quote_blob.c   |  24 ++
 .../stdio/support/support_quote_blob_main.c   |  87 ++++++++
 .../stdio/support/support_record_failure.c    | 116 ++++++++++
 .../support/support_test_compare_failure.c    |  60 +++++
 .../support/support_test_compare_string.c     |  28 +++
 .../support_test_compare_string_main.c        |  97 ++++++++
 .../lib/libc/stdio/support/test-driver.c      |   5 +
 .../lib/libc/stdio/tst-printf-binary-main.c   | 130 +++++++++++
 .../lib/libc/stdio/tst-printf-binary.c        |  25 +++
 12 files changed, 854 insertions(+)
 create mode 100644 tools/regression/lib/libc/stdio/build.sh
 create mode 100644 tools/regression/lib/libc/stdio/libc-diag.h
 create mode 100644 tools/regression/lib/libc/stdio/support/check.h
 create mode 100644 tools/regression/lib/libc/stdio/support/support_quote_blob.c
 create mode 100644 tools/regression/lib/libc/stdio/support/support_quote_blob_main.c
 create mode 100644 tools/regression/lib/libc/stdio/support/support_record_failure.c
 create mode 100644 tools/regression/lib/libc/stdio/support/support_test_compare_failure.c
 create mode 100644 tools/regression/lib/libc/stdio/support/support_test_compare_string.c
 create mode 100644 tools/regression/lib/libc/stdio/support/support_test_compare_string_main.c
 create mode 100644 tools/regression/lib/libc/stdio/support/test-driver.c
 create mode 100644 tools/regression/lib/libc/stdio/tst-printf-binary-main.c
 create mode 100644 tools/regression/lib/libc/stdio/tst-printf-binary.c

diff --git a/tools/regression/lib/libc/stdio/build.sh b/tools/regression/lib/libc/stdio/build.sh
new file mode 100644
index 00000000000..28a35248b2e
--- /dev/null
+++ b/tools/regression/lib/libc/stdio/build.sh
@@ -0,0 +1 @@
+cc -I. -D__GNUC_PREREQ=__GNUC_PREREQ__ -o tst-printf-binary tst-printf-binary.c support/support_test_compare_string.c support/support_quote_blob.c support/support_record_failure.c support/support_test_compare_failure.c
diff --git a/tools/regression/lib/libc/stdio/libc-diag.h b/tools/regression/lib/libc/stdio/libc-diag.h
new file mode 100644
index 00000000000..eaa8f775e11
--- /dev/null
+++ b/tools/regression/lib/libc/stdio/libc-diag.h
@@ -0,0 +1,74 @@
+/* Macros for controlling diagnostic output from the compiler.
+   Copyright (C) 2014-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/>.  */
+
+#ifndef _LIBC_DIAG_H
+#define _LIBC_DIAG_H 1
+
+/* Ignore the value of an expression when a cast to void does not
+   suffice (in particular, for a call to a function declared with
+   attribute warn_unused_result).  */
+#define ignore_value(x) \
+  ({ __typeof__ (x) __ignored_value = (x); (void) __ignored_value; })
+
+/* The macros to control diagnostics are structured like this, rather
+   than a single macro that both pushes and pops diagnostic state and
+   takes the affected code as an argument, because the GCC pragmas
+   work by disabling the diagnostic for a range of source locations
+   and do not work when all the pragmas and the affected code are in a
+   single macro expansion.  */
+
+/* Push diagnostic state.  */
+#define DIAG_PUSH_NEEDS_COMMENT _Pragma ("GCC diagnostic push")
+
+/* Pop diagnostic state.  */
+#define DIAG_POP_NEEDS_COMMENT _Pragma ("GCC diagnostic pop")
+
+#define _DIAG_STR1(s) #s
+#define _DIAG_STR(s) _DIAG_STR1(s)
+
+/* Ignore the diagnostic OPTION.  VERSION is the most recent GCC
+   version for which the diagnostic has been confirmed to appear in
+   the absence of the pragma (in the form MAJOR.MINOR for GCC 4.x,
+   just MAJOR for GCC 5 and later).  Uses of this pragma should be
+   reviewed when the GCC version given is no longer supported for
+   building glibc; the version number should always be on the same
+   source line as the macro name, so such uses can be found with grep.
+   Uses should come with a comment giving more details of the
+   diagnostic, and an architecture on which it is seen if possibly
+   optimization-related and not in architecture-specific code.  This
+   macro should only be used if the diagnostic seems hard to fix (for
+   example, optimization-related false positives).  */
+#define DIAG_IGNORE_NEEDS_COMMENT(version, option)     \
+  _Pragma (_DIAG_STR (GCC diagnostic ignored option))
+
+/* Similar to DIAG_IGNORE_NEEDS_COMMENT the following macro ignores the
+   diagnostic OPTION but only if optimizations for size are enabled.
+   This is required because different warnings may be generated for
+   different optimization levels.  For example a key piece of code may
+   only generate a warning when compiled at -Os, but at -O2 you could
+   still want the warning to be enabled to catch errors.  In this case
+   you would use DIAG_IGNORE_Os_NEEDS_COMMENT to disable the warning
+   only for -Os.  */
+#ifdef __OPTIMIZE_SIZE__
+# define DIAG_IGNORE_Os_NEEDS_COMMENT(version, option) \
+  _Pragma (_DIAG_STR (GCC diagnostic ignored option))
+#else
+# define DIAG_IGNORE_Os_NEEDS_COMMENT(version, option)
+#endif
+
+#endif /* libc-diag.h */
diff --git a/tools/regression/lib/libc/stdio/support/check.h b/tools/regression/lib/libc/stdio/support/check.h
new file mode 100644
index 00000000000..9b1844352f3
--- /dev/null
+++ b/tools/regression/lib/libc/stdio/support/check.h
@@ -0,0 +1,207 @@
+/* Functionality for reporting test results.
+   Copyright (C) 2016-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/>.  */
+
+#ifndef SUPPORT_CHECK_H
+#define SUPPORT_CHECK_H
+
+#include <sys/cdefs.h>
+#include <stddef.h>
+
+__BEGIN_DECLS
+
+/* Record a test failure, print the failure message to standard output
+   and return 1.  */
+#define FAIL_RET(...) \
+  return support_print_failure_impl (__FILE__, __LINE__, __VA_ARGS__)
+
+/* Print the failure message and terminate the process with STATUS.
+   Record a the process as failed if STATUS is neither EXIT_SUCCESS
+   nor EXIT_UNSUPPORTED.  */
+#define FAIL_EXIT(status, ...) \
+  support_exit_failure_impl (status, __FILE__, __LINE__, __VA_ARGS__)
+
+/* Record a test failure, print the failure message and terminate with
+   exit status 1.  */
+#define FAIL_EXIT1(...) \
+  support_exit_failure_impl (1, __FILE__, __LINE__, __VA_ARGS__)
+
+/* Print failure message and terminate with as unsupported test (exit
+   status of 77).  */
+#define FAIL_UNSUPPORTED(...) \
+  support_exit_failure_impl (77, __FILE__, __LINE__, __VA_ARGS__)
+
+/* Record a test failure (but continue executing) if EXPR evaluates to
+   false.  */
+#define TEST_VERIFY(expr)                                       \
+  ({                                                            \
+    if (expr)                                                   \
+      ;                                                         \
+    else                                                        \
+      support_test_verify_impl (__FILE__, __LINE__, #expr);     \
+  })
+
+/* Record a test failure and exit if EXPR evaluates to false.  */
+#define TEST_VERIFY_EXIT(expr)                                  \
+  ({                                                            \
+    if (expr)                                                   \
+      ;                                                         \
+    else                                                        \
+      support_test_verify_exit_impl                             \
+        (1, __FILE__, __LINE__, #expr);                         \
+  })
+
+
+
+int support_print_failure_impl (const char *file, int line,
+                                const char *format, ...)
+  __attribute__ ((nonnull (1), format (printf, 3, 4)));
+void support_exit_failure_impl (int exit_status,
+                                const char *file, int line,
+                                const char *format, ...)
+  __attribute__ ((noreturn, nonnull (2), format (printf, 4, 5)));
+void support_test_verify_impl (const char *file, int line,
+                               const char *expr);
+void support_test_verify_exit_impl (int status, const char *file, int line,
+                                    const char *expr)
+  __attribute__ ((noreturn));
+
+/* Record a test failure.  This function returns and does not
+   terminate the process.  The failure counter is stored in a shared
+   memory mapping, so that failures reported in child processes are
+   visible to the parent process and test driver.  This function
+   depends on initialization by an ELF constructor, so it can only be
+   invoked after the test driver has run.  Note that this function
+   does not support reporting failures from a DSO.  */
+void support_record_failure (void);
+
+/* Static assertion, under a common name for both C++ and C11.  */
+#ifdef __cplusplus
+# define support_static_assert static_assert
+#else
+# define support_static_assert _Static_assert
+#endif
+
+/* Compare the two integers LEFT and RIGHT and report failure if they
+   are different.  */
+#define TEST_COMPARE(left, right)                                       \
+  ({                                                                    \
+    /* + applies the integer promotions, for bitfield support.   */     \
+    typedef __typeof__ (+ (left)) __left_type;                          \
+    typedef __typeof__ (+ (right)) __right_type;                        \
+    __left_type __left_value = (left);                                  \
+    __right_type __right_value = (right);                               \
+    int __left_is_positive = __left_value > 0;                          \
+    int __right_is_positive = __right_value > 0;                        \
+    /* Prevent use with floating-point types.  */                       \
+    support_static_assert ((__left_type) 1.0 == (__left_type) 1.5,      \
+                           "left value has floating-point type");       \
+    support_static_assert ((__right_type) 1.0 == (__right_type) 1.5,    \
+                           "right value has floating-point type");      \
+    /* Prevent accidental use with larger-than-long long types.  */     \
+    support_static_assert (sizeof (__left_value) <= sizeof (long long), \
+                           "left value fits into long long");           \
+    support_static_assert (sizeof (__right_value) <= sizeof (long long), \
+                    "right value fits into long long");                 \
+    /* Compare the value.  */                                           \
+    if (__left_value != __right_value                                   \
+        || __left_is_positive != __right_is_positive)                   \
+      /* Pass the sign for printing the correct value.  */              \
+      support_test_compare_failure                                      \
+        (__FILE__, __LINE__,                                            \
+         #left, __left_value, __left_is_positive, sizeof (__left_type), \
+         #right, __right_value, __right_is_positive, sizeof (__right_type)); \
+  })
+
+/* Internal implementation of TEST_COMPARE.  LEFT_POSITIVE and
+   RIGHT_POSITIVE are used to store the sign separately, so that both
+   unsigned long long and long long arguments fit into LEFT_VALUE and
+   RIGHT_VALUE, and the function can still print the original value.
+   LEFT_SIZE and RIGHT_SIZE specify the size of the argument in bytes,
+   for hexadecimal formatting.  */
+void support_test_compare_failure (const char *file, int line,
+                                   const char *left_expr,
+                                   long long left_value,
+                                   int left_positive,
+                                   int left_size,
+                                   const char *right_expr,
+                                   long long right_value,
+                                   int right_positive,
+                                   int right_size);
+
+
+/* Compare [LEFT, LEFT + LEFT_LENGTH) with [RIGHT, RIGHT +
+   RIGHT_LENGTH) and report a test failure if the arrays are
+   different.  LEFT_LENGTH and RIGHT_LENGTH are measured in bytes.  If
+   the length is null, the corresponding pointer is ignored (i.e., it
+   can be NULL).  The blobs should be reasonably short because on
+   mismatch, both are printed.  */
+#define TEST_COMPARE_BLOB(left, left_length, right, right_length)       \
+  (support_test_compare_blob (left, left_length, right, right_length,   \
+                              __FILE__, __LINE__,                       \
+                              #left, #left_length, #right, #right_length))
+
+void support_test_compare_blob (const void *left,
+                                unsigned long int left_length,
+                                const void *right,
+                                unsigned long int right_length,
+                                const char *file, int line,
+                                const char *left_exp, const char *left_len_exp,
+                                const char *right_exp,
+                                const char *right_len_exp);
+
+/* Compare the strings LEFT and RIGHT and report a test failure if
+   they are different.  Also report failure if one of the arguments is
+   a null pointer and the other is not.  The strings should be
+   reasonably short because on mismatch, both are printed.  */
+#define TEST_COMPARE_STRING(left, right)                         \
+  (support_test_compare_string (left, right, __FILE__, __LINE__, \
+                                #left, #right))
+
+/* Compare the wide strings LEFT and RIGHT and report a test failure
+   if they are different.  Also report failure if one of the arguments
+   is a null pointer and the other is not.  The strings should be
+   reasonably short because on mismatch, both are printed.  */
+#define TEST_COMPARE_STRING_WIDE(left, right)                         \
+  (support_test_compare_string_wide (left, right, __FILE__, __LINE__, \
+				     #left, #right))
+
+void support_test_compare_string (const char *left, const char *right,
+                                  const char *file, int line,
+                                  const char *left_expr,
+                                  const char *right_expr);
+
+void support_test_compare_string_wide (const wchar_t *left,
+				       const wchar_t *right,
+				       const char *file, int line,
+				       const char *left_expr,
+				       const char *right_expr);
+
+/* Internal function called by the test driver.  */
+int support_report_failure (int status)
+  __attribute__ ((weak, warn_unused_result));
+
+/* Internal function used to test the failure recording framework.  */
+void support_record_failure_reset (void);
+
+/* Returns true or false depending on whether there have been test
+   failures or not.  */
+int support_record_failure_is_failed (void);
+
+__END_DECLS
+
+#endif /* SUPPORT_CHECK_H */
diff --git a/tools/regression/lib/libc/stdio/support/support_quote_blob.c b/tools/regression/lib/libc/stdio/support/support_quote_blob.c
new file mode 100644
index 00000000000..611980c9a21
--- /dev/null
+++ b/tools/regression/lib/libc/stdio/support/support_quote_blob.c
@@ -0,0 +1,24 @@
+/* Quote a narrow string blob so that it can be used in C literals.
+   Copyright (C) 2018-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/>.  */
+
+#define CHAR unsigned char
+#define L_(C) C
+#define SUPPORT_QUOTE_BLOB support_quote_blob
+#define WIDE 0
+
+#include "support_quote_blob_main.c"
diff --git a/tools/regression/lib/libc/stdio/support/support_quote_blob_main.c b/tools/regression/lib/libc/stdio/support/support_quote_blob_main.c
new file mode 100644
index 00000000000..a426a7d7f92
--- /dev/null
+++ b/tools/regression/lib/libc/stdio/support/support_quote_blob_main.c
@@ -0,0 +1,87 @@
+/* Quote a blob so that it can be used in C literals.
+   Copyright (C) 2018-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 <support/support.h>
+//#include <support/xmemstream.h>
+
+#include <stddef.h>
+#include <stdio.h>
+
+char *
+SUPPORT_QUOTE_BLOB (const void *blob, size_t length)
+{
+  const CHAR *p = blob;
+  for (size_t i = 0; i < length; ++i)
+    {
+      CHAR ch = p[i];
+
+      /* Use C backslash escapes for those control characters for
+	 which they are defined.  */
+      switch (ch)
+	{
+	case L_('\a'):
+	  putc_unlocked ('\\', stdout);
+	  putc_unlocked ('a', stdout);
+	  break;
+	case L_('\b'):
+	  putc_unlocked ('\\', stdout);
+	  putc_unlocked ('b', stdout);
+	  break;
+	case L_('\f'):
+	  putc_unlocked ('\\', stdout);
+	  putc_unlocked ('f', stdout);
+	  break;
+	case L_('\n'):
+	  putc_unlocked ('\\', stdout);
+	  putc_unlocked ('n', stdout);
+	  break;
+	case L_('\r'):
+	  putc_unlocked ('\\', stdout);
+	  putc_unlocked ('r', stdout);
+	  break;
+	case L_('\t'):
+	  putc_unlocked ('\\', stdout);
+	  putc_unlocked ('t', stdout);
+	  break;
+	case L_('\v'):
+	  putc_unlocked ('\\', stdout);
+	  putc_unlocked ('v', stdout);
+	  break;
+	case L_('\\'):
+	case L_('\''):
+	case L_('\"'):
+	  putc_unlocked ('\\', stdout);
+	  putc_unlocked (ch, stdout);
+	  break;
+	default:
+	  if (ch < L_(' ') || ch > L_('~'))
+	    /* For narrow characters, use octal sequences because they
+	       are fixed width, unlike hexadecimal sequences.  For
+	       wide characters, use N2785 delimited escape
+	       sequences.  */
+	    if (WIDE)
+	      fprintf (stdout, "\\x{%x}", (unsigned int) ch);
+	    else
+	      fprintf (stdout, "\\%03o", (unsigned int) ch);
+	  else
+	    putc_unlocked (ch, stdout);
+	}
+    }
+
+  return NULL;
+}
diff --git a/tools/regression/lib/libc/stdio/support/support_record_failure.c b/tools/regression/lib/libc/stdio/support/support_record_failure.c
new file mode 100644
index 00000000000..edabb3bee06
--- /dev/null
+++ b/tools/regression/lib/libc/stdio/support/support_record_failure.c
@@ -0,0 +1,116 @@
+/* Global test failure counter.
+   Copyright (C) 2016-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 <support/check.h>
+//#include <support/support.h>
+//#include <support/test-driver.h>
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <unistd.h>
+
+#define	EXIT_UNSUPPORTED	77
+
+/* This structure keeps track of test failures.  The counter is
+   incremented on each failure.  The failed member is set to true if a
+   failure is detected, so that even if the counter wraps around to
+   zero, the failure of a test can be detected.
+
+   The init constructor function below puts *state on a shared
+   annonymous mapping, so that failure reports from subprocesses
+   propagate to the parent process.  */
+struct test_failures
+{
+  unsigned int counter;
+  unsigned int failed;
+};
+static struct test_failures *state;
+
+static __attribute__ ((constructor)) void
+init (void)
+{
+  void *ptr = mmap (NULL, sizeof (*state), PROT_READ | PROT_WRITE,
+                    MAP_ANONYMOUS | MAP_SHARED, -1, 0);
+  if (ptr == MAP_FAILED)
+    {
+      printf ("error: could not map %zu bytes: %m\n", sizeof (*state));
+      exit (1);
+    }
+  /* Zero-initialization of the struct is sufficient.  */
+  state = ptr;
+}
+
+void
+support_record_failure (void)
+{
+  if (state == NULL)
+    {
+      printf
+        ("error: support_record_failure called without initialization\n");
+      _exit (1);
+    }
+  /* Relaxed MO is sufficient because we are only interested in the
+     values themselves, in isolation.  */
+  __atomic_store_n (&state->failed, 1, __ATOMIC_RELEASE);
+  __atomic_add_fetch (&state->counter, 1, __ATOMIC_RELEASE);
+}
+
+int
+support_report_failure (int status)
+{
+  if (state == NULL)
+    {
+      printf
+        ("error: support_report_failure called without initialization\n");
+      return 1;
+    }
+
+  /* Relaxed MO is sufficient because acquire test result reporting
+     assumes that exiting from the main thread happens before the
+     error reporting via support_record_failure, which requires some
+     form of external synchronization.  */
+  bool failed = __atomic_load_n (&state->failed, __ATOMIC_RELAXED);
+  if (failed)
+    printf ("error: %u test failures\n",
+            __atomic_load_n (&state->counter, __ATOMIC_RELAXED));
+
+  if ((status == 0 || status == EXIT_UNSUPPORTED) && failed)
+    /* If we have a recorded failure, it overrides a non-failure
+       report from the test function.  */
+    status = 1;
+  return status;
+}
+
+void
+support_record_failure_reset (void)
+{
+  /* Only used for testing the test framework, with external
+     synchronization, but use release MO for consistency.  */
+  __atomic_store_n (&state->failed, 0, __ATOMIC_RELAXED);
+  __atomic_add_fetch (&state->counter, 0, __ATOMIC_RELAXED);
+}
+
+int
+support_record_failure_is_failed (void)
+{
+  /* Relaxed MO is sufficient because we need (blocking) external
+     synchronization for reliable test error reporting anyway.  */
+  return __atomic_load_n (&state->failed, __ATOMIC_RELAXED);
+}
diff --git a/tools/regression/lib/libc/stdio/support/support_test_compare_failure.c b/tools/regression/lib/libc/stdio/support/support_test_compare_failure.c
new file mode 100644
index 00000000000..1ef6ebd0ab1
--- /dev/null
+++ b/tools/regression/lib/libc/stdio/support/support_test_compare_failure.c
@@ -0,0 +1,60 @@
+/* Reporting a numeric comparison failure.
+   Copyright (C) 2017-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 <errno.h>
+#include <stdio.h>
+//#include <support/check.h>
+
+void support_record_failure (void);
+
+static void
+report (const char *which, const char *expr, long long value, int positive,
+        int size)
+{
+  printf ("  %s: ", which);
+  if (positive)
+    printf ("%llu", (unsigned long long) value);
+  else
+    printf ("%lld", value);
+  unsigned long long mask
+    = (~0ULL) >> (8 * (sizeof (unsigned long long) - size));
+  printf (" (0x%llx); from: %s\n", (unsigned long long) value & mask, expr);
+}
+
+void
+support_test_compare_failure (const char *file, int line,
+                              const char *left_expr,
+                              long long left_value,
+                              int left_positive,
+                              int left_size,
+                              const char *right_expr,
+                              long long right_value,
+                              int right_positive,
+                              int right_size)
+{
+  int saved_errno = errno;
+  support_record_failure ();
+  if (left_size != right_size)
+    printf ("%s:%d: numeric comparison failure (widths %d and %d)\n",
+            file, line, left_size * 8, right_size * 8);
+  else
+    printf ("%s:%d: numeric comparison failure\n", file, line);
+  report (" left", left_expr, left_value, left_positive, left_size);
+  report ("right", right_expr, right_value, right_positive, right_size);
+  errno = saved_errno;
+}
diff --git a/tools/regression/lib/libc/stdio/support/support_test_compare_string.c b/tools/regression/lib/libc/stdio/support/support_test_compare_string.c
new file mode 100644
index 00000000000..12bafe43d44
--- /dev/null
+++ b/tools/regression/lib/libc/stdio/support/support_test_compare_string.c
@@ -0,0 +1,28 @@
+/* Check two strings for equality.
+   Copyright (C) 2018-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/>.  */
+
+#define CHAR char
+#define UCHAR unsigned char
+#define LPREFIX ""
+#define STRLEN strlen
+#define MEMCMP memcmp
+#define SUPPORT_QUOTE_BLOB support_quote_blob
+#define SUPPORT_TEST_COMPARE_STRING support_test_compare_string
+#define WIDE 0
+
+#include "support_test_compare_string_main.c"
diff --git a/tools/regression/lib/libc/stdio/support/support_test_compare_string_main.c b/tools/regression/lib/libc/stdio/support/support_test_compare_string_main.c
new file mode 100644
index 00000000000..40507abb600
--- /dev/null
+++ b/tools/regression/lib/libc/stdio/support/support_test_compare_string_main.c
@@ -0,0 +1,97 @@
+/* Check two strings for equality.
+   Copyright (C) 2018-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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+//#include <support/check.h>
+//#include <support/support.h>
+//#include <support/xmemstream.h>
+
+char *support_quote_blob (const void *blob, size_t length);
+void support_record_failure (void);
+
+static void
+report_length (const char *what, const CHAR *str, size_t length)
+{
+  if (str == NULL)
+    printf ("  %s string: NULL\n", what);
+  else
+    printf ("  %s string: %zu %s\n", what, length,
+	    WIDE ? "wide characters" : "bytes");
+}
+
+static void
+report_string (const char *what, const UCHAR *blob,
+               size_t length, const char *expr)
+{
+  if (length > 0)
+    {
+      printf ("  %s (evaluated from %s):\n", what, expr);
+      char *quoted = SUPPORT_QUOTE_BLOB (blob, length);
+      printf ("      %s\"%s\"\n", LPREFIX, quoted);
+      free (quoted);
+
+      fputs ("     ", stdout);
+      for (size_t i = 0; i < length; ++i)
+        printf (" %02X", (unsigned int) blob[i]);
+      putc ('\n', stdout);
+    }
+}
+
+static size_t
+string_length_or_zero (const CHAR *str)
+{
+  if (str == NULL)
+    return 0;
+  else
+    return STRLEN (str);
+}
+
+void
+SUPPORT_TEST_COMPARE_STRING (const CHAR *left, const CHAR *right,
+                             const char *file, int line,
+                             const char *left_expr, const char *right_expr)
+{
+  /* Two null pointers are accepted.  */
+  if (left == NULL && right == NULL)
+    return;
+
+  size_t left_length = string_length_or_zero (left);
+  size_t right_length = string_length_or_zero (right);
+
+  if (left_length != right_length || left == NULL || right == NULL
+      || MEMCMP (left, right, left_length) != 0)
+    {
+      support_record_failure ();
+      printf ("%s:%d: error: string comparison failed\n", file, line);
+      if (left_length == right_length && right != NULL && left != NULL)
+        printf ("  string length: %zu %s\n", left_length,
+		WIDE ? "wide characters" : "bytes");
+      else
+        {
+          report_length ("left", left, left_length);
+          report_length ("right", right, right_length);
+        }
+      report_string ("left", (const UCHAR *) left,
+                     left_length, left_expr);
+      report_string ("right", (const UCHAR *) right,
+                     right_length, right_expr);
+    }
+}
diff --git a/tools/regression/lib/libc/stdio/support/test-driver.c b/tools/regression/lib/libc/stdio/support/test-driver.c
new file mode 100644
index 00000000000..ebc2de5acf3
--- /dev/null
+++ b/tools/regression/lib/libc/stdio/support/test-driver.c
@@ -0,0 +1,5 @@
+int
+main(void)
+{
+	return do_test();
+}
diff --git a/tools/regression/lib/libc/stdio/tst-printf-binary-main.c b/tools/regression/lib/libc/stdio/tst-printf-binary-main.c
new file mode 100644
index 00000000000..02698f65ba9
--- /dev/null
+++ b/tools/regression/lib/libc/stdio/tst-printf-binary-main.c
@@ -0,0 +1,130 @@
+/* Test binary printf formats.
+   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 <limits.h>
+#include <stdio.h>
+#include <string.h>
+#include <wchar.h>
+
+#include <libc-diag.h>
+#include <support/check.h>
+
+/* GCC does not know the %b or %B formats before GCC 12.  */
+DIAG_PUSH_NEEDS_COMMENT;
+#if !__GNUC_PREREQ (12, 0)
+DIAG_IGNORE_NEEDS_COMMENT (11, "-Wformat");
+DIAG_IGNORE_NEEDS_COMMENT (11, "-Wformat-extra-args");
+#endif
+
+#define CHECK_PRINTF(EXPECTED, FMT, ...)				\
+  do									\
+    {									\
+      int ret = SNPRINTF (buf, sizeof buf / sizeof buf[0], L_(FMT),	\
+			  __VA_ARGS__);					\
+      TEST_COMPARE_STRING_MACRO (buf, L_(EXPECTED));			\
+      TEST_COMPARE (ret, STRLEN (L_(EXPECTED)));			\
+    }									\
+  while (0)
+
+static int
+do_test (void)
+{
+  CHAR buf[1024];
+  CHECK_PRINTF ("0", "%b", 0u);
+  CHECK_PRINTF ("0", "%B", 0u);
+  CHECK_PRINTF ("0", "%#b", 0u);
+  CHECK_PRINTF ("0", "%#B", 0u);
+  CHECK_PRINTF ("1", "%b", 1u);
+  CHECK_PRINTF ("1", "%B", 1u);
+  CHECK_PRINTF ("10", "%b", 2u);
+  CHECK_PRINTF ("10", "%B", 2u);
+  CHECK_PRINTF ("11", "%b", 3u);
+  CHECK_PRINTF ("11", "%B", 3u);
+  CHECK_PRINTF ("10000111011001010100001100100001", "%b", 0x87654321);
+  CHECK_PRINTF ("10000111011001010100001100100001", "%B", 0x87654321);
+  CHECK_PRINTF ("100001100100001", "%hb", (int) 0x87654321);
+  CHECK_PRINTF ("100001100100001", "%hB", (int) 0x87654321);
+  CHECK_PRINTF ("100001", "%hhb", (int) 0x87654321);
+  CHECK_PRINTF ("100001", "%hhB", (int) 0x87654321);
+  CHECK_PRINTF ("10000111011001010100001100100001", "%lb", 0x87654321ul);
+  CHECK_PRINTF ("10000111011001010100001100100001", "%lB", 0x87654321ul);
+  CHECK_PRINTF ("11111110110111001011101010011001"
+		"10000111011001010100001100100001", "%llb",
+		0xfedcba9987654321ull);
+  CHECK_PRINTF ("11111110110111001011101010011001"
+		"10000111011001010100001100100001", "%llB",
+		0xfedcba9987654321ull);
+#if LONG_WIDTH >= 64
+  CHECK_PRINTF ("11111110110111001011101010011001"
+		"10000111011001010100001100100001", "%lb",
+		0xfedcba9987654321ul);
+  CHECK_PRINTF ("11111110110111001011101010011001"
+		"10000111011001010100001100100001", "%lB",
+		0xfedcba9987654321ul);
+#endif
+  CHECK_PRINTF (" 1010", "%5b", 10u);
+  CHECK_PRINTF (" 1010", "%5B", 10u);
+  CHECK_PRINTF ("01010", "%05b", 10u);
+  CHECK_PRINTF ("01010", "%05B", 10u);
+  CHECK_PRINTF ("1011 ", "%-5b", 11u);
+  CHECK_PRINTF ("1011 ", "%-5B", 11u);
+  CHECK_PRINTF ("0b10011", "%#b", 19u);
+  CHECK_PRINTF ("0B10011", "%#B", 19u);
+  CHECK_PRINTF ("   0b10011", "%#10b", 19u);
+  CHECK_PRINTF ("   0B10011", "%#10B", 19u);
+  CHECK_PRINTF ("0b00010011", "%0#10b", 19u);
+  CHECK_PRINTF ("0B00010011", "%0#10B", 19u);
+  CHECK_PRINTF ("0b00010011", "%#010b", 19u);
+  CHECK_PRINTF ("0B00010011", "%#010B", 19u);
+  CHECK_PRINTF ("0b10011   ", "%#-10b", 19u);
+  CHECK_PRINTF ("0B10011   ", "%#-10B", 19u);
+  CHECK_PRINTF ("00010011", "%.8b", 19u);
+  CHECK_PRINTF ("00010011", "%.8B", 19u);
+  CHECK_PRINTF ("0b00010011", "%#.8b", 19u);
+  CHECK_PRINTF ("0B00010011", "%#.8B", 19u);
+  CHECK_PRINTF ("       00010011", "%15.8b", 19u);
+  CHECK_PRINTF ("       00010011", "%15.8B", 19u);
+  CHECK_PRINTF ("00010011       ", "%-15.8b", 19u);
+  CHECK_PRINTF ("00010011       ", "%-15.8B", 19u);
+  CHECK_PRINTF ("     0b00010011", "%#15.8b", 19u);
+  CHECK_PRINTF ("     0B00010011", "%#15.8B", 19u);
+  CHECK_PRINTF ("0b00010011     ", "%-#15.8b", 19u);
+  CHECK_PRINTF ("0B00010011     ", "%-#15.8B", 19u);
+  /* GCC diagnoses ignored flags.  */
+  DIAG_PUSH_NEEDS_COMMENT;
+  DIAG_IGNORE_NEEDS_COMMENT (12, "-Wformat");
+  /* '0' flag ignored with '-'.  */
+  CHECK_PRINTF ("1011 ", "%0-5b", 11u);
+  CHECK_PRINTF ("1011 ", "%0-5B", 11u);
+  CHECK_PRINTF ("0b10011   ", "%#0-10b", 19u);
+  CHECK_PRINTF ("0B10011   ", "%#0-10B", 19u);
+  /* '0' flag ignored with precision.  */
+  CHECK_PRINTF ("       00010011", "%015.8b", 19u);
+  CHECK_PRINTF ("       00010011", "%015.8B", 19u);
+  CHECK_PRINTF ("     0b00010011", "%0#15.8b", 19u);
+  CHECK_PRINTF ("     0B00010011", "%0#15.8B", 19u);
+  DIAG_POP_NEEDS_COMMENT;
+  /* Test positional argument handling.  */
+  CHECK_PRINTF ("test 1011 test2 100010001000100010001000100010001",
+		"%2$s %1$b %4$s %3$llb", 11u, "test", 0x111111111ull, "test2");
+  return 0;
+}
+
+DIAG_POP_NEEDS_COMMENT;
+
+#include <support/test-driver.c>
diff --git a/tools/regression/lib/libc/stdio/tst-printf-binary.c b/tools/regression/lib/libc/stdio/tst-printf-binary.c
new file mode 100644
index 00000000000..bb044b571d2
--- /dev/null
+++ b/tools/regression/lib/libc/stdio/tst-printf-binary.c
@@ -0,0 +1,25 @@
+/* Test binary printf formats.  Narrow string version.
+   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/>.  */
+
+#define SNPRINTF snprintf
+#define TEST_COMPARE_STRING_MACRO TEST_COMPARE_STRING
+#define STRLEN strlen
+#define CHAR char
+#define L_(C) C
+
+#include <tst-printf-binary-main.c>
-- 
2.42.0

