Brian Carlstrom | 27ec961 | 2011-09-19 20:20:38 -0700 | [diff] [blame] | 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 <sys/mman.h> |
| 20 | |
Elliott Hughes | 6c9c06d | 2011-11-07 16:43:47 -0800 | [diff] [blame^] | 21 | #include "ScopedFd.h" |
| 22 | #include "utils.h" |
| 23 | |
| 24 | #define USE_ASHMEM 1 |
| 25 | |
| 26 | #ifdef USE_ASHMEM |
| 27 | #include <cutils/ashmem.h> |
| 28 | #endif |
| 29 | |
Brian Carlstrom | 27ec961 | 2011-09-19 20:20:38 -0700 | [diff] [blame] | 30 | namespace art { |
| 31 | |
| 32 | size_t ParseHex(const std::string& string) { |
| 33 | CHECK_EQ(8U, string.size()); |
| 34 | const char* str = string.c_str(); |
| 35 | char* end; |
| 36 | size_t value = strtoul(str, &end, 16); |
| 37 | CHECK(end != str) << "Failed to parse hexadecimal value from " << string; |
Elliott Hughes | cc60747 | 2011-10-17 15:34:11 -0700 | [diff] [blame] | 38 | CHECK_EQ(*end, '\0') << "Failed to parse hexadecimal value from " << string; |
Brian Carlstrom | 27ec961 | 2011-09-19 20:20:38 -0700 | [diff] [blame] | 39 | return value; |
| 40 | } |
| 41 | |
| 42 | void CheckMapRequest(byte* addr, size_t length) { |
| 43 | #ifndef NDEBUG |
| 44 | if (addr == NULL) { |
| 45 | return; |
| 46 | } |
| 47 | size_t base = reinterpret_cast<size_t>(addr); |
| 48 | size_t limit = base + length; |
| 49 | |
| 50 | std::string maps; |
| 51 | bool read = ReadFileToString("/proc/self/maps", &maps); |
| 52 | if (!read) { |
| 53 | PLOG(FATAL) << "Failed to read /proc/self/maps"; |
| 54 | } |
| 55 | // Quick and dirty parse of output like shown below. We only focus |
| 56 | // on grabbing the two 32-bit hex values at the start of each line |
| 57 | // and will fail on wider addresses found on 64-bit systems. |
| 58 | |
| 59 | // 00008000-0001f000 r-xp 00000000 b3:01 273 /system/bin/toolbox |
| 60 | // 0001f000-00021000 rw-p 00017000 b3:01 273 /system/bin/toolbox |
| 61 | // 00021000-00029000 rw-p 00000000 00:00 0 [heap] |
| 62 | // 40011000-40053000 r-xp 00000000 b3:01 1050 /system/lib/libc.so |
| 63 | // 40053000-40056000 rw-p 00042000 b3:01 1050 /system/lib/libc.so |
| 64 | // 40056000-40061000 rw-p 00000000 00:00 0 |
| 65 | // 40061000-40063000 r-xp 00000000 b3:01 1107 /system/lib/libusbhost.so |
| 66 | // 40063000-40064000 rw-p 00002000 b3:01 1107 /system/lib/libusbhost.so |
| 67 | // 4009d000-400a0000 r-xp 00000000 b3:01 1022 /system/lib/liblog.so |
| 68 | // 400a0000-400a1000 rw-p 00003000 b3:01 1022 /system/lib/liblog.so |
| 69 | // 400b7000-400cc000 r-xp 00000000 b3:01 932 /system/lib/libm.so |
| 70 | // 400cc000-400cd000 rw-p 00015000 b3:01 932 /system/lib/libm.so |
| 71 | // 400cf000-400d0000 r--p 00000000 00:00 0 |
| 72 | // 400e4000-400ec000 r--s 00000000 00:0b 388 /dev/__properties__ (deleted) |
| 73 | // 400ec000-400fa000 r-xp 00000000 b3:01 1101 /system/lib/libcutils.so |
| 74 | // 400fa000-400fb000 rw-p 0000e000 b3:01 1101 /system/lib/libcutils.so |
| 75 | // 400fb000-4010a000 rw-p 00000000 00:00 0 |
| 76 | // 4010d000-4010e000 r-xp 00000000 b3:01 929 /system/lib/libstdc++.so |
| 77 | // 4010e000-4010f000 rw-p 00001000 b3:01 929 /system/lib/libstdc++.so |
| 78 | // b0001000-b0009000 r-xp 00001000 b3:01 1098 /system/bin/linker |
| 79 | // b0009000-b000a000 rw-p 00009000 b3:01 1098 /system/bin/linker |
| 80 | // b000a000-b0015000 rw-p 00000000 00:00 0 |
| 81 | // bee35000-bee56000 rw-p 00000000 00:00 0 [stack] |
| 82 | // ffff0000-ffff1000 r-xp 00000000 00:00 0 [vectors] |
| 83 | |
| 84 | for (size_t i = 0; i < maps.size(); i++) { |
| 85 | size_t remaining = maps.size() - i; |
| 86 | if (remaining < 8+1+8) { // 00008000-0001f000 |
| 87 | LOG(FATAL) << "Failed to parse at pos " << i << "\n" << maps; |
| 88 | } |
| 89 | std::string start_str = maps.substr(i, 8); |
| 90 | std::string end_str = maps.substr(i+1+8, 8); |
| 91 | uint32_t start = ParseHex(start_str); |
| 92 | uint32_t end = ParseHex(end_str); |
Brian Carlstrom | e24fa61 | 2011-09-29 00:53:55 -0700 | [diff] [blame] | 93 | CHECK(!(base >= start && base < end) // start of new within old |
| 94 | && !(limit > start && limit < end) // end of new within old |
| 95 | && !(base <= start && limit > end)) // start/end of new includes all of old |
Brian Carlstrom | 27ec961 | 2011-09-19 20:20:38 -0700 | [diff] [blame] | 96 | << StringPrintf("Requested region %08x-%08x overlaps with existing map %08x-%08x\n", |
| 97 | base, limit, start, end) |
| 98 | << maps; |
| 99 | i += 8+1+8; |
| 100 | i = maps.find('\n', i); |
| 101 | CHECK(i != std::string::npos) << "Failed to find newline from pos " << i << "\n" << maps; |
| 102 | } |
| 103 | #endif |
| 104 | } |
| 105 | |
Elliott Hughes | 6c9c06d | 2011-11-07 16:43:47 -0800 | [diff] [blame^] | 106 | MemMap* MemMap::Map(const char* name, byte* addr, size_t length, int prot) { |
Brian Carlstrom | 27ec961 | 2011-09-19 20:20:38 -0700 | [diff] [blame] | 107 | CHECK_NE(0U, length); |
| 108 | CHECK_NE(0, prot); |
| 109 | size_t page_aligned_size = RoundUp(length, kPageSize); |
| 110 | CheckMapRequest(addr, page_aligned_size); |
Elliott Hughes | 6c9c06d | 2011-11-07 16:43:47 -0800 | [diff] [blame^] | 111 | |
| 112 | #ifdef USE_ASHMEM |
| 113 | ScopedFd fd(ashmem_create_region(name, page_aligned_size)); |
| 114 | int flags = MAP_PRIVATE; |
| 115 | if (fd.get() == -1) { |
| 116 | PLOG(ERROR) << "ashmem_create_region failed (" << name << ")"; |
| 117 | return NULL; |
| 118 | } |
| 119 | #else |
| 120 | ScopedFd fd(-1); |
| 121 | int flags = MAP_PRIVATE | MAP_ANONYMOUS; |
| 122 | #endif |
| 123 | |
| 124 | byte* actual = reinterpret_cast<byte*>(mmap(addr, page_aligned_size, prot, flags, fd.get(), 0)); |
Brian Carlstrom | 27ec961 | 2011-09-19 20:20:38 -0700 | [diff] [blame] | 125 | if (actual == MAP_FAILED) { |
Elliott Hughes | 6c9c06d | 2011-11-07 16:43:47 -0800 | [diff] [blame^] | 126 | PLOG(ERROR) << "mmap failed (" << name << ")"; |
Brian Carlstrom | 27ec961 | 2011-09-19 20:20:38 -0700 | [diff] [blame] | 127 | return NULL; |
| 128 | } |
| 129 | return new MemMap(actual, length, actual, page_aligned_size); |
| 130 | } |
| 131 | |
| 132 | MemMap* MemMap::Map(byte* addr, size_t length, int prot, int flags, int fd, off_t start) { |
| 133 | CHECK_NE(0U, length); |
| 134 | CHECK_NE(0, prot); |
| 135 | CHECK_NE(0, flags & (MAP_SHARED | MAP_PRIVATE)); |
| 136 | // adjust to be page-aligned |
| 137 | int page_offset = start % kPageSize; |
| 138 | off_t page_aligned_offset = start - page_offset; |
| 139 | size_t page_aligned_size = RoundUp(length + page_offset, kPageSize); |
| 140 | CheckMapRequest(addr, page_aligned_size); |
| 141 | byte* actual = reinterpret_cast<byte*>(mmap(addr, |
| 142 | page_aligned_size, |
| 143 | prot, |
| 144 | flags, |
| 145 | fd, |
| 146 | page_aligned_offset)); |
| 147 | if (actual == MAP_FAILED) { |
| 148 | PLOG(ERROR) << "mmap failed"; |
| 149 | return NULL; |
| 150 | } |
| 151 | return new MemMap(actual + page_offset, length, actual, page_aligned_size); |
| 152 | } |
| 153 | |
| 154 | MemMap::~MemMap() { |
| 155 | if (base_addr_ == NULL && base_length_ == 0) { |
| 156 | return; |
| 157 | } |
| 158 | int result = munmap(base_addr_, base_length_); |
| 159 | base_addr_ = NULL; |
| 160 | base_length_ = 0; |
| 161 | if (result == -1) { |
| 162 | PLOG(FATAL) << "munmap failed"; |
| 163 | } |
| 164 | } |
| 165 | |
| 166 | MemMap::MemMap(byte* addr, size_t length, void* base_addr, size_t base_length) |
| 167 | : addr_(addr), length_(length), base_addr_(base_addr), base_length_(base_length) { |
| 168 | CHECK(addr_ != NULL); |
Elliott Hughes | cc60747 | 2011-10-17 15:34:11 -0700 | [diff] [blame] | 169 | CHECK_NE(length_, 0U); |
Brian Carlstrom | 27ec961 | 2011-09-19 20:20:38 -0700 | [diff] [blame] | 170 | CHECK(base_addr_ != NULL); |
Elliott Hughes | cc60747 | 2011-10-17 15:34:11 -0700 | [diff] [blame] | 171 | CHECK_NE(base_length_, 0U); |
Brian Carlstrom | 27ec961 | 2011-09-19 20:20:38 -0700 | [diff] [blame] | 172 | }; |
| 173 | |
| 174 | } // namespace art |