blob: 24c8d234a8cfee73672b60fa911138389b64cad8 [file] [log] [blame]
Alexey Samsonov2c5fc3b2012-06-04 14:27:50 +00001//===-- sanitizer_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 shared between AddressSanitizer and ThreadSanitizer
11// run-time libraries and implements linux-specific functions from
12// sanitizer_libc.h.
13//===----------------------------------------------------------------------===//
14#ifdef __linux__
15
Alexey Samsonov28a98952012-06-07 06:15:12 +000016#include "sanitizer_common.h"
Alexey Samsonov5bbf8292012-06-05 14:25:27 +000017#include "sanitizer_internal_defs.h"
Alexey Samsonov2c5fc3b2012-06-04 14:27:50 +000018#include "sanitizer_libc.h"
Alexey Samsonov28a98952012-06-07 06:15:12 +000019#include "sanitizer_procmaps.h"
Alexey Samsonov2c5fc3b2012-06-04 14:27:50 +000020
Alexey Samsonovdde1f112012-06-05 07:05:10 +000021#include <fcntl.h>
Alexey Samsonov4b1f1032012-06-07 07:13:46 +000022#include <pthread.h>
Alexey Samsonov2c5fc3b2012-06-04 14:27:50 +000023#include <sys/mman.h>
Alexey Samsonov4b1f1032012-06-07 07:13:46 +000024#include <sys/resource.h>
Alexey Samsonovdde1f112012-06-05 07:05:10 +000025#include <sys/stat.h>
Alexey Samsonov2c5fc3b2012-06-04 14:27:50 +000026#include <sys/syscall.h>
Alexey Samsonov4b1f1032012-06-07 07:13:46 +000027#include <sys/time.h>
Alexey Samsonov2c5fc3b2012-06-04 14:27:50 +000028#include <sys/types.h>
29#include <unistd.h>
30
31namespace __sanitizer {
32
Alexey Samsonov4b1f1032012-06-07 07:13:46 +000033// --------------- sanitizer_libc.h
Alexey Samsonov2c5fc3b2012-06-04 14:27:50 +000034void *internal_mmap(void *addr, uptr length, int prot, int flags,
35 int fd, u64 offset) {
36#if __WORDSIZE == 64
37 return (void *)syscall(__NR_mmap, addr, length, prot, flags, fd, offset);
38#else
39 return (void *)syscall(__NR_mmap2, addr, length, prot, flags, fd, offset);
40#endif
41}
42
Alexey Samsonov7ac77d62012-06-05 09:49:25 +000043int internal_munmap(void *addr, uptr length) {
44 return syscall(__NR_munmap, addr, length);
45}
46
Alexey Samsonov03c8b842012-06-05 08:32:53 +000047int internal_close(fd_t fd) {
48 return syscall(__NR_close, fd);
49}
50
Alexey Samsonovdde1f112012-06-05 07:05:10 +000051fd_t internal_open(const char *filename, bool write) {
52 return syscall(__NR_open, filename,
Kostya Serebryany64166ca2012-06-06 14:11:31 +000053 write ? O_WRONLY | O_CREAT /*| O_CLOEXEC*/ : O_RDONLY, 0660);
Alexey Samsonovdde1f112012-06-05 07:05:10 +000054}
55
Alexey Samsonov03c8b842012-06-05 08:32:53 +000056uptr internal_read(fd_t fd, void *buf, uptr count) {
57 return (uptr)syscall(__NR_read, fd, buf, count);
58}
59
60uptr internal_write(fd_t fd, const void *buf, uptr count) {
61 return (uptr)syscall(__NR_write, fd, buf, count);
62}
63
Alexey Samsonovca2b5d72012-06-06 07:30:33 +000064uptr internal_filesize(fd_t fd) {
65 struct stat st = {};
66 if (syscall(__NR_fstat, fd, &st))
67 return -1;
68 return (uptr)st.st_size;
69}
70
71int internal_dup2(int oldfd, int newfd) {
72 return syscall(__NR_dup2, oldfd, newfd);
73}
74
Alexey Samsonov4b1f1032012-06-07 07:13:46 +000075// ----------------- sanitizer_common.h
Alexey Samsonovcf4d3a02012-06-07 07:32:00 +000076void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
Alexey Samsonov4b1f1032012-06-07 07:13:46 +000077 uptr *stack_bottom) {
78 static const uptr kMaxThreadStackSize = 256 * (1 << 20); // 256M
79 CHECK(stack_top);
80 CHECK(stack_bottom);
Alexey Samsonovcf4d3a02012-06-07 07:32:00 +000081 if (at_initialization) {
Alexey Samsonov4b1f1032012-06-07 07:13:46 +000082 // This is the main thread. Libpthread may not be initialized yet.
83 struct rlimit rl;
84 CHECK(getrlimit(RLIMIT_STACK, &rl) == 0);
85
86 // Find the mapping that contains a stack variable.
87 ProcessMaps proc_maps;
88 uptr start, end, offset;
89 uptr prev_end = 0;
90 while (proc_maps.Next(&start, &end, &offset, 0, 0)) {
91 if ((uptr)&rl < end)
92 break;
93 prev_end = end;
94 }
95 CHECK((uptr)&rl >= start && (uptr)&rl < end);
96
97 // Get stacksize from rlimit, but clip it so that it does not overlap
98 // with other mappings.
99 uptr stacksize = rl.rlim_cur;
100 if (stacksize > end - prev_end)
101 stacksize = end - prev_end;
102 // When running with unlimited stack size, we still want to set some limit.
103 // The unlimited stack size is caused by 'ulimit -s unlimited'.
104 // Also, for some reason, GNU make spawns subprocesses with unlimited stack.
105 if (stacksize > kMaxThreadStackSize)
106 stacksize = kMaxThreadStackSize;
107 *stack_top = end;
108 *stack_bottom = end - stacksize;
109 return;
110 }
111 pthread_attr_t attr;
112 CHECK(pthread_getattr_np(pthread_self(), &attr) == 0);
113 uptr stacksize = 0;
114 void *stackaddr = 0;
115 pthread_attr_getstack(&attr, &stackaddr, (size_t*)&stacksize);
116 pthread_attr_destroy(&attr);
117
118 *stack_top = (uptr)stackaddr + stacksize;
119 *stack_bottom = (uptr)stackaddr;
120 CHECK(stacksize < kMaxThreadStackSize); // Sanity check.
121}
122
123// ----------------- sanitizer_procmaps.h
Alexey Samsonov28a98952012-06-07 06:15:12 +0000124ProcessMaps::ProcessMaps() {
125 proc_self_maps_buff_len_ =
126 ReadFileToBuffer("/proc/self/maps", &proc_self_maps_buff_,
127 &proc_self_maps_buff_mmaped_size_, 1 << 26);
128 CHECK(proc_self_maps_buff_len_ > 0);
129 // internal_write(2, proc_self_maps_buff_, proc_self_maps_buff_len_);
130 Reset();
131}
132
133ProcessMaps::~ProcessMaps() {
134 UnmapOrDie(proc_self_maps_buff_, proc_self_maps_buff_mmaped_size_);
135}
136
137void ProcessMaps::Reset() {
138 current_ = proc_self_maps_buff_;
139}
140
141bool ProcessMaps::Next(uptr *start, uptr *end, uptr *offset,
142 char filename[], uptr filename_size) {
143 char *last = proc_self_maps_buff_ + proc_self_maps_buff_len_;
144 if (current_ >= last) return false;
145 int consumed = 0;
146 char flags[10];
147 int major, minor;
148 uptr inode;
149 uptr dummy;
150 if (!start) start = &dummy;
151 if (!end) end = &dummy;
152 if (!offset) offset = &dummy;
153 char *next_line = (char*)internal_memchr(current_, '\n', last - current_);
154 if (next_line == 0)
155 next_line = last;
156 if (internal_sscanf(current_, "%lx-%lx %4s %lx %x:%x %ld %n",
157 start, end, flags, offset, &major, &minor,
158 &inode, &consumed) != 7)
159 return false;
160 current_ += consumed;
161 // Skip spaces.
162 while (current_ < next_line && *current_ == ' ')
163 current_++;
164 // Fill in the filename.
165 uptr i = 0;
166 while (current_ < next_line) {
167 if (filename && i < filename_size - 1)
168 filename[i++] = *current_;
169 current_++;
170 }
171 if (filename && i < filename_size)
172 filename[i] = 0;
173 current_ = next_line + 1;
174 return true;
175}
176
177// Gets the object name and the offset by walking ProcessMaps.
178bool ProcessMaps::GetObjectNameAndOffset(uptr addr, uptr *offset,
179 char filename[],
180 uptr filename_size) {
181 return IterateForObjectNameAndOffset(addr, offset, filename, filename_size);
182}
183
Alexey Samsonov2c5fc3b2012-06-04 14:27:50 +0000184} // namespace __sanitizer
185
186#endif // __linux__