2012-10-29 Wei Mi <wmi@google.com>
[official-gcc.git] / libasan / sanitizer_common / sanitizer_linux.cc
blobab6c5a4b82c4fa1f785306e5d03516a9895e8188
1 //===-- sanitizer_linux.cc ------------------------------------------------===//
2 //
3 // This file is distributed under the University of Illinois Open Source
4 // License. See LICENSE.TXT for details.
5 //
6 //===----------------------------------------------------------------------===//
7 //
8 // This file is shared between AddressSanitizer and ThreadSanitizer
9 // run-time libraries and implements linux-specific functions from
10 // sanitizer_libc.h.
11 //===----------------------------------------------------------------------===//
12 #ifdef __linux__
14 #include "sanitizer_common.h"
15 #include "sanitizer_internal_defs.h"
16 #include "sanitizer_libc.h"
17 #include "sanitizer_placement_new.h"
18 #include "sanitizer_procmaps.h"
20 #include <fcntl.h>
21 #include <pthread.h>
22 #include <sched.h>
23 #include <sys/mman.h>
24 #include <sys/resource.h>
25 #include <sys/stat.h>
26 #include <sys/syscall.h>
27 #include <sys/time.h>
28 #include <sys/types.h>
29 #include <unistd.h>
30 #include <errno.h>
32 namespace __sanitizer {
34 // --------------- sanitizer_libc.h
35 void *internal_mmap(void *addr, uptr length, int prot, int flags,
36 int fd, u64 offset) {
37 #if __WORDSIZE == 64
38 return (void *)syscall(__NR_mmap, addr, length, prot, flags, fd, offset);
39 #else
40 return (void *)syscall(__NR_mmap2, addr, length, prot, flags, fd, offset);
41 #endif
44 int internal_munmap(void *addr, uptr length) {
45 return syscall(__NR_munmap, addr, length);
48 int internal_close(fd_t fd) {
49 return syscall(__NR_close, fd);
52 fd_t internal_open(const char *filename, bool write) {
53 return syscall(__NR_open, filename,
54 write ? O_WRONLY | O_CREAT /*| O_CLOEXEC*/ : O_RDONLY, 0660);
57 uptr internal_read(fd_t fd, void *buf, uptr count) {
58 sptr res;
59 HANDLE_EINTR(res, (sptr)syscall(__NR_read, fd, buf, count));
60 return res;
63 uptr internal_write(fd_t fd, const void *buf, uptr count) {
64 sptr res;
65 HANDLE_EINTR(res, (sptr)syscall(__NR_write, fd, buf, count));
66 return res;
69 uptr internal_filesize(fd_t fd) {
70 #if __WORDSIZE == 64
71 struct stat st;
72 if (syscall(__NR_fstat, fd, &st))
73 return -1;
74 #else
75 struct stat64 st;
76 if (syscall(__NR_fstat64, fd, &st))
77 return -1;
78 #endif
79 return (uptr)st.st_size;
82 int internal_dup2(int oldfd, int newfd) {
83 return syscall(__NR_dup2, oldfd, newfd);
86 uptr internal_readlink(const char *path, char *buf, uptr bufsize) {
87 return (uptr)syscall(__NR_readlink, path, buf, bufsize);
90 int internal_sched_yield() {
91 return syscall(__NR_sched_yield);
94 // ----------------- sanitizer_common.h
95 uptr GetTid() {
96 return syscall(__NR_gettid);
99 void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
100 uptr *stack_bottom) {
101 static const uptr kMaxThreadStackSize = 256 * (1 << 20); // 256M
102 CHECK(stack_top);
103 CHECK(stack_bottom);
104 if (at_initialization) {
105 // This is the main thread. Libpthread may not be initialized yet.
106 struct rlimit rl;
107 CHECK_EQ(getrlimit(RLIMIT_STACK, &rl), 0);
109 // Find the mapping that contains a stack variable.
110 MemoryMappingLayout proc_maps;
111 uptr start, end, offset;
112 uptr prev_end = 0;
113 while (proc_maps.Next(&start, &end, &offset, 0, 0)) {
114 if ((uptr)&rl < end)
115 break;
116 prev_end = end;
118 CHECK((uptr)&rl >= start && (uptr)&rl < end);
120 // Get stacksize from rlimit, but clip it so that it does not overlap
121 // with other mappings.
122 uptr stacksize = rl.rlim_cur;
123 if (stacksize > end - prev_end)
124 stacksize = end - prev_end;
125 // When running with unlimited stack size, we still want to set some limit.
126 // The unlimited stack size is caused by 'ulimit -s unlimited'.
127 // Also, for some reason, GNU make spawns subprocesses with unlimited stack.
128 if (stacksize > kMaxThreadStackSize)
129 stacksize = kMaxThreadStackSize;
130 *stack_top = end;
131 *stack_bottom = end - stacksize;
132 return;
134 pthread_attr_t attr;
135 CHECK_EQ(pthread_getattr_np(pthread_self(), &attr), 0);
136 uptr stacksize = 0;
137 void *stackaddr = 0;
138 pthread_attr_getstack(&attr, &stackaddr, (size_t*)&stacksize);
139 pthread_attr_destroy(&attr);
141 *stack_top = (uptr)stackaddr + stacksize;
142 *stack_bottom = (uptr)stackaddr;
143 CHECK(stacksize < kMaxThreadStackSize); // Sanity check.
146 // Like getenv, but reads env directly from /proc and does not use libc.
147 // This function should be called first inside __asan_init.
148 const char *GetEnv(const char *name) {
149 static char *environ;
150 static uptr len;
151 static bool inited;
152 if (!inited) {
153 inited = true;
154 uptr environ_size;
155 len = ReadFileToBuffer("/proc/self/environ",
156 &environ, &environ_size, 1 << 26);
158 if (!environ || len == 0) return 0;
159 uptr namelen = internal_strlen(name);
160 const char *p = environ;
161 while (*p != '\0') { // will happen at the \0\0 that terminates the buffer
162 // proc file has the format NAME=value\0NAME=value\0NAME=value\0...
163 const char* endp =
164 (char*)internal_memchr(p, '\0', len - (p - environ));
165 if (endp == 0) // this entry isn't NUL terminated
166 return 0;
167 else if (!internal_memcmp(p, name, namelen) && p[namelen] == '=') // Match.
168 return p + namelen + 1; // point after =
169 p = endp + 1;
171 return 0; // Not found.
174 void ReExec() {
175 static const int kMaxArgv = 100;
176 InternalScopedBuffer<char*> argv(kMaxArgv + 1);
177 static char *buff;
178 uptr buff_size = 0;
179 ReadFileToBuffer("/proc/self/cmdline", &buff, &buff_size, 1024 * 1024);
180 argv[0] = buff;
181 int argc, i;
182 for (argc = 1, i = 1; ; i++) {
183 if (buff[i] == 0) {
184 if (buff[i+1] == 0) break;
185 argv[argc] = &buff[i+1];
186 CHECK_LE(argc, kMaxArgv); // FIXME: make this more flexible.
187 argc++;
190 argv[argc] = 0;
191 execv(argv[0], argv.data());
194 // ----------------- sanitizer_procmaps.h
195 MemoryMappingLayout::MemoryMappingLayout() {
196 proc_self_maps_buff_len_ =
197 ReadFileToBuffer("/proc/self/maps", &proc_self_maps_buff_,
198 &proc_self_maps_buff_mmaped_size_, 1 << 26);
199 CHECK_GT(proc_self_maps_buff_len_, 0);
200 // internal_write(2, proc_self_maps_buff_, proc_self_maps_buff_len_);
201 Reset();
204 MemoryMappingLayout::~MemoryMappingLayout() {
205 UnmapOrDie(proc_self_maps_buff_, proc_self_maps_buff_mmaped_size_);
208 void MemoryMappingLayout::Reset() {
209 current_ = proc_self_maps_buff_;
212 // Parse a hex value in str and update str.
213 static uptr ParseHex(char **str) {
214 uptr x = 0;
215 char *s;
216 for (s = *str; ; s++) {
217 char c = *s;
218 uptr v = 0;
219 if (c >= '0' && c <= '9')
220 v = c - '0';
221 else if (c >= 'a' && c <= 'f')
222 v = c - 'a' + 10;
223 else if (c >= 'A' && c <= 'F')
224 v = c - 'A' + 10;
225 else
226 break;
227 x = x * 16 + v;
229 *str = s;
230 return x;
233 static bool IsOnOf(char c, char c1, char c2) {
234 return c == c1 || c == c2;
237 static bool IsDecimal(char c) {
238 return c >= '0' && c <= '9';
241 bool MemoryMappingLayout::Next(uptr *start, uptr *end, uptr *offset,
242 char filename[], uptr filename_size) {
243 char *last = proc_self_maps_buff_ + proc_self_maps_buff_len_;
244 if (current_ >= last) return false;
245 uptr dummy;
246 if (!start) start = &dummy;
247 if (!end) end = &dummy;
248 if (!offset) offset = &dummy;
249 char *next_line = (char*)internal_memchr(current_, '\n', last - current_);
250 if (next_line == 0)
251 next_line = last;
252 // Example: 08048000-08056000 r-xp 00000000 03:0c 64593 /foo/bar
253 *start = ParseHex(&current_);
254 CHECK_EQ(*current_++, '-');
255 *end = ParseHex(&current_);
256 CHECK_EQ(*current_++, ' ');
257 CHECK(IsOnOf(*current_++, '-', 'r'));
258 CHECK(IsOnOf(*current_++, '-', 'w'));
259 CHECK(IsOnOf(*current_++, '-', 'x'));
260 CHECK(IsOnOf(*current_++, 's', 'p'));
261 CHECK_EQ(*current_++, ' ');
262 *offset = ParseHex(&current_);
263 CHECK_EQ(*current_++, ' ');
264 ParseHex(&current_);
265 CHECK_EQ(*current_++, ':');
266 ParseHex(&current_);
267 CHECK_EQ(*current_++, ' ');
268 while (IsDecimal(*current_))
269 current_++;
270 CHECK_EQ(*current_++, ' ');
271 // Skip spaces.
272 while (current_ < next_line && *current_ == ' ')
273 current_++;
274 // Fill in the filename.
275 uptr i = 0;
276 while (current_ < next_line) {
277 if (filename && i < filename_size - 1)
278 filename[i++] = *current_;
279 current_++;
281 if (filename && i < filename_size)
282 filename[i] = 0;
283 current_ = next_line + 1;
284 return true;
287 // Gets the object name and the offset by walking MemoryMappingLayout.
288 bool MemoryMappingLayout::GetObjectNameAndOffset(uptr addr, uptr *offset,
289 char filename[],
290 uptr filename_size) {
291 return IterateForObjectNameAndOffset(addr, offset, filename, filename_size);
294 } // namespace __sanitizer
296 #endif // __linux__