blob: 0d014c2bd8ed0ce0cbf46f75d5cc9ca892ef539c [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) {
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 Carlstrome24fa612011-09-29 00:53:55 -070093 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 Carlstrom27ec9612011-09-19 20:20:38 -070096 << 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 Hughes6c9c06d2011-11-07 16:43:47 -0800106MemMap* MemMap::Map(const char* name, byte* addr, size_t length, int prot) {
Brian Carlstrom27ec9612011-09-19 20:20:38 -0700107 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 Hughes6c9c06d2011-11-07 16:43:47 -0800111
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 Carlstrom27ec9612011-09-19 20:20:38 -0700125 if (actual == MAP_FAILED) {
Elliott Hughes6c9c06d2011-11-07 16:43:47 -0800126 PLOG(ERROR) << "mmap failed (" << name << ")";
Brian Carlstrom27ec9612011-09-19 20:20:38 -0700127 return NULL;
128 }
129 return new MemMap(actual, length, actual, page_aligned_size);
130}
131
132MemMap* 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
154MemMap::~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
166MemMap::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 Hughescc607472011-10-17 15:34:11 -0700169 CHECK_NE(length_, 0U);
Brian Carlstrom27ec9612011-09-19 20:20:38 -0700170 CHECK(base_addr_ != NULL);
Elliott Hughescc607472011-10-17 15:34:11 -0700171 CHECK_NE(base_length_, 0U);
Brian Carlstrom27ec9612011-09-19 20:20:38 -0700172};
173
174} // namespace art