1 /* dlinfo -- Get information from the dynamic linker.
2    Copyright (C) 2003-2022 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4 
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9 
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14 
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, see
17    <https://www.gnu.org/licenses/>.  */
18 
19 #include <dlfcn.h>
20 #include <link.h>
21 #include <ldsodefs.h>
22 #include <libintl.h>
23 #include <dl-tls.h>
24 #include <shlib-compat.h>
25 
26 struct dlinfo_args
27 {
28   void *handle;
29   int request;
30   void *arg;
31 
32   /* This is the value that is returned from dlinfo if no error is
33      signaled.  */
34   int result;
35 };
36 
37 static void
dlinfo_doit(void * argsblock)38 dlinfo_doit (void *argsblock)
39 {
40   struct dlinfo_args *const args = argsblock;
41   struct link_map *l = args->handle;
42 
43   switch (args->request)
44     {
45     case RTLD_DI_CONFIGADDR:
46     default:
47       args->result = -1;
48       _dl_signal_error (0, NULL, NULL, N_("unsupported dlinfo request"));
49       break;
50 
51     case RTLD_DI_LMID:
52       *(Lmid_t *) args->arg = l->l_ns;
53       break;
54 
55     case RTLD_DI_LINKMAP:
56       *(struct link_map **) args->arg = l;
57       break;
58 
59     case RTLD_DI_SERINFO:
60       _dl_rtld_di_serinfo (l, args->arg, false);
61       break;
62     case RTLD_DI_SERINFOSIZE:
63       _dl_rtld_di_serinfo (l, args->arg, true);
64       break;
65 
66     case RTLD_DI_ORIGIN:
67       strcpy (args->arg, l->l_origin);
68       break;
69 
70     case RTLD_DI_TLS_MODID:
71       *(size_t *) args->arg = 0;
72       *(size_t *) args->arg = l->l_tls_modid;
73       break;
74 
75     case RTLD_DI_TLS_DATA:
76       {
77 	void *data = NULL;
78 	if (l->l_tls_modid != 0)
79 	  data = GLRO(dl_tls_get_addr_soft) (l);
80 	*(void **) args->arg = data;
81 	break;
82       }
83 
84     case RTLD_DI_PHDR:
85       *(const ElfW(Phdr) **) args->arg = l->l_phdr;
86       args->result = l->l_phnum;
87       break;
88     }
89 }
90 
91 static int
dlinfo_implementation(void * handle,int request,void * arg)92 dlinfo_implementation (void *handle, int request, void *arg)
93 {
94   struct dlinfo_args args = { handle, request, arg };
95   _dlerror_run (&dlinfo_doit, &args);
96   return args.result;
97 }
98 
99 #ifdef SHARED
100 int
___dlinfo(void * handle,int request,void * arg)101 ___dlinfo (void *handle, int request, void *arg)
102 {
103   if (GLRO (dl_dlfcn_hook) != NULL)
104     return GLRO (dl_dlfcn_hook)->dlinfo (handle, request, arg);
105   else
106     return dlinfo_implementation (handle, request, arg);
107 }
108 versioned_symbol (libc, ___dlinfo, dlinfo, GLIBC_2_34);
109 
110 # if OTHER_SHLIB_COMPAT (libdl, GLIBC_2_3_3, GLIBC_2_34)
111 compat_symbol (libc, ___dlinfo, dlinfo, GLIBC_2_3_3);
112 # endif
113 #else /* !SHARED */
114 /* Also used with _dlfcn_hook.  */
115 int
__dlinfo(void * handle,int request,void * arg)116 __dlinfo (void *handle, int request, void *arg)
117 {
118   return dlinfo_implementation (handle, request, arg);
119 }
120 weak_alias (__dlinfo, dlinfo)
121 #endif
122