1 //===-- mem_map_linux.cpp ---------------------------------------*- C++ -*-===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
13 #include "mem_map_linux.h"
16 #include "internal_defs.h"
19 #include "report_linux.h"
20 #include "string_utils.h"
24 #include <linux/futex.h>
31 #include <sys/syscall.h>
37 // TODO(chiahungduan): Review if we still need the followings macros.
38 #include <sys/prctl.h>
39 // Definitions of prctl arguments to set a vma name in Android kernels.
40 #define ANDROID_PR_SET_VMA 0x53564d41
41 #define ANDROID_PR_SET_VMA_ANON_NAME 0
46 static void *mmapWrapper(uptr Addr
, uptr Size
, const char *Name
, uptr Flags
) {
47 int MmapFlags
= MAP_PRIVATE
| MAP_ANONYMOUS
;
49 if (Flags
& MAP_NOACCESS
) {
50 MmapFlags
|= MAP_NORESERVE
;
53 MmapProt
= PROT_READ
| PROT_WRITE
;
55 #if defined(__aarch64__)
59 if (Flags
& MAP_MEMTAG
)
63 MmapFlags
|= MAP_FIXED
;
65 mmap(reinterpret_cast<void *>(Addr
), Size
, MmapProt
, MmapFlags
, -1, 0);
66 if (P
== MAP_FAILED
) {
67 if (!(Flags
& MAP_ALLOWNOMEM
) || errno
!= ENOMEM
)
68 reportMapError(errno
== ENOMEM
? Size
: 0);
73 prctl(ANDROID_PR_SET_VMA
, ANDROID_PR_SET_VMA_ANON_NAME
, P
, Size
, Name
);
81 bool MemMapLinux::mapImpl(uptr Addr
, uptr Size
, const char *Name
, uptr Flags
) {
82 void *P
= mmapWrapper(Addr
, Size
, Name
, Flags
);
86 MapBase
= reinterpret_cast<uptr
>(P
);
91 void MemMapLinux::unmapImpl(uptr Addr
, uptr Size
) {
92 // If we unmap all the pages, also mark `MapBase` to 0 to indicate invalid
94 if (Size
== MapCapacity
) {
95 MapBase
= MapCapacity
= 0;
97 // This is partial unmap and is unmapping the pages from the beginning,
98 // shift `MapBase` to the new base.
100 MapBase
= Addr
+ Size
;
104 if (munmap(reinterpret_cast<void *>(Addr
), Size
) != 0)
105 reportUnmapError(Addr
, Size
);
108 bool MemMapLinux::remapImpl(uptr Addr
, uptr Size
, const char *Name
,
110 void *P
= mmapWrapper(Addr
, Size
, Name
, Flags
);
111 if (reinterpret_cast<uptr
>(P
) != Addr
)
116 void MemMapLinux::setMemoryPermissionImpl(uptr Addr
, uptr Size
, uptr Flags
) {
117 int Prot
= (Flags
& MAP_NOACCESS
) ? PROT_NONE
: (PROT_READ
| PROT_WRITE
);
118 if (mprotect(reinterpret_cast<void *>(Addr
), Size
, Prot
) != 0)
119 reportProtectError(Addr
, Size
, Prot
);
122 void MemMapLinux::releaseAndZeroPagesToOSImpl(uptr From
, uptr Size
) {
123 void *Addr
= reinterpret_cast<void *>(From
);
125 while (madvise(Addr
, Size
, MADV_DONTNEED
) == -1 && errno
== EAGAIN
) {
129 bool ReservedMemoryLinux::createImpl(uptr Addr
, uptr Size
, const char *Name
,
131 ReservedMemoryLinux::MemMapT MemMap
;
132 if (!MemMap
.map(Addr
, Size
, Name
, Flags
| MAP_NOACCESS
))
135 MapBase
= MemMap
.getBase();
136 MapCapacity
= MemMap
.getCapacity();
141 void ReservedMemoryLinux::releaseImpl() {
142 if (munmap(reinterpret_cast<void *>(getBase()), getCapacity()) != 0)
143 reportUnmapError(getBase(), getCapacity());
146 ReservedMemoryLinux::MemMapT
ReservedMemoryLinux::dispatchImpl(uptr Addr
,
148 return ReservedMemoryLinux::MemMapT(Addr
, Size
);
153 #endif // SCUDO_LINUX