blob: e44a894767a3753603d3038722354ae4163ebbb3 [file] [log] [blame]
Brian Carlstrom27ec9612011-09-19 20:20:38 -07001#include "mem_map.h"
2
3#include <sys/mman.h>
4
5#include "utils.h"
6
7/*
8 * Copyright (C) 2008 The Android Open Source Project
9 *
10 * Licensed under the Apache License, Version 2.0 (the "License");
11 * you may not use this file except in compliance with the License.
12 * You may obtain a copy of the License at
13 *
14 * http://www.apache.org/licenses/LICENSE-2.0
15 *
16 * Unless required by applicable law or agreed to in writing, software
17 * distributed under the License is distributed on an "AS IS" BASIS,
18 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19 * See the License for the specific language governing permissions and
20 * limitations under the License.
21 */
22
23#include "mem_map.h"
24
25#include <sys/mman.h>
26
27namespace art {
28
29size_t ParseHex(const std::string& string) {
30 CHECK_EQ(8U, string.size());
31 const char* str = string.c_str();
32 char* end;
33 size_t value = strtoul(str, &end, 16);
34 CHECK(end != str) << "Failed to parse hexadecimal value from " << string;
35 CHECK(*end == '\0') << "Failed to parse hexadecimal value from " << string;
36 return value;
37}
38
39void CheckMapRequest(byte* addr, size_t length) {
40#ifndef NDEBUG
41 if (addr == NULL) {
42 return;
43 }
44 size_t base = reinterpret_cast<size_t>(addr);
45 size_t limit = base + length;
46
47 std::string maps;
48 bool read = ReadFileToString("/proc/self/maps", &maps);
49 if (!read) {
50 PLOG(FATAL) << "Failed to read /proc/self/maps";
51 }
52 // Quick and dirty parse of output like shown below. We only focus
53 // on grabbing the two 32-bit hex values at the start of each line
54 // and will fail on wider addresses found on 64-bit systems.
55
56 // 00008000-0001f000 r-xp 00000000 b3:01 273 /system/bin/toolbox
57 // 0001f000-00021000 rw-p 00017000 b3:01 273 /system/bin/toolbox
58 // 00021000-00029000 rw-p 00000000 00:00 0 [heap]
59 // 40011000-40053000 r-xp 00000000 b3:01 1050 /system/lib/libc.so
60 // 40053000-40056000 rw-p 00042000 b3:01 1050 /system/lib/libc.so
61 // 40056000-40061000 rw-p 00000000 00:00 0
62 // 40061000-40063000 r-xp 00000000 b3:01 1107 /system/lib/libusbhost.so
63 // 40063000-40064000 rw-p 00002000 b3:01 1107 /system/lib/libusbhost.so
64 // 4009d000-400a0000 r-xp 00000000 b3:01 1022 /system/lib/liblog.so
65 // 400a0000-400a1000 rw-p 00003000 b3:01 1022 /system/lib/liblog.so
66 // 400b7000-400cc000 r-xp 00000000 b3:01 932 /system/lib/libm.so
67 // 400cc000-400cd000 rw-p 00015000 b3:01 932 /system/lib/libm.so
68 // 400cf000-400d0000 r--p 00000000 00:00 0
69 // 400e4000-400ec000 r--s 00000000 00:0b 388 /dev/__properties__ (deleted)
70 // 400ec000-400fa000 r-xp 00000000 b3:01 1101 /system/lib/libcutils.so
71 // 400fa000-400fb000 rw-p 0000e000 b3:01 1101 /system/lib/libcutils.so
72 // 400fb000-4010a000 rw-p 00000000 00:00 0
73 // 4010d000-4010e000 r-xp 00000000 b3:01 929 /system/lib/libstdc++.so
74 // 4010e000-4010f000 rw-p 00001000 b3:01 929 /system/lib/libstdc++.so
75 // b0001000-b0009000 r-xp 00001000 b3:01 1098 /system/bin/linker
76 // b0009000-b000a000 rw-p 00009000 b3:01 1098 /system/bin/linker
77 // b000a000-b0015000 rw-p 00000000 00:00 0
78 // bee35000-bee56000 rw-p 00000000 00:00 0 [stack]
79 // ffff0000-ffff1000 r-xp 00000000 00:00 0 [vectors]
80
81 for (size_t i = 0; i < maps.size(); i++) {
82 size_t remaining = maps.size() - i;
83 if (remaining < 8+1+8) { // 00008000-0001f000
84 LOG(FATAL) << "Failed to parse at pos " << i << "\n" << maps;
85 }
86 std::string start_str = maps.substr(i, 8);
87 std::string end_str = maps.substr(i+1+8, 8);
88 uint32_t start = ParseHex(start_str);
89 uint32_t end = ParseHex(end_str);
90 CHECK(!(base >= start && base < end)
91 && !(limit >= start && limit < end)
92 && !(base <= start && limit > end))
93 << StringPrintf("Requested region %08x-%08x overlaps with existing map %08x-%08x\n",
94 base, limit, start, end)
95 << maps;
96 i += 8+1+8;
97 i = maps.find('\n', i);
98 CHECK(i != std::string::npos) << "Failed to find newline from pos " << i << "\n" << maps;
99 }
100#endif
101}
102
103MemMap* MemMap::Map(byte* addr, size_t length, int prot) {
104 CHECK_NE(0U, length);
105 CHECK_NE(0, prot);
106 size_t page_aligned_size = RoundUp(length, kPageSize);
107 CheckMapRequest(addr, page_aligned_size);
108 byte* actual = reinterpret_cast<byte*>(mmap(addr,
109 page_aligned_size,
110 prot,
111 MAP_PRIVATE | MAP_ANONYMOUS,
112 -1,
113 0));
114 if (actual == MAP_FAILED) {
115 PLOG(ERROR) << "mmap failed";
116 return NULL;
117 }
118 return new MemMap(actual, length, actual, page_aligned_size);
119}
120
121MemMap* MemMap::Map(byte* addr, size_t length, int prot, int flags, int fd, off_t start) {
122 CHECK_NE(0U, length);
123 CHECK_NE(0, prot);
124 CHECK_NE(0, flags & (MAP_SHARED | MAP_PRIVATE));
125 // adjust to be page-aligned
126 int page_offset = start % kPageSize;
127 off_t page_aligned_offset = start - page_offset;
128 size_t page_aligned_size = RoundUp(length + page_offset, kPageSize);
129 CheckMapRequest(addr, page_aligned_size);
130 byte* actual = reinterpret_cast<byte*>(mmap(addr,
131 page_aligned_size,
132 prot,
133 flags,
134 fd,
135 page_aligned_offset));
136 if (actual == MAP_FAILED) {
137 PLOG(ERROR) << "mmap failed";
138 return NULL;
139 }
140 return new MemMap(actual + page_offset, length, actual, page_aligned_size);
141}
142
143MemMap::~MemMap() {
144 if (base_addr_ == NULL && base_length_ == 0) {
145 return;
146 }
147 int result = munmap(base_addr_, base_length_);
148 base_addr_ = NULL;
149 base_length_ = 0;
150 if (result == -1) {
151 PLOG(FATAL) << "munmap failed";
152 }
153}
154
155MemMap::MemMap(byte* addr, size_t length, void* base_addr, size_t base_length)
156 : addr_(addr), length_(length), base_addr_(base_addr), base_length_(base_length) {
157 CHECK(addr_ != NULL);
158 CHECK(length_ != 0);
159 CHECK(base_addr_ != NULL);
160 CHECK(base_length_ != 0);
161};
162
163} // namespace art