forked from rpms/glibc
bdebdc5e8b
* Wed Jan 19 2022 Florian Weimer <fweimer@redhat.com> - 2.34-20 - More reliable CPU compatibility diagnostics (#2040657) Resolves: #2040657
634 lines
14 KiB
Diff
634 lines
14 KiB
Diff
commit b693d75f0c611bce9b0ad984bad306121d42c535
|
|
Author: Florian Weimer <fweimer@redhat.com>
|
|
Date: Fri Jan 14 20:16:05 2022 +0100
|
|
|
|
elf: Split dl-printf.c from dl-misc.c
|
|
|
|
This allows to use different compiler flags for the diagnostics
|
|
code.
|
|
|
|
Reviewed-by: H.J. Lu <hjl.tools@gmail.com>
|
|
|
|
diff --git a/elf/Makefile b/elf/Makefile
|
|
index 124905f96c88ab53..52aafc89cec835ab 100644
|
|
--- a/elf/Makefile
|
|
+++ b/elf/Makefile
|
|
@@ -64,6 +64,7 @@ dl-routines = \
|
|
dl-object \
|
|
dl-open \
|
|
dl-origin \
|
|
+ dl-printf \
|
|
dl-profile \
|
|
dl-reloc \
|
|
dl-runtime \
|
|
diff --git a/elf/dl-misc.c b/elf/dl-misc.c
|
|
index b256d792c6198683..f17140b129343f7b 100644
|
|
--- a/elf/dl-misc.c
|
|
+++ b/elf/dl-misc.c
|
|
@@ -16,24 +16,16 @@
|
|
License along with the GNU C Library; if not, see
|
|
<https://www.gnu.org/licenses/>. */
|
|
|
|
-#include <assert.h>
|
|
+#include <_itoa.h>
|
|
#include <fcntl.h>
|
|
#include <ldsodefs.h>
|
|
-#include <limits.h>
|
|
#include <link.h>
|
|
-#include <stdarg.h>
|
|
-#include <stdlib.h>
|
|
-#include <string.h>
|
|
-#include <unistd.h>
|
|
+#include <not-cancel.h>
|
|
#include <stdint.h>
|
|
+#include <stdlib.h>
|
|
#include <sys/mman.h>
|
|
-#include <sys/param.h>
|
|
#include <sys/stat.h>
|
|
-#include <sys/uio.h>
|
|
-#include <sysdep.h>
|
|
-#include <_itoa.h>
|
|
-#include <dl-writev.h>
|
|
-#include <not-cancel.h>
|
|
+#include <unistd.h>
|
|
|
|
/* Read the whole contents of FILE into new mmap'd space with given
|
|
protections. *SIZEP gets the size of the file. On error MAP_FAILED
|
|
@@ -70,270 +62,6 @@ _dl_sysdep_read_whole_file (const char *file, size_t *sizep, int prot)
|
|
return result;
|
|
}
|
|
|
|
-
|
|
-/* Bare-bones printf implementation. This function only knows about
|
|
- the formats and flags needed and can handle only up to 64 stripes in
|
|
- the output. */
|
|
-static void
|
|
-_dl_debug_vdprintf (int fd, int tag_p, const char *fmt, va_list arg)
|
|
-{
|
|
-# define NIOVMAX 64
|
|
- struct iovec iov[NIOVMAX];
|
|
- int niov = 0;
|
|
- pid_t pid = 0;
|
|
- char pidbuf[12];
|
|
-
|
|
- while (*fmt != '\0')
|
|
- {
|
|
- const char *startp = fmt;
|
|
-
|
|
- if (tag_p > 0)
|
|
- {
|
|
- /* Generate the tag line once. It consists of the PID and a
|
|
- colon followed by a tab. */
|
|
- if (pid == 0)
|
|
- {
|
|
- char *p;
|
|
- pid = __getpid ();
|
|
- assert (pid >= 0 && sizeof (pid_t) <= 4);
|
|
- p = _itoa (pid, &pidbuf[10], 10, 0);
|
|
- while (p > pidbuf)
|
|
- *--p = ' ';
|
|
- pidbuf[10] = ':';
|
|
- pidbuf[11] = '\t';
|
|
- }
|
|
-
|
|
- /* Append to the output. */
|
|
- assert (niov < NIOVMAX);
|
|
- iov[niov].iov_len = 12;
|
|
- iov[niov++].iov_base = pidbuf;
|
|
-
|
|
- /* No more tags until we see the next newline. */
|
|
- tag_p = -1;
|
|
- }
|
|
-
|
|
- /* Skip everything except % and \n (if tags are needed). */
|
|
- while (*fmt != '\0' && *fmt != '%' && (! tag_p || *fmt != '\n'))
|
|
- ++fmt;
|
|
-
|
|
- /* Append constant string. */
|
|
- assert (niov < NIOVMAX);
|
|
- if ((iov[niov].iov_len = fmt - startp) != 0)
|
|
- iov[niov++].iov_base = (char *) startp;
|
|
-
|
|
- if (*fmt == '%')
|
|
- {
|
|
- /* It is a format specifier. */
|
|
- char fill = ' ';
|
|
- int width = -1;
|
|
- int prec = -1;
|
|
-#if LONG_MAX != INT_MAX
|
|
- int long_mod = 0;
|
|
-#endif
|
|
-
|
|
- /* Recognize zero-digit fill flag. */
|
|
- if (*++fmt == '0')
|
|
- {
|
|
- fill = '0';
|
|
- ++fmt;
|
|
- }
|
|
-
|
|
- /* See whether with comes from a parameter. Note that no other
|
|
- way to specify the width is implemented. */
|
|
- if (*fmt == '*')
|
|
- {
|
|
- width = va_arg (arg, int);
|
|
- ++fmt;
|
|
- }
|
|
-
|
|
- /* Handle precision. */
|
|
- if (*fmt == '.' && fmt[1] == '*')
|
|
- {
|
|
- prec = va_arg (arg, int);
|
|
- fmt += 2;
|
|
- }
|
|
-
|
|
- /* Recognize the l modifier. It is only important on some
|
|
- platforms where long and int have a different size. We
|
|
- can use the same code for size_t. */
|
|
- if (*fmt == 'l' || *fmt == 'Z')
|
|
- {
|
|
-#if LONG_MAX != INT_MAX
|
|
- long_mod = 1;
|
|
-#endif
|
|
- ++fmt;
|
|
- }
|
|
-
|
|
- switch (*fmt)
|
|
- {
|
|
- /* Integer formatting. */
|
|
- case 'd':
|
|
- case 'u':
|
|
- case 'x':
|
|
- {
|
|
- /* We have to make a difference if long and int have a
|
|
- different size. */
|
|
-#if LONG_MAX != INT_MAX
|
|
- unsigned long int num = (long_mod
|
|
- ? va_arg (arg, unsigned long int)
|
|
- : va_arg (arg, unsigned int));
|
|
-#else
|
|
- unsigned long int num = va_arg (arg, unsigned int);
|
|
-#endif
|
|
- bool negative = false;
|
|
- if (*fmt == 'd')
|
|
- {
|
|
-#if LONG_MAX != INT_MAX
|
|
- if (long_mod)
|
|
- {
|
|
- if ((long int) num < 0)
|
|
- negative = true;
|
|
- }
|
|
- else
|
|
- {
|
|
- if ((int) num < 0)
|
|
- {
|
|
- num = (unsigned int) num;
|
|
- negative = true;
|
|
- }
|
|
- }
|
|
-#else
|
|
- if ((int) num < 0)
|
|
- negative = true;
|
|
-#endif
|
|
- }
|
|
-
|
|
- /* We use alloca() to allocate the buffer with the most
|
|
- pessimistic guess for the size. Using alloca() allows
|
|
- having more than one integer formatting in a call. */
|
|
- char *buf = (char *) alloca (1 + 3 * sizeof (unsigned long int));
|
|
- char *endp = &buf[1 + 3 * sizeof (unsigned long int)];
|
|
- char *cp = _itoa (num, endp, *fmt == 'x' ? 16 : 10, 0);
|
|
-
|
|
- /* Pad to the width the user specified. */
|
|
- if (width != -1)
|
|
- while (endp - cp < width)
|
|
- *--cp = fill;
|
|
-
|
|
- if (negative)
|
|
- *--cp = '-';
|
|
-
|
|
- iov[niov].iov_base = cp;
|
|
- iov[niov].iov_len = endp - cp;
|
|
- ++niov;
|
|
- }
|
|
- break;
|
|
-
|
|
- case 's':
|
|
- /* Get the string argument. */
|
|
- iov[niov].iov_base = va_arg (arg, char *);
|
|
- iov[niov].iov_len = strlen (iov[niov].iov_base);
|
|
- if (prec != -1)
|
|
- iov[niov].iov_len = MIN ((size_t) prec, iov[niov].iov_len);
|
|
- ++niov;
|
|
- break;
|
|
-
|
|
- case '%':
|
|
- iov[niov].iov_base = (void *) fmt;
|
|
- iov[niov].iov_len = 1;
|
|
- ++niov;
|
|
- break;
|
|
-
|
|
- default:
|
|
- assert (! "invalid format specifier");
|
|
- }
|
|
- ++fmt;
|
|
- }
|
|
- else if (*fmt == '\n')
|
|
- {
|
|
- /* See whether we have to print a single newline character. */
|
|
- if (fmt == startp)
|
|
- {
|
|
- iov[niov].iov_base = (char *) startp;
|
|
- iov[niov++].iov_len = 1;
|
|
- }
|
|
- else
|
|
- /* No, just add it to the rest of the string. */
|
|
- ++iov[niov - 1].iov_len;
|
|
-
|
|
- /* Next line, print a tag again. */
|
|
- tag_p = 1;
|
|
- ++fmt;
|
|
- }
|
|
- }
|
|
-
|
|
- /* Finally write the result. */
|
|
- _dl_writev (fd, iov, niov);
|
|
-}
|
|
-
|
|
-
|
|
-/* Write to debug file. */
|
|
-void
|
|
-_dl_debug_printf (const char *fmt, ...)
|
|
-{
|
|
- va_list arg;
|
|
-
|
|
- va_start (arg, fmt);
|
|
- _dl_debug_vdprintf (GLRO(dl_debug_fd), 1, fmt, arg);
|
|
- va_end (arg);
|
|
-}
|
|
-
|
|
-
|
|
-/* Write to debug file but don't start with a tag. */
|
|
-void
|
|
-_dl_debug_printf_c (const char *fmt, ...)
|
|
-{
|
|
- va_list arg;
|
|
-
|
|
- va_start (arg, fmt);
|
|
- _dl_debug_vdprintf (GLRO(dl_debug_fd), -1, fmt, arg);
|
|
- va_end (arg);
|
|
-}
|
|
-
|
|
-
|
|
-/* Write the given file descriptor. */
|
|
-void
|
|
-_dl_dprintf (int fd, const char *fmt, ...)
|
|
-{
|
|
- va_list arg;
|
|
-
|
|
- va_start (arg, fmt);
|
|
- _dl_debug_vdprintf (fd, 0, fmt, arg);
|
|
- va_end (arg);
|
|
-}
|
|
-
|
|
-void
|
|
-_dl_printf (const char *fmt, ...)
|
|
-{
|
|
- va_list arg;
|
|
-
|
|
- va_start (arg, fmt);
|
|
- _dl_debug_vdprintf (STDOUT_FILENO, 0, fmt, arg);
|
|
- va_end (arg);
|
|
-}
|
|
-
|
|
-void
|
|
-_dl_error_printf (const char *fmt, ...)
|
|
-{
|
|
- va_list arg;
|
|
-
|
|
- va_start (arg, fmt);
|
|
- _dl_debug_vdprintf (STDERR_FILENO, 0, fmt, arg);
|
|
- va_end (arg);
|
|
-}
|
|
-
|
|
-void
|
|
-_dl_fatal_printf (const char *fmt, ...)
|
|
-{
|
|
- va_list arg;
|
|
-
|
|
- va_start (arg, fmt);
|
|
- _dl_debug_vdprintf (STDERR_FILENO, 0, fmt, arg);
|
|
- va_end (arg);
|
|
- _exit (127);
|
|
-}
|
|
-rtld_hidden_def (_dl_fatal_printf)
|
|
-
|
|
/* Test whether given NAME matches any of the names of the given object. */
|
|
int
|
|
_dl_name_match_p (const char *name, const struct link_map *map)
|
|
@@ -354,7 +82,6 @@ _dl_name_match_p (const char *name, const struct link_map *map)
|
|
return 0;
|
|
}
|
|
|
|
-
|
|
unsigned long int
|
|
_dl_higher_prime_number (unsigned long int n)
|
|
{
|
|
diff --git a/elf/dl-printf.c b/elf/dl-printf.c
|
|
new file mode 100644
|
|
index 0000000000000000..d3264ba96cd959bf
|
|
--- /dev/null
|
|
+++ b/elf/dl-printf.c
|
|
@@ -0,0 +1,292 @@
|
|
+/* printf implementation for the dynamic loader.
|
|
+ Copyright (C) 1997-2022 Free Software Foundation, Inc.
|
|
+ This file is part of the GNU C Library.
|
|
+
|
|
+ The GNU C Library is free software; you can redistribute it and/or
|
|
+ modify it under the terms of the GNU Lesser General Public
|
|
+ License as published by the Free Software Foundation; either
|
|
+ version 2.1 of the License, or (at your option) any later version.
|
|
+
|
|
+ The GNU C Library is distributed in the hope that it will be useful,
|
|
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
+ Lesser General Public License for more details.
|
|
+
|
|
+ You should have received a copy of the GNU Lesser General Public
|
|
+ License along with the GNU C Library; if not, see
|
|
+ <https://www.gnu.org/licenses/>. */
|
|
+
|
|
+#include <_itoa.h>
|
|
+#include <assert.h>
|
|
+#include <dl-writev.h>
|
|
+#include <ldsodefs.h>
|
|
+#include <limits.h>
|
|
+#include <stdarg.h>
|
|
+#include <stdint.h>
|
|
+#include <stdlib.h>
|
|
+#include <string.h>
|
|
+#include <sys/uio.h>
|
|
+#include <unistd.h>
|
|
+
|
|
+/* Bare-bones printf implementation. This function only knows about
|
|
+ the formats and flags needed and can handle only up to 64 stripes in
|
|
+ the output. */
|
|
+static void
|
|
+_dl_debug_vdprintf (int fd, int tag_p, const char *fmt, va_list arg)
|
|
+{
|
|
+# define NIOVMAX 64
|
|
+ struct iovec iov[NIOVMAX];
|
|
+ int niov = 0;
|
|
+ pid_t pid = 0;
|
|
+ char pidbuf[12];
|
|
+
|
|
+ while (*fmt != '\0')
|
|
+ {
|
|
+ const char *startp = fmt;
|
|
+
|
|
+ if (tag_p > 0)
|
|
+ {
|
|
+ /* Generate the tag line once. It consists of the PID and a
|
|
+ colon followed by a tab. */
|
|
+ if (pid == 0)
|
|
+ {
|
|
+ char *p;
|
|
+ pid = __getpid ();
|
|
+ assert (pid >= 0 && sizeof (pid_t) <= 4);
|
|
+ p = _itoa (pid, &pidbuf[10], 10, 0);
|
|
+ while (p > pidbuf)
|
|
+ *--p = ' ';
|
|
+ pidbuf[10] = ':';
|
|
+ pidbuf[11] = '\t';
|
|
+ }
|
|
+
|
|
+ /* Append to the output. */
|
|
+ assert (niov < NIOVMAX);
|
|
+ iov[niov].iov_len = 12;
|
|
+ iov[niov++].iov_base = pidbuf;
|
|
+
|
|
+ /* No more tags until we see the next newline. */
|
|
+ tag_p = -1;
|
|
+ }
|
|
+
|
|
+ /* Skip everything except % and \n (if tags are needed). */
|
|
+ while (*fmt != '\0' && *fmt != '%' && (! tag_p || *fmt != '\n'))
|
|
+ ++fmt;
|
|
+
|
|
+ /* Append constant string. */
|
|
+ assert (niov < NIOVMAX);
|
|
+ if ((iov[niov].iov_len = fmt - startp) != 0)
|
|
+ iov[niov++].iov_base = (char *) startp;
|
|
+
|
|
+ if (*fmt == '%')
|
|
+ {
|
|
+ /* It is a format specifier. */
|
|
+ char fill = ' ';
|
|
+ int width = -1;
|
|
+ int prec = -1;
|
|
+#if LONG_MAX != INT_MAX
|
|
+ int long_mod = 0;
|
|
+#endif
|
|
+
|
|
+ /* Recognize zero-digit fill flag. */
|
|
+ if (*++fmt == '0')
|
|
+ {
|
|
+ fill = '0';
|
|
+ ++fmt;
|
|
+ }
|
|
+
|
|
+ /* See whether with comes from a parameter. Note that no other
|
|
+ way to specify the width is implemented. */
|
|
+ if (*fmt == '*')
|
|
+ {
|
|
+ width = va_arg (arg, int);
|
|
+ ++fmt;
|
|
+ }
|
|
+
|
|
+ /* Handle precision. */
|
|
+ if (*fmt == '.' && fmt[1] == '*')
|
|
+ {
|
|
+ prec = va_arg (arg, int);
|
|
+ fmt += 2;
|
|
+ }
|
|
+
|
|
+ /* Recognize the l modifier. It is only important on some
|
|
+ platforms where long and int have a different size. We
|
|
+ can use the same code for size_t. */
|
|
+ if (*fmt == 'l' || *fmt == 'Z')
|
|
+ {
|
|
+#if LONG_MAX != INT_MAX
|
|
+ long_mod = 1;
|
|
+#endif
|
|
+ ++fmt;
|
|
+ }
|
|
+
|
|
+ switch (*fmt)
|
|
+ {
|
|
+ /* Integer formatting. */
|
|
+ case 'd':
|
|
+ case 'u':
|
|
+ case 'x':
|
|
+ {
|
|
+ /* We have to make a difference if long and int have a
|
|
+ different size. */
|
|
+#if LONG_MAX != INT_MAX
|
|
+ unsigned long int num = (long_mod
|
|
+ ? va_arg (arg, unsigned long int)
|
|
+ : va_arg (arg, unsigned int));
|
|
+#else
|
|
+ unsigned long int num = va_arg (arg, unsigned int);
|
|
+#endif
|
|
+ bool negative = false;
|
|
+ if (*fmt == 'd')
|
|
+ {
|
|
+#if LONG_MAX != INT_MAX
|
|
+ if (long_mod)
|
|
+ {
|
|
+ if ((long int) num < 0)
|
|
+ negative = true;
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ if ((int) num < 0)
|
|
+ {
|
|
+ num = (unsigned int) num;
|
|
+ negative = true;
|
|
+ }
|
|
+ }
|
|
+#else
|
|
+ if ((int) num < 0)
|
|
+ negative = true;
|
|
+#endif
|
|
+ }
|
|
+
|
|
+ /* We use alloca() to allocate the buffer with the most
|
|
+ pessimistic guess for the size. Using alloca() allows
|
|
+ having more than one integer formatting in a call. */
|
|
+ char *buf = (char *) alloca (1 + 3 * sizeof (unsigned long int));
|
|
+ char *endp = &buf[1 + 3 * sizeof (unsigned long int)];
|
|
+ char *cp = _itoa (num, endp, *fmt == 'x' ? 16 : 10, 0);
|
|
+
|
|
+ /* Pad to the width the user specified. */
|
|
+ if (width != -1)
|
|
+ while (endp - cp < width)
|
|
+ *--cp = fill;
|
|
+
|
|
+ if (negative)
|
|
+ *--cp = '-';
|
|
+
|
|
+ iov[niov].iov_base = cp;
|
|
+ iov[niov].iov_len = endp - cp;
|
|
+ ++niov;
|
|
+ }
|
|
+ break;
|
|
+
|
|
+ case 's':
|
|
+ /* Get the string argument. */
|
|
+ iov[niov].iov_base = va_arg (arg, char *);
|
|
+ iov[niov].iov_len = strlen (iov[niov].iov_base);
|
|
+ if (prec != -1)
|
|
+ iov[niov].iov_len = MIN ((size_t) prec, iov[niov].iov_len);
|
|
+ ++niov;
|
|
+ break;
|
|
+
|
|
+ case '%':
|
|
+ iov[niov].iov_base = (void *) fmt;
|
|
+ iov[niov].iov_len = 1;
|
|
+ ++niov;
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ assert (! "invalid format specifier");
|
|
+ }
|
|
+ ++fmt;
|
|
+ }
|
|
+ else if (*fmt == '\n')
|
|
+ {
|
|
+ /* See whether we have to print a single newline character. */
|
|
+ if (fmt == startp)
|
|
+ {
|
|
+ iov[niov].iov_base = (char *) startp;
|
|
+ iov[niov++].iov_len = 1;
|
|
+ }
|
|
+ else
|
|
+ /* No, just add it to the rest of the string. */
|
|
+ ++iov[niov - 1].iov_len;
|
|
+
|
|
+ /* Next line, print a tag again. */
|
|
+ tag_p = 1;
|
|
+ ++fmt;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* Finally write the result. */
|
|
+ _dl_writev (fd, iov, niov);
|
|
+}
|
|
+
|
|
+
|
|
+/* Write to debug file. */
|
|
+void
|
|
+_dl_debug_printf (const char *fmt, ...)
|
|
+{
|
|
+ va_list arg;
|
|
+
|
|
+ va_start (arg, fmt);
|
|
+ _dl_debug_vdprintf (GLRO(dl_debug_fd), 1, fmt, arg);
|
|
+ va_end (arg);
|
|
+}
|
|
+
|
|
+
|
|
+/* Write to debug file but don't start with a tag. */
|
|
+void
|
|
+_dl_debug_printf_c (const char *fmt, ...)
|
|
+{
|
|
+ va_list arg;
|
|
+
|
|
+ va_start (arg, fmt);
|
|
+ _dl_debug_vdprintf (GLRO(dl_debug_fd), -1, fmt, arg);
|
|
+ va_end (arg);
|
|
+}
|
|
+
|
|
+
|
|
+/* Write the given file descriptor. */
|
|
+void
|
|
+_dl_dprintf (int fd, const char *fmt, ...)
|
|
+{
|
|
+ va_list arg;
|
|
+
|
|
+ va_start (arg, fmt);
|
|
+ _dl_debug_vdprintf (fd, 0, fmt, arg);
|
|
+ va_end (arg);
|
|
+}
|
|
+
|
|
+void
|
|
+_dl_printf (const char *fmt, ...)
|
|
+{
|
|
+ va_list arg;
|
|
+
|
|
+ va_start (arg, fmt);
|
|
+ _dl_debug_vdprintf (STDOUT_FILENO, 0, fmt, arg);
|
|
+ va_end (arg);
|
|
+}
|
|
+
|
|
+void
|
|
+_dl_error_printf (const char *fmt, ...)
|
|
+{
|
|
+ va_list arg;
|
|
+
|
|
+ va_start (arg, fmt);
|
|
+ _dl_debug_vdprintf (STDERR_FILENO, 0, fmt, arg);
|
|
+ va_end (arg);
|
|
+}
|
|
+
|
|
+void
|
|
+_dl_fatal_printf (const char *fmt, ...)
|
|
+{
|
|
+ va_list arg;
|
|
+
|
|
+ va_start (arg, fmt);
|
|
+ _dl_debug_vdprintf (STDERR_FILENO, 0, fmt, arg);
|
|
+ va_end (arg);
|
|
+ _exit (127);
|
|
+}
|
|
+rtld_hidden_def (_dl_fatal_printf)
|