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