asan_linux.cc revision 6895adc39c4e09371154c8037366ad4464163ed0
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//===----------------------------------------------------------------------===//
14#ifdef __linux__
15
16#include "asan_interceptors.h"
17#include "asan_internal.h"
18#include "asan_lock.h"
19#include "asan_procmaps.h"
20#include "asan_thread.h"
21#include "sanitizer_common/sanitizer_libc.h"
22#include "sanitizer_common/sanitizer_procmaps.h"
23
24#include <sys/time.h>
25#include <sys/resource.h>
26#include <sys/mman.h>
27#include <sys/syscall.h>
28#include <sys/types.h>
29#include <fcntl.h>
30#include <pthread.h>
31#include <stdio.h>
32#include <unistd.h>
33#include <unwind.h>
34
35#ifndef ANDROID
36// FIXME: where to get ucontext on Android?
37#include <sys/ucontext.h>
38#endif
39
40extern "C" void* _DYNAMIC;
41
42namespace __asan {
43
44const uptr kMaxThreadStackSize = 256 * (1 << 20);  // 256M
45
46void *AsanDoesNotSupportStaticLinkage() {
47  // This will fail to link with -static.
48  return &_DYNAMIC;  // defined in link.h
49}
50
51void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) {
52#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
74bool AsanInterceptsSignal(int signum) {
75  return signum == SIGSEGV && FLAG_handle_segv;
76}
77
78void *AsanMmapFixedNoReserve(uptr fixed_addr, uptr size) {
79  return internal_mmap((void*)fixed_addr, size,
80                      PROT_READ | PROT_WRITE,
81                      MAP_PRIVATE | MAP_ANON | MAP_FIXED | MAP_NORESERVE,
82                      0, 0);
83}
84
85void *AsanMprotect(uptr fixed_addr, uptr size) {
86  return internal_mmap((void*)fixed_addr, size,
87                       PROT_NONE,
88                       MAP_PRIVATE | MAP_ANON | MAP_FIXED | MAP_NORESERVE,
89                       0, 0);
90}
91
92// 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;
96  static uptr len;
97  static bool inited;
98  if (!inited) {
99    inited = true;
100    uptr environ_size;
101    len = ReadFileToBuffer("/proc/self/environ",
102                           &environ, &environ_size, 1 << 26);
103  }
104  if (!environ || len == 0) return 0;
105  uptr namelen = internal_strlen(name);
106  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));
111    if (endp == 0)  // this entry isn't NUL terminated
112      return 0;
113    else if (!internal_memcmp(p, name, namelen) && p[namelen] == '=')  // Match.
114      return p + namelen + 1;  // point after =
115    p = endp + 1;
116  }
117  return 0;  // Not found.
118}
119
120void 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.
127    ProcessMaps proc_maps;
128    uptr start, end, offset;
129    uptr prev_end = 0;
130    while (proc_maps.Next(&start, &end, &offset, 0, 0)) {
131      if ((uptr)&rl < end)
132        break;
133      prev_end = end;
134    }
135    CHECK((uptr)&rl >= start && (uptr)&rl < end);
136
137    // Get stacksize from rlimit, but clip it so that it does not overlap
138    // with other mappings.
139    uptr stacksize = rl.rlim_cur;
140    if (stacksize > end - prev_end)
141      stacksize = end - prev_end;
142    // When running with unlimited stack size, we still want to set some limit.
143    // The unlimited stack size is caused by 'ulimit -s unlimited'.
144    // Also, for some reason, GNU make spawns subprocesses with unlimited stack.
145    if (stacksize > kMaxThreadStackSize)
146      stacksize = kMaxThreadStackSize;
147    stack_top_ = end;
148    stack_bottom_ = end - stacksize;
149    CHECK(AddrIsInStack((uptr)&rl));
150    return;
151  }
152  pthread_attr_t attr;
153  CHECK(pthread_getattr_np(pthread_self(), &attr) == 0);
154  uptr stacksize = 0;
155  void *stackaddr = 0;
156  pthread_attr_getstack(&attr, &stackaddr, (size_t*)&stacksize);
157  pthread_attr_destroy(&attr);
158
159  stack_top_ = (uptr)stackaddr + stacksize;
160  stack_bottom_ = (uptr)stackaddr;
161  CHECK(stacksize < kMaxThreadStackSize);  // Sanity check.
162  CHECK(AddrIsInStack((uptr)&attr));
163}
164
165AsanLock::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_);
176  owner_ = (uptr)pthread_self();
177}
178
179void AsanLock::Unlock() {
180  CHECK(owner_ == (uptr)pthread_self());
181  owner_ = 0;
182  pthread_mutex_unlock((pthread_mutex_t*)&opaque_storage_);
183}
184
185#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
193uptr Unwind_GetIP(struct _Unwind_Context *ctx) {
194#ifdef __arm__
195  uptr val;
196  _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.
200  return val & ~(uptr)1;
201#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);
210  uptr pc = Unwind_GetIP(ctx);
211  b->trace[b->size++] = pc;
212  if (b->size == b->max_size) return UNWIND_STOP;
213  return UNWIND_CONTINUE;
214}
215
216void AsanStackTrace::GetStackTrace(uptr max_s, uptr pc, uptr bp) {
217  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
229}  // namespace __asan
230
231#endif  // __linux__
232