Index: third_party/crashpad/crashpad/util/posix/scoped_mmap.cc |
diff --git a/third_party/crashpad/crashpad/util/posix/scoped_mmap.cc b/third_party/crashpad/crashpad/util/posix/scoped_mmap.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..4860cecbc5b47a2143c9e24a89674dd56d2869ce |
--- /dev/null |
+++ b/third_party/crashpad/crashpad/util/posix/scoped_mmap.cc |
@@ -0,0 +1,115 @@ |
+// Copyright 2017 The Crashpad Authors. All rights reserved. |
+// |
+// 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 "util/posix/scoped_mmap.h" |
+ |
+#include <unistd.h> |
+ |
+#include <algorithm> |
+ |
+#include "base/logging.h" |
+#include "base/numerics/safe_math.h" |
+ |
+namespace { |
+ |
+bool Munmap(uintptr_t addr, size_t len) { |
+ if (munmap(reinterpret_cast<void*>(addr), len) != 0) { |
+ PLOG(ERROR) << "munmap"; |
+ return false; |
+ } |
+ |
+ return true; |
+} |
+ |
+} // namespace |
+ |
+namespace crashpad { |
+ |
+ScopedMmap::ScopedMmap() {} |
+ |
+ScopedMmap::~ScopedMmap() { |
+ if (is_valid()) { |
+ Munmap(reinterpret_cast<uintptr_t>(addr_), len_); |
+ } |
+} |
+ |
+bool ScopedMmap::Reset() { |
+ return ResetAddrLen(MAP_FAILED, 0); |
+} |
+ |
+bool ScopedMmap::ResetAddrLen(void* addr, size_t len) { |
+ const uintptr_t new_addr = reinterpret_cast<uintptr_t>(addr); |
+ |
+ if (addr == MAP_FAILED) { |
+ DCHECK_EQ(len, 0u); |
+ } else { |
+ DCHECK_NE(len, 0u); |
+ DCHECK_EQ(new_addr % getpagesize(), 0u); |
+ DCHECK_EQ(len % getpagesize(), 0u); |
+ DCHECK((base::CheckedNumeric<uintptr_t>(new_addr) + (len - 1)).IsValid()); |
+ } |
+ |
+ bool result = true; |
+ |
+ if (is_valid()) { |
+ const uintptr_t old_addr = reinterpret_cast<uintptr_t>(addr_); |
+ if (old_addr < new_addr) { |
+ result &= Munmap(old_addr, std::min(len_, new_addr - old_addr)); |
+ } |
+ if (old_addr + len_ > new_addr + len) { |
+ uintptr_t unmap_start = std::max(old_addr, new_addr + len); |
+ result &= Munmap(unmap_start, old_addr + len_ - unmap_start); |
+ } |
+ } |
+ |
+ addr_ = addr; |
+ len_ = len; |
+ |
+ return result; |
+} |
+ |
+bool ScopedMmap::ResetMmap(void* addr, |
+ size_t len, |
+ int prot, |
+ int flags, |
+ int fd, |
+ off_t offset) { |
+ // Reset() first, so that a new anonymous mapping can use the address space |
+ // occupied by the old mapping if appropriate. The new mapping will be |
+ // attempted even if there was something wrong with the old mapping, so don’t |
+ // consider the return value from Reset(). |
+ Reset(); |
+ |
+ void* new_addr = mmap(addr, len, prot, flags, fd, offset); |
+ if (new_addr == MAP_FAILED) { |
+ PLOG(ERROR) << "mmap"; |
+ return false; |
+ } |
+ |
+ // The new mapping is effective even if there was something wrong with the old |
+ // mapping, so don’t consider the return value from ResetAddrLen(). |
+ ResetAddrLen(new_addr, len); |
+ return true; |
+} |
+ |
+bool ScopedMmap::Mprotect(int prot) { |
+ if (mprotect(addr_, len_, prot) < 0) { |
+ PLOG(ERROR) << "mprotect"; |
+ return false; |
+ } |
+ |
+ return true; |
+} |
+ |
+} // namespace crashpad |