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 33namespace __sanitizer { 34 35// --------------- sanitizer_libc.h 36void *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 45int internal_munmap(void *addr, uptr length) { 46 return syscall(__NR_munmap, addr, length); 47} 48 49int internal_close(fd_t fd) { 50 return syscall(__NR_close, fd); 51} 52 53fd_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 58uptr internal_read(fd_t fd, void *buf, uptr count) { 59 return (uptr)syscall(__NR_read, fd, buf, count); 60} 61 62uptr internal_write(fd_t fd, const void *buf, uptr count) { 63 return (uptr)syscall(__NR_write, fd, buf, count); 64} 65 66uptr 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 79int internal_dup2(int oldfd, int newfd) { 80 return syscall(__NR_dup2, oldfd, newfd); 81} 82 83uptr internal_readlink(const char *path, char *buf, uptr bufsize) { 84 return (uptr)syscall(__NR_readlink, path, buf, bufsize); 85} 86 87int internal_sched_yield() { 88 return syscall(__NR_sched_yield); 89} 90 91// ----------------- sanitizer_common.h 92void 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. 141const 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 168MemoryMappingLayout::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 177MemoryMappingLayout::~MemoryMappingLayout() { 178 UnmapOrDie(proc_self_maps_buff_, proc_self_maps_buff_mmaped_size_); 179} 180 181void MemoryMappingLayout::Reset() { 182 current_ = proc_self_maps_buff_; 183} 184 185// Parse a hex value in str and update str. 186static 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 206static bool IsOnOf(char c, char c1, char c2) { 207 return c == c1 || c == c2; 208} 209 210static bool IsDecimal(char c) { 211 return c >= '0' && c <= '9'; 212} 213 214bool 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(¤t_); 227 CHECK_EQ(*current_++, '-'); 228 *end = ParseHex(¤t_); 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(¤t_); 236 CHECK_EQ(*current_++, ' '); 237 ParseHex(¤t_); 238 CHECK_EQ(*current_++, ':'); 239 ParseHex(¤t_); 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. 261bool 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