OSDN Git Service

ARM64: Restore FP registers in read barrier thunk.
[android-x86/art.git] / dexlayout / dexdiag.cc
1 /*
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>
18 #include <inttypes.h>
19 #include <stdint.h>
20 #include <stdlib.h>
21 #include <string.h>
22
23 #include <iostream>
24 #include <memory>
25 #include <vector>
26
27 #include "android-base/stringprintf.h"
28
29 #include "base/stringpiece.h"
30
31 #include "dex_file.h"
32 #include "dex_ir.h"
33 #include "dex_ir_builder.h"
34 #include "pagemap/pagemap.h"
35 #include "runtime.h"
36 #include "vdex_file.h"
37
38 namespace art {
39
40 using android::base::StringPrintf;
41
42 static constexpr size_t kLineLength = 32;
43
44 static bool g_verbose = false;
45
46 // The width needed to print a file page offset (32-bit).
47 static constexpr int kPageCountWidth =
48     static_cast<int>(std::numeric_limits<uint32_t>::digits10);
49 // Display the sections.
50 static constexpr char kSectionHeader[] = "Section name";
51
52 struct DexSectionInfo {
53  public:
54   std::string name;
55   char letter;
56 };
57
58 static const std::map<uint16_t, DexSectionInfo> kDexSectionInfoMap = {
59   { DexFile::kDexTypeHeaderItem, { "Header", 'H' } },
60   { DexFile::kDexTypeStringIdItem, { "StringId", 'S' } },
61   { DexFile::kDexTypeTypeIdItem, { "TypeId", 'T' } },
62   { DexFile::kDexTypeProtoIdItem, { "ProtoId", 'P' } },
63   { DexFile::kDexTypeFieldIdItem, { "FieldId", 'F' } },
64   { DexFile::kDexTypeMethodIdItem, { "MethodId", 'M' } },
65   { DexFile::kDexTypeClassDefItem, { "ClassDef", 'C' } },
66   { DexFile::kDexTypeCallSiteIdItem, { "CallSiteId", 'z' } },
67   { DexFile::kDexTypeMethodHandleItem, { "MethodHandle", 'Z' } },
68   { DexFile::kDexTypeMapList, { "TypeMap", 'L' } },
69   { DexFile::kDexTypeTypeList, { "TypeList", 't' } },
70   { DexFile::kDexTypeAnnotationSetRefList, { "AnnotationSetReferenceItem", '1' } },
71   { DexFile::kDexTypeAnnotationSetItem, { "AnnotationSetItem", '2' } },
72   { DexFile::kDexTypeClassDataItem, { "ClassData", 'c' } },
73   { DexFile::kDexTypeCodeItem, { "CodeItem", 'X' } },
74   { DexFile::kDexTypeStringDataItem, { "StringData", 's' } },
75   { DexFile::kDexTypeDebugInfoItem, { "DebugInfo", 'D' } },
76   { DexFile::kDexTypeAnnotationItem, { "AnnotationItem", '3' } },
77   { DexFile::kDexTypeEncodedArrayItem, { "EncodedArrayItem", 'E' } },
78   { DexFile::kDexTypeAnnotationsDirectoryItem, { "AnnotationsDirectoryItem", '4' } }
79 };
80
81 class PageCount {
82  public:
83   PageCount() {
84     for (auto it = kDexSectionInfoMap.begin(); it != kDexSectionInfoMap.end(); ++it) {
85       map_[it->first] = 0;
86     }
87   }
88   void Increment(uint16_t type) {
89     map_[type]++;
90   }
91   size_t Get(uint16_t type) const {
92     return map_.at(type);
93   }
94  private:
95   std::map<uint16_t, size_t> map_;
96   DISALLOW_COPY_AND_ASSIGN(PageCount);
97 };
98
99 class Printer {
100  public:
101   Printer() : section_header_width_(ComputeHeaderWidth()) {
102   }
103
104   void PrintHeader() const {
105     std::cout << StringPrintf("%-*s %*s %*s %% of   %% of",
106                               section_header_width_,
107                               kSectionHeader,
108                               kPageCountWidth,
109                               "resident",
110                               kPageCountWidth,
111                               "total"
112                               )
113               << std::endl;
114     std::cout << StringPrintf("%-*s %*s %*s sect.  total",
115                               section_header_width_,
116                               "",
117                               kPageCountWidth,
118                               "pages",
119                               kPageCountWidth,
120                               "pages")
121               << std::endl;
122   }
123
124   void PrintOne(const char* name,
125                 size_t resident,
126                 size_t mapped,
127                 double percent_of_section,
128                 double percent_of_total) const {
129     // 6.2 is sufficient to print 0-100% with two decimal places of accuracy.
130     std::cout << StringPrintf("%-*s %*zd %*zd %6.2f %6.2f",
131                               section_header_width_,
132                               name,
133                               kPageCountWidth,
134                               resident,
135                               kPageCountWidth,
136                               mapped,
137                               percent_of_section,
138                               percent_of_total)
139               << std::endl;
140   }
141
142   void PrintSkipLine() const { std::cout << std::endl; }
143
144   // Computes the width of the section header column in the table (for fixed formatting).
145   static int ComputeHeaderWidth() {
146     int header_width = 0;
147     for (const auto& pair : kDexSectionInfoMap) {
148       const DexSectionInfo& section_info = pair.second;
149       header_width = std::max(header_width, static_cast<int>(section_info.name.length()));
150     }
151     return header_width;
152   }
153
154  private:
155   const int section_header_width_;
156 };
157
158 static void PrintLetterKey() {
159   std::cout << "L pagetype" << std::endl;
160   for (const auto& pair : kDexSectionInfoMap) {
161     const DexSectionInfo& section_info = pair.second;
162     std::cout << section_info.letter << " " << section_info.name.c_str() << std::endl;
163   }
164   std::cout << "* (Executable page resident)" << std::endl;
165   std::cout << ". (Mapped page not resident)" << std::endl;
166 }
167
168 static char PageTypeChar(uint16_t type) {
169   if (kDexSectionInfoMap.find(type) == kDexSectionInfoMap.end()) {
170     return '-';
171   }
172   return kDexSectionInfoMap.find(type)->second.letter;
173 }
174
175 static uint16_t FindSectionTypeForPage(size_t page,
176                                        const std::vector<dex_ir::DexFileSection>& sections) {
177   for (const auto& section : sections) {
178     size_t first_page_of_section = section.offset / kPageSize;
179     // Only consider non-empty sections.
180     if (section.size == 0) {
181       continue;
182     }
183     // Attribute the page to the highest-offset section that starts before the page.
184     if (first_page_of_section <= page) {
185       return section.type;
186     }
187   }
188   // If there's no non-zero sized section with an offset below offset we're looking for, it
189   // must be the header.
190   return DexFile::kDexTypeHeaderItem;
191 }
192
193 static void ProcessPageMap(uint64_t* pagemap,
194                            size_t start,
195                            size_t end,
196                            const std::vector<dex_ir::DexFileSection>& sections,
197                            PageCount* page_counts) {
198   for (size_t page = start; page < end; ++page) {
199     char type_char = '.';
200     if (PM_PAGEMAP_PRESENT(pagemap[page])) {
201       const size_t dex_page_offset = page - start;
202       uint16_t type = FindSectionTypeForPage(dex_page_offset, sections);
203       page_counts->Increment(type);
204       type_char = PageTypeChar(type);
205     }
206     if (g_verbose) {
207       std::cout << type_char;
208       if ((page - start) % kLineLength == kLineLength - 1) {
209         std::cout << std::endl;
210       }
211     }
212   }
213   if (g_verbose) {
214     if ((end - start) % kLineLength != 0) {
215       std::cout << std::endl;
216     }
217   }
218 }
219
220 static void DisplayDexStatistics(size_t start,
221                                  size_t end,
222                                  const PageCount& resident_pages,
223                                  const std::vector<dex_ir::DexFileSection>& sections,
224                                  Printer* printer) {
225   // Compute the total possible sizes for sections.
226   PageCount mapped_pages;
227   DCHECK_GE(end, start);
228   size_t total_mapped_pages = end - start;
229   if (total_mapped_pages == 0) {
230     return;
231   }
232   for (size_t page = start; page < end; ++page) {
233     const size_t dex_page_offset = page - start;
234     mapped_pages.Increment(FindSectionTypeForPage(dex_page_offset, sections));
235   }
236   size_t total_resident_pages = 0;
237   printer->PrintHeader();
238   for (size_t i = sections.size(); i > 0; --i) {
239     const dex_ir::DexFileSection& section = sections[i - 1];
240     const uint16_t type = section.type;
241     const DexSectionInfo& section_info = kDexSectionInfoMap.find(type)->second;
242     size_t pages_resident = resident_pages.Get(type);
243     double percent_resident = 0;
244     if (mapped_pages.Get(type) > 0) {
245       percent_resident = 100.0 * pages_resident / mapped_pages.Get(type);
246     }
247     printer->PrintOne(section_info.name.c_str(),
248                       pages_resident,
249                       mapped_pages.Get(type),
250                       percent_resident,
251                       100.0 * pages_resident / total_mapped_pages);
252     total_resident_pages += pages_resident;
253   }
254   double percent_of_total = 100.0 * total_resident_pages / total_mapped_pages;
255   printer->PrintOne("GRAND TOTAL",
256                     total_resident_pages,
257                     total_mapped_pages,
258                     percent_of_total,
259                     percent_of_total);
260   printer->PrintSkipLine();
261 }
262
263 static void ProcessOneDexMapping(uint64_t* pagemap,
264                                  uint64_t map_start,
265                                  const DexFile* dex_file,
266                                  uint64_t vdex_start,
267                                  Printer* printer) {
268   uint64_t dex_file_start = reinterpret_cast<uint64_t>(dex_file->Begin());
269   size_t dex_file_size = dex_file->Size();
270   if (dex_file_start < vdex_start) {
271     std::cerr << "Dex file start offset for "
272               << dex_file->GetLocation().c_str()
273               << " is incorrect: map start "
274               << StringPrintf("%" PRIx64 " > dex start %" PRIx64 "\n", map_start, dex_file_start)
275               << std::endl;
276     return;
277   }
278   uint64_t start_page = (dex_file_start - vdex_start) / kPageSize;
279   uint64_t start_address = start_page * kPageSize;
280   uint64_t end_page = RoundUp(start_address + dex_file_size, kPageSize) / kPageSize;
281   std::cout << "DEX "
282             << dex_file->GetLocation().c_str()
283             << StringPrintf(": %" PRIx64 "-%" PRIx64,
284                             map_start + start_page * kPageSize,
285                             map_start + end_page * kPageSize)
286             << std::endl;
287   // Build a list of the dex file section types, sorted from highest offset to lowest.
288   std::vector<dex_ir::DexFileSection> sections;
289   {
290     std::unique_ptr<dex_ir::Header> header(dex_ir::DexIrBuilder(*dex_file));
291     sections = dex_ir::GetSortedDexFileSections(header.get(),
292                                                 dex_ir::SortDirection::kSortDescending);
293   }
294   PageCount section_resident_pages;
295   ProcessPageMap(pagemap, start_page, end_page, sections, &section_resident_pages);
296   DisplayDexStatistics(start_page, end_page, section_resident_pages, sections, printer);
297 }
298
299 static bool DisplayMappingIfFromVdexFile(pm_map_t* map, Printer* printer) {
300   // Confirm that the map is from a vdex file.
301   static const char* suffixes[] = { ".vdex" };
302   std::string vdex_name;
303   bool found = false;
304   for (size_t j = 0; j < sizeof(suffixes) / sizeof(suffixes[0]); ++j) {
305     if (strstr(pm_map_name(map), suffixes[j]) != nullptr) {
306       vdex_name = pm_map_name(map);
307       found = true;
308       break;
309     }
310   }
311   if (!found) {
312     return true;
313   }
314   // Extract all the dex files from the vdex file.
315   std::string error_msg;
316   std::unique_ptr<VdexFile> vdex(VdexFile::Open(vdex_name,
317                                                 false /*writeable*/,
318                                                 false /*low_4gb*/,
319                                                 false /*unquicken */,
320                                                 &error_msg /*out*/));
321   if (vdex == nullptr) {
322     std::cerr << "Could not open vdex file "
323               << vdex_name
324               << ": error "
325               << error_msg
326               << std::endl;
327     return false;
328   }
329
330   std::vector<std::unique_ptr<const DexFile>> dex_files;
331   if (!vdex->OpenAllDexFiles(&dex_files, &error_msg)) {
332     std::cerr << "Dex files could not be opened for "
333               << vdex_name
334               << ": error "
335               << error_msg
336               << std::endl;
337   }
338   // Open the page mapping (one uint64_t per page) for the entire vdex mapping.
339   uint64_t* pagemap;
340   size_t len;
341   if (pm_map_pagemap(map, &pagemap, &len) != 0) {
342     std::cerr << "Error creating pagemap." << std::endl;
343     return false;
344   }
345   // Process the dex files.
346   std::cout << "MAPPING "
347             << pm_map_name(map)
348             << StringPrintf(": %" PRIx64 "-%" PRIx64, pm_map_start(map), pm_map_end(map))
349             << std::endl;
350   for (const auto& dex_file : dex_files) {
351     ProcessOneDexMapping(pagemap,
352                          pm_map_start(map),
353                          dex_file.get(),
354                          reinterpret_cast<uint64_t>(vdex->Begin()),
355                          printer);
356   }
357   free(pagemap);
358   return true;
359 }
360
361 static void ProcessOneOatMapping(uint64_t* pagemap, size_t size, Printer* printer) {
362   size_t resident_page_count = 0;
363   for (size_t page = 0; page < size; ++page) {
364     char type_char = '.';
365     if (PM_PAGEMAP_PRESENT(pagemap[page])) {
366       ++resident_page_count;
367       type_char = '*';
368     }
369     if (g_verbose) {
370       std::cout << type_char;
371       if (page % kLineLength == kLineLength - 1) {
372         std::cout << std::endl;
373       }
374     }
375   }
376   if (g_verbose) {
377     if (size % kLineLength != 0) {
378       std::cout << std::endl;
379     }
380   }
381   double percent_of_total = 100.0 * resident_page_count / size;
382   printer->PrintHeader();
383   printer->PrintOne("EXECUTABLE", resident_page_count, size, percent_of_total, percent_of_total);
384   printer->PrintSkipLine();
385 }
386
387 static bool DisplayMappingIfFromOatFile(pm_map_t* map, Printer* printer) {
388   // Confirm that the map is from a vdex file.
389   static const char* suffixes[] = { ".odex", ".oat" };
390   std::string vdex_name;
391   bool found = false;
392   for (size_t j = 0; j < sizeof(suffixes) / sizeof(suffixes[0]); ++j) {
393     if (strstr(pm_map_name(map), suffixes[j]) != nullptr) {
394       vdex_name = pm_map_name(map);
395       found = true;
396       break;
397     }
398   }
399   if (!found) {
400     return true;
401   }
402   // Open the page mapping (one uint64_t per page) for the entire vdex mapping.
403   uint64_t* pagemap;
404   size_t len;
405   if (pm_map_pagemap(map, &pagemap, &len) != 0) {
406     std::cerr << "Error creating pagemap." << std::endl;
407     return false;
408   }
409   // Process the dex files.
410   std::cout << "MAPPING "
411             << pm_map_name(map)
412             << StringPrintf(": %" PRIx64 "-%" PRIx64, pm_map_start(map), pm_map_end(map))
413             << std::endl;
414   ProcessOneOatMapping(pagemap, len, printer);
415   free(pagemap);
416   return true;
417 }
418
419 static bool FilterByNameContains(const std::string& mapped_file_name,
420                                  const std::vector<std::string>& name_filters) {
421   // If no filters were set, everything matches.
422   if (name_filters.empty()) {
423     return true;
424   }
425   for (const auto& name_contains : name_filters) {
426     if (mapped_file_name.find(name_contains) != std::string::npos) {
427       return true;
428     }
429   }
430   return false;
431 }
432
433 static void Usage(const char* cmd) {
434   std::cerr << "Usage: " << cmd << " [options] pid" << std::endl
435             << "    --contains=<string>:  Display sections containing string." << std::endl
436             << "    --help:               Shows this message." << std::endl
437             << "    --verbose:            Makes displays verbose." << std::endl;
438   PrintLetterKey();
439 }
440
441 static int DexDiagMain(int argc, char* argv[]) {
442   if (argc < 2) {
443     Usage(argv[0]);
444     return EXIT_FAILURE;
445   }
446
447   std::vector<std::string> name_filters;
448   // TODO: add option to track usage by class name, etc.
449   for (int i = 1; i < argc - 1; ++i) {
450     const StringPiece option(argv[i]);
451     if (option == "--help") {
452       Usage(argv[0]);
453       return EXIT_SUCCESS;
454     } else if (option == "--verbose") {
455       g_verbose = true;
456     } else if (option.starts_with("--contains=")) {
457       std::string contains(option.substr(strlen("--contains=")).data());
458       name_filters.push_back(contains);
459     } else {
460       Usage(argv[0]);
461       return EXIT_FAILURE;
462     }
463   }
464
465   // Art specific set up.
466   InitLogging(argv, Runtime::Aborter);
467   MemMap::Init();
468
469   pid_t pid;
470   char* endptr;
471   pid = (pid_t)strtol(argv[argc - 1], &endptr, 10);
472   if (*endptr != '\0' || kill(pid, 0) != 0) {
473     std::cerr << StringPrintf("Invalid PID \"%s\".\n", argv[argc - 1]) << std::endl;
474     return EXIT_FAILURE;
475   }
476
477   // get libpagemap kernel information.
478   pm_kernel_t* ker;
479   if (pm_kernel_create(&ker) != 0) {
480     std::cerr << "Error creating kernel interface -- does this kernel have pagemap?" << std::endl;
481     return EXIT_FAILURE;
482   }
483
484   // get libpagemap process information.
485   pm_process_t* proc;
486   if (pm_process_create(ker, pid, &proc) != 0) {
487     std::cerr << "Error creating process interface -- does process "
488               << pid
489               << " really exist?"
490               << std::endl;
491     return EXIT_FAILURE;
492   }
493
494   // Get the set of mappings by the specified process.
495   pm_map_t** maps;
496   size_t num_maps;
497   if (pm_process_maps(proc, &maps, &num_maps) != 0) {
498     std::cerr << "Error listing maps." << std::endl;
499     return EXIT_FAILURE;
500   }
501
502   // Process the mappings that are due to DEX files.
503   Printer printer;
504   for (size_t i = 0; i < num_maps; ++i) {
505     std::string mapped_file_name = pm_map_name(maps[i]);
506     // Filter by name contains options (if any).
507     if (!FilterByNameContains(mapped_file_name, name_filters)) {
508       continue;
509     }
510     if (!DisplayMappingIfFromVdexFile(maps[i], &printer)) {
511       return EXIT_FAILURE;
512     } else if (!DisplayMappingIfFromOatFile(maps[i], &printer)) {
513       return EXIT_FAILURE;
514     }
515   }
516
517   return EXIT_SUCCESS;
518 }
519
520 }  // namespace art
521
522 int main(int argc, char* argv[]) {
523   return art::DexDiagMain(argc, argv);
524 }