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