1353944Sdim//===-- dd_interceptors.cpp -----------------------------------------------===//
2353944Sdim//
3353944Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353944Sdim// See https://llvm.org/LICENSE.txt for license information.
5353944Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6353944Sdim//
7353944Sdim//===----------------------------------------------------------------------===//
8353944Sdim
9353944Sdim#include "dd_rtl.h"
10353944Sdim#include "interception/interception.h"
11353944Sdim#include "sanitizer_common/sanitizer_procmaps.h"
12353944Sdim#include <pthread.h>
13353944Sdim#include <stdlib.h>
14353944Sdim
15353944Sdimusing namespace __dsan;
16353944Sdim
17353944Sdim__attribute__((tls_model("initial-exec")))
18353944Sdimstatic __thread Thread *thr;
19353944Sdim__attribute__((tls_model("initial-exec")))
20353944Sdimstatic __thread volatile int initing;
21353944Sdimstatic bool inited;
22353944Sdimstatic uptr g_data_start;
23353944Sdimstatic uptr g_data_end;
24353944Sdim
25353944Sdimstatic bool InitThread() {
26353944Sdim  if (initing)
27353944Sdim    return false;
28353944Sdim  if (thr != 0)
29353944Sdim    return true;
30353944Sdim  initing = true;
31353944Sdim  if (!inited) {
32353944Sdim    inited = true;
33353944Sdim    Initialize();
34353944Sdim  }
35353944Sdim  thr = (Thread*)InternalAlloc(sizeof(*thr));
36353944Sdim  internal_memset(thr, 0, sizeof(*thr));
37353944Sdim  ThreadInit(thr);
38353944Sdim  initing = false;
39353944Sdim  return true;
40353944Sdim}
41353944Sdim
42353944SdimINTERCEPTOR(int, pthread_mutex_destroy, pthread_mutex_t *m) {
43353944Sdim  InitThread();
44353944Sdim  MutexDestroy(thr, (uptr)m);
45353944Sdim  return REAL(pthread_mutex_destroy)(m);
46353944Sdim}
47353944Sdim
48353944SdimINTERCEPTOR(int, pthread_mutex_lock, pthread_mutex_t *m) {
49353944Sdim  InitThread();
50353944Sdim  MutexBeforeLock(thr, (uptr)m, true);
51353944Sdim  int res = REAL(pthread_mutex_lock)(m);
52353944Sdim  MutexAfterLock(thr, (uptr)m, true, false);
53353944Sdim  return res;
54353944Sdim}
55353944Sdim
56353944SdimINTERCEPTOR(int, pthread_mutex_trylock, pthread_mutex_t *m) {
57353944Sdim  InitThread();
58353944Sdim  int res = REAL(pthread_mutex_trylock)(m);
59353944Sdim  if (res == 0)
60353944Sdim    MutexAfterLock(thr, (uptr)m, true, true);
61353944Sdim  return res;
62353944Sdim}
63353944Sdim
64353944SdimINTERCEPTOR(int, pthread_mutex_unlock, pthread_mutex_t *m) {
65353944Sdim  InitThread();
66353944Sdim  MutexBeforeUnlock(thr, (uptr)m, true);
67353944Sdim  return REAL(pthread_mutex_unlock)(m);
68353944Sdim}
69353944Sdim
70353944SdimINTERCEPTOR(int, pthread_spin_destroy, pthread_spinlock_t *m) {
71353944Sdim  InitThread();
72353944Sdim  int res = REAL(pthread_spin_destroy)(m);
73353944Sdim  MutexDestroy(thr, (uptr)m);
74353944Sdim  return res;
75353944Sdim}
76353944Sdim
77353944SdimINTERCEPTOR(int, pthread_spin_lock, pthread_spinlock_t *m) {
78353944Sdim  InitThread();
79353944Sdim  MutexBeforeLock(thr, (uptr)m, true);
80353944Sdim  int res = REAL(pthread_spin_lock)(m);
81353944Sdim  MutexAfterLock(thr, (uptr)m, true, false);
82353944Sdim  return res;
83353944Sdim}
84353944Sdim
85353944SdimINTERCEPTOR(int, pthread_spin_trylock, pthread_spinlock_t *m) {
86353944Sdim  InitThread();
87353944Sdim  int res = REAL(pthread_spin_trylock)(m);
88353944Sdim  if (res == 0)
89353944Sdim    MutexAfterLock(thr, (uptr)m, true, true);
90353944Sdim  return res;
91353944Sdim}
92353944Sdim
93353944SdimINTERCEPTOR(int, pthread_spin_unlock, pthread_spinlock_t *m) {
94353944Sdim  InitThread();
95353944Sdim  MutexBeforeUnlock(thr, (uptr)m, true);
96353944Sdim  return REAL(pthread_spin_unlock)(m);
97353944Sdim}
98353944Sdim
99353944SdimINTERCEPTOR(int, pthread_rwlock_destroy, pthread_rwlock_t *m) {
100353944Sdim  InitThread();
101353944Sdim  MutexDestroy(thr, (uptr)m);
102353944Sdim  return REAL(pthread_rwlock_destroy)(m);
103353944Sdim}
104353944Sdim
105353944SdimINTERCEPTOR(int, pthread_rwlock_rdlock, pthread_rwlock_t *m) {
106353944Sdim  InitThread();
107353944Sdim  MutexBeforeLock(thr, (uptr)m, false);
108353944Sdim  int res = REAL(pthread_rwlock_rdlock)(m);
109353944Sdim  MutexAfterLock(thr, (uptr)m, false, false);
110353944Sdim  return res;
111353944Sdim}
112353944Sdim
113353944SdimINTERCEPTOR(int, pthread_rwlock_tryrdlock, pthread_rwlock_t *m) {
114353944Sdim  InitThread();
115353944Sdim  int res = REAL(pthread_rwlock_tryrdlock)(m);
116353944Sdim  if (res == 0)
117353944Sdim    MutexAfterLock(thr, (uptr)m, false, true);
118353944Sdim  return res;
119353944Sdim}
120353944Sdim
121353944SdimINTERCEPTOR(int, pthread_rwlock_timedrdlock, pthread_rwlock_t *m,
122353944Sdim    const timespec *abstime) {
123353944Sdim  InitThread();
124353944Sdim  int res = REAL(pthread_rwlock_timedrdlock)(m, abstime);
125353944Sdim  if (res == 0)
126353944Sdim    MutexAfterLock(thr, (uptr)m, false, true);
127353944Sdim  return res;
128353944Sdim}
129353944Sdim
130353944SdimINTERCEPTOR(int, pthread_rwlock_wrlock, pthread_rwlock_t *m) {
131353944Sdim  InitThread();
132353944Sdim  MutexBeforeLock(thr, (uptr)m, true);
133353944Sdim  int res = REAL(pthread_rwlock_wrlock)(m);
134353944Sdim  MutexAfterLock(thr, (uptr)m, true, false);
135353944Sdim  return res;
136353944Sdim}
137353944Sdim
138353944SdimINTERCEPTOR(int, pthread_rwlock_trywrlock, pthread_rwlock_t *m) {
139353944Sdim  InitThread();
140353944Sdim  int res = REAL(pthread_rwlock_trywrlock)(m);
141353944Sdim  if (res == 0)
142353944Sdim    MutexAfterLock(thr, (uptr)m, true, true);
143353944Sdim  return res;
144353944Sdim}
145353944Sdim
146353944SdimINTERCEPTOR(int, pthread_rwlock_timedwrlock, pthread_rwlock_t *m,
147353944Sdim    const timespec *abstime) {
148353944Sdim  InitThread();
149353944Sdim  int res = REAL(pthread_rwlock_timedwrlock)(m, abstime);
150353944Sdim  if (res == 0)
151353944Sdim    MutexAfterLock(thr, (uptr)m, true, true);
152353944Sdim  return res;
153353944Sdim}
154353944Sdim
155353944SdimINTERCEPTOR(int, pthread_rwlock_unlock, pthread_rwlock_t *m) {
156353944Sdim  InitThread();
157353944Sdim  MutexBeforeUnlock(thr, (uptr)m, true);  // note: not necessary write unlock
158353944Sdim  return REAL(pthread_rwlock_unlock)(m);
159353944Sdim}
160353944Sdim
161353944Sdimstatic pthread_cond_t *init_cond(pthread_cond_t *c, bool force = false) {
162353944Sdim  atomic_uintptr_t *p = (atomic_uintptr_t*)c;
163353944Sdim  uptr cond = atomic_load(p, memory_order_acquire);
164353944Sdim  if (!force && cond != 0)
165353944Sdim    return (pthread_cond_t*)cond;
166353944Sdim  void *newcond = malloc(sizeof(pthread_cond_t));
167353944Sdim  internal_memset(newcond, 0, sizeof(pthread_cond_t));
168353944Sdim  if (atomic_compare_exchange_strong(p, &cond, (uptr)newcond,
169353944Sdim      memory_order_acq_rel))
170353944Sdim    return (pthread_cond_t*)newcond;
171353944Sdim  free(newcond);
172353944Sdim  return (pthread_cond_t*)cond;
173353944Sdim}
174353944Sdim
175353944SdimINTERCEPTOR(int, pthread_cond_init, pthread_cond_t *c,
176353944Sdim    const pthread_condattr_t *a) {
177353944Sdim  InitThread();
178353944Sdim  pthread_cond_t *cond = init_cond(c, true);
179353944Sdim  return REAL(pthread_cond_init)(cond, a);
180353944Sdim}
181353944Sdim
182353944SdimINTERCEPTOR(int, pthread_cond_wait, pthread_cond_t *c, pthread_mutex_t *m) {
183353944Sdim  InitThread();
184353944Sdim  pthread_cond_t *cond = init_cond(c);
185353944Sdim  MutexBeforeUnlock(thr, (uptr)m, true);
186353944Sdim  MutexBeforeLock(thr, (uptr)m, true);
187353944Sdim  int res = REAL(pthread_cond_wait)(cond, m);
188353944Sdim  MutexAfterLock(thr, (uptr)m, true, false);
189353944Sdim  return res;
190353944Sdim}
191353944Sdim
192353944SdimINTERCEPTOR(int, pthread_cond_timedwait, pthread_cond_t *c, pthread_mutex_t *m,
193353944Sdim    const timespec *abstime) {
194353944Sdim  InitThread();
195353944Sdim  pthread_cond_t *cond = init_cond(c);
196353944Sdim  MutexBeforeUnlock(thr, (uptr)m, true);
197353944Sdim  MutexBeforeLock(thr, (uptr)m, true);
198353944Sdim  int res = REAL(pthread_cond_timedwait)(cond, m, abstime);
199353944Sdim  MutexAfterLock(thr, (uptr)m, true, false);
200353944Sdim  return res;
201353944Sdim}
202353944Sdim
203353944SdimINTERCEPTOR(int, pthread_cond_signal, pthread_cond_t *c) {
204353944Sdim  InitThread();
205353944Sdim  pthread_cond_t *cond = init_cond(c);
206353944Sdim  return REAL(pthread_cond_signal)(cond);
207353944Sdim}
208353944Sdim
209353944SdimINTERCEPTOR(int, pthread_cond_broadcast, pthread_cond_t *c) {
210353944Sdim  InitThread();
211353944Sdim  pthread_cond_t *cond = init_cond(c);
212353944Sdim  return REAL(pthread_cond_broadcast)(cond);
213353944Sdim}
214353944Sdim
215353944SdimINTERCEPTOR(int, pthread_cond_destroy, pthread_cond_t *c) {
216353944Sdim  InitThread();
217353944Sdim  pthread_cond_t *cond = init_cond(c);
218353944Sdim  int res = REAL(pthread_cond_destroy)(cond);
219353944Sdim  free(cond);
220353944Sdim  atomic_store((atomic_uintptr_t*)c, 0, memory_order_relaxed);
221353944Sdim  return res;
222353944Sdim}
223353944Sdim
224353944Sdim// for symbolizer
225353944SdimINTERCEPTOR(char*, realpath, const char *path, char *resolved_path) {
226353944Sdim  InitThread();
227353944Sdim  return REAL(realpath)(path, resolved_path);
228353944Sdim}
229353944Sdim
230353944SdimINTERCEPTOR(SSIZE_T, read, int fd, void *ptr, SIZE_T count) {
231353944Sdim  InitThread();
232353944Sdim  return REAL(read)(fd, ptr, count);
233353944Sdim}
234353944Sdim
235353944SdimINTERCEPTOR(SSIZE_T, pread, int fd, void *ptr, SIZE_T count, OFF_T offset) {
236353944Sdim  InitThread();
237353944Sdim  return REAL(pread)(fd, ptr, count, offset);
238353944Sdim}
239353944Sdim
240353944Sdimextern "C" {
241353944Sdimvoid __dsan_before_mutex_lock(uptr m, int writelock) {
242353944Sdim  if (!InitThread())
243353944Sdim    return;
244353944Sdim  MutexBeforeLock(thr, m, writelock);
245353944Sdim}
246353944Sdim
247353944Sdimvoid __dsan_after_mutex_lock(uptr m, int writelock, int trylock) {
248353944Sdim  if (!InitThread())
249353944Sdim    return;
250353944Sdim  MutexAfterLock(thr, m, writelock, trylock);
251353944Sdim}
252353944Sdim
253353944Sdimvoid __dsan_before_mutex_unlock(uptr m, int writelock) {
254353944Sdim  if (!InitThread())
255353944Sdim    return;
256353944Sdim  MutexBeforeUnlock(thr, m, writelock);
257353944Sdim}
258353944Sdim
259353944Sdimvoid __dsan_mutex_destroy(uptr m) {
260353944Sdim  if (!InitThread())
261353944Sdim    return;
262353944Sdim  // if (m >= g_data_start && m < g_data_end)
263353944Sdim  //   return;
264353944Sdim  MutexDestroy(thr, m);
265353944Sdim}
266353944Sdim}  // extern "C"
267353944Sdim
268353944Sdimnamespace __dsan {
269353944Sdim
270353944Sdimstatic void InitDataSeg() {
271353944Sdim  MemoryMappingLayout proc_maps(true);
272353944Sdim  char name[128];
273353944Sdim  MemoryMappedSegment segment(name, ARRAY_SIZE(name));
274353944Sdim  bool prev_is_data = false;
275353944Sdim  while (proc_maps.Next(&segment)) {
276353944Sdim    bool is_data = segment.offset != 0 && segment.filename[0] != 0;
277353944Sdim    // BSS may get merged with [heap] in /proc/self/maps. This is not very
278353944Sdim    // reliable.
279353944Sdim    bool is_bss = segment.offset == 0 &&
280353944Sdim                  (segment.filename[0] == 0 ||
281353944Sdim                   internal_strcmp(segment.filename, "[heap]") == 0) &&
282353944Sdim                  prev_is_data;
283353944Sdim    if (g_data_start == 0 && is_data) g_data_start = segment.start;
284353944Sdim    if (is_bss) g_data_end = segment.end;
285353944Sdim    prev_is_data = is_data;
286353944Sdim  }
287353944Sdim  VPrintf(1, "guessed data_start=%p data_end=%p\n",  g_data_start, g_data_end);
288353944Sdim  CHECK_LT(g_data_start, g_data_end);
289353944Sdim  CHECK_GE((uptr)&g_data_start, g_data_start);
290353944Sdim  CHECK_LT((uptr)&g_data_start, g_data_end);
291353944Sdim}
292353944Sdim
293353944Sdimvoid InitializeInterceptors() {
294353944Sdim  INTERCEPT_FUNCTION(pthread_mutex_destroy);
295353944Sdim  INTERCEPT_FUNCTION(pthread_mutex_lock);
296353944Sdim  INTERCEPT_FUNCTION(pthread_mutex_trylock);
297353944Sdim  INTERCEPT_FUNCTION(pthread_mutex_unlock);
298353944Sdim
299353944Sdim  INTERCEPT_FUNCTION(pthread_spin_destroy);
300353944Sdim  INTERCEPT_FUNCTION(pthread_spin_lock);
301353944Sdim  INTERCEPT_FUNCTION(pthread_spin_trylock);
302353944Sdim  INTERCEPT_FUNCTION(pthread_spin_unlock);
303353944Sdim
304353944Sdim  INTERCEPT_FUNCTION(pthread_rwlock_destroy);
305353944Sdim  INTERCEPT_FUNCTION(pthread_rwlock_rdlock);
306353944Sdim  INTERCEPT_FUNCTION(pthread_rwlock_tryrdlock);
307353944Sdim  INTERCEPT_FUNCTION(pthread_rwlock_timedrdlock);
308353944Sdim  INTERCEPT_FUNCTION(pthread_rwlock_wrlock);
309353944Sdim  INTERCEPT_FUNCTION(pthread_rwlock_trywrlock);
310353944Sdim  INTERCEPT_FUNCTION(pthread_rwlock_timedwrlock);
311353944Sdim  INTERCEPT_FUNCTION(pthread_rwlock_unlock);
312353944Sdim
313353944Sdim  INTERCEPT_FUNCTION_VER(pthread_cond_init, "GLIBC_2.3.2");
314353944Sdim  INTERCEPT_FUNCTION_VER(pthread_cond_signal, "GLIBC_2.3.2");
315353944Sdim  INTERCEPT_FUNCTION_VER(pthread_cond_broadcast, "GLIBC_2.3.2");
316353944Sdim  INTERCEPT_FUNCTION_VER(pthread_cond_wait, "GLIBC_2.3.2");
317353944Sdim  INTERCEPT_FUNCTION_VER(pthread_cond_timedwait, "GLIBC_2.3.2");
318353944Sdim  INTERCEPT_FUNCTION_VER(pthread_cond_destroy, "GLIBC_2.3.2");
319353944Sdim
320353944Sdim  // for symbolizer
321353944Sdim  INTERCEPT_FUNCTION(realpath);
322353944Sdim  INTERCEPT_FUNCTION(read);
323353944Sdim  INTERCEPT_FUNCTION(pread);
324353944Sdim
325353944Sdim  InitDataSeg();
326353944Sdim}
327353944Sdim
328353944Sdim}  // namespace __dsan
329