// 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 #include #include #include #include #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 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 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