dlfnc: Add RTLD_DL_HANDLE (dlopen handle) support to dladdr1
diff mbox series

Message ID 87zhiclnrv.fsf@oldenburg2.str.redhat.com
State New
Headers show
Series
  • dlfnc: Add RTLD_DL_HANDLE (dlopen handle) support to dladdr1
Related show

Commit Message

Florian Weimer Oct. 7, 2019, 12:53 p.m. UTC
Previously, only struct link_map * results were supported.  While
the two pointers are the same in the currrent implementation, this
is not gurantueed by the interface in other places.

-----
Note: Not posting a ChangeLog entry, on the assumption that we will
switch to automatic generation.

Comments

Florian Weimer Oct. 7, 2019, 2:37 p.m. UTC | #1
I fixed the typo in the subject locally.

Florian

Patch
diff mbox series

diff --git a/NEWS b/NEWS
index d7286841c9..2ea7378d10 100644
--- a/NEWS
+++ b/NEWS
@@ -21,6 +21,9 @@  Major new features:
   18661-1:2014 and TS 18661-3:2015 as amended by the resolution of
   Clarification Request 13 to TS 18661-3.
 
+* The dladdr1 function accepts a new flag, RTLD_DL_HANDLE, to obtain a
+  handle (as used with dlsym and other functions) based on an address.
+
 Deprecated and removed features, and other changes affecting compatibility:
 
 * The totalorder and totalordermag functions, and the corresponding
diff --git a/dlfcn/Makefile b/dlfcn/Makefile
index 749bb79b91..2169a77f83 100644
--- a/dlfcn/Makefile
+++ b/dlfcn/Makefile
@@ -36,7 +36,7 @@  endif
 ifeq (yes,$(build-shared))
 tests = glrefmain failtest tst-dladdr default errmsg1 tstcxaatexit \
 	bug-dlopen1 bug-dlsym1 tst-dlinfo bug-atexit1 bug-atexit2 \
-	bug-atexit3 tstatexit bug-dl-leaf tst-rec-dlopen
+	bug-atexit3 tstatexit bug-dl-leaf tst-rec-dlopen tst-dladdr1-handle
 endif
 modules-names = glreflib1 glreflib2 glreflib3 failtestmod defaultmod1 \
 		defaultmod2 errmsg1mod modatexit modcxaatexit \
@@ -151,3 +151,6 @@  $(objpfx)bug-dl-leaf-lib-cb.so: $(objpfx)bug-dl-leaf-lib.so
 
 $(objpfx)tst-rec-dlopen: $(libdl)
 $(objpfx)tst-rec-dlopen.out: $(objpfx)moddummy1.so $(objpfx)moddummy2.so
+
+$(objpfx)tst-dladdr1-handle: $(libdl)
+$(objpfx)tst-dladdr1-handle.out: $(objpfx)moddummy1.so $(objpfx)moddummy2.so
diff --git a/dlfcn/dladdr1.c b/dlfcn/dladdr1.c
index 63e78ff525..536116543e 100644
--- a/dlfcn/dladdr1.c
+++ b/dlfcn/dladdr1.c
@@ -45,6 +45,7 @@  __dladdr1 (const void *address, Dl_info *info, void **extra, int flags)
     case RTLD_DL_SYMENT:
       return _dl_addr (address, info, NULL, (const ElfW(Sym) **) extra);
     case RTLD_DL_LINKMAP:
+    case RTLD_DL_HANDLE:
       return _dl_addr (address, info, (struct link_map **) extra, NULL);
     }
 }
diff --git a/dlfcn/dlfcn.h b/dlfcn/dlfcn.h
index ebd3c457e3..b657f2762f 100644
--- a/dlfcn/dlfcn.h
+++ b/dlfcn/dlfcn.h
@@ -111,7 +111,12 @@  enum
     RTLD_DL_SYMENT = 1,
 
     /* The object containing the address (struct link_map *).  */
-    RTLD_DL_LINKMAP = 2
+    RTLD_DL_LINKMAP = 2,
+
+    /* The object containing the address, as identified by its handle
+       (void *).  The handle is compatible with functions such as
+       dlsym.  */
+    RTLD_DL_HANDLE = 3
   };
 
 
