blob: 3150f8df91b841ce2fe8d52748e1c3c926867201 [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 Serebryanydf499b42012-01-05 00:44:33 +000018#include "asan_procmaps.h"
Kostya Serebryanyc549dd72012-01-05 01:07:27 +000019#include "asan_thread.h"
Kostya Serebryany1e172b42011-11-30 01:07:02 +000020
Kostya Serebryanyc549dd72012-01-05 01:07:27 +000021#include <sys/time.h>
22#include <sys/resource.h>
Kostya Serebryany1e172b42011-11-30 01:07:02 +000023#include <sys/mman.h>
24#include <sys/syscall.h>
Kostya Serebryanyde496f42011-12-28 22:58:01 +000025#include <sys/types.h>
26#include <fcntl.h>
Kostya Serebryanyc549dd72012-01-05 01:07:27 +000027#include <pthread.h>
Kostya Serebryanydf499b42012-01-05 00:44:33 +000028#include <stdio.h>
Kostya Serebryany1e172b42011-11-30 01:07:02 +000029#include <unistd.h>
30
31extern char _DYNAMIC[];
32
33namespace __asan {
34
35void *AsanDoesNotSupportStaticLinkage() {
36 // This will fail to link with -static.
37 return &_DYNAMIC;
38}
39
Kostya Serebryanya874fe52011-12-28 23:28:54 +000040static void *asan_mmap(void *addr, size_t length, int prot, int flags,
Kostya Serebryany1e172b42011-11-30 01:07:02 +000041 int fd, uint64_t offset) {
42# if __WORDSIZE == 64
Kostya Serebryanyde496f42011-12-28 22:58:01 +000043 return (void *)syscall(__NR_mmap, addr, length, prot, flags, fd, offset);
Kostya Serebryany1e172b42011-11-30 01:07:02 +000044# else
Kostya Serebryanyde496f42011-12-28 22:58:01 +000045 return (void *)syscall(__NR_mmap2, addr, length, prot, flags, fd, offset);
Kostya Serebryany1e172b42011-11-30 01:07:02 +000046# endif
47}
48
Kostya Serebryanyde496f42011-12-28 22:58:01 +000049void *AsanMmapSomewhereOrDie(size_t size, const char *mem_type) {
50 size = RoundUpTo(size, kPageSize);
51 void *res = asan_mmap(0, size,
52 PROT_READ | PROT_WRITE,
53 MAP_PRIVATE | MAP_ANON, -1, 0);
54 if (res == (void*)-1) {
55 OutOfMemoryMessageAndDie(mem_type, size);
56 }
57 return res;
58}
59
Kostya Serebryanya874fe52011-12-28 23:28:54 +000060void *AsanMmapFixedNoReserve(uintptr_t fixed_addr, size_t size) {
61 return asan_mmap((void*)fixed_addr, size,
62 PROT_READ | PROT_WRITE,
63 MAP_PRIVATE | MAP_ANON | MAP_FIXED | MAP_NORESERVE,
64 0, 0);
65}
66
67void *AsanMmapFixedReserve(uintptr_t fixed_addr, size_t size) {
68 return asan_mmap((void*)fixed_addr, size,
69 PROT_READ | PROT_WRITE,
70 MAP_PRIVATE | MAP_ANON | MAP_FIXED,
71 0, 0);
72}
73
74void *AsanMprotect(uintptr_t fixed_addr, size_t size) {
75 return asan_mmap((void*)fixed_addr, size,
76 PROT_NONE,
77 MAP_PRIVATE | MAP_ANON | MAP_FIXED | MAP_NORESERVE,
78 0, 0);
79}
80
Kostya Serebryanyde496f42011-12-28 22:58:01 +000081void AsanUnmapOrDie(void *addr, size_t size) {
82 if (!addr || !size) return;
83 int res = syscall(__NR_munmap, addr, size);
84 if (res != 0) {
85 Report("Failed to unmap\n");
86 ASAN_DIE;
87 }
88}
89
90ssize_t AsanWrite(int fd, const void *buf, size_t count) {
91 return (ssize_t)syscall(__NR_write, fd, buf, count);
92}
93
94int AsanOpenReadonly(const char* filename) {
95 return open(filename, O_RDONLY);
96}
97
98ssize_t AsanRead(int fd, void *buf, size_t count) {
99 return (ssize_t)syscall(__NR_read, fd, buf, count);
100}
101
102int AsanClose(int fd) {
103 return close(fd);
Kostya Serebryany1e172b42011-11-30 01:07:02 +0000104}
105
Kostya Serebryanydf499b42012-01-05 00:44:33 +0000106AsanProcMaps::AsanProcMaps() {
107 proc_self_maps_buff_len_ =
108 ReadFileToBuffer("/proc/self/maps", &proc_self_maps_buff_,
109 &proc_self_maps_buff_mmaped_size_, 1 << 20);
110 CHECK(proc_self_maps_buff_len_ > 0);
111 // AsanWrite(2, proc_self_maps_buff_, proc_self_maps_buff_len_);
112 Reset();
113}
114
115AsanProcMaps::~AsanProcMaps() {
116 AsanUnmapOrDie(proc_self_maps_buff_, proc_self_maps_buff_mmaped_size_);
117}
118
119void AsanProcMaps::Reset() {
120 current_ = proc_self_maps_buff_;
121}
122
123bool AsanProcMaps::Next(uint64_t *start, uint64_t *end,
124 uint64_t *offset, char filename[],
125 size_t filename_size) {
126 char *last = proc_self_maps_buff_ + proc_self_maps_buff_len_;
127 if (current_ >= last) return false;
128 int consumed = 0;
129 char flags[10];
130 int major, minor;
131 uint64_t inode;
132 char *next_line = (char*)internal_memchr(current_, '\n', last - current_);
133 if (next_line == NULL)
134 next_line = last;
135 if (SScanf(current_,
136 "%llx-%llx %4s %llx %x:%x %lld %n",
137 start, end, flags, offset, &major, &minor,
138 &inode, &consumed) != 7)
139 return false;
140 current_ += consumed;
141 // Skip spaces.
142 while (current_ < next_line && *current_ == ' ')
143 current_++;
144 // Fill in the filename.
145 size_t i = 0;
146 while (current_ < next_line) {
147 if (filename && i < filename_size - 1)
148 filename[i++] = *current_;
149 current_++;
150 }
151 if (filename && i < filename_size)
152 filename[i] = 0;
153 current_ = next_line + 1;
154 return true;
155}
156
Kostya Serebryanyc549dd72012-01-05 01:07:27 +0000157void AsanThread::SetThreadStackTopAndBottom() {
158 if (tid() == 0) {
159 // This is the main thread. Libpthread may not be initialized yet.
160 struct rlimit rl;
161 CHECK(getrlimit(RLIMIT_STACK, &rl) == 0);
162
163 // Find the mapping that contains a stack variable.
164 AsanProcMaps proc_maps;
165 uint64_t start, end, offset;
166 uint64_t prev_end = 0;
167 while (proc_maps.Next(&start, &end, &offset, NULL, 0)) {
168 if ((uintptr_t)&rl < end)
169 break;
170 prev_end = end;
171 }
172 CHECK((uintptr_t)&rl >= start && (uintptr_t)&rl < end);
173
174 // Get stacksize from rlimit, but clip it so that it does not overlap
175 // with other mappings.
176 size_t stacksize = rl.rlim_cur;
177 if (stacksize > end - prev_end)
178 stacksize = end - prev_end;
179 if (stacksize > kMaxThreadStackSize)
180 stacksize = kMaxThreadStackSize;
181 stack_top_ = end;
182 stack_bottom_ = end - stacksize;
183 CHECK(AddrIsInStack((uintptr_t)&rl));
184 return;
185 }
186 pthread_attr_t attr;
187 CHECK(pthread_getattr_np(pthread_self(), &attr) == 0);
188 size_t stacksize = 0;
189 void *stackaddr = NULL;
190 pthread_attr_getstack(&attr, &stackaddr, &stacksize);
191 pthread_attr_destroy(&attr);
192
193 stack_top_ = (uintptr_t)stackaddr + stacksize;
194 stack_bottom_ = (uintptr_t)stackaddr;
195 // When running with unlimited stack size, we still want to set some limit.
196 // The unlimited stack size is caused by 'ulimit -s unlimited'.
197 // Also, for some reason, GNU make spawns subrocesses with unlimited stack.
198 if (stacksize > kMaxThreadStackSize) {
199 stack_bottom_ = stack_top_ - kMaxThreadStackSize;
200 }
201 CHECK(AddrIsInStack((uintptr_t)&attr));
202}
203
204
Kostya Serebryany1e172b42011-11-30 01:07:02 +0000205} // namespace __asan
Kostya Serebryanyd6567c52011-12-01 21:40:52 +0000206
207#endif // __linux__