xref: /netbsd-src/external/gpl3/gcc.old/dist/libsanitizer/asan/asan_posix.cc (revision 4d5abbe83f525258eb479e5fca29f25cb943f379)
1 //===-- asan_linux.cc -----------------------------------------------------===//
2 //
3 // This file is distributed under the University of Illinois Open Source
4 // License. See LICENSE.TXT for details.
5 //
6 //===----------------------------------------------------------------------===//
7 //
8 // This file is a part of AddressSanitizer, an address sanity checker.
9 //
10 // Posix-specific details.
11 //===----------------------------------------------------------------------===//
12 #if defined(__linux__) || defined(__APPLE__) || defined(__NetBSD__)
13 
14 #include "asan_internal.h"
15 #include "asan_interceptors.h"
16 #include "asan_mapping.h"
17 #include "asan_report.h"
18 #include "asan_stack.h"
19 #include "asan_thread_registry.h"
20 #include "sanitizer_common/sanitizer_libc.h"
21 #include "sanitizer_common/sanitizer_procmaps.h"
22 
23 #include <pthread.h>
24 #include <signal.h>
25 #include <stdlib.h>
26 #include <sys/time.h>
27 #include <sys/resource.h>
28 #include <unistd.h>
29 
30 static const uptr kAltStackSize = SIGSTKSZ * 4;  // SIGSTKSZ is not enough.
31 
32 namespace __asan {
33 
34 static void MaybeInstallSigaction(int signum,
35                                   void (*handler)(int, siginfo_t *, void *)) {
36   if (!AsanInterceptsSignal(signum))
37     return;
38   struct sigaction sigact;
39   REAL(memset)(&sigact, 0, sizeof(sigact));
40   sigact.sa_sigaction = handler;
41   sigact.sa_flags = SA_SIGINFO;
42   if (flags()->use_sigaltstack) sigact.sa_flags |= SA_ONSTACK;
43   CHECK(0 == REAL(sigaction)(signum, &sigact, 0));
44   if (flags()->verbosity >= 1) {
45     Report("Installed the sigaction for signal %d\n", signum);
46   }
47 }
48 
49 static void     ASAN_OnSIGSEGV(int, siginfo_t *siginfo, void *context) {
50   uptr addr = (uptr)siginfo->si_addr;
51   // Write the first message using the bullet-proof write.
52   if (13 != internal_write(2, "ASAN:SIGSEGV\n", 13)) Die();
53   uptr pc, sp, bp;
54   GetPcSpBp(context, &pc, &sp, &bp);
55   ReportSIGSEGV(pc, sp, bp, addr);
56 }
57 
58 void SetAlternateSignalStack() {
59   stack_t altstack, oldstack;
60   CHECK(0 == sigaltstack(0, &oldstack));
61   // If the alternate stack is already in place, do nothing.
62   if ((oldstack.ss_flags & SS_DISABLE) == 0) return;
63   // TODO(glider): the mapped stack should have the MAP_STACK flag in the
64   // future. It is not required by man 2 sigaltstack now (they're using
65   // malloc()).
66   void* base = MmapOrDie(kAltStackSize, __FUNCTION__);
67   altstack.ss_sp = base;
68   altstack.ss_flags = 0;
69   altstack.ss_size = kAltStackSize;
70   CHECK(0 == sigaltstack(&altstack, 0));
71   if (flags()->verbosity > 0) {
72     Report("Alternative stack for T%d set: [%p,%p)\n",
73            asanThreadRegistry().GetCurrentTidOrInvalid(),
74            altstack.ss_sp, (char*)altstack.ss_sp + altstack.ss_size);
75   }
76 }
77 
78 void UnsetAlternateSignalStack() {
79   stack_t altstack, oldstack;
80   altstack.ss_sp = 0;
81   altstack.ss_flags = SS_DISABLE;
82   altstack.ss_size = 0;
83   CHECK(0 == sigaltstack(&altstack, &oldstack));
84   UnmapOrDie(oldstack.ss_sp, oldstack.ss_size);
85 }
86 
87 void InstallSignalHandlers() {
88   // Set the alternate signal stack for the main thread.
89   // This will cause SetAlternateSignalStack to be called twice, but the stack
90   // will be actually set only once.
91   if (flags()->use_sigaltstack) SetAlternateSignalStack();
92   MaybeInstallSigaction(SIGSEGV, ASAN_OnSIGSEGV);
93   MaybeInstallSigaction(SIGBUS, ASAN_OnSIGSEGV);
94 }
95 
96 // ---------------------- TSD ---------------- {{{1
97 
98 static pthread_key_t tsd_key;
99 static bool tsd_key_inited = false;
100 void AsanTSDInit(void (*destructor)(void *tsd)) {
101   CHECK(!tsd_key_inited);
102   tsd_key_inited = true;
103   CHECK(0 == pthread_key_create(&tsd_key, destructor));
104 }
105 
106 void *AsanTSDGet() {
107   CHECK(tsd_key_inited);
108   return pthread_getspecific(tsd_key);
109 }
110 
111 void AsanTSDSet(void *tsd) {
112   CHECK(tsd_key_inited);
113   pthread_setspecific(tsd_key, tsd);
114 }
115 
116 }  // namespace __asan
117 
118 #endif  // __linux__ || __APPLE_ || __NetBSD__
119