blob: b86991854ece6547787c3a520619c799a7c77f35 [file] [log] [blame]
Christopher Ferris09385e72017-04-05 13:25:04 -07001/*
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 <memory>
29#include <string>
30#include <vector>
31
32#include "Maps.h"
33
34MapInfo* Maps::Find(uint64_t pc) {
35 if (maps_.empty()) {
36 return nullptr;
37 }
38 size_t first = 0;
39 size_t last = maps_.size();
40 while (first < last) {
41 size_t index = (first + last) / 2;
42 MapInfo* cur = &maps_[index];
43 if (pc >= cur->start && pc < cur->end) {
44 return cur;
45 } else if (pc < cur->start) {
46 last = index;
47 } else {
48 first = index + 1;
49 }
50 }
51 return nullptr;
52}
53
54bool Maps::ParseLine(const char* line, MapInfo* map_info) {
55 char permissions[5];
56 int name_pos;
57 // Linux /proc/<pid>/maps lines:
58 // 6f000000-6f01e000 rwxp 00000000 00:0c 16389419 /system/lib/libcomposer.so
59 if (sscanf(line, "%" SCNx64 "-%" SCNx64 " %4s %" SCNx64 " %*x:%*x %*d %n", &map_info->start,
60 &map_info->end, permissions, &map_info->offset, &name_pos) != 4) {
61 return false;
62 }
63 map_info->flags = PROT_NONE;
64 if (permissions[0] == 'r') {
65 map_info->flags |= PROT_READ;
66 }
67 if (permissions[1] == 'w') {
68 map_info->flags |= PROT_WRITE;
69 }
70 if (permissions[2] == 'x') {
71 map_info->flags |= PROT_EXEC;
72 }
73
Christopher Ferris051792f2017-06-19 13:42:04 -070074 if (line[name_pos] != '\0') {
75 map_info->name = &line[name_pos];
76 size_t length = map_info->name.length() - 1;
77 if (map_info->name[length] == '\n') {
78 map_info->name.erase(length);
79 }
80
81 // Mark a device map in /dev/and not in /dev/ashmem/ specially.
82 if (map_info->name.substr(0, 5) == "/dev/" && map_info->name.substr(5, 7) != "ashmem/") {
83 map_info->flags |= MAPS_FLAGS_DEVICE_MAP;
84 }
Christopher Ferris09385e72017-04-05 13:25:04 -070085 }
86
87 return true;
88}
89
90bool Maps::Parse() {
91 std::unique_ptr<FILE, decltype(&fclose)> fp(fopen(GetMapsFile().c_str(), "re"), fclose);
92 if (!fp) {
93 return false;
94 }
95
96 bool valid = true;
97 char* line = nullptr;
98 size_t line_len;
99 while (getline(&line, &line_len, fp.get()) > 0) {
100 MapInfo map_info;
101 if (!ParseLine(line, &map_info)) {
102 valid = false;
103 break;
104 }
105
106 maps_.push_back(map_info);
107 }
108 free(line);
109
110 return valid;
111}
112
113Maps::~Maps() {
114 for (auto& map : maps_) {
115 delete map.elf;
116 map.elf = nullptr;
117 }
118}
119
120bool BufferMaps::Parse() {
121 const char* start_of_line = buffer_;
122 do {
123 std::string line;
124 const char* end_of_line = strchr(start_of_line, '\n');
125 if (end_of_line == nullptr) {
126 line = start_of_line;
127 } else {
128 end_of_line++;
129 line = std::string(start_of_line, end_of_line - start_of_line);
130 }
131
132 MapInfo map_info;
133 if (!ParseLine(line.c_str(), &map_info)) {
134 return false;
135 }
136 maps_.push_back(map_info);
137
138 start_of_line = end_of_line;
139 } while (start_of_line != nullptr && *start_of_line != '\0');
140 return true;
141}
142
143const std::string RemoteMaps::GetMapsFile() const {
144 return "/proc/" + std::to_string(pid_) + "/maps";
145}
146
147bool OfflineMaps::Parse() {
148 // Format of maps information:
149 // <uint64_t> StartOffset
150 // <uint64_t> EndOffset
151 // <uint64_t> offset
152 // <uint16_t> flags
153 // <uint16_t> MapNameLength
154 // <VariableLengthValue> MapName
155 android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(file_.c_str(), O_RDONLY)));
156 if (fd == -1) {
157 return false;
158 }
159
160 std::vector<char> name;
161 while (true) {
162 MapInfo map_info;
163 ssize_t bytes = TEMP_FAILURE_RETRY(read(fd, &map_info.start, sizeof(map_info.start)));
164 if (bytes == 0) {
165 break;
166 }
167 if (bytes == -1 || bytes != sizeof(map_info.start)) {
168 return false;
169 }
170 bytes = TEMP_FAILURE_RETRY(read(fd, &map_info.end, sizeof(map_info.end)));
171 if (bytes == -1 || bytes != sizeof(map_info.end)) {
172 return false;
173 }
174 bytes = TEMP_FAILURE_RETRY(read(fd, &map_info.offset, sizeof(map_info.offset)));
175 if (bytes == -1 || bytes != sizeof(map_info.offset)) {
176 return false;
177 }
178 bytes = TEMP_FAILURE_RETRY(read(fd, &map_info.flags, sizeof(map_info.flags)));
179 if (bytes == -1 || bytes != sizeof(map_info.flags)) {
180 return false;
181 }
182 uint16_t len;
183 bytes = TEMP_FAILURE_RETRY(read(fd, &len, sizeof(len)));
184 if (bytes == -1 || bytes != sizeof(len)) {
185 return false;
186 }
187 if (len > 0) {
188 name.resize(len);
189 bytes = TEMP_FAILURE_RETRY(read(fd, name.data(), len));
190 if (bytes == -1 || bytes != len) {
191 return false;
192 }
193 map_info.name = std::string(name.data(), len);
194 }
195 maps_.push_back(map_info);
196 }
197 return true;
198}