1 //===-- sanitizer_posix.cc ------------------------------------------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This file is shared between AddressSanitizer and ThreadSanitizer
11 // run-time libraries and implements POSIX-specific functions from
13 //===----------------------------------------------------------------------===//
15 #include "sanitizer_platform.h"
18 #include "sanitizer_common.h"
19 #include "sanitizer_libc.h"
20 #include "sanitizer_procmaps.h"
21 #include "sanitizer_stacktrace.h"
25 namespace __sanitizer
{
27 // ------------- sanitizer_common.h
28 uptr
GetMmapGranularity() {
32 uptr
GetMaxVirtualAddress() {
33 #if SANITIZER_WORDSIZE == 64
34 # if defined(__powerpc64__)
35 // On PowerPC64 we have two different address space layouts: 44- and 46-bit.
36 // We somehow need to figure our which one we are using now and choose
37 // one of 0x00000fffffffffffUL and 0x00003fffffffffffUL.
38 // Note that with 'ulimit -s unlimited' the stack is moved away from the top
39 // of the address space, so simply checking the stack address is not enough.
40 return (1ULL << 44) - 1; // 0x00000fffffffffffUL
41 # elif defined(__aarch64__)
42 return (1ULL << 39) - 1;
44 return (1ULL << 47) - 1; // 0x00007fffffffffffUL;
46 #else // SANITIZER_WORDSIZE == 32
47 // FIXME: We can probably lower this on Android?
48 return (1ULL << 32) - 1; // 0xffffffff;
49 #endif // SANITIZER_WORDSIZE
52 void *MmapOrDie(uptr size
, const char *mem_type
) {
53 size
= RoundUpTo(size
, GetPageSizeCached());
54 uptr res
= internal_mmap(0, size
,
55 PROT_READ
| PROT_WRITE
,
56 MAP_PRIVATE
| MAP_ANON
, -1, 0);
58 if (internal_iserror(res
, &reserrno
)) {
59 static int recursion_count
;
60 if (recursion_count
) {
61 // The Report() and CHECK calls below may call mmap recursively and fail.
62 // If we went into recursion, just die.
63 RawWrite("ERROR: Failed to mmap\n");
67 Report("ERROR: %s failed to allocate 0x%zx (%zd) bytes of %s: %d\n",
68 SanitizerToolName
, size
, size
, mem_type
, reserrno
);
70 CHECK("unable to mmap" && 0);
75 void UnmapOrDie(void *addr
, uptr size
) {
76 if (!addr
|| !size
) return;
77 uptr res
= internal_munmap(addr
, size
);
78 if (internal_iserror(res
)) {
79 Report("ERROR: %s failed to deallocate 0x%zx (%zd) bytes at address %p\n",
80 SanitizerToolName
, size
, size
, addr
);
81 CHECK("unable to unmap" && 0);
85 void *MmapNoReserveOrDie(uptr size
, const char *mem_type
) {
86 uptr PageSize
= GetPageSizeCached();
87 uptr p
= internal_mmap(0,
88 RoundUpTo(size
, PageSize
),
89 PROT_READ
| PROT_WRITE
,
90 MAP_PRIVATE
| MAP_ANON
| MAP_NORESERVE
,
93 if (internal_iserror(p
, &reserrno
)) {
95 "%s failed to allocate noreserve 0x%zx (%zd) bytes for '%s' (%d)\n",
96 SanitizerToolName
, size
, size
, mem_type
, reserrno
);
97 CHECK("unable to mmap" && 0);
102 void *MmapFixedNoReserve(uptr fixed_addr
, uptr size
) {
103 uptr PageSize
= GetPageSizeCached();
104 uptr p
= internal_mmap((void*)(fixed_addr
& ~(PageSize
- 1)),
105 RoundUpTo(size
, PageSize
),
106 PROT_READ
| PROT_WRITE
,
107 MAP_PRIVATE
| MAP_ANON
| MAP_FIXED
| MAP_NORESERVE
,
110 if (internal_iserror(p
, &reserrno
))
112 "%s failed to allocate 0x%zx (%zd) bytes at address %zu (%d)\n",
113 SanitizerToolName
, size
, size
, fixed_addr
, reserrno
);
117 void *MmapFixedOrDie(uptr fixed_addr
, uptr size
) {
118 uptr PageSize
= GetPageSizeCached();
119 uptr p
= internal_mmap((void*)(fixed_addr
& ~(PageSize
- 1)),
120 RoundUpTo(size
, PageSize
),
121 PROT_READ
| PROT_WRITE
,
122 MAP_PRIVATE
| MAP_ANON
| MAP_FIXED
,
125 if (internal_iserror(p
, &reserrno
)) {
127 " %s failed to allocate 0x%zx (%zd) bytes at address %zu (%d)\n",
128 SanitizerToolName
, size
, size
, fixed_addr
, reserrno
);
129 CHECK("unable to mmap" && 0);
134 void *Mprotect(uptr fixed_addr
, uptr size
) {
135 return (void *)internal_mmap((void*)fixed_addr
, size
,
137 MAP_PRIVATE
| MAP_ANON
| MAP_FIXED
|
138 MAP_NORESERVE
, -1, 0);
141 void *MapFileToMemory(const char *file_name
, uptr
*buff_size
) {
142 uptr openrv
= OpenFile(file_name
, false);
143 CHECK(!internal_iserror(openrv
));
145 uptr fsize
= internal_filesize(fd
);
146 CHECK_NE(fsize
, (uptr
)-1);
148 *buff_size
= RoundUpTo(fsize
, GetPageSizeCached());
149 uptr map
= internal_mmap(0, *buff_size
, PROT_READ
, MAP_PRIVATE
, fd
, 0);
150 return internal_iserror(map
) ? 0 : (void *)map
;
154 static inline bool IntervalsAreSeparate(uptr start1
, uptr end1
,
155 uptr start2
, uptr end2
) {
156 CHECK(start1
<= end1
);
157 CHECK(start2
<= end2
);
158 return (end1
< start2
) || (end2
< start1
);
161 // FIXME: this is thread-unsafe, but should not cause problems most of the time.
162 // When the shadow is mapped only a single thread usually exists (plus maybe
163 // several worker threads on Mac, which aren't expected to map big chunks of
165 bool MemoryRangeIsAvailable(uptr range_start
, uptr range_end
) {
166 MemoryMappingLayout
proc_maps(/*cache_enabled*/true);
168 while (proc_maps
.Next(&start
, &end
,
169 /*offset*/0, /*filename*/0, /*filename_size*/0,
171 if (!IntervalsAreSeparate(start
, end
, range_start
, range_end
))
177 void DumpProcessMap() {
178 MemoryMappingLayout
proc_maps(/*cache_enabled*/true);
180 const sptr kBufSize
= 4095;
181 char *filename
= (char*)MmapOrDie(kBufSize
, __func__
);
182 Report("Process memory map follows:\n");
183 while (proc_maps
.Next(&start
, &end
, /* file_offset */0,
184 filename
, kBufSize
, /* protection */0)) {
185 Printf("\t%p-%p\t%s\n", (void*)start
, (void*)end
, filename
);
187 Report("End of process memory map.\n");
188 UnmapOrDie(filename
, kBufSize
);
191 const char *GetPwd() {
192 return GetEnv("PWD");
195 char *FindPathToBinary(const char *name
) {
196 const char *path
= GetEnv("PATH");
199 uptr name_len
= internal_strlen(name
);
200 InternalScopedBuffer
<char> buffer(kMaxPathLength
);
201 const char *beg
= path
;
203 const char *end
= internal_strchrnul(beg
, ':');
204 uptr prefix_len
= end
- beg
;
205 if (prefix_len
+ name_len
+ 2 <= kMaxPathLength
) {
206 internal_memcpy(buffer
.data(), beg
, prefix_len
);
207 buffer
[prefix_len
] = '/';
208 internal_memcpy(&buffer
[prefix_len
+ 1], name
, name_len
);
209 buffer
[prefix_len
+ 1 + name_len
] = '\0';
210 if (FileExists(buffer
.data()))
211 return internal_strdup(buffer
.data());
213 if (*end
== '\0') break;
219 void MaybeOpenReportFile() {
220 if (!log_to_file
) return;
221 uptr pid
= internal_getpid();
222 // If in tracer, use the parent's file.
223 if (pid
== stoptheworld_tracer_pid
)
224 pid
= stoptheworld_tracer_ppid
;
225 if (report_fd_pid
== pid
) return;
226 InternalScopedBuffer
<char> report_path_full(4096);
227 internal_snprintf(report_path_full
.data(), report_path_full
.size(),
228 "%s.%zu", report_path_prefix
, pid
);
229 uptr openrv
= OpenFile(report_path_full
.data(), true);
230 if (internal_iserror(openrv
)) {
231 report_fd
= kStderrFd
;
233 Report("ERROR: Can't open file: %s\n", report_path_full
.data());
236 if (report_fd
!= kInvalidFd
) {
237 // We're in the child. Close the parent's log.
238 internal_close(report_fd
);
244 void RawWrite(const char *buffer
) {
245 static const char *kRawWriteError
=
246 "RawWrite can't output requested buffer!\n";
247 uptr length
= (uptr
)internal_strlen(buffer
);
248 MaybeOpenReportFile();
249 if (length
!= internal_write(report_fd
, buffer
, length
)) {
250 internal_write(report_fd
, kRawWriteError
, internal_strlen(kRawWriteError
));
255 bool GetCodeRangeForFile(const char *module
, uptr
*start
, uptr
*end
) {
256 uptr s
, e
, off
, prot
;
257 InternalScopedString
buff(4096);
258 MemoryMappingLayout
proc_maps(/*cache_enabled*/false);
259 while (proc_maps
.Next(&s
, &e
, &off
, buff
.data(), buff
.size(), &prot
)) {
260 if ((prot
& MemoryMappingLayout::kProtectionExecute
) != 0
261 && internal_strcmp(module
, buff
.data()) == 0) {
270 } // namespace __sanitizer
272 #endif // SANITIZER_POSIX