• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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