about summary refs log tree commit diff
path: root/elf/tst-libc_dlvsym.h
diff options
context:
space:
mode:
authorFlorian Weimer <fweimer@redhat.com>2018-01-04 18:46:17 +0100
committerFlorian Weimer <fweimer@redhat.com>2018-01-04 18:46:24 +0100
commit82eef55f8fad3e00c53050de5d6ebea08df488b3 (patch)
treee0e1ed86b2296703182789d7f5ea607bf066ffe4 /elf/tst-libc_dlvsym.h
parent7abf02f3ee7627d617def77d0d6e7bea2da8d98c (diff)
downloadglibc-82eef55f8fad3e00c53050de5d6ebea08df488b3.tar.gz
glibc-82eef55f8fad3e00c53050de5d6ebea08df488b3.tar.xz
glibc-82eef55f8fad3e00c53050de5d6ebea08df488b3.zip
elf: Support dlvsym within libc.so
This commit adds a new _dl_open_hook entry for dlvsym and implements the
function using the existing dl_lookup_symbol_x function supplied by the
dynamic loader.

A new hook variable, _dl_open_hook2, is introduced, which should make
this change suitable for backporting: For old statically linked
binaries, __libc_dlvsym will always return NULL.
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);
+}