blob: 947c17f708f56927be2152216f479fa7a04c071b [file] [log] [blame]
Kostya Serebryany1e172b42011-11-30 01:07:02 +00001//===-- 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//===----------------------------------------------------------------------===//
Kostya Serebryanyd6567c52011-12-01 21:40:52 +000014#ifdef __linux__
Kostya Serebryany1e172b42011-11-30 01:07:02 +000015
Kostya Serebryanydf499b42012-01-05 00:44:33 +000016#include "asan_interceptors.h"
Kostya Serebryany1e172b42011-11-30 01:07:02 +000017#include "asan_internal.h"
Kostya Serebryanyd55f5f82012-01-10 21:24:40 +000018#include "asan_lock.h"
Kostya Serebryanydf499b42012-01-05 00:44:33 +000019#include "asan_procmaps.h"
Kostya Serebryanyc549dd72012-01-05 01:07:27 +000020#include "asan_thread.h"
Alexey Samsonovae4d9ca2012-06-04 14:27:50 +000021#include "sanitizer_common/sanitizer_libc.h"
Alexey Samsonov6895adc2012-06-07 06:15:12 +000022#include "sanitizer_common/sanitizer_procmaps.h"
Kostya Serebryany1e172b42011-11-30 01:07:02 +000023
Kostya Serebryanyc549dd72012-01-05 01:07:27 +000024#include <sys/time.h>
25#include <sys/resource.h>
Kostya Serebryany1e172b42011-11-30 01:07:02 +000026#include <sys/mman.h>
27#include <sys/syscall.h>
Kostya Serebryanyde496f42011-12-28 22:58:01 +000028#include <sys/types.h>
29#include <fcntl.h>
Kostya Serebryanyc549dd72012-01-05 01:07:27 +000030#include <pthread.h>
Kostya Serebryanydf499b42012-01-05 00:44:33 +000031#include <stdio.h>
Kostya Serebryany1e172b42011-11-30 01:07:02 +000032#include <unistd.h>
Evgeniy Stepanov9cfa1942012-01-19 11:34:18 +000033#include <unwind.h>
Kostya Serebryany1e172b42011-11-30 01:07:02 +000034
Kostya Serebryany9107c262012-01-06 19:11:09 +000035#ifndef ANDROID
36// FIXME: where to get ucontext on Android?
37#include <sys/ucontext.h>
38#endif
39
Evgeniy Stepanovaa33a502012-03-26 09:48:41 +000040extern "C" void* _DYNAMIC;
41
Kostya Serebryany1e172b42011-11-30 01:07:02 +000042namespace __asan {
43
Kostya Serebryany3f4c3872012-05-31 14:35:53 +000044const uptr kMaxThreadStackSize = 256 * (1 << 20); // 256M
Kostya Serebryany6f350e02012-05-22 11:54:44 +000045
Kostya Serebryany1e172b42011-11-30 01:07:02 +000046void *AsanDoesNotSupportStaticLinkage() {
47 // This will fail to link with -static.
Kostya Serebryanyefb3fa32012-01-05 23:50:34 +000048 return &_DYNAMIC; // defined in link.h
Kostya Serebryany1e172b42011-11-30 01:07:02 +000049}
50
Kostya Serebryany3f4c3872012-05-31 14:35:53 +000051void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) {
Kostya Serebryany9107c262012-01-06 19:11:09 +000052#ifdef ANDROID
53 *pc = *sp = *bp = 0;
54#elif defined(__arm__)
55 ucontext_t *ucontext = (ucontext_t*)context;
56 *pc = ucontext->uc_mcontext.arm_pc;
57 *bp = ucontext->uc_mcontext.arm_fp;
58 *sp = ucontext->uc_mcontext.arm_sp;
59# elif defined(__x86_64__)
60 ucontext_t *ucontext = (ucontext_t*)context;
61 *pc = ucontext->uc_mcontext.gregs[REG_RIP];
62 *bp = ucontext->uc_mcontext.gregs[REG_RBP];
63 *sp = ucontext->uc_mcontext.gregs[REG_RSP];
64# elif defined(__i386__)
65 ucontext_t *ucontext = (ucontext_t*)context;
66 *pc = ucontext->uc_mcontext.gregs[REG_EIP];
67 *bp = ucontext->uc_mcontext.gregs[REG_EBP];
68 *sp = ucontext->uc_mcontext.gregs[REG_ESP];
69#else
70# error "Unsupported arch"
71#endif
72}
73
Kostya Serebryany4803ab92012-01-09 18:53:15 +000074bool AsanInterceptsSignal(int signum) {
75 return signum == SIGSEGV && FLAG_handle_segv;
76}
77
Kostya Serebryany3f4c3872012-05-31 14:35:53 +000078void *AsanMmapFixedNoReserve(uptr fixed_addr, uptr size) {
Alexey Samsonovae4d9ca2012-06-04 14:27:50 +000079 return internal_mmap((void*)fixed_addr, size,
80 PROT_READ | PROT_WRITE,
81 MAP_PRIVATE | MAP_ANON | MAP_FIXED | MAP_NORESERVE,
82 0, 0);
Kostya Serebryanya874fe52011-12-28 23:28:54 +000083}
84
Kostya Serebryany3f4c3872012-05-31 14:35:53 +000085void *AsanMprotect(uptr fixed_addr, uptr size) {
Alexey Samsonovae4d9ca2012-06-04 14:27:50 +000086 return internal_mmap((void*)fixed_addr, size,
87 PROT_NONE,
88 MAP_PRIVATE | MAP_ANON | MAP_FIXED | MAP_NORESERVE,
89 0, 0);
Kostya Serebryanya874fe52011-12-28 23:28:54 +000090}
91
Alexander Potapenko1e316d72012-01-13 12:59:48 +000092// Like getenv, but reads env directly from /proc and does not use libc.
93// This function should be called first inside __asan_init.
94const char* AsanGetEnv(const char* name) {
95 static char *environ;
Kostya Serebryany3f4c3872012-05-31 14:35:53 +000096 static uptr len;
Alexander Potapenko1e316d72012-01-13 12:59:48 +000097 static bool inited;
98 if (!inited) {
99 inited = true;
Kostya Serebryany3f4c3872012-05-31 14:35:53 +0000100 uptr environ_size;
Alexander Potapenko1e316d72012-01-13 12:59:48 +0000101 len = ReadFileToBuffer("/proc/self/environ",
Kostya Serebryany160cc4a2012-02-07 00:47:35 +0000102 &environ, &environ_size, 1 << 26);
Alexander Potapenko1e316d72012-01-13 12:59:48 +0000103 }
Kostya Serebryany3f4c3872012-05-31 14:35:53 +0000104 if (!environ || len == 0) return 0;
105 uptr namelen = internal_strlen(name);
Alexander Potapenko1e316d72012-01-13 12:59:48 +0000106 const char *p = environ;
107 while (*p != '\0') { // will happen at the \0\0 that terminates the buffer
108 // proc file has the format NAME=value\0NAME=value\0NAME=value\0...
109 const char* endp =
110 (char*)internal_memchr(p, '\0', len - (p - environ));
Kostya Serebryany3f4c3872012-05-31 14:35:53 +0000111 if (endp == 0) // this entry isn't NUL terminated
112 return 0;
Alexander Potapenko1e316d72012-01-13 12:59:48 +0000113 else if (!internal_memcmp(p, name, namelen) && p[namelen] == '=') // Match.
114 return p + namelen + 1; // point after =
115 p = endp + 1;
116 }
Kostya Serebryany3f4c3872012-05-31 14:35:53 +0000117 return 0; // Not found.
Alexander Potapenko1e316d72012-01-13 12:59:48 +0000118}
119
Kostya Serebryanyc549dd72012-01-05 01:07:27 +0000120void AsanThread::SetThreadStackTopAndBottom() {
121 if (tid() == 0) {
122 // This is the main thread. Libpthread may not be initialized yet.
123 struct rlimit rl;
124 CHECK(getrlimit(RLIMIT_STACK, &rl) == 0);
125
126 // Find the mapping that contains a stack variable.
Alexey Samsonov6895adc2012-06-07 06:15:12 +0000127 ProcessMaps proc_maps;
Kostya Serebryany3f4c3872012-05-31 14:35:53 +0000128 uptr start, end, offset;
129 uptr prev_end = 0;
130 while (proc_maps.Next(&start, &end, &offset, 0, 0)) {
131 if ((uptr)&rl < end)
Kostya Serebryanyc549dd72012-01-05 01:07:27 +0000132 break;
133 prev_end = end;
134 }
Kostya Serebryany3f4c3872012-05-31 14:35:53 +0000135 CHECK((uptr)&rl >= start && (uptr)&rl < end);
Kostya Serebryanyc549dd72012-01-05 01:07:27 +0000136
137 // Get stacksize from rlimit, but clip it so that it does not overlap
138 // with other mappings.
Kostya Serebryany3f4c3872012-05-31 14:35:53 +0000139 uptr stacksize = rl.rlim_cur;
Kostya Serebryanyc549dd72012-01-05 01:07:27 +0000140 if (stacksize > end - prev_end)
141 stacksize = end - prev_end;
Kostya Serebryany6f350e02012-05-22 11:54:44 +0000142 // When running with unlimited stack size, we still want to set some limit.
143 // The unlimited stack size is caused by 'ulimit -s unlimited'.
Dmitry Vyukoved234182012-05-23 06:14:21 +0000144 // Also, for some reason, GNU make spawns subprocesses with unlimited stack.
Kostya Serebryanyc549dd72012-01-05 01:07:27 +0000145 if (stacksize > kMaxThreadStackSize)
146 stacksize = kMaxThreadStackSize;
147 stack_top_ = end;
148 stack_bottom_ = end - stacksize;
Kostya Serebryany3f4c3872012-05-31 14:35:53 +0000149 CHECK(AddrIsInStack((uptr)&rl));
Kostya Serebryanyc549dd72012-01-05 01:07:27 +0000150 return;
151 }
152 pthread_attr_t attr;
153 CHECK(pthread_getattr_np(pthread_self(), &attr) == 0);
Kostya Serebryany3f4c3872012-05-31 14:35:53 +0000154 uptr stacksize = 0;
155 void *stackaddr = 0;
156 pthread_attr_getstack(&attr, &stackaddr, (size_t*)&stacksize);
Kostya Serebryanyc549dd72012-01-05 01:07:27 +0000157 pthread_attr_destroy(&attr);
158
Kostya Serebryany3f4c3872012-05-31 14:35:53 +0000159 stack_top_ = (uptr)stackaddr + stacksize;
160 stack_bottom_ = (uptr)stackaddr;
Kostya Serebryany6f350e02012-05-22 11:54:44 +0000161 CHECK(stacksize < kMaxThreadStackSize); // Sanity check.
Kostya Serebryany3f4c3872012-05-31 14:35:53 +0000162 CHECK(AddrIsInStack((uptr)&attr));
Kostya Serebryanyc549dd72012-01-05 01:07:27 +0000163}
164
Kostya Serebryanyd55f5f82012-01-10 21:24:40 +0000165AsanLock::AsanLock(LinkerInitialized) {
166 // We assume that pthread_mutex_t initialized to all zeroes is a valid
167 // unlocked mutex. We can not use PTHREAD_MUTEX_INITIALIZER as it triggers
168 // a gcc warning:
169 // extended initializer lists only available with -std=c++0x or -std=gnu++0x
170}
171
172void AsanLock::Lock() {
173 CHECK(sizeof(pthread_mutex_t) <= sizeof(opaque_storage_));
174 pthread_mutex_lock((pthread_mutex_t*)&opaque_storage_);
175 CHECK(!owner_);
Kostya Serebryany3f4c3872012-05-31 14:35:53 +0000176 owner_ = (uptr)pthread_self();
Kostya Serebryanyd55f5f82012-01-10 21:24:40 +0000177}
178
179void AsanLock::Unlock() {
Kostya Serebryany3f4c3872012-05-31 14:35:53 +0000180 CHECK(owner_ == (uptr)pthread_self());
Kostya Serebryanyd55f5f82012-01-10 21:24:40 +0000181 owner_ = 0;
182 pthread_mutex_unlock((pthread_mutex_t*)&opaque_storage_);
183}
184
Evgeniy Stepanov9cfa1942012-01-19 11:34:18 +0000185#ifdef __arm__
186#define UNWIND_STOP _URC_END_OF_STACK
187#define UNWIND_CONTINUE _URC_NO_REASON
188#else
189#define UNWIND_STOP _URC_NORMAL_STOP
190#define UNWIND_CONTINUE _URC_NO_REASON
191#endif
192
Kostya Serebryany3f4c3872012-05-31 14:35:53 +0000193uptr Unwind_GetIP(struct _Unwind_Context *ctx) {
Evgeniy Stepanov9cfa1942012-01-19 11:34:18 +0000194#ifdef __arm__
Kostya Serebryany3f4c3872012-05-31 14:35:53 +0000195 uptr val;
Evgeniy Stepanov9cfa1942012-01-19 11:34:18 +0000196 _Unwind_VRS_Result res = _Unwind_VRS_Get(ctx, _UVRSC_CORE,
197 15 /* r15 = PC */, _UVRSD_UINT32, &val);
198 CHECK(res == _UVRSR_OK && "_Unwind_VRS_Get failed");
199 // Clear the Thumb bit.
Kostya Serebryany3f4c3872012-05-31 14:35:53 +0000200 return val & ~(uptr)1;
Evgeniy Stepanov9cfa1942012-01-19 11:34:18 +0000201#else
202 return _Unwind_GetIP(ctx);
203#endif
204}
205
206_Unwind_Reason_Code Unwind_Trace(struct _Unwind_Context *ctx,
207 void *param) {
208 AsanStackTrace *b = (AsanStackTrace*)param;
209 CHECK(b->size < b->max_size);
Kostya Serebryany3f4c3872012-05-31 14:35:53 +0000210 uptr pc = Unwind_GetIP(ctx);
Evgeniy Stepanov9cfa1942012-01-19 11:34:18 +0000211 b->trace[b->size++] = pc;
212 if (b->size == b->max_size) return UNWIND_STOP;
213 return UNWIND_CONTINUE;
214}
215
Kostya Serebryany3f4c3872012-05-31 14:35:53 +0000216void AsanStackTrace::GetStackTrace(uptr max_s, uptr pc, uptr bp) {
Evgeniy Stepanov9cfa1942012-01-19 11:34:18 +0000217 size = 0;
218 trace[0] = pc;
219 if ((max_s) > 1) {
220 max_size = max_s;
221#ifdef __arm__
222 _Unwind_Backtrace(Unwind_Trace, this);
223#else
224 FastUnwindStack(pc, bp);
225#endif
226 }
227}
228
Kostya Serebryany1e172b42011-11-30 01:07:02 +0000229} // namespace __asan
Kostya Serebryanyd6567c52011-12-01 21:40:52 +0000230
231#endif // __linux__