1 //===-- sanitizer_linux.cc ------------------------------------------------===//
3 // This file is distributed under the University of Illinois Open Source
4 // License. See LICENSE.TXT for details.
6 //===----------------------------------------------------------------------===//
8 // This file is shared between AddressSanitizer and ThreadSanitizer
9 // run-time libraries and implements linux-specific functions from
11 //===----------------------------------------------------------------------===//
14 #include "sanitizer_common.h"
15 #include "sanitizer_internal_defs.h"
16 #include "sanitizer_libc.h"
17 #include "sanitizer_placement_new.h"
18 #include "sanitizer_procmaps.h"
24 #include <sys/resource.h>
26 #include <sys/syscall.h>
28 #include <sys/types.h>
32 namespace __sanitizer
{
34 // --------------- sanitizer_libc.h
35 void *internal_mmap(void *addr
, uptr length
, int prot
, int flags
,
38 return (void *)syscall(__NR_mmap
, addr
, length
, prot
, flags
, fd
, offset
);
40 return (void *)syscall(__NR_mmap2
, addr
, length
, prot
, flags
, fd
, offset
);
44 int internal_munmap(void *addr
, uptr length
) {
45 return syscall(__NR_munmap
, addr
, length
);
48 int internal_close(fd_t fd
) {
49 return syscall(__NR_close
, fd
);
52 fd_t
internal_open(const char *filename
, bool write
) {
53 return syscall(__NR_open
, filename
,
54 write
? O_WRONLY
| O_CREAT
/*| O_CLOEXEC*/ : O_RDONLY
, 0660);
57 uptr
internal_read(fd_t fd
, void *buf
, uptr count
) {
59 HANDLE_EINTR(res
, (sptr
)syscall(__NR_read
, fd
, buf
, count
));
63 uptr
internal_write(fd_t fd
, const void *buf
, uptr count
) {
65 HANDLE_EINTR(res
, (sptr
)syscall(__NR_write
, fd
, buf
, count
));
69 uptr
internal_filesize(fd_t fd
) {
72 if (syscall(__NR_fstat
, fd
, &st
))
76 if (syscall(__NR_fstat64
, fd
, &st
))
79 return (uptr
)st
.st_size
;
82 int internal_dup2(int oldfd
, int newfd
) {
83 return syscall(__NR_dup2
, oldfd
, newfd
);
86 uptr
internal_readlink(const char *path
, char *buf
, uptr bufsize
) {
87 return (uptr
)syscall(__NR_readlink
, path
, buf
, bufsize
);
90 int internal_sched_yield() {
91 return syscall(__NR_sched_yield
);
94 // ----------------- sanitizer_common.h
96 return syscall(__NR_gettid
);
99 void GetThreadStackTopAndBottom(bool at_initialization
, uptr
*stack_top
,
100 uptr
*stack_bottom
) {
101 static const uptr kMaxThreadStackSize
= 256 * (1 << 20); // 256M
104 if (at_initialization
) {
105 // This is the main thread. Libpthread may not be initialized yet.
107 CHECK_EQ(getrlimit(RLIMIT_STACK
, &rl
), 0);
109 // Find the mapping that contains a stack variable.
110 MemoryMappingLayout proc_maps
;
111 uptr start
, end
, offset
;
113 while (proc_maps
.Next(&start
, &end
, &offset
, 0, 0)) {
118 CHECK((uptr
)&rl
>= start
&& (uptr
)&rl
< end
);
120 // Get stacksize from rlimit, but clip it so that it does not overlap
121 // with other mappings.
122 uptr stacksize
= rl
.rlim_cur
;
123 if (stacksize
> end
- prev_end
)
124 stacksize
= end
- prev_end
;
125 // When running with unlimited stack size, we still want to set some limit.
126 // The unlimited stack size is caused by 'ulimit -s unlimited'.
127 // Also, for some reason, GNU make spawns subprocesses with unlimited stack.
128 if (stacksize
> kMaxThreadStackSize
)
129 stacksize
= kMaxThreadStackSize
;
131 *stack_bottom
= end
- stacksize
;
135 CHECK_EQ(pthread_getattr_np(pthread_self(), &attr
), 0);
138 pthread_attr_getstack(&attr
, &stackaddr
, (size_t*)&stacksize
);
139 pthread_attr_destroy(&attr
);
141 *stack_top
= (uptr
)stackaddr
+ stacksize
;
142 *stack_bottom
= (uptr
)stackaddr
;
143 CHECK(stacksize
< kMaxThreadStackSize
); // Sanity check.
146 // Like getenv, but reads env directly from /proc and does not use libc.
147 // This function should be called first inside __asan_init.
148 const char *GetEnv(const char *name
) {
149 static char *environ
;
155 len
= ReadFileToBuffer("/proc/self/environ",
156 &environ
, &environ_size
, 1 << 26);
158 if (!environ
|| len
== 0) return 0;
159 uptr namelen
= internal_strlen(name
);
160 const char *p
= environ
;
161 while (*p
!= '\0') { // will happen at the \0\0 that terminates the buffer
162 // proc file has the format NAME=value\0NAME=value\0NAME=value\0...
164 (char*)internal_memchr(p
, '\0', len
- (p
- environ
));
165 if (endp
== 0) // this entry isn't NUL terminated
167 else if (!internal_memcmp(p
, name
, namelen
) && p
[namelen
] == '=') // Match.
168 return p
+ namelen
+ 1; // point after =
171 return 0; // Not found.
175 static const int kMaxArgv
= 100;
176 InternalScopedBuffer
<char*> argv(kMaxArgv
+ 1);
179 ReadFileToBuffer("/proc/self/cmdline", &buff
, &buff_size
, 1024 * 1024);
182 for (argc
= 1, i
= 1; ; i
++) {
184 if (buff
[i
+1] == 0) break;
185 argv
[argc
] = &buff
[i
+1];
186 CHECK_LE(argc
, kMaxArgv
); // FIXME: make this more flexible.
191 execv(argv
[0], argv
.data());
194 // ----------------- sanitizer_procmaps.h
195 MemoryMappingLayout::MemoryMappingLayout() {
196 proc_self_maps_buff_len_
=
197 ReadFileToBuffer("/proc/self/maps", &proc_self_maps_buff_
,
198 &proc_self_maps_buff_mmaped_size_
, 1 << 26);
199 CHECK_GT(proc_self_maps_buff_len_
, 0);
200 // internal_write(2, proc_self_maps_buff_, proc_self_maps_buff_len_);
204 MemoryMappingLayout::~MemoryMappingLayout() {
205 UnmapOrDie(proc_self_maps_buff_
, proc_self_maps_buff_mmaped_size_
);
208 void MemoryMappingLayout::Reset() {
209 current_
= proc_self_maps_buff_
;
212 // Parse a hex value in str and update str.
213 static uptr
ParseHex(char **str
) {
216 for (s
= *str
; ; s
++) {
219 if (c
>= '0' && c
<= '9')
221 else if (c
>= 'a' && c
<= 'f')
223 else if (c
>= 'A' && c
<= 'F')
233 static bool IsOnOf(char c
, char c1
, char c2
) {
234 return c
== c1
|| c
== c2
;
237 static bool IsDecimal(char c
) {
238 return c
>= '0' && c
<= '9';
241 bool MemoryMappingLayout::Next(uptr
*start
, uptr
*end
, uptr
*offset
,
242 char filename
[], uptr filename_size
) {
243 char *last
= proc_self_maps_buff_
+ proc_self_maps_buff_len_
;
244 if (current_
>= last
) return false;
246 if (!start
) start
= &dummy
;
247 if (!end
) end
= &dummy
;
248 if (!offset
) offset
= &dummy
;
249 char *next_line
= (char*)internal_memchr(current_
, '\n', last
- current_
);
252 // Example: 08048000-08056000 r-xp 00000000 03:0c 64593 /foo/bar
253 *start
= ParseHex(¤t_
);
254 CHECK_EQ(*current_
++, '-');
255 *end
= ParseHex(¤t_
);
256 CHECK_EQ(*current_
++, ' ');
257 CHECK(IsOnOf(*current_
++, '-', 'r'));
258 CHECK(IsOnOf(*current_
++, '-', 'w'));
259 CHECK(IsOnOf(*current_
++, '-', 'x'));
260 CHECK(IsOnOf(*current_
++, 's', 'p'));
261 CHECK_EQ(*current_
++, ' ');
262 *offset
= ParseHex(¤t_
);
263 CHECK_EQ(*current_
++, ' ');
265 CHECK_EQ(*current_
++, ':');
267 CHECK_EQ(*current_
++, ' ');
268 while (IsDecimal(*current_
))
270 CHECK_EQ(*current_
++, ' ');
272 while (current_
< next_line
&& *current_
== ' ')
274 // Fill in the filename.
276 while (current_
< next_line
) {
277 if (filename
&& i
< filename_size
- 1)
278 filename
[i
++] = *current_
;
281 if (filename
&& i
< filename_size
)
283 current_
= next_line
+ 1;
287 // Gets the object name and the offset by walking MemoryMappingLayout.
288 bool MemoryMappingLayout::GetObjectNameAndOffset(uptr addr
, uptr
*offset
,
290 uptr filename_size
) {
291 return IterateForObjectNameAndOffset(addr
, offset
, filename
, filename_size
);
294 } // namespace __sanitizer