blob: 9aa47b7b298eb938e25f3f257a589caac7f99d4d [file] [log] [blame]
Edgar Arriaga28392b52023-09-12 18:47:31 +00001#include <android-base/parseint.h>
Edgar Arriagaa66cc9a2023-08-21 22:00:48 +00002#include <fcntl.h>
3#include <sys/endian.h>
4#include <sys/mman.h>
5#include <sys/stat.h>
6#include <sys/types.h>
7#include <unistd.h>
8#include <iostream>
9#include <string>
10#include <vector>
11
12#include <meminspect.h>
13#include <pin_utils.h>
14
15using namespace std;
16using namespace android::base;
17
Edgar Arriaga28392b52023-09-12 18:47:31 +000018enum ToolMode {
19 MAPPED_FILE, // Files that are mapped in memory
20 PINLIST, // pinlist.meta style file
21 UNKNOWN
22};
Edgar Arriagaa66cc9a2023-08-21 22:00:48 +000023
Edgar Arriaga28392b52023-09-12 18:47:31 +000024void print_pinlist_ranges(const std::vector<VmaRange>& ranges) {
25 cout << "--pinlist memory ranges--" << endl;
26 for (auto&& range : ranges) {
27 cout << "start=" << range.offset << " bytes=" << range.length << endl;
Edgar Arriagaa66cc9a2023-08-21 22:00:48 +000028 }
29}
30
Edgar Arriaga28392b52023-09-12 18:47:31 +000031void print_pinlist_summary(const std::vector<VmaRange>& ranges) {
32 cout << "--pinlist summary--" << endl;
33 uint64_t total_bytes = 0;
34 for (auto&& range : ranges) {
35 total_bytes += range.length;
36 }
37 cout << "total_bytes_to_pin=" << total_bytes << endl;
38}
Edgar Arriagaa66cc9a2023-08-21 22:00:48 +000039
Edgar Arriaga28392b52023-09-12 18:47:31 +000040int perform_file_action(const vector<string>& options) {
41 std::string custom_probe_file;
42 std::string output_file;
43 std::string pinconfig_file;
44
45 bool verbose = false;
46 bool is_zip = false;
47 bool dump_results = false;
48 ProbeType probe_type = UNSET;
49 int64_t write_quota = -1; // unbounded by default
50
51 if (options.empty()) {
52 cerr << "Missing filename for file action, see usage for details." << endl;
53 return 1;
54 }
55
56 std::string input_file = options[0];
57
58 // Validate that the file exists.
59 if (get_file_size(input_file) == -1) {
60 cerr << "Error: Could not read file: " << input_file << endl;
61 return 1;
62 }
63
64 if (input_file.empty()) {
65 cerr << "Error: Should specify an input file." << endl;
66 return 1;
67 }
68
69 // Parse flags
70 for (int i = 1; i < options.size(); ++i) {
Edgar Arriagaa66cc9a2023-08-21 22:00:48 +000071 string option = options[i];
Edgar Arriaga28392b52023-09-12 18:47:31 +000072 if (option == "--gen-probe") {
73 if (probe_type != ProbeType::UNSET) {
74 cerr << "Should only specify one probe treatment. See usage for details." << endl;
75 return 1;
76 }
77 probe_type = ProbeType::GENERATE;
78 continue;
79 }
80
81 if (option == "--use-probe") {
82 if (probe_type != ProbeType::UNSET) {
83 cerr << "Should only specify one probe treatment. See usage for details." << endl;
84 return 1;
85 }
86 probe_type = ProbeType::CUSTOM;
Edgar Arriagaa66cc9a2023-08-21 22:00:48 +000087 ++i;
Edgar Arriaga28392b52023-09-12 18:47:31 +000088 custom_probe_file = options[i];
89 continue;
90 }
91 if (option == "--pinconfig") {
92 ++i;
93 pinconfig_file = options[i];
Edgar Arriagaa66cc9a2023-08-21 22:00:48 +000094 continue;
95 }
96 if (option == "-o") {
97 ++i;
98 output_file = options[i];
99 continue;
100 }
Edgar Arriaga28392b52023-09-12 18:47:31 +0000101 if (option == "--quota") {
102 ++i;
103 android::base::ParseInt(options[i], &write_quota);
104 continue;
105 }
Edgar Arriagaa66cc9a2023-08-21 22:00:48 +0000106 if (option == "-v") {
107 verbose = true;
108 continue;
109 }
Edgar Arriaga28392b52023-09-12 18:47:31 +0000110 if (option == "--zip") {
111 is_zip = true;
112 continue;
113 }
114 if (option == "--dump") {
115 dump_results = true;
Edgar Arriagaa66cc9a2023-08-21 22:00:48 +0000116 continue;
117 }
118 }
119
120 if (verbose) {
Edgar Arriaga28392b52023-09-12 18:47:31 +0000121 cout << "Setting output pinlist file: " << output_file.c_str() << endl;
122 cout << "Setting input file: " << input_file.c_str() << endl;
123 cout << "Setting pinconfig file: " << pinconfig_file.c_str() << endl;
124 cout << "Setting custom probe file: " << custom_probe_file.c_str() << endl;
125 cout << "Setting probe type: " << probe_type << endl;
126 cout << "Dump enabled: " << dump_results << endl;
127 cout << "Is Zip file: " << is_zip << endl;
128 if (write_quota != -1) {
129 cout << "Set Write quota: " << write_quota << endl;
130 }
Edgar Arriagaa66cc9a2023-08-21 22:00:48 +0000131 }
132
Edgar Arriaga28392b52023-09-12 18:47:31 +0000133 PinTool pintool(input_file);
Edgar Arriagaa66cc9a2023-08-21 22:00:48 +0000134
Edgar Arriaga28392b52023-09-12 18:47:31 +0000135 if (is_zip) {
136 pintool.set_verbose_output(verbose);
137 if (probe_type == ProbeType::CUSTOM) {
138 if (verbose) {
139 cout << "Using custom probe file: " << custom_probe_file << endl;
140 }
141 pintool.read_probe_from_pinlist(custom_probe_file);
142 } else if (probe_type == ProbeType::GENERATE) {
143 if (verbose) {
144 cout << "Generating probe" << endl;
145 }
146 int res = pintool.probe_resident();
147 if (res > 0) {
148 cerr << "Failed to generate probe. Error Code: " << res << endl;
149 return 1;
150 }
151 }
152 pintool.compute_zip_entry_coverages();
153
154 if (pinconfig_file.length() > 0) {
155 // We have provided a pinconfig file so perform filtering
156 // of computed coverages based on it.
157 pintool.filter_zip_entry_coverages(pinconfig_file);
Edgar Arriagaa66cc9a2023-08-21 22:00:48 +0000158 }
159
Edgar Arriaga28392b52023-09-12 18:47:31 +0000160 if (dump_results) {
161 cout << endl << "----Unfiltered file coverages----" << endl << endl;
162 pintool.dump_coverages(PinTool::DumpType::FILE_COVERAGE);
163
164 if (pinconfig_file.length() > 0) {
165 cout << endl << "----Filtered file coverages----" << endl << endl;
166 pintool.dump_coverages(PinTool::DumpType::FILTERED);
167 }
Edgar Arriagaa66cc9a2023-08-21 22:00:48 +0000168 }
169
Edgar Arriaga28392b52023-09-12 18:47:31 +0000170 if (output_file.length() > 0) {
171 pintool.write_coverages_as_pinlist(output_file, write_quota);
Edgar Arriagaa66cc9a2023-08-21 22:00:48 +0000172 }
173
Edgar Arriaga28392b52023-09-12 18:47:31 +0000174 return 0;
175 } else {
176 if (probe_type != ProbeType::GENERATE) {
177 cerr << "Only generating probes is supported for non-zip files, please include "
178 "--gen-probe on your command"
179 << endl;
180 return 1;
181 }
182
183 // Generic file probing will just return resident memory and offsets
184 // without more contextual information.
185 VmaRangeGroup resident;
186
187 int res = pintool.probe_resident();
188 if (res > 0) {
189 cerr << "Failed to generate probe. Error Code: " << res << endl;
190 return 1;
191 }
192
193 pintool.dump_coverages(PinTool::DumpType::PROBE);
194
195 if (output_file.length() > 0) {
196 res = write_pinlist_file(output_file, resident.ranges, write_quota);
197 if (res > 0) {
198 cerr << "Failed to write pin file at: " << output_file << endl;
199 } else if (verbose) {
200 cout << "Finished writing pin file at: " << output_file << endl;
201 }
202 }
Edgar Arriagaa66cc9a2023-08-21 22:00:48 +0000203 return res;
204 }
Edgar Arriaga28392b52023-09-12 18:47:31 +0000205 return 0;
Edgar Arriagaa66cc9a2023-08-21 22:00:48 +0000206}
207
Edgar Arriaga28392b52023-09-12 18:47:31 +0000208int perform_pinlist_action(const vector<string>& options) {
Edgar Arriagaa66cc9a2023-08-21 22:00:48 +0000209 string pinner_file;
210 bool verbose = false;
Edgar Arriaga28392b52023-09-12 18:47:31 +0000211 bool dump = false;
212 bool summary = false;
213
214 if (options.size() < 1) {
215 cerr << "Missing arguments for pinlist mode. See usage for details << endl";
216 return 1;
217 }
218 pinner_file = options[0];
219 for (int i = 1; i < options.size(); ++i) {
Edgar Arriagaa66cc9a2023-08-21 22:00:48 +0000220 string option = options[i];
Edgar Arriagaa66cc9a2023-08-21 22:00:48 +0000221
222 if (option == "-v") {
223 verbose = true;
224 }
Edgar Arriaga28392b52023-09-12 18:47:31 +0000225
226 if (option == "--dump") {
227 dump = true;
228 }
229
230 if (option == "--summary") {
231 summary = true;
232 }
Edgar Arriagaa66cc9a2023-08-21 22:00:48 +0000233 }
Edgar Arriaga28392b52023-09-12 18:47:31 +0000234
Edgar Arriagaa66cc9a2023-08-21 22:00:48 +0000235 if (pinner_file.empty()) {
236 cerr << "Error: Pinlist file to dump is missing. Specify it with '-p <file>'" << endl;
237 return 1;
238 }
Edgar Arriaga28392b52023-09-12 18:47:31 +0000239
Edgar Arriagaa66cc9a2023-08-21 22:00:48 +0000240 if (verbose) {
241 cout << "Setting file to dump: " << pinner_file.c_str() << endl;
242 }
Edgar Arriaga28392b52023-09-12 18:47:31 +0000243
Edgar Arriagaa66cc9a2023-08-21 22:00:48 +0000244 vector<VmaRange> vma_ranges;
245 if (read_pinlist_file(pinner_file, vma_ranges) == 1) {
246 cerr << "Failed reading pinlist file" << endl;
247 }
Edgar Arriaga28392b52023-09-12 18:47:31 +0000248
249 if (dump) {
250 print_pinlist_ranges(vma_ranges);
251 }
252
253 if (summary) {
254 print_pinlist_summary(vma_ranges);
255 }
Edgar Arriagaa66cc9a2023-08-21 22:00:48 +0000256
257 return 0;
258}
259
Edgar Arriaga28392b52023-09-12 18:47:31 +0000260void print_usage() {
261 const string usage = R"(
262 Expected usage: pintool <mode> <required> [option]
263 where:
264 ./pintool <MODE>
265 <MODE>
266 file <filename> [option]
267 [option]
268 --gen-probe
269 Generate a probe from current resident memory based on provided "file"
270 --use-probe <path_to_input_pinlist.meta>
271 Use a previously generated pinlist.meta style file as the probe to match against.
272 --dump
273 Dump output contents to console.
274 --zip
275 Treat the file as a zip/apk file required for doing per-file coverage analysis and generation.
276 --pinconfig <path_to_pinconfig.txt>
277 Filter output coverage ranges using a provided pinconfig.txt style file. See README.md for samples
278 on the format of that file.
279 -v
280 Enable verbose output.
281
282 pinlist <pinlist_file> [option]
283 <pinlist_file>
284 this is the file that will be used for reading and it should follow the pinlist.meta format.
285 [option]
286 --dump
287 Dump <pinlist_file> contents to console output.
288 -v
289 Enable verbose output.
290 --summary
291 Summary results for the pinlist.meta file
292 )";
293 cout << usage.c_str();
294}
295
Edgar Arriagaa66cc9a2023-08-21 22:00:48 +0000296int main(int argc, char** argv) {
297 if (argc == 1) {
Edgar Arriaga28392b52023-09-12 18:47:31 +0000298 print_usage();
Edgar Arriagaa66cc9a2023-08-21 22:00:48 +0000299 return 0;
300 }
301
302 if (argc < 2) {
303 cerr << "<mode> is missing";
304 return 1;
305 }
Edgar Arriaga28392b52023-09-12 18:47:31 +0000306
307 if (strcmp(argv[1], "--help") == 0) {
308 print_usage();
309 return 0;
Edgar Arriagaa66cc9a2023-08-21 22:00:48 +0000310 }
311
Edgar Arriaga28392b52023-09-12 18:47:31 +0000312 ToolMode mode = ToolMode::UNKNOWN;
313 if (strcmp(argv[1], "file") == 0) {
314 mode = ToolMode::MAPPED_FILE;
315 } else if (strcmp(argv[1], "pinlist") == 0) {
316 mode = ToolMode::PINLIST;
317 }
318
319 if (mode == ToolMode::UNKNOWN) {
Edgar Arriagaa66cc9a2023-08-21 22:00:48 +0000320 cerr << "Failed to find mode: " << argv[1] << ". See usage for available modes." << endl;
321 return 1;
322 }
323
324 vector<string> options;
325 for (int i = 2; i < argc; ++i) {
326 options.push_back(argv[i]);
327 }
328
329 int res;
330 switch (mode) {
Edgar Arriaga28392b52023-09-12 18:47:31 +0000331 case ToolMode::MAPPED_FILE:
332 res = perform_file_action(options);
Edgar Arriagaa66cc9a2023-08-21 22:00:48 +0000333 break;
Edgar Arriaga28392b52023-09-12 18:47:31 +0000334 case ToolMode::PINLIST:
335 res = perform_pinlist_action(options);
Edgar Arriagaa66cc9a2023-08-21 22:00:48 +0000336 break;
Edgar Arriaga28392b52023-09-12 18:47:31 +0000337 case ToolMode::UNKNOWN:
338 cerr << "Unknown <MODE> see usage for details." << endl;
Edgar Arriagaa66cc9a2023-08-21 22:00:48 +0000339 return 1;
Edgar Arriagaa66cc9a2023-08-21 22:00:48 +0000340 }
341
342 return res;
343}