blob: 92c6a591fffad5e32ab1990f7e1f70676de3fe25 [file] [log] [blame]
Brian Carlstrom27ec9612011-09-19 20:20:38 -07001/*
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 Hughes6c9c06d2011-11-07 16:43:47 -080021#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 Carlstrom27ec9612011-09-19 20:20:38 -070030namespace art {
31
32size_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 Hughescc607472011-10-17 15:34:11 -070038 CHECK_EQ(*end, '\0') << "Failed to parse hexadecimal value from " << string;
Brian Carlstrom27ec9612011-09-19 20:20:38 -070039 return value;
40}
41
42void CheckMapRequest(byte* addr, size_t length) {
Elliott Hughesad6c9c32012-01-19 17:39:12 -080043#if !defined(NDEBUG)
44#if defined(__APPLE__)
45 UNIMPLEMENTED(WARNING);
46#else
Brian Carlstrom27ec9612011-09-19 20:20:38 -070047 if (addr == NULL) {
48 return;
49 }
50 size_t base = reinterpret_cast<size_t>(addr);
51 size_t limit = base + length;
52
53 std::string maps;
54 bool read = ReadFileToString("/proc/self/maps", &maps);
55 if (!read) {
56 PLOG(FATAL) << "Failed to read /proc/self/maps";
57 }
58 // Quick and dirty parse of output like shown below. We only focus
59 // on grabbing the two 32-bit hex values at the start of each line
60 // and will fail on wider addresses found on 64-bit systems.
61
62 // 00008000-0001f000 r-xp 00000000 b3:01 273 /system/bin/toolbox
63 // 0001f000-00021000 rw-p 00017000 b3:01 273 /system/bin/toolbox
64 // 00021000-00029000 rw-p 00000000 00:00 0 [heap]
65 // 40011000-40053000 r-xp 00000000 b3:01 1050 /system/lib/libc.so
66 // 40053000-40056000 rw-p 00042000 b3:01 1050 /system/lib/libc.so
67 // 40056000-40061000 rw-p 00000000 00:00 0
68 // 40061000-40063000 r-xp 00000000 b3:01 1107 /system/lib/libusbhost.so
69 // 40063000-40064000 rw-p 00002000 b3:01 1107 /system/lib/libusbhost.so
70 // 4009d000-400a0000 r-xp 00000000 b3:01 1022 /system/lib/liblog.so
71 // 400a0000-400a1000 rw-p 00003000 b3:01 1022 /system/lib/liblog.so
72 // 400b7000-400cc000 r-xp 00000000 b3:01 932 /system/lib/libm.so
73 // 400cc000-400cd000 rw-p 00015000 b3:01 932 /system/lib/libm.so
74 // 400cf000-400d0000 r--p 00000000 00:00 0
75 // 400e4000-400ec000 r--s 00000000 00:0b 388 /dev/__properties__ (deleted)
76 // 400ec000-400fa000 r-xp 00000000 b3:01 1101 /system/lib/libcutils.so
77 // 400fa000-400fb000 rw-p 0000e000 b3:01 1101 /system/lib/libcutils.so
78 // 400fb000-4010a000 rw-p 00000000 00:00 0
79 // 4010d000-4010e000 r-xp 00000000 b3:01 929 /system/lib/libstdc++.so
80 // 4010e000-4010f000 rw-p 00001000 b3:01 929 /system/lib/libstdc++.so
81 // b0001000-b0009000 r-xp 00001000 b3:01 1098 /system/bin/linker
82 // b0009000-b000a000 rw-p 00009000 b3:01 1098 /system/bin/linker
83 // b000a000-b0015000 rw-p 00000000 00:00 0
84 // bee35000-bee56000 rw-p 00000000 00:00 0 [stack]
85 // ffff0000-ffff1000 r-xp 00000000 00:00 0 [vectors]
86
87 for (size_t i = 0; i < maps.size(); i++) {
88 size_t remaining = maps.size() - i;
89 if (remaining < 8+1+8) { // 00008000-0001f000
90 LOG(FATAL) << "Failed to parse at pos " << i << "\n" << maps;
91 }
Elliott Hughes95572412011-12-13 18:14:20 -080092 std::string start_str(maps.substr(i, 8));
93 std::string end_str(maps.substr(i+1+8, 8));
Brian Carlstrom27ec9612011-09-19 20:20:38 -070094 uint32_t start = ParseHex(start_str);
95 uint32_t end = ParseHex(end_str);
Brian Carlstrome24fa612011-09-29 00:53:55 -070096 CHECK(!(base >= start && base < end) // start of new within old
97 && !(limit > start && limit < end) // end of new within old
98 && !(base <= start && limit > end)) // start/end of new includes all of old
Brian Carlstrom27ec9612011-09-19 20:20:38 -070099 << StringPrintf("Requested region %08x-%08x overlaps with existing map %08x-%08x\n",
100 base, limit, start, end)
101 << maps;
102 i += 8+1+8;
103 i = maps.find('\n', i);
104 CHECK(i != std::string::npos) << "Failed to find newline from pos " << i << "\n" << maps;
105 }
106#endif
Elliott Hughesad6c9c32012-01-19 17:39:12 -0800107#endif
Brian Carlstrom27ec9612011-09-19 20:20:38 -0700108}
109
Brian Carlstrom89521892011-12-07 22:05:07 -0800110MemMap* MemMap::MapAnonymous(const char* name, byte* addr, size_t length, int prot) {
Brian Carlstrom27ec9612011-09-19 20:20:38 -0700111 CHECK_NE(0U, length);
112 CHECK_NE(0, prot);
113 size_t page_aligned_size = RoundUp(length, kPageSize);
114 CheckMapRequest(addr, page_aligned_size);
Elliott Hughes6c9c06d2011-11-07 16:43:47 -0800115
116#ifdef USE_ASHMEM
117 ScopedFd fd(ashmem_create_region(name, page_aligned_size));
118 int flags = MAP_PRIVATE;
119 if (fd.get() == -1) {
120 PLOG(ERROR) << "ashmem_create_region failed (" << name << ")";
121 return NULL;
122 }
123#else
124 ScopedFd fd(-1);
125 int flags = MAP_PRIVATE | MAP_ANONYMOUS;
126#endif
127
128 byte* actual = reinterpret_cast<byte*>(mmap(addr, page_aligned_size, prot, flags, fd.get(), 0));
Brian Carlstrom27ec9612011-09-19 20:20:38 -0700129 if (actual == MAP_FAILED) {
Elliott Hughes6c9c06d2011-11-07 16:43:47 -0800130 PLOG(ERROR) << "mmap failed (" << name << ")";
Brian Carlstrom27ec9612011-09-19 20:20:38 -0700131 return NULL;
132 }
133 return new MemMap(actual, length, actual, page_aligned_size);
134}
135
Brian Carlstrom89521892011-12-07 22:05:07 -0800136MemMap* MemMap::MapFileAtAddress(byte* addr, size_t length, int prot, int flags, int fd, off_t start) {
Brian Carlstrom27ec9612011-09-19 20:20:38 -0700137 CHECK_NE(0U, length);
138 CHECK_NE(0, prot);
139 CHECK_NE(0, flags & (MAP_SHARED | MAP_PRIVATE));
140 // adjust to be page-aligned
141 int page_offset = start % kPageSize;
142 off_t page_aligned_offset = start - page_offset;
143 size_t page_aligned_size = RoundUp(length + page_offset, kPageSize);
144 CheckMapRequest(addr, page_aligned_size);
145 byte* actual = reinterpret_cast<byte*>(mmap(addr,
146 page_aligned_size,
147 prot,
148 flags,
149 fd,
150 page_aligned_offset));
151 if (actual == MAP_FAILED) {
152 PLOG(ERROR) << "mmap failed";
153 return NULL;
154 }
155 return new MemMap(actual + page_offset, length, actual, page_aligned_size);
156}
157
158MemMap::~MemMap() {
Ian Rogers30fab402012-01-23 15:43:46 -0800159 if (base_begin_ == NULL && base_size_ == 0) {
Brian Carlstrom27ec9612011-09-19 20:20:38 -0700160 return;
161 }
Ian Rogers30fab402012-01-23 15:43:46 -0800162 int result = munmap(base_begin_, base_size_);
Brian Carlstrom27ec9612011-09-19 20:20:38 -0700163 if (result == -1) {
164 PLOG(FATAL) << "munmap failed";
165 }
166}
167
Ian Rogers30fab402012-01-23 15:43:46 -0800168MemMap::MemMap(byte* begin, size_t size, void* base_begin, size_t base_size)
169 : begin_(begin), size_(size), base_begin_(base_begin), base_size_(base_size) {
170 CHECK(begin_ != NULL);
171 CHECK_NE(size_, 0U);
172 CHECK(base_begin_ != NULL);
173 CHECK_NE(base_size_, 0U);
Brian Carlstrom27ec9612011-09-19 20:20:38 -0700174};
175
176} // namespace art