1 /*
2 * Copyright (C) 2018 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 #pragma once
18
19 #include <stdlib.h>
20 #include <string.h>
21 #include <sys/mman.h>
22 #include <sys/types.h>
23
24 #include <functional>
25 #include <string>
26 #include <vector>
27
28 #include <android-base/file.h>
29
30 namespace android {
31 namespace procinfo {
32
33 template <class CallbackType>
ReadMapFileContent(char * content,const CallbackType & callback)34 bool ReadMapFileContent(char* content, const CallbackType& callback) {
35 uint64_t start_addr;
36 uint64_t end_addr;
37 uint16_t flags;
38 uint64_t pgoff;
39 ino_t inode;
40 char* next_line = content;
41 char* p;
42
43 auto pass_space = [&]() {
44 if (*p != ' ') {
45 return false;
46 }
47 while (*p == ' ') {
48 p++;
49 }
50 return true;
51 };
52
53 auto pass_xdigit = [&]() {
54 if (!isxdigit(*p)) {
55 return false;
56 }
57 do {
58 p++;
59 } while (isxdigit(*p));
60 return true;
61 };
62
63 while (next_line != nullptr && *next_line != '\0') {
64 p = next_line;
65 next_line = strchr(next_line, '\n');
66 if (next_line != nullptr) {
67 *next_line = '\0';
68 next_line++;
69 }
70 // Parse line like: 00400000-00409000 r-xp 00000000 fc:00 426998 /usr/lib/gvfs/gvfsd-http
71 char* end;
72 // start_addr
73 start_addr = strtoull(p, &end, 16);
74 if (end == p || *end != '-') {
75 return false;
76 }
77 p = end + 1;
78 // end_addr
79 end_addr = strtoull(p, &end, 16);
80 if (end == p) {
81 return false;
82 }
83 p = end;
84 if (!pass_space()) {
85 return false;
86 }
87 // flags
88 flags = 0;
89 if (*p == 'r') {
90 flags |= PROT_READ;
91 } else if (*p != '-') {
92 return false;
93 }
94 p++;
95 if (*p == 'w') {
96 flags |= PROT_WRITE;
97 } else if (*p != '-') {
98 return false;
99 }
100 p++;
101 if (*p == 'x') {
102 flags |= PROT_EXEC;
103 } else if (*p != '-') {
104 return false;
105 }
106 p++;
107 if (*p != 'p' && *p != 's') {
108 return false;
109 }
110 p++;
111 if (!pass_space()) {
112 return false;
113 }
114 // pgoff
115 pgoff = strtoull(p, &end, 16);
116 if (end == p) {
117 return false;
118 }
119 p = end;
120 if (!pass_space()) {
121 return false;
122 }
123 // major:minor
124 if (!pass_xdigit() || *p++ != ':' || !pass_xdigit() || !pass_space()) {
125 return false;
126 }
127 // inode
128 inode = strtoull(p, &end, 10);
129 if (end == p) {
130 return false;
131 }
132 p = end;
133
134 if (*p != '\0' && !pass_space()) {
135 return false;
136 }
137
138 // filename
139 callback(start_addr, end_addr, flags, pgoff, inode, p);
140 }
141 return true;
142 }
143
ReadMapFile(const std::string & map_file,const std::function<void (uint64_t,uint64_t,uint16_t,uint64_t,ino_t,const char *)> & callback)144 inline bool ReadMapFile(const std::string& map_file,
145 const std::function<void(uint64_t, uint64_t, uint16_t, uint64_t, ino_t,
146 const char*)>& callback) {
147 std::string content;
148 if (!android::base::ReadFileToString(map_file, &content)) {
149 return false;
150 }
151 return ReadMapFileContent(&content[0], callback);
152 }
153
ReadProcessMaps(pid_t pid,const std::function<void (uint64_t,uint64_t,uint16_t,uint64_t,ino_t,const char *)> & callback)154 inline bool ReadProcessMaps(pid_t pid,
155 const std::function<void(uint64_t, uint64_t, uint16_t, uint64_t, ino_t,
156 const char*)>& callback) {
157 return ReadMapFile("/proc/" + std::to_string(pid) + "/maps", callback);
158 }
159
160 struct MapInfo {
161 uint64_t start;
162 uint64_t end;
163 uint16_t flags;
164 uint64_t pgoff;
165 ino_t inode;
166 std::string name;
167
MapInfoMapInfo168 MapInfo(uint64_t start, uint64_t end, uint16_t flags, uint64_t pgoff, ino_t inode,
169 const char* name)
170 : start(start), end(end), flags(flags), pgoff(pgoff), inode(inode), name(name) {}
171 };
172
ReadProcessMaps(pid_t pid,std::vector<MapInfo> * maps)173 inline bool ReadProcessMaps(pid_t pid, std::vector<MapInfo>* maps) {
174 return ReadProcessMaps(
175 pid, [&](uint64_t start, uint64_t end, uint16_t flags, uint64_t pgoff, ino_t inode,
176 const char* name) { maps->emplace_back(start, end, flags, pgoff, inode, name); });
177 }
178
179 bool ReadMapFileAsyncSafe(const char* map_file, void* buffer, size_t buffer_size,
180 const std::function<void(uint64_t, uint64_t, uint16_t, uint64_t, ino_t,
181 const char*)>& callback);
182
183 } /* namespace procinfo */
184 } /* namespace android */
185