1#include "libc.h"
2#include "threads_impl.h"
3#include <dlfcn.h>
4#include <stdarg.h>
5#include <stdlib.h>
6
7char* dlerror(void) {
8    thrd_t self = __thrd_current();
9    if (!self->dlerror_flag)
10        return 0;
11    self->dlerror_flag = 0;
12    char* s = self->dlerror_buf;
13    if (s == (void*)-1)
14        return (char*)"Dynamic linker failed to allocate memory for error message";
15    else
16        return s;
17}
18
19void __dl_thread_cleanup(void) {
20    thrd_t self = __thrd_current();
21    if (self->dlerror_buf != (void*)-1)
22        free(self->dlerror_buf);
23}
24
25__attribute__((__visibility__("hidden"))) void __dl_vseterr(const char* fmt, va_list ap) {
26    va_list ap2;
27    va_copy(ap2, ap);
28    thrd_t self = __thrd_current();
29    if (self->dlerror_buf != (void*)-1)
30        free(self->dlerror_buf);
31    size_t len = vsnprintf(0, 0, fmt, ap2);
32    va_end(ap2);
33    char* buf = malloc(len + 1);
34    if (buf) {
35        vsnprintf(buf, len + 1, fmt, ap);
36    } else {
37        buf = (void*)-1;
38    }
39    self->dlerror_buf = buf;
40    self->dlerror_flag = 1;
41}
42
43__attribute__((__visibility__("hidden"))) void __dl_seterr(const char* fmt, ...) {
44    va_list ap;
45    va_start(ap, fmt);
46    __dl_vseterr(fmt, ap);
47    va_end(ap);
48}
49
50__attribute__((__visibility__("hidden"))) int __dl_invalid_handle(void*);
51
52static int stub_invalid_handle(void* h) {
53    __dl_seterr("Invalid library handle %p", (void*)h);
54    return 1;
55}
56
57weak_alias(stub_invalid_handle, __dl_invalid_handle);
58