diff --git a/dlfcn/moddummy1.c b/dlfcn/moddummy1.c
index 6e549fa7d2..6496d2eaeb 100644
--- a/dlfcn/moddummy1.c
+++ b/dlfcn/moddummy1.c
@@ -1,4 +1,4 @@ 
-/* Provide a dummy DSO for tst-rec-dlopen to use.  */
+/* Provide a dummy DSO for tst-rec-dlopen, tst-dladdr1-handle to use.  */
 #include <stdio.h>
 #include <stdlib.h>
 
diff --git a/dlfcn/moddummy2.c b/dlfcn/moddummy2.c
index cb4edc8da7..4e63e9a1fc 100644
--- a/dlfcn/moddummy2.c
+++ b/dlfcn/moddummy2.c
@@ -1,4 +1,4 @@ 
-/* Provide a dummy DSO for tst-rec-dlopen to use.  */
+/* Provide a dummy DSO for tst-rec-dlopen, tst-dladdr1-handle to use.  */
 #include <stdio.h>
 #include <stdlib.h>
 
diff --git a/dlfcn/tst-dladdr1-handle.c b/dlfcn/tst-dladdr1-handle.c
new file mode 100644
index 0000000000..25f36a2edf
--- /dev/null
+++ b/dlfcn/tst-dladdr1-handle.c
@@ -0,0 +1,75 @@ 
+/* Test for dladdr1 with RTLD_DL_HANDLE.
+   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, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <dlfcn.h>
+#include <gnu/lib-names.h>
+#include <link.h>
+#include <support/check.h>
+#include <support/xdlfcn.h>
+#include <stddef.h>
+
+static void
+local_function (void)
+{
+}
+
+static int
+do_test (void)
+{
+  Dl_info info;
+  void *handle;
+
+  if (dladdr1 (&local_function, &info, &handle, RTLD_DL_HANDLE) == 0)
+    FAIL_EXIT1 ("dladdr1 for local_function failed");
+
+  /* The handle should be usable with dlsym.  */
+  TEST_VERIFY (xdlsym (handle, "dlsym") == xdlsym (NULL, "dlsym"));
+
+  /* Check that libc is correctly identified.  Use an obscure libc
+     function as reference, to avoid PLT stubs and similar constructs
+     moving the active definition to another object.  */
+  void *libc_handle = xdlopen (LIBC_SO, RTLD_NOW);
+  void *ptr = xdlsym (libc_handle, "grantpt");
+  if (dladdr1 (ptr, &info, &handle, RTLD_DL_HANDLE) == 0)
+    FAIL_EXIT1 ("dladdr1 for grantpt failed");
+  TEST_VERIFY (handle == libc_handle);
+
+  /* Check that the handle of a new-loaded shared object is
+     returned from dladdr1.  */
+  void *moddummy1_handle = xdlopen ("moddummy1.so", RTLD_NOW);
+  ptr = xdlsym (moddummy1_handle, "dummy1");
+  if (dladdr1 (ptr, &info, &handle, RTLD_DL_HANDLE) == 0)
+    FAIL_EXIT1 ("dladdr1 for dummy1 failed");
+  TEST_VERIFY (handle == moddummy1_handle);
+
+  /* Check that the handle of a shared object loaded into a new
+     namespace is returned from dladdr1.  */
+  void *moddummy2_handle = xdlmopen (LM_ID_NEWLM, "moddummy2.so", RTLD_NOW);
+  ptr = xdlsym (moddummy2_handle, "dummy2");
+  if (dladdr1 (ptr, &info, &handle, RTLD_DL_HANDLE) == 0)
+    FAIL_EXIT1 ("dladdr1 for dummy2 failed");
+  TEST_VERIFY (handle == moddummy2_handle);
+
+  xdlclose (moddummy2_handle);
+  xdlclose (moddummy1_handle);
+  xdlclose (libc_handle);
+
+  return 0;
+}
+
+#include <support/test-driver.c>