blob: 7a849f2898d31f97560114f69c70d34547d54a94 [file] [log] [blame]
David Sehrbeca4fe2017-03-30 17:50:24 -07001/*
2 * Copyright (C) 2017 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>
David Sehr55232f12017-04-19 14:06:49 -070018#include <inttypes.h>
David Sehrbeca4fe2017-03-30 17:50:24 -070019#include <stdint.h>
20#include <stdlib.h>
21#include <string.h>
22
23#include <iostream>
24#include <memory>
David Sehr3f3ec672017-04-05 14:43:38 -070025#include <vector>
David Sehrbeca4fe2017-03-30 17:50:24 -070026
27#include "android-base/stringprintf.h"
28
Andreas Gampe57943812017-12-06 21:39:13 -080029#include "base/logging.h" // For InitLogging.
David Sehr3f3ec672017-04-05 14:43:38 -070030#include "base/stringpiece.h"
31
Mathieu Chartier75175552018-01-25 11:23:01 -080032#include "dexlayout.h"
David Sehr9e734c72018-01-04 17:56:19 -080033#include "dex/dex_file.h"
David Sehrbeca4fe2017-03-30 17:50:24 -070034#include "dex_ir.h"
35#include "dex_ir_builder.h"
David Sehr55232f12017-04-19 14:06:49 -070036#ifdef ART_TARGET_ANDROID
David Sehrbeca4fe2017-03-30 17:50:24 -070037#include "pagemap/pagemap.h"
David Sehr55232f12017-04-19 14:06:49 -070038#endif
David Sehrbeca4fe2017-03-30 17:50:24 -070039#include "vdex_file.h"
40
41namespace art {
42
43using android::base::StringPrintf;
44
David Sehrbeca4fe2017-03-30 17:50:24 -070045static bool g_verbose = false;
David Sehr3f3ec672017-04-05 14:43:38 -070046
47// The width needed to print a file page offset (32-bit).
48static constexpr int kPageCountWidth =
49 static_cast<int>(std::numeric_limits<uint32_t>::digits10);
50// Display the sections.
51static constexpr char kSectionHeader[] = "Section name";
David Sehrbeca4fe2017-03-30 17:50:24 -070052
53struct DexSectionInfo {
54 public:
55 std::string name;
56 char letter;
57};
58
59static const std::map<uint16_t, DexSectionInfo> kDexSectionInfoMap = {
60 { DexFile::kDexTypeHeaderItem, { "Header", 'H' } },
61 { DexFile::kDexTypeStringIdItem, { "StringId", 'S' } },
62 { DexFile::kDexTypeTypeIdItem, { "TypeId", 'T' } },
63 { DexFile::kDexTypeProtoIdItem, { "ProtoId", 'P' } },
64 { DexFile::kDexTypeFieldIdItem, { "FieldId", 'F' } },
65 { DexFile::kDexTypeMethodIdItem, { "MethodId", 'M' } },
66 { DexFile::kDexTypeClassDefItem, { "ClassDef", 'C' } },
67 { DexFile::kDexTypeCallSiteIdItem, { "CallSiteId", 'z' } },
68 { DexFile::kDexTypeMethodHandleItem, { "MethodHandle", 'Z' } },
69 { DexFile::kDexTypeMapList, { "TypeMap", 'L' } },
70 { DexFile::kDexTypeTypeList, { "TypeList", 't' } },
71 { DexFile::kDexTypeAnnotationSetRefList, { "AnnotationSetReferenceItem", '1' } },
72 { DexFile::kDexTypeAnnotationSetItem, { "AnnotationSetItem", '2' } },
73 { DexFile::kDexTypeClassDataItem, { "ClassData", 'c' } },
74 { DexFile::kDexTypeCodeItem, { "CodeItem", 'X' } },
75 { DexFile::kDexTypeStringDataItem, { "StringData", 's' } },
76 { DexFile::kDexTypeDebugInfoItem, { "DebugInfo", 'D' } },
77 { DexFile::kDexTypeAnnotationItem, { "AnnotationItem", '3' } },
78 { DexFile::kDexTypeEncodedArrayItem, { "EncodedArrayItem", 'E' } },
79 { DexFile::kDexTypeAnnotationsDirectoryItem, { "AnnotationsDirectoryItem", '4' } }
80};
81
82class PageCount {
83 public:
84 PageCount() {
85 for (auto it = kDexSectionInfoMap.begin(); it != kDexSectionInfoMap.end(); ++it) {
86 map_[it->first] = 0;
87 }
88 }
89 void Increment(uint16_t type) {
90 map_[type]++;
91 }
92 size_t Get(uint16_t type) const {
Vladimir Marko35d5b8a2018-07-03 09:18:32 +010093 auto it = map_.find(type);
94 DCHECK(it != map_.end());
95 return it->second;
David Sehrbeca4fe2017-03-30 17:50:24 -070096 }
97 private:
98 std::map<uint16_t, size_t> map_;
99 DISALLOW_COPY_AND_ASSIGN(PageCount);
100};
101
David Sehr3f3ec672017-04-05 14:43:38 -0700102class Printer {
103 public:
104 Printer() : section_header_width_(ComputeHeaderWidth()) {
David Sehrbeca4fe2017-03-30 17:50:24 -0700105 }
David Sehr3f3ec672017-04-05 14:43:38 -0700106
107 void PrintHeader() const {
108 std::cout << StringPrintf("%-*s %*s %*s %% of %% of",
109 section_header_width_,
110 kSectionHeader,
111 kPageCountWidth,
112 "resident",
113 kPageCountWidth,
114 "total"
115 )
116 << std::endl;
117 std::cout << StringPrintf("%-*s %*s %*s sect. total",
118 section_header_width_,
119 "",
120 kPageCountWidth,
121 "pages",
122 kPageCountWidth,
123 "pages")
124 << std::endl;
125 }
126
127 void PrintOne(const char* name,
128 size_t resident,
129 size_t mapped,
130 double percent_of_section,
131 double percent_of_total) const {
132 // 6.2 is sufficient to print 0-100% with two decimal places of accuracy.
133 std::cout << StringPrintf("%-*s %*zd %*zd %6.2f %6.2f",
134 section_header_width_,
135 name,
136 kPageCountWidth,
137 resident,
138 kPageCountWidth,
139 mapped,
140 percent_of_section,
141 percent_of_total)
142 << std::endl;
143 }
144
145 void PrintSkipLine() const { std::cout << std::endl; }
146
147 // Computes the width of the section header column in the table (for fixed formatting).
148 static int ComputeHeaderWidth() {
149 int header_width = 0;
150 for (const auto& pair : kDexSectionInfoMap) {
151 const DexSectionInfo& section_info = pair.second;
152 header_width = std::max(header_width, static_cast<int>(section_info.name.length()));
153 }
154 return header_width;
155 }
156
157 private:
158 const int section_header_width_;
159};
160
161static void PrintLetterKey() {
162 std::cout << "L pagetype" << std::endl;
163 for (const auto& pair : kDexSectionInfoMap) {
164 const DexSectionInfo& section_info = pair.second;
165 std::cout << section_info.letter << " " << section_info.name.c_str() << std::endl;
166 }
167 std::cout << "* (Executable page resident)" << std::endl;
168 std::cout << ". (Mapped page not resident)" << std::endl;
David Sehrbeca4fe2017-03-30 17:50:24 -0700169}
170
David Sehr55232f12017-04-19 14:06:49 -0700171#ifdef ART_TARGET_ANDROID
David Sehrbeca4fe2017-03-30 17:50:24 -0700172static char PageTypeChar(uint16_t type) {
173 if (kDexSectionInfoMap.find(type) == kDexSectionInfoMap.end()) {
174 return '-';
175 }
176 return kDexSectionInfoMap.find(type)->second.letter;
177}
178
179static uint16_t FindSectionTypeForPage(size_t page,
180 const std::vector<dex_ir::DexFileSection>& sections) {
181 for (const auto& section : sections) {
182 size_t first_page_of_section = section.offset / kPageSize;
183 // Only consider non-empty sections.
184 if (section.size == 0) {
185 continue;
186 }
187 // Attribute the page to the highest-offset section that starts before the page.
188 if (first_page_of_section <= page) {
189 return section.type;
190 }
191 }
192 // If there's no non-zero sized section with an offset below offset we're looking for, it
193 // must be the header.
194 return DexFile::kDexTypeHeaderItem;
195}
196
197static void ProcessPageMap(uint64_t* pagemap,
198 size_t start,
199 size_t end,
200 const std::vector<dex_ir::DexFileSection>& sections,
201 PageCount* page_counts) {
David Sehr55232f12017-04-19 14:06:49 -0700202 static constexpr size_t kLineLength = 32;
David Sehrbeca4fe2017-03-30 17:50:24 -0700203 for (size_t page = start; page < end; ++page) {
204 char type_char = '.';
205 if (PM_PAGEMAP_PRESENT(pagemap[page])) {
David Sehr093a6fb2017-05-09 15:41:09 -0700206 const size_t dex_page_offset = page - start;
207 uint16_t type = FindSectionTypeForPage(dex_page_offset, sections);
David Sehrbeca4fe2017-03-30 17:50:24 -0700208 page_counts->Increment(type);
209 type_char = PageTypeChar(type);
210 }
211 if (g_verbose) {
212 std::cout << type_char;
213 if ((page - start) % kLineLength == kLineLength - 1) {
214 std::cout << std::endl;
215 }
216 }
217 }
218 if (g_verbose) {
219 if ((end - start) % kLineLength != 0) {
220 std::cout << std::endl;
221 }
222 }
223}
224
225static void DisplayDexStatistics(size_t start,
226 size_t end,
227 const PageCount& resident_pages,
David Sehr3f3ec672017-04-05 14:43:38 -0700228 const std::vector<dex_ir::DexFileSection>& sections,
229 Printer* printer) {
David Sehrbeca4fe2017-03-30 17:50:24 -0700230 // Compute the total possible sizes for sections.
231 PageCount mapped_pages;
232 DCHECK_GE(end, start);
233 size_t total_mapped_pages = end - start;
234 if (total_mapped_pages == 0) {
235 return;
236 }
237 for (size_t page = start; page < end; ++page) {
David Sehr093a6fb2017-05-09 15:41:09 -0700238 const size_t dex_page_offset = page - start;
239 mapped_pages.Increment(FindSectionTypeForPage(dex_page_offset, sections));
David Sehrbeca4fe2017-03-30 17:50:24 -0700240 }
241 size_t total_resident_pages = 0;
David Sehr3f3ec672017-04-05 14:43:38 -0700242 printer->PrintHeader();
David Sehrbeca4fe2017-03-30 17:50:24 -0700243 for (size_t i = sections.size(); i > 0; --i) {
244 const dex_ir::DexFileSection& section = sections[i - 1];
245 const uint16_t type = section.type;
246 const DexSectionInfo& section_info = kDexSectionInfoMap.find(type)->second;
247 size_t pages_resident = resident_pages.Get(type);
248 double percent_resident = 0;
249 if (mapped_pages.Get(type) > 0) {
250 percent_resident = 100.0 * pages_resident / mapped_pages.Get(type);
251 }
David Sehr3f3ec672017-04-05 14:43:38 -0700252 printer->PrintOne(section_info.name.c_str(),
253 pages_resident,
254 mapped_pages.Get(type),
255 percent_resident,
256 100.0 * pages_resident / total_mapped_pages);
David Sehrbeca4fe2017-03-30 17:50:24 -0700257 total_resident_pages += pages_resident;
258 }
David Sehr3f3ec672017-04-05 14:43:38 -0700259 double percent_of_total = 100.0 * total_resident_pages / total_mapped_pages;
260 printer->PrintOne("GRAND TOTAL",
261 total_resident_pages,
262 total_mapped_pages,
263 percent_of_total,
264 percent_of_total);
265 printer->PrintSkipLine();
David Sehrbeca4fe2017-03-30 17:50:24 -0700266}
267
268static void ProcessOneDexMapping(uint64_t* pagemap,
269 uint64_t map_start,
270 const DexFile* dex_file,
David Sehr3f3ec672017-04-05 14:43:38 -0700271 uint64_t vdex_start,
272 Printer* printer) {
David Sehrbeca4fe2017-03-30 17:50:24 -0700273 uint64_t dex_file_start = reinterpret_cast<uint64_t>(dex_file->Begin());
274 size_t dex_file_size = dex_file->Size();
275 if (dex_file_start < vdex_start) {
276 std::cerr << "Dex file start offset for "
277 << dex_file->GetLocation().c_str()
278 << " is incorrect: map start "
David Sehr55232f12017-04-19 14:06:49 -0700279 << StringPrintf("%" PRIx64 " > dex start %" PRIx64 "\n", map_start, dex_file_start)
David Sehrbeca4fe2017-03-30 17:50:24 -0700280 << std::endl;
281 return;
282 }
David Sehrc0e638f2017-04-07 16:56:46 -0700283 uint64_t start_page = (dex_file_start - vdex_start) / kPageSize;
284 uint64_t start_address = start_page * kPageSize;
285 uint64_t end_page = RoundUp(start_address + dex_file_size, kPageSize) / kPageSize;
David Sehrbeca4fe2017-03-30 17:50:24 -0700286 std::cout << "DEX "
287 << dex_file->GetLocation().c_str()
David Sehr55232f12017-04-19 14:06:49 -0700288 << StringPrintf(": %" PRIx64 "-%" PRIx64,
David Sehrc0e638f2017-04-07 16:56:46 -0700289 map_start + start_page * kPageSize,
290 map_start + end_page * kPageSize)
David Sehrbeca4fe2017-03-30 17:50:24 -0700291 << std::endl;
292 // Build a list of the dex file section types, sorted from highest offset to lowest.
293 std::vector<dex_ir::DexFileSection> sections;
294 {
Mathieu Chartier75175552018-01-25 11:23:01 -0800295 Options options;
Mathieu Chartier3e0c5172017-11-12 12:58:40 -0800296 std::unique_ptr<dex_ir::Header> header(dex_ir::DexIrBuilder(*dex_file,
Andreas Gampe9b031f72018-10-04 11:03:34 -0700297 /*eagerly_assign_offsets=*/ true,
Mathieu Chartier75175552018-01-25 11:23:01 -0800298 options));
David Sehrbeca4fe2017-03-30 17:50:24 -0700299 sections = dex_ir::GetSortedDexFileSections(header.get(),
300 dex_ir::SortDirection::kSortDescending);
301 }
302 PageCount section_resident_pages;
David Sehrc0e638f2017-04-07 16:56:46 -0700303 ProcessPageMap(pagemap, start_page, end_page, sections, &section_resident_pages);
David Sehr3f3ec672017-04-05 14:43:38 -0700304 DisplayDexStatistics(start_page, end_page, section_resident_pages, sections, printer);
David Sehrbeca4fe2017-03-30 17:50:24 -0700305}
306
David Sehr592f8022017-05-04 13:58:29 -0700307static bool IsVdexFileMapping(const std::string& mapped_name) {
David Sehrbeca4fe2017-03-30 17:50:24 -0700308 // Confirm that the map is from a vdex file.
309 static const char* suffixes[] = { ".vdex" };
David Sehr592f8022017-05-04 13:58:29 -0700310 for (const char* suffix : suffixes) {
311 size_t match_loc = mapped_name.find(suffix);
312 if (match_loc != std::string::npos && mapped_name.length() == match_loc + strlen(suffix)) {
313 return true;
David Sehrbeca4fe2017-03-30 17:50:24 -0700314 }
315 }
David Sehr592f8022017-05-04 13:58:29 -0700316 return false;
317}
318
319static bool DisplayMappingIfFromVdexFile(pm_map_t* map, Printer* printer) {
320 std::string vdex_name = pm_map_name(map);
David Sehrbeca4fe2017-03-30 17:50:24 -0700321 // Extract all the dex files from the vdex file.
322 std::string error_msg;
323 std::unique_ptr<VdexFile> vdex(VdexFile::Open(vdex_name,
Andreas Gampe9b031f72018-10-04 11:03:34 -0700324 /*writable=*/ false,
325 /*low_4gb=*/ false,
326 /*unquicken= */ false,
David Sehrbeca4fe2017-03-30 17:50:24 -0700327 &error_msg /*out*/));
328 if (vdex == nullptr) {
329 std::cerr << "Could not open vdex file "
David Sehr3f3ec672017-04-05 14:43:38 -0700330 << vdex_name
David Sehrbeca4fe2017-03-30 17:50:24 -0700331 << ": error "
David Sehr3f3ec672017-04-05 14:43:38 -0700332 << error_msg
David Sehrbeca4fe2017-03-30 17:50:24 -0700333 << std::endl;
334 return false;
335 }
336
337 std::vector<std::unique_ptr<const DexFile>> dex_files;
338 if (!vdex->OpenAllDexFiles(&dex_files, &error_msg)) {
339 std::cerr << "Dex files could not be opened for "
David Sehr3f3ec672017-04-05 14:43:38 -0700340 << vdex_name
David Sehrbeca4fe2017-03-30 17:50:24 -0700341 << ": error "
David Sehr3f3ec672017-04-05 14:43:38 -0700342 << error_msg
David Sehrbeca4fe2017-03-30 17:50:24 -0700343 << std::endl;
David Sehr592f8022017-05-04 13:58:29 -0700344 return false;
David Sehrbeca4fe2017-03-30 17:50:24 -0700345 }
346 // Open the page mapping (one uint64_t per page) for the entire vdex mapping.
347 uint64_t* pagemap;
348 size_t len;
349 if (pm_map_pagemap(map, &pagemap, &len) != 0) {
350 std::cerr << "Error creating pagemap." << std::endl;
351 return false;
352 }
353 // Process the dex files.
354 std::cout << "MAPPING "
355 << pm_map_name(map)
David Sehr55232f12017-04-19 14:06:49 -0700356 << StringPrintf(": %" PRIx64 "-%" PRIx64, pm_map_start(map), pm_map_end(map))
David Sehrbeca4fe2017-03-30 17:50:24 -0700357 << std::endl;
358 for (const auto& dex_file : dex_files) {
359 ProcessOneDexMapping(pagemap,
360 pm_map_start(map),
361 dex_file.get(),
David Sehr3f3ec672017-04-05 14:43:38 -0700362 reinterpret_cast<uint64_t>(vdex->Begin()),
363 printer);
David Sehrbeca4fe2017-03-30 17:50:24 -0700364 }
365 free(pagemap);
366 return true;
367}
368
David Sehr3f3ec672017-04-05 14:43:38 -0700369static void ProcessOneOatMapping(uint64_t* pagemap, size_t size, Printer* printer) {
David Sehr55232f12017-04-19 14:06:49 -0700370 static constexpr size_t kLineLength = 32;
David Sehr3f3ec672017-04-05 14:43:38 -0700371 size_t resident_page_count = 0;
372 for (size_t page = 0; page < size; ++page) {
373 char type_char = '.';
374 if (PM_PAGEMAP_PRESENT(pagemap[page])) {
375 ++resident_page_count;
376 type_char = '*';
377 }
378 if (g_verbose) {
379 std::cout << type_char;
380 if (page % kLineLength == kLineLength - 1) {
381 std::cout << std::endl;
382 }
383 }
384 }
385 if (g_verbose) {
386 if (size % kLineLength != 0) {
387 std::cout << std::endl;
388 }
389 }
390 double percent_of_total = 100.0 * resident_page_count / size;
391 printer->PrintHeader();
392 printer->PrintOne("EXECUTABLE", resident_page_count, size, percent_of_total, percent_of_total);
393 printer->PrintSkipLine();
394}
395
David Sehr592f8022017-05-04 13:58:29 -0700396static bool IsOatFileMapping(const std::string& mapped_name) {
397 // Confirm that the map is from an oat file.
David Sehr3f3ec672017-04-05 14:43:38 -0700398 static const char* suffixes[] = { ".odex", ".oat" };
David Sehr592f8022017-05-04 13:58:29 -0700399 for (const char* suffix : suffixes) {
400 size_t match_loc = mapped_name.find(suffix);
401 if (match_loc != std::string::npos && mapped_name.length() == match_loc + strlen(suffix)) {
402 return true;
David Sehr3f3ec672017-04-05 14:43:38 -0700403 }
404 }
David Sehr592f8022017-05-04 13:58:29 -0700405 return false;
406}
407
408static bool DisplayMappingIfFromOatFile(pm_map_t* map, Printer* printer) {
David Sehr3f3ec672017-04-05 14:43:38 -0700409 // Open the page mapping (one uint64_t per page) for the entire vdex mapping.
410 uint64_t* pagemap;
411 size_t len;
412 if (pm_map_pagemap(map, &pagemap, &len) != 0) {
413 std::cerr << "Error creating pagemap." << std::endl;
414 return false;
415 }
416 // Process the dex files.
417 std::cout << "MAPPING "
418 << pm_map_name(map)
David Sehr55232f12017-04-19 14:06:49 -0700419 << StringPrintf(": %" PRIx64 "-%" PRIx64, pm_map_start(map), pm_map_end(map))
David Sehr3f3ec672017-04-05 14:43:38 -0700420 << std::endl;
421 ProcessOneOatMapping(pagemap, len, printer);
422 free(pagemap);
423 return true;
424}
425
426static bool FilterByNameContains(const std::string& mapped_file_name,
427 const std::vector<std::string>& name_filters) {
428 // If no filters were set, everything matches.
429 if (name_filters.empty()) {
430 return true;
431 }
432 for (const auto& name_contains : name_filters) {
433 if (mapped_file_name.find(name_contains) != std::string::npos) {
434 return true;
435 }
436 }
437 return false;
438}
David Sehr55232f12017-04-19 14:06:49 -0700439#endif
David Sehrbeca4fe2017-03-30 17:50:24 -0700440
441static void Usage(const char* cmd) {
David Sehr55232f12017-04-19 14:06:49 -0700442 std::cout << "Usage: " << cmd << " [options] pid" << std::endl
David Sehr3f3ec672017-04-05 14:43:38 -0700443 << " --contains=<string>: Display sections containing string." << std::endl
444 << " --help: Shows this message." << std::endl
445 << " --verbose: Makes displays verbose." << std::endl;
446 PrintLetterKey();
David Sehrbeca4fe2017-03-30 17:50:24 -0700447}
448
David Sehr671af6c2018-05-17 11:00:35 -0700449NO_RETURN static void Abort(const char* msg) {
450 std::cerr << msg;
451 exit(1);
452}
453
David Sehrbeca4fe2017-03-30 17:50:24 -0700454static int DexDiagMain(int argc, char* argv[]) {
455 if (argc < 2) {
456 Usage(argv[0]);
457 return EXIT_FAILURE;
458 }
459
David Sehr3f3ec672017-04-05 14:43:38 -0700460 std::vector<std::string> name_filters;
David Sehrbeca4fe2017-03-30 17:50:24 -0700461 // TODO: add option to track usage by class name, etc.
462 for (int i = 1; i < argc - 1; ++i) {
David Sehr3f3ec672017-04-05 14:43:38 -0700463 const StringPiece option(argv[i]);
464 if (option == "--help") {
465 Usage(argv[0]);
466 return EXIT_SUCCESS;
467 } else if (option == "--verbose") {
David Sehrbeca4fe2017-03-30 17:50:24 -0700468 g_verbose = true;
David Sehr3f3ec672017-04-05 14:43:38 -0700469 } else if (option.starts_with("--contains=")) {
470 std::string contains(option.substr(strlen("--contains=")).data());
471 name_filters.push_back(contains);
David Sehrbeca4fe2017-03-30 17:50:24 -0700472 } else {
473 Usage(argv[0]);
474 return EXIT_FAILURE;
475 }
476 }
477
478 // Art specific set up.
David Sehr671af6c2018-05-17 11:00:35 -0700479 InitLogging(argv, Abort);
David Sehrbeca4fe2017-03-30 17:50:24 -0700480 MemMap::Init();
481
David Sehr55232f12017-04-19 14:06:49 -0700482#ifdef ART_TARGET_ANDROID
David Sehrbeca4fe2017-03-30 17:50:24 -0700483 pid_t pid;
484 char* endptr;
485 pid = (pid_t)strtol(argv[argc - 1], &endptr, 10);
486 if (*endptr != '\0' || kill(pid, 0) != 0) {
487 std::cerr << StringPrintf("Invalid PID \"%s\".\n", argv[argc - 1]) << std::endl;
488 return EXIT_FAILURE;
489 }
490
491 // get libpagemap kernel information.
492 pm_kernel_t* ker;
493 if (pm_kernel_create(&ker) != 0) {
494 std::cerr << "Error creating kernel interface -- does this kernel have pagemap?" << std::endl;
495 return EXIT_FAILURE;
496 }
497
498 // get libpagemap process information.
499 pm_process_t* proc;
500 if (pm_process_create(ker, pid, &proc) != 0) {
501 std::cerr << "Error creating process interface -- does process "
502 << pid
503 << " really exist?"
504 << std::endl;
505 return EXIT_FAILURE;
506 }
507
508 // Get the set of mappings by the specified process.
509 pm_map_t** maps;
510 size_t num_maps;
511 if (pm_process_maps(proc, &maps, &num_maps) != 0) {
512 std::cerr << "Error listing maps." << std::endl;
513 return EXIT_FAILURE;
514 }
515
David Sehr55232f12017-04-19 14:06:49 -0700516 bool match_found = false;
517 // Process the mappings that are due to vdex or oat files.
David Sehr3f3ec672017-04-05 14:43:38 -0700518 Printer printer;
David Sehrbeca4fe2017-03-30 17:50:24 -0700519 for (size_t i = 0; i < num_maps; ++i) {
David Sehr3f3ec672017-04-05 14:43:38 -0700520 std::string mapped_file_name = pm_map_name(maps[i]);
521 // Filter by name contains options (if any).
522 if (!FilterByNameContains(mapped_file_name, name_filters)) {
523 continue;
524 }
David Sehr592f8022017-05-04 13:58:29 -0700525 if (IsVdexFileMapping(mapped_file_name)) {
526 if (!DisplayMappingIfFromVdexFile(maps[i], &printer)) {
527 return EXIT_FAILURE;
528 }
529 match_found = true;
530 } else if (IsOatFileMapping(mapped_file_name)) {
531 if (!DisplayMappingIfFromOatFile(maps[i], &printer)) {
532 return EXIT_FAILURE;
533 }
534 match_found = true;
David Sehrbeca4fe2017-03-30 17:50:24 -0700535 }
536 }
David Sehr55232f12017-04-19 14:06:49 -0700537 if (!match_found) {
David Sehr592f8022017-05-04 13:58:29 -0700538 std::cerr << "No relevant memory maps were found." << std::endl;
David Sehr55232f12017-04-19 14:06:49 -0700539 return EXIT_FAILURE;
540 }
541#endif
David Sehrbeca4fe2017-03-30 17:50:24 -0700542
David Sehr3f3ec672017-04-05 14:43:38 -0700543 return EXIT_SUCCESS;
David Sehrbeca4fe2017-03-30 17:50:24 -0700544}
545
546} // namespace art
547
548int main(int argc, char* argv[]) {
549 return art::DexDiagMain(argc, argv);
550}