• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 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  * Implementation file of the dexlayout utility.
17  *
18  * This is a tool to read dex files into an internal representation,
19  * reorganize the representation, and emit dex files with a better
20  * file layout.
21  */
22 
23 #include "dexlayout.h"
24 
25 #include <inttypes.h>
26 #include <stdio.h>
27 
28 #include <cstdint>
29 #include <iostream>
30 #include <iterator>
31 #include <memory>
32 #include <sstream>
33 #include <unordered_set>
34 #include <vector>
35 
36 #include "android-base/stringprintf.h"
37 #include "base/hiddenapi_flags.h"
38 #include "base/logging.h"  // For VLOG_IS_ON.
39 #include "base/mem_map.h"
40 #include "base/mman.h"  // For the PROT_* and MAP_* constants.
41 #include "base/os.h"
42 #include "base/utils.h"
43 #include "dex/art_dex_file_loader.h"
44 #include "dex/descriptors_names.h"
45 #include "dex/dex_file-inl.h"
46 #include "dex/dex_file_layout.h"
47 #include "dex/dex_file_loader.h"
48 #include "dex/dex_file_types.h"
49 #include "dex/dex_file_verifier.h"
50 #include "dex/dex_instruction-inl.h"
51 #include "dex_ir.h"
52 #include "dex_ir_builder.h"
53 #include "dex_verify.h"
54 #include "dex_visualize.h"
55 #include "dex_writer.h"
56 #include "profile/profile_compilation_info.h"
57 
58 namespace art {
59 
60 using android::base::StringPrintf;
61 
62 /*
63  * Flags for use with createAccessFlagStr().
64  */
65 enum AccessFor {
66   kAccessForClass = 0, kAccessForMethod = 1, kAccessForField = 2, kAccessForMAX
67 };
68 const int kNumFlags = 18;
69 
70 /*
71  * Gets 2 little-endian bytes.
72  */
Get2LE(unsigned char const * src)73 static inline uint16_t Get2LE(unsigned char const* src) {
74   return src[0] | (src[1] << 8);
75 }
76 
77 /*
78  * Converts the class name portion of a type descriptor to human-readable
79  * "dotted" form. For example, "Ljava/lang/String;" becomes "String".
80  */
DescriptorClassToName(const char * str)81 static std::string DescriptorClassToName(const char* str) {
82   std::string descriptor(str);
83   // Reduce to just the class name prefix.
84   size_t last_slash = descriptor.rfind('/');
85   if (last_slash == std::string::npos) {
86     last_slash = 0;
87   }
88   // Start past the '/' or 'L'.
89   last_slash++;
90 
91   // Copy class name over, trimming trailing ';'.
92   size_t size = descriptor.size() - 1 - last_slash;
93   std::string result(descriptor.substr(last_slash, size));
94 
95   return result;
96 }
97 
98 /*
99  * Returns string representing the boolean value.
100  */
StrBool(bool val)101 static const char* StrBool(bool val) {
102   return val ? "true" : "false";
103 }
104 
105 /*
106  * Returns a quoted string representing the boolean value.
107  */
QuotedBool(bool val)108 static const char* QuotedBool(bool val) {
109   return val ? "\"true\"" : "\"false\"";
110 }
111 
112 /*
113  * Returns a quoted string representing the access flags.
114  */
QuotedVisibility(uint32_t access_flags)115 static const char* QuotedVisibility(uint32_t access_flags) {
116   if (access_flags & kAccPublic) {
117     return "\"public\"";
118   } else if (access_flags & kAccProtected) {
119     return "\"protected\"";
120   } else if (access_flags & kAccPrivate) {
121     return "\"private\"";
122   } else {
123     return "\"package\"";
124   }
125 }
126 
127 /*
128  * Counts the number of '1' bits in a word.
129  */
CountOnes(uint32_t val)130 static int CountOnes(uint32_t val) {
131   val = val - ((val >> 1) & 0x55555555);
132   val = (val & 0x33333333) + ((val >> 2) & 0x33333333);
133   return (((val + (val >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24;
134 }
135 
136 /*
137  * Creates a new string with human-readable access flags.
138  *
139  * In the base language the access_flags fields are type uint16_t; in Dalvik they're uint32_t.
140  */
CreateAccessFlagStr(uint32_t flags,AccessFor for_what)141 static char* CreateAccessFlagStr(uint32_t flags, AccessFor for_what) {
142   static const char* kAccessStrings[kAccessForMAX][kNumFlags] = {
143     {
144       "PUBLIC",                /* 0x00001 */
145       "PRIVATE",               /* 0x00002 */
146       "PROTECTED",             /* 0x00004 */
147       "STATIC",                /* 0x00008 */
148       "FINAL",                 /* 0x00010 */
149       "?",                     /* 0x00020 */
150       "?",                     /* 0x00040 */
151       "?",                     /* 0x00080 */
152       "?",                     /* 0x00100 */
153       "INTERFACE",             /* 0x00200 */
154       "ABSTRACT",              /* 0x00400 */
155       "?",                     /* 0x00800 */
156       "SYNTHETIC",             /* 0x01000 */
157       "ANNOTATION",            /* 0x02000 */
158       "ENUM",                  /* 0x04000 */
159       "?",                     /* 0x08000 */
160       "VERIFIED",              /* 0x10000 */
161       "OPTIMIZED",             /* 0x20000 */
162     }, {
163       "PUBLIC",                /* 0x00001 */
164       "PRIVATE",               /* 0x00002 */
165       "PROTECTED",             /* 0x00004 */
166       "STATIC",                /* 0x00008 */
167       "FINAL",                 /* 0x00010 */
168       "SYNCHRONIZED",          /* 0x00020 */
169       "BRIDGE",                /* 0x00040 */
170       "VARARGS",               /* 0x00080 */
171       "NATIVE",                /* 0x00100 */
172       "?",                     /* 0x00200 */
173       "ABSTRACT",              /* 0x00400 */
174       "STRICT",                /* 0x00800 */
175       "SYNTHETIC",             /* 0x01000 */
176       "?",                     /* 0x02000 */
177       "?",                     /* 0x04000 */
178       "MIRANDA",               /* 0x08000 */
179       "CONSTRUCTOR",           /* 0x10000 */
180       "DECLARED_SYNCHRONIZED", /* 0x20000 */
181     }, {
182       "PUBLIC",                /* 0x00001 */
183       "PRIVATE",               /* 0x00002 */
184       "PROTECTED",             /* 0x00004 */
185       "STATIC",                /* 0x00008 */
186       "FINAL",                 /* 0x00010 */
187       "?",                     /* 0x00020 */
188       "VOLATILE",              /* 0x00040 */
189       "TRANSIENT",             /* 0x00080 */
190       "?",                     /* 0x00100 */
191       "?",                     /* 0x00200 */
192       "?",                     /* 0x00400 */
193       "?",                     /* 0x00800 */
194       "SYNTHETIC",             /* 0x01000 */
195       "?",                     /* 0x02000 */
196       "ENUM",                  /* 0x04000 */
197       "?",                     /* 0x08000 */
198       "?",                     /* 0x10000 */
199       "?",                     /* 0x20000 */
200     },
201   };
202 
203   // Allocate enough storage to hold the expected number of strings,
204   // plus a space between each.  We over-allocate, using the longest
205   // string above as the base metric.
206   const int kLongest = 21;  // The strlen of longest string above.
207   const int count = CountOnes(flags);
208   char* str;
209   char* cp;
210   cp = str = reinterpret_cast<char*>(malloc(count * (kLongest + 1) + 1));
211 
212   for (int i = 0; i < kNumFlags; i++) {
213     if (flags & 0x01) {
214       const char* accessStr = kAccessStrings[for_what][i];
215       const int len = strlen(accessStr);
216       if (cp != str) {
217         *cp++ = ' ';
218       }
219       memcpy(cp, accessStr, len);
220       cp += len;
221     }
222     flags >>= 1;
223   }  // for
224 
225   *cp = '\0';
226   return str;
227 }
228 
GetHiddenapiFlagStr(uint32_t hiddenapi_flags)229 static std::string GetHiddenapiFlagStr(uint32_t hiddenapi_flags) {
230   std::stringstream ss;
231   hiddenapi::ApiList(hiddenapi_flags).Dump(ss);
232   std::string api_list = ss.str();
233   std::transform(api_list.begin(), api_list.end(), api_list.begin(), ::toupper);
234   return api_list;
235 }
236 
GetSignatureForProtoId(const dex_ir::ProtoId * proto)237 static std::string GetSignatureForProtoId(const dex_ir::ProtoId* proto) {
238   if (proto == nullptr) {
239     return "<no signature>";
240   }
241 
242   std::string result("(");
243   const dex_ir::TypeList* type_list = proto->Parameters();
244   if (type_list != nullptr) {
245     for (const dex_ir::TypeId* type_id : *type_list->GetTypeList()) {
246       result += type_id->GetStringId()->Data();
247     }
248   }
249   result += ")";
250   result += proto->ReturnType()->GetStringId()->Data();
251   return result;
252 }
253 
254 /*
255  * Copies character data from "data" to "out", converting non-ASCII values
256  * to fprintf format chars or an ASCII filler ('.' or '?').
257  *
258  * The output buffer must be able to hold (2*len)+1 bytes.  The result is
259  * NULL-terminated.
260  */
Asciify(char * out,const unsigned char * data,size_t len)261 static void Asciify(char* out, const unsigned char* data, size_t len) {
262   for (; len != 0u; --len) {
263     if (*data < 0x20) {
264       // Could do more here, but we don't need them yet.
265       switch (*data) {
266         case '\0':
267           *out++ = '\\';
268           *out++ = '0';
269           break;
270         case '\n':
271           *out++ = '\\';
272           *out++ = 'n';
273           break;
274         default:
275           *out++ = '.';
276           break;
277       }  // switch
278     } else if (*data >= 0x80) {
279       *out++ = '?';
280     } else {
281       *out++ = *data;
282     }
283     data++;
284   }  // while
285   *out = '\0';
286 }
287 /* clang-format off */
288 constexpr char kEscapedLength[256] = {
289     4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 4, 2, 2, 4, 4,  // \a, \b, \t, \n, \r
290     4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
291     1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  // ",
292     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  // '0'..'9'
293     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  // 'A'..'O'
294     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1,  // 'P'..'Z', '\'
295     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  // 'a'..'o'
296     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4,  // 'p'..'z', DEL
297     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  // Unicode range, keep
298     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
299     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
300     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
301     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
302     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
303     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
304     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
305 };
306 /* clang-format on */
307 
308 /*
309  * Check if a UTF8 string contains characters we should quote.
310  */
needsEscape(std::string_view s)311 static bool needsEscape(std::string_view s) {
312   for (unsigned char c : s) {
313     if (kEscapedLength[c] != 1) {
314       return true;
315     }
316   }
317   return false;
318 }
319 
escapeString(std::string_view s)320 std::string escapeString(std::string_view s) {
321   std::ostringstream oss;
322   for (unsigned char c : s) {
323     switch (kEscapedLength[c]) {
324       case 1:
325         oss << static_cast<char>(c);
326         break;
327       case 2:
328         switch (c) {
329           case '\b':
330             oss << '\\' << 'b';
331             break;
332           case '\f':
333             oss << '\\' << 'f';
334             break;
335           case '\n':
336             oss << '\\' << 'n';
337             break;
338           case '\r':
339             oss << '\\' << 'r';
340             break;
341           case '\t':
342             oss << '\\' << 't';
343             break;
344           case '\"':
345             oss << '\\' << '"';
346             break;
347           case '\\':
348             oss << '\\' << '\\';
349             break;
350         }
351         break;
352       case 4:
353         oss << '\\' << '0' + (c / 64) << '0' + ((c % 64) / 8) << '0' + (c % 8);
354         break;
355     }
356   }
357   return oss.str();
358 }
359 
360 /*
361  * Dumps a string value with some escape characters.
362  */
DumpEscapedString(std::string_view s,FILE * out_file)363 static void DumpEscapedString(std::string_view s, FILE* out_file) {
364   fputs("\"", out_file);
365   if (needsEscape(s)) {
366     std::string e = escapeString(s);
367     fputs(e.c_str(), out_file);
368   } else {
369     for (char c : s) {
370       fputc(c, out_file);
371     }
372   }
373   fputs("\"", out_file);
374 }
375 
376 /*
377  * Dumps a string as an XML attribute value.
378  */
DumpXmlAttribute(const char * p,FILE * out_file)379 static void DumpXmlAttribute(const char* p, FILE* out_file) {
380   for (; *p; p++) {
381     switch (*p) {
382       case '&':
383         fputs("&amp;", out_file);
384         break;
385       case '<':
386         fputs("&lt;", out_file);
387         break;
388       case '>':
389         fputs("&gt;", out_file);
390         break;
391       case '"':
392         fputs("&quot;", out_file);
393         break;
394       case '\t':
395         fputs("&#x9;", out_file);
396         break;
397       case '\n':
398         fputs("&#xA;", out_file);
399         break;
400       case '\r':
401         fputs("&#xD;", out_file);
402         break;
403       default:
404         putc(*p, out_file);
405     }  // switch
406   }  // for
407 }
408 
409 /*
410  * Helper for dumpInstruction(), which builds the string
411  * representation for the index in the given instruction.
412  * Returns a pointer to a buffer of sufficient size.
413  */
IndexString(dex_ir::Header * header,const Instruction * dec_insn,size_t buf_size)414 static std::unique_ptr<char[]> IndexString(dex_ir::Header* header,
415                                            const Instruction* dec_insn,
416                                            size_t buf_size) {
417   std::unique_ptr<char[]> buf(new char[buf_size]);
418   // Determine index and width of the string.
419   uint32_t index = 0;
420   uint32_t secondary_index = dex::kDexNoIndex;
421   uint32_t width = 4;
422   switch (Instruction::FormatOf(dec_insn->Opcode())) {
423     // SOME NOT SUPPORTED:
424     // case Instruction::k20bc:
425     case Instruction::k21c:
426     case Instruction::k35c:
427     // case Instruction::k35ms:
428     case Instruction::k3rc:
429     // case Instruction::k3rms:
430     // case Instruction::k35mi:
431     // case Instruction::k3rmi:
432       index = dec_insn->VRegB();
433       width = 4;
434       break;
435     case Instruction::k31c:
436       index = dec_insn->VRegB();
437       width = 8;
438       break;
439     case Instruction::k22c:
440     // case Instruction::k22cs:
441       index = dec_insn->VRegC();
442       width = 4;
443       break;
444     case Instruction::k45cc:
445     case Instruction::k4rcc:
446       index = dec_insn->VRegB();
447       secondary_index = dec_insn->VRegH();
448       width = 4;
449       break;
450     default:
451       break;
452   }  // switch
453 
454   // Determine index type.
455   size_t outSize = 0;
456   switch (Instruction::IndexTypeOf(dec_insn->Opcode())) {
457     case Instruction::kIndexUnknown:
458       // This function should never get called for this type, but do
459       // something sensible here, just to help with debugging.
460       outSize = snprintf(buf.get(), buf_size, "<unknown-index>");
461       break;
462     case Instruction::kIndexNone:
463       // This function should never get called for this type, but do
464       // something sensible here, just to help with debugging.
465       outSize = snprintf(buf.get(), buf_size, "<no-index>");
466       break;
467     case Instruction::kIndexTypeRef:
468       if (index < header->TypeIds().Size()) {
469         const char* tp = header->TypeIds()[index]->GetStringId()->Data();
470         outSize = snprintf(buf.get(), buf_size, "%s // type@%0*x", tp, width, index);
471       } else {
472         outSize = snprintf(buf.get(), buf_size, "<type?> // type@%0*x", width, index);
473       }
474       break;
475     case Instruction::kIndexStringRef:
476       if (index < header->StringIds().Size()) {
477         const char* st = header->StringIds()[index]->Data();
478         if (needsEscape(std::string_view(st))) {
479           std::string escaped = escapeString(st);
480           outSize =
481               snprintf(buf.get(), buf_size, "\"%s\" // string@%0*x", escaped.c_str(), width, index);
482         } else {
483           outSize = snprintf(buf.get(), buf_size, "\"%s\" // string@%0*x", st, width, index);
484         }
485       } else {
486         outSize = snprintf(buf.get(), buf_size, "<string?> // string@%0*x", width, index);
487       }
488       break;
489     case Instruction::kIndexMethodRef:
490       if (index < header->MethodIds().Size()) {
491         dex_ir::MethodId* method_id = header->MethodIds()[index];
492         const char* name = method_id->Name()->Data();
493         std::string type_descriptor = GetSignatureForProtoId(method_id->Proto());
494         const char* back_descriptor = method_id->Class()->GetStringId()->Data();
495         outSize = snprintf(buf.get(), buf_size, "%s.%s:%s // method@%0*x",
496                            back_descriptor, name, type_descriptor.c_str(), width, index);
497       } else {
498         outSize = snprintf(buf.get(), buf_size, "<method?> // method@%0*x", width, index);
499       }
500       break;
501     case Instruction::kIndexFieldRef:
502       if (index < header->FieldIds().Size()) {
503         dex_ir::FieldId* field_id = header->FieldIds()[index];
504         const char* name = field_id->Name()->Data();
505         const char* type_descriptor = field_id->Type()->GetStringId()->Data();
506         const char* back_descriptor = field_id->Class()->GetStringId()->Data();
507         outSize = snprintf(buf.get(), buf_size, "%s.%s:%s // field@%0*x",
508                            back_descriptor, name, type_descriptor, width, index);
509       } else {
510         outSize = snprintf(buf.get(), buf_size, "<field?> // field@%0*x", width, index);
511       }
512       break;
513     case Instruction::kIndexVtableOffset:
514       outSize = snprintf(buf.get(), buf_size, "[%0*x] // vtable #%0*x",
515                          width, index, width, index);
516       break;
517     case Instruction::kIndexFieldOffset:
518       outSize = snprintf(buf.get(), buf_size, "[obj+%0*x]", width, index);
519       break;
520     case Instruction::kIndexMethodAndProtoRef: {
521       std::string method("<method?>");
522       std::string proto("<proto?>");
523       if (index < header->MethodIds().Size()) {
524         dex_ir::MethodId* method_id = header->MethodIds()[index];
525         const char* name = method_id->Name()->Data();
526         std::string type_descriptor = GetSignatureForProtoId(method_id->Proto());
527         const char* back_descriptor = method_id->Class()->GetStringId()->Data();
528         method = StringPrintf("%s.%s:%s", back_descriptor, name, type_descriptor.c_str());
529       }
530       if (secondary_index < header->ProtoIds().Size()) {
531         dex_ir::ProtoId* proto_id = header->ProtoIds()[secondary_index];
532         proto = GetSignatureForProtoId(proto_id);
533       }
534       outSize = snprintf(buf.get(), buf_size, "%s, %s // method@%0*x, proto@%0*x",
535                          method.c_str(), proto.c_str(), width, index, width, secondary_index);
536     }
537     break;
538     case Instruction::kIndexCallSiteRef:
539       outSize = snprintf(buf.get(), buf_size, "call_site@%0*x", width, index);
540       break;
541     // SOME NOT SUPPORTED:
542     // case Instruction::kIndexVaries:
543     // case Instruction::kIndexInlineMethod:
544     default:
545       outSize = snprintf(buf.get(), buf_size, "<?>");
546       break;
547   }  // switch
548 
549   // Determine success of string construction.
550   if (outSize >= buf_size) {
551     // The buffer wasn't big enough; retry with computed size. Note: snprintf()
552     // doesn't count/ the '\0' as part of its returned size, so we add explicit
553     // space for it here.
554     return IndexString(header, dec_insn, outSize + 1);
555   }
556   return buf;
557 }
558 
559 /*
560  * Dumps encoded annotation.
561  */
DumpEncodedAnnotation(dex_ir::EncodedAnnotation * annotation)562 void DexLayout::DumpEncodedAnnotation(dex_ir::EncodedAnnotation* annotation) {
563   fputs(annotation->GetType()->GetStringId()->Data(), out_file_);
564   // Display all name=value pairs.
565   for (auto& subannotation : *annotation->GetAnnotationElements()) {
566     fputc(' ', out_file_);
567     fputs(subannotation->GetName()->Data(), out_file_);
568     fputc('=', out_file_);
569     DumpEncodedValue(subannotation->GetValue());
570   }
571 }
572 /*
573  * Dumps encoded value.
574  */
DumpEncodedValue(const dex_ir::EncodedValue * data)575 void DexLayout::DumpEncodedValue(const dex_ir::EncodedValue* data) {
576   switch (data->Type()) {
577     case DexFile::kDexAnnotationByte:
578       fprintf(out_file_, "%" PRId8, data->GetByte());
579       break;
580     case DexFile::kDexAnnotationShort:
581       fprintf(out_file_, "%" PRId16, data->GetShort());
582       break;
583     case DexFile::kDexAnnotationChar:
584       fprintf(out_file_, "%" PRIu16, data->GetChar());
585       break;
586     case DexFile::kDexAnnotationInt:
587       fprintf(out_file_, "%" PRId32, data->GetInt());
588       break;
589     case DexFile::kDexAnnotationLong:
590       fprintf(out_file_, "%" PRId64, data->GetLong());
591       break;
592     case DexFile::kDexAnnotationFloat: {
593       fprintf(out_file_, "%g", data->GetFloat());
594       break;
595     }
596     case DexFile::kDexAnnotationDouble: {
597       fprintf(out_file_, "%g", data->GetDouble());
598       break;
599     }
600     case DexFile::kDexAnnotationString: {
601       dex_ir::StringId* string_id = data->GetStringId();
602       if (options_.output_format_ == kOutputPlain) {
603         DumpEscapedString(string_id->Data(), out_file_);
604       } else {
605         DumpXmlAttribute(string_id->Data(), out_file_);
606       }
607       break;
608     }
609     case DexFile::kDexAnnotationType: {
610       dex_ir::TypeId* type_id = data->GetTypeId();
611       fputs(type_id->GetStringId()->Data(), out_file_);
612       break;
613     }
614     case DexFile::kDexAnnotationField:
615     case DexFile::kDexAnnotationEnum: {
616       dex_ir::FieldId* field_id = data->GetFieldId();
617       fputs(field_id->Name()->Data(), out_file_);
618       break;
619     }
620     case DexFile::kDexAnnotationMethod: {
621       dex_ir::MethodId* method_id = data->GetMethodId();
622       fputs(method_id->Name()->Data(), out_file_);
623       break;
624     }
625     case DexFile::kDexAnnotationArray: {
626       fputc('{', out_file_);
627       // Display all elements.
628       for (auto& value : *data->GetEncodedArray()->GetEncodedValues()) {
629         fputc(' ', out_file_);
630         DumpEncodedValue(value.get());
631       }
632       fputs(" }", out_file_);
633       break;
634     }
635     case DexFile::kDexAnnotationAnnotation: {
636       DumpEncodedAnnotation(data->GetEncodedAnnotation());
637       break;
638     }
639     case DexFile::kDexAnnotationNull:
640       fputs("null", out_file_);
641       break;
642     case DexFile::kDexAnnotationBoolean:
643       fputs(StrBool(data->GetBoolean()), out_file_);
644       break;
645     default:
646       fputs("????", out_file_);
647       break;
648   }  // switch
649 }
650 
651 /*
652  * Dumps the file header.
653  */
DumpFileHeader()654 void DexLayout::DumpFileHeader() {
655   char sanitized[8 * 2 + 1];
656   fprintf(out_file_, "DEX file header:\n");
657   Asciify(sanitized, header_->Magic(), 8);
658   fprintf(out_file_, "magic               : '%s'\n", sanitized);
659   fprintf(out_file_, "checksum            : %08x\n", header_->Checksum());
660   fprintf(out_file_, "signature           : %02x%02x...%02x%02x\n",
661           header_->Signature()[0], header_->Signature()[1],
662           header_->Signature()[DexFile::kSha1DigestSize - 2],
663           header_->Signature()[DexFile::kSha1DigestSize - 1]);
664   fprintf(out_file_, "file_size           : %d\n", header_->FileSize());
665   fprintf(out_file_, "header_size         : %d\n", header_->HeaderSize());
666   fprintf(out_file_, "link_size           : %d\n", header_->LinkSize());
667   fprintf(out_file_, "link_off            : %d (0x%06x)\n",
668           header_->LinkOffset(), header_->LinkOffset());
669   fprintf(out_file_, "string_ids_size     : %d\n", header_->StringIds().Size());
670   fprintf(out_file_, "string_ids_off      : %d (0x%06x)\n",
671           header_->StringIds().GetOffset(), header_->StringIds().GetOffset());
672   fprintf(out_file_, "type_ids_size       : %d\n", header_->TypeIds().Size());
673   fprintf(out_file_, "type_ids_off        : %d (0x%06x)\n",
674           header_->TypeIds().GetOffset(), header_->TypeIds().GetOffset());
675   fprintf(out_file_, "proto_ids_size      : %d\n", header_->ProtoIds().Size());
676   fprintf(out_file_, "proto_ids_off       : %d (0x%06x)\n",
677           header_->ProtoIds().GetOffset(), header_->ProtoIds().GetOffset());
678   fprintf(out_file_, "field_ids_size      : %d\n", header_->FieldIds().Size());
679   fprintf(out_file_, "field_ids_off       : %d (0x%06x)\n",
680           header_->FieldIds().GetOffset(), header_->FieldIds().GetOffset());
681   fprintf(out_file_, "method_ids_size     : %d\n", header_->MethodIds().Size());
682   fprintf(out_file_, "method_ids_off      : %d (0x%06x)\n",
683           header_->MethodIds().GetOffset(), header_->MethodIds().GetOffset());
684   fprintf(out_file_, "class_defs_size     : %d\n", header_->ClassDefs().Size());
685   fprintf(out_file_, "class_defs_off      : %d (0x%06x)\n",
686           header_->ClassDefs().GetOffset(), header_->ClassDefs().GetOffset());
687   fprintf(out_file_, "data_size           : %d\n", header_->DataSize());
688   fprintf(out_file_, "data_off            : %d (0x%06x)\n\n",
689           header_->DataOffset(), header_->DataOffset());
690 }
691 
692 /*
693  * Dumps a class_def_item.
694  */
DumpClassDef(int idx)695 void DexLayout::DumpClassDef(int idx) {
696   // General class information.
697   dex_ir::ClassDef* class_def = header_->ClassDefs()[idx];
698   fprintf(out_file_, "Class #%d header:\n", idx);
699   fprintf(out_file_, "class_idx           : %d\n", class_def->ClassType()->GetIndex());
700   fprintf(out_file_, "access_flags        : %d (0x%04x)\n",
701           class_def->GetAccessFlags(), class_def->GetAccessFlags());
702   uint32_t superclass_idx =  class_def->Superclass() == nullptr ?
703       DexFile::kDexNoIndex16 : class_def->Superclass()->GetIndex();
704   fprintf(out_file_, "superclass_idx      : %d\n", superclass_idx);
705   fprintf(out_file_, "interfaces_off      : %d (0x%06x)\n",
706           class_def->InterfacesOffset(), class_def->InterfacesOffset());
707   uint32_t source_file_offset = 0xffffffffU;
708   if (class_def->SourceFile() != nullptr) {
709     source_file_offset = class_def->SourceFile()->GetIndex();
710   }
711   fprintf(out_file_, "source_file_idx     : %d\n", source_file_offset);
712   uint32_t annotations_offset = 0;
713   if (class_def->Annotations() != nullptr) {
714     annotations_offset = class_def->Annotations()->GetOffset();
715   }
716   fprintf(out_file_, "annotations_off     : %d (0x%06x)\n",
717           annotations_offset, annotations_offset);
718   if (class_def->GetClassData() == nullptr) {
719     fprintf(out_file_, "class_data_off      : %d (0x%06x)\n", 0, 0);
720   } else {
721     fprintf(out_file_, "class_data_off      : %d (0x%06x)\n",
722             class_def->GetClassData()->GetOffset(), class_def->GetClassData()->GetOffset());
723   }
724 
725   // Fields and methods.
726   dex_ir::ClassData* class_data = class_def->GetClassData();
727   if (class_data != nullptr && class_data->StaticFields() != nullptr) {
728     fprintf(out_file_, "static_fields_size  : %zu\n", class_data->StaticFields()->size());
729   } else {
730     fprintf(out_file_, "static_fields_size  : 0\n");
731   }
732   if (class_data != nullptr && class_data->InstanceFields() != nullptr) {
733     fprintf(out_file_, "instance_fields_size: %zu\n", class_data->InstanceFields()->size());
734   } else {
735     fprintf(out_file_, "instance_fields_size: 0\n");
736   }
737   if (class_data != nullptr && class_data->DirectMethods() != nullptr) {
738     fprintf(out_file_, "direct_methods_size : %zu\n", class_data->DirectMethods()->size());
739   } else {
740     fprintf(out_file_, "direct_methods_size : 0\n");
741   }
742   if (class_data != nullptr && class_data->VirtualMethods() != nullptr) {
743     fprintf(out_file_, "virtual_methods_size: %zu\n", class_data->VirtualMethods()->size());
744   } else {
745     fprintf(out_file_, "virtual_methods_size: 0\n");
746   }
747   fprintf(out_file_, "\n");
748 }
749 
750 /**
751  * Dumps an annotation set item.
752  */
DumpAnnotationSetItem(dex_ir::AnnotationSetItem * set_item)753 void DexLayout::DumpAnnotationSetItem(dex_ir::AnnotationSetItem* set_item) {
754   if (set_item == nullptr || set_item->GetItems()->size() == 0) {
755     fputs("  empty-annotation-set\n", out_file_);
756     return;
757   }
758   for (dex_ir::AnnotationItem* annotation : *set_item->GetItems()) {
759     if (annotation == nullptr) {
760       continue;
761     }
762     fputs("  ", out_file_);
763     switch (annotation->GetVisibility()) {
764       case DexFile::kDexVisibilityBuild:   fputs("VISIBILITY_BUILD ",   out_file_); break;
765       case DexFile::kDexVisibilityRuntime: fputs("VISIBILITY_RUNTIME ", out_file_); break;
766       case DexFile::kDexVisibilitySystem:  fputs("VISIBILITY_SYSTEM ",  out_file_); break;
767       default:                             fputs("VISIBILITY_UNKNOWN ", out_file_); break;
768     }  // switch
769     DumpEncodedAnnotation(annotation->GetAnnotation());
770     fputc('\n', out_file_);
771   }
772 }
773 
774 /*
775  * Dumps class annotations.
776  */
DumpClassAnnotations(int idx)777 void DexLayout::DumpClassAnnotations(int idx) {
778   dex_ir::ClassDef* class_def = header_->ClassDefs()[idx];
779   dex_ir::AnnotationsDirectoryItem* annotations_directory = class_def->Annotations();
780   if (annotations_directory == nullptr) {
781     return;  // none
782   }
783 
784   fprintf(out_file_, "Class #%d annotations:\n", idx);
785 
786   dex_ir::AnnotationSetItem* class_set_item = annotations_directory->GetClassAnnotation();
787   dex_ir::FieldAnnotationVector* fields = annotations_directory->GetFieldAnnotations();
788   dex_ir::MethodAnnotationVector* methods = annotations_directory->GetMethodAnnotations();
789   dex_ir::ParameterAnnotationVector* parameters = annotations_directory->GetParameterAnnotations();
790 
791   // Annotations on the class itself.
792   if (class_set_item != nullptr) {
793     fprintf(out_file_, "Annotations on class\n");
794     DumpAnnotationSetItem(class_set_item);
795   }
796 
797   // Annotations on fields.
798   if (fields != nullptr) {
799     for (auto& field : *fields) {
800       const dex_ir::FieldId* field_id = field->GetFieldId();
801       const uint32_t field_idx = field_id->GetIndex();
802       const char* field_name = field_id->Name()->Data();
803       fprintf(out_file_, "Annotations on field #%u '%s'\n", field_idx, field_name);
804       DumpAnnotationSetItem(field->GetAnnotationSetItem());
805     }
806   }
807 
808   // Annotations on methods.
809   if (methods != nullptr) {
810     for (auto& method : *methods) {
811       const dex_ir::MethodId* method_id = method->GetMethodId();
812       const uint32_t method_idx = method_id->GetIndex();
813       const char* method_name = method_id->Name()->Data();
814       fprintf(out_file_, "Annotations on method #%u '%s'\n", method_idx, method_name);
815       DumpAnnotationSetItem(method->GetAnnotationSetItem());
816     }
817   }
818 
819   // Annotations on method parameters.
820   if (parameters != nullptr) {
821     for (auto& parameter : *parameters) {
822       const dex_ir::MethodId* method_id = parameter->GetMethodId();
823       const uint32_t method_idx = method_id->GetIndex();
824       const char* method_name = method_id->Name()->Data();
825       fprintf(out_file_, "Annotations on method #%u '%s' parameters\n", method_idx, method_name);
826       uint32_t j = 0;
827       for (dex_ir::AnnotationSetItem* annotation : *parameter->GetAnnotations()->GetItems()) {
828         fprintf(out_file_, "#%u\n", j);
829         DumpAnnotationSetItem(annotation);
830         ++j;
831       }
832     }
833   }
834 
835   fputc('\n', out_file_);
836 }
837 
838 /*
839  * Dumps an interface that a class declares to implement.
840  */
DumpInterface(const dex_ir::TypeId * type_item,int i)841 void DexLayout::DumpInterface(const dex_ir::TypeId* type_item, int i) {
842   const char* interface_name = type_item->GetStringId()->Data();
843   if (options_.output_format_ == kOutputPlain) {
844     fprintf(out_file_, "    #%d              : '%s'\n", i, interface_name);
845   } else {
846     std::string dot(DescriptorToDot(interface_name));
847     fprintf(out_file_, "<implements name=\"%s\">\n</implements>\n", dot.c_str());
848   }
849 }
850 
851 /*
852  * Dumps the catches table associated with the code.
853  */
DumpCatches(const dex_ir::CodeItem * code)854 void DexLayout::DumpCatches(const dex_ir::CodeItem* code) {
855   const uint16_t tries_size = code->TriesSize();
856 
857   // No catch table.
858   if (tries_size == 0) {
859     fprintf(out_file_, "      catches       : (none)\n");
860     return;
861   }
862 
863   // Dump all table entries.
864   fprintf(out_file_, "      catches       : %d\n", tries_size);
865   std::vector<std::unique_ptr<const dex_ir::TryItem>>* tries = code->Tries();
866   for (uint32_t i = 0; i < tries_size; i++) {
867     const dex_ir::TryItem* try_item = (*tries)[i].get();
868     const uint32_t start = try_item->StartAddr();
869     const uint32_t end = start + try_item->InsnCount();
870     fprintf(out_file_, "        0x%04x - 0x%04x\n", start, end);
871     for (auto& handler : *try_item->GetHandlers()->GetHandlers()) {
872       const dex_ir::TypeId* type_id = handler->GetTypeId();
873       const char* descriptor = (type_id == nullptr) ? "<any>" : type_id->GetStringId()->Data();
874       fprintf(out_file_, "          %s -> 0x%04x\n", descriptor, handler->GetAddress());
875     }  // for
876   }  // for
877 }
878 
879 /*
880  * Dumps a single instruction.
881  */
DumpInstruction(const dex_ir::CodeItem * code,uint32_t code_offset,uint32_t insn_idx,uint32_t insn_width,const Instruction * dec_insn)882 void DexLayout::DumpInstruction(const dex_ir::CodeItem* code,
883                                 uint32_t code_offset,
884                                 uint32_t insn_idx,
885                                 uint32_t insn_width,
886                                 const Instruction* dec_insn) {
887   // Address of instruction (expressed as byte offset).
888   fprintf(out_file_, "%06x:", code_offset + 0x10 + insn_idx * 2);
889 
890   // Dump (part of) raw bytes.
891   const uint16_t* insns = code->Insns();
892   for (uint32_t i = 0; i < 8; i++) {
893     if (i < insn_width) {
894       if (i == 7) {
895         fprintf(out_file_, " ... ");
896       } else {
897         // Print 16-bit value in little-endian order.
898         const uint8_t* bytePtr = (const uint8_t*) &insns[insn_idx + i];
899         fprintf(out_file_, " %02x%02x", bytePtr[0], bytePtr[1]);
900       }
901     } else {
902       fputs("     ", out_file_);
903     }
904   }  // for
905 
906   // Dump pseudo-instruction or opcode.
907   if (dec_insn->Opcode() == Instruction::NOP) {
908     const uint16_t instr = Get2LE((const uint8_t*) &insns[insn_idx]);
909     if (instr == Instruction::kPackedSwitchSignature) {
910       fprintf(out_file_, "|%04x: packed-switch-data (%d units)", insn_idx, insn_width);
911     } else if (instr == Instruction::kSparseSwitchSignature) {
912       fprintf(out_file_, "|%04x: sparse-switch-data (%d units)", insn_idx, insn_width);
913     } else if (instr == Instruction::kArrayDataSignature) {
914       fprintf(out_file_, "|%04x: array-data (%d units)", insn_idx, insn_width);
915     } else {
916       fprintf(out_file_, "|%04x: nop // spacer", insn_idx);
917     }
918   } else {
919     fprintf(out_file_, "|%04x: %s", insn_idx, dec_insn->Name());
920   }
921 
922   // Set up additional argument.
923   std::unique_ptr<char[]> index_buf;
924   if (Instruction::IndexTypeOf(dec_insn->Opcode()) != Instruction::kIndexNone) {
925     index_buf = IndexString(header_, dec_insn, 200);
926   }
927 
928   // Dump the instruction.
929   //
930   // NOTE: pDecInsn->DumpString(pDexFile) differs too much from original.
931   //
932   switch (Instruction::FormatOf(dec_insn->Opcode())) {
933     case Instruction::k10x:        // op
934       break;
935     case Instruction::k12x:        // op vA, vB
936       fprintf(out_file_, " v%d, v%d", dec_insn->VRegA(), dec_insn->VRegB());
937       break;
938     case Instruction::k11n:        // op vA, #+B
939       fprintf(out_file_, " v%d, #int %d // #%x",
940               dec_insn->VRegA(), (int32_t) dec_insn->VRegB(), (uint8_t)dec_insn->VRegB());
941       break;
942     case Instruction::k11x:        // op vAA
943       fprintf(out_file_, " v%d", dec_insn->VRegA());
944       break;
945     case Instruction::k10t:        // op +AA
946     case Instruction::k20t: {      // op +AAAA
947       const int32_t targ = (int32_t) dec_insn->VRegA();
948       fprintf(out_file_, " %04x // %c%04x",
949               insn_idx + targ,
950               (targ < 0) ? '-' : '+',
951               (targ < 0) ? -targ : targ);
952       break;
953     }
954     case Instruction::k22x:        // op vAA, vBBBB
955       fprintf(out_file_, " v%d, v%d", dec_insn->VRegA(), dec_insn->VRegB());
956       break;
957     case Instruction::k21t: {     // op vAA, +BBBB
958       const int32_t targ = (int32_t) dec_insn->VRegB();
959       fprintf(out_file_, " v%d, %04x // %c%04x", dec_insn->VRegA(),
960               insn_idx + targ,
961               (targ < 0) ? '-' : '+',
962               (targ < 0) ? -targ : targ);
963       break;
964     }
965     case Instruction::k21s:        // op vAA, #+BBBB
966       fprintf(out_file_, " v%d, #int %d // #%x",
967               dec_insn->VRegA(), (int32_t) dec_insn->VRegB(), (uint16_t)dec_insn->VRegB());
968       break;
969     case Instruction::k21h:        // op vAA, #+BBBB0000[00000000]
970       // The printed format varies a bit based on the actual opcode.
971       if (dec_insn->Opcode() == Instruction::CONST_HIGH16) {
972         const int32_t value = dec_insn->VRegB() << 16;
973         fprintf(out_file_, " v%d, #int %d // #%x",
974                 dec_insn->VRegA(), value, (uint16_t) dec_insn->VRegB());
975       } else {
976         const int64_t value = ((int64_t) dec_insn->VRegB()) << 48;
977         fprintf(out_file_, " v%d, #long %" PRId64 " // #%x",
978                 dec_insn->VRegA(), value, (uint16_t) dec_insn->VRegB());
979       }
980       break;
981     case Instruction::k21c:        // op vAA, thing@BBBB
982     case Instruction::k31c:        // op vAA, thing@BBBBBBBB
983       fprintf(out_file_, " v%d, %s", dec_insn->VRegA(), index_buf.get());
984       break;
985     case Instruction::k23x:        // op vAA, vBB, vCC
986       fprintf(out_file_, " v%d, v%d, v%d",
987               dec_insn->VRegA(), dec_insn->VRegB(), dec_insn->VRegC());
988       break;
989     case Instruction::k22b:        // op vAA, vBB, #+CC
990       fprintf(out_file_, " v%d, v%d, #int %d // #%02x",
991               dec_insn->VRegA(), dec_insn->VRegB(),
992               (int32_t) dec_insn->VRegC(), (uint8_t) dec_insn->VRegC());
993       break;
994     case Instruction::k22t: {      // op vA, vB, +CCCC
995       const int32_t targ = (int32_t) dec_insn->VRegC();
996       fprintf(out_file_, " v%d, v%d, %04x // %c%04x",
997               dec_insn->VRegA(), dec_insn->VRegB(),
998               insn_idx + targ,
999               (targ < 0) ? '-' : '+',
1000               (targ < 0) ? -targ : targ);
1001       break;
1002     }
1003     case Instruction::k22s:        // op vA, vB, #+CCCC
1004       fprintf(out_file_, " v%d, v%d, #int %d // #%04x",
1005               dec_insn->VRegA(), dec_insn->VRegB(),
1006               (int32_t) dec_insn->VRegC(), (uint16_t) dec_insn->VRegC());
1007       break;
1008     case Instruction::k22c:        // op vA, vB, thing@CCCC
1009     // NOT SUPPORTED:
1010     // case Instruction::k22cs:    // [opt] op vA, vB, field offset CCCC
1011       fprintf(out_file_, " v%d, v%d, %s",
1012               dec_insn->VRegA(), dec_insn->VRegB(), index_buf.get());
1013       break;
1014     case Instruction::k30t:
1015       fprintf(out_file_, " #%08x", dec_insn->VRegA());
1016       break;
1017     case Instruction::k31i: {     // op vAA, #+BBBBBBBB
1018       // This is often, but not always, a float.
1019       union {
1020         float f;
1021         uint32_t i;
1022       } conv;
1023       conv.i = dec_insn->VRegB();
1024       fprintf(out_file_, " v%d, #float %g // #%08x",
1025               dec_insn->VRegA(), conv.f, dec_insn->VRegB());
1026       break;
1027     }
1028     case Instruction::k31t:       // op vAA, offset +BBBBBBBB
1029       fprintf(out_file_, " v%d, %08x // +%08x",
1030               dec_insn->VRegA(), insn_idx + dec_insn->VRegB(), dec_insn->VRegB());
1031       break;
1032     case Instruction::k32x:        // op vAAAA, vBBBB
1033       fprintf(out_file_, " v%d, v%d", dec_insn->VRegA(), dec_insn->VRegB());
1034       break;
1035     case Instruction::k35c:           // op {vC, vD, vE, vF, vG}, thing@BBBB
1036     case Instruction::k45cc: {        // op {vC, vD, vE, vF, vG}, meth@BBBB, proto@HHHH
1037     // NOT SUPPORTED:
1038     // case Instruction::k35ms:       // [opt] invoke-virtual+super
1039     // case Instruction::k35mi:       // [opt] inline invoke
1040       uint32_t arg[Instruction::kMaxVarArgRegs];
1041       dec_insn->GetVarArgs(arg);
1042       fputs(" {", out_file_);
1043       for (int i = 0, n = dec_insn->VRegA(); i < n; i++) {
1044         if (i == 0) {
1045           fprintf(out_file_, "v%d", arg[i]);
1046         } else {
1047           fprintf(out_file_, ", v%d", arg[i]);
1048         }
1049       }  // for
1050       fprintf(out_file_, "}, %s", index_buf.get());
1051       break;
1052     }
1053     case Instruction::k3rc:           // op {vCCCC .. v(CCCC+AA-1)}, thing@BBBB
1054     case Instruction::k4rcc:          // op {vCCCC .. v(CCCC+AA-1)}, meth@BBBB, proto@HHHH
1055     // NOT SUPPORTED:
1056     // case Instruction::k3rms:       // [opt] invoke-virtual+super/range
1057     // case Instruction::k3rmi:       // [opt] execute-inline/range
1058       {
1059         // This doesn't match the "dx" output when some of the args are
1060         // 64-bit values -- dx only shows the first register.
1061         fputs(" {", out_file_);
1062         for (int i = 0, n = dec_insn->VRegA(); i < n; i++) {
1063           if (i == 0) {
1064             fprintf(out_file_, "v%d", dec_insn->VRegC() + i);
1065           } else {
1066             fprintf(out_file_, ", v%d", dec_insn->VRegC() + i);
1067           }
1068         }  // for
1069         fprintf(out_file_, "}, %s", index_buf.get());
1070       }
1071       break;
1072     case Instruction::k51l: {      // op vAA, #+BBBBBBBBBBBBBBBB
1073       // This is often, but not always, a double.
1074       union {
1075         double d;
1076         uint64_t j;
1077       } conv;
1078       conv.j = dec_insn->WideVRegB();
1079       fprintf(out_file_, " v%d, #double %g // #%016" PRIx64,
1080               dec_insn->VRegA(), conv.d, dec_insn->WideVRegB());
1081       break;
1082     }
1083     // NOT SUPPORTED:
1084     // case Instruction::k00x:        // unknown op or breakpoint
1085     //    break;
1086     default:
1087       fprintf(out_file_, " ???");
1088       break;
1089   }  // switch
1090 
1091   fputc('\n', out_file_);
1092 }
1093 
1094 /*
1095  * Dumps a bytecode disassembly.
1096  */
DumpBytecodes(uint32_t idx,const dex_ir::CodeItem * code,uint32_t code_offset)1097 void DexLayout::DumpBytecodes(uint32_t idx, const dex_ir::CodeItem* code, uint32_t code_offset) {
1098   dex_ir::MethodId* method_id = header_->MethodIds()[idx];
1099   const char* name = method_id->Name()->Data();
1100   std::string type_descriptor = GetSignatureForProtoId(method_id->Proto());
1101   const char* back_descriptor = method_id->Class()->GetStringId()->Data();
1102 
1103   // Generate header.
1104   std::string dot(DescriptorToDot(back_descriptor));
1105   fprintf(out_file_, "%06x:                                        |[%06x] %s.%s:%s\n",
1106           code_offset, code_offset, dot.c_str(), name, type_descriptor.c_str());
1107 
1108   // Iterate over all instructions.
1109   for (const DexInstructionPcPair& inst : code->Instructions()) {
1110     const uint32_t insn_width = inst->SizeInCodeUnits();
1111     if (insn_width == 0) {
1112       LOG(WARNING) << "GLITCH: zero-width instruction at idx=0x" << std::hex << inst.DexPc();
1113       break;
1114     }
1115     DumpInstruction(code, code_offset, inst.DexPc(), insn_width, &inst.Inst());
1116   }  // for
1117 }
1118 
1119 /*
1120  * Lookup functions.
1121  */
StringDataByIdx(uint32_t idx,dex_ir::Header * header)1122 static const char* StringDataByIdx(uint32_t idx, dex_ir::Header* header) {
1123   dex_ir::StringId* string_id = header->GetStringIdOrNullPtr(idx);
1124   if (string_id == nullptr) {
1125     return nullptr;
1126   }
1127   return string_id->Data();
1128 }
1129 
StringDataByTypeIdx(uint16_t idx,dex_ir::Header * header)1130 static const char* StringDataByTypeIdx(uint16_t idx, dex_ir::Header* header) {
1131   dex_ir::TypeId* type_id = header->GetTypeIdOrNullPtr(idx);
1132   if (type_id == nullptr) {
1133     return nullptr;
1134   }
1135   dex_ir::StringId* string_id = type_id->GetStringId();
1136   if (string_id == nullptr) {
1137     return nullptr;
1138   }
1139   return string_id->Data();
1140 }
1141 
1142 
1143 /*
1144  * Dumps code of a method.
1145  */
DumpCode(uint32_t idx,const dex_ir::CodeItem * code,uint32_t code_offset,const char * declaring_class_descriptor,const char * method_name,bool is_static,const dex_ir::ProtoId * proto)1146 void DexLayout::DumpCode(uint32_t idx,
1147                          const dex_ir::CodeItem* code,
1148                          uint32_t code_offset,
1149                          const char* declaring_class_descriptor,
1150                          const char* method_name,
1151                          bool is_static,
1152                          const dex_ir::ProtoId* proto) {
1153   fprintf(out_file_, "      registers     : %d\n", code->RegistersSize());
1154   fprintf(out_file_, "      ins           : %d\n", code->InsSize());
1155   fprintf(out_file_, "      outs          : %d\n", code->OutsSize());
1156   fprintf(out_file_, "      insns size    : %d 16-bit code units\n",
1157           code->InsnsSize());
1158 
1159   // Bytecode disassembly, if requested.
1160   if (options_.disassemble_) {
1161     DumpBytecodes(idx, code, code_offset);
1162   }
1163 
1164   // Try-catch blocks.
1165   DumpCatches(code);
1166 
1167   // Positions and locals table in the debug info.
1168   dex_ir::DebugInfoItem* debug_info = code->DebugInfo();
1169   fprintf(out_file_, "      positions     :\n");
1170   if (debug_info != nullptr) {
1171     DexFile::DecodeDebugPositionInfo(debug_info->GetDebugInfo(),
1172                                      [this](uint32_t idx) {
1173                                        return StringDataByIdx(idx, this->header_);
1174                                      },
1175                                      [&](const DexFile::PositionInfo& entry) {
1176                                        fprintf(out_file_,
1177                                                "        0x%04x line=%d\n",
1178                                                entry.address_,
1179                                                entry.line_);
1180                                         return false;
1181                                      });
1182   }
1183   fprintf(out_file_, "      locals        :\n");
1184   if (debug_info != nullptr) {
1185     std::vector<const char*> arg_descriptors;
1186     const dex_ir::TypeList* parameters = proto->Parameters();
1187     if (parameters != nullptr) {
1188       const dex_ir::TypeIdVector* parameter_type_vector = parameters->GetTypeList();
1189       if (parameter_type_vector != nullptr) {
1190         for (const dex_ir::TypeId* type_id : *parameter_type_vector) {
1191           arg_descriptors.push_back(type_id->GetStringId()->Data());
1192         }
1193       }
1194     }
1195     DexFile::DecodeDebugLocalInfo(debug_info->GetDebugInfo(),
1196                                   "DexLayout in-memory",
1197                                   declaring_class_descriptor,
1198                                   arg_descriptors,
1199                                   method_name,
1200                                   is_static,
1201                                   code->RegistersSize(),
1202                                   code->InsSize(),
1203                                   code->InsnsSize(),
1204                                   [this](uint32_t idx) {
1205                                     return StringDataByIdx(idx, this->header_);
1206                                   },
1207                                   [this](uint32_t idx) {
1208                                     return
1209                                         StringDataByTypeIdx(dchecked_integral_cast<uint16_t>(idx),
1210                                                             this->header_);
1211                                   },
1212                                   [&](const DexFile::LocalInfo& entry) {
1213                                     fprintf(out_file_,
1214                                             "        0x%04x - 0x%04x reg=%d %s %s",
1215                                             entry.start_address_,
1216                                             entry.end_address_,
1217                                             entry.reg_,
1218                                             entry.name_,
1219                                             entry.descriptor_);
1220                                     if (entry.signature_) {
1221                                       fputc(' ', out_file_);
1222                                       fputs(entry.signature_, out_file_);
1223                                     }
1224                                     fputc('\n', out_file_);
1225                                   });
1226   }
1227 }
1228 
1229 /*
1230  * Dumps a method.
1231  */
DumpMethod(uint32_t idx,uint32_t flags,uint32_t hiddenapi_flags,const dex_ir::CodeItem * code,int i)1232 void DexLayout::DumpMethod(uint32_t idx,
1233                            uint32_t flags,
1234                            uint32_t hiddenapi_flags,
1235                            const dex_ir::CodeItem* code,
1236                            int i) {
1237   // Bail for anything private if export only requested.
1238   if (options_.exports_only_ && (flags & (kAccPublic | kAccProtected)) == 0) {
1239     return;
1240   }
1241 
1242   dex_ir::MethodId* method_id = header_->MethodIds()[idx];
1243   const char* name = method_id->Name()->Data();
1244   char* type_descriptor = strdup(GetSignatureForProtoId(method_id->Proto()).c_str());
1245   const char* back_descriptor = method_id->Class()->GetStringId()->Data();
1246   char* access_str = CreateAccessFlagStr(flags, kAccessForMethod);
1247 
1248   if (options_.output_format_ == kOutputPlain) {
1249     fprintf(out_file_, "    #%d              : (in %s)\n", i, back_descriptor);
1250     fprintf(out_file_, "      name          : '%s'\n", name);
1251     fprintf(out_file_, "      type          : '%s'\n", type_descriptor);
1252     fprintf(out_file_, "      access        : 0x%04x (%s)\n", flags, access_str);
1253     if (options_.show_section_headers_) {
1254       fprintf(out_file_, "      method_idx    : %d\n", method_id->GetIndex());
1255     }
1256     if (hiddenapi_flags != 0u) {
1257       fprintf(out_file_,
1258               "      hiddenapi     : 0x%04x (%s)\n",
1259               hiddenapi_flags,
1260               GetHiddenapiFlagStr(hiddenapi_flags).c_str());
1261     }
1262     if (code == nullptr) {
1263       fprintf(out_file_, "      code          : (none)\n");
1264     } else {
1265       fprintf(out_file_, "      code          -\n");
1266       DumpCode(idx,
1267                code,
1268                code->GetOffset(),
1269                back_descriptor,
1270                name,
1271                (flags & kAccStatic) != 0,
1272                method_id->Proto());
1273     }
1274     if (options_.disassemble_) {
1275       fputc('\n', out_file_);
1276     }
1277   } else if (options_.output_format_ == kOutputXml) {
1278     const bool constructor = (name[0] == '<');
1279 
1280     // Method name and prototype.
1281     if (constructor) {
1282       std::string dot(DescriptorClassToName(back_descriptor));
1283       fprintf(out_file_, "<constructor name=\"%s\"\n", dot.c_str());
1284       dot = DescriptorToDot(back_descriptor);
1285       fprintf(out_file_, " type=\"%s\"\n", dot.c_str());
1286     } else {
1287       fprintf(out_file_, "<method name=\"%s\"\n", name);
1288       const char* return_type = strrchr(type_descriptor, ')');
1289       if (return_type == nullptr) {
1290         LOG(ERROR) << "bad method type descriptor '" << type_descriptor << "'";
1291         goto bail;
1292       }
1293       std::string dot(DescriptorToDot(return_type + 1));
1294       fprintf(out_file_, " return=\"%s\"\n", dot.c_str());
1295       fprintf(out_file_, " abstract=%s\n", QuotedBool((flags & kAccAbstract) != 0));
1296       fprintf(out_file_, " native=%s\n", QuotedBool((flags & kAccNative) != 0));
1297       fprintf(out_file_, " synchronized=%s\n", QuotedBool(
1298           (flags & (kAccSynchronized | kAccDeclaredSynchronized)) != 0));
1299     }
1300 
1301     // Additional method flags.
1302     fprintf(out_file_, " static=%s\n", QuotedBool((flags & kAccStatic) != 0));
1303     fprintf(out_file_, " final=%s\n", QuotedBool((flags & kAccFinal) != 0));
1304     // The "deprecated=" not knowable w/o parsing annotations.
1305     fprintf(out_file_, " visibility=%s\n>\n", QuotedVisibility(flags));
1306 
1307     // Parameters.
1308     if (type_descriptor[0] != '(') {
1309       LOG(ERROR) << "ERROR: bad descriptor '" << type_descriptor << "'";
1310       goto bail;
1311     }
1312     char* tmp_buf = reinterpret_cast<char*>(malloc(strlen(type_descriptor) + 1));
1313     const char* base = type_descriptor + 1;
1314     int arg_num = 0;
1315     while (*base != ')') {
1316       char* cp = tmp_buf;
1317       while (*base == '[') {
1318         *cp++ = *base++;
1319       }
1320       if (*base == 'L') {
1321         // Copy through ';'.
1322         do {
1323           *cp = *base++;
1324         } while (*cp++ != ';');
1325       } else {
1326         // Primitive char, copy it.
1327         if (strchr("ZBCSIFJD", *base) == nullptr) {
1328           LOG(ERROR) << "ERROR: bad method signature '" << base << "'";
1329           break;  // while
1330         }
1331         *cp++ = *base++;
1332       }
1333       // Null terminate and display.
1334       *cp++ = '\0';
1335       std::string dot(DescriptorToDot(tmp_buf));
1336       fprintf(out_file_, "<parameter name=\"arg%d\" type=\"%s\">\n"
1337                         "</parameter>\n", arg_num++, dot.c_str());
1338     }  // while
1339     free(tmp_buf);
1340     if (constructor) {
1341       fprintf(out_file_, "</constructor>\n");
1342     } else {
1343       fprintf(out_file_, "</method>\n");
1344     }
1345   }
1346 
1347 bail:
1348   free(type_descriptor);
1349   free(access_str);
1350 }
1351 
1352 /*
1353  * Dumps a static (class) field.
1354  */
DumpSField(uint32_t idx,uint32_t flags,uint32_t hiddenapi_flags,int i,dex_ir::EncodedValue * init)1355 void DexLayout::DumpSField(uint32_t idx,
1356                            uint32_t flags,
1357                            uint32_t hiddenapi_flags,
1358                            int i,
1359                            dex_ir::EncodedValue* init) {
1360   // Bail for anything private if export only requested.
1361   if (options_.exports_only_ && (flags & (kAccPublic | kAccProtected)) == 0) {
1362     return;
1363   }
1364 
1365   dex_ir::FieldId* field_id = header_->FieldIds()[idx];
1366   const char* name = field_id->Name()->Data();
1367   const char* type_descriptor = field_id->Type()->GetStringId()->Data();
1368   const char* back_descriptor = field_id->Class()->GetStringId()->Data();
1369   char* access_str = CreateAccessFlagStr(flags, kAccessForField);
1370 
1371   if (options_.output_format_ == kOutputPlain) {
1372     fprintf(out_file_, "    #%d              : (in %s)\n", i, back_descriptor);
1373     fprintf(out_file_, "      name          : '%s'\n", name);
1374     fprintf(out_file_, "      type          : '%s'\n", type_descriptor);
1375     fprintf(out_file_, "      access        : 0x%04x (%s)\n", flags, access_str);
1376     if (hiddenapi_flags != 0u) {
1377       fprintf(out_file_,
1378               "      hiddenapi     : 0x%04x (%s)\n",
1379               hiddenapi_flags,
1380               GetHiddenapiFlagStr(hiddenapi_flags).c_str());
1381     }
1382     if (init != nullptr) {
1383       fputs("      value         : ", out_file_);
1384       DumpEncodedValue(init);
1385       fputs("\n", out_file_);
1386     }
1387   } else if (options_.output_format_ == kOutputXml) {
1388     fprintf(out_file_, "<field name=\"%s\"\n", name);
1389     std::string dot(DescriptorToDot(type_descriptor));
1390     fprintf(out_file_, " type=\"%s\"\n", dot.c_str());
1391     fprintf(out_file_, " transient=%s\n", QuotedBool((flags & kAccTransient) != 0));
1392     fprintf(out_file_, " volatile=%s\n", QuotedBool((flags & kAccVolatile) != 0));
1393     // The "value=" is not knowable w/o parsing annotations.
1394     fprintf(out_file_, " static=%s\n", QuotedBool((flags & kAccStatic) != 0));
1395     fprintf(out_file_, " final=%s\n", QuotedBool((flags & kAccFinal) != 0));
1396     // The "deprecated=" is not knowable w/o parsing annotations.
1397     fprintf(out_file_, " visibility=%s\n", QuotedVisibility(flags));
1398     if (init != nullptr) {
1399       fputs(" value=\"", out_file_);
1400       DumpEncodedValue(init);
1401       fputs("\"\n", out_file_);
1402     }
1403     fputs(">\n</field>\n", out_file_);
1404   }
1405 
1406   free(access_str);
1407 }
1408 
1409 /*
1410  * Dumps an instance field.
1411  */
DumpIField(uint32_t idx,uint32_t flags,uint32_t hiddenapi_flags,int i)1412 void DexLayout::DumpIField(uint32_t idx,
1413                            uint32_t flags,
1414                            uint32_t hiddenapi_flags,
1415                            int i) {
1416   DumpSField(idx, flags, hiddenapi_flags, i, nullptr);
1417 }
1418 
1419 /*
1420  * Dumps the class.
1421  *
1422  * Note "idx" is a DexClassDef index, not a DexTypeId index.
1423  *
1424  * If "*last_package" is nullptr or does not match the current class' package,
1425  * the value will be replaced with a newly-allocated string.
1426  */
DumpClass(int idx,char ** last_package)1427 void DexLayout::DumpClass(int idx, char** last_package) {
1428   dex_ir::ClassDef* class_def = header_->ClassDefs()[idx];
1429   // Omitting non-public class.
1430   if (options_.exports_only_ && (class_def->GetAccessFlags() & kAccPublic) == 0) {
1431     return;
1432   }
1433 
1434   if (options_.show_section_headers_) {
1435     DumpClassDef(idx);
1436   }
1437 
1438   if (options_.show_annotations_) {
1439     DumpClassAnnotations(idx);
1440   }
1441 
1442   // For the XML output, show the package name.  Ideally we'd gather
1443   // up the classes, sort them, and dump them alphabetically so the
1444   // package name wouldn't jump around, but that's not a great plan
1445   // for something that needs to run on the device.
1446   const char* class_descriptor = header_->ClassDefs()[idx]->ClassType()->GetStringId()->Data();
1447   if (!(class_descriptor[0] == 'L' &&
1448         class_descriptor[strlen(class_descriptor)-1] == ';')) {
1449     // Arrays and primitives should not be defined explicitly. Keep going?
1450     LOG(ERROR) << "Malformed class name '" << class_descriptor << "'";
1451   } else if (options_.output_format_ == kOutputXml) {
1452     char* mangle = strdup(class_descriptor + 1);
1453     mangle[strlen(mangle)-1] = '\0';
1454 
1455     // Reduce to just the package name.
1456     char* last_slash = strrchr(mangle, '/');
1457     if (last_slash != nullptr) {
1458       *last_slash = '\0';
1459     } else {
1460       *mangle = '\0';
1461     }
1462 
1463     for (char* cp = mangle; *cp != '\0'; cp++) {
1464       if (*cp == '/') {
1465         *cp = '.';
1466       }
1467     }  // for
1468 
1469     if (*last_package == nullptr || strcmp(mangle, *last_package) != 0) {
1470       // Start of a new package.
1471       if (*last_package != nullptr) {
1472         fprintf(out_file_, "</package>\n");
1473       }
1474       fprintf(out_file_, "<package name=\"%s\"\n>\n", mangle);
1475       free(*last_package);
1476       *last_package = mangle;
1477     } else {
1478       free(mangle);
1479     }
1480   }
1481 
1482   // General class information.
1483   char* access_str = CreateAccessFlagStr(class_def->GetAccessFlags(), kAccessForClass);
1484   const char* superclass_descriptor = nullptr;
1485   if (class_def->Superclass() != nullptr) {
1486     superclass_descriptor = class_def->Superclass()->GetStringId()->Data();
1487   }
1488   if (options_.output_format_ == kOutputPlain) {
1489     fprintf(out_file_, "Class #%d            -\n", idx);
1490     fprintf(out_file_, "  Class descriptor  : '%s'\n", class_descriptor);
1491     fprintf(out_file_, "  Access flags      : 0x%04x (%s)\n",
1492             class_def->GetAccessFlags(), access_str);
1493     if (superclass_descriptor != nullptr) {
1494       fprintf(out_file_, "  Superclass        : '%s'\n", superclass_descriptor);
1495     }
1496     fprintf(out_file_, "  Interfaces        -\n");
1497   } else {
1498     std::string dot(DescriptorClassToName(class_descriptor));
1499     fprintf(out_file_, "<class name=\"%s\"\n", dot.c_str());
1500     if (superclass_descriptor != nullptr) {
1501       dot = DescriptorToDot(superclass_descriptor);
1502       fprintf(out_file_, " extends=\"%s\"\n", dot.c_str());
1503     }
1504     fprintf(out_file_, " interface=%s\n",
1505             QuotedBool((class_def->GetAccessFlags() & kAccInterface) != 0));
1506     fprintf(out_file_, " abstract=%s\n",
1507             QuotedBool((class_def->GetAccessFlags() & kAccAbstract) != 0));
1508     fprintf(out_file_, " static=%s\n", QuotedBool((class_def->GetAccessFlags() & kAccStatic) != 0));
1509     fprintf(out_file_, " final=%s\n", QuotedBool((class_def->GetAccessFlags() & kAccFinal) != 0));
1510     // The "deprecated=" not knowable w/o parsing annotations.
1511     fprintf(out_file_, " visibility=%s\n", QuotedVisibility(class_def->GetAccessFlags()));
1512     fprintf(out_file_, ">\n");
1513   }
1514 
1515   // Interfaces.
1516   const dex_ir::TypeList* interfaces = class_def->Interfaces();
1517   if (interfaces != nullptr) {
1518     const dex_ir::TypeIdVector* interfaces_vector = interfaces->GetTypeList();
1519     for (uint32_t i = 0; i < interfaces_vector->size(); i++) {
1520       DumpInterface((*interfaces_vector)[i], i);
1521     }  // for
1522   }
1523 
1524   // Fields and methods.
1525   dex_ir::ClassData* class_data = class_def->GetClassData();
1526   // Prepare data for static fields.
1527   dex_ir::EncodedArrayItem* static_values = class_def->StaticValues();
1528   dex_ir::EncodedValueVector* encoded_values =
1529       static_values == nullptr ? nullptr : static_values->GetEncodedValues();
1530   const uint32_t encoded_values_size = (encoded_values == nullptr) ? 0 : encoded_values->size();
1531 
1532   // Static fields.
1533   if (options_.output_format_ == kOutputPlain) {
1534     fprintf(out_file_, "  Static fields     -\n");
1535   }
1536   if (class_data != nullptr) {
1537     dex_ir::FieldItemVector* static_fields = class_data->StaticFields();
1538     if (static_fields != nullptr) {
1539       for (uint32_t i = 0; i < static_fields->size(); i++) {
1540         DumpSField((*static_fields)[i].GetFieldId()->GetIndex(),
1541                    (*static_fields)[i].GetAccessFlags(),
1542                    dex_ir::HiddenapiClassData::GetFlags(header_, class_def, &(*static_fields)[i]),
1543                    i,
1544                    i < encoded_values_size ? (*encoded_values)[i].get() : nullptr);
1545       }  // for
1546     }
1547   }
1548 
1549   // Instance fields.
1550   if (options_.output_format_ == kOutputPlain) {
1551     fprintf(out_file_, "  Instance fields   -\n");
1552   }
1553   if (class_data != nullptr) {
1554     dex_ir::FieldItemVector* instance_fields = class_data->InstanceFields();
1555     if (instance_fields != nullptr) {
1556       for (uint32_t i = 0; i < instance_fields->size(); i++) {
1557         DumpIField((*instance_fields)[i].GetFieldId()->GetIndex(),
1558                    (*instance_fields)[i].GetAccessFlags(),
1559                    dex_ir::HiddenapiClassData::GetFlags(header_, class_def, &(*instance_fields)[i]),
1560                    i);
1561       }  // for
1562     }
1563   }
1564 
1565   // Direct methods.
1566   if (options_.output_format_ == kOutputPlain) {
1567     fprintf(out_file_, "  Direct methods    -\n");
1568   }
1569   if (class_data != nullptr) {
1570     dex_ir::MethodItemVector* direct_methods = class_data->DirectMethods();
1571     if (direct_methods != nullptr) {
1572       for (uint32_t i = 0; i < direct_methods->size(); i++) {
1573         DumpMethod((*direct_methods)[i].GetMethodId()->GetIndex(),
1574                    (*direct_methods)[i].GetAccessFlags(),
1575                    dex_ir::HiddenapiClassData::GetFlags(header_, class_def, &(*direct_methods)[i]),
1576                    (*direct_methods)[i].GetCodeItem(),
1577                    i);
1578       }  // for
1579     }
1580   }
1581 
1582   // Virtual methods.
1583   if (options_.output_format_ == kOutputPlain) {
1584     fprintf(out_file_, "  Virtual methods   -\n");
1585   }
1586   if (class_data != nullptr) {
1587     dex_ir::MethodItemVector* virtual_methods = class_data->VirtualMethods();
1588     if (virtual_methods != nullptr) {
1589       for (uint32_t i = 0; i < virtual_methods->size(); i++) {
1590         DumpMethod((*virtual_methods)[i].GetMethodId()->GetIndex(),
1591                    (*virtual_methods)[i].GetAccessFlags(),
1592                    dex_ir::HiddenapiClassData::GetFlags(header_, class_def, &(*virtual_methods)[i]),
1593                    (*virtual_methods)[i].GetCodeItem(),
1594                    i);
1595       }  // for
1596     }
1597   }
1598 
1599   // End of class.
1600   if (options_.output_format_ == kOutputPlain) {
1601     const char* file_name = "unknown";
1602     if (class_def->SourceFile() != nullptr) {
1603       file_name = class_def->SourceFile()->Data();
1604     }
1605     const dex_ir::StringId* source_file = class_def->SourceFile();
1606     fprintf(out_file_, "  source_file_idx   : %d (%s)\n\n",
1607             source_file == nullptr ? 0xffffffffU : source_file->GetIndex(), file_name);
1608   } else if (options_.output_format_ == kOutputXml) {
1609     fprintf(out_file_, "</class>\n");
1610   }
1611 
1612   free(access_str);
1613 }
1614 
DumpMethodHandle(int idx)1615 void DexLayout::DumpMethodHandle(int idx) {
1616   const dex_ir::MethodHandleItem* mh = header_->MethodHandleItems()[idx];
1617   const char* type = nullptr;
1618   bool is_instance = false;
1619   bool is_invoke = false;
1620 
1621   switch (mh->GetMethodHandleType()) {
1622     case DexFile::MethodHandleType::kStaticPut:
1623       type = "put-static";
1624       is_instance = false;
1625       is_invoke = false;
1626       break;
1627     case DexFile::MethodHandleType::kStaticGet:
1628       type = "get-static";
1629       is_instance = false;
1630       is_invoke = false;
1631       break;
1632     case DexFile::MethodHandleType::kInstancePut:
1633       type = "put-instance";
1634       is_instance = true;
1635       is_invoke = false;
1636       break;
1637     case DexFile::MethodHandleType::kInstanceGet:
1638       type = "get-instance";
1639       is_instance = true;
1640       is_invoke = false;
1641       break;
1642     case DexFile::MethodHandleType::kInvokeStatic:
1643       type = "invoke-static";
1644       is_instance = false;
1645       is_invoke = true;
1646       break;
1647     case DexFile::MethodHandleType::kInvokeInstance:
1648       type = "invoke-instance";
1649       is_instance = true;
1650       is_invoke = true;
1651       break;
1652     case DexFile::MethodHandleType::kInvokeConstructor:
1653       type = "invoke-constructor";
1654       is_instance = true;
1655       is_invoke = true;
1656       break;
1657     case DexFile::MethodHandleType::kInvokeDirect:
1658       type = "invoke-direct";
1659       is_instance = true;
1660       is_invoke = true;
1661       break;
1662     case DexFile::MethodHandleType::kInvokeInterface:
1663       type = "invoke-interface";
1664       is_instance = true;
1665       is_invoke = true;
1666       break;
1667     default:
1668       type = "????";
1669       break;
1670   }  // switch
1671 
1672   const char* declaring_class;
1673   const char* member;
1674   std::string member_type;
1675   if (type != nullptr) {
1676     if (is_invoke) {
1677       auto method_id = static_cast<dex_ir::MethodId*>(mh->GetFieldOrMethodId());
1678       declaring_class = method_id->Class()->GetStringId()->Data();
1679       member = method_id->Name()->Data();
1680       auto proto_id = method_id->Proto();
1681       member_type = GetSignatureForProtoId(proto_id);
1682     } else {
1683       auto field_id = static_cast<dex_ir::FieldId*>(mh->GetFieldOrMethodId());
1684       declaring_class = field_id->Class()->GetStringId()->Data();
1685       member = field_id->Name()->Data();
1686       member_type = field_id->Type()->GetStringId()->Data();
1687     }
1688     if (is_instance) {
1689       member_type = android::base::StringPrintf("(%s%s", declaring_class, member_type.c_str() + 1);
1690     }
1691   } else {
1692     type = "?";
1693     declaring_class = "?";
1694     member = "?";
1695     member_type = "?";
1696   }
1697 
1698   if (options_.output_format_ == kOutputPlain) {
1699     fprintf(out_file_, "Method handle #%u:\n", idx);
1700     fprintf(out_file_, "  type        : %s\n", type);
1701     fprintf(out_file_, "  target      : %s %s\n", declaring_class, member);
1702     fprintf(out_file_, "  target_type : %s\n", member_type.c_str());
1703   }
1704 }
1705 
DumpCallSite(int idx)1706 void DexLayout::DumpCallSite(int idx) {
1707   const dex_ir::CallSiteId* call_site_id = header_->CallSiteIds()[idx];
1708   auto call_site_items = call_site_id->CallSiteItem()->GetEncodedValues();
1709   if (call_site_items->size() < 3) {
1710     LOG(ERROR) << "ERROR: Call site " << idx << " has too few values.";
1711     return;
1712   }
1713   uint32_t offset = call_site_id->CallSiteItem()->GetOffset();
1714 
1715   auto it = call_site_items->begin();
1716   if ((*it)->Type() != EncodedArrayValueIterator::ValueType::kMethodHandle) {
1717     LOG(ERROR) << "ERROR: Call site " << idx << " needs to have a MethodHandle as its first item."
1718                << " Found " << (*it)->Type();
1719     return;
1720   }
1721   auto method_handle = (*it)->GetMethodHandle();
1722   uint32_t method_handle_idx = method_handle->GetIndex();
1723 
1724   it++;
1725   if ((*it)->Type() != EncodedArrayValueIterator::ValueType::kString) {
1726     LOG(ERROR) << "ERROR: Call site " << idx << " needs to have a String for method name "
1727                << "as its second item."
1728                << " Found " << (*it)->Type();
1729     return;
1730   }
1731   const char* method_name = (*it)->GetStringId()->Data();
1732 
1733   it++;
1734   if ((*it)->Type() != EncodedArrayValueIterator::ValueType::kMethodType) {
1735     LOG(ERROR) << "ERROR: Call site " << idx << " needs to have a Prototype as its third item."
1736                << " Found " << (*it)->Type();
1737     return;
1738   }
1739   auto proto_id = (*it)->GetProtoId();
1740   std::string method_type = GetSignatureForProtoId(proto_id);
1741 
1742   it++;
1743   if (options_.output_format_ == kOutputPlain) {
1744     fprintf(out_file_, "Call site #%u: // offset %u\n", idx, offset);
1745     fprintf(out_file_, "  link_argument[0] : %u (MethodHandle)\n", method_handle_idx);
1746     fprintf(out_file_, "  link_argument[1] : %s (String)\n", method_name);
1747     fprintf(out_file_, "  link_argument[2] : %s (MethodType)\n", method_type.c_str());
1748   }
1749 
1750   size_t argument = 3;
1751 
1752   while (it != call_site_items->end()) {
1753     const char* type;
1754     std::string value;
1755     switch ((*it)->Type()) {
1756       case EncodedArrayValueIterator::ValueType::kByte:
1757         type = "byte";
1758         value = android::base::StringPrintf("%u", (*it)->GetByte());
1759         break;
1760       case EncodedArrayValueIterator::ValueType::kShort:
1761         type = "short";
1762         value = android::base::StringPrintf("%d", (*it)->GetShort());
1763         break;
1764       case EncodedArrayValueIterator::ValueType::kChar:
1765         type = "char";
1766         value = android::base::StringPrintf("%u", (*it)->GetChar());
1767         break;
1768       case EncodedArrayValueIterator::ValueType::kInt:
1769         type = "int";
1770         value = android::base::StringPrintf("%d", (*it)->GetInt());
1771         break;
1772       case EncodedArrayValueIterator::ValueType::kLong:
1773         type = "long";
1774         value = android::base::StringPrintf("%" PRId64, (*it)->GetLong());
1775         break;
1776       case EncodedArrayValueIterator::ValueType::kFloat:
1777         type = "float";
1778         value = android::base::StringPrintf("%g", (*it)->GetFloat());
1779         break;
1780       case EncodedArrayValueIterator::ValueType::kDouble:
1781         type = "double";
1782         value = android::base::StringPrintf("%g", (*it)->GetDouble());
1783         break;
1784       case EncodedArrayValueIterator::ValueType::kMethodType: {
1785         type = "MethodType";
1786         auto proto_id_item = (*it)->GetProtoId();
1787         value = GetSignatureForProtoId(proto_id_item);
1788         break;
1789       }
1790       case EncodedArrayValueIterator::ValueType::kMethodHandle: {
1791         type = "MethodHandle";
1792         auto method_handle_item = (*it)->GetMethodHandle();
1793         value = android::base::StringPrintf("%d", method_handle_item->GetIndex());
1794         break;
1795       }
1796       case EncodedArrayValueIterator::ValueType::kString: {
1797         type = "String";
1798         auto string_id = (*it)->GetStringId();
1799         value = string_id->Data();
1800         break;
1801       }
1802       case EncodedArrayValueIterator::ValueType::kType: {
1803         type = "Class";
1804         auto type_id = (*it)->GetTypeId();
1805         value = type_id->GetStringId()->Data();
1806         break;
1807       }
1808       case EncodedArrayValueIterator::ValueType::kField:
1809       case EncodedArrayValueIterator::ValueType::kMethod:
1810       case EncodedArrayValueIterator::ValueType::kEnum:
1811       case EncodedArrayValueIterator::ValueType::kArray:
1812       case EncodedArrayValueIterator::ValueType::kAnnotation:
1813         // Unreachable based on current EncodedArrayValueIterator::Next().
1814         UNIMPLEMENTED(FATAL) << " type " << (*it)->Type();
1815         UNREACHABLE();
1816       case EncodedArrayValueIterator::ValueType::kNull:
1817         type = "Null";
1818         value = "null";
1819         break;
1820       case EncodedArrayValueIterator::ValueType::kBoolean:
1821         type = "boolean";
1822         value = (*it)->GetBoolean() ? "true" : "false";
1823         break;
1824     }
1825 
1826     if (options_.output_format_ == kOutputPlain) {
1827       fprintf(out_file_, "  link_argument[%zu] : %s (%s)\n", argument, value.c_str(), type);
1828     }
1829 
1830     it++;
1831     argument++;
1832   }
1833 }
1834 
DumpDexFile()1835 void DexLayout::DumpDexFile() {
1836   // Headers.
1837   if (options_.show_file_headers_) {
1838     DumpFileHeader();
1839   }
1840 
1841   // Open XML context.
1842   if (options_.output_format_ == kOutputXml) {
1843     fprintf(out_file_, "<api>\n");
1844   }
1845 
1846   // Iterate over all classes.
1847   char* package = nullptr;
1848   const uint32_t class_defs_size = header_->ClassDefs().Size();
1849   for (uint32_t i = 0; i < class_defs_size; i++) {
1850     DumpClass(i, &package);
1851   }  // for
1852 
1853   const uint32_t mh_items_size = header_->MethodHandleItems().Size();
1854   for (uint32_t i = 0; i < mh_items_size; i++) {
1855     DumpMethodHandle(i);
1856   }
1857 
1858   const uint32_t call_sites_size = header_->CallSiteIds().Size();
1859   for (uint32_t i = 0; i < call_sites_size; i++) {
1860     DumpCallSite(i);
1861   }
1862 
1863   // Free the last package allocated.
1864   if (package != nullptr) {
1865     fprintf(out_file_, "</package>\n");
1866     free(package);
1867   }
1868 
1869   // Close XML context.
1870   if (options_.output_format_ == kOutputXml) {
1871     fprintf(out_file_, "</api>\n");
1872   }
1873 }
1874 
LayoutClassDefsAndClassData(const DexFile * dex_file)1875 void DexLayout::LayoutClassDefsAndClassData(const DexFile* dex_file) {
1876   std::vector<dex_ir::ClassDef*> new_class_def_order;
1877   for (auto& class_def : header_->ClassDefs()) {
1878     dex::TypeIndex type_idx(class_def->ClassType()->GetIndex());
1879     if (info_->ContainsClass(*dex_file, type_idx)) {
1880       new_class_def_order.push_back(class_def.get());
1881     }
1882   }
1883   for (auto& class_def : header_->ClassDefs()) {
1884     dex::TypeIndex type_idx(class_def->ClassType()->GetIndex());
1885     if (!info_->ContainsClass(*dex_file, type_idx)) {
1886       new_class_def_order.push_back(class_def.get());
1887     }
1888   }
1889   std::unordered_set<dex_ir::ClassData*> visited_class_data;
1890   size_t class_data_index = 0;
1891   auto& class_datas = header_->ClassDatas();
1892   for (dex_ir::ClassDef* class_def : new_class_def_order) {
1893     dex_ir::ClassData* class_data = class_def->GetClassData();
1894     if (class_data != nullptr && visited_class_data.find(class_data) == visited_class_data.end()) {
1895       visited_class_data.insert(class_data);
1896       // Overwrite the existing vector with the new ordering, note that the sets of objects are
1897       // equivalent, but the order changes. This is why this is not a memory leak.
1898       // TODO: Consider cleaning this up with a shared_ptr.
1899       class_datas[class_data_index].release();  // NOLINT b/117926937
1900       class_datas[class_data_index].reset(class_data);
1901       ++class_data_index;
1902     }
1903   }
1904   CHECK_EQ(class_data_index, class_datas.Size());
1905 
1906   if (DexLayout::kChangeClassDefOrder) {
1907     // This currently produces dex files that violate the spec since the super class class_def is
1908     // supposed to occur before any subclasses.
1909     dex_ir::CollectionVector<dex_ir::ClassDef>& class_defs = header_->ClassDefs();
1910     CHECK_EQ(new_class_def_order.size(), class_defs.Size());
1911     for (size_t i = 0; i < class_defs.Size(); ++i) {
1912       // Overwrite the existing vector with the new ordering, note that the sets of objects are
1913       // equivalent, but the order changes. This is why this is not a memory leak.
1914       // TODO: Consider cleaning this up with a shared_ptr.
1915       class_defs[i].release();  // NOLINT b/117926937
1916       class_defs[i].reset(new_class_def_order[i]);
1917     }
1918   }
1919 }
1920 
LayoutStringData(const DexFile * dex_file)1921 void DexLayout::LayoutStringData(const DexFile* dex_file) {
1922   const size_t num_strings = header_->StringIds().Size();
1923   std::vector<bool> is_shorty(num_strings, false);
1924   std::vector<bool> from_hot_method(num_strings, false);
1925   for (auto& class_def : header_->ClassDefs()) {
1926     // A name of a profile class is probably going to get looked up by ClassTable::Lookup, mark it
1927     // as hot. Add its super class and interfaces as well, which can be used during initialization.
1928     const bool is_profile_class =
1929         info_->ContainsClass(*dex_file, dex::TypeIndex(class_def->ClassType()->GetIndex()));
1930     if (is_profile_class) {
1931       from_hot_method[class_def->ClassType()->GetStringId()->GetIndex()] = true;
1932       const dex_ir::TypeId* superclass = class_def->Superclass();
1933       if (superclass != nullptr) {
1934         from_hot_method[superclass->GetStringId()->GetIndex()] = true;
1935       }
1936       const dex_ir::TypeList* interfaces = class_def->Interfaces();
1937       if (interfaces != nullptr) {
1938         for (const dex_ir::TypeId* interface_type : *interfaces->GetTypeList()) {
1939           from_hot_method[interface_type->GetStringId()->GetIndex()] = true;
1940         }
1941       }
1942     }
1943     dex_ir::ClassData* data = class_def->GetClassData();
1944     if (data == nullptr) {
1945       continue;
1946     }
1947     for (size_t i = 0; i < 2; ++i) {
1948       for (auto& method : *(i == 0 ? data->DirectMethods() : data->VirtualMethods())) {
1949         const dex_ir::MethodId* method_id = method.GetMethodId();
1950         dex_ir::CodeItem* code_item = method.GetCodeItem();
1951         if (code_item == nullptr) {
1952           continue;
1953         }
1954         const bool is_clinit = is_profile_class &&
1955             (method.GetAccessFlags() & kAccConstructor) != 0 &&
1956             (method.GetAccessFlags() & kAccStatic) != 0;
1957         const bool method_executed = is_clinit ||
1958             info_->GetMethodHotness(MethodReference(dex_file, method_id->GetIndex())).IsInProfile();
1959         if (!method_executed) {
1960           continue;
1961         }
1962         is_shorty[method_id->Proto()->Shorty()->GetIndex()] = true;
1963         dex_ir::CodeFixups* fixups = code_item->GetCodeFixups();
1964         if (fixups == nullptr) {
1965           continue;
1966         }
1967         // Add const-strings.
1968         for (dex_ir::StringId* id : fixups->StringIds()) {
1969           from_hot_method[id->GetIndex()] = true;
1970         }
1971         // Add field classes, names, and types.
1972         for (dex_ir::FieldId* id : fixups->FieldIds()) {
1973           // TODO: Only visit field ids from static getters and setters.
1974           from_hot_method[id->Class()->GetStringId()->GetIndex()] = true;
1975           from_hot_method[id->Name()->GetIndex()] = true;
1976           from_hot_method[id->Type()->GetStringId()->GetIndex()] = true;
1977         }
1978         // For clinits, add referenced method classes, names, and protos.
1979         if (is_clinit) {
1980           for (dex_ir::MethodId* id : fixups->MethodIds()) {
1981             from_hot_method[id->Class()->GetStringId()->GetIndex()] = true;
1982             from_hot_method[id->Name()->GetIndex()] = true;
1983             is_shorty[id->Proto()->Shorty()->GetIndex()] = true;
1984           }
1985         }
1986       }
1987     }
1988   }
1989   // Sort string data by specified order.
1990   std::vector<dex_ir::StringId*> string_ids;
1991   for (auto& string_id : header_->StringIds()) {
1992     string_ids.push_back(string_id.get());
1993   }
1994   std::sort(string_ids.begin(),
1995             string_ids.end(),
1996             [&is_shorty, &from_hot_method](const dex_ir::StringId* a,
1997                                            const dex_ir::StringId* b) {
1998     const bool a_is_hot = from_hot_method[a->GetIndex()];
1999     const bool b_is_hot = from_hot_method[b->GetIndex()];
2000     if (a_is_hot != b_is_hot) {
2001       return a_is_hot < b_is_hot;
2002     }
2003     // After hot methods are partitioned, subpartition shorties.
2004     const bool a_is_shorty = is_shorty[a->GetIndex()];
2005     const bool b_is_shorty = is_shorty[b->GetIndex()];
2006     if (a_is_shorty != b_is_shorty) {
2007       return a_is_shorty < b_is_shorty;
2008     }
2009     // Order by index by default.
2010     return a->GetIndex() < b->GetIndex();
2011   });
2012   auto& string_datas = header_->StringDatas();
2013   // Now we know what order we want the string data, reorder them.
2014   size_t data_index = 0;
2015   for (dex_ir::StringId* string_id : string_ids) {
2016     string_datas[data_index].release();  // NOLINT b/117926937
2017     string_datas[data_index].reset(string_id->DataItem());
2018     ++data_index;
2019   }
2020   if (kIsDebugBuild) {
2021     std::unordered_set<dex_ir::StringData*> visited;
2022     for (const std::unique_ptr<dex_ir::StringData>& data : string_datas) {
2023       visited.insert(data.get());
2024     }
2025     for (auto& string_id : header_->StringIds()) {
2026       CHECK(visited.find(string_id->DataItem()) != visited.end());
2027     }
2028   }
2029   CHECK_EQ(data_index, string_datas.Size());
2030 }
2031 
2032 // Orders code items according to specified class data ordering.
LayoutCodeItems(const DexFile * dex_file)2033 void DexLayout::LayoutCodeItems(const DexFile* dex_file) {
2034   static constexpr InvokeType invoke_types[] = {
2035     kDirect,
2036     kVirtual
2037   };
2038 
2039   std::unordered_map<dex_ir::CodeItem*, LayoutType>& code_item_layout =
2040       layout_hotness_info_.code_item_layout_;
2041 
2042   // Assign hotness flags to all code items.
2043   for (InvokeType invoke_type : invoke_types) {
2044     for (auto& class_def : header_->ClassDefs()) {
2045       const bool is_profile_class =
2046           info_->ContainsClass(*dex_file, dex::TypeIndex(class_def->ClassType()->GetIndex()));
2047 
2048       // Skip classes that are not defined in this dex file.
2049       dex_ir::ClassData* class_data = class_def->GetClassData();
2050       if (class_data == nullptr) {
2051         continue;
2052       }
2053       for (auto& method : *(invoke_type == InvokeType::kDirect
2054                                 ? class_data->DirectMethods()
2055                                 : class_data->VirtualMethods())) {
2056         const dex_ir::MethodId *method_id = method.GetMethodId();
2057         dex_ir::CodeItem *code_item = method.GetCodeItem();
2058         if (code_item == nullptr) {
2059           continue;
2060         }
2061         // Separate executed methods (clinits and profiled methods) from unexecuted methods.
2062         const bool is_clinit = (method.GetAccessFlags() & kAccConstructor) != 0 &&
2063             (method.GetAccessFlags() & kAccStatic) != 0;
2064         const bool is_startup_clinit = is_profile_class && is_clinit;
2065         using Hotness = ProfileCompilationInfo::MethodHotness;
2066         Hotness hotness = info_->GetMethodHotness(MethodReference(dex_file, method_id->GetIndex()));
2067         LayoutType state = LayoutType::kLayoutTypeUnused;
2068         if (hotness.IsHot()) {
2069           // Hot code is compiled, maybe one day it won't be accessed. So lay it out together for
2070           // now.
2071           state = LayoutType::kLayoutTypeHot;
2072         } else if (is_startup_clinit || hotness.GetFlags() == Hotness::kFlagStartup) {
2073           // Startup clinit or a method that only has the startup flag.
2074           state = LayoutType::kLayoutTypeStartupOnly;
2075         } else if (is_clinit) {
2076           state = LayoutType::kLayoutTypeUsedOnce;
2077         } else if (hotness.IsInProfile()) {
2078           state = LayoutType::kLayoutTypeSometimesUsed;
2079         }
2080         auto it = code_item_layout.emplace(code_item, state);
2081         if (!it.second) {
2082           LayoutType& layout_type = it.first->second;
2083           // Already exists, merge the hotness.
2084           layout_type = MergeLayoutType(layout_type, state);
2085         }
2086       }
2087     }
2088   }
2089 
2090   const auto& code_items = header_->CodeItems();
2091   if (VLOG_IS_ON(dex)) {
2092     size_t layout_count[static_cast<size_t>(LayoutType::kLayoutTypeCount)] = {};
2093     for (const std::unique_ptr<dex_ir::CodeItem>& code_item : code_items) {
2094       auto it = code_item_layout.find(code_item.get());
2095       DCHECK(it != code_item_layout.end());
2096       ++layout_count[static_cast<size_t>(it->second)];
2097     }
2098     for (size_t i = 0; i < static_cast<size_t>(LayoutType::kLayoutTypeCount); ++i) {
2099       LOG(INFO) << "Code items in category " << i << " count=" << layout_count[i];
2100     }
2101   }
2102 
2103   // Sort the code items vector by new layout. The writing process will take care of calculating
2104   // all the offsets. Stable sort to preserve any existing locality that might be there.
2105   std::stable_sort(code_items.begin(),
2106                    code_items.end(),
2107                    [&](const std::unique_ptr<dex_ir::CodeItem>& a,
2108                        const std::unique_ptr<dex_ir::CodeItem>& b) {
2109     auto it_a = code_item_layout.find(a.get());
2110     auto it_b = code_item_layout.find(b.get());
2111     DCHECK(it_a != code_item_layout.end());
2112     DCHECK(it_b != code_item_layout.end());
2113     const LayoutType layout_type_a = it_a->second;
2114     const LayoutType layout_type_b = it_b->second;
2115     return layout_type_a < layout_type_b;
2116   });
2117 }
2118 
LayoutOutputFile(const DexFile * dex_file)2119 void DexLayout::LayoutOutputFile(const DexFile* dex_file) {
2120   LayoutStringData(dex_file);
2121   LayoutClassDefsAndClassData(dex_file);
2122   LayoutCodeItems(dex_file);
2123 }
2124 
OutputDexFile(const DexFile * input_dex_file,bool compute_offsets,std::unique_ptr<DexContainer> * dex_container,std::string * error_msg)2125 bool DexLayout::OutputDexFile(const DexFile* input_dex_file,
2126                               bool compute_offsets,
2127                               std::unique_ptr<DexContainer>* dex_container,
2128                               std::string* error_msg) {
2129   const std::string& dex_file_location = input_dex_file->GetLocation();
2130   std::unique_ptr<File> new_file;
2131   // If options_.output_dex_directory_ is non null, we are outputting to a file.
2132   if (options_.output_dex_directory_ != nullptr) {
2133     std::string output_location(options_.output_dex_directory_);
2134     const size_t last_slash = dex_file_location.rfind('/');
2135     std::string dex_file_directory = dex_file_location.substr(0, last_slash + 1);
2136     if (output_location == dex_file_directory) {
2137       output_location = dex_file_location + ".new";
2138     } else {
2139       if (!output_location.empty() && output_location.back() != '/') {
2140         output_location += "/";
2141       }
2142       const size_t separator = dex_file_location.rfind('!');
2143       if (separator != std::string::npos) {
2144         output_location += dex_file_location.substr(separator + 1);
2145       } else {
2146         output_location += "classes.dex";
2147       }
2148     }
2149     new_file.reset(OS::CreateEmptyFile(output_location.c_str()));
2150     if (new_file == nullptr) {
2151       LOG(ERROR) << "Could not create dex writer output file: " << output_location;
2152       return false;
2153     }
2154   }
2155   if (!DexWriter::Output(this, dex_container, compute_offsets, error_msg)) {
2156     return false;
2157   }
2158   if (new_file != nullptr) {
2159     DexContainer* const container = dex_container->get();
2160     DexContainer::Section* const main_section = container->GetMainSection();
2161     if (!new_file->WriteFully(main_section->Begin(), main_section->Size())) {
2162       LOG(ERROR) << "Failed to write main section for dex file " << dex_file_location;
2163       new_file->Erase();
2164       return false;
2165     }
2166     DexContainer::Section* const data_section = container->GetDataSection();
2167     if (!new_file->WriteFully(data_section->Begin(), data_section->Size())) {
2168       LOG(ERROR) << "Failed to write data section for dex file " << dex_file_location;
2169       new_file->Erase();
2170       return false;
2171     }
2172     UNUSED(new_file->FlushCloseOrErase());
2173   }
2174   return true;
2175 }
2176 
2177 /*
2178  * Dumps the requested sections of the file.
2179  */
ProcessDexFile(const char * file_name,const DexFile * dex_file,size_t dex_file_index,std::unique_ptr<DexContainer> * dex_container,std::string * error_msg)2180 bool DexLayout::ProcessDexFile(const char* file_name,
2181                                const DexFile* dex_file,
2182                                size_t dex_file_index,
2183                                std::unique_ptr<DexContainer>* dex_container,
2184                                std::string* error_msg) {
2185   const bool has_output_container = dex_container != nullptr;
2186   const bool output = options_.output_dex_directory_ != nullptr || has_output_container;
2187 
2188   // Try to avoid eagerly assigning offsets to find bugs since Offset will abort if the offset
2189   // is unassigned.
2190   bool eagerly_assign_offsets = false;
2191   if (options_.visualize_pattern_ || options_.show_section_statistics_ || options_.dump_) {
2192     // These options required the offsets for dumping purposes.
2193     eagerly_assign_offsets = true;
2194   }
2195   std::unique_ptr<dex_ir::Header> header(dex_ir::DexIrBuilder(*dex_file,
2196                                                                eagerly_assign_offsets,
2197                                                                GetOptions()));
2198   SetHeader(header.get());
2199 
2200   if (options_.verbose_) {
2201     fprintf(out_file_, "Opened '%s', DEX version '%.3s'\n",
2202             file_name, dex_file->GetHeader().magic_ + 4);
2203   }
2204 
2205   if (options_.visualize_pattern_) {
2206     VisualizeDexLayout(header_, dex_file, dex_file_index, info_);
2207     return true;
2208   }
2209 
2210   if (options_.show_section_statistics_) {
2211     ShowDexSectionStatistics(header_, dex_file_index);
2212     return true;
2213   }
2214 
2215   // Dump dex file.
2216   if (options_.dump_) {
2217     DumpDexFile();
2218   }
2219 
2220   // In case we are outputting to a file, keep it open so we can verify.
2221   if (output) {
2222     // Layout information about what strings and code items are hot. Used by the writing process
2223     // to generate the sections that are stored in the oat file.
2224     bool do_layout = info_ != nullptr && !info_->IsEmpty();
2225     if (do_layout) {
2226       LayoutOutputFile(dex_file);
2227     }
2228     // The output needs a dex container, use a temporary one.
2229     std::unique_ptr<DexContainer> temp_container;
2230     if (dex_container == nullptr) {
2231       dex_container = &temp_container;
2232     }
2233     // If we didn't set the offsets eagerly, we definitely need to compute them here.
2234     if (!OutputDexFile(dex_file, do_layout || !eagerly_assign_offsets, dex_container, error_msg)) {
2235       return false;
2236     }
2237 
2238     // Clear header before verifying to reduce peak RAM usage.
2239     const size_t file_size = header_->FileSize();
2240     header.reset();
2241 
2242     // Verify the output dex file's structure, only enabled by default for debug builds.
2243     if (options_.verify_output_ && has_output_container) {
2244       std::string location = "memory mapped file for " + std::string(file_name);
2245       // Dex file verifier cannot handle compact dex.
2246       bool verify = options_.compact_dex_level_ == CompactDexLevel::kCompactDexLevelNone;
2247       DexContainer::Section* const main_section = (*dex_container)->GetMainSection();
2248       DexContainer::Section* const data_section = (*dex_container)->GetDataSection();
2249       DCHECK_EQ(file_size, main_section->Size())
2250           << main_section->Size() << " " << data_section->Size();
2251       auto container = std::make_unique<DexLoaderContainer>(
2252           main_section->Begin(), main_section->End(), data_section->Begin(), data_section->End());
2253       ArtDexFileLoader dex_file_loader(std::move(container), location);
2254       std::unique_ptr<const DexFile> output_dex_file(
2255           dex_file_loader.Open(/* location_checksum= */ 0,
2256                                /*oat_dex_file=*/nullptr,
2257                                verify,
2258                                /*verify_checksum=*/false,
2259                                error_msg));
2260       CHECK(output_dex_file != nullptr) << "Failed to re-open output file:" << *error_msg;
2261 
2262       // Do IR-level comparison between input and output. This check ignores potential differences
2263       // due to layout, so offsets are not checked. Instead, it checks the data contents of each
2264       // item.
2265       //
2266       // Regenerate output IR to catch any bugs that might happen during writing.
2267       std::unique_ptr<dex_ir::Header> output_header(
2268           dex_ir::DexIrBuilder(*output_dex_file,
2269                                /*eagerly_assign_offsets=*/ true,
2270                                GetOptions()));
2271       std::unique_ptr<dex_ir::Header> orig_header(
2272           dex_ir::DexIrBuilder(*dex_file,
2273                                /*eagerly_assign_offsets=*/ true,
2274                                GetOptions()));
2275       CHECK(VerifyOutputDexFile(output_header.get(), orig_header.get(), error_msg)) << *error_msg;
2276     }
2277   }
2278   return true;
2279 }
2280 
2281 /*
2282  * Processes a single file (either direct .dex or indirect .zip/.jar/.apk).
2283  */
ProcessFile(const char * file_name)2284 int DexLayout::ProcessFile(const char* file_name) {
2285   if (options_.verbose_) {
2286     fprintf(out_file_, "Processing '%s'...\n", file_name);
2287   }
2288 
2289   // If the file is not a .dex file, the function tries .zip/.jar/.apk files,
2290   // all of which are Zip archives with "classes.dex" inside.
2291   const bool verify_checksum = !options_.ignore_bad_checksum_;
2292   std::string error_msg;
2293   ArtDexFileLoader dex_file_loader(file_name);
2294   std::vector<std::unique_ptr<const DexFile>> dex_files;
2295   if (!dex_file_loader.Open(
2296           /* verify= */ true, verify_checksum, &error_msg, &dex_files)) {
2297     // Display returned error message to user. Note that this error behavior
2298     // differs from the error messages shown by the original Dalvik dexdump.
2299     LOG(ERROR) << error_msg;
2300     return -1;
2301   }
2302 
2303   // Success. Either report checksum verification or process
2304   // all dex files found in given file.
2305   if (options_.checksum_only_) {
2306     fprintf(out_file_, "Checksum verified\n");
2307   } else {
2308     for (size_t i = 0; i < dex_files.size(); i++) {
2309       // Pass in a null container to avoid output by default.
2310       if (!ProcessDexFile(file_name,
2311                           dex_files[i].get(),
2312                           i,
2313                           /*dex_container=*/ nullptr,
2314                           &error_msg)) {
2315         LOG(WARNING) << "Failed to run dex file " << i << " in " << file_name << " : " << error_msg;
2316       }
2317     }
2318   }
2319   return 0;
2320 }
2321 
2322 }  // namespace art
2323