Message ID | 87zhiclnrv.fsf@oldenburg2.str.redhat.com |
---|---|
State | New |
Headers | show |
Series | dlfnc: Add RTLD_DL_HANDLE (dlopen handle) support to dladdr1 | expand |
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.
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>