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