1 //===-- 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
16 #include "sanitizer_common.h"
17 #include "sanitizer_internal_defs.h"
18 #include "sanitizer_libc.h"
19 #include "sanitizer_linux.h"
20 #include "sanitizer_mutex.h"
21 #include "sanitizer_placement_new.h"
22 #include "sanitizer_procmaps.h"
23 #include "sanitizer_stacktrace.h"
24
25 #include <dlfcn.h>
26 #include <errno.h>
27 #include <fcntl.h>
28 #include <pthread.h>
29 #include <sched.h>
30 #include <sys/mman.h>
31 #include <sys/ptrace.h>
32 #include <sys/resource.h>
33 #include <sys/stat.h>
34 #include <sys/syscall.h>
35 #include <sys/time.h>
36 #include <sys/types.h>
37 #include <sys/prctl.h>
38 #include <unistd.h>
39 #include <unwind.h>
40
41 #if !defined(__ANDROID__) && !defined(ANDROID)
42 #include <sys/signal.h>
43 #endif
44
45 // <linux/futex.h> is broken on some linux distributions.
46 const int FUTEX_WAIT = 0;
47 const int FUTEX_WAKE = 1;
48
49 // Are we using 32-bit or 64-bit syscalls?
50 // x32 (which defines __x86_64__) has SANITIZER_WORDSIZE == 32
51 // but it still needs to use 64-bit syscalls.
52 #if defined(__x86_64__) || SANITIZER_WORDSIZE == 64
53 # define SANITIZER_LINUX_USES_64BIT_SYSCALLS 1
54 #else
55 # define SANITIZER_LINUX_USES_64BIT_SYSCALLS 0
56 #endif
57
58 namespace __sanitizer {
59
60 // --------------- sanitizer_libc.h
internal_mmap(void * addr,uptr length,int prot,int flags,int fd,u64 offset)61 void *internal_mmap(void *addr, uptr length, int prot, int flags,
62 int fd, u64 offset) {
63 #if SANITIZER_LINUX_USES_64BIT_SYSCALLS
64 return (void *)syscall(__NR_mmap, addr, length, prot, flags, fd, offset);
65 #else
66 return (void *)syscall(__NR_mmap2, addr, length, prot, flags, fd, offset);
67 #endif
68 }
69
internal_munmap(void * addr,uptr length)70 int internal_munmap(void *addr, uptr length) {
71 return syscall(__NR_munmap, addr, length);
72 }
73
internal_close(fd_t fd)74 int internal_close(fd_t fd) {
75 return syscall(__NR_close, fd);
76 }
77
internal_open(const char * filename,int flags)78 fd_t internal_open(const char *filename, int flags) {
79 return syscall(__NR_open, filename, flags);
80 }
81
internal_open(const char * filename,int flags,u32 mode)82 fd_t internal_open(const char *filename, int flags, u32 mode) {
83 return syscall(__NR_open, filename, flags, mode);
84 }
85
OpenFile(const char * filename,bool write)86 fd_t OpenFile(const char *filename, bool write) {
87 return internal_open(filename,
88 write ? O_WRONLY | O_CREAT /*| O_CLOEXEC*/ : O_RDONLY, 0660);
89 }
90
internal_read(fd_t fd,void * buf,uptr count)91 uptr internal_read(fd_t fd, void *buf, uptr count) {
92 sptr res;
93 HANDLE_EINTR(res, (sptr)syscall(__NR_read, fd, buf, count));
94 return res;
95 }
96
internal_write(fd_t fd,const void * buf,uptr count)97 uptr internal_write(fd_t fd, const void *buf, uptr count) {
98 sptr res;
99 HANDLE_EINTR(res, (sptr)syscall(__NR_write, fd, buf, count));
100 return res;
101 }
102
internal_stat(const char * path,void * buf)103 int internal_stat(const char *path, void *buf) {
104 #if SANITIZER_LINUX_USES_64BIT_SYSCALLS
105 return syscall(__NR_stat, path, buf);
106 #else
107 return syscall(__NR_stat64, path, buf);
108 #endif
109 }
110
internal_lstat(const char * path,void * buf)111 int internal_lstat(const char *path, void *buf) {
112 #if SANITIZER_LINUX_USES_64BIT_SYSCALLS
113 return syscall(__NR_lstat, path, buf);
114 #else
115 return syscall(__NR_lstat64, path, buf);
116 #endif
117 }
118
internal_fstat(fd_t fd,void * buf)119 int internal_fstat(fd_t fd, void *buf) {
120 #if SANITIZER_LINUX_USES_64BIT_SYSCALLS
121 return syscall(__NR_fstat, fd, buf);
122 #else
123 return syscall(__NR_fstat64, fd, buf);
124 #endif
125 }
126
internal_filesize(fd_t fd)127 uptr internal_filesize(fd_t fd) {
128 #if SANITIZER_LINUX_USES_64BIT_SYSCALLS
129 struct stat st;
130 #else
131 struct stat64 st;
132 #endif
133 if (internal_fstat(fd, &st))
134 return -1;
135 return (uptr)st.st_size;
136 }
137
internal_dup2(int oldfd,int newfd)138 int internal_dup2(int oldfd, int newfd) {
139 return syscall(__NR_dup2, oldfd, newfd);
140 }
141
internal_readlink(const char * path,char * buf,uptr bufsize)142 uptr internal_readlink(const char *path, char *buf, uptr bufsize) {
143 return (uptr)syscall(__NR_readlink, path, buf, bufsize);
144 }
145
internal_sched_yield()146 int internal_sched_yield() {
147 return syscall(__NR_sched_yield);
148 }
149
internal__exit(int exitcode)150 void internal__exit(int exitcode) {
151 syscall(__NR_exit_group, exitcode);
152 Die(); // Unreachable.
153 }
154
155 // ----------------- sanitizer_common.h
FileExists(const char * filename)156 bool FileExists(const char *filename) {
157 #if SANITIZER_LINUX_USES_64BIT_SYSCALLS
158 struct stat st;
159 if (syscall(__NR_stat, filename, &st))
160 return false;
161 #else
162 struct stat64 st;
163 if (syscall(__NR_stat64, filename, &st))
164 return false;
165 #endif
166 // Sanity check: filename is a regular file.
167 return S_ISREG(st.st_mode);
168 }
169
GetTid()170 uptr GetTid() {
171 return syscall(__NR_gettid);
172 }
173
GetThreadStackTopAndBottom(bool at_initialization,uptr * stack_top,uptr * stack_bottom)174 void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
175 uptr *stack_bottom) {
176 static const uptr kMaxThreadStackSize = 256 * (1 << 20); // 256M
177 CHECK(stack_top);
178 CHECK(stack_bottom);
179 if (at_initialization) {
180 // This is the main thread. Libpthread may not be initialized yet.
181 struct rlimit rl;
182 CHECK_EQ(getrlimit(RLIMIT_STACK, &rl), 0);
183
184 // Find the mapping that contains a stack variable.
185 MemoryMappingLayout proc_maps;
186 uptr start, end, offset;
187 uptr prev_end = 0;
188 while (proc_maps.Next(&start, &end, &offset, 0, 0, /* protection */0)) {
189 if ((uptr)&rl < end)
190 break;
191 prev_end = end;
192 }
193 CHECK((uptr)&rl >= start && (uptr)&rl < end);
194
195 // Get stacksize from rlimit, but clip it so that it does not overlap
196 // with other mappings.
197 uptr stacksize = rl.rlim_cur;
198 if (stacksize > end - prev_end)
199 stacksize = end - prev_end;
200 // When running with unlimited stack size, we still want to set some limit.
201 // The unlimited stack size is caused by 'ulimit -s unlimited'.
202 // Also, for some reason, GNU make spawns subprocesses with unlimited stack.
203 if (stacksize > kMaxThreadStackSize)
204 stacksize = kMaxThreadStackSize;
205 *stack_top = end;
206 *stack_bottom = end - stacksize;
207 return;
208 }
209 pthread_attr_t attr;
210 CHECK_EQ(pthread_getattr_np(pthread_self(), &attr), 0);
211 uptr stacksize = 0;
212 void *stackaddr = 0;
213 pthread_attr_getstack(&attr, &stackaddr, (size_t*)&stacksize);
214 pthread_attr_destroy(&attr);
215
216 *stack_top = (uptr)stackaddr + stacksize;
217 *stack_bottom = (uptr)stackaddr;
218 CHECK(stacksize < kMaxThreadStackSize); // Sanity check.
219 }
220
221 // Like getenv, but reads env directly from /proc and does not use libc.
222 // This function should be called first inside __asan_init.
GetEnv(const char * name)223 const char *GetEnv(const char *name) {
224 static char *environ;
225 static uptr len;
226 static bool inited;
227 if (!inited) {
228 inited = true;
229 uptr environ_size;
230 len = ReadFileToBuffer("/proc/self/environ",
231 &environ, &environ_size, 1 << 26);
232 }
233 if (!environ || len == 0) return 0;
234 uptr namelen = internal_strlen(name);
235 const char *p = environ;
236 while (*p != '\0') { // will happen at the \0\0 that terminates the buffer
237 // proc file has the format NAME=value\0NAME=value\0NAME=value\0...
238 const char* endp =
239 (char*)internal_memchr(p, '\0', len - (p - environ));
240 if (endp == 0) // this entry isn't NUL terminated
241 return 0;
242 else if (!internal_memcmp(p, name, namelen) && p[namelen] == '=') // Match.
243 return p + namelen + 1; // point after =
244 p = endp + 1;
245 }
246 return 0; // Not found.
247 }
248
249 #ifdef __GLIBC__
250
251 extern "C" {
252 extern void *__libc_stack_end;
253 }
254
GetArgsAndEnv(char *** argv,char *** envp)255 static void GetArgsAndEnv(char ***argv, char ***envp) {
256 uptr *stack_end = (uptr *)__libc_stack_end;
257 int argc = *stack_end;
258 *argv = (char**)(stack_end + 1);
259 *envp = (char**)(stack_end + argc + 2);
260 }
261
262 #else // __GLIBC__
263
ReadNullSepFileToArray(const char * path,char *** arr,int arr_size)264 static void ReadNullSepFileToArray(const char *path, char ***arr,
265 int arr_size) {
266 char *buff;
267 uptr buff_size = 0;
268 *arr = (char **)MmapOrDie(arr_size * sizeof(char *), "NullSepFileArray");
269 ReadFileToBuffer(path, &buff, &buff_size, 1024 * 1024);
270 (*arr)[0] = buff;
271 int count, i;
272 for (count = 1, i = 1; ; i++) {
273 if (buff[i] == 0) {
274 if (buff[i+1] == 0) break;
275 (*arr)[count] = &buff[i+1];
276 CHECK_LE(count, arr_size - 1); // FIXME: make this more flexible.
277 count++;
278 }
279 }
280 (*arr)[count] = 0;
281 }
282
GetArgsAndEnv(char *** argv,char *** envp)283 static void GetArgsAndEnv(char ***argv, char ***envp) {
284 static const int kMaxArgv = 2000, kMaxEnvp = 2000;
285 ReadNullSepFileToArray("/proc/self/cmdline", argv, kMaxArgv);
286 ReadNullSepFileToArray("/proc/self/environ", envp, kMaxEnvp);
287 }
288
289 #endif // __GLIBC__
290
ReExec()291 void ReExec() {
292 char **argv, **envp;
293 GetArgsAndEnv(&argv, &envp);
294 execve("/proc/self/exe", argv, envp);
295 Printf("execve failed, errno %d\n", errno);
296 Die();
297 }
298
PrepareForSandboxing()299 void PrepareForSandboxing() {
300 // Some kinds of sandboxes may forbid filesystem access, so we won't be able
301 // to read the file mappings from /proc/self/maps. Luckily, neither the
302 // process will be able to load additional libraries, so it's fine to use the
303 // cached mappings.
304 MemoryMappingLayout::CacheMemoryMappings();
305 }
306
307 // ----------------- sanitizer_procmaps.h
308 // Linker initialized.
309 ProcSelfMapsBuff MemoryMappingLayout::cached_proc_self_maps_;
310 StaticSpinMutex MemoryMappingLayout::cache_lock_; // Linker initialized.
311
MemoryMappingLayout()312 MemoryMappingLayout::MemoryMappingLayout() {
313 proc_self_maps_.len =
314 ReadFileToBuffer("/proc/self/maps", &proc_self_maps_.data,
315 &proc_self_maps_.mmaped_size, 1 << 26);
316 if (proc_self_maps_.mmaped_size == 0) {
317 LoadFromCache();
318 CHECK_GT(proc_self_maps_.len, 0);
319 }
320 // internal_write(2, proc_self_maps_.data, proc_self_maps_.len);
321 Reset();
322 // FIXME: in the future we may want to cache the mappings on demand only.
323 CacheMemoryMappings();
324 }
325
~MemoryMappingLayout()326 MemoryMappingLayout::~MemoryMappingLayout() {
327 // Only unmap the buffer if it is different from the cached one. Otherwise
328 // it will be unmapped when the cache is refreshed.
329 if (proc_self_maps_.data != cached_proc_self_maps_.data) {
330 UnmapOrDie(proc_self_maps_.data, proc_self_maps_.mmaped_size);
331 }
332 }
333
Reset()334 void MemoryMappingLayout::Reset() {
335 current_ = proc_self_maps_.data;
336 }
337
338 // static
CacheMemoryMappings()339 void MemoryMappingLayout::CacheMemoryMappings() {
340 SpinMutexLock l(&cache_lock_);
341 // Don't invalidate the cache if the mappings are unavailable.
342 ProcSelfMapsBuff old_proc_self_maps;
343 old_proc_self_maps = cached_proc_self_maps_;
344 cached_proc_self_maps_.len =
345 ReadFileToBuffer("/proc/self/maps", &cached_proc_self_maps_.data,
346 &cached_proc_self_maps_.mmaped_size, 1 << 26);
347 if (cached_proc_self_maps_.mmaped_size == 0) {
348 cached_proc_self_maps_ = old_proc_self_maps;
349 } else {
350 if (old_proc_self_maps.mmaped_size) {
351 UnmapOrDie(old_proc_self_maps.data,
352 old_proc_self_maps.mmaped_size);
353 }
354 }
355 }
356
LoadFromCache()357 void MemoryMappingLayout::LoadFromCache() {
358 SpinMutexLock l(&cache_lock_);
359 if (cached_proc_self_maps_.data) {
360 proc_self_maps_ = cached_proc_self_maps_;
361 }
362 }
363
364 // Parse a hex value in str and update str.
ParseHex(char ** str)365 static uptr ParseHex(char **str) {
366 uptr x = 0;
367 char *s;
368 for (s = *str; ; s++) {
369 char c = *s;
370 uptr v = 0;
371 if (c >= '0' && c <= '9')
372 v = c - '0';
373 else if (c >= 'a' && c <= 'f')
374 v = c - 'a' + 10;
375 else if (c >= 'A' && c <= 'F')
376 v = c - 'A' + 10;
377 else
378 break;
379 x = x * 16 + v;
380 }
381 *str = s;
382 return x;
383 }
384
IsOneOf(char c,char c1,char c2)385 static bool IsOneOf(char c, char c1, char c2) {
386 return c == c1 || c == c2;
387 }
388
IsDecimal(char c)389 static bool IsDecimal(char c) {
390 return c >= '0' && c <= '9';
391 }
392
Next(uptr * start,uptr * end,uptr * offset,char filename[],uptr filename_size,uptr * protection)393 bool MemoryMappingLayout::Next(uptr *start, uptr *end, uptr *offset,
394 char filename[], uptr filename_size,
395 uptr *protection) {
396 char *last = proc_self_maps_.data + proc_self_maps_.len;
397 if (current_ >= last) return false;
398 uptr dummy;
399 if (!start) start = &dummy;
400 if (!end) end = &dummy;
401 if (!offset) offset = &dummy;
402 char *next_line = (char*)internal_memchr(current_, '\n', last - current_);
403 if (next_line == 0)
404 next_line = last;
405 // Example: 08048000-08056000 r-xp 00000000 03:0c 64593 /foo/bar
406 *start = ParseHex(¤t_);
407 CHECK_EQ(*current_++, '-');
408 *end = ParseHex(¤t_);
409 CHECK_EQ(*current_++, ' ');
410 uptr local_protection = 0;
411 CHECK(IsOneOf(*current_, '-', 'r'));
412 if (*current_++ == 'r')
413 local_protection |= kProtectionRead;
414 CHECK(IsOneOf(*current_, '-', 'w'));
415 if (*current_++ == 'w')
416 local_protection |= kProtectionWrite;
417 CHECK(IsOneOf(*current_, '-', 'x'));
418 if (*current_++ == 'x')
419 local_protection |= kProtectionExecute;
420 CHECK(IsOneOf(*current_, 's', 'p'));
421 if (*current_++ == 's')
422 local_protection |= kProtectionShared;
423 if (protection) {
424 *protection = local_protection;
425 }
426 CHECK_EQ(*current_++, ' ');
427 *offset = ParseHex(¤t_);
428 CHECK_EQ(*current_++, ' ');
429 ParseHex(¤t_);
430 CHECK_EQ(*current_++, ':');
431 ParseHex(¤t_);
432 CHECK_EQ(*current_++, ' ');
433 while (IsDecimal(*current_))
434 current_++;
435 CHECK_EQ(*current_++, ' ');
436 // Skip spaces.
437 while (current_ < next_line && *current_ == ' ')
438 current_++;
439 // Fill in the filename.
440 uptr i = 0;
441 while (current_ < next_line) {
442 if (filename && i < filename_size - 1)
443 filename[i++] = *current_;
444 current_++;
445 }
446 if (filename && i < filename_size)
447 filename[i] = 0;
448 current_ = next_line + 1;
449 return true;
450 }
451
452 // Gets the object name and the offset by walking MemoryMappingLayout.
GetObjectNameAndOffset(uptr addr,uptr * offset,char filename[],uptr filename_size,uptr * protection)453 bool MemoryMappingLayout::GetObjectNameAndOffset(uptr addr, uptr *offset,
454 char filename[],
455 uptr filename_size,
456 uptr *protection) {
457 return IterateForObjectNameAndOffset(addr, offset, filename, filename_size,
458 protection);
459 }
460
SanitizerSetThreadName(const char * name)461 bool SanitizerSetThreadName(const char *name) {
462 #ifdef PR_SET_NAME
463 return 0 == prctl(PR_SET_NAME, (unsigned long)name, 0, 0, 0); // NOLINT
464 #else
465 return false;
466 #endif
467 }
468
SanitizerGetThreadName(char * name,int max_len)469 bool SanitizerGetThreadName(char *name, int max_len) {
470 #ifdef PR_GET_NAME
471 char buff[17];
472 if (prctl(PR_GET_NAME, (unsigned long)buff, 0, 0, 0)) // NOLINT
473 return false;
474 internal_strncpy(name, buff, max_len);
475 name[max_len] = 0;
476 return true;
477 #else
478 return false;
479 #endif
480 }
481
482 #ifndef SANITIZER_GO
483 //------------------------- SlowUnwindStack -----------------------------------
484 #ifdef __arm__
485 #define UNWIND_STOP _URC_END_OF_STACK
486 #define UNWIND_CONTINUE _URC_NO_REASON
487 #else
488 #define UNWIND_STOP _URC_NORMAL_STOP
489 #define UNWIND_CONTINUE _URC_NO_REASON
490 #endif
491
Unwind_GetIP(struct _Unwind_Context * ctx)492 uptr Unwind_GetIP(struct _Unwind_Context *ctx) {
493 #ifdef __arm__
494 uptr val;
495 _Unwind_VRS_Result res = _Unwind_VRS_Get(ctx, _UVRSC_CORE,
496 15 /* r15 = PC */, _UVRSD_UINT32, &val);
497 CHECK(res == _UVRSR_OK && "_Unwind_VRS_Get failed");
498 // Clear the Thumb bit.
499 return val & ~(uptr)1;
500 #else
501 return _Unwind_GetIP(ctx);
502 #endif
503 }
504
Unwind_Trace(struct _Unwind_Context * ctx,void * param)505 _Unwind_Reason_Code Unwind_Trace(struct _Unwind_Context *ctx, void *param) {
506 StackTrace *b = (StackTrace*)param;
507 CHECK(b->size < b->max_size);
508 uptr pc = Unwind_GetIP(ctx);
509 b->trace[b->size++] = pc;
510 if (b->size == b->max_size) return UNWIND_STOP;
511 return UNWIND_CONTINUE;
512 }
513
MatchPc(uptr cur_pc,uptr trace_pc)514 static bool MatchPc(uptr cur_pc, uptr trace_pc) {
515 return cur_pc - trace_pc <= 64 || trace_pc - cur_pc <= 64;
516 }
517
SlowUnwindStack(uptr pc,uptr max_depth)518 void StackTrace::SlowUnwindStack(uptr pc, uptr max_depth) {
519 this->size = 0;
520 this->max_size = max_depth;
521 if (max_depth > 1) {
522 _Unwind_Backtrace(Unwind_Trace, this);
523 // We need to pop a few frames so that pc is on top.
524 // trace[0] belongs to the current function so we always pop it.
525 int to_pop = 1;
526 /**/ if (size > 1 && MatchPc(pc, trace[1])) to_pop = 1;
527 else if (size > 2 && MatchPc(pc, trace[2])) to_pop = 2;
528 else if (size > 3 && MatchPc(pc, trace[3])) to_pop = 3;
529 else if (size > 4 && MatchPc(pc, trace[4])) to_pop = 4;
530 else if (size > 5 && MatchPc(pc, trace[5])) to_pop = 5;
531 this->PopStackFrames(to_pop);
532 }
533 this->trace[0] = pc;
534 }
535
536 #endif // #ifndef SANITIZER_GO
537
538 enum MutexState {
539 MtxUnlocked = 0,
540 MtxLocked = 1,
541 MtxSleeping = 2
542 };
543
BlockingMutex(LinkerInitialized)544 BlockingMutex::BlockingMutex(LinkerInitialized) {
545 CHECK_EQ(owner_, 0);
546 }
547
BlockingMutex()548 BlockingMutex::BlockingMutex() {
549 internal_memset(this, 0, sizeof(*this));
550 }
551
Lock()552 void BlockingMutex::Lock() {
553 atomic_uint32_t *m = reinterpret_cast<atomic_uint32_t *>(&opaque_storage_);
554 if (atomic_exchange(m, MtxLocked, memory_order_acquire) == MtxUnlocked)
555 return;
556 while (atomic_exchange(m, MtxSleeping, memory_order_acquire) != MtxUnlocked)
557 syscall(__NR_futex, m, FUTEX_WAIT, MtxSleeping, 0, 0, 0);
558 }
559
Unlock()560 void BlockingMutex::Unlock() {
561 atomic_uint32_t *m = reinterpret_cast<atomic_uint32_t *>(&opaque_storage_);
562 u32 v = atomic_exchange(m, MtxUnlocked, memory_order_relaxed);
563 CHECK_NE(v, MtxUnlocked);
564 if (v == MtxSleeping)
565 syscall(__NR_futex, m, FUTEX_WAKE, 1, 0, 0, 0);
566 }
567
CheckLocked()568 void BlockingMutex::CheckLocked() {
569 atomic_uint32_t *m = reinterpret_cast<atomic_uint32_t *>(&opaque_storage_);
570 CHECK_NE(MtxUnlocked, atomic_load(m, memory_order_relaxed));
571 }
572
573 // ----------------- sanitizer_linux.h
574 // The actual size of this structure is specified by d_reclen.
575 // Note that getdents64 uses a different structure format. We only provide the
576 // 32-bit syscall here.
577 struct linux_dirent {
578 unsigned long d_ino;
579 unsigned long d_off;
580 unsigned short d_reclen;
581 char d_name[256];
582 };
583
584 // Syscall wrappers.
internal_ptrace(int request,int pid,void * addr,void * data)585 long internal_ptrace(int request, int pid, void *addr, void *data) {
586 return syscall(__NR_ptrace, request, pid, addr, data);
587 }
588
internal_waitpid(int pid,int * status,int options)589 int internal_waitpid(int pid, int *status, int options) {
590 return syscall(__NR_wait4, pid, status, options, NULL /* rusage */);
591 }
592
internal_getppid()593 int internal_getppid() {
594 return syscall(__NR_getppid);
595 }
596
internal_getdents(fd_t fd,struct linux_dirent * dirp,unsigned int count)597 int internal_getdents(fd_t fd, struct linux_dirent *dirp, unsigned int count) {
598 return syscall(__NR_getdents, fd, dirp, count);
599 }
600
internal_lseek(fd_t fd,OFF_T offset,int whence)601 OFF_T internal_lseek(fd_t fd, OFF_T offset, int whence) {
602 return syscall(__NR_lseek, fd, offset, whence);
603 }
604
internal_prctl(int option,uptr arg2,uptr arg3,uptr arg4,uptr arg5)605 int internal_prctl(int option, uptr arg2, uptr arg3, uptr arg4, uptr arg5) {
606 return syscall(__NR_prctl, option, arg2, arg3, arg4, arg5);
607 }
608
internal_sigaltstack(const struct sigaltstack * ss,struct sigaltstack * oss)609 int internal_sigaltstack(const struct sigaltstack *ss,
610 struct sigaltstack *oss) {
611 return syscall(__NR_sigaltstack, ss, oss);
612 }
613
614
615 // ThreadLister implementation.
ThreadLister(int pid)616 ThreadLister::ThreadLister(int pid)
617 : pid_(pid),
618 descriptor_(-1),
619 error_(true),
620 entry_((linux_dirent *)buffer_),
621 bytes_read_(0) {
622 char task_directory_path[80];
623 internal_snprintf(task_directory_path, sizeof(task_directory_path),
624 "/proc/%d/task/", pid);
625 descriptor_ = internal_open(task_directory_path, O_RDONLY | O_DIRECTORY);
626 if (descriptor_ < 0) {
627 error_ = true;
628 Report("Can't open /proc/%d/task for reading.\n", pid);
629 } else {
630 error_ = false;
631 }
632 }
633
GetNextTID()634 int ThreadLister::GetNextTID() {
635 int tid = -1;
636 do {
637 if (error_)
638 return -1;
639 if ((char *)entry_ >= &buffer_[bytes_read_] && !GetDirectoryEntries())
640 return -1;
641 if (entry_->d_ino != 0 && entry_->d_name[0] >= '0' &&
642 entry_->d_name[0] <= '9') {
643 // Found a valid tid.
644 tid = (int)internal_atoll(entry_->d_name);
645 }
646 entry_ = (struct linux_dirent *)(((char *)entry_) + entry_->d_reclen);
647 } while (tid < 0);
648 return tid;
649 }
650
Reset()651 void ThreadLister::Reset() {
652 if (error_ || descriptor_ < 0)
653 return;
654 internal_lseek(descriptor_, 0, SEEK_SET);
655 }
656
~ThreadLister()657 ThreadLister::~ThreadLister() {
658 if (descriptor_ >= 0)
659 internal_close(descriptor_);
660 }
661
error()662 bool ThreadLister::error() { return error_; }
663
GetDirectoryEntries()664 bool ThreadLister::GetDirectoryEntries() {
665 CHECK_GE(descriptor_, 0);
666 CHECK_NE(error_, true);
667 bytes_read_ = internal_getdents(descriptor_,
668 (struct linux_dirent *)buffer_,
669 sizeof(buffer_));
670 if (bytes_read_ < 0) {
671 Report("Can't read directory entries from /proc/%d/task.\n", pid_);
672 error_ = true;
673 return false;
674 } else if (bytes_read_ == 0) {
675 return false;
676 }
677 entry_ = (struct linux_dirent *)buffer_;
678 return true;
679 }
680
681 static uptr g_tls_size;
682
683 #ifdef __i386__
684 # define DL_INTERNAL_FUNCTION __attribute__((regparm(3), stdcall))
685 #else
686 # define DL_INTERNAL_FUNCTION
687 #endif
688
InitTlsSize()689 void InitTlsSize() {
690 #ifndef SANITIZER_GO
691 typedef void (*get_tls_func)(size_t*, size_t*) DL_INTERNAL_FUNCTION;
692 get_tls_func get_tls;
693 void *get_tls_static_info_ptr = dlsym(RTLD_NEXT, "_dl_get_tls_static_info");
694 CHECK_EQ(sizeof(get_tls), sizeof(get_tls_static_info_ptr));
695 internal_memcpy(&get_tls, &get_tls_static_info_ptr,
696 sizeof(get_tls_static_info_ptr));
697 CHECK_NE(get_tls, 0);
698 size_t tls_size = 0;
699 size_t tls_align = 0;
700 get_tls(&tls_size, &tls_align);
701 g_tls_size = tls_size;
702 #endif
703 }
704
GetTlsSize()705 uptr GetTlsSize() {
706 return g_tls_size;
707 }
708
709 } // namespace __sanitizer
710
711 #endif // __linux__
712