1 /*
2 * Copyright (C) 2016 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 <errno.h>
18 #include <fcntl.h>
19 #include <inttypes.h>
20 #include <stdint.h>
21 #include <stdio.h>
22 #include <sys/mman.h>
23 #include <sys/types.h>
24 #include <unistd.h>
25
26 #include <android-base/unique_fd.h>
27
28 #include <cctype>
29 #include <memory>
30 #include <string>
31 #include <vector>
32
33 #include <unwindstack/Elf.h>
34 #include <unwindstack/Maps.h>
35 #include <unwindstack/Memory.h>
36
37 namespace unwindstack {
38
Find(uint64_t pc)39 MapInfo* Maps::Find(uint64_t pc) {
40 if (maps_.empty()) {
41 return nullptr;
42 }
43 size_t first = 0;
44 size_t last = maps_.size();
45 while (first < last) {
46 size_t index = (first + last) / 2;
47 MapInfo* cur = maps_[index];
48 if (pc >= cur->start && pc < cur->end) {
49 return cur;
50 } else if (pc < cur->start) {
51 last = index;
52 } else {
53 first = index + 1;
54 }
55 }
56 return nullptr;
57 }
58
59 // Assumes that line does not end in '\n'.
InternalParseLine(const char * line)60 static MapInfo* InternalParseLine(const char* line) {
61 // Do not use a sscanf implementation since it is not performant.
62
63 // Example linux /proc/<pid>/maps lines:
64 // 6f000000-6f01e000 rwxp 00000000 00:0c 16389419 /system/lib/libcomposer.so
65 char* str;
66 const char* old_str = line;
67 uint64_t start = strtoull(old_str, &str, 16);
68 if (old_str == str || *str++ != '-') {
69 return nullptr;
70 }
71
72 old_str = str;
73 uint64_t end = strtoull(old_str, &str, 16);
74 if (old_str == str || !std::isspace(*str++)) {
75 return nullptr;
76 }
77
78 while (std::isspace(*str)) {
79 str++;
80 }
81
82 // Parse permissions data.
83 if (*str == '\0') {
84 return nullptr;
85 }
86 uint16_t flags = 0;
87 if (*str == 'r') {
88 flags |= PROT_READ;
89 } else if (*str != '-') {
90 return nullptr;
91 }
92 str++;
93 if (*str == 'w') {
94 flags |= PROT_WRITE;
95 } else if (*str != '-') {
96 return nullptr;
97 }
98 str++;
99 if (*str == 'x') {
100 flags |= PROT_EXEC;
101 } else if (*str != '-') {
102 return nullptr;
103 }
104 str++;
105 if (*str != 'p' && *str != 's') {
106 return nullptr;
107 }
108 str++;
109
110 if (!std::isspace(*str++)) {
111 return nullptr;
112 }
113
114 old_str = str;
115 uint64_t offset = strtoull(old_str, &str, 16);
116 if (old_str == str || !std::isspace(*str)) {
117 return nullptr;
118 }
119
120 // Ignore the 00:00 values.
121 old_str = str;
122 (void)strtoull(old_str, &str, 16);
123 if (old_str == str || *str++ != ':') {
124 return nullptr;
125 }
126 if (std::isspace(*str)) {
127 return nullptr;
128 }
129
130 // Skip the inode.
131 old_str = str;
132 (void)strtoull(str, &str, 16);
133 if (old_str == str || !std::isspace(*str++)) {
134 return nullptr;
135 }
136
137 // Skip decimal digit.
138 old_str = str;
139 (void)strtoull(old_str, &str, 10);
140 if (old_str == str || (!std::isspace(*str) && *str != '\0')) {
141 return nullptr;
142 }
143
144 while (std::isspace(*str)) {
145 str++;
146 }
147 if (*str == '\0') {
148 return new MapInfo(start, end, offset, flags, "");
149 }
150
151 // Save the name data.
152 std::string name(str);
153
154 // Mark a device map in /dev/ and not in /dev/ashmem/ specially.
155 if (name.substr(0, 5) == "/dev/" && name.substr(5, 7) != "ashmem/") {
156 flags |= MAPS_FLAGS_DEVICE_MAP;
157 }
158 return new MapInfo(start, end, offset, flags, name);
159 }
160
Parse()161 bool Maps::Parse() {
162 int fd = open(GetMapsFile().c_str(), O_RDONLY | O_CLOEXEC);
163 if (fd == -1) {
164 return false;
165 }
166
167 bool return_value = true;
168 char buffer[2048];
169 size_t leftover = 0;
170 while (true) {
171 ssize_t bytes = read(fd, &buffer[leftover], 2048 - leftover);
172 if (bytes == -1) {
173 return_value = false;
174 break;
175 }
176 if (bytes == 0) {
177 break;
178 }
179 bytes += leftover;
180 char* line = buffer;
181 while (bytes > 0) {
182 char* newline = static_cast<char*>(memchr(line, '\n', bytes));
183 if (newline == nullptr) {
184 memmove(buffer, line, bytes);
185 break;
186 }
187 *newline = '\0';
188
189 MapInfo* map_info = InternalParseLine(line);
190 if (map_info == nullptr) {
191 return_value = false;
192 break;
193 }
194 maps_.push_back(map_info);
195
196 bytes -= newline - line + 1;
197 line = newline + 1;
198 }
199 leftover = bytes;
200 }
201 close(fd);
202 return return_value;
203 }
204
Add(uint64_t start,uint64_t end,uint64_t offset,uint64_t flags,const std::string & name,uint64_t load_bias)205 void Maps::Add(uint64_t start, uint64_t end, uint64_t offset, uint64_t flags,
206 const std::string& name, uint64_t load_bias) {
207 MapInfo* map_info = new MapInfo(start, end, offset, flags, name);
208 map_info->load_bias = load_bias;
209 maps_.push_back(map_info);
210 }
211
~Maps()212 Maps::~Maps() {
213 for (auto& map : maps_) {
214 delete map;
215 }
216 }
217
Parse()218 bool BufferMaps::Parse() {
219 const char* start_of_line = buffer_;
220 do {
221 std::string line;
222 const char* end_of_line = strchr(start_of_line, '\n');
223 if (end_of_line == nullptr) {
224 line = start_of_line;
225 } else {
226 line = std::string(start_of_line, end_of_line - start_of_line);
227 end_of_line++;
228 }
229
230 MapInfo* map_info = InternalParseLine(line.c_str());
231 if (map_info == nullptr) {
232 return false;
233 }
234 maps_.push_back(map_info);
235
236 start_of_line = end_of_line;
237 } while (start_of_line != nullptr && *start_of_line != '\0');
238 return true;
239 }
240
GetMapsFile() const241 const std::string RemoteMaps::GetMapsFile() const {
242 return "/proc/" + std::to_string(pid_) + "/maps";
243 }
244
245 } // namespace unwindstack
246