1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20: #include <dlfcn.h>
21: #include <libintl.h>
22: #include <stdbool.h>
23: #include <stdio.h>
24: #include <stdlib.h>
25: #include <string.h>
26: #include <bits/libc-lock.h>
27: #include <ldsodefs.h>
28:
29: #if !defined SHARED && defined IS_IN_libdl
30:
31: char *
32: dlerror (void)
33: {
34: return __dlerror ();
35: }
36:
37: #else
38:
39:
40: struct dl_action_result
41: {
42: int errcode;
43: int returned;
44: bool malloced;
45: const char *objname;
46: const char *errstring;
47: };
48: static struct dl_action_result last_result;
49: static struct dl_action_result *static_buf;
50:
51:
52: static __libc_key_t key;
53: __libc_once_define (static, once);
54:
55:
56: static void init (void);
57: static void free_key_mem (void *mem);
58:
59:
60: char *
61: __dlerror (void)
62: {
63: char *buf = NULL;
64: struct dl_action_result *result;
65:
66: # ifdef SHARED
67: if (__builtin_expect (_dlfcn_hook != NULL, 0))
68: return _dlfcn_hook->dlerror ();
69: # endif
70:
71:
72: __libc_once (once, init);
73:
74:
75: result = (struct dl_action_result *) __libc_getspecific (key);
76: if (result == NULL)
77: result = &last_result;
78:
79:
80: if (result->returned != 0)
81: {
82:
83: if (result->errstring != NULL)
84: {
85: if (strcmp (result->errstring, "out of memory") != 0)
86: free ((char *) result->errstring);
87: result->errstring = NULL;
88: }
89: }
90: else if (result->errstring != NULL)
91: {
92: buf = (char *) result->errstring;
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)
106: {
107:
108: if (strcmp (result->errstring, "out of memory") != 0)
109: free ((char *) result->errstring);
110: result->errstring = buf;
111: }
112:
113:
114: result->returned = 1;
115: }
116:
117: return buf;
118: }
119: # ifdef SHARED
120: strong_alias (__dlerror, dlerror)
121: # endif
122:
123: int
124: internal_function
125: _dlerror_run (void (*operate) (void *), void *args)
126: {
127: struct dl_action_result *result;
128:
129:
130: __libc_once (once, init);
131:
132:
133: if (static_buf != NULL)
134: result = static_buf;
135: else
136: {
137:
138:
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:
145:
146:
147:
148: result = &last_result;
149: else
150:
151: __libc_setspecific (key, result);
152: }
153: }
154:
155: if (result->errstring != NULL)
156: {
157:
158:
159: if (result->malloced)
160: free ((char *) result->errstring);
161: result->errstring = NULL;
162: }
163:
164: result->errcode = GLRO(dl_catch_error) (&result->objname, &result->errstring,
165: &result->malloced, operate, args);
166:
167:
168: result->returned = result->errstring == NULL;
169:
170: return result->errstring != NULL;
171: }
172:
173:
174:
175: static void
176: init (void)
177: {
178: if (__libc_key_create (&key, free_key_mem))
179:
180:
181:
182: static_buf = &last_result;
183: }
184:
185:
186: static void
187: check_free (struct dl_action_result *rec)
188: {
189: if (rec->errstring != NULL
190: && strcmp (rec->errstring, "out of memory") != 0)
191: {
192:
193:
194:
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:
204: static void
205: __attribute__ ((destructor))
206: fini (void)
207: {
208: check_free (&last_result);
209: }
210:
211:
212:
213: static void
214: free_key_mem (void *mem)
215: {
216: check_free ((struct dl_action_result *) mem);
217:
218: free (mem);
219: __libc_setspecific (key, NULL);
220: }
221:
222: # ifdef SHARED
223:
224: struct dlfcn_hook *_dlfcn_hook __attribute__((nocommon));
225: libdl_hidden_data_def (_dlfcn_hook)
226:
227: # else
228:
229: static 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:
242: void
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