blob: b369c435e04d2f399d3fb6328c19f12a565789fb [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
74 map_info->name = &line[name_pos];
75 size_t length = map_info->name.length() - 1;
76 if (map_info->name[length] == '\n') {
77 map_info->name.erase(length);
78 }
79 // Mark a device map in /dev/and not in /dev/ashmem/ specially.
80 if (!map_info->name.empty() && map_info->name.substr(0, 5) == "/dev/" &&
81 map_info->name.substr(5, 7) != "ashmem/") {
82 map_info->flags |= MAPS_FLAGS_DEVICE_MAP;
83 }
84
85 return true;
86}
87
88bool Maps::Parse() {
89 std::unique_ptr<FILE, decltype(&fclose)> fp(fopen(GetMapsFile().c_str(), "re"), fclose);
90 if (!fp) {
91 return false;
92 }
93
94 bool valid = true;
95 char* line = nullptr;
96 size_t line_len;
97 while (getline(&line, &line_len, fp.get()) > 0) {
98 MapInfo map_info;
99 if (!ParseLine(line, &map_info)) {
100 valid = false;
101 break;
102 }
103
104 maps_.push_back(map_info);
105 }
106 free(line);
107
108 return valid;
109}
110
111Maps::~Maps() {
112 for (auto& map : maps_) {
113 delete map.elf;
114 map.elf = nullptr;
115 }
116}
117
118bool BufferMaps::Parse() {
119 const char* start_of_line = buffer_;
120 do {
121 std::string line;
122 const char* end_of_line = strchr(start_of_line, '\n');
123 if (end_of_line == nullptr) {
124 line = start_of_line;
125 } else {
126 end_of_line++;
127 line = std::string(start_of_line, end_of_line - start_of_line);
128 }
129
130 MapInfo map_info;
131 if (!ParseLine(line.c_str(), &map_info)) {
132 return false;
133 }
134 maps_.push_back(map_info);
135
136 start_of_line = end_of_line;
137 } while (start_of_line != nullptr && *start_of_line != '\0');
138 return true;
139}
140
141const std::string RemoteMaps::GetMapsFile() const {
142 return "/proc/" + std::to_string(pid_) + "/maps";
143}
144
145bool OfflineMaps::Parse() {
146 // Format of maps information:
147 // <uint64_t> StartOffset
148 // <uint64_t> EndOffset
149 // <uint64_t> offset
150 // <uint16_t> flags
151 // <uint16_t> MapNameLength
152 // <VariableLengthValue> MapName
153 android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(file_.c_str(), O_RDONLY)));
154 if (fd == -1) {
155 return false;
156 }
157
158 std::vector<char> name;
159 while (true) {
160 MapInfo map_info;
161 ssize_t bytes = TEMP_FAILURE_RETRY(read(fd, &map_info.start, sizeof(map_info.start)));
162 if (bytes == 0) {
163 break;
164 }
165 if (bytes == -1 || bytes != sizeof(map_info.start)) {
166 return false;
167 }
168 bytes = TEMP_FAILURE_RETRY(read(fd, &map_info.end, sizeof(map_info.end)));
169 if (bytes == -1 || bytes != sizeof(map_info.end)) {
170 return false;
171 }
172 bytes = TEMP_FAILURE_RETRY(read(fd, &map_info.offset, sizeof(map_info.offset)));
173 if (bytes == -1 || bytes != sizeof(map_info.offset)) {
174 return false;
175 }
176 bytes = TEMP_FAILURE_RETRY(read(fd, &map_info.flags, sizeof(map_info.flags)));
177 if (bytes == -1 || bytes != sizeof(map_info.flags)) {
178 return false;
179 }
180 uint16_t len;
181 bytes = TEMP_FAILURE_RETRY(read(fd, &len, sizeof(len)));
182 if (bytes == -1 || bytes != sizeof(len)) {
183 return false;
184 }
185 if (len > 0) {
186 name.resize(len);
187 bytes = TEMP_FAILURE_RETRY(read(fd, name.data(), len));
188 if (bytes == -1 || bytes != len) {
189 return false;
190 }
191 map_info.name = std::string(name.data(), len);
192 }
193 maps_.push_back(map_info);
194 }
195 return true;
196}