blob: f9b0c4e6bf76a5179435637d7e1153d4d3ee788f [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 Samsonov961276a2012-07-03 08:24:14 +000019#include "sanitizer_placement_new.h"
Alexey Samsonov28a98952012-06-07 06:15:12 +000020#include "sanitizer_procmaps.h"
Alexey Samsonov961276a2012-07-03 08:24:14 +000021#include "sanitizer_symbolizer.h"
Alexey Samsonov2c5fc3b2012-06-04 14:27:50 +000022
Alexey Samsonov961276a2012-07-03 08:24:14 +000023#include <elf.h>
Alexey Samsonovdde1f112012-06-05 07:05:10 +000024#include <fcntl.h>
Alexey Samsonov961276a2012-07-03 08:24:14 +000025#include <link.h>
Alexey Samsonov4b1f1032012-06-07 07:13:46 +000026#include <pthread.h>
Alexey Samsonov58a3c582012-06-18 08:44:30 +000027#include <sched.h>
Alexey Samsonov2c5fc3b2012-06-04 14:27:50 +000028#include <sys/mman.h>
Alexey Samsonov4b1f1032012-06-07 07:13:46 +000029#include <sys/resource.h>
Alexey Samsonovdde1f112012-06-05 07:05:10 +000030#include <sys/stat.h>
Alexey Samsonov2c5fc3b2012-06-04 14:27:50 +000031#include <sys/syscall.h>
Alexey Samsonov4b1f1032012-06-07 07:13:46 +000032#include <sys/time.h>
Alexey Samsonov2c5fc3b2012-06-04 14:27:50 +000033#include <sys/types.h>
34#include <unistd.h>
35
36namespace __sanitizer {
37
Alexey Samsonov4b1f1032012-06-07 07:13:46 +000038// --------------- sanitizer_libc.h
Alexey Samsonov2c5fc3b2012-06-04 14:27:50 +000039void *internal_mmap(void *addr, uptr length, int prot, int flags,
40 int fd, u64 offset) {
41#if __WORDSIZE == 64
42 return (void *)syscall(__NR_mmap, addr, length, prot, flags, fd, offset);
43#else
44 return (void *)syscall(__NR_mmap2, addr, length, prot, flags, fd, offset);
45#endif
46}
47
Alexey Samsonov7ac77d62012-06-05 09:49:25 +000048int internal_munmap(void *addr, uptr length) {
49 return syscall(__NR_munmap, addr, length);
50}
51
Alexey Samsonov03c8b842012-06-05 08:32:53 +000052int internal_close(fd_t fd) {
53 return syscall(__NR_close, fd);
54}
55
Alexey Samsonovdde1f112012-06-05 07:05:10 +000056fd_t internal_open(const char *filename, bool write) {
57 return syscall(__NR_open, filename,
Kostya Serebryany64166ca2012-06-06 14:11:31 +000058 write ? O_WRONLY | O_CREAT /*| O_CLOEXEC*/ : O_RDONLY, 0660);
Alexey Samsonovdde1f112012-06-05 07:05:10 +000059}
60
Alexey Samsonov03c8b842012-06-05 08:32:53 +000061uptr internal_read(fd_t fd, void *buf, uptr count) {
62 return (uptr)syscall(__NR_read, fd, buf, count);
63}
64
65uptr internal_write(fd_t fd, const void *buf, uptr count) {
66 return (uptr)syscall(__NR_write, fd, buf, count);
67}
68
Alexey Samsonovca2b5d72012-06-06 07:30:33 +000069uptr internal_filesize(fd_t fd) {
Alexey Samsonov961276a2012-07-03 08:24:14 +000070#if __WORDSIZE == 64
71 struct stat st;
Alexey Samsonovca2b5d72012-06-06 07:30:33 +000072 if (syscall(__NR_fstat, fd, &st))
73 return -1;
Alexey Samsonov961276a2012-07-03 08:24:14 +000074#else
75 struct stat64 st;
76 if (syscall(__NR_fstat64, fd, &st))
77 return -1;
78#endif
Alexey Samsonovca2b5d72012-06-06 07:30:33 +000079 return (uptr)st.st_size;
80}
81
82int internal_dup2(int oldfd, int newfd) {
83 return syscall(__NR_dup2, oldfd, newfd);
84}
85
Alexey Samsonov58a3c582012-06-18 08:44:30 +000086int internal_sched_yield() {
87 return syscall(__NR_sched_yield);
88}
89
Alexey Samsonov4b1f1032012-06-07 07:13:46 +000090// ----------------- sanitizer_common.h
Alexey Samsonovcf4d3a02012-06-07 07:32:00 +000091void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
Alexey Samsonov4b1f1032012-06-07 07:13:46 +000092 uptr *stack_bottom) {
93 static const uptr kMaxThreadStackSize = 256 * (1 << 20); // 256M
94 CHECK(stack_top);
95 CHECK(stack_bottom);
Alexey Samsonovcf4d3a02012-06-07 07:32:00 +000096 if (at_initialization) {
Alexey Samsonov4b1f1032012-06-07 07:13:46 +000097 // This is the main thread. Libpthread may not be initialized yet.
98 struct rlimit rl;
Kostya Serebryany98390d02012-06-20 15:19:17 +000099 CHECK_EQ(getrlimit(RLIMIT_STACK, &rl), 0);
Alexey Samsonov4b1f1032012-06-07 07:13:46 +0000100
101 // Find the mapping that contains a stack variable.
102 ProcessMaps proc_maps;
103 uptr start, end, offset;
104 uptr prev_end = 0;
105 while (proc_maps.Next(&start, &end, &offset, 0, 0)) {
106 if ((uptr)&rl < end)
107 break;
108 prev_end = end;
109 }
110 CHECK((uptr)&rl >= start && (uptr)&rl < end);
111
112 // Get stacksize from rlimit, but clip it so that it does not overlap
113 // with other mappings.
114 uptr stacksize = rl.rlim_cur;
115 if (stacksize > end - prev_end)
116 stacksize = end - prev_end;
117 // When running with unlimited stack size, we still want to set some limit.
118 // The unlimited stack size is caused by 'ulimit -s unlimited'.
119 // Also, for some reason, GNU make spawns subprocesses with unlimited stack.
120 if (stacksize > kMaxThreadStackSize)
121 stacksize = kMaxThreadStackSize;
122 *stack_top = end;
123 *stack_bottom = end - stacksize;
124 return;
125 }
126 pthread_attr_t attr;
Kostya Serebryany98390d02012-06-20 15:19:17 +0000127 CHECK_EQ(pthread_getattr_np(pthread_self(), &attr), 0);
Alexey Samsonov4b1f1032012-06-07 07:13:46 +0000128 uptr stacksize = 0;
129 void *stackaddr = 0;
130 pthread_attr_getstack(&attr, &stackaddr, (size_t*)&stacksize);
131 pthread_attr_destroy(&attr);
132
133 *stack_top = (uptr)stackaddr + stacksize;
134 *stack_bottom = (uptr)stackaddr;
135 CHECK(stacksize < kMaxThreadStackSize); // Sanity check.
136}
137
Alexey Samsonov0c53a382012-06-14 14:07:21 +0000138// Like getenv, but reads env directly from /proc and does not use libc.
139// This function should be called first inside __asan_init.
140const char *GetEnv(const char *name) {
141 static char *environ;
142 static uptr len;
143 static bool inited;
144 if (!inited) {
145 inited = true;
146 uptr environ_size;
147 len = ReadFileToBuffer("/proc/self/environ",
148 &environ, &environ_size, 1 << 26);
149 }
150 if (!environ || len == 0) return 0;
151 uptr namelen = internal_strlen(name);
152 const char *p = environ;
153 while (*p != '\0') { // will happen at the \0\0 that terminates the buffer
154 // proc file has the format NAME=value\0NAME=value\0NAME=value\0...
155 const char* endp =
156 (char*)internal_memchr(p, '\0', len - (p - environ));
157 if (endp == 0) // this entry isn't NUL terminated
158 return 0;
159 else if (!internal_memcmp(p, name, namelen) && p[namelen] == '=') // Match.
160 return p + namelen + 1; // point after =
161 p = endp + 1;
162 }
163 return 0; // Not found.
164}
165
Alexey Samsonov961276a2012-07-03 08:24:14 +0000166// ------------------ sanitizer_symbolizer.h
167typedef ElfW(Ehdr) Elf_Ehdr;
168typedef ElfW(Shdr) Elf_Shdr;
169
170bool FindDWARFSection(uptr object_file_addr, const char *section_name,
171 DWARFSection *section) {
172 Elf_Ehdr *exe = (Elf_Ehdr*)object_file_addr;
173 Elf_Shdr *sections = (Elf_Shdr*)(object_file_addr + exe->e_shoff);
174 uptr section_names = object_file_addr +
175 sections[exe->e_shstrndx].sh_offset;
176 for (int i = 0; i < exe->e_shnum; i++) {
177 Elf_Shdr *current_section = &sections[i];
178 const char *current_name = (const char*)section_names +
179 current_section->sh_name;
180 if (IsFullNameOfDWARFSection(current_name, section_name)) {
181 section->data = (const char*)object_file_addr +
182 current_section->sh_offset;
183 section->size = current_section->sh_size;
184 return true;
185 }
186 }
187 return false;
188}
189
190#ifdef ANDROID
191uptr GetListOfModules(ModuleDIContext *modules, uptr max_modules) {
192 UNIMPLEMENTED();
193}
194#else // ANDROID
195struct DlIteratePhdrData {
196 ModuleDIContext *modules;
197 uptr current_n;
198 uptr max_n;
199};
200
201static const uptr kMaxPathLength = 512;
202
203static int dl_iterate_phdr_cb(dl_phdr_info *info, size_t size, void *arg) {
204 DlIteratePhdrData *data = (DlIteratePhdrData*)arg;
205 if (data->current_n == data->max_n)
206 return 0;
207 char *module_name = 0;
208 if (data->current_n == 0) {
209 // First module is the binary itself.
210 module_name = (char*)InternalAlloc(kMaxPathLength);
211 uptr module_name_len = readlink("/proc/self/exe",
212 module_name, kMaxPathLength);
213 CHECK_NE(module_name_len, (uptr)-1);
214 CHECK_LT(module_name_len, kMaxPathLength);
215 module_name[module_name_len] = '\0';
216 } else if (info->dlpi_name) {
217 module_name = internal_strdup(info->dlpi_name);
218 }
219 if (module_name == 0 || module_name[0] == '\0')
220 return 0;
221 void *mem = &data->modules[data->current_n];
222 ModuleDIContext *cur_module = new(mem) ModuleDIContext(module_name);
223 data->current_n++;
224 for (int i = 0; i < info->dlpi_phnum; i++) {
225 uptr cur_beg = info->dlpi_addr + info->dlpi_phdr[i].p_vaddr;
226 uptr cur_end = cur_beg + info->dlpi_phdr[i].p_memsz;
227 cur_module->addAddressRange(cur_beg, cur_end);
228 }
229 InternalFree(module_name);
230 return 0;
231}
232
233uptr GetListOfModules(ModuleDIContext *modules, uptr max_modules) {
234 CHECK(modules);
235 DlIteratePhdrData data = {modules, 0, max_modules};
236 dl_iterate_phdr(dl_iterate_phdr_cb, &data);
237 return data.current_n;
238}
239#endif // ANDROID
240
Alexey Samsonov4b1f1032012-06-07 07:13:46 +0000241// ----------------- sanitizer_procmaps.h
Alexey Samsonov28a98952012-06-07 06:15:12 +0000242ProcessMaps::ProcessMaps() {
243 proc_self_maps_buff_len_ =
244 ReadFileToBuffer("/proc/self/maps", &proc_self_maps_buff_,
245 &proc_self_maps_buff_mmaped_size_, 1 << 26);
Kostya Serebryany98390d02012-06-20 15:19:17 +0000246 CHECK_GT(proc_self_maps_buff_len_, 0);
Alexey Samsonov28a98952012-06-07 06:15:12 +0000247 // internal_write(2, proc_self_maps_buff_, proc_self_maps_buff_len_);
248 Reset();
249}
250
251ProcessMaps::~ProcessMaps() {
252 UnmapOrDie(proc_self_maps_buff_, proc_self_maps_buff_mmaped_size_);
253}
254
255void ProcessMaps::Reset() {
256 current_ = proc_self_maps_buff_;
257}
258
Kostya Serebryanyd32d5372012-06-29 13:05:36 +0000259// Parse a hex value in str and update str.
260static uptr ParseHex(char **str) {
261 uptr x = 0;
262 char *s;
263 for (s = *str; ; s++) {
264 char c = *s;
265 uptr v = 0;
266 if (c >= '0' && c <= '9')
267 v = c - '0';
268 else if (c >= 'a' && c <= 'f')
269 v = c - 'a' + 10;
270 else if (c >= 'A' && c <= 'F')
271 v = c - 'A' + 10;
272 else
273 break;
274 x = x * 16 + v;
275 }
276 *str = s;
277 return x;
278}
279
280static bool IsOnOf(char c, char c1, char c2) {
281 return c == c1 || c == c2;
282}
283
284static bool IsDecimal(char c) {
285 return c >= '0' && c <= '9';
286}
287
Alexey Samsonov28a98952012-06-07 06:15:12 +0000288bool ProcessMaps::Next(uptr *start, uptr *end, uptr *offset,
289 char filename[], uptr filename_size) {
290 char *last = proc_self_maps_buff_ + proc_self_maps_buff_len_;
291 if (current_ >= last) return false;
Alexey Samsonov28a98952012-06-07 06:15:12 +0000292 uptr dummy;
293 if (!start) start = &dummy;
294 if (!end) end = &dummy;
295 if (!offset) offset = &dummy;
296 char *next_line = (char*)internal_memchr(current_, '\n', last - current_);
297 if (next_line == 0)
298 next_line = last;
Kostya Serebryanyd32d5372012-06-29 13:05:36 +0000299 // Example: 08048000-08056000 r-xp 00000000 03:0c 64593 /foo/bar
300 *start = ParseHex(&current_);
Kostya Serebryany5766a9e2012-06-29 14:14:32 +0000301 CHECK_EQ(*current_++, '-');
Kostya Serebryanyd32d5372012-06-29 13:05:36 +0000302 *end = ParseHex(&current_);
Kostya Serebryany5766a9e2012-06-29 14:14:32 +0000303 CHECK_EQ(*current_++, ' ');
Kostya Serebryanyd32d5372012-06-29 13:05:36 +0000304 CHECK(IsOnOf(*current_++, '-', 'r'));
305 CHECK(IsOnOf(*current_++, '-', 'w'));
306 CHECK(IsOnOf(*current_++, '-', 'x'));
307 CHECK(IsOnOf(*current_++, 's', 'p'));
Kostya Serebryany5766a9e2012-06-29 14:14:32 +0000308 CHECK_EQ(*current_++, ' ');
Kostya Serebryanyd32d5372012-06-29 13:05:36 +0000309 *offset = ParseHex(&current_);
Kostya Serebryany5766a9e2012-06-29 14:14:32 +0000310 CHECK_EQ(*current_++, ' ');
Kostya Serebryanyd32d5372012-06-29 13:05:36 +0000311 ParseHex(&current_);
Kostya Serebryany5766a9e2012-06-29 14:14:32 +0000312 CHECK_EQ(*current_++, ':');
Kostya Serebryanyd32d5372012-06-29 13:05:36 +0000313 ParseHex(&current_);
Kostya Serebryany5766a9e2012-06-29 14:14:32 +0000314 CHECK_EQ(*current_++, ' ');
Kostya Serebryanyd32d5372012-06-29 13:05:36 +0000315 while (IsDecimal(*current_))
316 current_++;
Kostya Serebryany5766a9e2012-06-29 14:14:32 +0000317 CHECK_EQ(*current_++, ' ');
Alexey Samsonov28a98952012-06-07 06:15:12 +0000318 // Skip spaces.
319 while (current_ < next_line && *current_ == ' ')
320 current_++;
321 // Fill in the filename.
322 uptr i = 0;
323 while (current_ < next_line) {
324 if (filename && i < filename_size - 1)
325 filename[i++] = *current_;
326 current_++;
327 }
328 if (filename && i < filename_size)
329 filename[i] = 0;
330 current_ = next_line + 1;
331 return true;
332}
333
334// Gets the object name and the offset by walking ProcessMaps.
335bool ProcessMaps::GetObjectNameAndOffset(uptr addr, uptr *offset,
336 char filename[],
337 uptr filename_size) {
338 return IterateForObjectNameAndOffset(addr, offset, filename, filename_size);
339}
340
Alexey Samsonov2c5fc3b2012-06-04 14:27:50 +0000341} // namespace __sanitizer
342
343#endif // __linux__