xref: /freebsd-src/contrib/llvm-project/compiler-rt/lib/sanitizer_common/sanitizer_posix.cpp (revision 68d75eff68281c1b445e3010bb975eae07aac225)
1*68d75effSDimitry Andric //===-- sanitizer_posix.cpp -----------------------------------------------===//
2*68d75effSDimitry Andric //
3*68d75effSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*68d75effSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*68d75effSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*68d75effSDimitry Andric //
7*68d75effSDimitry Andric //===----------------------------------------------------------------------===//
8*68d75effSDimitry Andric //
9*68d75effSDimitry Andric // This file is shared between AddressSanitizer and ThreadSanitizer
10*68d75effSDimitry Andric // run-time libraries and implements POSIX-specific functions from
11*68d75effSDimitry Andric // sanitizer_posix.h.
12*68d75effSDimitry Andric //===----------------------------------------------------------------------===//
13*68d75effSDimitry Andric 
14*68d75effSDimitry Andric #include "sanitizer_platform.h"
15*68d75effSDimitry Andric 
16*68d75effSDimitry Andric #if SANITIZER_POSIX
17*68d75effSDimitry Andric 
18*68d75effSDimitry Andric #include "sanitizer_common.h"
19*68d75effSDimitry Andric #include "sanitizer_file.h"
20*68d75effSDimitry Andric #include "sanitizer_flags.h"
21*68d75effSDimitry Andric #include "sanitizer_libc.h"
22*68d75effSDimitry Andric #include "sanitizer_posix.h"
23*68d75effSDimitry Andric #include "sanitizer_procmaps.h"
24*68d75effSDimitry Andric 
25*68d75effSDimitry Andric #include <errno.h>
26*68d75effSDimitry Andric #include <fcntl.h>
27*68d75effSDimitry Andric #include <signal.h>
28*68d75effSDimitry Andric #include <sys/mman.h>
29*68d75effSDimitry Andric 
30*68d75effSDimitry Andric #if SANITIZER_FREEBSD
31*68d75effSDimitry Andric // The MAP_NORESERVE define has been removed in FreeBSD 11.x, and even before
32*68d75effSDimitry Andric // that, it was never implemented.  So just define it to zero.
33*68d75effSDimitry Andric #undef  MAP_NORESERVE
34*68d75effSDimitry Andric #define MAP_NORESERVE 0
35*68d75effSDimitry Andric #endif
36*68d75effSDimitry Andric 
37*68d75effSDimitry Andric namespace __sanitizer {
38*68d75effSDimitry Andric 
39*68d75effSDimitry Andric // ------------- sanitizer_common.h
40*68d75effSDimitry Andric uptr GetMmapGranularity() {
41*68d75effSDimitry Andric   return GetPageSize();
42*68d75effSDimitry Andric }
43*68d75effSDimitry Andric 
44*68d75effSDimitry Andric void *MmapOrDie(uptr size, const char *mem_type, bool raw_report) {
45*68d75effSDimitry Andric   size = RoundUpTo(size, GetPageSizeCached());
46*68d75effSDimitry Andric   uptr res = MmapNamed(nullptr, size, PROT_READ | PROT_WRITE,
47*68d75effSDimitry Andric                        MAP_PRIVATE | MAP_ANON, mem_type);
48*68d75effSDimitry Andric   int reserrno;
49*68d75effSDimitry Andric   if (UNLIKELY(internal_iserror(res, &reserrno)))
50*68d75effSDimitry Andric     ReportMmapFailureAndDie(size, mem_type, "allocate", reserrno, raw_report);
51*68d75effSDimitry Andric   IncreaseTotalMmap(size);
52*68d75effSDimitry Andric   return (void *)res;
53*68d75effSDimitry Andric }
54*68d75effSDimitry Andric 
55*68d75effSDimitry Andric void UnmapOrDie(void *addr, uptr size) {
56*68d75effSDimitry Andric   if (!addr || !size) return;
57*68d75effSDimitry Andric   uptr res = internal_munmap(addr, size);
58*68d75effSDimitry Andric   if (UNLIKELY(internal_iserror(res))) {
59*68d75effSDimitry Andric     Report("ERROR: %s failed to deallocate 0x%zx (%zd) bytes at address %p\n",
60*68d75effSDimitry Andric            SanitizerToolName, size, size, addr);
61*68d75effSDimitry Andric     CHECK("unable to unmap" && 0);
62*68d75effSDimitry Andric   }
63*68d75effSDimitry Andric   DecreaseTotalMmap(size);
64*68d75effSDimitry Andric }
65*68d75effSDimitry Andric 
66*68d75effSDimitry Andric void *MmapOrDieOnFatalError(uptr size, const char *mem_type) {
67*68d75effSDimitry Andric   size = RoundUpTo(size, GetPageSizeCached());
68*68d75effSDimitry Andric   uptr res = MmapNamed(nullptr, size, PROT_READ | PROT_WRITE,
69*68d75effSDimitry Andric                        MAP_PRIVATE | MAP_ANON, mem_type);
70*68d75effSDimitry Andric   int reserrno;
71*68d75effSDimitry Andric   if (UNLIKELY(internal_iserror(res, &reserrno))) {
72*68d75effSDimitry Andric     if (reserrno == ENOMEM)
73*68d75effSDimitry Andric       return nullptr;
74*68d75effSDimitry Andric     ReportMmapFailureAndDie(size, mem_type, "allocate", reserrno);
75*68d75effSDimitry Andric   }
76*68d75effSDimitry Andric   IncreaseTotalMmap(size);
77*68d75effSDimitry Andric   return (void *)res;
78*68d75effSDimitry Andric }
79*68d75effSDimitry Andric 
80*68d75effSDimitry Andric // We want to map a chunk of address space aligned to 'alignment'.
81*68d75effSDimitry Andric // We do it by mapping a bit more and then unmapping redundant pieces.
82*68d75effSDimitry Andric // We probably can do it with fewer syscalls in some OS-dependent way.
83*68d75effSDimitry Andric void *MmapAlignedOrDieOnFatalError(uptr size, uptr alignment,
84*68d75effSDimitry Andric                                    const char *mem_type) {
85*68d75effSDimitry Andric   CHECK(IsPowerOfTwo(size));
86*68d75effSDimitry Andric   CHECK(IsPowerOfTwo(alignment));
87*68d75effSDimitry Andric   uptr map_size = size + alignment;
88*68d75effSDimitry Andric   uptr map_res = (uptr)MmapOrDieOnFatalError(map_size, mem_type);
89*68d75effSDimitry Andric   if (UNLIKELY(!map_res))
90*68d75effSDimitry Andric     return nullptr;
91*68d75effSDimitry Andric   uptr map_end = map_res + map_size;
92*68d75effSDimitry Andric   uptr res = map_res;
93*68d75effSDimitry Andric   if (!IsAligned(res, alignment)) {
94*68d75effSDimitry Andric     res = (map_res + alignment - 1) & ~(alignment - 1);
95*68d75effSDimitry Andric     UnmapOrDie((void*)map_res, res - map_res);
96*68d75effSDimitry Andric   }
97*68d75effSDimitry Andric   uptr end = res + size;
98*68d75effSDimitry Andric   if (end != map_end)
99*68d75effSDimitry Andric     UnmapOrDie((void*)end, map_end - end);
100*68d75effSDimitry Andric   return (void*)res;
101*68d75effSDimitry Andric }
102*68d75effSDimitry Andric 
103*68d75effSDimitry Andric void *MmapNoReserveOrDie(uptr size, const char *mem_type) {
104*68d75effSDimitry Andric   size = RoundUpTo(size, GetPageSizeCached());
105*68d75effSDimitry Andric   uptr p = MmapNamed(nullptr, size, PROT_READ | PROT_WRITE,
106*68d75effSDimitry Andric                      MAP_PRIVATE | MAP_ANON | MAP_NORESERVE, mem_type);
107*68d75effSDimitry Andric   int reserrno;
108*68d75effSDimitry Andric   if (UNLIKELY(internal_iserror(p, &reserrno)))
109*68d75effSDimitry Andric     ReportMmapFailureAndDie(size, mem_type, "allocate noreserve", reserrno);
110*68d75effSDimitry Andric   IncreaseTotalMmap(size);
111*68d75effSDimitry Andric   return (void *)p;
112*68d75effSDimitry Andric }
113*68d75effSDimitry Andric 
114*68d75effSDimitry Andric static void *MmapFixedImpl(uptr fixed_addr, uptr size, bool tolerate_enomem,
115*68d75effSDimitry Andric                            const char *name) {
116*68d75effSDimitry Andric   size = RoundUpTo(size, GetPageSizeCached());
117*68d75effSDimitry Andric   fixed_addr = RoundDownTo(fixed_addr, GetPageSizeCached());
118*68d75effSDimitry Andric   uptr p = MmapNamed((void *)fixed_addr, size, PROT_READ | PROT_WRITE,
119*68d75effSDimitry Andric                      MAP_PRIVATE | MAP_ANON | MAP_FIXED, name);
120*68d75effSDimitry Andric   int reserrno;
121*68d75effSDimitry Andric   if (UNLIKELY(internal_iserror(p, &reserrno))) {
122*68d75effSDimitry Andric     if (tolerate_enomem && reserrno == ENOMEM)
123*68d75effSDimitry Andric       return nullptr;
124*68d75effSDimitry Andric     char mem_type[40];
125*68d75effSDimitry Andric     internal_snprintf(mem_type, sizeof(mem_type), "memory at address 0x%zx",
126*68d75effSDimitry Andric                       fixed_addr);
127*68d75effSDimitry Andric     ReportMmapFailureAndDie(size, mem_type, "allocate", reserrno);
128*68d75effSDimitry Andric   }
129*68d75effSDimitry Andric   IncreaseTotalMmap(size);
130*68d75effSDimitry Andric   return (void *)p;
131*68d75effSDimitry Andric }
132*68d75effSDimitry Andric 
133*68d75effSDimitry Andric void *MmapFixedOrDie(uptr fixed_addr, uptr size, const char *name) {
134*68d75effSDimitry Andric   return MmapFixedImpl(fixed_addr, size, false /*tolerate_enomem*/, name);
135*68d75effSDimitry Andric }
136*68d75effSDimitry Andric 
137*68d75effSDimitry Andric void *MmapFixedOrDieOnFatalError(uptr fixed_addr, uptr size, const char *name) {
138*68d75effSDimitry Andric   return MmapFixedImpl(fixed_addr, size, true /*tolerate_enomem*/, name);
139*68d75effSDimitry Andric }
140*68d75effSDimitry Andric 
141*68d75effSDimitry Andric bool MprotectNoAccess(uptr addr, uptr size) {
142*68d75effSDimitry Andric   return 0 == internal_mprotect((void*)addr, size, PROT_NONE);
143*68d75effSDimitry Andric }
144*68d75effSDimitry Andric 
145*68d75effSDimitry Andric bool MprotectReadOnly(uptr addr, uptr size) {
146*68d75effSDimitry Andric   return 0 == internal_mprotect((void *)addr, size, PROT_READ);
147*68d75effSDimitry Andric }
148*68d75effSDimitry Andric 
149*68d75effSDimitry Andric #if !SANITIZER_MAC
150*68d75effSDimitry Andric void MprotectMallocZones(void *addr, int prot) {}
151*68d75effSDimitry Andric #endif
152*68d75effSDimitry Andric 
153*68d75effSDimitry Andric fd_t OpenFile(const char *filename, FileAccessMode mode, error_t *errno_p) {
154*68d75effSDimitry Andric   if (ShouldMockFailureToOpen(filename))
155*68d75effSDimitry Andric     return kInvalidFd;
156*68d75effSDimitry Andric   int flags;
157*68d75effSDimitry Andric   switch (mode) {
158*68d75effSDimitry Andric     case RdOnly: flags = O_RDONLY; break;
159*68d75effSDimitry Andric     case WrOnly: flags = O_WRONLY | O_CREAT | O_TRUNC; break;
160*68d75effSDimitry Andric     case RdWr: flags = O_RDWR | O_CREAT; break;
161*68d75effSDimitry Andric   }
162*68d75effSDimitry Andric   fd_t res = internal_open(filename, flags, 0660);
163*68d75effSDimitry Andric   if (internal_iserror(res, errno_p))
164*68d75effSDimitry Andric     return kInvalidFd;
165*68d75effSDimitry Andric   return ReserveStandardFds(res);
166*68d75effSDimitry Andric }
167*68d75effSDimitry Andric 
168*68d75effSDimitry Andric void CloseFile(fd_t fd) {
169*68d75effSDimitry Andric   internal_close(fd);
170*68d75effSDimitry Andric }
171*68d75effSDimitry Andric 
172*68d75effSDimitry Andric bool ReadFromFile(fd_t fd, void *buff, uptr buff_size, uptr *bytes_read,
173*68d75effSDimitry Andric                   error_t *error_p) {
174*68d75effSDimitry Andric   uptr res = internal_read(fd, buff, buff_size);
175*68d75effSDimitry Andric   if (internal_iserror(res, error_p))
176*68d75effSDimitry Andric     return false;
177*68d75effSDimitry Andric   if (bytes_read)
178*68d75effSDimitry Andric     *bytes_read = res;
179*68d75effSDimitry Andric   return true;
180*68d75effSDimitry Andric }
181*68d75effSDimitry Andric 
182*68d75effSDimitry Andric bool WriteToFile(fd_t fd, const void *buff, uptr buff_size, uptr *bytes_written,
183*68d75effSDimitry Andric                  error_t *error_p) {
184*68d75effSDimitry Andric   uptr res = internal_write(fd, buff, buff_size);
185*68d75effSDimitry Andric   if (internal_iserror(res, error_p))
186*68d75effSDimitry Andric     return false;
187*68d75effSDimitry Andric   if (bytes_written)
188*68d75effSDimitry Andric     *bytes_written = res;
189*68d75effSDimitry Andric   return true;
190*68d75effSDimitry Andric }
191*68d75effSDimitry Andric 
192*68d75effSDimitry Andric void *MapFileToMemory(const char *file_name, uptr *buff_size) {
193*68d75effSDimitry Andric   fd_t fd = OpenFile(file_name, RdOnly);
194*68d75effSDimitry Andric   CHECK(fd != kInvalidFd);
195*68d75effSDimitry Andric   uptr fsize = internal_filesize(fd);
196*68d75effSDimitry Andric   CHECK_NE(fsize, (uptr)-1);
197*68d75effSDimitry Andric   CHECK_GT(fsize, 0);
198*68d75effSDimitry Andric   *buff_size = RoundUpTo(fsize, GetPageSizeCached());
199*68d75effSDimitry Andric   uptr map = internal_mmap(nullptr, *buff_size, PROT_READ, MAP_PRIVATE, fd, 0);
200*68d75effSDimitry Andric   return internal_iserror(map) ? nullptr : (void *)map;
201*68d75effSDimitry Andric }
202*68d75effSDimitry Andric 
203*68d75effSDimitry Andric void *MapWritableFileToMemory(void *addr, uptr size, fd_t fd, OFF_T offset) {
204*68d75effSDimitry Andric   uptr flags = MAP_SHARED;
205*68d75effSDimitry Andric   if (addr) flags |= MAP_FIXED;
206*68d75effSDimitry Andric   uptr p = internal_mmap(addr, size, PROT_READ | PROT_WRITE, flags, fd, offset);
207*68d75effSDimitry Andric   int mmap_errno = 0;
208*68d75effSDimitry Andric   if (internal_iserror(p, &mmap_errno)) {
209*68d75effSDimitry Andric     Printf("could not map writable file (%d, %lld, %zu): %zd, errno: %d\n",
210*68d75effSDimitry Andric            fd, (long long)offset, size, p, mmap_errno);
211*68d75effSDimitry Andric     return nullptr;
212*68d75effSDimitry Andric   }
213*68d75effSDimitry Andric   return (void *)p;
214*68d75effSDimitry Andric }
215*68d75effSDimitry Andric 
216*68d75effSDimitry Andric static inline bool IntervalsAreSeparate(uptr start1, uptr end1,
217*68d75effSDimitry Andric                                         uptr start2, uptr end2) {
218*68d75effSDimitry Andric   CHECK(start1 <= end1);
219*68d75effSDimitry Andric   CHECK(start2 <= end2);
220*68d75effSDimitry Andric   return (end1 < start2) || (end2 < start1);
221*68d75effSDimitry Andric }
222*68d75effSDimitry Andric 
223*68d75effSDimitry Andric // FIXME: this is thread-unsafe, but should not cause problems most of the time.
224*68d75effSDimitry Andric // When the shadow is mapped only a single thread usually exists (plus maybe
225*68d75effSDimitry Andric // several worker threads on Mac, which aren't expected to map big chunks of
226*68d75effSDimitry Andric // memory).
227*68d75effSDimitry Andric bool MemoryRangeIsAvailable(uptr range_start, uptr range_end) {
228*68d75effSDimitry Andric   MemoryMappingLayout proc_maps(/*cache_enabled*/true);
229*68d75effSDimitry Andric   if (proc_maps.Error())
230*68d75effSDimitry Andric     return true; // and hope for the best
231*68d75effSDimitry Andric   MemoryMappedSegment segment;
232*68d75effSDimitry Andric   while (proc_maps.Next(&segment)) {
233*68d75effSDimitry Andric     if (segment.start == segment.end) continue;  // Empty range.
234*68d75effSDimitry Andric     CHECK_NE(0, segment.end);
235*68d75effSDimitry Andric     if (!IntervalsAreSeparate(segment.start, segment.end - 1, range_start,
236*68d75effSDimitry Andric                               range_end))
237*68d75effSDimitry Andric       return false;
238*68d75effSDimitry Andric   }
239*68d75effSDimitry Andric   return true;
240*68d75effSDimitry Andric }
241*68d75effSDimitry Andric 
242*68d75effSDimitry Andric void DumpProcessMap() {
243*68d75effSDimitry Andric   MemoryMappingLayout proc_maps(/*cache_enabled*/true);
244*68d75effSDimitry Andric   const sptr kBufSize = 4095;
245*68d75effSDimitry Andric   char *filename = (char*)MmapOrDie(kBufSize, __func__);
246*68d75effSDimitry Andric   MemoryMappedSegment segment(filename, kBufSize);
247*68d75effSDimitry Andric   Report("Process memory map follows:\n");
248*68d75effSDimitry Andric   while (proc_maps.Next(&segment)) {
249*68d75effSDimitry Andric     Printf("\t%p-%p\t%s\n", (void *)segment.start, (void *)segment.end,
250*68d75effSDimitry Andric            segment.filename);
251*68d75effSDimitry Andric   }
252*68d75effSDimitry Andric   Report("End of process memory map.\n");
253*68d75effSDimitry Andric   UnmapOrDie(filename, kBufSize);
254*68d75effSDimitry Andric }
255*68d75effSDimitry Andric 
256*68d75effSDimitry Andric const char *GetPwd() {
257*68d75effSDimitry Andric   return GetEnv("PWD");
258*68d75effSDimitry Andric }
259*68d75effSDimitry Andric 
260*68d75effSDimitry Andric bool IsPathSeparator(const char c) {
261*68d75effSDimitry Andric   return c == '/';
262*68d75effSDimitry Andric }
263*68d75effSDimitry Andric 
264*68d75effSDimitry Andric bool IsAbsolutePath(const char *path) {
265*68d75effSDimitry Andric   return path != nullptr && IsPathSeparator(path[0]);
266*68d75effSDimitry Andric }
267*68d75effSDimitry Andric 
268*68d75effSDimitry Andric void ReportFile::Write(const char *buffer, uptr length) {
269*68d75effSDimitry Andric   SpinMutexLock l(mu);
270*68d75effSDimitry Andric   ReopenIfNecessary();
271*68d75effSDimitry Andric   internal_write(fd, buffer, length);
272*68d75effSDimitry Andric }
273*68d75effSDimitry Andric 
274*68d75effSDimitry Andric bool GetCodeRangeForFile(const char *module, uptr *start, uptr *end) {
275*68d75effSDimitry Andric   MemoryMappingLayout proc_maps(/*cache_enabled*/false);
276*68d75effSDimitry Andric   InternalScopedString buff(kMaxPathLength);
277*68d75effSDimitry Andric   MemoryMappedSegment segment(buff.data(), kMaxPathLength);
278*68d75effSDimitry Andric   while (proc_maps.Next(&segment)) {
279*68d75effSDimitry Andric     if (segment.IsExecutable() &&
280*68d75effSDimitry Andric         internal_strcmp(module, segment.filename) == 0) {
281*68d75effSDimitry Andric       *start = segment.start;
282*68d75effSDimitry Andric       *end = segment.end;
283*68d75effSDimitry Andric       return true;
284*68d75effSDimitry Andric     }
285*68d75effSDimitry Andric   }
286*68d75effSDimitry Andric   return false;
287*68d75effSDimitry Andric }
288*68d75effSDimitry Andric 
289*68d75effSDimitry Andric uptr SignalContext::GetAddress() const {
290*68d75effSDimitry Andric   auto si = static_cast<const siginfo_t *>(siginfo);
291*68d75effSDimitry Andric   return (uptr)si->si_addr;
292*68d75effSDimitry Andric }
293*68d75effSDimitry Andric 
294*68d75effSDimitry Andric bool SignalContext::IsMemoryAccess() const {
295*68d75effSDimitry Andric   auto si = static_cast<const siginfo_t *>(siginfo);
296*68d75effSDimitry Andric   return si->si_signo == SIGSEGV;
297*68d75effSDimitry Andric }
298*68d75effSDimitry Andric 
299*68d75effSDimitry Andric int SignalContext::GetType() const {
300*68d75effSDimitry Andric   return static_cast<const siginfo_t *>(siginfo)->si_signo;
301*68d75effSDimitry Andric }
302*68d75effSDimitry Andric 
303*68d75effSDimitry Andric const char *SignalContext::Describe() const {
304*68d75effSDimitry Andric   switch (GetType()) {
305*68d75effSDimitry Andric     case SIGFPE:
306*68d75effSDimitry Andric       return "FPE";
307*68d75effSDimitry Andric     case SIGILL:
308*68d75effSDimitry Andric       return "ILL";
309*68d75effSDimitry Andric     case SIGABRT:
310*68d75effSDimitry Andric       return "ABRT";
311*68d75effSDimitry Andric     case SIGSEGV:
312*68d75effSDimitry Andric       return "SEGV";
313*68d75effSDimitry Andric     case SIGBUS:
314*68d75effSDimitry Andric       return "BUS";
315*68d75effSDimitry Andric     case SIGTRAP:
316*68d75effSDimitry Andric       return "TRAP";
317*68d75effSDimitry Andric   }
318*68d75effSDimitry Andric   return "UNKNOWN SIGNAL";
319*68d75effSDimitry Andric }
320*68d75effSDimitry Andric 
321*68d75effSDimitry Andric fd_t ReserveStandardFds(fd_t fd) {
322*68d75effSDimitry Andric   CHECK_GE(fd, 0);
323*68d75effSDimitry Andric   if (fd > 2)
324*68d75effSDimitry Andric     return fd;
325*68d75effSDimitry Andric   bool used[3];
326*68d75effSDimitry Andric   internal_memset(used, 0, sizeof(used));
327*68d75effSDimitry Andric   while (fd <= 2) {
328*68d75effSDimitry Andric     used[fd] = true;
329*68d75effSDimitry Andric     fd = internal_dup(fd);
330*68d75effSDimitry Andric   }
331*68d75effSDimitry Andric   for (int i = 0; i <= 2; ++i)
332*68d75effSDimitry Andric     if (used[i])
333*68d75effSDimitry Andric       internal_close(i);
334*68d75effSDimitry Andric   return fd;
335*68d75effSDimitry Andric }
336*68d75effSDimitry Andric 
337*68d75effSDimitry Andric bool ShouldMockFailureToOpen(const char *path) {
338*68d75effSDimitry Andric   return common_flags()->test_only_emulate_no_memorymap &&
339*68d75effSDimitry Andric          internal_strncmp(path, "/proc/", 6) == 0;
340*68d75effSDimitry Andric }
341*68d75effSDimitry Andric 
342*68d75effSDimitry Andric #if SANITIZER_LINUX && !SANITIZER_ANDROID && !SANITIZER_GO
343*68d75effSDimitry Andric int GetNamedMappingFd(const char *name, uptr size, int *flags) {
344*68d75effSDimitry Andric   if (!common_flags()->decorate_proc_maps || !name)
345*68d75effSDimitry Andric     return -1;
346*68d75effSDimitry Andric   char shmname[200];
347*68d75effSDimitry Andric   CHECK(internal_strlen(name) < sizeof(shmname) - 10);
348*68d75effSDimitry Andric   internal_snprintf(shmname, sizeof(shmname), "/dev/shm/%zu [%s]",
349*68d75effSDimitry Andric                     internal_getpid(), name);
350*68d75effSDimitry Andric   int fd = ReserveStandardFds(
351*68d75effSDimitry Andric       internal_open(shmname, O_RDWR | O_CREAT | O_TRUNC | O_CLOEXEC, S_IRWXU));
352*68d75effSDimitry Andric   CHECK_GE(fd, 0);
353*68d75effSDimitry Andric   int res = internal_ftruncate(fd, size);
354*68d75effSDimitry Andric   CHECK_EQ(0, res);
355*68d75effSDimitry Andric   res = internal_unlink(shmname);
356*68d75effSDimitry Andric   CHECK_EQ(0, res);
357*68d75effSDimitry Andric   *flags &= ~(MAP_ANON | MAP_ANONYMOUS);
358*68d75effSDimitry Andric   return fd;
359*68d75effSDimitry Andric }
360*68d75effSDimitry Andric #else
361*68d75effSDimitry Andric int GetNamedMappingFd(const char *name, uptr size, int *flags) {
362*68d75effSDimitry Andric   return -1;
363*68d75effSDimitry Andric }
364*68d75effSDimitry Andric #endif
365*68d75effSDimitry Andric 
366*68d75effSDimitry Andric #if SANITIZER_ANDROID
367*68d75effSDimitry Andric #define PR_SET_VMA 0x53564d41
368*68d75effSDimitry Andric #define PR_SET_VMA_ANON_NAME 0
369*68d75effSDimitry Andric void DecorateMapping(uptr addr, uptr size, const char *name) {
370*68d75effSDimitry Andric   if (!common_flags()->decorate_proc_maps || !name)
371*68d75effSDimitry Andric     return;
372*68d75effSDimitry Andric   internal_prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, addr, size, (uptr)name);
373*68d75effSDimitry Andric }
374*68d75effSDimitry Andric #else
375*68d75effSDimitry Andric void DecorateMapping(uptr addr, uptr size, const char *name) {
376*68d75effSDimitry Andric }
377*68d75effSDimitry Andric #endif
378*68d75effSDimitry Andric 
379*68d75effSDimitry Andric uptr MmapNamed(void *addr, uptr length, int prot, int flags, const char *name) {
380*68d75effSDimitry Andric   int fd = GetNamedMappingFd(name, length, &flags);
381*68d75effSDimitry Andric   uptr res = internal_mmap(addr, length, prot, flags, fd, 0);
382*68d75effSDimitry Andric   if (!internal_iserror(res))
383*68d75effSDimitry Andric     DecorateMapping(res, length, name);
384*68d75effSDimitry Andric   return res;
385*68d75effSDimitry Andric }
386*68d75effSDimitry Andric 
387*68d75effSDimitry Andric 
388*68d75effSDimitry Andric } // namespace __sanitizer
389*68d75effSDimitry Andric 
390*68d75effSDimitry Andric #endif // SANITIZER_POSIX
391