106 lines
3.1 KiB
C++
106 lines
3.1 KiB
C++
// Copyright 2017 The Crashpad Authors
|
||
//
|
||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||
// you may not use this file except in compliance with the License.
|
||
// You may obtain a copy of the License at
|
||
//
|
||
// http://www.apache.org/licenses/LICENSE-2.0
|
||
//
|
||
// Unless required by applicable law or agreed to in writing, software
|
||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
// See the License for the specific language governing permissions and
|
||
// limitations under the License.
|
||
|
||
#include <sys/mman.h>
|
||
|
||
#include <dlfcn.h>
|
||
#include <errno.h>
|
||
#include <stdint.h>
|
||
#include <unistd.h>
|
||
|
||
#include "dlfcn_internal.h"
|
||
#include "util/misc/no_cfi_icall.h"
|
||
|
||
#if defined(__USE_FILE_OFFSET64) && __ANDROID_API__ < 21
|
||
|
||
// Bionic has provided a wrapper for __mmap2() since the beginning of time. See
|
||
// bionic/libc/SYSCALLS.TXT in any Android version.
|
||
extern "C" void* __mmap2(void* addr,
|
||
size_t size,
|
||
int prot,
|
||
int flags,
|
||
int fd,
|
||
size_t pgoff);
|
||
|
||
namespace {
|
||
|
||
template <typename T>
|
||
T Align(T value, size_t alignment) {
|
||
return (value + alignment - 1) & ~(alignment - 1);
|
||
}
|
||
|
||
// Adapted from Android 8.0.0 bionic/libc/bionic/mmap.cpp.
|
||
void* LocalMmap64(void* addr,
|
||
size_t size,
|
||
int prot,
|
||
int flags,
|
||
int fd,
|
||
off64_t offset) {
|
||
constexpr int kMmap2Shift = 12;
|
||
|
||
if (offset < 0 || (offset & ((1UL << kMmap2Shift) - 1)) != 0) {
|
||
errno = EINVAL;
|
||
return MAP_FAILED;
|
||
}
|
||
|
||
const size_t rounded = Align(size, getpagesize());
|
||
if (rounded < size || rounded > PTRDIFF_MAX) {
|
||
errno = ENOMEM;
|
||
return MAP_FAILED;
|
||
}
|
||
|
||
const bool is_private_anonymous =
|
||
(flags & (MAP_PRIVATE | MAP_ANONYMOUS)) == (MAP_PRIVATE | MAP_ANONYMOUS);
|
||
const bool is_stack_or_grows_down =
|
||
(flags & (MAP_STACK | MAP_GROWSDOWN)) != 0;
|
||
|
||
void* const result =
|
||
__mmap2(addr, size, prot, flags, fd, offset >> kMmap2Shift);
|
||
|
||
static bool kernel_has_MADV_MERGEABLE = true;
|
||
if (result != MAP_FAILED && kernel_has_MADV_MERGEABLE &&
|
||
is_private_anonymous && !is_stack_or_grows_down) {
|
||
const int saved_errno = errno;
|
||
const int rc = madvise(result, size, MADV_MERGEABLE);
|
||
if (rc == -1 && errno == EINVAL) {
|
||
kernel_has_MADV_MERGEABLE = false;
|
||
}
|
||
errno = saved_errno;
|
||
}
|
||
|
||
return result;
|
||
}
|
||
|
||
} // namespace
|
||
|
||
extern "C" {
|
||
|
||
void* mmap(void* addr, size_t size, int prot, int flags, int fd, off_t offset) {
|
||
// Use the system’s mmap64() wrapper if available. It will be available on
|
||
// Android 5.0 (“Lollipop”) and later.
|
||
static const crashpad::NoCfiIcall<decltype(LocalMmap64)*> mmap64(
|
||
crashpad::internal::Dlsym(RTLD_DEFAULT, "mmap64"));
|
||
if (mmap64) {
|
||
return mmap64(addr, size, prot, flags, fd, offset);
|
||
}
|
||
|
||
// Otherwise, use the local implementation, which should amount to exactly the
|
||
// same thing.
|
||
return LocalMmap64(addr, size, prot, flags, fd, offset);
|
||
}
|
||
|
||
} // extern "C"
|
||
|
||
#endif // defined(__USE_FILE_OFFSET64) && __ANDROID_API__ < 21
|