mem_map.cc revision 6c9c06dbb0b16714079afaedbebd3d548aa832b2
127ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom/* 227ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom * Copyright (C) 2008 The Android Open Source Project 327ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom * 427ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom * Licensed under the Apache License, Version 2.0 (the "License"); 527ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom * you may not use this file except in compliance with the License. 627ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom * You may obtain a copy of the License at 727ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom * 827ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom * http://www.apache.org/licenses/LICENSE-2.0 927ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom * 1027ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom * Unless required by applicable law or agreed to in writing, software 1127ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom * distributed under the License is distributed on an "AS IS" BASIS, 1227ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1327ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom * See the License for the specific language governing permissions and 1427ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom * limitations under the License. 1527ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom */ 1627ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom 1727ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom#include "mem_map.h" 1827ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom 1927ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom#include <sys/mman.h> 2027ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom 216c9c06dbb0b16714079afaedbebd3d548aa832b2Elliott Hughes#include "ScopedFd.h" 226c9c06dbb0b16714079afaedbebd3d548aa832b2Elliott Hughes#include "utils.h" 236c9c06dbb0b16714079afaedbebd3d548aa832b2Elliott Hughes 246c9c06dbb0b16714079afaedbebd3d548aa832b2Elliott Hughes#define USE_ASHMEM 1 256c9c06dbb0b16714079afaedbebd3d548aa832b2Elliott Hughes 266c9c06dbb0b16714079afaedbebd3d548aa832b2Elliott Hughes#ifdef USE_ASHMEM 276c9c06dbb0b16714079afaedbebd3d548aa832b2Elliott Hughes#include <cutils/ashmem.h> 286c9c06dbb0b16714079afaedbebd3d548aa832b2Elliott Hughes#endif 296c9c06dbb0b16714079afaedbebd3d548aa832b2Elliott Hughes 3027ec961a1da540ba7f16c07a682585ab167317adBrian Carlstromnamespace art { 3127ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom 3227ec961a1da540ba7f16c07a682585ab167317adBrian Carlstromsize_t ParseHex(const std::string& string) { 3327ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom CHECK_EQ(8U, string.size()); 3427ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom const char* str = string.c_str(); 3527ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom char* end; 3627ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom size_t value = strtoul(str, &end, 16); 3727ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom CHECK(end != str) << "Failed to parse hexadecimal value from " << string; 38cc607471d301e468ac0d84deacd1f60667331f67Elliott Hughes CHECK_EQ(*end, '\0') << "Failed to parse hexadecimal value from " << string; 3927ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom return value; 4027ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom} 4127ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom 4227ec961a1da540ba7f16c07a682585ab167317adBrian Carlstromvoid CheckMapRequest(byte* addr, size_t length) { 4327ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom#ifndef NDEBUG 4427ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom if (addr == NULL) { 4527ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom return; 4627ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom } 4727ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom size_t base = reinterpret_cast<size_t>(addr); 4827ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom size_t limit = base + length; 4927ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom 5027ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom std::string maps; 5127ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom bool read = ReadFileToString("/proc/self/maps", &maps); 5227ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom if (!read) { 5327ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom PLOG(FATAL) << "Failed to read /proc/self/maps"; 5427ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom } 5527ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom // Quick and dirty parse of output like shown below. We only focus 5627ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom // on grabbing the two 32-bit hex values at the start of each line 5727ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom // and will fail on wider addresses found on 64-bit systems. 5827ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom 5927ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom // 00008000-0001f000 r-xp 00000000 b3:01 273 /system/bin/toolbox 6027ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom // 0001f000-00021000 rw-p 00017000 b3:01 273 /system/bin/toolbox 6127ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom // 00021000-00029000 rw-p 00000000 00:00 0 [heap] 6227ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom // 40011000-40053000 r-xp 00000000 b3:01 1050 /system/lib/libc.so 6327ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom // 40053000-40056000 rw-p 00042000 b3:01 1050 /system/lib/libc.so 6427ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom // 40056000-40061000 rw-p 00000000 00:00 0 6527ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom // 40061000-40063000 r-xp 00000000 b3:01 1107 /system/lib/libusbhost.so 6627ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom // 40063000-40064000 rw-p 00002000 b3:01 1107 /system/lib/libusbhost.so 6727ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom // 4009d000-400a0000 r-xp 00000000 b3:01 1022 /system/lib/liblog.so 6827ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom // 400a0000-400a1000 rw-p 00003000 b3:01 1022 /system/lib/liblog.so 6927ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom // 400b7000-400cc000 r-xp 00000000 b3:01 932 /system/lib/libm.so 7027ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom // 400cc000-400cd000 rw-p 00015000 b3:01 932 /system/lib/libm.so 7127ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom // 400cf000-400d0000 r--p 00000000 00:00 0 7227ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom // 400e4000-400ec000 r--s 00000000 00:0b 388 /dev/__properties__ (deleted) 7327ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom // 400ec000-400fa000 r-xp 00000000 b3:01 1101 /system/lib/libcutils.so 7427ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom // 400fa000-400fb000 rw-p 0000e000 b3:01 1101 /system/lib/libcutils.so 7527ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom // 400fb000-4010a000 rw-p 00000000 00:00 0 7627ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom // 4010d000-4010e000 r-xp 00000000 b3:01 929 /system/lib/libstdc++.so 7727ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom // 4010e000-4010f000 rw-p 00001000 b3:01 929 /system/lib/libstdc++.so 7827ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom // b0001000-b0009000 r-xp 00001000 b3:01 1098 /system/bin/linker 7927ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom // b0009000-b000a000 rw-p 00009000 b3:01 1098 /system/bin/linker 8027ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom // b000a000-b0015000 rw-p 00000000 00:00 0 8127ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom // bee35000-bee56000 rw-p 00000000 00:00 0 [stack] 8227ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom // ffff0000-ffff1000 r-xp 00000000 00:00 0 [vectors] 8327ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom 8427ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom for (size_t i = 0; i < maps.size(); i++) { 8527ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom size_t remaining = maps.size() - i; 8627ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom if (remaining < 8+1+8) { // 00008000-0001f000 8727ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom LOG(FATAL) << "Failed to parse at pos " << i << "\n" << maps; 8827ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom } 8927ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom std::string start_str = maps.substr(i, 8); 9027ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom std::string end_str = maps.substr(i+1+8, 8); 9127ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom uint32_t start = ParseHex(start_str); 9227ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom uint32_t end = ParseHex(end_str); 93e24fa61603a60ade3797e4a0c8b3fccb346cb048Brian Carlstrom CHECK(!(base >= start && base < end) // start of new within old 94e24fa61603a60ade3797e4a0c8b3fccb346cb048Brian Carlstrom && !(limit > start && limit < end) // end of new within old 95e24fa61603a60ade3797e4a0c8b3fccb346cb048Brian Carlstrom && !(base <= start && limit > end)) // start/end of new includes all of old 9627ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom << StringPrintf("Requested region %08x-%08x overlaps with existing map %08x-%08x\n", 9727ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom base, limit, start, end) 9827ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom << maps; 9927ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom i += 8+1+8; 10027ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom i = maps.find('\n', i); 10127ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom CHECK(i != std::string::npos) << "Failed to find newline from pos " << i << "\n" << maps; 10227ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom } 10327ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom#endif 10427ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom} 10527ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom 1066c9c06dbb0b16714079afaedbebd3d548aa832b2Elliott HughesMemMap* MemMap::Map(const char* name, byte* addr, size_t length, int prot) { 10727ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom CHECK_NE(0U, length); 10827ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom CHECK_NE(0, prot); 10927ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom size_t page_aligned_size = RoundUp(length, kPageSize); 11027ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom CheckMapRequest(addr, page_aligned_size); 1116c9c06dbb0b16714079afaedbebd3d548aa832b2Elliott Hughes 1126c9c06dbb0b16714079afaedbebd3d548aa832b2Elliott Hughes#ifdef USE_ASHMEM 1136c9c06dbb0b16714079afaedbebd3d548aa832b2Elliott Hughes ScopedFd fd(ashmem_create_region(name, page_aligned_size)); 1146c9c06dbb0b16714079afaedbebd3d548aa832b2Elliott Hughes int flags = MAP_PRIVATE; 1156c9c06dbb0b16714079afaedbebd3d548aa832b2Elliott Hughes if (fd.get() == -1) { 1166c9c06dbb0b16714079afaedbebd3d548aa832b2Elliott Hughes PLOG(ERROR) << "ashmem_create_region failed (" << name << ")"; 1176c9c06dbb0b16714079afaedbebd3d548aa832b2Elliott Hughes return NULL; 1186c9c06dbb0b16714079afaedbebd3d548aa832b2Elliott Hughes } 1196c9c06dbb0b16714079afaedbebd3d548aa832b2Elliott Hughes#else 1206c9c06dbb0b16714079afaedbebd3d548aa832b2Elliott Hughes ScopedFd fd(-1); 1216c9c06dbb0b16714079afaedbebd3d548aa832b2Elliott Hughes int flags = MAP_PRIVATE | MAP_ANONYMOUS; 1226c9c06dbb0b16714079afaedbebd3d548aa832b2Elliott Hughes#endif 1236c9c06dbb0b16714079afaedbebd3d548aa832b2Elliott Hughes 1246c9c06dbb0b16714079afaedbebd3d548aa832b2Elliott Hughes byte* actual = reinterpret_cast<byte*>(mmap(addr, page_aligned_size, prot, flags, fd.get(), 0)); 12527ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom if (actual == MAP_FAILED) { 1266c9c06dbb0b16714079afaedbebd3d548aa832b2Elliott Hughes PLOG(ERROR) << "mmap failed (" << name << ")"; 12727ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom return NULL; 12827ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom } 12927ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom return new MemMap(actual, length, actual, page_aligned_size); 13027ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom} 13127ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom 13227ec961a1da540ba7f16c07a682585ab167317adBrian CarlstromMemMap* MemMap::Map(byte* addr, size_t length, int prot, int flags, int fd, off_t start) { 13327ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom CHECK_NE(0U, length); 13427ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom CHECK_NE(0, prot); 13527ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom CHECK_NE(0, flags & (MAP_SHARED | MAP_PRIVATE)); 13627ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom // adjust to be page-aligned 13727ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom int page_offset = start % kPageSize; 13827ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom off_t page_aligned_offset = start - page_offset; 13927ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom size_t page_aligned_size = RoundUp(length + page_offset, kPageSize); 14027ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom CheckMapRequest(addr, page_aligned_size); 14127ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom byte* actual = reinterpret_cast<byte*>(mmap(addr, 14227ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom page_aligned_size, 14327ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom prot, 14427ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom flags, 14527ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom fd, 14627ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom page_aligned_offset)); 14727ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom if (actual == MAP_FAILED) { 14827ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom PLOG(ERROR) << "mmap failed"; 14927ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom return NULL; 15027ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom } 15127ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom return new MemMap(actual + page_offset, length, actual, page_aligned_size); 15227ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom} 15327ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom 15427ec961a1da540ba7f16c07a682585ab167317adBrian CarlstromMemMap::~MemMap() { 15527ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom if (base_addr_ == NULL && base_length_ == 0) { 15627ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom return; 15727ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom } 15827ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom int result = munmap(base_addr_, base_length_); 15927ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom base_addr_ = NULL; 16027ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom base_length_ = 0; 16127ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom if (result == -1) { 16227ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom PLOG(FATAL) << "munmap failed"; 16327ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom } 16427ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom} 16527ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom 16627ec961a1da540ba7f16c07a682585ab167317adBrian CarlstromMemMap::MemMap(byte* addr, size_t length, void* base_addr, size_t base_length) 16727ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom : addr_(addr), length_(length), base_addr_(base_addr), base_length_(base_length) { 16827ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom CHECK(addr_ != NULL); 169cc607471d301e468ac0d84deacd1f60667331f67Elliott Hughes CHECK_NE(length_, 0U); 17027ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom CHECK(base_addr_ != NULL); 171cc607471d301e468ac0d84deacd1f60667331f67Elliott Hughes CHECK_NE(base_length_, 0U); 17227ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom}; 17327ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom 17427ec961a1da540ba7f16c07a682585ab167317adBrian Carlstrom} // namespace art 175