sanitizer_linux.cc revision 497ae56316cd05a0d539e0d6e065bbaee254aca3
1ae4d9caa4f47fa6abcd641719e9f520622940c17Alexey Samsonov//===-- sanitizer_linux.cc ------------------------------------------------===//
2ae4d9caa4f47fa6abcd641719e9f520622940c17Alexey Samsonov//
3ae4d9caa4f47fa6abcd641719e9f520622940c17Alexey Samsonov//                     The LLVM Compiler Infrastructure
4ae4d9caa4f47fa6abcd641719e9f520622940c17Alexey Samsonov//
5ae4d9caa4f47fa6abcd641719e9f520622940c17Alexey Samsonov// This file is distributed under the University of Illinois Open Source
6ae4d9caa4f47fa6abcd641719e9f520622940c17Alexey Samsonov// License. See LICENSE.TXT for details.
7ae4d9caa4f47fa6abcd641719e9f520622940c17Alexey Samsonov//
8ae4d9caa4f47fa6abcd641719e9f520622940c17Alexey Samsonov//===----------------------------------------------------------------------===//
9ae4d9caa4f47fa6abcd641719e9f520622940c17Alexey Samsonov//
10ae4d9caa4f47fa6abcd641719e9f520622940c17Alexey Samsonov// This file is shared between AddressSanitizer and ThreadSanitizer
11ae4d9caa4f47fa6abcd641719e9f520622940c17Alexey Samsonov// run-time libraries and implements linux-specific functions from
12ae4d9caa4f47fa6abcd641719e9f520622940c17Alexey Samsonov// sanitizer_libc.h.
13ae4d9caa4f47fa6abcd641719e9f520622940c17Alexey Samsonov//===----------------------------------------------------------------------===//
1424e13723f8477d8c42ab8b2a7f4f69fc089842f1Evgeniy Stepanov
1524e13723f8477d8c42ab8b2a7f4f69fc089842f1Evgeniy Stepanov#include "sanitizer_platform.h"
1624e13723f8477d8c42ab8b2a7f4f69fc089842f1Evgeniy Stepanov#if SANITIZER_LINUX
17ae4d9caa4f47fa6abcd641719e9f520622940c17Alexey Samsonov
186895adc39c4e09371154c8037366ad4464163ed0Alexey Samsonov#include "sanitizer_common.h"
1994b5036ee6ba866e1702848855b6d687d1e70afaAlexey Samsonov#include "sanitizer_internal_defs.h"
20ae4d9caa4f47fa6abcd641719e9f520622940c17Alexey Samsonov#include "sanitizer_libc.h"
216fb47af2d2d305adbfc3d41bea589d1527a364a9Kostya Serebryany#include "sanitizer_linux.h"
2293da8b6a5e0ed2ca621897504c5d06449b3d7077Alexander Potapenko#include "sanitizer_mutex.h"
23a68633fb76208137ccb807914df52758ee5ca6f0Alexey Samsonov#include "sanitizer_placement_new.h"
246895adc39c4e09371154c8037366ad4464163ed0Alexey Samsonov#include "sanitizer_procmaps.h"
25a30c8f9eac981dcf137e84226810b760e35c7be1Kostya Serebryany#include "sanitizer_stacktrace.h"
265ce93fc96ab5e2defd85890da63b51cc4c57a2afAlexander Potapenko#include "sanitizer_symbolizer.h"
27ae4d9caa4f47fa6abcd641719e9f520622940c17Alexey Samsonov
28088ea2b46f97172bd0b0663a629e11cf826b84f7Peter Collingbourne#include <asm/param.h>
29b114ed83859d8d4964ac2284584733bcd2acf4f6Evgeniy Stepanov#include <dlfcn.h>
3035a7faf1fbfac678136e79d53824672dafb7d13eAlexey Samsonov#include <errno.h>
31c5d465136b911bf925f2a631e2b79f1c03e8a1b0Alexey Samsonov#include <fcntl.h>
326d40a0a2ffa6735e45bd1d62c94ff725fd3e8b71Peter Collingbourne#if !SANITIZER_ANDROID
332e75ac983cb233daa1abfa35fb33d2bafffe2ab1Peter Collingbourne#include <link.h>
346d40a0a2ffa6735e45bd1d62c94ff725fd3e8b71Peter Collingbourne#endif
35e5931fd7d2a74fd7fb60bd8d7f644cca51a24364Alexey Samsonov#include <pthread.h>
360969bcf2c936126b1f6e636b978aade8fc207437Alexey Samsonov#include <sched.h>
37ae4d9caa4f47fa6abcd641719e9f520622940c17Alexey Samsonov#include <sys/mman.h>
386fb47af2d2d305adbfc3d41bea589d1527a364a9Kostya Serebryany#include <sys/ptrace.h>
39e5931fd7d2a74fd7fb60bd8d7f644cca51a24364Alexey Samsonov#include <sys/resource.h>
40c5d465136b911bf925f2a631e2b79f1c03e8a1b0Alexey Samsonov#include <sys/stat.h>
41ae4d9caa4f47fa6abcd641719e9f520622940c17Alexey Samsonov#include <sys/syscall.h>
42e5931fd7d2a74fd7fb60bd8d7f644cca51a24364Alexey Samsonov#include <sys/time.h>
43ae4d9caa4f47fa6abcd641719e9f520622940c17Alexey Samsonov#include <sys/types.h>
44ae4d9caa4f47fa6abcd641719e9f520622940c17Alexey Samsonov#include <unistd.h>
45a30c8f9eac981dcf137e84226810b760e35c7be1Kostya Serebryany#include <unwind.h>
4635a7faf1fbfac678136e79d53824672dafb7d13eAlexey Samsonov
4724e13723f8477d8c42ab8b2a7f4f69fc089842f1Evgeniy Stepanov#if !SANITIZER_ANDROID
4835a7faf1fbfac678136e79d53824672dafb7d13eAlexey Samsonov#include <sys/signal.h>
4935a7faf1fbfac678136e79d53824672dafb7d13eAlexey Samsonov#endif
50fa5c41eddf77a3614da0f62044ebf741d86aeab7Dmitry Vyukov
514bebe7bab966c82f0a8952f797ed3d490624dc62Dmitry Vyukov// <linux/time.h>
524bebe7bab966c82f0a8952f797ed3d490624dc62Dmitry Vyukovstruct kernel_timeval {
534bebe7bab966c82f0a8952f797ed3d490624dc62Dmitry Vyukov  long tv_sec;
544bebe7bab966c82f0a8952f797ed3d490624dc62Dmitry Vyukov  long tv_usec;
554bebe7bab966c82f0a8952f797ed3d490624dc62Dmitry Vyukov};
564bebe7bab966c82f0a8952f797ed3d490624dc62Dmitry Vyukov
57fa5c41eddf77a3614da0f62044ebf741d86aeab7Dmitry Vyukov// <linux/futex.h> is broken on some linux distributions.
58fa5c41eddf77a3614da0f62044ebf741d86aeab7Dmitry Vyukovconst int FUTEX_WAIT = 0;
59fa5c41eddf77a3614da0f62044ebf741d86aeab7Dmitry Vyukovconst int FUTEX_WAKE = 1;
60ae4d9caa4f47fa6abcd641719e9f520622940c17Alexey Samsonov
619d0dbbaf33e5c2fe280f141e30be497d62b703a8Kostya Serebryany// Are we using 32-bit or 64-bit syscalls?
625af39e50366f1aacbebc284f572f08ad1ad07357Kostya Serebryany// x32 (which defines __x86_64__) has SANITIZER_WORDSIZE == 32
6308bfe4988de493dd3e61d02759b3f19c42f8fb78Kostya Serebryany// but it still needs to use 64-bit syscalls.
645af39e50366f1aacbebc284f572f08ad1ad07357Kostya Serebryany#if defined(__x86_64__) || SANITIZER_WORDSIZE == 64
659d0dbbaf33e5c2fe280f141e30be497d62b703a8Kostya Serebryany# define SANITIZER_LINUX_USES_64BIT_SYSCALLS 1
669d0dbbaf33e5c2fe280f141e30be497d62b703a8Kostya Serebryany#else
679d0dbbaf33e5c2fe280f141e30be497d62b703a8Kostya Serebryany# define SANITIZER_LINUX_USES_64BIT_SYSCALLS 0
689d0dbbaf33e5c2fe280f141e30be497d62b703a8Kostya Serebryany#endif
699d0dbbaf33e5c2fe280f141e30be497d62b703a8Kostya Serebryany
70ae4d9caa4f47fa6abcd641719e9f520622940c17Alexey Samsonovnamespace __sanitizer {
71ae4d9caa4f47fa6abcd641719e9f520622940c17Alexey Samsonov
729578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne#ifdef __x86_64__
739578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne#include "sanitizer_syscall_linux_x86_64.inc"
749578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne#else
759578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne#include "sanitizer_syscall_generic.inc"
769578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne#endif
779578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne
78e5931fd7d2a74fd7fb60bd8d7f644cca51a24364Alexey Samsonov// --------------- sanitizer_libc.h
799578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourneuptr internal_mmap(void *addr, uptr length, int prot, int flags,
80ae4d9caa4f47fa6abcd641719e9f520622940c17Alexey Samsonov                    int fd, u64 offset) {
819d0dbbaf33e5c2fe280f141e30be497d62b703a8Kostya Serebryany#if SANITIZER_LINUX_USES_64BIT_SYSCALLS
829578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne  return internal_syscall(__NR_mmap, addr, length, prot, flags, fd, offset);
83ae4d9caa4f47fa6abcd641719e9f520622940c17Alexey Samsonov#else
849578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne  return internal_syscall(__NR_mmap2, addr, length, prot, flags, fd, offset);
85ae4d9caa4f47fa6abcd641719e9f520622940c17Alexey Samsonov#endif
86ae4d9caa4f47fa6abcd641719e9f520622940c17Alexey Samsonov}
87ae4d9caa4f47fa6abcd641719e9f520622940c17Alexey Samsonov
889578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourneuptr internal_munmap(void *addr, uptr length) {
899578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne  return internal_syscall(__NR_munmap, addr, length);
901f11d31faa5ed89b74f7d543b1182fe8de198be5Alexey Samsonov}
911f11d31faa5ed89b74f7d543b1182fe8de198be5Alexey Samsonov
929578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourneuptr internal_close(fd_t fd) {
939578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne  return internal_syscall(__NR_close, fd);
94a56aefd2e01940fcf88d1426f9de3d5e4b1ee203Alexey Samsonov}
95a56aefd2e01940fcf88d1426f9de3d5e4b1ee203Alexey Samsonov
969578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourneuptr internal_open(const char *filename, int flags) {
979578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne  return internal_syscall(__NR_open, filename, flags);
98ee7cc4454421a176d23442382afd9a01d36e7ad4Alexey Samsonov}
99ee7cc4454421a176d23442382afd9a01d36e7ad4Alexey Samsonov
1009578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourneuptr internal_open(const char *filename, int flags, u32 mode) {
1019578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne  return internal_syscall(__NR_open, filename, flags, mode);
102ee7cc4454421a176d23442382afd9a01d36e7ad4Alexey Samsonov}
103ee7cc4454421a176d23442382afd9a01d36e7ad4Alexey Samsonov
1049578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourneuptr OpenFile(const char *filename, bool write) {
105ee7cc4454421a176d23442382afd9a01d36e7ad4Alexey Samsonov  return internal_open(filename,
1069b8a9c1b1ce4659457178ff4c0838ac1b35ca9dcKostya Serebryany      write ? O_WRONLY | O_CREAT /*| O_CLOEXEC*/ : O_RDONLY, 0660);
107c5d465136b911bf925f2a631e2b79f1c03e8a1b0Alexey Samsonov}
108c5d465136b911bf925f2a631e2b79f1c03e8a1b0Alexey Samsonov
109a56aefd2e01940fcf88d1426f9de3d5e4b1ee203Alexey Samsonovuptr internal_read(fd_t fd, void *buf, uptr count) {
1103334e12d33261cb8f211f2f49f28ddfa027a40c3Evgeniy Stepanov  sptr res;
1119578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne  HANDLE_EINTR(res, (sptr)internal_syscall(__NR_read, fd, buf, count));
1123334e12d33261cb8f211f2f49f28ddfa027a40c3Evgeniy Stepanov  return res;
113a56aefd2e01940fcf88d1426f9de3d5e4b1ee203Alexey Samsonov}
114a56aefd2e01940fcf88d1426f9de3d5e4b1ee203Alexey Samsonov
115a56aefd2e01940fcf88d1426f9de3d5e4b1ee203Alexey Samsonovuptr internal_write(fd_t fd, const void *buf, uptr count) {
1163334e12d33261cb8f211f2f49f28ddfa027a40c3Evgeniy Stepanov  sptr res;
1179578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne  HANDLE_EINTR(res, (sptr)internal_syscall(__NR_write, fd, buf, count));
1183334e12d33261cb8f211f2f49f28ddfa027a40c3Evgeniy Stepanov  return res;
119a56aefd2e01940fcf88d1426f9de3d5e4b1ee203Alexey Samsonov}
120a56aefd2e01940fcf88d1426f9de3d5e4b1ee203Alexey Samsonov
1212be3a283939d4fc14ad86f6cd8be34b1468f22baEvgeniy Stepanov#if !SANITIZER_LINUX_USES_64BIT_SYSCALLS
1222be3a283939d4fc14ad86f6cd8be34b1468f22baEvgeniy Stepanovstatic void stat64_to_stat(struct stat64 *in, struct stat *out) {
1232be3a283939d4fc14ad86f6cd8be34b1468f22baEvgeniy Stepanov  internal_memset(out, 0, sizeof(*out));
1242be3a283939d4fc14ad86f6cd8be34b1468f22baEvgeniy Stepanov  out->st_dev = in->st_dev;
1252be3a283939d4fc14ad86f6cd8be34b1468f22baEvgeniy Stepanov  out->st_ino = in->st_ino;
1262be3a283939d4fc14ad86f6cd8be34b1468f22baEvgeniy Stepanov  out->st_mode = in->st_mode;
1272be3a283939d4fc14ad86f6cd8be34b1468f22baEvgeniy Stepanov  out->st_nlink = in->st_nlink;
1282be3a283939d4fc14ad86f6cd8be34b1468f22baEvgeniy Stepanov  out->st_uid = in->st_uid;
1292be3a283939d4fc14ad86f6cd8be34b1468f22baEvgeniy Stepanov  out->st_gid = in->st_gid;
1302be3a283939d4fc14ad86f6cd8be34b1468f22baEvgeniy Stepanov  out->st_rdev = in->st_rdev;
1312be3a283939d4fc14ad86f6cd8be34b1468f22baEvgeniy Stepanov  out->st_size = in->st_size;
1322be3a283939d4fc14ad86f6cd8be34b1468f22baEvgeniy Stepanov  out->st_blksize = in->st_blksize;
1332be3a283939d4fc14ad86f6cd8be34b1468f22baEvgeniy Stepanov  out->st_blocks = in->st_blocks;
1342be3a283939d4fc14ad86f6cd8be34b1468f22baEvgeniy Stepanov  out->st_atime = in->st_atime;
1352be3a283939d4fc14ad86f6cd8be34b1468f22baEvgeniy Stepanov  out->st_mtime = in->st_mtime;
1362be3a283939d4fc14ad86f6cd8be34b1468f22baEvgeniy Stepanov  out->st_ctime = in->st_ctime;
1372be3a283939d4fc14ad86f6cd8be34b1468f22baEvgeniy Stepanov  out->st_ino = in->st_ino;
1382be3a283939d4fc14ad86f6cd8be34b1468f22baEvgeniy Stepanov}
1392be3a283939d4fc14ad86f6cd8be34b1468f22baEvgeniy Stepanov#endif
1402be3a283939d4fc14ad86f6cd8be34b1468f22baEvgeniy Stepanov
1419578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourneuptr internal_stat(const char *path, void *buf) {
1424c9317a7b61e136f832d2ede70f557963fd46bceAlexey Samsonov#if SANITIZER_LINUX_USES_64BIT_SYSCALLS
1439578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne  return internal_syscall(__NR_stat, path, buf);
1444c9317a7b61e136f832d2ede70f557963fd46bceAlexey Samsonov#else
1452be3a283939d4fc14ad86f6cd8be34b1468f22baEvgeniy Stepanov  struct stat64 buf64;
1469578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne  int res = internal_syscall(__NR_stat64, path, &buf64);
1472be3a283939d4fc14ad86f6cd8be34b1468f22baEvgeniy Stepanov  stat64_to_stat(&buf64, (struct stat *)buf);
1482be3a283939d4fc14ad86f6cd8be34b1468f22baEvgeniy Stepanov  return res;
1494c9317a7b61e136f832d2ede70f557963fd46bceAlexey Samsonov#endif
1504c9317a7b61e136f832d2ede70f557963fd46bceAlexey Samsonov}
1514c9317a7b61e136f832d2ede70f557963fd46bceAlexey Samsonov
1529578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourneuptr internal_lstat(const char *path, void *buf) {
1534c9317a7b61e136f832d2ede70f557963fd46bceAlexey Samsonov#if SANITIZER_LINUX_USES_64BIT_SYSCALLS
1549578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne  return internal_syscall(__NR_lstat, path, buf);
1554c9317a7b61e136f832d2ede70f557963fd46bceAlexey Samsonov#else
1562be3a283939d4fc14ad86f6cd8be34b1468f22baEvgeniy Stepanov  struct stat64 buf64;
1579578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne  int res = internal_syscall(__NR_lstat64, path, &buf64);
1582be3a283939d4fc14ad86f6cd8be34b1468f22baEvgeniy Stepanov  stat64_to_stat(&buf64, (struct stat *)buf);
1592be3a283939d4fc14ad86f6cd8be34b1468f22baEvgeniy Stepanov  return res;
1604c9317a7b61e136f832d2ede70f557963fd46bceAlexey Samsonov#endif
1614c9317a7b61e136f832d2ede70f557963fd46bceAlexey Samsonov}
1624c9317a7b61e136f832d2ede70f557963fd46bceAlexey Samsonov
1639578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourneuptr internal_fstat(fd_t fd, void *buf) {
1644c9317a7b61e136f832d2ede70f557963fd46bceAlexey Samsonov#if SANITIZER_LINUX_USES_64BIT_SYSCALLS
1659578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne  return internal_syscall(__NR_fstat, fd, buf);
1664c9317a7b61e136f832d2ede70f557963fd46bceAlexey Samsonov#else
1672be3a283939d4fc14ad86f6cd8be34b1468f22baEvgeniy Stepanov  struct stat64 buf64;
1689578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne  int res = internal_syscall(__NR_fstat64, fd, &buf64);
1692be3a283939d4fc14ad86f6cd8be34b1468f22baEvgeniy Stepanov  stat64_to_stat(&buf64, (struct stat *)buf);
1702be3a283939d4fc14ad86f6cd8be34b1468f22baEvgeniy Stepanov  return res;
1714c9317a7b61e136f832d2ede70f557963fd46bceAlexey Samsonov#endif
1724c9317a7b61e136f832d2ede70f557963fd46bceAlexey Samsonov}
1734c9317a7b61e136f832d2ede70f557963fd46bceAlexey Samsonov
1748e820fcf7aafeb8101322182d742fcf99255d972Alexey Samsonovuptr internal_filesize(fd_t fd) {
175a68633fb76208137ccb807914df52758ee5ca6f0Alexey Samsonov  struct stat st;
1764c9317a7b61e136f832d2ede70f557963fd46bceAlexey Samsonov  if (internal_fstat(fd, &st))
1774c9317a7b61e136f832d2ede70f557963fd46bceAlexey Samsonov    return -1;
1788e820fcf7aafeb8101322182d742fcf99255d972Alexey Samsonov  return (uptr)st.st_size;
1798e820fcf7aafeb8101322182d742fcf99255d972Alexey Samsonov}
1808e820fcf7aafeb8101322182d742fcf99255d972Alexey Samsonov
1819578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourneuptr internal_dup2(int oldfd, int newfd) {
1829578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne  return internal_syscall(__NR_dup2, oldfd, newfd);
1838e820fcf7aafeb8101322182d742fcf99255d972Alexey Samsonov}
1848e820fcf7aafeb8101322182d742fcf99255d972Alexey Samsonov
185d1b8f588d6b712b6ff2b3d58c73d71614f520122Alexey Samsonovuptr internal_readlink(const char *path, char *buf, uptr bufsize) {
1869578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne  return internal_syscall(__NR_readlink, path, buf, bufsize);
187d1b8f588d6b712b6ff2b3d58c73d71614f520122Alexey Samsonov}
188d1b8f588d6b712b6ff2b3d58c73d71614f520122Alexey Samsonov
1899578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourneuptr internal_unlink(const char *path) {
1909578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne  return internal_syscall(__NR_unlink, path);
1916d6ab9eeea4a99370d7ab18ce80eb96091e2cf3fDmitry Vyukov}
1926d6ab9eeea4a99370d7ab18ce80eb96091e2cf3fDmitry Vyukov
1939578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourneuptr internal_sched_yield() {
1949578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne  return internal_syscall(__NR_sched_yield);
1950969bcf2c936126b1f6e636b978aade8fc207437Alexey Samsonov}
1960969bcf2c936126b1f6e636b978aade8fc207437Alexey Samsonov
197f882247088952deed954a19d745c2dd8871e2035Alexey Samsonovvoid internal__exit(int exitcode) {
1989578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne  internal_syscall(__NR_exit_group, exitcode);
199f882247088952deed954a19d745c2dd8871e2035Alexey Samsonov  Die();  // Unreachable.
200f882247088952deed954a19d745c2dd8871e2035Alexey Samsonov}
201f882247088952deed954a19d745c2dd8871e2035Alexey Samsonov
2029578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourneuptr internal_execve(const char *filename, char *const argv[],
2039578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne                     char *const envp[]) {
2049578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne  return internal_syscall(__NR_execve, filename, argv, envp);
2059578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne}
2069578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne
207e5931fd7d2a74fd7fb60bd8d7f644cca51a24364Alexey Samsonov// ----------------- sanitizer_common.h
20893b4cafd631b661b4b612ccdc0938f7f1e1c86d6Alexey Samsonovbool FileExists(const char *filename) {
20993b4cafd631b661b4b612ccdc0938f7f1e1c86d6Alexey Samsonov  struct stat st;
2102be3a283939d4fc14ad86f6cd8be34b1468f22baEvgeniy Stepanov  if (internal_stat(filename, &st))
21193b4cafd631b661b4b612ccdc0938f7f1e1c86d6Alexey Samsonov    return false;
21293b4cafd631b661b4b612ccdc0938f7f1e1c86d6Alexey Samsonov  // Sanity check: filename is a regular file.
21393b4cafd631b661b4b612ccdc0938f7f1e1c86d6Alexey Samsonov  return S_ISREG(st.st_mode);
21493b4cafd631b661b4b612ccdc0938f7f1e1c86d6Alexey Samsonov}
21593b4cafd631b661b4b612ccdc0938f7f1e1c86d6Alexey Samsonov
216e0023f74ea88efee329f68391b70f8adc6b21617Dmitry Vyukovuptr GetTid() {
2179578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne  return internal_syscall(__NR_gettid);
218e0023f74ea88efee329f68391b70f8adc6b21617Dmitry Vyukov}
219e0023f74ea88efee329f68391b70f8adc6b21617Dmitry Vyukov
2204bebe7bab966c82f0a8952f797ed3d490624dc62Dmitry Vyukovu64 NanoTime() {
221e57f26b5c99cedd56de76f3a10cadcecece768bdDmitry Vyukov  kernel_timeval tv = {};
2229578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne  internal_syscall(__NR_gettimeofday, &tv, 0);
2234bebe7bab966c82f0a8952f797ed3d490624dc62Dmitry Vyukov  return (u64)tv.tv_sec * 1000*1000*1000 + tv.tv_usec * 1000;
2244bebe7bab966c82f0a8952f797ed3d490624dc62Dmitry Vyukov}
2254bebe7bab966c82f0a8952f797ed3d490624dc62Dmitry Vyukov
2263dbeabb3446f203156ae03d957de9bdf50933ae4Alexey Samsonov// Like getenv, but reads env directly from /proc and does not use libc.
2273dbeabb3446f203156ae03d957de9bdf50933ae4Alexey Samsonov// This function should be called first inside __asan_init.
2283dbeabb3446f203156ae03d957de9bdf50933ae4Alexey Samsonovconst char *GetEnv(const char *name) {
2293dbeabb3446f203156ae03d957de9bdf50933ae4Alexey Samsonov  static char *environ;
2303dbeabb3446f203156ae03d957de9bdf50933ae4Alexey Samsonov  static uptr len;
2313dbeabb3446f203156ae03d957de9bdf50933ae4Alexey Samsonov  static bool inited;
2323dbeabb3446f203156ae03d957de9bdf50933ae4Alexey Samsonov  if (!inited) {
2333dbeabb3446f203156ae03d957de9bdf50933ae4Alexey Samsonov    inited = true;
2343dbeabb3446f203156ae03d957de9bdf50933ae4Alexey Samsonov    uptr environ_size;
2353dbeabb3446f203156ae03d957de9bdf50933ae4Alexey Samsonov    len = ReadFileToBuffer("/proc/self/environ",
2363dbeabb3446f203156ae03d957de9bdf50933ae4Alexey Samsonov                           &environ, &environ_size, 1 << 26);
2373dbeabb3446f203156ae03d957de9bdf50933ae4Alexey Samsonov  }
2383dbeabb3446f203156ae03d957de9bdf50933ae4Alexey Samsonov  if (!environ || len == 0) return 0;
2393dbeabb3446f203156ae03d957de9bdf50933ae4Alexey Samsonov  uptr namelen = internal_strlen(name);
2403dbeabb3446f203156ae03d957de9bdf50933ae4Alexey Samsonov  const char *p = environ;
2413dbeabb3446f203156ae03d957de9bdf50933ae4Alexey Samsonov  while (*p != '\0') {  // will happen at the \0\0 that terminates the buffer
2423dbeabb3446f203156ae03d957de9bdf50933ae4Alexey Samsonov    // proc file has the format NAME=value\0NAME=value\0NAME=value\0...
2433dbeabb3446f203156ae03d957de9bdf50933ae4Alexey Samsonov    const char* endp =
2443dbeabb3446f203156ae03d957de9bdf50933ae4Alexey Samsonov        (char*)internal_memchr(p, '\0', len - (p - environ));
2453dbeabb3446f203156ae03d957de9bdf50933ae4Alexey Samsonov    if (endp == 0)  // this entry isn't NUL terminated
2463dbeabb3446f203156ae03d957de9bdf50933ae4Alexey Samsonov      return 0;
2473dbeabb3446f203156ae03d957de9bdf50933ae4Alexey Samsonov    else if (!internal_memcmp(p, name, namelen) && p[namelen] == '=')  // Match.
2483dbeabb3446f203156ae03d957de9bdf50933ae4Alexey Samsonov      return p + namelen + 1;  // point after =
2493dbeabb3446f203156ae03d957de9bdf50933ae4Alexey Samsonov    p = endp + 1;
2503dbeabb3446f203156ae03d957de9bdf50933ae4Alexey Samsonov  }
2513dbeabb3446f203156ae03d957de9bdf50933ae4Alexey Samsonov  return 0;  // Not found.
2523dbeabb3446f203156ae03d957de9bdf50933ae4Alexey Samsonov}
2533dbeabb3446f203156ae03d957de9bdf50933ae4Alexey Samsonov
254eab061185ec0046d447b298a1dff84f028202a3cEvgeniy Stepanovextern "C" {
2553c80c6c574850106481f82b9e23d1c728458d4a9Timur Iskhodzhanov  SANITIZER_WEAK_ATTRIBUTE extern void *__libc_stack_end;
256eab061185ec0046d447b298a1dff84f028202a3cEvgeniy Stepanov}
257eab061185ec0046d447b298a1dff84f028202a3cEvgeniy Stepanov
25826337b60b1d551c4744454edd8e5ef3c479e3467Peter Collingbourne#if !SANITIZER_GO
25923709c9ad9ac7c45de288f5260403426bf932db7Peter Collingbournestatic void ReadNullSepFileToArray(const char *path, char ***arr,
26023709c9ad9ac7c45de288f5260403426bf932db7Peter Collingbourne                                   int arr_size) {
26123709c9ad9ac7c45de288f5260403426bf932db7Peter Collingbourne  char *buff;
262d7e5bb4043adf4756e6f8cfe0f5a3165b185474dAlexey Samsonov  uptr buff_size = 0;
26323709c9ad9ac7c45de288f5260403426bf932db7Peter Collingbourne  *arr = (char **)MmapOrDie(arr_size * sizeof(char *), "NullSepFileArray");
26423709c9ad9ac7c45de288f5260403426bf932db7Peter Collingbourne  ReadFileToBuffer(path, &buff, &buff_size, 1024 * 1024);
26523709c9ad9ac7c45de288f5260403426bf932db7Peter Collingbourne  (*arr)[0] = buff;
26623709c9ad9ac7c45de288f5260403426bf932db7Peter Collingbourne  int count, i;
26723709c9ad9ac7c45de288f5260403426bf932db7Peter Collingbourne  for (count = 1, i = 1; ; i++) {
268d7e5bb4043adf4756e6f8cfe0f5a3165b185474dAlexey Samsonov    if (buff[i] == 0) {
269d7e5bb4043adf4756e6f8cfe0f5a3165b185474dAlexey Samsonov      if (buff[i+1] == 0) break;
27023709c9ad9ac7c45de288f5260403426bf932db7Peter Collingbourne      (*arr)[count] = &buff[i+1];
27123709c9ad9ac7c45de288f5260403426bf932db7Peter Collingbourne      CHECK_LE(count, arr_size - 1);  // FIXME: make this more flexible.
27223709c9ad9ac7c45de288f5260403426bf932db7Peter Collingbourne      count++;
273d7e5bb4043adf4756e6f8cfe0f5a3165b185474dAlexey Samsonov    }
274d7e5bb4043adf4756e6f8cfe0f5a3165b185474dAlexey Samsonov  }
27523709c9ad9ac7c45de288f5260403426bf932db7Peter Collingbourne  (*arr)[count] = 0;
27623709c9ad9ac7c45de288f5260403426bf932db7Peter Collingbourne}
27726337b60b1d551c4744454edd8e5ef3c479e3467Peter Collingbourne#endif
27823709c9ad9ac7c45de288f5260403426bf932db7Peter Collingbourne
27926337b60b1d551c4744454edd8e5ef3c479e3467Peter Collingbournestatic void GetArgsAndEnv(char*** argv, char*** envp) {
28026337b60b1d551c4744454edd8e5ef3c479e3467Peter Collingbourne#if !SANITIZER_GO
28126337b60b1d551c4744454edd8e5ef3c479e3467Peter Collingbourne  if (&__libc_stack_end) {
28226337b60b1d551c4744454edd8e5ef3c479e3467Peter Collingbourne#endif
28326337b60b1d551c4744454edd8e5ef3c479e3467Peter Collingbourne    uptr* stack_end = (uptr*)__libc_stack_end;
28426337b60b1d551c4744454edd8e5ef3c479e3467Peter Collingbourne    int argc = *stack_end;
28526337b60b1d551c4744454edd8e5ef3c479e3467Peter Collingbourne    *argv = (char**)(stack_end + 1);
28626337b60b1d551c4744454edd8e5ef3c479e3467Peter Collingbourne    *envp = (char**)(stack_end + argc + 2);
28726337b60b1d551c4744454edd8e5ef3c479e3467Peter Collingbourne#if !SANITIZER_GO
28826337b60b1d551c4744454edd8e5ef3c479e3467Peter Collingbourne  } else {
28926337b60b1d551c4744454edd8e5ef3c479e3467Peter Collingbourne    static const int kMaxArgv = 2000, kMaxEnvp = 2000;
29026337b60b1d551c4744454edd8e5ef3c479e3467Peter Collingbourne    ReadNullSepFileToArray("/proc/self/cmdline", argv, kMaxArgv);
29126337b60b1d551c4744454edd8e5ef3c479e3467Peter Collingbourne    ReadNullSepFileToArray("/proc/self/environ", envp, kMaxEnvp);
29226337b60b1d551c4744454edd8e5ef3c479e3467Peter Collingbourne  }
29326337b60b1d551c4744454edd8e5ef3c479e3467Peter Collingbourne#endif
294eab061185ec0046d447b298a1dff84f028202a3cEvgeniy Stepanov}
295eab061185ec0046d447b298a1dff84f028202a3cEvgeniy Stepanov
296eab061185ec0046d447b298a1dff84f028202a3cEvgeniy Stepanovvoid ReExec() {
29723709c9ad9ac7c45de288f5260403426bf932db7Peter Collingbourne  char **argv, **envp;
298eab061185ec0046d447b298a1dff84f028202a3cEvgeniy Stepanov  GetArgsAndEnv(&argv, &envp);
2999578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne  uptr rv = internal_execve("/proc/self/exe", argv, envp);
3009578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne  int rverrno;
3019578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne  CHECK_EQ(internal_iserror(rv, &rverrno), true);
3029578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne  Printf("execve failed, errno %d\n", rverrno);
303f35eae83757946decb312deab3f0fe155fe5d580Evgeniy Stepanov  Die();
304d7e5bb4043adf4756e6f8cfe0f5a3165b185474dAlexey Samsonov}
305d7e5bb4043adf4756e6f8cfe0f5a3165b185474dAlexey Samsonov
30625742574510cfb41b97e32f63f107fbb9b328d13Alexander Potapenkovoid PrepareForSandboxing() {
30725742574510cfb41b97e32f63f107fbb9b328d13Alexander Potapenko  // Some kinds of sandboxes may forbid filesystem access, so we won't be able
30825742574510cfb41b97e32f63f107fbb9b328d13Alexander Potapenko  // to read the file mappings from /proc/self/maps. Luckily, neither the
30925742574510cfb41b97e32f63f107fbb9b328d13Alexander Potapenko  // process will be able to load additional libraries, so it's fine to use the
31025742574510cfb41b97e32f63f107fbb9b328d13Alexander Potapenko  // cached mappings.
31125742574510cfb41b97e32f63f107fbb9b328d13Alexander Potapenko  MemoryMappingLayout::CacheMemoryMappings();
3125ce93fc96ab5e2defd85890da63b51cc4c57a2afAlexander Potapenko  // Same for /proc/self/exe in the symbolizer.
313cac631e3a63ec6c8a74008fe358af9c4b2306582Alexey Samsonov#if !SANITIZER_GO
3147847d77b246635211c3bf465421d49d7af5226c1Alexey Samsonov  getSymbolizer()->PrepareForSandboxing();
315cac631e3a63ec6c8a74008fe358af9c4b2306582Alexey Samsonov#endif
31625742574510cfb41b97e32f63f107fbb9b328d13Alexander Potapenko}
31725742574510cfb41b97e32f63f107fbb9b328d13Alexander Potapenko
318e5931fd7d2a74fd7fb60bd8d7f644cca51a24364Alexey Samsonov// ----------------- sanitizer_procmaps.h
319286dd3f8afe6700e5dd9b0bdb7afd23121c98c12Dmitry Vyukov// Linker initialized.
320286dd3f8afe6700e5dd9b0bdb7afd23121c98c12Dmitry VyukovProcSelfMapsBuff MemoryMappingLayout::cached_proc_self_maps_;
321ad91267d45fef531c1082ab7974e4cc78aba5280Alexander PotapenkoStaticSpinMutex MemoryMappingLayout::cache_lock_;  // Linker initialized.
32293da8b6a5e0ed2ca621897504c5d06449b3d7077Alexander Potapenko
3239ae2883d88dd28b9c5dc862107e6e6d12a35926eAlexander PotapenkoMemoryMappingLayout::MemoryMappingLayout(bool cache_enabled) {
324ad91267d45fef531c1082ab7974e4cc78aba5280Alexander Potapenko  proc_self_maps_.len =
325ad91267d45fef531c1082ab7974e4cc78aba5280Alexander Potapenko      ReadFileToBuffer("/proc/self/maps", &proc_self_maps_.data,
326ad91267d45fef531c1082ab7974e4cc78aba5280Alexander Potapenko                       &proc_self_maps_.mmaped_size, 1 << 26);
3279ae2883d88dd28b9c5dc862107e6e6d12a35926eAlexander Potapenko  if (cache_enabled) {
3289ae2883d88dd28b9c5dc862107e6e6d12a35926eAlexander Potapenko    if (proc_self_maps_.mmaped_size == 0) {
3299ae2883d88dd28b9c5dc862107e6e6d12a35926eAlexander Potapenko      LoadFromCache();
3309ae2883d88dd28b9c5dc862107e6e6d12a35926eAlexander Potapenko      CHECK_GT(proc_self_maps_.len, 0);
3319ae2883d88dd28b9c5dc862107e6e6d12a35926eAlexander Potapenko    }
3329ae2883d88dd28b9c5dc862107e6e6d12a35926eAlexander Potapenko  } else {
3339ae2883d88dd28b9c5dc862107e6e6d12a35926eAlexander Potapenko    CHECK_GT(proc_self_maps_.mmaped_size, 0);
33493da8b6a5e0ed2ca621897504c5d06449b3d7077Alexander Potapenko  }
3356895adc39c4e09371154c8037366ad4464163ed0Alexey Samsonov  Reset();
33693da8b6a5e0ed2ca621897504c5d06449b3d7077Alexander Potapenko  // FIXME: in the future we may want to cache the mappings on demand only.
3379ae2883d88dd28b9c5dc862107e6e6d12a35926eAlexander Potapenko  if (cache_enabled)
3389ae2883d88dd28b9c5dc862107e6e6d12a35926eAlexander Potapenko    CacheMemoryMappings();
3396895adc39c4e09371154c8037366ad4464163ed0Alexey Samsonov}
3406895adc39c4e09371154c8037366ad4464163ed0Alexey Samsonov
341e1f5dac9296df08ff83ae5fca51ce4da995b55cfAlexey SamsonovMemoryMappingLayout::~MemoryMappingLayout() {
3427385f8b8b8723064910cf9737dc929e90aeac548Alexander Potapenko  // Only unmap the buffer if it is different from the cached one. Otherwise
3437385f8b8b8723064910cf9737dc929e90aeac548Alexander Potapenko  // it will be unmapped when the cache is refreshed.
3447385f8b8b8723064910cf9737dc929e90aeac548Alexander Potapenko  if (proc_self_maps_.data != cached_proc_self_maps_.data) {
3457385f8b8b8723064910cf9737dc929e90aeac548Alexander Potapenko    UnmapOrDie(proc_self_maps_.data, proc_self_maps_.mmaped_size);
3467385f8b8b8723064910cf9737dc929e90aeac548Alexander Potapenko  }
3476895adc39c4e09371154c8037366ad4464163ed0Alexey Samsonov}
3486895adc39c4e09371154c8037366ad4464163ed0Alexey Samsonov
349e1f5dac9296df08ff83ae5fca51ce4da995b55cfAlexey Samsonovvoid MemoryMappingLayout::Reset() {
350ad91267d45fef531c1082ab7974e4cc78aba5280Alexander Potapenko  current_ = proc_self_maps_.data;
3516895adc39c4e09371154c8037366ad4464163ed0Alexey Samsonov}
3526895adc39c4e09371154c8037366ad4464163ed0Alexey Samsonov
35393da8b6a5e0ed2ca621897504c5d06449b3d7077Alexander Potapenko// static
35493da8b6a5e0ed2ca621897504c5d06449b3d7077Alexander Potapenkovoid MemoryMappingLayout::CacheMemoryMappings() {
35593da8b6a5e0ed2ca621897504c5d06449b3d7077Alexander Potapenko  SpinMutexLock l(&cache_lock_);
35693da8b6a5e0ed2ca621897504c5d06449b3d7077Alexander Potapenko  // Don't invalidate the cache if the mappings are unavailable.
357ad91267d45fef531c1082ab7974e4cc78aba5280Alexander Potapenko  ProcSelfMapsBuff old_proc_self_maps;
358ad91267d45fef531c1082ab7974e4cc78aba5280Alexander Potapenko  old_proc_self_maps = cached_proc_self_maps_;
359ad91267d45fef531c1082ab7974e4cc78aba5280Alexander Potapenko  cached_proc_self_maps_.len =
360ad91267d45fef531c1082ab7974e4cc78aba5280Alexander Potapenko      ReadFileToBuffer("/proc/self/maps", &cached_proc_self_maps_.data,
361ad91267d45fef531c1082ab7974e4cc78aba5280Alexander Potapenko                       &cached_proc_self_maps_.mmaped_size, 1 << 26);
362ad91267d45fef531c1082ab7974e4cc78aba5280Alexander Potapenko  if (cached_proc_self_maps_.mmaped_size == 0) {
363ad91267d45fef531c1082ab7974e4cc78aba5280Alexander Potapenko    cached_proc_self_maps_ = old_proc_self_maps;
36493da8b6a5e0ed2ca621897504c5d06449b3d7077Alexander Potapenko  } else {
365ad91267d45fef531c1082ab7974e4cc78aba5280Alexander Potapenko    if (old_proc_self_maps.mmaped_size) {
366ad91267d45fef531c1082ab7974e4cc78aba5280Alexander Potapenko      UnmapOrDie(old_proc_self_maps.data,
367ad91267d45fef531c1082ab7974e4cc78aba5280Alexander Potapenko                 old_proc_self_maps.mmaped_size);
36893da8b6a5e0ed2ca621897504c5d06449b3d7077Alexander Potapenko    }
36993da8b6a5e0ed2ca621897504c5d06449b3d7077Alexander Potapenko  }
37093da8b6a5e0ed2ca621897504c5d06449b3d7077Alexander Potapenko}
37193da8b6a5e0ed2ca621897504c5d06449b3d7077Alexander Potapenko
37293da8b6a5e0ed2ca621897504c5d06449b3d7077Alexander Potapenkovoid MemoryMappingLayout::LoadFromCache() {
37393da8b6a5e0ed2ca621897504c5d06449b3d7077Alexander Potapenko  SpinMutexLock l(&cache_lock_);
374ad91267d45fef531c1082ab7974e4cc78aba5280Alexander Potapenko  if (cached_proc_self_maps_.data) {
375286dd3f8afe6700e5dd9b0bdb7afd23121c98c12Dmitry Vyukov    proc_self_maps_ = cached_proc_self_maps_;
37693da8b6a5e0ed2ca621897504c5d06449b3d7077Alexander Potapenko  }
37793da8b6a5e0ed2ca621897504c5d06449b3d7077Alexander Potapenko}
37893da8b6a5e0ed2ca621897504c5d06449b3d7077Alexander Potapenko
379a4e4744778e6b3067f5cf223cf28bb586c1ecf67Kostya Serebryany// Parse a hex value in str and update str.
380a4e4744778e6b3067f5cf223cf28bb586c1ecf67Kostya Serebryanystatic uptr ParseHex(char **str) {
381a4e4744778e6b3067f5cf223cf28bb586c1ecf67Kostya Serebryany  uptr x = 0;
382a4e4744778e6b3067f5cf223cf28bb586c1ecf67Kostya Serebryany  char *s;
383a4e4744778e6b3067f5cf223cf28bb586c1ecf67Kostya Serebryany  for (s = *str; ; s++) {
384a4e4744778e6b3067f5cf223cf28bb586c1ecf67Kostya Serebryany    char c = *s;
385a4e4744778e6b3067f5cf223cf28bb586c1ecf67Kostya Serebryany    uptr v = 0;
386a4e4744778e6b3067f5cf223cf28bb586c1ecf67Kostya Serebryany    if (c >= '0' && c <= '9')
387a4e4744778e6b3067f5cf223cf28bb586c1ecf67Kostya Serebryany      v = c - '0';
388a4e4744778e6b3067f5cf223cf28bb586c1ecf67Kostya Serebryany    else if (c >= 'a' && c <= 'f')
389a4e4744778e6b3067f5cf223cf28bb586c1ecf67Kostya Serebryany      v = c - 'a' + 10;
390a4e4744778e6b3067f5cf223cf28bb586c1ecf67Kostya Serebryany    else if (c >= 'A' && c <= 'F')
391a4e4744778e6b3067f5cf223cf28bb586c1ecf67Kostya Serebryany      v = c - 'A' + 10;
392a4e4744778e6b3067f5cf223cf28bb586c1ecf67Kostya Serebryany    else
393a4e4744778e6b3067f5cf223cf28bb586c1ecf67Kostya Serebryany      break;
394a4e4744778e6b3067f5cf223cf28bb586c1ecf67Kostya Serebryany    x = x * 16 + v;
395a4e4744778e6b3067f5cf223cf28bb586c1ecf67Kostya Serebryany  }
396a4e4744778e6b3067f5cf223cf28bb586c1ecf67Kostya Serebryany  *str = s;
397a4e4744778e6b3067f5cf223cf28bb586c1ecf67Kostya Serebryany  return x;
398a4e4744778e6b3067f5cf223cf28bb586c1ecf67Kostya Serebryany}
399a4e4744778e6b3067f5cf223cf28bb586c1ecf67Kostya Serebryany
400ab11e0b10d077945a6e681766b41e12ac6aeb0f0Alexey Samsonovstatic bool IsOneOf(char c, char c1, char c2) {
401a4e4744778e6b3067f5cf223cf28bb586c1ecf67Kostya Serebryany  return c == c1 || c == c2;
402a4e4744778e6b3067f5cf223cf28bb586c1ecf67Kostya Serebryany}
403a4e4744778e6b3067f5cf223cf28bb586c1ecf67Kostya Serebryany
404a4e4744778e6b3067f5cf223cf28bb586c1ecf67Kostya Serebryanystatic bool IsDecimal(char c) {
405a4e4744778e6b3067f5cf223cf28bb586c1ecf67Kostya Serebryany  return c >= '0' && c <= '9';
406a4e4744778e6b3067f5cf223cf28bb586c1ecf67Kostya Serebryany}
407a4e4744778e6b3067f5cf223cf28bb586c1ecf67Kostya Serebryany
4082e13ca86c9ce926e6fefd528892592326478ac6cAlexander Potapenkostatic bool IsHex(char c) {
4092e13ca86c9ce926e6fefd528892592326478ac6cAlexander Potapenko  return (c >= '0' && c <= '9')
4102e13ca86c9ce926e6fefd528892592326478ac6cAlexander Potapenko      || (c >= 'a' && c <= 'f');
4112e13ca86c9ce926e6fefd528892592326478ac6cAlexander Potapenko}
4122e13ca86c9ce926e6fefd528892592326478ac6cAlexander Potapenko
4132e13ca86c9ce926e6fefd528892592326478ac6cAlexander Potapenkostatic uptr ReadHex(const char *p) {
4142e13ca86c9ce926e6fefd528892592326478ac6cAlexander Potapenko  uptr v = 0;
4152e13ca86c9ce926e6fefd528892592326478ac6cAlexander Potapenko  for (; IsHex(p[0]); p++) {
4162e13ca86c9ce926e6fefd528892592326478ac6cAlexander Potapenko    if (p[0] >= '0' && p[0] <= '9')
4172e13ca86c9ce926e6fefd528892592326478ac6cAlexander Potapenko      v = v * 16 + p[0] - '0';
4182e13ca86c9ce926e6fefd528892592326478ac6cAlexander Potapenko    else
4192e13ca86c9ce926e6fefd528892592326478ac6cAlexander Potapenko      v = v * 16 + p[0] - 'a' + 10;
4202e13ca86c9ce926e6fefd528892592326478ac6cAlexander Potapenko  }
4212e13ca86c9ce926e6fefd528892592326478ac6cAlexander Potapenko  return v;
4222e13ca86c9ce926e6fefd528892592326478ac6cAlexander Potapenko}
4232e13ca86c9ce926e6fefd528892592326478ac6cAlexander Potapenko
4242e13ca86c9ce926e6fefd528892592326478ac6cAlexander Potapenkostatic uptr ReadDecimal(const char *p) {
4252e13ca86c9ce926e6fefd528892592326478ac6cAlexander Potapenko  uptr v = 0;
4262e13ca86c9ce926e6fefd528892592326478ac6cAlexander Potapenko  for (; IsDecimal(p[0]); p++)
4272e13ca86c9ce926e6fefd528892592326478ac6cAlexander Potapenko    v = v * 10 + p[0] - '0';
4282e13ca86c9ce926e6fefd528892592326478ac6cAlexander Potapenko  return v;
4292e13ca86c9ce926e6fefd528892592326478ac6cAlexander Potapenko}
4302e13ca86c9ce926e6fefd528892592326478ac6cAlexander Potapenko
4312e13ca86c9ce926e6fefd528892592326478ac6cAlexander Potapenko
432e1f5dac9296df08ff83ae5fca51ce4da995b55cfAlexey Samsonovbool MemoryMappingLayout::Next(uptr *start, uptr *end, uptr *offset,
43345717c9d5e39a434749ae10509111f9df1b2cdf4Alexey Samsonov                               char filename[], uptr filename_size,
43445717c9d5e39a434749ae10509111f9df1b2cdf4Alexey Samsonov                               uptr *protection) {
435ad91267d45fef531c1082ab7974e4cc78aba5280Alexander Potapenko  char *last = proc_self_maps_.data + proc_self_maps_.len;
4366895adc39c4e09371154c8037366ad4464163ed0Alexey Samsonov  if (current_ >= last) return false;
4376895adc39c4e09371154c8037366ad4464163ed0Alexey Samsonov  uptr dummy;
4386895adc39c4e09371154c8037366ad4464163ed0Alexey Samsonov  if (!start) start = &dummy;
4396895adc39c4e09371154c8037366ad4464163ed0Alexey Samsonov  if (!end) end = &dummy;
4406895adc39c4e09371154c8037366ad4464163ed0Alexey Samsonov  if (!offset) offset = &dummy;
4416895adc39c4e09371154c8037366ad4464163ed0Alexey Samsonov  char *next_line = (char*)internal_memchr(current_, '\n', last - current_);
4426895adc39c4e09371154c8037366ad4464163ed0Alexey Samsonov  if (next_line == 0)
4436895adc39c4e09371154c8037366ad4464163ed0Alexey Samsonov    next_line = last;
444a4e4744778e6b3067f5cf223cf28bb586c1ecf67Kostya Serebryany  // Example: 08048000-08056000 r-xp 00000000 03:0c 64593   /foo/bar
445a4e4744778e6b3067f5cf223cf28bb586c1ecf67Kostya Serebryany  *start = ParseHex(&current_);
446bb8a9511bc748d6a4fd601d713bda584ef7bb772Kostya Serebryany  CHECK_EQ(*current_++, '-');
447a4e4744778e6b3067f5cf223cf28bb586c1ecf67Kostya Serebryany  *end = ParseHex(&current_);
448bb8a9511bc748d6a4fd601d713bda584ef7bb772Kostya Serebryany  CHECK_EQ(*current_++, ' ');
44945717c9d5e39a434749ae10509111f9df1b2cdf4Alexey Samsonov  uptr local_protection = 0;
450ab11e0b10d077945a6e681766b41e12ac6aeb0f0Alexey Samsonov  CHECK(IsOneOf(*current_, '-', 'r'));
45145717c9d5e39a434749ae10509111f9df1b2cdf4Alexey Samsonov  if (*current_++ == 'r')
45245717c9d5e39a434749ae10509111f9df1b2cdf4Alexey Samsonov    local_protection |= kProtectionRead;
453ab11e0b10d077945a6e681766b41e12ac6aeb0f0Alexey Samsonov  CHECK(IsOneOf(*current_, '-', 'w'));
45445717c9d5e39a434749ae10509111f9df1b2cdf4Alexey Samsonov  if (*current_++ == 'w')
45545717c9d5e39a434749ae10509111f9df1b2cdf4Alexey Samsonov    local_protection |= kProtectionWrite;
456ab11e0b10d077945a6e681766b41e12ac6aeb0f0Alexey Samsonov  CHECK(IsOneOf(*current_, '-', 'x'));
45745717c9d5e39a434749ae10509111f9df1b2cdf4Alexey Samsonov  if (*current_++ == 'x')
45845717c9d5e39a434749ae10509111f9df1b2cdf4Alexey Samsonov    local_protection |= kProtectionExecute;
459ab11e0b10d077945a6e681766b41e12ac6aeb0f0Alexey Samsonov  CHECK(IsOneOf(*current_, 's', 'p'));
46045717c9d5e39a434749ae10509111f9df1b2cdf4Alexey Samsonov  if (*current_++ == 's')
46145717c9d5e39a434749ae10509111f9df1b2cdf4Alexey Samsonov    local_protection |= kProtectionShared;
46245717c9d5e39a434749ae10509111f9df1b2cdf4Alexey Samsonov  if (protection) {
46345717c9d5e39a434749ae10509111f9df1b2cdf4Alexey Samsonov    *protection = local_protection;
46445717c9d5e39a434749ae10509111f9df1b2cdf4Alexey Samsonov  }
465bb8a9511bc748d6a4fd601d713bda584ef7bb772Kostya Serebryany  CHECK_EQ(*current_++, ' ');
466a4e4744778e6b3067f5cf223cf28bb586c1ecf67Kostya Serebryany  *offset = ParseHex(&current_);
467bb8a9511bc748d6a4fd601d713bda584ef7bb772Kostya Serebryany  CHECK_EQ(*current_++, ' ');
468a4e4744778e6b3067f5cf223cf28bb586c1ecf67Kostya Serebryany  ParseHex(&current_);
469bb8a9511bc748d6a4fd601d713bda584ef7bb772Kostya Serebryany  CHECK_EQ(*current_++, ':');
470a4e4744778e6b3067f5cf223cf28bb586c1ecf67Kostya Serebryany  ParseHex(&current_);
471bb8a9511bc748d6a4fd601d713bda584ef7bb772Kostya Serebryany  CHECK_EQ(*current_++, ' ');
472a4e4744778e6b3067f5cf223cf28bb586c1ecf67Kostya Serebryany  while (IsDecimal(*current_))
473a4e4744778e6b3067f5cf223cf28bb586c1ecf67Kostya Serebryany    current_++;
4742592a0614d91fe947cd04fe7e2719d273e3e4880Kostya Serebryany  // Qemu may lack the trailing space.
4752592a0614d91fe947cd04fe7e2719d273e3e4880Kostya Serebryany  // http://code.google.com/p/address-sanitizer/issues/detail?id=160
4762592a0614d91fe947cd04fe7e2719d273e3e4880Kostya Serebryany  // CHECK_EQ(*current_++, ' ');
4776895adc39c4e09371154c8037366ad4464163ed0Alexey Samsonov  // Skip spaces.
4786895adc39c4e09371154c8037366ad4464163ed0Alexey Samsonov  while (current_ < next_line && *current_ == ' ')
4796895adc39c4e09371154c8037366ad4464163ed0Alexey Samsonov    current_++;
4806895adc39c4e09371154c8037366ad4464163ed0Alexey Samsonov  // Fill in the filename.
4816895adc39c4e09371154c8037366ad4464163ed0Alexey Samsonov  uptr i = 0;
4826895adc39c4e09371154c8037366ad4464163ed0Alexey Samsonov  while (current_ < next_line) {
4836895adc39c4e09371154c8037366ad4464163ed0Alexey Samsonov    if (filename && i < filename_size - 1)
4846895adc39c4e09371154c8037366ad4464163ed0Alexey Samsonov      filename[i++] = *current_;
4856895adc39c4e09371154c8037366ad4464163ed0Alexey Samsonov    current_++;
4866895adc39c4e09371154c8037366ad4464163ed0Alexey Samsonov  }
4876895adc39c4e09371154c8037366ad4464163ed0Alexey Samsonov  if (filename && i < filename_size)
4886895adc39c4e09371154c8037366ad4464163ed0Alexey Samsonov    filename[i] = 0;
4896895adc39c4e09371154c8037366ad4464163ed0Alexey Samsonov  current_ = next_line + 1;
4906895adc39c4e09371154c8037366ad4464163ed0Alexey Samsonov  return true;
4916895adc39c4e09371154c8037366ad4464163ed0Alexey Samsonov}
4926895adc39c4e09371154c8037366ad4464163ed0Alexey Samsonov
493e1f5dac9296df08ff83ae5fca51ce4da995b55cfAlexey Samsonov// Gets the object name and the offset by walking MemoryMappingLayout.
494e1f5dac9296df08ff83ae5fca51ce4da995b55cfAlexey Samsonovbool MemoryMappingLayout::GetObjectNameAndOffset(uptr addr, uptr *offset,
495e1f5dac9296df08ff83ae5fca51ce4da995b55cfAlexey Samsonov                                                 char filename[],
49645717c9d5e39a434749ae10509111f9df1b2cdf4Alexey Samsonov                                                 uptr filename_size,
49745717c9d5e39a434749ae10509111f9df1b2cdf4Alexey Samsonov                                                 uptr *protection) {
49845717c9d5e39a434749ae10509111f9df1b2cdf4Alexey Samsonov  return IterateForObjectNameAndOffset(addr, offset, filename, filename_size,
49945717c9d5e39a434749ae10509111f9df1b2cdf4Alexey Samsonov                                       protection);
5006895adc39c4e09371154c8037366ad4464163ed0Alexey Samsonov}
5016895adc39c4e09371154c8037366ad4464163ed0Alexey Samsonov
5022e13ca86c9ce926e6fefd528892592326478ac6cAlexander Potapenkovoid GetMemoryProfile(fill_profile_f cb, uptr *stats, uptr stats_size) {
5032e13ca86c9ce926e6fefd528892592326478ac6cAlexander Potapenko  char *smaps = 0;
5042e13ca86c9ce926e6fefd528892592326478ac6cAlexander Potapenko  uptr smaps_cap = 0;
5052e13ca86c9ce926e6fefd528892592326478ac6cAlexander Potapenko  uptr smaps_len = ReadFileToBuffer("/proc/self/smaps",
5062e13ca86c9ce926e6fefd528892592326478ac6cAlexander Potapenko      &smaps, &smaps_cap, 64<<20);
5072e13ca86c9ce926e6fefd528892592326478ac6cAlexander Potapenko  uptr start = 0;
5082e13ca86c9ce926e6fefd528892592326478ac6cAlexander Potapenko  bool file = false;
5092e13ca86c9ce926e6fefd528892592326478ac6cAlexander Potapenko  const char *pos = smaps;
5102e13ca86c9ce926e6fefd528892592326478ac6cAlexander Potapenko  while (pos < smaps + smaps_len) {
5112e13ca86c9ce926e6fefd528892592326478ac6cAlexander Potapenko    if (IsHex(pos[0])) {
5122e13ca86c9ce926e6fefd528892592326478ac6cAlexander Potapenko      start = ReadHex(pos);
5132e13ca86c9ce926e6fefd528892592326478ac6cAlexander Potapenko      for (; *pos != '/' && *pos > '\n'; pos++) {}
5142e13ca86c9ce926e6fefd528892592326478ac6cAlexander Potapenko      file = *pos == '/';
5152e13ca86c9ce926e6fefd528892592326478ac6cAlexander Potapenko    } else if (internal_strncmp(pos, "Rss:", 4) == 0) {
5162e13ca86c9ce926e6fefd528892592326478ac6cAlexander Potapenko      for (; *pos < '0' || *pos > '9'; pos++) {}
5172e13ca86c9ce926e6fefd528892592326478ac6cAlexander Potapenko      uptr rss = ReadDecimal(pos) * 1024;
5182e13ca86c9ce926e6fefd528892592326478ac6cAlexander Potapenko      cb(start, rss, file, stats, stats_size);
5192e13ca86c9ce926e6fefd528892592326478ac6cAlexander Potapenko    }
5202e13ca86c9ce926e6fefd528892592326478ac6cAlexander Potapenko    while (*pos++ != '\n') {}
5212e13ca86c9ce926e6fefd528892592326478ac6cAlexander Potapenko  }
5222e13ca86c9ce926e6fefd528892592326478ac6cAlexander Potapenko  UnmapOrDie(smaps, smaps_cap);
5232e13ca86c9ce926e6fefd528892592326478ac6cAlexander Potapenko}
5242e13ca86c9ce926e6fefd528892592326478ac6cAlexander Potapenko
525f4f51f2cc6fa936f0c65577f82e6b62989d546eeDmitry Vyukovenum MutexState {
526f4f51f2cc6fa936f0c65577f82e6b62989d546eeDmitry Vyukov  MtxUnlocked = 0,
527f4f51f2cc6fa936f0c65577f82e6b62989d546eeDmitry Vyukov  MtxLocked = 1,
528f4f51f2cc6fa936f0c65577f82e6b62989d546eeDmitry Vyukov  MtxSleeping = 2
529f4f51f2cc6fa936f0c65577f82e6b62989d546eeDmitry Vyukov};
530f4f51f2cc6fa936f0c65577f82e6b62989d546eeDmitry Vyukov
531f4f51f2cc6fa936f0c65577f82e6b62989d546eeDmitry VyukovBlockingMutex::BlockingMutex(LinkerInitialized) {
532d164ed175a61529589938b3db3cab076a19acf67Dmitry Vyukov  CHECK_EQ(owner_, 0);
533f4f51f2cc6fa936f0c65577f82e6b62989d546eeDmitry Vyukov}
534f4f51f2cc6fa936f0c65577f82e6b62989d546eeDmitry Vyukov
53593af5948d3e0c5bdc396f432dd0ae782f499c449Alexey SamsonovBlockingMutex::BlockingMutex() {
53693af5948d3e0c5bdc396f432dd0ae782f499c449Alexey Samsonov  internal_memset(this, 0, sizeof(*this));
53793af5948d3e0c5bdc396f432dd0ae782f499c449Alexey Samsonov}
53893af5948d3e0c5bdc396f432dd0ae782f499c449Alexey Samsonov
539f4f51f2cc6fa936f0c65577f82e6b62989d546eeDmitry Vyukovvoid BlockingMutex::Lock() {
540f4f51f2cc6fa936f0c65577f82e6b62989d546eeDmitry Vyukov  atomic_uint32_t *m = reinterpret_cast<atomic_uint32_t *>(&opaque_storage_);
541f4f51f2cc6fa936f0c65577f82e6b62989d546eeDmitry Vyukov  if (atomic_exchange(m, MtxLocked, memory_order_acquire) == MtxUnlocked)
542f4f51f2cc6fa936f0c65577f82e6b62989d546eeDmitry Vyukov    return;
543f4f51f2cc6fa936f0c65577f82e6b62989d546eeDmitry Vyukov  while (atomic_exchange(m, MtxSleeping, memory_order_acquire) != MtxUnlocked)
5449578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne    internal_syscall(__NR_futex, m, FUTEX_WAIT, MtxSleeping, 0, 0, 0);
545f4f51f2cc6fa936f0c65577f82e6b62989d546eeDmitry Vyukov}
546f4f51f2cc6fa936f0c65577f82e6b62989d546eeDmitry Vyukov
547f4f51f2cc6fa936f0c65577f82e6b62989d546eeDmitry Vyukovvoid BlockingMutex::Unlock() {
548f4f51f2cc6fa936f0c65577f82e6b62989d546eeDmitry Vyukov  atomic_uint32_t *m = reinterpret_cast<atomic_uint32_t *>(&opaque_storage_);
549f4f51f2cc6fa936f0c65577f82e6b62989d546eeDmitry Vyukov  u32 v = atomic_exchange(m, MtxUnlocked, memory_order_relaxed);
55048526014de78e21f7ed027a60670016bc7f5d292Dmitry Vyukov  CHECK_NE(v, MtxUnlocked);
551f4f51f2cc6fa936f0c65577f82e6b62989d546eeDmitry Vyukov  if (v == MtxSleeping)
5529578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne    internal_syscall(__NR_futex, m, FUTEX_WAKE, 1, 0, 0, 0);
553f4f51f2cc6fa936f0c65577f82e6b62989d546eeDmitry Vyukov}
554f4f51f2cc6fa936f0c65577f82e6b62989d546eeDmitry Vyukov
555ce700979f644c790c2d9d80f5cc2a1ada0380284Alexey Samsonovvoid BlockingMutex::CheckLocked() {
556ce700979f644c790c2d9d80f5cc2a1ada0380284Alexey Samsonov  atomic_uint32_t *m = reinterpret_cast<atomic_uint32_t *>(&opaque_storage_);
557ce700979f644c790c2d9d80f5cc2a1ada0380284Alexey Samsonov  CHECK_NE(MtxUnlocked, atomic_load(m, memory_order_relaxed));
558ce700979f644c790c2d9d80f5cc2a1ada0380284Alexey Samsonov}
559ce700979f644c790c2d9d80f5cc2a1ada0380284Alexey Samsonov
5606fb47af2d2d305adbfc3d41bea589d1527a364a9Kostya Serebryany// ----------------- sanitizer_linux.h
5616fb47af2d2d305adbfc3d41bea589d1527a364a9Kostya Serebryany// The actual size of this structure is specified by d_reclen.
5626fb47af2d2d305adbfc3d41bea589d1527a364a9Kostya Serebryany// Note that getdents64 uses a different structure format. We only provide the
5636fb47af2d2d305adbfc3d41bea589d1527a364a9Kostya Serebryany// 32-bit syscall here.
5646fb47af2d2d305adbfc3d41bea589d1527a364a9Kostya Serebryanystruct linux_dirent {
5656fb47af2d2d305adbfc3d41bea589d1527a364a9Kostya Serebryany  unsigned long      d_ino;
5666fb47af2d2d305adbfc3d41bea589d1527a364a9Kostya Serebryany  unsigned long      d_off;
5676fb47af2d2d305adbfc3d41bea589d1527a364a9Kostya Serebryany  unsigned short     d_reclen;
5686fb47af2d2d305adbfc3d41bea589d1527a364a9Kostya Serebryany  char               d_name[256];
5696fb47af2d2d305adbfc3d41bea589d1527a364a9Kostya Serebryany};
5706fb47af2d2d305adbfc3d41bea589d1527a364a9Kostya Serebryany
5716fb47af2d2d305adbfc3d41bea589d1527a364a9Kostya Serebryany// Syscall wrappers.
5729578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourneuptr internal_ptrace(int request, int pid, void *addr, void *data) {
5739578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne  return internal_syscall(__NR_ptrace, request, pid, addr, data);
5749578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne}
5759578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne
5769578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourneuptr internal_waitpid(int pid, int *status, int options) {
5779578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne  return internal_syscall(__NR_wait4, pid, status, options, 0 /* rusage */);
5786fb47af2d2d305adbfc3d41bea589d1527a364a9Kostya Serebryany}
5796fb47af2d2d305adbfc3d41bea589d1527a364a9Kostya Serebryany
5809578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourneuptr internal_getpid() {
5819578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne  return internal_syscall(__NR_getpid);
5826fb47af2d2d305adbfc3d41bea589d1527a364a9Kostya Serebryany}
5836fb47af2d2d305adbfc3d41bea589d1527a364a9Kostya Serebryany
5849578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourneuptr internal_getppid() {
5859578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne  return internal_syscall(__NR_getppid);
5866fb47af2d2d305adbfc3d41bea589d1527a364a9Kostya Serebryany}
5876fb47af2d2d305adbfc3d41bea589d1527a364a9Kostya Serebryany
5889578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourneuptr internal_getdents(fd_t fd, struct linux_dirent *dirp, unsigned int count) {
5899578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne  return internal_syscall(__NR_getdents, fd, dirp, count);
5906fb47af2d2d305adbfc3d41bea589d1527a364a9Kostya Serebryany}
5916fb47af2d2d305adbfc3d41bea589d1527a364a9Kostya Serebryany
5929578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourneuptr internal_lseek(fd_t fd, OFF_T offset, int whence) {
5939578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne  return internal_syscall(__NR_lseek, fd, offset, whence);
5946fb47af2d2d305adbfc3d41bea589d1527a364a9Kostya Serebryany}
5956fb47af2d2d305adbfc3d41bea589d1527a364a9Kostya Serebryany
5969578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourneuptr internal_prctl(int option, uptr arg2, uptr arg3, uptr arg4, uptr arg5) {
5979578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne  return internal_syscall(__NR_prctl, option, arg2, arg3, arg4, arg5);
5986fb47af2d2d305adbfc3d41bea589d1527a364a9Kostya Serebryany}
5996fb47af2d2d305adbfc3d41bea589d1527a364a9Kostya Serebryany
6009578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourneuptr internal_sigaltstack(const struct sigaltstack *ss,
6016fb47af2d2d305adbfc3d41bea589d1527a364a9Kostya Serebryany                         struct sigaltstack *oss) {
6029578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne  return internal_syscall(__NR_sigaltstack, ss, oss);
6036fb47af2d2d305adbfc3d41bea589d1527a364a9Kostya Serebryany}
6046fb47af2d2d305adbfc3d41bea589d1527a364a9Kostya Serebryany
6056fb47af2d2d305adbfc3d41bea589d1527a364a9Kostya Serebryany// ThreadLister implementation.
6066fb47af2d2d305adbfc3d41bea589d1527a364a9Kostya SerebryanyThreadLister::ThreadLister(int pid)
6076fb47af2d2d305adbfc3d41bea589d1527a364a9Kostya Serebryany  : pid_(pid),
6086fb47af2d2d305adbfc3d41bea589d1527a364a9Kostya Serebryany    descriptor_(-1),
60910f3ab775088bec69dd9e7b611f9b4e152f629bcAlexey Samsonov    buffer_(4096),
6106fb47af2d2d305adbfc3d41bea589d1527a364a9Kostya Serebryany    error_(true),
61110f3ab775088bec69dd9e7b611f9b4e152f629bcAlexey Samsonov    entry_((struct linux_dirent *)buffer_.data()),
6126fb47af2d2d305adbfc3d41bea589d1527a364a9Kostya Serebryany    bytes_read_(0) {
6136fb47af2d2d305adbfc3d41bea589d1527a364a9Kostya Serebryany  char task_directory_path[80];
6146fb47af2d2d305adbfc3d41bea589d1527a364a9Kostya Serebryany  internal_snprintf(task_directory_path, sizeof(task_directory_path),
6156fb47af2d2d305adbfc3d41bea589d1527a364a9Kostya Serebryany                    "/proc/%d/task/", pid);
6169578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne  uptr openrv = internal_open(task_directory_path, O_RDONLY | O_DIRECTORY);
6179578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne  if (internal_iserror(openrv)) {
6186fb47af2d2d305adbfc3d41bea589d1527a364a9Kostya Serebryany    error_ = true;
6196fb47af2d2d305adbfc3d41bea589d1527a364a9Kostya Serebryany    Report("Can't open /proc/%d/task for reading.\n", pid);
6206fb47af2d2d305adbfc3d41bea589d1527a364a9Kostya Serebryany  } else {
6216fb47af2d2d305adbfc3d41bea589d1527a364a9Kostya Serebryany    error_ = false;
6229578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne    descriptor_ = openrv;
6236fb47af2d2d305adbfc3d41bea589d1527a364a9Kostya Serebryany  }
6246fb47af2d2d305adbfc3d41bea589d1527a364a9Kostya Serebryany}
6256fb47af2d2d305adbfc3d41bea589d1527a364a9Kostya Serebryany
6266fb47af2d2d305adbfc3d41bea589d1527a364a9Kostya Serebryanyint ThreadLister::GetNextTID() {
6276fb47af2d2d305adbfc3d41bea589d1527a364a9Kostya Serebryany  int tid = -1;
6286fb47af2d2d305adbfc3d41bea589d1527a364a9Kostya Serebryany  do {
6296fb47af2d2d305adbfc3d41bea589d1527a364a9Kostya Serebryany    if (error_)
6306fb47af2d2d305adbfc3d41bea589d1527a364a9Kostya Serebryany      return -1;
6316fb47af2d2d305adbfc3d41bea589d1527a364a9Kostya Serebryany    if ((char *)entry_ >= &buffer_[bytes_read_] && !GetDirectoryEntries())
6326fb47af2d2d305adbfc3d41bea589d1527a364a9Kostya Serebryany      return -1;
6336fb47af2d2d305adbfc3d41bea589d1527a364a9Kostya Serebryany    if (entry_->d_ino != 0 && entry_->d_name[0] >= '0' &&
6346fb47af2d2d305adbfc3d41bea589d1527a364a9Kostya Serebryany        entry_->d_name[0] <= '9') {
6356fb47af2d2d305adbfc3d41bea589d1527a364a9Kostya Serebryany      // Found a valid tid.
6366fb47af2d2d305adbfc3d41bea589d1527a364a9Kostya Serebryany      tid = (int)internal_atoll(entry_->d_name);
6376fb47af2d2d305adbfc3d41bea589d1527a364a9Kostya Serebryany    }
6386fb47af2d2d305adbfc3d41bea589d1527a364a9Kostya Serebryany    entry_ = (struct linux_dirent *)(((char *)entry_) + entry_->d_reclen);
6396fb47af2d2d305adbfc3d41bea589d1527a364a9Kostya Serebryany  } while (tid < 0);
6406fb47af2d2d305adbfc3d41bea589d1527a364a9Kostya Serebryany  return tid;
6416fb47af2d2d305adbfc3d41bea589d1527a364a9Kostya Serebryany}
6426fb47af2d2d305adbfc3d41bea589d1527a364a9Kostya Serebryany
6436fb47af2d2d305adbfc3d41bea589d1527a364a9Kostya Serebryanyvoid ThreadLister::Reset() {
6446fb47af2d2d305adbfc3d41bea589d1527a364a9Kostya Serebryany  if (error_ || descriptor_ < 0)
6456fb47af2d2d305adbfc3d41bea589d1527a364a9Kostya Serebryany    return;
6466fb47af2d2d305adbfc3d41bea589d1527a364a9Kostya Serebryany  internal_lseek(descriptor_, 0, SEEK_SET);
6476fb47af2d2d305adbfc3d41bea589d1527a364a9Kostya Serebryany}
6486fb47af2d2d305adbfc3d41bea589d1527a364a9Kostya Serebryany
6496fb47af2d2d305adbfc3d41bea589d1527a364a9Kostya SerebryanyThreadLister::~ThreadLister() {
6506fb47af2d2d305adbfc3d41bea589d1527a364a9Kostya Serebryany  if (descriptor_ >= 0)
6516fb47af2d2d305adbfc3d41bea589d1527a364a9Kostya Serebryany    internal_close(descriptor_);
6526fb47af2d2d305adbfc3d41bea589d1527a364a9Kostya Serebryany}
6536fb47af2d2d305adbfc3d41bea589d1527a364a9Kostya Serebryany
6546fb47af2d2d305adbfc3d41bea589d1527a364a9Kostya Serebryanybool ThreadLister::error() { return error_; }
6556fb47af2d2d305adbfc3d41bea589d1527a364a9Kostya Serebryany
6566fb47af2d2d305adbfc3d41bea589d1527a364a9Kostya Serebryanybool ThreadLister::GetDirectoryEntries() {
6576fb47af2d2d305adbfc3d41bea589d1527a364a9Kostya Serebryany  CHECK_GE(descriptor_, 0);
6586fb47af2d2d305adbfc3d41bea589d1527a364a9Kostya Serebryany  CHECK_NE(error_, true);
6596fb47af2d2d305adbfc3d41bea589d1527a364a9Kostya Serebryany  bytes_read_ = internal_getdents(descriptor_,
66010f3ab775088bec69dd9e7b611f9b4e152f629bcAlexey Samsonov                                  (struct linux_dirent *)buffer_.data(),
66110f3ab775088bec69dd9e7b611f9b4e152f629bcAlexey Samsonov                                  buffer_.size());
6629578a3ecfc35a264ede1135033398e2a77a6cad6Peter Collingbourne  if (internal_iserror(bytes_read_)) {
6636fb47af2d2d305adbfc3d41bea589d1527a364a9Kostya Serebryany    Report("Can't read directory entries from /proc/%d/task.\n", pid_);
6646fb47af2d2d305adbfc3d41bea589d1527a364a9Kostya Serebryany    error_ = true;
6656fb47af2d2d305adbfc3d41bea589d1527a364a9Kostya Serebryany    return false;
6666fb47af2d2d305adbfc3d41bea589d1527a364a9Kostya Serebryany  } else if (bytes_read_ == 0) {
6676fb47af2d2d305adbfc3d41bea589d1527a364a9Kostya Serebryany    return false;
6686fb47af2d2d305adbfc3d41bea589d1527a364a9Kostya Serebryany  }
66910f3ab775088bec69dd9e7b611f9b4e152f629bcAlexey Samsonov  entry_ = (struct linux_dirent *)buffer_.data();
6706fb47af2d2d305adbfc3d41bea589d1527a364a9Kostya Serebryany  return true;
6716fb47af2d2d305adbfc3d41bea589d1527a364a9Kostya Serebryany}
6726fb47af2d2d305adbfc3d41bea589d1527a364a9Kostya Serebryany
6734df343a31cf57c309cf102b9aef870458318f579Peter Collingbourneuptr GetPageSize() {
674a8bc34e420d27c47560b0742cec295e40b0f430eKostya Serebryany#if defined(__x86_64__) || defined(__i386__)
6754df343a31cf57c309cf102b9aef870458318f579Peter Collingbourne  return EXEC_PAGESIZE;
676a8bc34e420d27c47560b0742cec295e40b0f430eKostya Serebryany#else
677a8bc34e420d27c47560b0742cec295e40b0f430eKostya Serebryany  return sysconf(_SC_PAGESIZE);  // EXEC_PAGESIZE may not be trustworthy.
678a8bc34e420d27c47560b0742cec295e40b0f430eKostya Serebryany#endif
6794df343a31cf57c309cf102b9aef870458318f579Peter Collingbourne}
6804df343a31cf57c309cf102b9aef870458318f579Peter Collingbourne
6817847d77b246635211c3bf465421d49d7af5226c1Alexey Samsonovstatic char proc_self_exe_cache_str[kMaxPathLength];
6827847d77b246635211c3bf465421d49d7af5226c1Alexey Samsonovstatic uptr proc_self_exe_cache_len = 0;
6837847d77b246635211c3bf465421d49d7af5226c1Alexey Samsonov
6847847d77b246635211c3bf465421d49d7af5226c1Alexey Samsonovuptr ReadBinaryName(/*out*/char *buf, uptr buf_len) {
6857847d77b246635211c3bf465421d49d7af5226c1Alexey Samsonov  uptr module_name_len = internal_readlink(
6867847d77b246635211c3bf465421d49d7af5226c1Alexey Samsonov      "/proc/self/exe", buf, buf_len);
6877847d77b246635211c3bf465421d49d7af5226c1Alexey Samsonov  int readlink_error;
688356cff7bb61083db3915cf571c5358aa8d3830baNick Lewycky  if (internal_iserror(module_name_len, &readlink_error)) {
6897847d77b246635211c3bf465421d49d7af5226c1Alexey Samsonov    if (proc_self_exe_cache_len) {
6907847d77b246635211c3bf465421d49d7af5226c1Alexey Samsonov      // If available, use the cached module name.
6917847d77b246635211c3bf465421d49d7af5226c1Alexey Samsonov      CHECK_LE(proc_self_exe_cache_len, buf_len);
6927847d77b246635211c3bf465421d49d7af5226c1Alexey Samsonov      internal_strncpy(buf, proc_self_exe_cache_str, buf_len);
6937847d77b246635211c3bf465421d49d7af5226c1Alexey Samsonov      module_name_len = internal_strlen(proc_self_exe_cache_str);
6947847d77b246635211c3bf465421d49d7af5226c1Alexey Samsonov    } else {
6957847d77b246635211c3bf465421d49d7af5226c1Alexey Samsonov      // We can't read /proc/self/exe for some reason, assume the name of the
6967847d77b246635211c3bf465421d49d7af5226c1Alexey Samsonov      // binary is unknown.
6977847d77b246635211c3bf465421d49d7af5226c1Alexey Samsonov      Report("WARNING: readlink(\"/proc/self/exe\") failed with errno %d, "
6987847d77b246635211c3bf465421d49d7af5226c1Alexey Samsonov             "some stack frames may not be symbolized\n", readlink_error);
6997847d77b246635211c3bf465421d49d7af5226c1Alexey Samsonov      module_name_len = internal_snprintf(buf, buf_len, "/proc/self/exe");
7007847d77b246635211c3bf465421d49d7af5226c1Alexey Samsonov    }
7017847d77b246635211c3bf465421d49d7af5226c1Alexey Samsonov    CHECK_LT(module_name_len, buf_len);
7027847d77b246635211c3bf465421d49d7af5226c1Alexey Samsonov    buf[module_name_len] = '\0';
7037847d77b246635211c3bf465421d49d7af5226c1Alexey Samsonov  }
7047847d77b246635211c3bf465421d49d7af5226c1Alexey Samsonov  return module_name_len;
7057847d77b246635211c3bf465421d49d7af5226c1Alexey Samsonov}
7067847d77b246635211c3bf465421d49d7af5226c1Alexey Samsonov
7077847d77b246635211c3bf465421d49d7af5226c1Alexey Samsonovvoid CacheBinaryName() {
7087847d77b246635211c3bf465421d49d7af5226c1Alexey Samsonov  if (!proc_self_exe_cache_len) {
7097847d77b246635211c3bf465421d49d7af5226c1Alexey Samsonov    proc_self_exe_cache_len =
7107847d77b246635211c3bf465421d49d7af5226c1Alexey Samsonov        ReadBinaryName(proc_self_exe_cache_str, kMaxPathLength);
7117847d77b246635211c3bf465421d49d7af5226c1Alexey Samsonov  }
7127847d77b246635211c3bf465421d49d7af5226c1Alexey Samsonov}
7137847d77b246635211c3bf465421d49d7af5226c1Alexey Samsonov
7143de0086409d143a612a54a7a0ed809e286656188Sergey Matveev// Match full names of the form /path/to/base_name{-,.}*
7153de0086409d143a612a54a7a0ed809e286656188Sergey Matveevbool LibraryNameIs(const char *full_name, const char *base_name) {
7163de0086409d143a612a54a7a0ed809e286656188Sergey Matveev  const char *name = full_name;
7173de0086409d143a612a54a7a0ed809e286656188Sergey Matveev  // Strip path.
7183de0086409d143a612a54a7a0ed809e286656188Sergey Matveev  while (*name != '\0') name++;
7193de0086409d143a612a54a7a0ed809e286656188Sergey Matveev  while (name > full_name && *name != '/') name--;
7203de0086409d143a612a54a7a0ed809e286656188Sergey Matveev  if (*name == '/') name++;
7213de0086409d143a612a54a7a0ed809e286656188Sergey Matveev  uptr base_name_length = internal_strlen(base_name);
7223de0086409d143a612a54a7a0ed809e286656188Sergey Matveev  if (internal_strncmp(name, base_name, base_name_length)) return false;
7233de0086409d143a612a54a7a0ed809e286656188Sergey Matveev  return (name[base_name_length] == '-' || name[base_name_length] == '.');
7243de0086409d143a612a54a7a0ed809e286656188Sergey Matveev}
7253de0086409d143a612a54a7a0ed809e286656188Sergey Matveev
726d054abef27369471e154ec5693949538c2fdffd9Evgeniy Stepanov#if !SANITIZER_ANDROID
7272e75ac983cb233daa1abfa35fb33d2bafffe2ab1Peter Collingbourne// Call cb for each region mapped by map.
7282e75ac983cb233daa1abfa35fb33d2bafffe2ab1Peter Collingbournevoid ForEachMappedRegion(link_map *map, void (*cb)(const void *, uptr)) {
7292e75ac983cb233daa1abfa35fb33d2bafffe2ab1Peter Collingbourne  typedef ElfW(Phdr) Elf_Phdr;
7302e75ac983cb233daa1abfa35fb33d2bafffe2ab1Peter Collingbourne  typedef ElfW(Ehdr) Elf_Ehdr;
7312e75ac983cb233daa1abfa35fb33d2bafffe2ab1Peter Collingbourne  char *base = (char *)map->l_addr;
7322e75ac983cb233daa1abfa35fb33d2bafffe2ab1Peter Collingbourne  Elf_Ehdr *ehdr = (Elf_Ehdr *)base;
7332e75ac983cb233daa1abfa35fb33d2bafffe2ab1Peter Collingbourne  char *phdrs = base + ehdr->e_phoff;
7342e75ac983cb233daa1abfa35fb33d2bafffe2ab1Peter Collingbourne  char *phdrs_end = phdrs + ehdr->e_phnum * ehdr->e_phentsize;
7352e75ac983cb233daa1abfa35fb33d2bafffe2ab1Peter Collingbourne
7362e75ac983cb233daa1abfa35fb33d2bafffe2ab1Peter Collingbourne  // Find the segment with the minimum base so we can "relocate" the p_vaddr
7372e75ac983cb233daa1abfa35fb33d2bafffe2ab1Peter Collingbourne  // fields.  Typically ET_DYN objects (DSOs) have base of zero and ET_EXEC
7382e75ac983cb233daa1abfa35fb33d2bafffe2ab1Peter Collingbourne  // objects have a non-zero base.
739f50b0fc601aea71d9fb22f01a11c7e206c666edcPeter Collingbourne  uptr preferred_base = (uptr)-1;
7402e75ac983cb233daa1abfa35fb33d2bafffe2ab1Peter Collingbourne  for (char *iter = phdrs; iter != phdrs_end; iter += ehdr->e_phentsize) {
7412e75ac983cb233daa1abfa35fb33d2bafffe2ab1Peter Collingbourne    Elf_Phdr *phdr = (Elf_Phdr *)iter;
7422e75ac983cb233daa1abfa35fb33d2bafffe2ab1Peter Collingbourne    if (phdr->p_type == PT_LOAD && preferred_base > (uptr)phdr->p_vaddr)
7432e75ac983cb233daa1abfa35fb33d2bafffe2ab1Peter Collingbourne      preferred_base = (uptr)phdr->p_vaddr;
7442e75ac983cb233daa1abfa35fb33d2bafffe2ab1Peter Collingbourne  }
7452e75ac983cb233daa1abfa35fb33d2bafffe2ab1Peter Collingbourne
7462e75ac983cb233daa1abfa35fb33d2bafffe2ab1Peter Collingbourne  // Compute the delta from the real base to get a relocation delta.
7472e75ac983cb233daa1abfa35fb33d2bafffe2ab1Peter Collingbourne  sptr delta = (uptr)base - preferred_base;
7482e75ac983cb233daa1abfa35fb33d2bafffe2ab1Peter Collingbourne  // Now we can figure out what the loader really mapped.
7492e75ac983cb233daa1abfa35fb33d2bafffe2ab1Peter Collingbourne  for (char *iter = phdrs; iter != phdrs_end; iter += ehdr->e_phentsize) {
7502e75ac983cb233daa1abfa35fb33d2bafffe2ab1Peter Collingbourne    Elf_Phdr *phdr = (Elf_Phdr *)iter;
7512e75ac983cb233daa1abfa35fb33d2bafffe2ab1Peter Collingbourne    if (phdr->p_type == PT_LOAD) {
7522e75ac983cb233daa1abfa35fb33d2bafffe2ab1Peter Collingbourne      uptr seg_start = phdr->p_vaddr + delta;
7532e75ac983cb233daa1abfa35fb33d2bafffe2ab1Peter Collingbourne      uptr seg_end = seg_start + phdr->p_memsz;
7542e75ac983cb233daa1abfa35fb33d2bafffe2ab1Peter Collingbourne      // None of these values are aligned.  We consider the ragged edges of the
7552e75ac983cb233daa1abfa35fb33d2bafffe2ab1Peter Collingbourne      // load command as defined, since they are mapped from the file.
7562e75ac983cb233daa1abfa35fb33d2bafffe2ab1Peter Collingbourne      seg_start = RoundDownTo(seg_start, GetPageSizeCached());
7572e75ac983cb233daa1abfa35fb33d2bafffe2ab1Peter Collingbourne      seg_end = RoundUpTo(seg_end, GetPageSizeCached());
7582e75ac983cb233daa1abfa35fb33d2bafffe2ab1Peter Collingbourne      cb((void *)seg_start, seg_end - seg_start);
7592e75ac983cb233daa1abfa35fb33d2bafffe2ab1Peter Collingbourne    }
7602e75ac983cb233daa1abfa35fb33d2bafffe2ab1Peter Collingbourne  }
7612e75ac983cb233daa1abfa35fb33d2bafffe2ab1Peter Collingbourne}
762d054abef27369471e154ec5693949538c2fdffd9Evgeniy Stepanov#endif
7632e75ac983cb233daa1abfa35fb33d2bafffe2ab1Peter Collingbourne
764cb339108cca40fb4c1ed520656cb6cb75889a237Sergey Matveev#if defined(__x86_64__)
765cb339108cca40fb4c1ed520656cb6cb75889a237Sergey Matveev// We cannot use glibc's clone wrapper, because it messes with the child
766cb339108cca40fb4c1ed520656cb6cb75889a237Sergey Matveev// task's TLS. It writes the PID and TID of the child task to its thread
767cb339108cca40fb4c1ed520656cb6cb75889a237Sergey Matveev// descriptor, but in our case the child task shares the thread descriptor with
768cb339108cca40fb4c1ed520656cb6cb75889a237Sergey Matveev// the parent (because we don't know how to allocate a new thread
769cb339108cca40fb4c1ed520656cb6cb75889a237Sergey Matveev// descriptor to keep glibc happy). So the stock version of clone(), when
770cb339108cca40fb4c1ed520656cb6cb75889a237Sergey Matveev// used with CLONE_VM, would end up corrupting the parent's thread descriptor.
771cb339108cca40fb4c1ed520656cb6cb75889a237Sergey Matveevuptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
772cb339108cca40fb4c1ed520656cb6cb75889a237Sergey Matveev                    int *parent_tidptr, void *newtls, int *child_tidptr) {
773cb339108cca40fb4c1ed520656cb6cb75889a237Sergey Matveev  long long res;
774cb339108cca40fb4c1ed520656cb6cb75889a237Sergey Matveev  if (!fn || !child_stack)
775cb339108cca40fb4c1ed520656cb6cb75889a237Sergey Matveev    return -EINVAL;
776cb339108cca40fb4c1ed520656cb6cb75889a237Sergey Matveev  CHECK_EQ(0, (uptr)child_stack % 16);
777cb339108cca40fb4c1ed520656cb6cb75889a237Sergey Matveev  child_stack = (char *)child_stack - 2 * sizeof(void *);
778cb339108cca40fb4c1ed520656cb6cb75889a237Sergey Matveev  ((void **)child_stack)[0] = (void *)(uptr)fn;
779cb339108cca40fb4c1ed520656cb6cb75889a237Sergey Matveev  ((void **)child_stack)[1] = arg;
780cb339108cca40fb4c1ed520656cb6cb75889a237Sergey Matveev  __asm__ __volatile__(
781cb339108cca40fb4c1ed520656cb6cb75889a237Sergey Matveev                       /* %rax = syscall(%rax = __NR_clone,
782cb339108cca40fb4c1ed520656cb6cb75889a237Sergey Matveev                        *                %rdi = flags,
783cb339108cca40fb4c1ed520656cb6cb75889a237Sergey Matveev                        *                %rsi = child_stack,
784cb339108cca40fb4c1ed520656cb6cb75889a237Sergey Matveev                        *                %rdx = parent_tidptr,
785cb339108cca40fb4c1ed520656cb6cb75889a237Sergey Matveev                        *                %r8  = new_tls,
786cb339108cca40fb4c1ed520656cb6cb75889a237Sergey Matveev                        *                %r10 = child_tidptr)
787cb339108cca40fb4c1ed520656cb6cb75889a237Sergey Matveev                        */
788cb339108cca40fb4c1ed520656cb6cb75889a237Sergey Matveev                       "movq   %6,%%r8\n"
789cb339108cca40fb4c1ed520656cb6cb75889a237Sergey Matveev                       "movq   %7,%%r10\n"
790cb339108cca40fb4c1ed520656cb6cb75889a237Sergey Matveev                       "syscall\n"
791cb339108cca40fb4c1ed520656cb6cb75889a237Sergey Matveev
792cb339108cca40fb4c1ed520656cb6cb75889a237Sergey Matveev                       /* if (%rax != 0)
793cb339108cca40fb4c1ed520656cb6cb75889a237Sergey Matveev                        *   return;
794cb339108cca40fb4c1ed520656cb6cb75889a237Sergey Matveev                        */
795cb339108cca40fb4c1ed520656cb6cb75889a237Sergey Matveev                       "testq  %%rax,%%rax\n"
796cb339108cca40fb4c1ed520656cb6cb75889a237Sergey Matveev                       "jnz    1f\n"
797cb339108cca40fb4c1ed520656cb6cb75889a237Sergey Matveev
798cb339108cca40fb4c1ed520656cb6cb75889a237Sergey Matveev                       /* In the child. Terminate unwind chain. */
799497ae56316cd05a0d539e0d6e065bbaee254aca3Sergey Matveev                       // XXX: We should also terminate the CFI unwind chain
800497ae56316cd05a0d539e0d6e065bbaee254aca3Sergey Matveev                       // here. Unfortunately clang 3.2 doesn't support the
801497ae56316cd05a0d539e0d6e065bbaee254aca3Sergey Matveev                       // necessary CFI directives, so we skip that part.
802cb339108cca40fb4c1ed520656cb6cb75889a237Sergey Matveev                       "xorq   %%rbp,%%rbp\n"
803cb339108cca40fb4c1ed520656cb6cb75889a237Sergey Matveev
804cb339108cca40fb4c1ed520656cb6cb75889a237Sergey Matveev                       /* Call "fn(arg)". */
805cb339108cca40fb4c1ed520656cb6cb75889a237Sergey Matveev                       "popq   %%rax\n"
806cb339108cca40fb4c1ed520656cb6cb75889a237Sergey Matveev                       "popq   %%rdi\n"
807cb339108cca40fb4c1ed520656cb6cb75889a237Sergey Matveev                       "call   *%%rax\n"
808cb339108cca40fb4c1ed520656cb6cb75889a237Sergey Matveev
809cb339108cca40fb4c1ed520656cb6cb75889a237Sergey Matveev                       /* Call _exit(%rax). */
810cb339108cca40fb4c1ed520656cb6cb75889a237Sergey Matveev                       "movq   %%rax,%%rdi\n"
811cb339108cca40fb4c1ed520656cb6cb75889a237Sergey Matveev                       "movq   %2,%%rax\n"
812cb339108cca40fb4c1ed520656cb6cb75889a237Sergey Matveev                       "syscall\n"
813cb339108cca40fb4c1ed520656cb6cb75889a237Sergey Matveev
814cb339108cca40fb4c1ed520656cb6cb75889a237Sergey Matveev                       /* Return to parent. */
815cb339108cca40fb4c1ed520656cb6cb75889a237Sergey Matveev                     "1:\n"
816cb339108cca40fb4c1ed520656cb6cb75889a237Sergey Matveev                       : "=a" (res)
817cb339108cca40fb4c1ed520656cb6cb75889a237Sergey Matveev                       : "a"(__NR_clone), "i"(__NR_exit),
818cb339108cca40fb4c1ed520656cb6cb75889a237Sergey Matveev                         "S"(child_stack),
819cb339108cca40fb4c1ed520656cb6cb75889a237Sergey Matveev                         "D"(flags),
820cb339108cca40fb4c1ed520656cb6cb75889a237Sergey Matveev                         "d"(parent_tidptr),
821cb339108cca40fb4c1ed520656cb6cb75889a237Sergey Matveev                         "r"(newtls),
822cb339108cca40fb4c1ed520656cb6cb75889a237Sergey Matveev                         "r"(child_tidptr)
823cb339108cca40fb4c1ed520656cb6cb75889a237Sergey Matveev                       : "rsp", "memory", "r8", "r10", "r11", "rcx");
824cb339108cca40fb4c1ed520656cb6cb75889a237Sergey Matveev  return res;
825cb339108cca40fb4c1ed520656cb6cb75889a237Sergey Matveev}
826cb339108cca40fb4c1ed520656cb6cb75889a237Sergey Matveev#endif  // defined(__x86_64__)
827ae4d9caa4f47fa6abcd641719e9f520622940c17Alexey Samsonov}  // namespace __sanitizer
828ae4d9caa4f47fa6abcd641719e9f520622940c17Alexey Samsonov
82946f9395baf65e17f1a3f7a3a1deee72a1560ac53Alexey Samsonov#endif  // SANITIZER_LINUX
830