summaryrefslogtreecommitdiff
path: root/elf/tst-libc_dlvsym.h
diff options
context:
space:
mode:
Diffstat (limited to 'elf/tst-libc_dlvsym.h')
-rw-r--r--elf/tst-libc_dlvsym.h125
1 files changed, 125 insertions, 0 deletions
diff --git a/elf/tst-libc_dlvsym.h b/elf/tst-libc_dlvsym.h
new file mode 100644
index 0000000000..6b1d8d5b3a
--- /dev/null
+++ b/elf/tst-libc_dlvsym.h
@@ -0,0 +1,125 @@
+/* Compare dlvsym and __libc_dlvsym results. Common code.
+ Copyright (C) 2017 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/>. */
+
+/* compare_vsyms is the main entry point for these tests.
+
+ Indirectly, It calls __libc_dlvsym (from libc.so; internal
+ interface) and dlvsym (from libdl.so; public interface) to compare
+ the results for a selected set of symbols in libc.so which
+ typically have more than one symbol version. The two functions are
+ implemented by somewhat different code, and this test checks that
+ their results are the same.
+
+ The versions are generated to range from GLIBC_2.0 to GLIBC_2.Y,
+ with Y being the current __GLIBC_MINOR__ version plus two. In
+ addition, there is a list of special symbol versions of the form
+ GLIBC_2.Y.Z, which were used for some releases.
+
+ Comparing the two dlvsym results at versions which do not actually
+ exist does not test much, but it will not contribute to false test
+ failures, either. */
+
+#include <array_length.h>
+#include <gnu/lib-names.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <support/check.h>
+#include <support/xdlfcn.h>
+
+/* Run consistency check for versioned symbol NAME@VERSION. NB: We
+ may execute in a shared object, so exit on error for proper error
+ reporting. */
+static void
+compare_vsyms_0 (void *libc_handle, const char *name, const char *version,
+ bool *pfound)
+{
+ void *dlvsym_address = dlvsym (libc_handle, name, version);
+ void *libc_dlvsym_address
+ = __libc_dlvsym (libc_handle, name, version);
+ if (dlvsym_address != libc_dlvsym_address)
+ FAIL_EXIT1 ("%s@%s mismatch: %p != %p",
+ name, version, dlvsym_address, libc_dlvsym_address);
+ if (dlvsym_address != NULL)
+ *pfound = true;
+}
+
+
+/* Run consistency check for versioned symbol NAME at multiple symbol
+ version. */
+static void
+compare_vsyms_1 (void *libc_handle, const char *name)
+{
+ bool found = false;
+
+ /* Historic versions which do not follow the usual GLIBC_2.Y
+ pattern, to increase test coverage. Not all architectures have
+ those, but probing additional versions does not hurt. */
+ static const char special_versions[][12] =
+ {
+ "GLIBC_2.1.1",
+ "GLIBC_2.1.2",
+ "GLIBC_2.1.3",
+ "GLIBC_2.1.4",
+ "GLIBC_2.2.1",
+ "GLIBC_2.2.2",
+ "GLIBC_2.2.3",
+ "GLIBC_2.2.4",
+ "GLIBC_2.2.5",
+ "GLIBC_2.2.6",
+ "GLIBC_2.3.2",
+ "GLIBC_2.3.3",
+ "GLIBC_2.3.4",
+ };
+ for (int i = 0; i < array_length (special_versions); ++i)
+ compare_vsyms_0 (libc_handle, name, special_versions[i], &found);
+
+ /* Iterate to an out-of-range version, to cover some unused symbols
+ as well. */
+ for (int minor_version = 0; minor_version <= __GLIBC_MINOR__ + 2;
+ ++minor_version)
+ {
+ char version[30];
+ snprintf (version, sizeof (version), "GLIBC_%d.%d",
+ __GLIBC__, minor_version);
+ compare_vsyms_0 (libc_handle, name, version, &found);
+ }
+
+ if (!found)
+ FAIL_EXIT1 ("symbol %s not found at any version", name);
+}
+
+/* Run consistency checks for various symbols which usually have
+ multiple versions. */
+static void
+compare_vsyms (void)
+{
+ /* The minor version loop in compare_vsyms_1 needs updating in case
+ we ever switch to glibc 3.0. */
+ if (__GLIBC__ != 2)
+ FAIL_EXIT1 ("unexpected glibc major version: %d", __GLIBC__);
+
+ /* __libc_dlvsym does not recognize the special RTLD_* handles, so
+ obtain an explicit handle for libc.so. */
+ void *libc_handle = xdlopen (LIBC_SO, RTLD_LAZY | RTLD_NOLOAD);
+
+ compare_vsyms_1 (libc_handle, "_sys_errlist");
+ compare_vsyms_1 (libc_handle, "_sys_siglist");
+ compare_vsyms_1 (libc_handle, "quick_exit");
+
+ xdlclose (libc_handle);
+}