Home | History | Annotate | Download | only in sanitizer_common
      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_placement_new.h"
     20 #include "sanitizer_procmaps.h"
     21 
     22 #include <fcntl.h>
     23 #include <pthread.h>
     24 #include <sched.h>
     25 #include <sys/mman.h>
     26 #include <sys/resource.h>
     27 #include <sys/stat.h>
     28 #include <sys/syscall.h>
     29 #include <sys/time.h>
     30 #include <sys/types.h>
     31 #include <unistd.h>
     32 
     33 namespace __sanitizer {
     34 
     35 // --------------- sanitizer_libc.h
     36 void *internal_mmap(void *addr, uptr length, int prot, int flags,
     37                     int fd, u64 offset) {
     38 #if __WORDSIZE == 64
     39   return (void *)syscall(__NR_mmap, addr, length, prot, flags, fd, offset);
     40 #else
     41   return (void *)syscall(__NR_mmap2, addr, length, prot, flags, fd, offset);
     42 #endif
     43 }
     44 
     45 int internal_munmap(void *addr, uptr length) {
     46   return syscall(__NR_munmap, addr, length);
     47 }
     48 
     49 int internal_close(fd_t fd) {
     50   return syscall(__NR_close, fd);
     51 }
     52 
     53 fd_t internal_open(const char *filename, bool write) {
     54   return syscall(__NR_open, filename,
     55       write ? O_WRONLY | O_CREAT /*| O_CLOEXEC*/ : O_RDONLY, 0660);
     56 }
     57 
     58 uptr internal_read(fd_t fd, void *buf, uptr count) {
     59   return (uptr)syscall(__NR_read, fd, buf, count);
     60 }
     61 
     62 uptr internal_write(fd_t fd, const void *buf, uptr count) {
     63   return (uptr)syscall(__NR_write, fd, buf, count);
     64 }
     65 
     66 uptr internal_filesize(fd_t fd) {
     67 #if __WORDSIZE == 64
     68   struct stat st;
     69   if (syscall(__NR_fstat, fd, &st))
     70     return -1;
     71 #else
     72   struct stat64 st;
     73   if (syscall(__NR_fstat64, fd, &st))
     74     return -1;
     75 #endif
     76   return (uptr)st.st_size;
     77 }
     78 
     79 int internal_dup2(int oldfd, int newfd) {
     80   return syscall(__NR_dup2, oldfd, newfd);
     81 }
     82 
     83 uptr internal_readlink(const char *path, char *buf, uptr bufsize) {
     84   return (uptr)syscall(__NR_readlink, path, buf, bufsize);
     85 }
     86 
     87 int internal_sched_yield() {
     88   return syscall(__NR_sched_yield);
     89 }
     90 
     91 // ----------------- sanitizer_common.h
     92 void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
     93                                 uptr *stack_bottom) {
     94   static const uptr kMaxThreadStackSize = 256 * (1 << 20);  // 256M
     95   CHECK(stack_top);
     96   CHECK(stack_bottom);
     97   if (at_initialization) {
     98     // This is the main thread. Libpthread may not be initialized yet.
     99     struct rlimit rl;
    100     CHECK_EQ(getrlimit(RLIMIT_STACK, &rl), 0);
    101 
    102     // Find the mapping that contains a stack variable.
    103     MemoryMappingLayout proc_maps;
    104     uptr start, end, offset;
    105     uptr prev_end = 0;
    106     while (proc_maps.Next(&start, &end, &offset, 0, 0)) {
    107       if ((uptr)&rl < end)
    108         break;
    109       prev_end = end;
    110     }
    111     CHECK((uptr)&rl >= start && (uptr)&rl < end);
    112 
    113     // Get stacksize from rlimit, but clip it so that it does not overlap
    114     // with other mappings.
    115     uptr stacksize = rl.rlim_cur;
    116     if (stacksize > end - prev_end)
    117       stacksize = end - prev_end;
    118     // When running with unlimited stack size, we still want to set some limit.
    119     // The unlimited stack size is caused by 'ulimit -s unlimited'.
    120     // Also, for some reason, GNU make spawns subprocesses with unlimited stack.
    121     if (stacksize > kMaxThreadStackSize)
    122       stacksize = kMaxThreadStackSize;
    123     *stack_top = end;
    124     *stack_bottom = end - stacksize;
    125     return;
    126   }
    127   pthread_attr_t attr;
    128   CHECK_EQ(pthread_getattr_np(pthread_self(), &attr), 0);
    129   uptr stacksize = 0;
    130   void *stackaddr = 0;
    131   pthread_attr_getstack(&attr, &stackaddr, (size_t*)&stacksize);
    132   pthread_attr_destroy(&attr);
    133 
    134   *stack_top = (uptr)stackaddr + stacksize;
    135   *stack_bottom = (uptr)stackaddr;
    136   CHECK(stacksize < kMaxThreadStackSize);  // Sanity check.
    137 }
    138 
    139 // Like getenv, but reads env directly from /proc and does not use libc.
    140 // This function should be called first inside __asan_init.
    141 const char *GetEnv(const char *name) {
    142   static char *environ;
    143   static uptr len;
    144   static bool inited;
    145   if (!inited) {
    146     inited = true;
    147     uptr environ_size;
    148     len = ReadFileToBuffer("/proc/self/environ",
    149                            &environ, &environ_size, 1 << 26);
    150   }
    151   if (!environ || len == 0) return 0;
    152   uptr namelen = internal_strlen(name);
    153   const char *p = environ;
    154   while (*p != '\0') {  // will happen at the \0\0 that terminates the buffer
    155     // proc file has the format NAME=value\0NAME=value\0NAME=value\0...
    156     const char* endp =
    157         (char*)internal_memchr(p, '\0', len - (p - environ));
    158     if (endp == 0)  // this entry isn't NUL terminated
    159       return 0;
    160     else if (!internal_memcmp(p, name, namelen) && p[namelen] == '=')  // Match.
    161       return p + namelen + 1;  // point after =
    162     p = endp + 1;
    163   }
    164   return 0;  // Not found.
    165 }
    166 
    167 // ----------------- sanitizer_procmaps.h
    168 MemoryMappingLayout::MemoryMappingLayout() {
    169   proc_self_maps_buff_len_ =
    170       ReadFileToBuffer("/proc/self/maps", &proc_self_maps_buff_,
    171                        &proc_self_maps_buff_mmaped_size_, 1 << 26);
    172   CHECK_GT(proc_self_maps_buff_len_, 0);
    173   // internal_write(2, proc_self_maps_buff_, proc_self_maps_buff_len_);
    174   Reset();
    175 }
    176 
    177 MemoryMappingLayout::~MemoryMappingLayout() {
    178   UnmapOrDie(proc_self_maps_buff_, proc_self_maps_buff_mmaped_size_);
    179 }
    180 
    181 void MemoryMappingLayout::Reset() {
    182   current_ = proc_self_maps_buff_;
    183 }
    184 
    185 // Parse a hex value in str and update str.
    186 static uptr ParseHex(char **str) {
    187   uptr x = 0;
    188   char *s;
    189   for (s = *str; ; s++) {
    190     char c = *s;
    191     uptr v = 0;
    192     if (c >= '0' && c <= '9')
    193       v = c - '0';
    194     else if (c >= 'a' && c <= 'f')
    195       v = c - 'a' + 10;
    196     else if (c >= 'A' && c <= 'F')
    197       v = c - 'A' + 10;
    198     else
    199       break;
    200     x = x * 16 + v;
    201   }
    202   *str = s;
    203   return x;
    204 }
    205 
    206 static bool IsOnOf(char c, char c1, char c2) {
    207   return c == c1 || c == c2;
    208 }
    209 
    210 static bool IsDecimal(char c) {
    211   return c >= '0' && c <= '9';
    212 }
    213 
    214 bool MemoryMappingLayout::Next(uptr *start, uptr *end, uptr *offset,
    215                                char filename[], uptr filename_size) {
    216   char *last = proc_self_maps_buff_ + proc_self_maps_buff_len_;
    217   if (current_ >= last) return false;
    218   uptr dummy;
    219   if (!start) start = &dummy;
    220   if (!end) end = &dummy;
    221   if (!offset) offset = &dummy;
    222   char *next_line = (char*)internal_memchr(current_, '\n', last - current_);
    223   if (next_line == 0)
    224     next_line = last;
    225   // Example: 08048000-08056000 r-xp 00000000 03:0c 64593   /foo/bar
    226   *start = ParseHex(&current_);
    227   CHECK_EQ(*current_++, '-');
    228   *end = ParseHex(&current_);
    229   CHECK_EQ(*current_++, ' ');
    230   CHECK(IsOnOf(*current_++, '-', 'r'));
    231   CHECK(IsOnOf(*current_++, '-', 'w'));
    232   CHECK(IsOnOf(*current_++, '-', 'x'));
    233   CHECK(IsOnOf(*current_++, 's', 'p'));
    234   CHECK_EQ(*current_++, ' ');
    235   *offset = ParseHex(&current_);
    236   CHECK_EQ(*current_++, ' ');
    237   ParseHex(&current_);
    238   CHECK_EQ(*current_++, ':');
    239   ParseHex(&current_);
    240   CHECK_EQ(*current_++, ' ');
    241   while (IsDecimal(*current_))
    242     current_++;
    243   CHECK_EQ(*current_++, ' ');
    244   // Skip spaces.
    245   while (current_ < next_line && *current_ == ' ')
    246     current_++;
    247   // Fill in the filename.
    248   uptr i = 0;
    249   while (current_ < next_line) {
    250     if (filename && i < filename_size - 1)
    251       filename[i++] = *current_;
    252     current_++;
    253   }
    254   if (filename && i < filename_size)
    255     filename[i] = 0;
    256   current_ = next_line + 1;
    257   return true;
    258 }
    259 
    260 // Gets the object name and the offset by walking MemoryMappingLayout.
    261 bool MemoryMappingLayout::GetObjectNameAndOffset(uptr addr, uptr *offset,
    262                                                  char filename[],
    263                                                  uptr filename_size) {
    264   return IterateForObjectNameAndOffset(addr, offset, filename, filename_size);
    265 }
    266 
    267 }  // namespace __sanitizer
    268 
    269 #endif  // __linux__
    270