dlfnc: Add RTLD_DL_HANDLE (dlopen handle) support to dladdr1
Commit Message
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
I fixed the typo in the subject locally.
Florian
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.
@@ -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
@@ -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
@@ -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);
}
}
@@ -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
};
@@ -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>
@@ -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>
new file mode 100644
@@ -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>