Update.
[kopensolaris-gnu/glibc.git] / dlfcn / dlinfo.c
1 /* dlinfo -- Get information from the dynamic linker.
2    Copyright (C) 2003, 2004, 2006 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, write to the Free
17    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18    02111-1307 USA.  */
19
20 #include <dlfcn.h>
21 #include <link.h>
22 #include <ldsodefs.h>
23 #include <libintl.h>
24
25 #if !defined SHARED && defined IS_IN_libdl
26
27 int
28 dlinfo (void *handle, int request, void *arg)
29 {
30   return __dlinfo (handle, request, arg, RETURN_ADDRESS (0));
31 }
32
33 #else
34
35 # ifdef USE_TLS
36 #  include <dl-tls.h>
37 # endif
38
39 struct dlinfo_args
40 {
41   ElfW(Addr) caller;
42   void *handle;
43   int request;
44   void *arg;
45 };
46
47 static void
48 dlinfo_doit (void *argsblock)
49 {
50   struct dlinfo_args *const args = argsblock;
51   struct link_map *l = args->handle;
52
53 # if 0
54   if (args->handle == RTLD_SELF)
55     {
56       Lmid_t nsid;
57
58       /* Find the highest-addressed object that CALLER is not below.  */
59       for (nsid = 0; nsid < DL_NNS; ++nsid)
60         for (l = GL(dl_ns)[nsid]._ns_loaded; l != NULL; l = l->l_next)
61           if (caller >= l->l_map_start && caller < l->l_map_end)
62             /* There must be exactly one DSO for the range of the virtual
63                memory.  Otherwise something is really broken.  */
64             break;
65
66       if (l == NULL)
67         GLRO(dl_signal_error) (0, NULL, NULL, N_("\
68 RTLD_SELF used in code not dynamically loaded"));
69     }
70 # endif
71
72   switch (args->request)
73     {
74     case RTLD_DI_CONFIGADDR:
75     default:
76       GLRO(dl_signal_error) (0, NULL, NULL, N_("unsupported dlinfo request"));
77       break;
78
79     case RTLD_DI_LMID:
80       *(Lmid_t *) args->arg = l->l_ns;
81       break;
82
83     case RTLD_DI_LINKMAP:
84       *(struct link_map **) args->arg = l;
85       break;
86
87     case RTLD_DI_SERINFO:
88       _dl_rtld_di_serinfo (l, args->arg, false);
89       break;
90     case RTLD_DI_SERINFOSIZE:
91       _dl_rtld_di_serinfo (l, args->arg, true);
92       break;
93
94     case RTLD_DI_ORIGIN:
95       strcpy (args->arg, l->l_origin);
96       break;
97
98     case RTLD_DI_TLS_MODID:
99       *(size_t *) args->arg = 0;
100 #ifdef USE_TLS
101       *(size_t *) args->arg = l->l_tls_modid;
102 #endif
103       break;
104
105     case RTLD_DI_TLS_DATA:
106       {
107         void *data = NULL;
108 #ifdef USE_TLS
109         if (l->l_tls_modid != 0)
110           data = _dl_tls_get_addr_soft (l);
111 #endif
112         *(void **) args->arg = data;
113         break;
114       }
115     }
116 }
117
118 int
119 __dlinfo (void *handle, int request, void *arg DL_CALLER_DECL)
120 {
121 # ifdef SHARED
122   if (__builtin_expect (_dlfcn_hook != NULL, 0))
123     return _dlfcn_hook->dlinfo (handle, request, arg,
124                                 DL_CALLER);
125 # endif
126
127   struct dlinfo_args args = { (ElfW(Addr)) DL_CALLER,
128                               handle, request, arg };
129   return _dlerror_run (&dlinfo_doit, &args) ? -1 : 0;
130 }
131 # ifdef SHARED
132 strong_alias (__dlinfo, dlinfo)
133 # endif
134 #endif