1 | //===-- sanitizer_wrappers.cpp ----------------------------------*- C++ -*-===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | // |
9 | // Redirect some functions to sanitizer interceptors. |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #include <dlfcn.h> |
14 | #include <errno.h> |
15 | #include <fcntl.h> |
16 | #include <inttypes.h> |
17 | #include <stdarg.h> |
18 | #include <stdio.h> |
19 | #include <unistd.h> |
20 | |
21 | #include <tuple> |
22 | |
23 | namespace __sanitizer { |
24 | unsigned long internal_open(const char *filename, int flags); |
25 | unsigned long internal_open(const char *filename, int flags, unsigned mode); |
26 | unsigned long internal_close(int fd); |
27 | unsigned long internal_stat(const char *path, void *buf); |
28 | unsigned long internal_lstat(const char *path, void *buf); |
29 | unsigned long internal_fstat(int fd, void *buf); |
30 | size_t internal_strlen(const char *s); |
31 | unsigned long internal_mmap(void *addr, uintptr_t length, int prot, int flags, |
32 | int fd, unsigned long long offset); |
33 | void *internal_memcpy(void *dest, const void *src, unsigned long n); |
34 | // Used to propagate errno. |
35 | bool internal_iserror(uintptr_t retval, int *rverrno = 0); |
36 | } // namespace __sanitizer |
37 | |
38 | namespace { |
39 | |
40 | template <typename T> |
41 | struct GetTypes; |
42 | |
43 | template <typename R, typename... Args> |
44 | struct GetTypes<R(Args...)> { |
45 | using Result = R; |
46 | template <size_t i> |
47 | struct Arg { |
48 | using Type = typename std::tuple_element<i, std::tuple<Args...>>::type; |
49 | }; |
50 | }; |
51 | |
52 | #define LLVM_SYMBOLIZER_GET_FUNC(Function) \ |
53 | ((__interceptor_##Function) \ |
54 | ? (__interceptor_##Function) \ |
55 | : reinterpret_cast<decltype(&Function)>(dlsym(RTLD_NEXT, #Function))) |
56 | |
57 | #define LLVM_SYMBOLIZER_INTERCEPTOR1(Function, ...) \ |
58 | GetTypes<__VA_ARGS__>::Result __interceptor_##Function( \ |
59 | GetTypes<__VA_ARGS__>::Arg<0>::Type) __attribute__((weak)); \ |
60 | GetTypes<__VA_ARGS__>::Result Function( \ |
61 | GetTypes<__VA_ARGS__>::Arg<0>::Type arg0) { \ |
62 | return LLVM_SYMBOLIZER_GET_FUNC(Function)(arg0); \ |
63 | } |
64 | |
65 | #define LLVM_SYMBOLIZER_INTERCEPTOR2(Function, ...) \ |
66 | GetTypes<__VA_ARGS__>::Result __interceptor_##Function( \ |
67 | GetTypes<__VA_ARGS__>::Arg<0>::Type, \ |
68 | GetTypes<__VA_ARGS__>::Arg<1>::Type) __attribute__((weak)); \ |
69 | GetTypes<__VA_ARGS__>::Result Function( \ |
70 | GetTypes<__VA_ARGS__>::Arg<0>::Type arg0, \ |
71 | GetTypes<__VA_ARGS__>::Arg<1>::Type arg1) { \ |
72 | return LLVM_SYMBOLIZER_GET_FUNC(Function)(arg0, arg1); \ |
73 | } |
74 | |
75 | #define LLVM_SYMBOLIZER_INTERCEPTOR3(Function, ...) \ |
76 | GetTypes<__VA_ARGS__>::Result __interceptor_##Function( \ |
77 | GetTypes<__VA_ARGS__>::Arg<0>::Type, \ |
78 | GetTypes<__VA_ARGS__>::Arg<1>::Type, \ |
79 | GetTypes<__VA_ARGS__>::Arg<2>::Type) __attribute__((weak)); \ |
80 | GetTypes<__VA_ARGS__>::Result Function( \ |
81 | GetTypes<__VA_ARGS__>::Arg<0>::Type arg0, \ |
82 | GetTypes<__VA_ARGS__>::Arg<1>::Type arg1, \ |
83 | GetTypes<__VA_ARGS__>::Arg<2>::Type arg2) { \ |
84 | return LLVM_SYMBOLIZER_GET_FUNC(Function)(arg0, arg1, arg2); \ |
85 | } |
86 | |
87 | #define LLVM_SYMBOLIZER_INTERCEPTOR4(Function, ...) \ |
88 | GetTypes<__VA_ARGS__>::Result __interceptor_##Function( \ |
89 | GetTypes<__VA_ARGS__>::Arg<0>::Type, \ |
90 | GetTypes<__VA_ARGS__>::Arg<1>::Type, \ |
91 | GetTypes<__VA_ARGS__>::Arg<2>::Type, \ |
92 | GetTypes<__VA_ARGS__>::Arg<3>::Type) __attribute__((weak)); \ |
93 | GetTypes<__VA_ARGS__>::Result Function( \ |
94 | GetTypes<__VA_ARGS__>::Arg<0>::Type arg0, \ |
95 | GetTypes<__VA_ARGS__>::Arg<1>::Type arg1, \ |
96 | GetTypes<__VA_ARGS__>::Arg<2>::Type arg2, \ |
97 | GetTypes<__VA_ARGS__>::Arg<3>::Type arg3) { \ |
98 | return LLVM_SYMBOLIZER_GET_FUNC(Function)(arg0, arg1, arg2, arg3); \ |
99 | } |
100 | |
101 | } // namespace |
102 | |
103 | // C-style interface around internal sanitizer libc functions. |
104 | extern "C" { |
105 | |
106 | #define RETURN_OR_SET_ERRNO(T, res) \ |
107 | int rverrno; \ |
108 | if (__sanitizer::internal_iserror(res, &rverrno)) { \ |
109 | errno = rverrno; \ |
110 | return (T)-1; \ |
111 | } \ |
112 | return (T)res; |
113 | |
114 | int open(const char *filename, int flags, ...) { |
115 | unsigned long res; |
116 | if (flags | O_CREAT) { |
117 | va_list va; |
118 | va_start(va, flags); |
119 | unsigned mode = va_arg(va, unsigned); |
120 | va_end(va); |
121 | res = __sanitizer::internal_open(filename, flags, mode); |
122 | } else { |
123 | res = __sanitizer::internal_open(filename, flags); |
124 | } |
125 | RETURN_OR_SET_ERRNO(int, res); |
126 | } |
127 | |
128 | int close(int fd) { |
129 | unsigned long res = __sanitizer::internal_close(fd); |
130 | RETURN_OR_SET_ERRNO(int, res); |
131 | } |
132 | |
133 | #define STAT(func, arg, buf) \ |
134 | unsigned long res = __sanitizer::internal_##func(arg, buf); \ |
135 | RETURN_OR_SET_ERRNO(int, res); |
136 | |
137 | int stat(const char *path, struct stat *buf) { STAT(stat, path, buf); } |
138 | |
139 | int lstat(const char *path, struct stat *buf) { STAT(lstat, path, buf); } |
140 | |
141 | int fstat(int fd, struct stat *buf) { STAT(fstat, fd, buf); } |
142 | |
143 | // Redirect versioned stat functions to the __sanitizer::internal() as well. |
144 | int __xstat(int version, const char *path, struct stat *buf) { |
145 | STAT(stat, path, buf); |
146 | } |
147 | |
148 | int __lxstat(int version, const char *path, struct stat *buf) { |
149 | STAT(lstat, path, buf); |
150 | } |
151 | |
152 | int __fxstat(int version, int fd, struct stat *buf) { STAT(fstat, fd, buf); } |
153 | |
154 | size_t strlen(const char *s) { return __sanitizer::internal_strlen(s); } |
155 | |
156 | void *mmap(void *addr, size_t length, int prot, int flags, int fd, |
157 | off_t offset) { |
158 | unsigned long res = |
159 | __sanitizer::internal_mmap(addr, length, prot, flags, fd, offset); |
160 | RETURN_OR_SET_ERRNO(void *, res); |
161 | } |
162 | |
163 | LLVM_SYMBOLIZER_INTERCEPTOR3(read, ssize_t(int, void *, size_t)) |
164 | LLVM_SYMBOLIZER_INTERCEPTOR4(pread, ssize_t(int, void *, size_t, off_t)) |
165 | LLVM_SYMBOLIZER_INTERCEPTOR4(pread64, ssize_t(int, void *, size_t, off64_t)) |
166 | LLVM_SYMBOLIZER_INTERCEPTOR2(realpath, char *(const char *, char *)) |
167 | |
168 | LLVM_SYMBOLIZER_INTERCEPTOR1(pthread_cond_broadcast, int(pthread_cond_t *)) |
169 | LLVM_SYMBOLIZER_INTERCEPTOR2(pthread_cond_wait, |
170 | int(pthread_cond_t *, pthread_mutex_t *)) |
171 | LLVM_SYMBOLIZER_INTERCEPTOR1(pthread_mutex_lock, int(pthread_mutex_t *)) |
172 | LLVM_SYMBOLIZER_INTERCEPTOR1(pthread_mutex_unlock, int(pthread_mutex_t *)) |
173 | LLVM_SYMBOLIZER_INTERCEPTOR1(pthread_mutex_destroy, int(pthread_mutex_t *)) |
174 | LLVM_SYMBOLIZER_INTERCEPTOR2(pthread_mutex_init, |
175 | int(pthread_mutex_t *, |
176 | const pthread_mutexattr_t *)) |
177 | LLVM_SYMBOLIZER_INTERCEPTOR1(pthread_mutexattr_destroy, |
178 | int(pthread_mutexattr_t *)) |
179 | LLVM_SYMBOLIZER_INTERCEPTOR1(pthread_mutexattr_init, int(pthread_mutexattr_t *)) |
180 | LLVM_SYMBOLIZER_INTERCEPTOR2(pthread_mutexattr_settype, |
181 | int(pthread_mutexattr_t *, int)) |
182 | LLVM_SYMBOLIZER_INTERCEPTOR1(pthread_getspecific, void *(pthread_key_t)) |
183 | LLVM_SYMBOLIZER_INTERCEPTOR2(pthread_key_create, |
184 | int(pthread_key_t *, void (*)(void *))) |
185 | LLVM_SYMBOLIZER_INTERCEPTOR2(pthread_once, |
186 | int(pthread_once_t *, void (*)(void))) |
187 | LLVM_SYMBOLIZER_INTERCEPTOR2(pthread_setspecific, |
188 | int(pthread_key_t, const void *)) |
189 | LLVM_SYMBOLIZER_INTERCEPTOR3(pthread_sigmask, |
190 | int(int, const sigset_t *, sigset_t *)) |
191 | |
192 | } // extern "C" |
193 | |