1 //===-- sanitizer_posix.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 POSIX-specific functions from
11 //===----------------------------------------------------------------------===//
13 #include "sanitizer_platform.h"
14 #if SANITIZER_LINUX || SANITIZER_MAC
16 #include "sanitizer_common.h"
17 #include "sanitizer_libc.h"
18 #include "sanitizer_procmaps.h"
19 #include "sanitizer_stacktrace.h"
23 namespace __sanitizer
{
25 // ------------- sanitizer_common.h
26 uptr
GetMmapGranularity() {
30 uptr
GetMaxVirtualAddress() {
31 #if SANITIZER_WORDSIZE == 64
32 # if defined(__powerpc64__)
33 // On PowerPC64 we have two different address space layouts: 44- and 46-bit.
34 // We somehow need to figure our which one we are using now and choose
35 // one of 0x00000fffffffffffUL and 0x00003fffffffffffUL.
36 // Note that with 'ulimit -s unlimited' the stack is moved away from the top
37 // of the address space, so simply checking the stack address is not enough.
38 return (1ULL << 44) - 1; // 0x00000fffffffffffUL
40 return (1ULL << 47) - 1; // 0x00007fffffffffffUL;
42 #else // SANITIZER_WORDSIZE == 32
43 // FIXME: We can probably lower this on Android?
44 return (1ULL << 32) - 1; // 0xffffffff;
45 #endif // SANITIZER_WORDSIZE
48 void *MmapOrDie(uptr size
, const char *mem_type
) {
49 size
= RoundUpTo(size
, GetPageSizeCached());
50 uptr res
= internal_mmap(0, size
,
51 PROT_READ
| PROT_WRITE
,
52 MAP_PRIVATE
| MAP_ANON
, -1, 0);
54 if (internal_iserror(res
, &reserrno
)) {
55 static int recursion_count
;
56 if (recursion_count
) {
57 // The Report() and CHECK calls below may call mmap recursively and fail.
58 // If we went into recursion, just die.
59 RawWrite("ERROR: Failed to mmap\n");
63 Report("ERROR: %s failed to allocate 0x%zx (%zd) bytes of %s: %d\n",
64 SanitizerToolName
, size
, size
, mem_type
, reserrno
);
66 CHECK("unable to mmap" && 0);
71 void UnmapOrDie(void *addr
, uptr size
) {
72 if (!addr
|| !size
) return;
73 uptr res
= internal_munmap(addr
, size
);
74 if (internal_iserror(res
)) {
75 Report("ERROR: %s failed to deallocate 0x%zx (%zd) bytes at address %p\n",
76 SanitizerToolName
, size
, size
, addr
);
77 CHECK("unable to unmap" && 0);
81 void *MmapFixedNoReserve(uptr fixed_addr
, uptr size
) {
82 uptr PageSize
= GetPageSizeCached();
83 uptr p
= internal_mmap((void*)(fixed_addr
& ~(PageSize
- 1)),
84 RoundUpTo(size
, PageSize
),
85 PROT_READ
| PROT_WRITE
,
86 MAP_PRIVATE
| MAP_ANON
| MAP_FIXED
| MAP_NORESERVE
,
89 if (internal_iserror(p
, &reserrno
))
91 "%s failed to allocate 0x%zx (%zd) bytes at address %p (%d)\n",
92 SanitizerToolName
, size
, size
, fixed_addr
, reserrno
);
96 void *MmapFixedOrDie(uptr fixed_addr
, uptr size
) {
97 uptr PageSize
= GetPageSizeCached();
98 uptr p
= internal_mmap((void*)(fixed_addr
& ~(PageSize
- 1)),
99 RoundUpTo(size
, PageSize
),
100 PROT_READ
| PROT_WRITE
,
101 MAP_PRIVATE
| MAP_ANON
| MAP_FIXED
,
104 if (internal_iserror(p
, &reserrno
)) {
106 " %s failed to allocate 0x%zx (%zd) bytes at address %p (%d)\n",
107 SanitizerToolName
, size
, size
, fixed_addr
, reserrno
);
108 CHECK("unable to mmap" && 0);
113 void *Mprotect(uptr fixed_addr
, uptr size
) {
114 return (void *)internal_mmap((void*)fixed_addr
, size
,
116 MAP_PRIVATE
| MAP_ANON
| MAP_FIXED
|
117 MAP_NORESERVE
, -1, 0);
120 void *MapFileToMemory(const char *file_name
, uptr
*buff_size
) {
121 uptr openrv
= OpenFile(file_name
, false);
122 CHECK(!internal_iserror(openrv
));
124 uptr fsize
= internal_filesize(fd
);
125 CHECK_NE(fsize
, (uptr
)-1);
127 *buff_size
= RoundUpTo(fsize
, GetPageSizeCached());
128 uptr map
= internal_mmap(0, *buff_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0);
129 return internal_iserror(map
) ? 0 : (void *)map
;
133 static inline bool IntervalsAreSeparate(uptr start1
, uptr end1
,
134 uptr start2
, uptr end2
) {
135 CHECK(start1
<= end1
);
136 CHECK(start2
<= end2
);
137 return (end1
< start2
) || (end2
< start1
);
140 // FIXME: this is thread-unsafe, but should not cause problems most of the time.
141 // When the shadow is mapped only a single thread usually exists (plus maybe
142 // several worker threads on Mac, which aren't expected to map big chunks of
144 bool MemoryRangeIsAvailable(uptr range_start
, uptr range_end
) {
145 MemoryMappingLayout
proc_maps(/*cache_enabled*/true);
147 while (proc_maps
.Next(&start
, &end
,
148 /*offset*/0, /*filename*/0, /*filename_size*/0,
150 if (!IntervalsAreSeparate(start
, end
, range_start
, range_end
))
156 void DumpProcessMap() {
157 MemoryMappingLayout
proc_maps(/*cache_enabled*/true);
159 const sptr kBufSize
= 4095;
160 char *filename
= (char*)MmapOrDie(kBufSize
, __FUNCTION__
);
161 Report("Process memory map follows:\n");
162 while (proc_maps
.Next(&start
, &end
, /* file_offset */0,
163 filename
, kBufSize
, /* protection */0)) {
164 Printf("\t%p-%p\t%s\n", (void*)start
, (void*)end
, filename
);
166 Report("End of process memory map.\n");
167 UnmapOrDie(filename
, kBufSize
);
170 const char *GetPwd() {
171 return GetEnv("PWD");
174 char *FindPathToBinary(const char *name
) {
175 const char *path
= GetEnv("PATH");
178 uptr name_len
= internal_strlen(name
);
179 InternalScopedBuffer
<char> buffer(kMaxPathLength
);
180 const char *beg
= path
;
182 const char *end
= internal_strchrnul(beg
, ':');
183 uptr prefix_len
= end
- beg
;
184 if (prefix_len
+ name_len
+ 2 <= kMaxPathLength
) {
185 internal_memcpy(buffer
.data(), beg
, prefix_len
);
186 buffer
[prefix_len
] = '/';
187 internal_memcpy(&buffer
[prefix_len
+ 1], name
, name_len
);
188 buffer
[prefix_len
+ 1 + name_len
] = '\0';
189 if (FileExists(buffer
.data()))
190 return internal_strdup(buffer
.data());
192 if (*end
== '\0') break;
198 void MaybeOpenReportFile() {
199 if (!log_to_file
) return;
200 uptr pid
= internal_getpid();
201 // If in tracer, use the parent's file.
202 if (pid
== stoptheworld_tracer_pid
)
203 pid
= stoptheworld_tracer_ppid
;
204 if (report_fd_pid
== pid
) return;
205 InternalScopedBuffer
<char> report_path_full(4096);
206 internal_snprintf(report_path_full
.data(), report_path_full
.size(),
207 "%s.%d", report_path_prefix
, pid
);
208 uptr openrv
= OpenFile(report_path_full
.data(), true);
209 if (internal_iserror(openrv
)) {
210 report_fd
= kStderrFd
;
212 Report("ERROR: Can't open file: %s\n", report_path_full
.data());
215 if (report_fd
!= kInvalidFd
) {
216 // We're in the child. Close the parent's log.
217 internal_close(report_fd
);
223 void RawWrite(const char *buffer
) {
224 static const char *kRawWriteError
=
225 "RawWrite can't output requested buffer!\n";
226 uptr length
= (uptr
)internal_strlen(buffer
);
227 MaybeOpenReportFile();
228 if (length
!= internal_write(report_fd
, buffer
, length
)) {
229 internal_write(report_fd
, kRawWriteError
, internal_strlen(kRawWriteError
));
234 bool GetCodeRangeForFile(const char *module
, uptr
*start
, uptr
*end
) {
235 uptr s
, e
, off
, prot
;
236 InternalScopedString
buff(4096);
237 MemoryMappingLayout
proc_maps(/*cache_enabled*/false);
238 while (proc_maps
.Next(&s
, &e
, &off
, buff
.data(), buff
.size(), &prot
)) {
239 if ((prot
& MemoryMappingLayout::kProtectionExecute
) != 0
240 && internal_strcmp(module
, buff
.data()) == 0) {
249 } // namespace __sanitizer
251 #endif // SANITIZER_LINUX || SANITIZER_MAC