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("&", out_file);
384 break;
385 case '<':
386 fputs("<", out_file);
387 break;
388 case '>':
389 fputs(">", out_file);
390 break;
391 case '"':
392 fputs(""", out_file);
393 break;
394 case '\t':
395 fputs("	", out_file);
396 break;
397 case '\n':
398 fputs("
", out_file);
399 break;
400 case '\r':
401 fputs("
", 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