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