dlfnc: Add RTLD_DL_HANDLE (dlopen handle) support to dladdr1

Message ID 87zhiclnrv.fsf@oldenburg2.str.redhat.com
State Accepted, archived
Headers

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
  
Adhemerval Zanella Netto Dec. 16, 2019, 7:35 p.m. UTC | #2
On 07/10/2019 09:53, Florian Weimer wrote:
> 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.

I am trying to understand why exactly you need another dladdr1 flag
that is essentially handled as RTLD_DL_HANDLE. Do you see requiring
handling it different for some specific / future usage?

> 
> 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.
> +

Ok.

>  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 \

Ok.

> @@ -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

Ok.

> 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);
>      }
>  }

Ok.

> 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
>    };
>  
>  

Ok.

> 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>
>  

Ok.

> 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>
>  

Ok.

> 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");

Ok.

> +
> +  /* The handle should be usable with dlsym.  */
> +  TEST_VERIFY (xdlsym (handle, "dlsym") == xdlsym (NULL, "dlsym"));
> +

Ok.

> +  /* 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);

Ok.

> +
> +  /* 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);

Ok.

> +
> +  /* 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);

Ok.

> +
> +  xdlclose (moddummy2_handle);
> +  xdlclose (moddummy1_handle);
> +  xdlclose (libc_handle);
> +
> +  return 0;
> +}
> +
> +#include <support/test-driver.c>
> 

Ok.
  

Patch

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>