blob: ca9018dff3f20fdfdf2680807ab42b8b3bf051d0 [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>
Vladimir Marko8581e2a2019-02-06 15:54:55 +000025#include <string>
26#include <string_view>
David Sehr3f3ec672017-04-05 14:43:38 -070027#include <vector>
David Sehrbeca4fe2017-03-30 17:50:24 -070028
29#include "android-base/stringprintf.h"
30
Andreas Gampe57943812017-12-06 21:39:13 -080031#include "base/logging.h" // For InitLogging.
Vladimir Marko8581e2a2019-02-06 15:54:55 +000032#include "base/string_view_cpp20.h"
David Sehr3f3ec672017-04-05 14:43:38 -070033
Mathieu Chartier75175552018-01-25 11:23:01 -080034#include "dexlayout.h"
David Sehr9e734c72018-01-04 17:56:19 -080035#include "dex/dex_file.h"
David Sehrbeca4fe2017-03-30 17:50:24 -070036#include "dex_ir.h"
37#include "dex_ir_builder.h"
David Sehr55232f12017-04-19 14:06:49 -070038#ifdef ART_TARGET_ANDROID
Sandeep Patil2110de52019-01-21 17:21:09 -080039#include <meminfo/pageacct.h>
40#include <meminfo/procmeminfo.h>
David Sehr55232f12017-04-19 14:06:49 -070041#endif
David Sehrbeca4fe2017-03-30 17:50:24 -070042#include "vdex_file.h"
43
44namespace art {
45
46using android::base::StringPrintf;
Sandeep Patil2110de52019-01-21 17:21:09 -080047#ifdef ART_TARGET_ANDROID
48using android::meminfo::ProcMemInfo;
49using android::meminfo::Vma;
50#endif
David Sehrbeca4fe2017-03-30 17:50:24 -070051
David Sehrbeca4fe2017-03-30 17:50:24 -070052static bool g_verbose = false;
David Sehr3f3ec672017-04-05 14:43:38 -070053
54// The width needed to print a file page offset (32-bit).
55static constexpr int kPageCountWidth =
56 static_cast<int>(std::numeric_limits<uint32_t>::digits10);
57// Display the sections.
58static constexpr char kSectionHeader[] = "Section name";
David Sehrbeca4fe2017-03-30 17:50:24 -070059
60struct DexSectionInfo {
61 public:
62 std::string name;
63 char letter;
64};
65
66static const std::map<uint16_t, DexSectionInfo> kDexSectionInfoMap = {
67 { DexFile::kDexTypeHeaderItem, { "Header", 'H' } },
68 { DexFile::kDexTypeStringIdItem, { "StringId", 'S' } },
69 { DexFile::kDexTypeTypeIdItem, { "TypeId", 'T' } },
70 { DexFile::kDexTypeProtoIdItem, { "ProtoId", 'P' } },
71 { DexFile::kDexTypeFieldIdItem, { "FieldId", 'F' } },
72 { DexFile::kDexTypeMethodIdItem, { "MethodId", 'M' } },
73 { DexFile::kDexTypeClassDefItem, { "ClassDef", 'C' } },
74 { DexFile::kDexTypeCallSiteIdItem, { "CallSiteId", 'z' } },
75 { DexFile::kDexTypeMethodHandleItem, { "MethodHandle", 'Z' } },
76 { DexFile::kDexTypeMapList, { "TypeMap", 'L' } },
77 { DexFile::kDexTypeTypeList, { "TypeList", 't' } },
78 { DexFile::kDexTypeAnnotationSetRefList, { "AnnotationSetReferenceItem", '1' } },
79 { DexFile::kDexTypeAnnotationSetItem, { "AnnotationSetItem", '2' } },
80 { DexFile::kDexTypeClassDataItem, { "ClassData", 'c' } },
81 { DexFile::kDexTypeCodeItem, { "CodeItem", 'X' } },
82 { DexFile::kDexTypeStringDataItem, { "StringData", 's' } },
83 { DexFile::kDexTypeDebugInfoItem, { "DebugInfo", 'D' } },
84 { DexFile::kDexTypeAnnotationItem, { "AnnotationItem", '3' } },
85 { DexFile::kDexTypeEncodedArrayItem, { "EncodedArrayItem", 'E' } },
86 { DexFile::kDexTypeAnnotationsDirectoryItem, { "AnnotationsDirectoryItem", '4' } }
87};
88
89class PageCount {
90 public:
91 PageCount() {
92 for (auto it = kDexSectionInfoMap.begin(); it != kDexSectionInfoMap.end(); ++it) {
93 map_[it->first] = 0;
94 }
95 }
96 void Increment(uint16_t type) {
97 map_[type]++;
98 }
99 size_t Get(uint16_t type) const {
Vladimir Marko35d5b8a2018-07-03 09:18:32 +0100100 auto it = map_.find(type);
101 DCHECK(it != map_.end());
102 return it->second;
David Sehrbeca4fe2017-03-30 17:50:24 -0700103 }
104 private:
105 std::map<uint16_t, size_t> map_;
106 DISALLOW_COPY_AND_ASSIGN(PageCount);
107};
108
David Sehr3f3ec672017-04-05 14:43:38 -0700109class Printer {
110 public:
111 Printer() : section_header_width_(ComputeHeaderWidth()) {
David Sehrbeca4fe2017-03-30 17:50:24 -0700112 }
David Sehr3f3ec672017-04-05 14:43:38 -0700113
114 void PrintHeader() const {
115 std::cout << StringPrintf("%-*s %*s %*s %% of %% of",
116 section_header_width_,
117 kSectionHeader,
118 kPageCountWidth,
119 "resident",
120 kPageCountWidth,
121 "total"
122 )
123 << std::endl;
124 std::cout << StringPrintf("%-*s %*s %*s sect. total",
125 section_header_width_,
126 "",
127 kPageCountWidth,
128 "pages",
129 kPageCountWidth,
130 "pages")
131 << std::endl;
132 }
133
134 void PrintOne(const char* name,
135 size_t resident,
136 size_t mapped,
137 double percent_of_section,
138 double percent_of_total) const {
139 // 6.2 is sufficient to print 0-100% with two decimal places of accuracy.
140 std::cout << StringPrintf("%-*s %*zd %*zd %6.2f %6.2f",
141 section_header_width_,
142 name,
143 kPageCountWidth,
144 resident,
145 kPageCountWidth,
146 mapped,
147 percent_of_section,
148 percent_of_total)
149 << std::endl;
150 }
151
152 void PrintSkipLine() const { std::cout << std::endl; }
153
154 // Computes the width of the section header column in the table (for fixed formatting).
155 static int ComputeHeaderWidth() {
156 int header_width = 0;
157 for (const auto& pair : kDexSectionInfoMap) {
158 const DexSectionInfo& section_info = pair.second;
159 header_width = std::max(header_width, static_cast<int>(section_info.name.length()));
160 }
161 return header_width;
162 }
163
164 private:
165 const int section_header_width_;
166};
167
168static void PrintLetterKey() {
169 std::cout << "L pagetype" << std::endl;
170 for (const auto& pair : kDexSectionInfoMap) {
171 const DexSectionInfo& section_info = pair.second;
172 std::cout << section_info.letter << " " << section_info.name.c_str() << std::endl;
173 }
174 std::cout << "* (Executable page resident)" << std::endl;
175 std::cout << ". (Mapped page not resident)" << std::endl;
David Sehrbeca4fe2017-03-30 17:50:24 -0700176}
177
David Sehr55232f12017-04-19 14:06:49 -0700178#ifdef ART_TARGET_ANDROID
David Sehrbeca4fe2017-03-30 17:50:24 -0700179static char PageTypeChar(uint16_t type) {
180 if (kDexSectionInfoMap.find(type) == kDexSectionInfoMap.end()) {
181 return '-';
182 }
183 return kDexSectionInfoMap.find(type)->second.letter;
184}
185
186static uint16_t FindSectionTypeForPage(size_t page,
187 const std::vector<dex_ir::DexFileSection>& sections) {
188 for (const auto& section : sections) {
189 size_t first_page_of_section = section.offset / kPageSize;
190 // Only consider non-empty sections.
191 if (section.size == 0) {
192 continue;
193 }
194 // Attribute the page to the highest-offset section that starts before the page.
195 if (first_page_of_section <= page) {
196 return section.type;
197 }
198 }
199 // If there's no non-zero sized section with an offset below offset we're looking for, it
200 // must be the header.
201 return DexFile::kDexTypeHeaderItem;
202}
203
Sandeep Patil2110de52019-01-21 17:21:09 -0800204static void ProcessPageMap(const std::vector<uint64_t>& pagemap,
David Sehrbeca4fe2017-03-30 17:50:24 -0700205 size_t start,
206 size_t end,
207 const std::vector<dex_ir::DexFileSection>& sections,
208 PageCount* page_counts) {
David Sehr55232f12017-04-19 14:06:49 -0700209 static constexpr size_t kLineLength = 32;
David Sehrbeca4fe2017-03-30 17:50:24 -0700210 for (size_t page = start; page < end; ++page) {
211 char type_char = '.';
Sandeep Patil2110de52019-01-21 17:21:09 -0800212 if (::android::meminfo::page_present(pagemap[page])) {
David Sehr093a6fb2017-05-09 15:41:09 -0700213 const size_t dex_page_offset = page - start;
214 uint16_t type = FindSectionTypeForPage(dex_page_offset, sections);
David Sehrbeca4fe2017-03-30 17:50:24 -0700215 page_counts->Increment(type);
216 type_char = PageTypeChar(type);
217 }
218 if (g_verbose) {
219 std::cout << type_char;
220 if ((page - start) % kLineLength == kLineLength - 1) {
221 std::cout << std::endl;
222 }
223 }
224 }
225 if (g_verbose) {
226 if ((end - start) % kLineLength != 0) {
227 std::cout << std::endl;
228 }
229 }
230}
231
232static void DisplayDexStatistics(size_t start,
233 size_t end,
234 const PageCount& resident_pages,
David Sehr3f3ec672017-04-05 14:43:38 -0700235 const std::vector<dex_ir::DexFileSection>& sections,
236 Printer* printer) {
David Sehrbeca4fe2017-03-30 17:50:24 -0700237 // Compute the total possible sizes for sections.
238 PageCount mapped_pages;
239 DCHECK_GE(end, start);
240 size_t total_mapped_pages = end - start;
241 if (total_mapped_pages == 0) {
242 return;
243 }
244 for (size_t page = start; page < end; ++page) {
David Sehr093a6fb2017-05-09 15:41:09 -0700245 const size_t dex_page_offset = page - start;
246 mapped_pages.Increment(FindSectionTypeForPage(dex_page_offset, sections));
David Sehrbeca4fe2017-03-30 17:50:24 -0700247 }
248 size_t total_resident_pages = 0;
David Sehr3f3ec672017-04-05 14:43:38 -0700249 printer->PrintHeader();
David Sehrbeca4fe2017-03-30 17:50:24 -0700250 for (size_t i = sections.size(); i > 0; --i) {
251 const dex_ir::DexFileSection& section = sections[i - 1];
252 const uint16_t type = section.type;
253 const DexSectionInfo& section_info = kDexSectionInfoMap.find(type)->second;
254 size_t pages_resident = resident_pages.Get(type);
255 double percent_resident = 0;
256 if (mapped_pages.Get(type) > 0) {
257 percent_resident = 100.0 * pages_resident / mapped_pages.Get(type);
258 }
David Sehr3f3ec672017-04-05 14:43:38 -0700259 printer->PrintOne(section_info.name.c_str(),
260 pages_resident,
261 mapped_pages.Get(type),
262 percent_resident,
263 100.0 * pages_resident / total_mapped_pages);
David Sehrbeca4fe2017-03-30 17:50:24 -0700264 total_resident_pages += pages_resident;
265 }
David Sehr3f3ec672017-04-05 14:43:38 -0700266 double percent_of_total = 100.0 * total_resident_pages / total_mapped_pages;
267 printer->PrintOne("GRAND TOTAL",
268 total_resident_pages,
269 total_mapped_pages,
270 percent_of_total,
271 percent_of_total);
272 printer->PrintSkipLine();
David Sehrbeca4fe2017-03-30 17:50:24 -0700273}
274
Sandeep Patil2110de52019-01-21 17:21:09 -0800275static void ProcessOneDexMapping(const std::vector<uint64_t>& pagemap,
David Sehrbeca4fe2017-03-30 17:50:24 -0700276 uint64_t map_start,
277 const DexFile* dex_file,
David Sehr3f3ec672017-04-05 14:43:38 -0700278 uint64_t vdex_start,
279 Printer* printer) {
David Sehrbeca4fe2017-03-30 17:50:24 -0700280 uint64_t dex_file_start = reinterpret_cast<uint64_t>(dex_file->Begin());
281 size_t dex_file_size = dex_file->Size();
282 if (dex_file_start < vdex_start) {
283 std::cerr << "Dex file start offset for "
284 << dex_file->GetLocation().c_str()
285 << " is incorrect: map start "
David Sehr55232f12017-04-19 14:06:49 -0700286 << StringPrintf("%" PRIx64 " > dex start %" PRIx64 "\n", map_start, dex_file_start)
David Sehrbeca4fe2017-03-30 17:50:24 -0700287 << std::endl;
288 return;
289 }
David Sehrc0e638f2017-04-07 16:56:46 -0700290 uint64_t start_page = (dex_file_start - vdex_start) / kPageSize;
291 uint64_t start_address = start_page * kPageSize;
292 uint64_t end_page = RoundUp(start_address + dex_file_size, kPageSize) / kPageSize;
David Sehrbeca4fe2017-03-30 17:50:24 -0700293 std::cout << "DEX "
294 << dex_file->GetLocation().c_str()
David Sehr55232f12017-04-19 14:06:49 -0700295 << StringPrintf(": %" PRIx64 "-%" PRIx64,
David Sehrc0e638f2017-04-07 16:56:46 -0700296 map_start + start_page * kPageSize,
297 map_start + end_page * kPageSize)
David Sehrbeca4fe2017-03-30 17:50:24 -0700298 << std::endl;
299 // Build a list of the dex file section types, sorted from highest offset to lowest.
300 std::vector<dex_ir::DexFileSection> sections;
301 {
Mathieu Chartier75175552018-01-25 11:23:01 -0800302 Options options;
Mathieu Chartier3e0c5172017-11-12 12:58:40 -0800303 std::unique_ptr<dex_ir::Header> header(dex_ir::DexIrBuilder(*dex_file,
Andreas Gampe9b031f72018-10-04 11:03:34 -0700304 /*eagerly_assign_offsets=*/ true,
Mathieu Chartier75175552018-01-25 11:23:01 -0800305 options));
David Sehrbeca4fe2017-03-30 17:50:24 -0700306 sections = dex_ir::GetSortedDexFileSections(header.get(),
307 dex_ir::SortDirection::kSortDescending);
308 }
309 PageCount section_resident_pages;
David Sehrc0e638f2017-04-07 16:56:46 -0700310 ProcessPageMap(pagemap, start_page, end_page, sections, &section_resident_pages);
David Sehr3f3ec672017-04-05 14:43:38 -0700311 DisplayDexStatistics(start_page, end_page, section_resident_pages, sections, printer);
David Sehrbeca4fe2017-03-30 17:50:24 -0700312}
313
David Sehr592f8022017-05-04 13:58:29 -0700314static bool IsVdexFileMapping(const std::string& mapped_name) {
David Sehrbeca4fe2017-03-30 17:50:24 -0700315 // Confirm that the map is from a vdex file.
316 static const char* suffixes[] = { ".vdex" };
David Sehr592f8022017-05-04 13:58:29 -0700317 for (const char* suffix : suffixes) {
318 size_t match_loc = mapped_name.find(suffix);
319 if (match_loc != std::string::npos && mapped_name.length() == match_loc + strlen(suffix)) {
320 return true;
David Sehrbeca4fe2017-03-30 17:50:24 -0700321 }
322 }
David Sehr592f8022017-05-04 13:58:29 -0700323 return false;
324}
325
Sandeep Patil2110de52019-01-21 17:21:09 -0800326static bool DisplayMappingIfFromVdexFile(ProcMemInfo& proc, const Vma& vma, Printer* printer) {
327 std::string vdex_name = vma.name;
David Sehrbeca4fe2017-03-30 17:50:24 -0700328 // Extract all the dex files from the vdex file.
329 std::string error_msg;
330 std::unique_ptr<VdexFile> vdex(VdexFile::Open(vdex_name,
Andreas Gampe9b031f72018-10-04 11:03:34 -0700331 /*writable=*/ false,
332 /*low_4gb=*/ false,
333 /*unquicken= */ false,
David Sehrbeca4fe2017-03-30 17:50:24 -0700334 &error_msg /*out*/));
335 if (vdex == nullptr) {
336 std::cerr << "Could not open vdex file "
David Sehr3f3ec672017-04-05 14:43:38 -0700337 << vdex_name
David Sehrbeca4fe2017-03-30 17:50:24 -0700338 << ": error "
David Sehr3f3ec672017-04-05 14:43:38 -0700339 << error_msg
David Sehrbeca4fe2017-03-30 17:50:24 -0700340 << std::endl;
341 return false;
342 }
343
344 std::vector<std::unique_ptr<const DexFile>> dex_files;
345 if (!vdex->OpenAllDexFiles(&dex_files, &error_msg)) {
346 std::cerr << "Dex files could not be opened for "
David Sehr3f3ec672017-04-05 14:43:38 -0700347 << vdex_name
David Sehrbeca4fe2017-03-30 17:50:24 -0700348 << ": error "
David Sehr3f3ec672017-04-05 14:43:38 -0700349 << error_msg
David Sehrbeca4fe2017-03-30 17:50:24 -0700350 << std::endl;
David Sehr592f8022017-05-04 13:58:29 -0700351 return false;
David Sehrbeca4fe2017-03-30 17:50:24 -0700352 }
353 // Open the page mapping (one uint64_t per page) for the entire vdex mapping.
Sandeep Patil2110de52019-01-21 17:21:09 -0800354 std::vector<uint64_t> pagemap;
355 if (!proc.PageMap(vma, &pagemap)) {
David Sehrbeca4fe2017-03-30 17:50:24 -0700356 std::cerr << "Error creating pagemap." << std::endl;
357 return false;
358 }
359 // Process the dex files.
360 std::cout << "MAPPING "
Sandeep Patil2110de52019-01-21 17:21:09 -0800361 << vma.name
362 << StringPrintf(": %" PRIx64 "-%" PRIx64, vma.start, vma.end)
David Sehrbeca4fe2017-03-30 17:50:24 -0700363 << std::endl;
364 for (const auto& dex_file : dex_files) {
365 ProcessOneDexMapping(pagemap,
Sandeep Patil2110de52019-01-21 17:21:09 -0800366 vma.start,
David Sehrbeca4fe2017-03-30 17:50:24 -0700367 dex_file.get(),
David Sehr3f3ec672017-04-05 14:43:38 -0700368 reinterpret_cast<uint64_t>(vdex->Begin()),
369 printer);
David Sehrbeca4fe2017-03-30 17:50:24 -0700370 }
David Sehrbeca4fe2017-03-30 17:50:24 -0700371 return true;
372}
373
Sandeep Patil2110de52019-01-21 17:21:09 -0800374static void ProcessOneOatMapping(const std::vector<uint64_t>& pagemap,
375 Printer* printer) {
David Sehr55232f12017-04-19 14:06:49 -0700376 static constexpr size_t kLineLength = 32;
David Sehr3f3ec672017-04-05 14:43:38 -0700377 size_t resident_page_count = 0;
Sandeep Patil2110de52019-01-21 17:21:09 -0800378 for (size_t page = 0; page < pagemap.size(); ++page) {
David Sehr3f3ec672017-04-05 14:43:38 -0700379 char type_char = '.';
Sandeep Patil2110de52019-01-21 17:21:09 -0800380 if (::android::meminfo::page_present(pagemap[page])) {
David Sehr3f3ec672017-04-05 14:43:38 -0700381 ++resident_page_count;
382 type_char = '*';
383 }
384 if (g_verbose) {
385 std::cout << type_char;
386 if (page % kLineLength == kLineLength - 1) {
387 std::cout << std::endl;
388 }
389 }
390 }
391 if (g_verbose) {
Sandeep Patil2110de52019-01-21 17:21:09 -0800392 if (pagemap.size() % kLineLength != 0) {
David Sehr3f3ec672017-04-05 14:43:38 -0700393 std::cout << std::endl;
394 }
395 }
Sandeep Patil2110de52019-01-21 17:21:09 -0800396 double percent_of_total = 100.0 * resident_page_count / pagemap.size();
David Sehr3f3ec672017-04-05 14:43:38 -0700397 printer->PrintHeader();
Sandeep Patil2110de52019-01-21 17:21:09 -0800398 printer->PrintOne("EXECUTABLE", resident_page_count, pagemap.size(), percent_of_total, percent_of_total);
David Sehr3f3ec672017-04-05 14:43:38 -0700399 printer->PrintSkipLine();
400}
401
David Sehr592f8022017-05-04 13:58:29 -0700402static bool IsOatFileMapping(const std::string& mapped_name) {
403 // Confirm that the map is from an oat file.
David Sehr3f3ec672017-04-05 14:43:38 -0700404 static const char* suffixes[] = { ".odex", ".oat" };
David Sehr592f8022017-05-04 13:58:29 -0700405 for (const char* suffix : suffixes) {
406 size_t match_loc = mapped_name.find(suffix);
407 if (match_loc != std::string::npos && mapped_name.length() == match_loc + strlen(suffix)) {
408 return true;
David Sehr3f3ec672017-04-05 14:43:38 -0700409 }
410 }
David Sehr592f8022017-05-04 13:58:29 -0700411 return false;
412}
413
Sandeep Patil2110de52019-01-21 17:21:09 -0800414static bool DisplayMappingIfFromOatFile(ProcMemInfo& proc, const Vma& vma, Printer* printer) {
David Sehr3f3ec672017-04-05 14:43:38 -0700415 // Open the page mapping (one uint64_t per page) for the entire vdex mapping.
Sandeep Patil2110de52019-01-21 17:21:09 -0800416 std::vector<uint64_t> pagemap;
417 if (!proc.PageMap(vma, &pagemap) != 0) {
David Sehr3f3ec672017-04-05 14:43:38 -0700418 std::cerr << "Error creating pagemap." << std::endl;
419 return false;
420 }
421 // Process the dex files.
422 std::cout << "MAPPING "
Sandeep Patil2110de52019-01-21 17:21:09 -0800423 << vma.name
424 << StringPrintf(": %" PRIx64 "-%" PRIx64, vma.start, vma.end)
David Sehr3f3ec672017-04-05 14:43:38 -0700425 << std::endl;
Sandeep Patil2110de52019-01-21 17:21:09 -0800426 ProcessOneOatMapping(pagemap, printer);
David Sehr3f3ec672017-04-05 14:43:38 -0700427 return true;
428}
429
430static bool FilterByNameContains(const std::string& mapped_file_name,
431 const std::vector<std::string>& name_filters) {
432 // If no filters were set, everything matches.
433 if (name_filters.empty()) {
434 return true;
435 }
436 for (const auto& name_contains : name_filters) {
437 if (mapped_file_name.find(name_contains) != std::string::npos) {
438 return true;
439 }
440 }
441 return false;
442}
David Sehr55232f12017-04-19 14:06:49 -0700443#endif
David Sehrbeca4fe2017-03-30 17:50:24 -0700444
445static void Usage(const char* cmd) {
David Sehr55232f12017-04-19 14:06:49 -0700446 std::cout << "Usage: " << cmd << " [options] pid" << std::endl
David Sehr3f3ec672017-04-05 14:43:38 -0700447 << " --contains=<string>: Display sections containing string." << std::endl
448 << " --help: Shows this message." << std::endl
449 << " --verbose: Makes displays verbose." << std::endl;
450 PrintLetterKey();
David Sehrbeca4fe2017-03-30 17:50:24 -0700451}
452
David Sehr671af6c2018-05-17 11:00:35 -0700453NO_RETURN static void Abort(const char* msg) {
454 std::cerr << msg;
455 exit(1);
456}
457
David Sehrbeca4fe2017-03-30 17:50:24 -0700458static int DexDiagMain(int argc, char* argv[]) {
459 if (argc < 2) {
460 Usage(argv[0]);
461 return EXIT_FAILURE;
462 }
463
David Sehr3f3ec672017-04-05 14:43:38 -0700464 std::vector<std::string> name_filters;
David Sehrbeca4fe2017-03-30 17:50:24 -0700465 // TODO: add option to track usage by class name, etc.
466 for (int i = 1; i < argc - 1; ++i) {
Vladimir Marko8581e2a2019-02-06 15:54:55 +0000467 const std::string_view option(argv[i]);
David Sehr3f3ec672017-04-05 14:43:38 -0700468 if (option == "--help") {
469 Usage(argv[0]);
470 return EXIT_SUCCESS;
471 } else if (option == "--verbose") {
David Sehrbeca4fe2017-03-30 17:50:24 -0700472 g_verbose = true;
Vladimir Marko8581e2a2019-02-06 15:54:55 +0000473 } else if (StartsWith(option, "--contains=")) {
474 std::string contains(option.substr(strlen("--contains=")));
David Sehr3f3ec672017-04-05 14:43:38 -0700475 name_filters.push_back(contains);
David Sehrbeca4fe2017-03-30 17:50:24 -0700476 } else {
477 Usage(argv[0]);
478 return EXIT_FAILURE;
479 }
480 }
481
482 // Art specific set up.
David Sehr671af6c2018-05-17 11:00:35 -0700483 InitLogging(argv, Abort);
David Sehrbeca4fe2017-03-30 17:50:24 -0700484 MemMap::Init();
485
David Sehr55232f12017-04-19 14:06:49 -0700486#ifdef ART_TARGET_ANDROID
David Sehrbeca4fe2017-03-30 17:50:24 -0700487 pid_t pid;
488 char* endptr;
489 pid = (pid_t)strtol(argv[argc - 1], &endptr, 10);
490 if (*endptr != '\0' || kill(pid, 0) != 0) {
491 std::cerr << StringPrintf("Invalid PID \"%s\".\n", argv[argc - 1]) << std::endl;
492 return EXIT_FAILURE;
493 }
494
Sandeep Patil2110de52019-01-21 17:21:09 -0800495 // get libmeminfo process information.
496 ProcMemInfo proc(pid);
David Sehrbeca4fe2017-03-30 17:50:24 -0700497 // Get the set of mappings by the specified process.
Sandeep Patil2110de52019-01-21 17:21:09 -0800498 const std::vector<Vma>& maps = proc.Maps();
499 if (maps.empty()) {
David Sehrbeca4fe2017-03-30 17:50:24 -0700500 std::cerr << "Error listing maps." << std::endl;
501 return EXIT_FAILURE;
502 }
503
David Sehr55232f12017-04-19 14:06:49 -0700504 bool match_found = false;
505 // Process the mappings that are due to vdex or oat files.
David Sehr3f3ec672017-04-05 14:43:38 -0700506 Printer printer;
Sandeep Patil2110de52019-01-21 17:21:09 -0800507 for (auto& vma : maps) {
508 std::string mapped_file_name = vma.name;
David Sehr3f3ec672017-04-05 14:43:38 -0700509 // Filter by name contains options (if any).
510 if (!FilterByNameContains(mapped_file_name, name_filters)) {
511 continue;
512 }
David Sehr592f8022017-05-04 13:58:29 -0700513 if (IsVdexFileMapping(mapped_file_name)) {
Sandeep Patil2110de52019-01-21 17:21:09 -0800514 if (!DisplayMappingIfFromVdexFile(proc, vma, &printer)) {
David Sehr592f8022017-05-04 13:58:29 -0700515 return EXIT_FAILURE;
516 }
517 match_found = true;
518 } else if (IsOatFileMapping(mapped_file_name)) {
Sandeep Patil2110de52019-01-21 17:21:09 -0800519 if (!DisplayMappingIfFromOatFile(proc, vma, &printer)) {
David Sehr592f8022017-05-04 13:58:29 -0700520 return EXIT_FAILURE;
521 }
522 match_found = true;
David Sehrbeca4fe2017-03-30 17:50:24 -0700523 }
524 }
David Sehr55232f12017-04-19 14:06:49 -0700525 if (!match_found) {
David Sehr592f8022017-05-04 13:58:29 -0700526 std::cerr << "No relevant memory maps were found." << std::endl;
David Sehr55232f12017-04-19 14:06:49 -0700527 return EXIT_FAILURE;
528 }
529#endif
David Sehrbeca4fe2017-03-30 17:50:24 -0700530
David Sehr3f3ec672017-04-05 14:43:38 -0700531 return EXIT_SUCCESS;
David Sehrbeca4fe2017-03-30 17:50:24 -0700532}
533
534} // namespace art
535
536int main(int argc, char* argv[]) {
537 return art::DexDiagMain(argc, argv);
538}