Serenity Operating System
1/*
2 * Copyright (c) 2021, Gunnar Beutner <gunnar@beutner.name>
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 */
6
7#include <AK/DeprecatedString.h>
8#include <AK/Types.h>
9#include <bits/dlfcn_integration.h>
10#include <dlfcn.h>
11#include <string.h>
12
13// These are filled in by the dynamic loader.
14DlCloseFunction __dlclose;
15DlOpenFunction __dlopen;
16DlSymFunction __dlsym;
17DlAddrFunction __dladdr;
18
19// FIXME: use thread_local and a String once TLS works
20#ifdef NO_TLS
21char* s_dlerror_text = NULL;
22bool s_dlerror_retrieved = false;
23#else
24__thread char* s_dlerror_text = NULL;
25__thread bool s_dlerror_retrieved = false;
26#endif
27
28static void store_error(DeprecatedString const& error)
29{
30 free(s_dlerror_text);
31 s_dlerror_text = strdup(error.characters());
32 s_dlerror_retrieved = false;
33}
34
35int dlclose(void* handle)
36{
37 auto result = __dlclose(handle);
38 if (result.is_error()) {
39 store_error(result.error().text);
40 return -1;
41 }
42 return 0;
43}
44
45char* dlerror()
46{
47 if (s_dlerror_retrieved) {
48 free(s_dlerror_text);
49 s_dlerror_text = nullptr;
50 }
51 s_dlerror_retrieved = true;
52 return const_cast<char*>(s_dlerror_text);
53}
54
55void* dlopen(char const* filename, int flags)
56{
57 auto result = __dlopen(filename, flags);
58 if (result.is_error()) {
59 store_error(result.error().text);
60 return nullptr;
61 }
62 return result.value();
63}
64
65void* dlsym(void* handle, char const* symbol_name)
66{
67 auto result = __dlsym(handle, symbol_name);
68 if (result.is_error()) {
69 store_error(result.error().text);
70 return nullptr;
71 }
72 return result.value();
73}
74
75int dladdr(void* addr, Dl_info* info)
76{
77 auto result = __dladdr(addr, info);
78 if (result.is_error()) {
79 // FIXME: According to the man page glibc does _not_ make the error
80 // available via dlerror(), however we do. Does this break anything?
81 store_error(result.error().text);
82 return 0;
83 }
84 return 1;
85}