factor dlerror and error-setting code out of dynlink.c
[musl] / src / ldso / dlerror.c
1 #include <dlfcn.h>
2 #include <stdlib.h>
3 #include <stdarg.h>
4 #include "pthread_impl.h"
5
6 char *dlerror()
7 {
8         pthread_t self = __pthread_self();
9         if (!self->dlerror_flag) return 0;
10         self->dlerror_flag = 0;
11         char *s = self->dlerror_buf;
12         if (s == (void *)-1)
13                 return "Dynamic linker failed to allocate memory for error message";
14         else
15                 return s;
16 }
17
18 void __dl_thread_cleanup(void)
19 {
20         pthread_t self = __pthread_self();
21         if (self->dlerror_buf != (void *)-1)
22                 free(self->dlerror_buf);
23 }
24
25 __attribute__((__visibility__("hidden")))
26 void __dl_vseterr(const char *fmt, va_list ap)
27 {
28         va_list ap2;
29         va_copy(ap2, ap);
30         pthread_t self = __pthread_self();
31         if (self->dlerror_buf != (void *)-1)
32                 free(self->dlerror_buf);
33         size_t len = vsnprintf(0, 0, fmt, ap2);
34         va_end(ap2);
35         char *buf = malloc(len+1);
36         if (buf) {
37                 vsnprintf(buf, len+1, fmt, ap);
38         } else {
39                 buf = (void *)-1;       
40         }
41         self->dlerror_buf = buf;
42         self->dlerror_flag = 1;
43 }
44
45 __attribute__((__visibility__("hidden")))
46 void __dl_seterr(const char *fmt, ...)
47 {
48         va_list ap;
49         va_start(ap, fmt);
50         __dl_vseterr(fmt, ap);
51         va_end(ap);
52 }