1 /* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "mem_map.h" 18 19 #include <corkscrew/map_info.h> 20 21 #include "base/stringprintf.h" 22 #include "ScopedFd.h" 23 #include "utils.h" 24 25 #define USE_ASHMEM 1 26 27 #ifdef USE_ASHMEM 28 #include <cutils/ashmem.h> 29 #endif 30 31 namespace art { 32 33 #if !defined(NDEBUG) 34 35 static std::ostream& operator<<(std::ostream& os, map_info_t* rhs) { 36 for (map_info_t* m = rhs; m != NULL; m = m->next) { 37 os << StringPrintf("0x%08x-0x%08x %c%c %s\n", 38 static_cast<uint32_t>(m->start), 39 static_cast<uint32_t>(m->end), 40 m->is_readable ? 'r' : '-', m->is_executable ? 'x' : '-', m->name); 41 } 42 return os; 43 } 44 45 static void CheckMapRequest(byte* addr, size_t byte_count) { 46 if (addr == NULL) { 47 return; 48 } 49 50 uint32_t base = reinterpret_cast<size_t>(addr); 51 uint32_t limit = base + byte_count; 52 53 map_info_t* map_info_list = load_map_info_list(getpid()); 54 for (map_info_t* m = map_info_list; m != NULL; m = m->next) { 55 CHECK(!(base >= m->start && base < m->end) // start of new within old 56 && !(limit > m->start && limit < m->end) // end of new within old 57 && !(base <= m->start && limit > m->end)) // start/end of new includes all of old 58 << StringPrintf("Requested region 0x%08x-0x%08x overlaps with existing map 0x%08x-0x%08x (%s)\n", 59 base, limit, 60 static_cast<uint32_t>(m->start), static_cast<uint32_t>(m->end), m->name) 61 << map_info_list; 62 } 63 free_map_info_list(map_info_list); 64 } 65 66 #else 67 static void CheckMapRequest(byte*, size_t) { } 68 #endif 69 70 MemMap* MemMap::MapAnonymous(const char* name, byte* addr, size_t byte_count, int prot) { 71 if (byte_count == 0) { 72 return new MemMap(name, NULL, 0, NULL, 0, prot); 73 } 74 size_t page_aligned_byte_count = RoundUp(byte_count, kPageSize); 75 CheckMapRequest(addr, page_aligned_byte_count); 76 77 #ifdef USE_ASHMEM 78 // android_os_Debug.cpp read_mapinfo assumes all ashmem regions associated with the VM are 79 // prefixed "dalvik-". 80 std::string debug_friendly_name("dalvik-"); 81 debug_friendly_name += name; 82 ScopedFd fd(ashmem_create_region(debug_friendly_name.c_str(), page_aligned_byte_count)); 83 int flags = MAP_PRIVATE; 84 if (fd.get() == -1) { 85 PLOG(ERROR) << "ashmem_create_region failed (" << name << ")"; 86 return NULL; 87 } 88 #else 89 ScopedFd fd(-1); 90 int flags = MAP_PRIVATE | MAP_ANONYMOUS; 91 #endif 92 93 byte* actual = reinterpret_cast<byte*>(mmap(addr, page_aligned_byte_count, prot, flags, fd.get(), 0)); 94 if (actual == MAP_FAILED) { 95 std::string maps; 96 ReadFileToString("/proc/self/maps", &maps); 97 PLOG(ERROR) << "mmap(" << reinterpret_cast<void*>(addr) << ", " << page_aligned_byte_count 98 << ", " << prot << ", " << flags << ", " << fd.get() << ", 0) failed for " << name 99 << "\n" << maps; 100 return NULL; 101 } 102 return new MemMap(name, actual, byte_count, actual, page_aligned_byte_count, prot); 103 } 104 105 MemMap* MemMap::MapFileAtAddress(byte* addr, size_t byte_count, 106 int prot, int flags, int fd, off_t start, bool reuse) { 107 CHECK_NE(0, prot); 108 CHECK_NE(0, flags & (MAP_SHARED | MAP_PRIVATE)); 109 if (byte_count == 0) { 110 return new MemMap("file", NULL, 0, NULL, 0, prot); 111 } 112 // Adjust 'offset' to be page-aligned as required by mmap. 113 int page_offset = start % kPageSize; 114 off_t page_aligned_offset = start - page_offset; 115 // Adjust 'byte_count' to be page-aligned as we will map this anyway. 116 size_t page_aligned_byte_count = RoundUp(byte_count + page_offset, kPageSize); 117 // The 'addr' is modified (if specified, ie non-null) to be page aligned to the file but not 118 // necessarily to virtual memory. mmap will page align 'addr' for us. 119 byte* page_aligned_addr = (addr == NULL) ? NULL : (addr - page_offset); 120 if (!reuse) { 121 // reuse means it is okay that it overlaps an existing page mapping. 122 // Only use this if you actually made the page reservation yourself. 123 CheckMapRequest(page_aligned_addr, page_aligned_byte_count); 124 } else { 125 CHECK(addr != NULL); 126 } 127 byte* actual = reinterpret_cast<byte*>(mmap(page_aligned_addr, 128 page_aligned_byte_count, 129 prot, 130 flags, 131 fd, 132 page_aligned_offset)); 133 if (actual == MAP_FAILED) { 134 std::string maps; 135 ReadFileToString("/proc/self/maps", &maps); 136 PLOG(ERROR) << "mmap(" << reinterpret_cast<void*>(page_aligned_addr) 137 << ", " << page_aligned_byte_count 138 << ", " << prot << ", " << flags << ", " << fd << ", " << page_aligned_offset 139 << ") failed\n" << maps; 140 return NULL; 141 } 142 return new MemMap("file", actual + page_offset, byte_count, actual, page_aligned_byte_count, 143 prot); 144 } 145 146 MemMap::~MemMap() { 147 if (base_begin_ == NULL && base_size_ == 0) { 148 return; 149 } 150 int result = munmap(base_begin_, base_size_); 151 if (result == -1) { 152 PLOG(FATAL) << "munmap failed"; 153 } 154 } 155 156 MemMap::MemMap(const std::string& name, byte* begin, size_t size, void* base_begin, 157 size_t base_size, int prot) 158 : name_(name), begin_(begin), size_(size), base_begin_(base_begin), base_size_(base_size), 159 prot_(prot) { 160 if (size_ == 0) { 161 CHECK(begin_ == NULL); 162 CHECK(base_begin_ == NULL); 163 CHECK_EQ(base_size_, 0U); 164 } else { 165 CHECK(begin_ != NULL); 166 CHECK(base_begin_ != NULL); 167 CHECK_NE(base_size_, 0U); 168 } 169 }; 170 171 void MemMap::UnMapAtEnd(byte* new_end) { 172 DCHECK_GE(new_end, Begin()); 173 DCHECK_LE(new_end, End()); 174 size_t unmap_size = End() - new_end; 175 munmap(new_end, unmap_size); 176 size_ -= unmap_size; 177 } 178 179 bool MemMap::Protect(int prot) { 180 if (base_begin_ == NULL && base_size_ == 0) { 181 prot_ = prot; 182 return true; 183 } 184 185 if (mprotect(base_begin_, base_size_, prot) == 0) { 186 prot_ = prot; 187 return true; 188 } 189 190 PLOG(ERROR) << "mprotect(" << reinterpret_cast<void*>(base_begin_) << ", " << base_size_ << ", " 191 << prot << ") failed"; 192 return false; 193 } 194 195 } // namespace art 196