]> git.ipfire.org Git - thirdparty/glibc.git/blame - dlfcn/dlerror.c
* dlfcn/dlopen.c (dlopen_doit): Allow __RTLD_SPROF flag.
[thirdparty/glibc.git] / dlfcn / dlerror.c
CommitLineData
c84142e8 1/* Return error detail for failing <dlfcn.h> functions.
bfeabc79 2 Copyright (C) 1995-2000,2002,2003,2004,2005 Free Software Foundation, Inc.
afd4eb37 3 This file is part of the GNU C Library.
d66e34cd 4
afd4eb37 5 The GNU C Library is free software; you can redistribute it and/or
41bdb6e2
AJ
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.
d66e34cd 9
afd4eb37
UD
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
41bdb6e2 13 Lesser General Public License for more details.
d66e34cd 14
41bdb6e2
AJ
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. */
d66e34cd 19
d66e34cd 20#include <dlfcn.h>
04470dc0 21#include <libintl.h>
74780cf6 22#include <stdbool.h>
d66e34cd 23#include <stdio.h>
d66e34cd 24#include <stdlib.h>
a853022c 25#include <string.h>
8d9618b7 26#include <bits/libc-lock.h>
154d10bd 27#include <ldsodefs.h>
8d9618b7 28
5f21997b
UD
29#if !defined SHARED && defined IS_IN_libdl
30
31char *
32dlerror (void)
33{
34 return __dlerror ();
35}
36
37#else
38
8d9618b7
UD
39/* Type for storing results of dynamic loading actions. */
40struct dl_action_result
41 {
42 int errcode;
4f2793d4 43 int returned;
74780cf6 44 bool malloced;
04470dc0
UD
45 const char *objname;
46 const char *errstring;
8d9618b7
UD
47 };
48static struct dl_action_result last_result;
49static struct dl_action_result *static_buf;
50
8d9618b7
UD
51/* This is the key for the thread specific memory. */
52static __libc_key_t key;
d347a4ab 53__libc_once_define (static, once);
8d9618b7
UD
54
55/* Destructor for the thread-specific data. */
56static void init (void);
57static void free_key_mem (void *mem);
d66e34cd 58
d66e34cd
RM
59
60char *
5f21997b 61__dlerror (void)
d66e34cd 62{
fb0dd050 63 char *buf = NULL;
8d9618b7 64 struct dl_action_result *result;
d66e34cd 65
5f21997b
UD
66# ifdef SHARED
67 if (__builtin_expect (_dlfcn_hook != NULL, 0))
68 return _dlfcn_hook->dlerror ();
69# endif
70
d347a4ab
UD
71 /* If we have not yet initialized the buffer do it now. */
72 __libc_once (once, init);
73
8d9618b7 74 /* Get error string. */
af3878df
UD
75 result = (struct dl_action_result *) __libc_getspecific (key);
76 if (result == NULL)
8d9618b7
UD
77 result = &last_result;
78
4f2793d4
UD
79 /* Test whether we already returned the string. */
80 if (result->returned != 0)
81 {
82 /* We can now free the string. */
83 if (result->errstring != NULL)
84 {
ca3c0135
UD
85 if (strcmp (result->errstring, "out of memory") != 0)
86 free ((char *) result->errstring);
4f2793d4
UD
87 result->errstring = NULL;
88 }
4f2793d4 89 }
fb0dd050 90 else if (result->errstring != NULL)
8d9618b7 91 {
04470dc0 92 buf = (char *) result->errstring;
4a8ff87c
RM
93 int n;
94 if (result->errcode == 0)
95 n = __asprintf (&buf, "%s%s%s",
96 result->objname,
97 result->objname[0] == '\0' ? "" : ": ",
98 _(result->errstring));
99 else
100 n = __asprintf (&buf, "%s%s%s: %s",
101 result->objname,
102 result->objname[0] == '\0' ? "" : ": ",
103 _(result->errstring),
104 strerror (result->errcode));
105 if (n != -1)
4f2793d4
UD
106 {
107 /* We don't need the error string anymore. */
ca3c0135
UD
108 if (strcmp (result->errstring, "out of memory") != 0)
109 free ((char *) result->errstring);
4f2793d4
UD
110 result->errstring = buf;
111 }
8d9618b7 112
4f2793d4
UD
113 /* Mark the error as returned. */
114 result->returned = 1;
8d9618b7 115 }
421f82e5 116
8d9618b7 117 return buf;
d66e34cd 118}
5f21997b
UD
119# ifdef SHARED
120strong_alias (__dlerror, dlerror)
121# endif
d66e34cd
RM
122
123int
d0fc4041 124internal_function
993b3242 125_dlerror_run (void (*operate) (void *), void *args)
d66e34cd 126{
8d9618b7
UD
127 struct dl_action_result *result;
128
129 /* If we have not yet initialized the buffer do it now. */
130 __libc_once (once, init);
131
132 /* Get error string and number. */
133 if (static_buf != NULL)
134 result = static_buf;
135 else
136 {
137 /* We don't use the static buffer and so we have a key. Use it
138 to get the thread-specific buffer. */
139 result = __libc_getspecific (key);
140 if (result == NULL)
141 {
142 result = (struct dl_action_result *) calloc (1, sizeof (*result));
143 if (result == NULL)
144 /* We are out of memory. Since this is no really critical
145 situation we carry on by using the global variable.
146 This might lead to conflicts between the threads but
147 they soon all will have memory problems. */
148 result = &last_result;
149 else
150 /* Set the tsd. */
151 __libc_setspecific (key, result);
152 }
153 }
154
155 if (result->errstring != NULL)
d743ba1e
UD
156 {
157 /* Free the error string from the last failed command. This can
158 happen if `dlerror' was not run after an error was found. */
74780cf6 159 if (result->malloced)
ca3c0135 160 free ((char *) result->errstring);
d743ba1e
UD
161 result->errstring = NULL;
162 }
8d9618b7 163
154d10bd 164 result->errcode = GLRO(dl_catch_error) (&result->objname, &result->errstring,
74780cf6 165 &result->malloced, operate, args);
8d9618b7 166
4f2793d4
UD
167 /* If no error we mark that no error string is available. */
168 result->returned = result->errstring == NULL;
169
8d9618b7
UD
170 return result->errstring != NULL;
171}
172
dcf0671d 173
8d9618b7
UD
174/* Initialize buffers for results. */
175static void
176init (void)
177{
178 if (__libc_key_create (&key, free_key_mem))
179 /* Creating the key failed. This means something really went
180 wrong. In any case use a static buffer which is better than
181 nothing. */
182 static_buf = &last_result;
183}
184
bfeabc79
UD
185
186static void
187check_free (struct dl_action_result *rec)
188{
189 if (rec->errstring != NULL
190 && strcmp (rec->errstring, "out of memory") != 0)
191 {
192 /* We can free the string only if the allocation happened in the
193 C library used by the dynamic linker. This means, it is
194 always the C library in the base namespave. */
195 struct link_map *map = NULL;
196 Dl_info info;
197 if (_dl_addr (check_free, &info, &map, NULL) != 0
198 && map != NULL && map->l_ns == 0)
199 free ((char *) rec->errstring);
200 }
201}
202
203
0bf5c050
RM
204static void
205__attribute__ ((destructor))
206fini (void)
207{
bfeabc79 208 check_free (&last_result);
0bf5c050
RM
209}
210
8d9618b7
UD
211
212/* Free the thread specific data, this is done if a thread terminates. */
213static void
214free_key_mem (void *mem)
215{
bfeabc79 216 check_free ((struct dl_action_result *) mem);
ca3c0135 217
8d9618b7
UD
218 free (mem);
219 __libc_setspecific (key, NULL);
d66e34cd 220}
5f21997b
UD
221
222# ifdef SHARED
223
224struct dlfcn_hook *_dlfcn_hook __attribute__((nocommon));
225libdl_hidden_data_def (_dlfcn_hook)
226
227# else
228
229static struct dlfcn_hook _dlfcn_hooks =
230 {
231 .dlopen = __dlopen,
232 .dlclose = __dlclose,
233 .dlsym = __dlsym,
234 .dlvsym = __dlvsym,
235 .dlerror = __dlerror,
236 .dladdr = __dladdr,
237 .dladdr1 = __dladdr1,
238 .dlinfo = __dlinfo,
239 .dlmopen = __dlmopen
240 };
241
242void
243__libc_register_dlfcn_hook (struct link_map *map)
244{
245 struct dlfcn_hook **hook;
246
247 hook = (struct dlfcn_hook **) __libc_dlsym_private (map, "_dlfcn_hook");
248 if (hook != NULL)
249 *hook = &_dlfcn_hooks;
250}
251# endif
252#endif