1 #include <dlfcn.h>
2 #include <stdlib.h>
3 #include <stdarg.h>
4 #include "pthread_impl.h"
5 #include "dynlink.h"
6 #include "lock.h"
7
dlerror()8 char *dlerror()
9 {
10 pthread_t self = __pthread_self();
11 if (!self->dlerror_flag) return 0;
12 self->dlerror_flag = 0;
13 char *s = self->dlerror_buf;
14 if (s == (void *)-1)
15 return "Dynamic linker failed to allocate memory for error message";
16 else
17 return s;
18 }
19
20 static volatile int freebuf_queue_lock[1];
21 static void **freebuf_queue;
22
__dl_thread_cleanup(void)23 void __dl_thread_cleanup(void)
24 {
25 pthread_t self = __pthread_self();
26 if (self->dlerror_buf && self->dlerror_buf != (void *)-1) {
27 LOCK(freebuf_queue_lock);
28 void **p = (void **)self->dlerror_buf;
29 *p = freebuf_queue;
30 freebuf_queue = p;
31 UNLOCK(freebuf_queue_lock);
32 }
33 }
34
__dl_vseterr(const char * fmt,va_list ap)35 hidden void __dl_vseterr(const char *fmt, va_list ap)
36 {
37 LOCK(freebuf_queue_lock);
38 while (freebuf_queue) {
39 void **p = freebuf_queue;
40 freebuf_queue = *p;
41 free(p);
42 }
43 UNLOCK(freebuf_queue_lock);
44
45 va_list ap2;
46 va_copy(ap2, ap);
47 pthread_t self = __pthread_self();
48 if (self->dlerror_buf != (void *)-1)
49 free(self->dlerror_buf);
50 size_t len = vsnprintf(0, 0, fmt, ap2);
51 if (len < sizeof(void *)) len = sizeof(void *);
52 va_end(ap2);
53 char *buf = malloc(len+1);
54 if (buf) {
55 vsnprintf(buf, len+1, fmt, ap);
56 } else {
57 buf = (void *)-1;
58 }
59 self->dlerror_buf = buf;
60 self->dlerror_flag = 1;
61 }
62
__dl_seterr(const char * fmt,...)63 hidden void __dl_seterr(const char *fmt, ...)
64 {
65 va_list ap;
66 va_start(ap, fmt);
67 __dl_vseterr(fmt, ap);
68 va_end(ap);
69 }
70
stub_invalid_handle(void * h)71 static int stub_invalid_handle(void *h)
72 {
73 __dl_seterr("Invalid library handle %p", (void *)h);
74 return 1;
75 }
76
77 weak_alias(stub_invalid_handle, __dl_invalid_handle);
78