Kostya Serebryany | 019b76f | 2011-11-30 01:07:02 +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 | // Linux-specific details. |
| 13 | //===----------------------------------------------------------------------===// |
Evgeniy Stepanov | 0af6723 | 2013-03-19 14:33:38 +0000 | [diff] [blame] | 14 | |
| 15 | #include "sanitizer_common/sanitizer_platform.h" |
Alexey Samsonov | 5ec35b7 | 2014-03-06 09:05:52 +0000 | [diff] [blame] | 16 | #if SANITIZER_FREEBSD || SANITIZER_LINUX |
Kostya Serebryany | 019b76f | 2011-11-30 01:07:02 +0000 | [diff] [blame] | 17 | |
Kostya Serebryany | cd271f5 | 2012-01-05 00:44:33 +0000 | [diff] [blame] | 18 | #include "asan_interceptors.h" |
Kostya Serebryany | 019b76f | 2011-11-30 01:07:02 +0000 | [diff] [blame] | 19 | #include "asan_internal.h" |
Kostya Serebryany | 78d87d3 | 2012-01-05 01:07:27 +0000 | [diff] [blame] | 20 | #include "asan_thread.h" |
Alexey Samsonov | 3d9adc0 | 2014-03-04 13:12:25 +0000 | [diff] [blame] | 21 | #include "sanitizer_common/sanitizer_flags.h" |
Alexey Samsonov | 2c5fc3b | 2012-06-04 14:27:50 +0000 | [diff] [blame] | 22 | #include "sanitizer_common/sanitizer_libc.h" |
Alexey Samsonov | 28a9895 | 2012-06-07 06:15:12 +0000 | [diff] [blame] | 23 | #include "sanitizer_common/sanitizer_procmaps.h" |
Kostya Serebryany | 019b76f | 2011-11-30 01:07:02 +0000 | [diff] [blame] | 24 | |
Kostya Serebryany | 78d87d3 | 2012-01-05 01:07:27 +0000 | [diff] [blame] | 25 | #include <sys/time.h> |
| 26 | #include <sys/resource.h> |
Kostya Serebryany | 019b76f | 2011-11-30 01:07:02 +0000 | [diff] [blame] | 27 | #include <sys/mman.h> |
| 28 | #include <sys/syscall.h> |
Kostya Serebryany | 6c4bd80 | 2011-12-28 22:58:01 +0000 | [diff] [blame] | 29 | #include <sys/types.h> |
| 30 | #include <fcntl.h> |
Kostya Serebryany | 78d87d3 | 2012-01-05 01:07:27 +0000 | [diff] [blame] | 31 | #include <pthread.h> |
Kostya Serebryany | cd271f5 | 2012-01-05 00:44:33 +0000 | [diff] [blame] | 32 | #include <stdio.h> |
Kostya Serebryany | 019b76f | 2011-11-30 01:07:02 +0000 | [diff] [blame] | 33 | #include <unistd.h> |
Evgeniy Stepanov | 84c44a8 | 2012-01-19 11:34:18 +0000 | [diff] [blame] | 34 | #include <unwind.h> |
Kostya Serebryany | 019b76f | 2011-11-30 01:07:02 +0000 | [diff] [blame] | 35 | |
Evgeniy Stepanov | 6db97e8 | 2014-02-10 13:34:43 +0000 | [diff] [blame] | 36 | #if SANITIZER_ANDROID |
| 37 | #include <ucontext.h> |
Alexey Samsonov | 56b6ee9 | 2014-04-01 13:16:30 +0000 | [diff] [blame] | 38 | extern "C" void* _DYNAMIC; |
Evgeniy Stepanov | 6db97e8 | 2014-02-10 13:34:43 +0000 | [diff] [blame] | 39 | #else |
Kostya Serebryany | 25d6c1b | 2012-01-06 19:11:09 +0000 | [diff] [blame] | 40 | #include <sys/ucontext.h> |
Alexey Samsonov | 56b6ee9 | 2014-04-01 13:16:30 +0000 | [diff] [blame] | 41 | #include <dlfcn.h> |
| 42 | #include <link.h> |
Kostya Serebryany | 25d6c1b | 2012-01-06 19:11:09 +0000 | [diff] [blame] | 43 | #endif |
| 44 | |
Viktor Kutuzov | ebb00e1 | 2014-03-12 12:44:36 +0000 | [diff] [blame] | 45 | // x86_64 FreeBSD 9.2 and older define 64-bit register names in both 64-bit |
| 46 | // and 32-bit modes. |
| 47 | #if SANITIZER_FREEBSD |
| 48 | #include <sys/param.h> |
| 49 | # if __FreeBSD_version <= 902001 // v9.2 |
| 50 | # define mc_eip mc_rip |
| 51 | # define mc_ebp mc_rbp |
| 52 | # define mc_esp mc_rsp |
| 53 | # endif |
| 54 | #endif |
| 55 | |
Alexey Samsonov | 56b6ee9 | 2014-04-01 13:16:30 +0000 | [diff] [blame] | 56 | typedef enum { |
| 57 | ASAN_RT_VERSION_UNDEFINED = 0, |
| 58 | ASAN_RT_VERSION_DYNAMIC, |
| 59 | ASAN_RT_VERSION_STATIC, |
| 60 | } asan_rt_version_t; |
| 61 | |
| 62 | // FIXME: perhaps also store abi version here? |
| 63 | extern "C" { |
| 64 | SANITIZER_INTERFACE_ATTRIBUTE |
| 65 | asan_rt_version_t __asan_rt_version; |
| 66 | } |
Evgeniy Stepanov | 4cc2631 | 2012-03-26 09:48:41 +0000 | [diff] [blame] | 67 | |
Kostya Serebryany | 019b76f | 2011-11-30 01:07:02 +0000 | [diff] [blame] | 68 | namespace __asan { |
| 69 | |
Alexander Potapenko | fefc1e9 | 2012-08-24 09:22:05 +0000 | [diff] [blame] | 70 | void MaybeReexec() { |
| 71 | // No need to re-exec on Linux. |
| 72 | } |
| 73 | |
Kostya Serebryany | 019b76f | 2011-11-30 01:07:02 +0000 | [diff] [blame] | 74 | void *AsanDoesNotSupportStaticLinkage() { |
| 75 | // This will fail to link with -static. |
Kostya Serebryany | 3b7fb10 | 2012-01-05 23:50:34 +0000 | [diff] [blame] | 76 | return &_DYNAMIC; // defined in link.h |
Kostya Serebryany | 019b76f | 2011-11-30 01:07:02 +0000 | [diff] [blame] | 77 | } |
| 78 | |
Alexey Samsonov | 2c66a22 | 2014-04-02 09:36:36 +0000 | [diff] [blame] | 79 | #if SANITIZER_ANDROID |
| 80 | // FIXME: should we do anything for Android? |
| 81 | void AsanCheckDynamicRTPrereqs() {} |
| 82 | void AsanCheckIncompatibleRT() {} |
| 83 | #else |
Alexey Samsonov | 56b6ee9 | 2014-04-01 13:16:30 +0000 | [diff] [blame] | 84 | static int FindFirstDSOCallback(struct dl_phdr_info *info, size_t size, |
| 85 | void *data) { |
| 86 | // Continue until the first dynamic library is found |
| 87 | if (!info->dlpi_name || info->dlpi_name[0] == 0) |
| 88 | return 0; |
| 89 | |
| 90 | *(const char **)data = info->dlpi_name; |
| 91 | return 1; |
| 92 | } |
| 93 | |
| 94 | static bool IsDynamicRTName(const char *libname) { |
| 95 | return internal_strstr(libname, "libclang_rt.asan") || |
| 96 | internal_strstr(libname, "libasan.so"); |
| 97 | } |
| 98 | |
Alexey Samsonov | 11ff0a2 | 2014-04-02 13:09:22 +0000 | [diff] [blame^] | 99 | static void ReportIncompatibleRT() { |
| 100 | Report("Your application is linked against incompatible ASan runtimes.\n"); |
| 101 | Die(); |
| 102 | } |
| 103 | |
Alexey Samsonov | 56b6ee9 | 2014-04-01 13:16:30 +0000 | [diff] [blame] | 104 | void AsanCheckDynamicRTPrereqs() { |
Alexey Samsonov | 56b6ee9 | 2014-04-01 13:16:30 +0000 | [diff] [blame] | 105 | // Ensure that dynamic RT is the first DSO in the list |
| 106 | const char *first_dso_name = 0; |
| 107 | dl_iterate_phdr(FindFirstDSOCallback, &first_dso_name); |
| 108 | if (first_dso_name && !IsDynamicRTName(first_dso_name)) { |
| 109 | Report("ASan runtime does not come first in initial library list; " |
| 110 | "you should either link runtime to your application or " |
| 111 | "manually preload it with LD_PRELOAD.\n"); |
| 112 | Die(); |
| 113 | } |
Alexey Samsonov | 56b6ee9 | 2014-04-01 13:16:30 +0000 | [diff] [blame] | 114 | } |
| 115 | |
| 116 | void AsanCheckIncompatibleRT() { |
Alexey Samsonov | 56b6ee9 | 2014-04-01 13:16:30 +0000 | [diff] [blame] | 117 | if (ASAN_DYNAMIC) { |
| 118 | if (__asan_rt_version == ASAN_RT_VERSION_UNDEFINED) { |
| 119 | __asan_rt_version = ASAN_RT_VERSION_DYNAMIC; |
| 120 | } else if (__asan_rt_version != ASAN_RT_VERSION_DYNAMIC) { |
Alexey Samsonov | 11ff0a2 | 2014-04-02 13:09:22 +0000 | [diff] [blame^] | 121 | ReportIncompatibleRT(); |
Alexey Samsonov | 56b6ee9 | 2014-04-01 13:16:30 +0000 | [diff] [blame] | 122 | } |
| 123 | } else { |
Alexey Samsonov | 11ff0a2 | 2014-04-02 13:09:22 +0000 | [diff] [blame^] | 124 | if (__asan_rt_version == ASAN_RT_VERSION_UNDEFINED) { |
| 125 | // Ensure that dynamic runtime is not present. We should detect it |
| 126 | // as early as possible, otherwise ASan interceptors could bind to |
| 127 | // the functions in dynamic ASan runtime instead of the functions in |
| 128 | // system libraries, causing crashes later in ASan initialization. |
| 129 | MemoryMappingLayout proc_maps(/*cache_enabled*/true); |
| 130 | char filename[128]; |
| 131 | while (proc_maps.Next(0, 0, 0, filename, sizeof(filename), 0)) { |
| 132 | if (IsDynamicRTName(filename)) { |
| 133 | Report("Your application is linked against " |
| 134 | "incompatible ASan runtimes.\n"); |
| 135 | Die(); |
| 136 | } |
Alexey Samsonov | 56b6ee9 | 2014-04-01 13:16:30 +0000 | [diff] [blame] | 137 | } |
Alexey Samsonov | 11ff0a2 | 2014-04-02 13:09:22 +0000 | [diff] [blame^] | 138 | __asan_rt_version = ASAN_RT_VERSION_STATIC; |
| 139 | } else if (__asan_rt_version != ASAN_RT_VERSION_STATIC) { |
| 140 | ReportIncompatibleRT(); |
Alexey Samsonov | 56b6ee9 | 2014-04-01 13:16:30 +0000 | [diff] [blame] | 141 | } |
Alexey Samsonov | 56b6ee9 | 2014-04-01 13:16:30 +0000 | [diff] [blame] | 142 | } |
Alexey Samsonov | 56b6ee9 | 2014-04-01 13:16:30 +0000 | [diff] [blame] | 143 | } |
Alexey Samsonov | 2c66a22 | 2014-04-02 09:36:36 +0000 | [diff] [blame] | 144 | #endif // SANITIZER_ANDROID |
Alexey Samsonov | 56b6ee9 | 2014-04-01 13:16:30 +0000 | [diff] [blame] | 145 | |
Kostya Serebryany | 8d03204 | 2012-05-31 14:35:53 +0000 | [diff] [blame] | 146 | void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) { |
Evgeniy Stepanov | 6db97e8 | 2014-02-10 13:34:43 +0000 | [diff] [blame] | 147 | #if defined(__arm__) |
Kostya Serebryany | 25d6c1b | 2012-01-06 19:11:09 +0000 | [diff] [blame] | 148 | ucontext_t *ucontext = (ucontext_t*)context; |
| 149 | *pc = ucontext->uc_mcontext.arm_pc; |
| 150 | *bp = ucontext->uc_mcontext.arm_fp; |
| 151 | *sp = ucontext->uc_mcontext.arm_sp; |
Alexey Samsonov | 5ec35b7 | 2014-03-06 09:05:52 +0000 | [diff] [blame] | 152 | #elif defined(__aarch64__) |
Kostya Serebryany | c98ce28 | 2014-02-13 07:50:20 +0000 | [diff] [blame] | 153 | ucontext_t *ucontext = (ucontext_t*)context; |
| 154 | *pc = ucontext->uc_mcontext.pc; |
| 155 | *bp = ucontext->uc_mcontext.regs[29]; |
| 156 | *sp = ucontext->uc_mcontext.sp; |
Alexey Samsonov | 5ec35b7 | 2014-03-06 09:05:52 +0000 | [diff] [blame] | 157 | #elif defined(__hppa__) |
Kostya Serebryany | a92b07d | 2013-11-18 08:20:13 +0000 | [diff] [blame] | 158 | ucontext_t *ucontext = (ucontext_t*)context; |
| 159 | *pc = ucontext->uc_mcontext.sc_iaoq[0]; |
| 160 | /* GCC uses %r3 whenever a frame pointer is needed. */ |
| 161 | *bp = ucontext->uc_mcontext.sc_gr[3]; |
| 162 | *sp = ucontext->uc_mcontext.sc_gr[30]; |
Alexey Samsonov | 5ec35b7 | 2014-03-06 09:05:52 +0000 | [diff] [blame] | 163 | #elif defined(__x86_64__) |
| 164 | # if SANITIZER_FREEBSD |
| 165 | ucontext_t *ucontext = (ucontext_t*)context; |
| 166 | *pc = ucontext->uc_mcontext.mc_rip; |
| 167 | *bp = ucontext->uc_mcontext.mc_rbp; |
| 168 | *sp = ucontext->uc_mcontext.mc_rsp; |
| 169 | # else |
Kostya Serebryany | 25d6c1b | 2012-01-06 19:11:09 +0000 | [diff] [blame] | 170 | ucontext_t *ucontext = (ucontext_t*)context; |
| 171 | *pc = ucontext->uc_mcontext.gregs[REG_RIP]; |
| 172 | *bp = ucontext->uc_mcontext.gregs[REG_RBP]; |
| 173 | *sp = ucontext->uc_mcontext.gregs[REG_RSP]; |
Alexey Samsonov | 5ec35b7 | 2014-03-06 09:05:52 +0000 | [diff] [blame] | 174 | # endif |
| 175 | #elif defined(__i386__) |
| 176 | # if SANITIZER_FREEBSD |
| 177 | ucontext_t *ucontext = (ucontext_t*)context; |
| 178 | *pc = ucontext->uc_mcontext.mc_eip; |
| 179 | *bp = ucontext->uc_mcontext.mc_ebp; |
| 180 | *sp = ucontext->uc_mcontext.mc_esp; |
| 181 | # else |
Kostya Serebryany | 25d6c1b | 2012-01-06 19:11:09 +0000 | [diff] [blame] | 182 | ucontext_t *ucontext = (ucontext_t*)context; |
| 183 | *pc = ucontext->uc_mcontext.gregs[REG_EIP]; |
| 184 | *bp = ucontext->uc_mcontext.gregs[REG_EBP]; |
| 185 | *sp = ucontext->uc_mcontext.gregs[REG_ESP]; |
Alexey Samsonov | 5ec35b7 | 2014-03-06 09:05:52 +0000 | [diff] [blame] | 186 | # endif |
| 187 | #elif defined(__sparc__) |
Dmitry Vyukov | 4ee90c23 | 2012-11-16 11:26:05 +0000 | [diff] [blame] | 188 | ucontext_t *ucontext = (ucontext_t*)context; |
| 189 | uptr *stk_ptr; |
| 190 | # if defined (__arch64__) |
| 191 | *pc = ucontext->uc_mcontext.mc_gregs[MC_PC]; |
| 192 | *sp = ucontext->uc_mcontext.mc_gregs[MC_O6]; |
| 193 | stk_ptr = (uptr *) (*sp + 2047); |
| 194 | *bp = stk_ptr[15]; |
| 195 | # else |
| 196 | *pc = ucontext->uc_mcontext.gregs[REG_PC]; |
| 197 | *sp = ucontext->uc_mcontext.gregs[REG_O6]; |
| 198 | stk_ptr = (uptr *) *sp; |
| 199 | *bp = stk_ptr[15]; |
| 200 | # endif |
Alexey Samsonov | 5ec35b7 | 2014-03-06 09:05:52 +0000 | [diff] [blame] | 201 | #elif defined(__mips__) |
Kostya Serebryany | c1aa0e8 | 2013-06-03 14:49:25 +0000 | [diff] [blame] | 202 | ucontext_t *ucontext = (ucontext_t*)context; |
| 203 | *pc = ucontext->uc_mcontext.gregs[31]; |
| 204 | *bp = ucontext->uc_mcontext.gregs[30]; |
| 205 | *sp = ucontext->uc_mcontext.gregs[29]; |
Kostya Serebryany | 25d6c1b | 2012-01-06 19:11:09 +0000 | [diff] [blame] | 206 | #else |
| 207 | # error "Unsupported arch" |
| 208 | #endif |
| 209 | } |
| 210 | |
Kostya Serebryany | 9fd01e5 | 2012-01-09 18:53:15 +0000 | [diff] [blame] | 211 | bool AsanInterceptsSignal(int signum) { |
Alexander Potapenko | cf4bef3 | 2014-01-28 09:28:57 +0000 | [diff] [blame] | 212 | return signum == SIGSEGV && common_flags()->handle_segv; |
Kostya Serebryany | 9fd01e5 | 2012-01-09 18:53:15 +0000 | [diff] [blame] | 213 | } |
| 214 | |
Alexander Potapenko | 51e6488 | 2012-07-23 14:07:58 +0000 | [diff] [blame] | 215 | void AsanPlatformThreadInit() { |
| 216 | // Nothing here for now. |
| 217 | } |
| 218 | |
Evgeniy Stepanov | d3b5660 | 2013-03-19 13:54:41 +0000 | [diff] [blame] | 219 | #if !SANITIZER_ANDROID |
Alexey Samsonov | 4f1885a | 2013-01-17 15:45:28 +0000 | [diff] [blame] | 220 | void ReadContextStack(void *context, uptr *stack, uptr *ssize) { |
Alexey Samsonov | aac36b3 | 2012-11-23 10:14:44 +0000 | [diff] [blame] | 221 | ucontext_t *ucp = (ucontext_t*)context; |
Alexey Samsonov | 4f1885a | 2013-01-17 15:45:28 +0000 | [diff] [blame] | 222 | *stack = (uptr)ucp->uc_stack.ss_sp; |
| 223 | *ssize = ucp->uc_stack.ss_size; |
Alexey Samsonov | aac36b3 | 2012-11-23 10:14:44 +0000 | [diff] [blame] | 224 | } |
| 225 | #else |
Alexey Samsonov | 4f1885a | 2013-01-17 15:45:28 +0000 | [diff] [blame] | 226 | void ReadContextStack(void *context, uptr *stack, uptr *ssize) { |
Alexey Samsonov | 9585613 | 2013-01-18 09:20:06 +0000 | [diff] [blame] | 227 | UNIMPLEMENTED(); |
Alexey Samsonov | aac36b3 | 2012-11-23 10:14:44 +0000 | [diff] [blame] | 228 | } |
| 229 | #endif |
| 230 | |
Kostya Serebryany | 019b76f | 2011-11-30 01:07:02 +0000 | [diff] [blame] | 231 | } // namespace __asan |
Kostya Serebryany | 5dfa4da | 2011-12-01 21:40:52 +0000 | [diff] [blame] | 232 | |
Alexey Samsonov | 5ec35b7 | 2014-03-06 09:05:52 +0000 | [diff] [blame] | 233 | #endif // SANITIZER_FREEBSD || SANITIZER_LINUX |