| Kostya Serebryany | a7e760a | 2012-01-09 19:18:27 +0000 | [diff] [blame] | 1 | //===-- asan_linux.cc -----------------------------------------------------===// |
| 2 | // |
| 3 | // The LLVM Compiler Infrastructure |
| 4 | // |
| 5 | // This file is distributed under the University of Illinois Open Source |
| 6 | // License. See LICENSE.TXT for details. |
| 7 | // |
| 8 | //===----------------------------------------------------------------------===// |
| 9 | // |
| 10 | // This file is a part of AddressSanitizer, an address sanity checker. |
| 11 | // |
| 12 | // Posix-specific details. |
| 13 | //===----------------------------------------------------------------------===// |
| 14 | #if defined(__linux__) || defined(__APPLE__) |
| 15 | |
| 16 | #include "asan_internal.h" |
| 17 | #include "asan_interceptors.h" |
| Evgeniy Stepanov | c99f700 | 2012-05-23 15:21:50 +0000 | [diff] [blame] | 18 | #include "asan_mapping.h" |
| Kostya Serebryany | a7e760a | 2012-01-09 19:18:27 +0000 | [diff] [blame] | 19 | #include "asan_stack.h" |
| 20 | #include "asan_thread_registry.h" |
| Alexey Samsonov | 2221f55 | 2012-06-05 08:48:10 +0000 | [diff] [blame] | 21 | #include "sanitizer_common/sanitizer_libc.h" |
| Alexey Samsonov | 6895adc | 2012-06-07 06:15:12 +0000 | [diff] [blame] | 22 | #include "sanitizer_common/sanitizer_procmaps.h" |
| Kostya Serebryany | a7e760a | 2012-01-09 19:18:27 +0000 | [diff] [blame] | 23 | |
| Kostya Serebryany | cc4e686 | 2012-01-11 02:21:06 +0000 | [diff] [blame] | 24 | #include <pthread.h> |
| Kostya Serebryany | a7e760a | 2012-01-09 19:18:27 +0000 | [diff] [blame] | 25 | #include <signal.h> |
| Alexey Samsonov | b823e3c | 2012-02-22 14:07:06 +0000 | [diff] [blame] | 26 | #include <stdlib.h> |
| Kostya Serebryany | a7e760a | 2012-01-09 19:18:27 +0000 | [diff] [blame] | 27 | #include <sys/time.h> |
| 28 | #include <sys/resource.h> |
| Kostya Serebryany | 0ecf5eb | 2012-01-09 23:11:26 +0000 | [diff] [blame] | 29 | #include <unistd.h> |
| Kostya Serebryany | a7e760a | 2012-01-09 19:18:27 +0000 | [diff] [blame] | 30 | |
| Kostya Serebryany | 3f4c387 | 2012-05-31 14:35:53 +0000 | [diff] [blame] | 31 | static const uptr kAltStackSize = SIGSTKSZ * 4; // SIGSTKSZ is not enough. |
| Alexander Potapenko | f03d8af | 2012-04-05 10:54:52 +0000 | [diff] [blame] | 32 | |
| Kostya Serebryany | a7e760a | 2012-01-09 19:18:27 +0000 | [diff] [blame] | 33 | namespace __asan { |
| 34 | |
| 35 | static void MaybeInstallSigaction(int signum, |
| 36 | void (*handler)(int, siginfo_t *, void *)) { |
| 37 | if (!AsanInterceptsSignal(signum)) |
| 38 | return; |
| 39 | struct sigaction sigact; |
| Alexey Samsonov | 09672ca | 2012-02-08 13:45:31 +0000 | [diff] [blame] | 40 | REAL(memset)(&sigact, 0, sizeof(sigact)); |
| Kostya Serebryany | a7e760a | 2012-01-09 19:18:27 +0000 | [diff] [blame] | 41 | sigact.sa_sigaction = handler; |
| 42 | sigact.sa_flags = SA_SIGINFO; |
| Alexey Samsonov | cb8c4dc | 2012-07-09 14:36:04 +0000 | [diff] [blame^] | 43 | if (flags()->use_sigaltstack) sigact.sa_flags |= SA_ONSTACK; |
| Alexey Samsonov | 09672ca | 2012-02-08 13:45:31 +0000 | [diff] [blame] | 44 | CHECK(0 == REAL(sigaction)(signum, &sigact, 0)); |
| Alexey Samsonov | cb8c4dc | 2012-07-09 14:36:04 +0000 | [diff] [blame^] | 45 | if (flags()->verbosity >= 1) { |
| Alexander Potapenko | a87bdaa | 2012-05-30 15:29:11 +0000 | [diff] [blame] | 46 | Report("Installed the sigaction for signal %d\n", signum); |
| 47 | } |
| Kostya Serebryany | a7e760a | 2012-01-09 19:18:27 +0000 | [diff] [blame] | 48 | } |
| 49 | |
| 50 | static void ASAN_OnSIGSEGV(int, siginfo_t *siginfo, void *context) { |
| Kostya Serebryany | 3f4c387 | 2012-05-31 14:35:53 +0000 | [diff] [blame] | 51 | uptr addr = (uptr)siginfo->si_addr; |
| Kostya Serebryany | a7e760a | 2012-01-09 19:18:27 +0000 | [diff] [blame] | 52 | // Write the first message using the bullet-proof write. |
| Alexey Samsonov | 47657ce | 2012-06-06 07:02:44 +0000 | [diff] [blame] | 53 | if (13 != internal_write(2, "ASAN:SIGSEGV\n", 13)) Die(); |
| Kostya Serebryany | 3f4c387 | 2012-05-31 14:35:53 +0000 | [diff] [blame] | 54 | uptr pc, sp, bp; |
| Kostya Serebryany | a7e760a | 2012-01-09 19:18:27 +0000 | [diff] [blame] | 55 | GetPcSpBp(context, &pc, &sp, &bp); |
| Alexey Samsonov | e954101 | 2012-06-06 13:11:29 +0000 | [diff] [blame] | 56 | AsanReport("ERROR: AddressSanitizer crashed on unknown address %p" |
| 57 | " (pc %p sp %p bp %p T%d)\n", |
| 58 | (void*)addr, (void*)pc, (void*)sp, (void*)bp, |
| Kostya Serebryany | e0cff0b | 2012-06-06 15:06:58 +0000 | [diff] [blame] | 59 | asanThreadRegistry().GetCurrentTidOrInvalid()); |
| Alexey Samsonov | e954101 | 2012-06-06 13:11:29 +0000 | [diff] [blame] | 60 | AsanPrintf("AddressSanitizer can not provide additional info. ABORTING\n"); |
| Evgeniy Stepanov | 9cfa194 | 2012-01-19 11:34:18 +0000 | [diff] [blame] | 61 | GET_STACK_TRACE_WITH_PC_AND_BP(kStackTraceMax, pc, bp); |
| Kostya Serebryany | a7e760a | 2012-01-09 19:18:27 +0000 | [diff] [blame] | 62 | stack.PrintStack(); |
| 63 | ShowStatsAndAbort(); |
| 64 | } |
| 65 | |
| Alexander Potapenko | f03d8af | 2012-04-05 10:54:52 +0000 | [diff] [blame] | 66 | void SetAlternateSignalStack() { |
| 67 | stack_t altstack, oldstack; |
| Kostya Serebryany | 3f4c387 | 2012-05-31 14:35:53 +0000 | [diff] [blame] | 68 | CHECK(0 == sigaltstack(0, &oldstack)); |
| Alexander Potapenko | f03d8af | 2012-04-05 10:54:52 +0000 | [diff] [blame] | 69 | // If the alternate stack is already in place, do nothing. |
| 70 | if ((oldstack.ss_flags & SS_DISABLE) == 0) return; |
| 71 | // TODO(glider): the mapped stack should have the MAP_STACK flag in the |
| 72 | // future. It is not required by man 2 sigaltstack now (they're using |
| 73 | // malloc()). |
| Alexey Samsonov | a25b346 | 2012-06-06 16:15:07 +0000 | [diff] [blame] | 74 | void* base = MmapOrDie(kAltStackSize, __FUNCTION__); |
| Alexander Potapenko | f03d8af | 2012-04-05 10:54:52 +0000 | [diff] [blame] | 75 | altstack.ss_sp = base; |
| 76 | altstack.ss_flags = 0; |
| 77 | altstack.ss_size = kAltStackSize; |
| Kostya Serebryany | 3f4c387 | 2012-05-31 14:35:53 +0000 | [diff] [blame] | 78 | CHECK(0 == sigaltstack(&altstack, 0)); |
| Alexey Samsonov | cb8c4dc | 2012-07-09 14:36:04 +0000 | [diff] [blame^] | 79 | if (flags()->verbosity > 0) { |
| Alexander Potapenko | f03d8af | 2012-04-05 10:54:52 +0000 | [diff] [blame] | 80 | Report("Alternative stack for T%d set: [%p,%p)\n", |
| Kostya Serebryany | e0cff0b | 2012-06-06 15:06:58 +0000 | [diff] [blame] | 81 | asanThreadRegistry().GetCurrentTidOrInvalid(), |
| Alexander Potapenko | f03d8af | 2012-04-05 10:54:52 +0000 | [diff] [blame] | 82 | altstack.ss_sp, (char*)altstack.ss_sp + altstack.ss_size); |
| 83 | } |
| 84 | } |
| 85 | |
| 86 | void UnsetAlternateSignalStack() { |
| 87 | stack_t altstack, oldstack; |
| Kostya Serebryany | 3f4c387 | 2012-05-31 14:35:53 +0000 | [diff] [blame] | 88 | altstack.ss_sp = 0; |
| Alexander Potapenko | f03d8af | 2012-04-05 10:54:52 +0000 | [diff] [blame] | 89 | altstack.ss_flags = SS_DISABLE; |
| 90 | altstack.ss_size = 0; |
| 91 | CHECK(0 == sigaltstack(&altstack, &oldstack)); |
| Alexey Samsonov | a25b346 | 2012-06-06 16:15:07 +0000 | [diff] [blame] | 92 | UnmapOrDie(oldstack.ss_sp, oldstack.ss_size); |
| Alexander Potapenko | f03d8af | 2012-04-05 10:54:52 +0000 | [diff] [blame] | 93 | } |
| 94 | |
| Kostya Serebryany | a7e760a | 2012-01-09 19:18:27 +0000 | [diff] [blame] | 95 | void InstallSignalHandlers() { |
| Alexander Potapenko | f03d8af | 2012-04-05 10:54:52 +0000 | [diff] [blame] | 96 | // Set the alternate signal stack for the main thread. |
| 97 | // This will cause SetAlternateSignalStack to be called twice, but the stack |
| 98 | // will be actually set only once. |
| Alexey Samsonov | cb8c4dc | 2012-07-09 14:36:04 +0000 | [diff] [blame^] | 99 | if (flags()->use_sigaltstack) SetAlternateSignalStack(); |
| Kostya Serebryany | a7e760a | 2012-01-09 19:18:27 +0000 | [diff] [blame] | 100 | MaybeInstallSigaction(SIGSEGV, ASAN_OnSIGSEGV); |
| 101 | MaybeInstallSigaction(SIGBUS, ASAN_OnSIGSEGV); |
| 102 | } |
| 103 | |
| Kostya Serebryany | cc4e686 | 2012-01-11 02:21:06 +0000 | [diff] [blame] | 104 | // ---------------------- TSD ---------------- {{{1 |
| 105 | |
| 106 | static pthread_key_t tsd_key; |
| 107 | static bool tsd_key_inited = false; |
| Kostya Serebryany | f58f998 | 2012-02-07 00:27:15 +0000 | [diff] [blame] | 108 | void AsanTSDInit(void (*destructor)(void *tsd)) { |
| Kostya Serebryany | cc4e686 | 2012-01-11 02:21:06 +0000 | [diff] [blame] | 109 | CHECK(!tsd_key_inited); |
| 110 | tsd_key_inited = true; |
| Kostya Serebryany | f58f998 | 2012-02-07 00:27:15 +0000 | [diff] [blame] | 111 | CHECK(0 == pthread_key_create(&tsd_key, destructor)); |
| Kostya Serebryany | cc4e686 | 2012-01-11 02:21:06 +0000 | [diff] [blame] | 112 | } |
| 113 | |
| 114 | void *AsanTSDGet() { |
| 115 | CHECK(tsd_key_inited); |
| 116 | return pthread_getspecific(tsd_key); |
| 117 | } |
| 118 | |
| 119 | void AsanTSDSet(void *tsd) { |
| 120 | CHECK(tsd_key_inited); |
| 121 | pthread_setspecific(tsd_key, tsd); |
| 122 | } |
| 123 | |
| Kostya Serebryany | a7e760a | 2012-01-09 19:18:27 +0000 | [diff] [blame] | 124 | } // namespace __asan |
| 125 | |
| 126 | #endif // __linux__ || __APPLE_ |