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