blob: fd92d7726598111860d34b4c5b82f4610e545cd7 [file] [log] [blame]
David Sehr7629f602016-08-07 16:01:51 -07001/*
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>
Andreas Gampe0dfc3152017-04-24 07:58:06 -070027#include <sys/mman.h> // For the PROT_* and MAP_* constants.
David Sehr7629f602016-08-07 16:01:51 -070028
29#include <iostream>
30#include <memory>
31#include <sstream>
32#include <vector>
33
Andreas Gampe46ee31b2016-12-14 10:11:49 -080034#include "android-base/stringprintf.h"
35
David Sehr7629f602016-08-07 16:01:51 -070036#include "dex_file-inl.h"
Jeff Haob7568152017-03-09 18:14:48 -080037#include "dex_file_verifier.h"
David Sehr7629f602016-08-07 16:01:51 -070038#include "dex_instruction-inl.h"
Andreas Gampe8cf9cb32017-07-19 09:28:38 -070039#include "dex_ir_builder.h"
Jeff Haoec7f1a92017-03-13 16:24:24 -070040#include "dex_verify.h"
David Sehrcdcfde72016-09-26 07:44:04 -070041#include "dex_visualize.h"
Jeff Haoa8621002016-10-04 18:13:44 +000042#include "dex_writer.h"
Calin Juravle33083d62017-01-18 15:29:12 -080043#include "jit/profile_compilation_info.h"
Jeff Haoea7c6292016-11-14 18:10:16 -080044#include "mem_map.h"
Nicolas Geoffrayfd1a6c22016-10-04 11:01:17 +000045#include "os.h"
David Sehr7629f602016-08-07 16:01:51 -070046#include "utils.h"
47
48namespace art {
49
Andreas Gampe46ee31b2016-12-14 10:11:49 -080050using android::base::StringPrintf;
51
Jeff Haoe17f5892017-02-23 16:14:04 -080052static constexpr uint32_t kDexCodeItemAlignment = 4;
53
David Sehr7629f602016-08-07 16:01:51 -070054/*
David Sehr7629f602016-08-07 16:01:51 -070055 * Flags for use with createAccessFlagStr().
56 */
57enum AccessFor {
58 kAccessForClass = 0, kAccessForMethod = 1, kAccessForField = 2, kAccessForMAX
59};
60const int kNumFlags = 18;
61
62/*
63 * Gets 2 little-endian bytes.
64 */
65static inline uint16_t Get2LE(unsigned char const* src) {
66 return src[0] | (src[1] << 8);
67}
68
69/*
Jeff Haoc3acfc52016-08-29 14:18:26 -070070 * Converts a type descriptor to human-readable "dotted" form. For
71 * example, "Ljava/lang/String;" becomes "java.lang.String", and
72 * "[I" becomes "int[]". Also converts '$' to '.', which means this
73 * form can't be converted back to a descriptor.
74 */
75static std::string DescriptorToDotWrapper(const char* descriptor) {
76 std::string result = DescriptorToDot(descriptor);
77 size_t found = result.find('$');
78 while (found != std::string::npos) {
79 result[found] = '.';
80 found = result.find('$', found);
81 }
82 return result;
83}
84
85/*
David Sehr7629f602016-08-07 16:01:51 -070086 * Converts the class name portion of a type descriptor to human-readable
87 * "dotted" form. For example, "Ljava/lang/String;" becomes "String".
88 */
89static std::string DescriptorClassToDot(const char* str) {
90 std::string descriptor(str);
91 // Reduce to just the class name prefix.
92 size_t last_slash = descriptor.rfind('/');
93 if (last_slash == std::string::npos) {
94 last_slash = 0;
95 }
96 // Start past the '/' or 'L'.
97 last_slash++;
98
99 // Copy class name over, trimming trailing ';'.
100 size_t size = descriptor.size() - 1 - last_slash;
101 std::string result(descriptor.substr(last_slash, size));
102
103 // Replace '$' with '.'.
104 size_t dollar_sign = result.find('$');
105 while (dollar_sign != std::string::npos) {
106 result[dollar_sign] = '.';
107 dollar_sign = result.find('$', dollar_sign);
108 }
109
110 return result;
111}
112
113/*
114 * Returns string representing the boolean value.
115 */
116static const char* StrBool(bool val) {
117 return val ? "true" : "false";
118}
119
120/*
121 * Returns a quoted string representing the boolean value.
122 */
123static const char* QuotedBool(bool val) {
124 return val ? "\"true\"" : "\"false\"";
125}
126
127/*
128 * Returns a quoted string representing the access flags.
129 */
130static const char* QuotedVisibility(uint32_t access_flags) {
131 if (access_flags & kAccPublic) {
132 return "\"public\"";
133 } else if (access_flags & kAccProtected) {
134 return "\"protected\"";
135 } else if (access_flags & kAccPrivate) {
136 return "\"private\"";
137 } else {
138 return "\"package\"";
139 }
140}
141
142/*
143 * Counts the number of '1' bits in a word.
144 */
145static int CountOnes(uint32_t val) {
146 val = val - ((val >> 1) & 0x55555555);
147 val = (val & 0x33333333) + ((val >> 2) & 0x33333333);
148 return (((val + (val >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24;
149}
150
151/*
152 * Creates a new string with human-readable access flags.
153 *
154 * In the base language the access_flags fields are type uint16_t; in Dalvik they're uint32_t.
155 */
156static char* CreateAccessFlagStr(uint32_t flags, AccessFor for_what) {
157 static const char* kAccessStrings[kAccessForMAX][kNumFlags] = {
158 {
159 "PUBLIC", /* 0x00001 */
160 "PRIVATE", /* 0x00002 */
161 "PROTECTED", /* 0x00004 */
162 "STATIC", /* 0x00008 */
163 "FINAL", /* 0x00010 */
164 "?", /* 0x00020 */
165 "?", /* 0x00040 */
166 "?", /* 0x00080 */
167 "?", /* 0x00100 */
168 "INTERFACE", /* 0x00200 */
169 "ABSTRACT", /* 0x00400 */
170 "?", /* 0x00800 */
171 "SYNTHETIC", /* 0x01000 */
172 "ANNOTATION", /* 0x02000 */
173 "ENUM", /* 0x04000 */
174 "?", /* 0x08000 */
175 "VERIFIED", /* 0x10000 */
176 "OPTIMIZED", /* 0x20000 */
177 }, {
178 "PUBLIC", /* 0x00001 */
179 "PRIVATE", /* 0x00002 */
180 "PROTECTED", /* 0x00004 */
181 "STATIC", /* 0x00008 */
182 "FINAL", /* 0x00010 */
183 "SYNCHRONIZED", /* 0x00020 */
184 "BRIDGE", /* 0x00040 */
185 "VARARGS", /* 0x00080 */
186 "NATIVE", /* 0x00100 */
187 "?", /* 0x00200 */
188 "ABSTRACT", /* 0x00400 */
189 "STRICT", /* 0x00800 */
190 "SYNTHETIC", /* 0x01000 */
191 "?", /* 0x02000 */
192 "?", /* 0x04000 */
193 "MIRANDA", /* 0x08000 */
194 "CONSTRUCTOR", /* 0x10000 */
195 "DECLARED_SYNCHRONIZED", /* 0x20000 */
196 }, {
197 "PUBLIC", /* 0x00001 */
198 "PRIVATE", /* 0x00002 */
199 "PROTECTED", /* 0x00004 */
200 "STATIC", /* 0x00008 */
201 "FINAL", /* 0x00010 */
202 "?", /* 0x00020 */
203 "VOLATILE", /* 0x00040 */
204 "TRANSIENT", /* 0x00080 */
205 "?", /* 0x00100 */
206 "?", /* 0x00200 */
207 "?", /* 0x00400 */
208 "?", /* 0x00800 */
209 "SYNTHETIC", /* 0x01000 */
210 "?", /* 0x02000 */
211 "ENUM", /* 0x04000 */
212 "?", /* 0x08000 */
213 "?", /* 0x10000 */
214 "?", /* 0x20000 */
215 },
216 };
217
218 // Allocate enough storage to hold the expected number of strings,
219 // plus a space between each. We over-allocate, using the longest
220 // string above as the base metric.
221 const int kLongest = 21; // The strlen of longest string above.
222 const int count = CountOnes(flags);
223 char* str;
224 char* cp;
225 cp = str = reinterpret_cast<char*>(malloc(count * (kLongest + 1) + 1));
226
227 for (int i = 0; i < kNumFlags; i++) {
228 if (flags & 0x01) {
229 const char* accessStr = kAccessStrings[for_what][i];
230 const int len = strlen(accessStr);
231 if (cp != str) {
232 *cp++ = ' ';
233 }
234 memcpy(cp, accessStr, len);
235 cp += len;
236 }
237 flags >>= 1;
238 } // for
239
240 *cp = '\0';
241 return str;
242}
243
244static std::string GetSignatureForProtoId(const dex_ir::ProtoId* proto) {
245 if (proto == nullptr) {
246 return "<no signature>";
247 }
248
David Sehr7629f602016-08-07 16:01:51 -0700249 std::string result("(");
Jeff Haoa8621002016-10-04 18:13:44 +0000250 const dex_ir::TypeList* type_list = proto->Parameters();
251 if (type_list != nullptr) {
252 for (const dex_ir::TypeId* type_id : *type_list->GetTypeList()) {
253 result += type_id->GetStringId()->Data();
254 }
David Sehr7629f602016-08-07 16:01:51 -0700255 }
256 result += ")";
257 result += proto->ReturnType()->GetStringId()->Data();
258 return result;
259}
260
261/*
262 * Copies character data from "data" to "out", converting non-ASCII values
263 * to fprintf format chars or an ASCII filler ('.' or '?').
264 *
265 * The output buffer must be able to hold (2*len)+1 bytes. The result is
266 * NULL-terminated.
267 */
268static void Asciify(char* out, const unsigned char* data, size_t len) {
269 while (len--) {
270 if (*data < 0x20) {
271 // Could do more here, but we don't need them yet.
272 switch (*data) {
273 case '\0':
274 *out++ = '\\';
275 *out++ = '0';
276 break;
277 case '\n':
278 *out++ = '\\';
279 *out++ = 'n';
280 break;
281 default:
282 *out++ = '.';
283 break;
284 } // switch
285 } else if (*data >= 0x80) {
286 *out++ = '?';
287 } else {
288 *out++ = *data;
289 }
290 data++;
291 } // while
292 *out = '\0';
293}
294
295/*
296 * Dumps a string value with some escape characters.
297 */
Jeff Haoea7c6292016-11-14 18:10:16 -0800298static void DumpEscapedString(const char* p, FILE* out_file) {
299 fputs("\"", out_file);
David Sehr7629f602016-08-07 16:01:51 -0700300 for (; *p; p++) {
301 switch (*p) {
302 case '\\':
Jeff Haoea7c6292016-11-14 18:10:16 -0800303 fputs("\\\\", out_file);
David Sehr7629f602016-08-07 16:01:51 -0700304 break;
305 case '\"':
Jeff Haoea7c6292016-11-14 18:10:16 -0800306 fputs("\\\"", out_file);
David Sehr7629f602016-08-07 16:01:51 -0700307 break;
308 case '\t':
Jeff Haoea7c6292016-11-14 18:10:16 -0800309 fputs("\\t", out_file);
David Sehr7629f602016-08-07 16:01:51 -0700310 break;
311 case '\n':
Jeff Haoea7c6292016-11-14 18:10:16 -0800312 fputs("\\n", out_file);
David Sehr7629f602016-08-07 16:01:51 -0700313 break;
314 case '\r':
Jeff Haoea7c6292016-11-14 18:10:16 -0800315 fputs("\\r", out_file);
David Sehr7629f602016-08-07 16:01:51 -0700316 break;
317 default:
Jeff Haoea7c6292016-11-14 18:10:16 -0800318 putc(*p, out_file);
David Sehr7629f602016-08-07 16:01:51 -0700319 } // switch
320 } // for
Jeff Haoea7c6292016-11-14 18:10:16 -0800321 fputs("\"", out_file);
David Sehr7629f602016-08-07 16:01:51 -0700322}
323
324/*
325 * Dumps a string as an XML attribute value.
326 */
Jeff Haoea7c6292016-11-14 18:10:16 -0800327static void DumpXmlAttribute(const char* p, FILE* out_file) {
David Sehr7629f602016-08-07 16:01:51 -0700328 for (; *p; p++) {
329 switch (*p) {
330 case '&':
Jeff Haoea7c6292016-11-14 18:10:16 -0800331 fputs("&amp;", out_file);
David Sehr7629f602016-08-07 16:01:51 -0700332 break;
333 case '<':
Jeff Haoea7c6292016-11-14 18:10:16 -0800334 fputs("&lt;", out_file);
David Sehr7629f602016-08-07 16:01:51 -0700335 break;
336 case '>':
Jeff Haoea7c6292016-11-14 18:10:16 -0800337 fputs("&gt;", out_file);
David Sehr7629f602016-08-07 16:01:51 -0700338 break;
339 case '"':
Jeff Haoea7c6292016-11-14 18:10:16 -0800340 fputs("&quot;", out_file);
David Sehr7629f602016-08-07 16:01:51 -0700341 break;
342 case '\t':
Jeff Haoea7c6292016-11-14 18:10:16 -0800343 fputs("&#x9;", out_file);
David Sehr7629f602016-08-07 16:01:51 -0700344 break;
345 case '\n':
Jeff Haoea7c6292016-11-14 18:10:16 -0800346 fputs("&#xA;", out_file);
David Sehr7629f602016-08-07 16:01:51 -0700347 break;
348 case '\r':
Jeff Haoea7c6292016-11-14 18:10:16 -0800349 fputs("&#xD;", out_file);
David Sehr7629f602016-08-07 16:01:51 -0700350 break;
351 default:
Jeff Haoea7c6292016-11-14 18:10:16 -0800352 putc(*p, out_file);
David Sehr7629f602016-08-07 16:01:51 -0700353 } // switch
354 } // for
355}
356
David Sehr7629f602016-08-07 16:01:51 -0700357/*
358 * Helper for dumpInstruction(), which builds the string
359 * representation for the index in the given instruction.
360 * Returns a pointer to a buffer of sufficient size.
361 */
362static std::unique_ptr<char[]> IndexString(dex_ir::Header* header,
363 const Instruction* dec_insn,
364 size_t buf_size) {
365 std::unique_ptr<char[]> buf(new char[buf_size]);
366 // Determine index and width of the string.
367 uint32_t index = 0;
Jeff Haoea7c6292016-11-14 18:10:16 -0800368 uint32_t secondary_index = DexFile::kDexNoIndex;
David Sehr7629f602016-08-07 16:01:51 -0700369 uint32_t width = 4;
370 switch (Instruction::FormatOf(dec_insn->Opcode())) {
371 // SOME NOT SUPPORTED:
372 // case Instruction::k20bc:
373 case Instruction::k21c:
374 case Instruction::k35c:
375 // case Instruction::k35ms:
376 case Instruction::k3rc:
377 // case Instruction::k3rms:
378 // case Instruction::k35mi:
379 // case Instruction::k3rmi:
380 index = dec_insn->VRegB();
381 width = 4;
382 break;
383 case Instruction::k31c:
384 index = dec_insn->VRegB();
385 width = 8;
386 break;
387 case Instruction::k22c:
388 // case Instruction::k22cs:
389 index = dec_insn->VRegC();
390 width = 4;
391 break;
Orion Hodsonb34bb192016-10-18 17:02:58 +0100392 case Instruction::k45cc:
393 case Instruction::k4rcc:
394 index = dec_insn->VRegB();
395 secondary_index = dec_insn->VRegH();
396 width = 4;
David Sehr7639cdc2017-04-15 10:06:21 -0700397 break;
David Sehr7629f602016-08-07 16:01:51 -0700398 default:
399 break;
400 } // switch
401
402 // Determine index type.
403 size_t outSize = 0;
404 switch (Instruction::IndexTypeOf(dec_insn->Opcode())) {
405 case Instruction::kIndexUnknown:
406 // This function should never get called for this type, but do
407 // something sensible here, just to help with debugging.
408 outSize = snprintf(buf.get(), buf_size, "<unknown-index>");
409 break;
410 case Instruction::kIndexNone:
411 // This function should never get called for this type, but do
412 // something sensible here, just to help with debugging.
413 outSize = snprintf(buf.get(), buf_size, "<no-index>");
414 break;
415 case Instruction::kIndexTypeRef:
Jeff Hao3ab96b42016-09-09 18:35:01 -0700416 if (index < header->GetCollections().TypeIdsSize()) {
417 const char* tp = header->GetCollections().GetTypeId(index)->GetStringId()->Data();
David Sehr7629f602016-08-07 16:01:51 -0700418 outSize = snprintf(buf.get(), buf_size, "%s // type@%0*x", tp, width, index);
419 } else {
420 outSize = snprintf(buf.get(), buf_size, "<type?> // type@%0*x", width, index);
421 }
422 break;
423 case Instruction::kIndexStringRef:
Jeff Hao3ab96b42016-09-09 18:35:01 -0700424 if (index < header->GetCollections().StringIdsSize()) {
425 const char* st = header->GetCollections().GetStringId(index)->Data();
David Sehr7629f602016-08-07 16:01:51 -0700426 outSize = snprintf(buf.get(), buf_size, "\"%s\" // string@%0*x", st, width, index);
427 } else {
428 outSize = snprintf(buf.get(), buf_size, "<string?> // string@%0*x", width, index);
429 }
430 break;
431 case Instruction::kIndexMethodRef:
Jeff Hao3ab96b42016-09-09 18:35:01 -0700432 if (index < header->GetCollections().MethodIdsSize()) {
433 dex_ir::MethodId* method_id = header->GetCollections().GetMethodId(index);
David Sehr7629f602016-08-07 16:01:51 -0700434 const char* name = method_id->Name()->Data();
David Sehr72359222016-09-07 13:04:01 -0700435 std::string type_descriptor = GetSignatureForProtoId(method_id->Proto());
David Sehr7629f602016-08-07 16:01:51 -0700436 const char* back_descriptor = method_id->Class()->GetStringId()->Data();
437 outSize = snprintf(buf.get(), buf_size, "%s.%s:%s // method@%0*x",
David Sehr72359222016-09-07 13:04:01 -0700438 back_descriptor, name, type_descriptor.c_str(), width, index);
David Sehr7629f602016-08-07 16:01:51 -0700439 } else {
440 outSize = snprintf(buf.get(), buf_size, "<method?> // method@%0*x", width, index);
441 }
442 break;
443 case Instruction::kIndexFieldRef:
Jeff Hao3ab96b42016-09-09 18:35:01 -0700444 if (index < header->GetCollections().FieldIdsSize()) {
445 dex_ir::FieldId* field_id = header->GetCollections().GetFieldId(index);
David Sehr7629f602016-08-07 16:01:51 -0700446 const char* name = field_id->Name()->Data();
447 const char* type_descriptor = field_id->Type()->GetStringId()->Data();
448 const char* back_descriptor = field_id->Class()->GetStringId()->Data();
449 outSize = snprintf(buf.get(), buf_size, "%s.%s:%s // field@%0*x",
450 back_descriptor, name, type_descriptor, width, index);
451 } else {
452 outSize = snprintf(buf.get(), buf_size, "<field?> // field@%0*x", width, index);
453 }
454 break;
455 case Instruction::kIndexVtableOffset:
456 outSize = snprintf(buf.get(), buf_size, "[%0*x] // vtable #%0*x",
457 width, index, width, index);
458 break;
459 case Instruction::kIndexFieldOffset:
460 outSize = snprintf(buf.get(), buf_size, "[obj+%0*x]", width, index);
461 break;
Orion Hodsonb34bb192016-10-18 17:02:58 +0100462 case Instruction::kIndexMethodAndProtoRef: {
463 std::string method("<method?>");
464 std::string proto("<proto?>");
465 if (index < header->GetCollections().MethodIdsSize()) {
466 dex_ir::MethodId* method_id = header->GetCollections().GetMethodId(index);
467 const char* name = method_id->Name()->Data();
468 std::string type_descriptor = GetSignatureForProtoId(method_id->Proto());
469 const char* back_descriptor = method_id->Class()->GetStringId()->Data();
470 method = StringPrintf("%s.%s:%s", back_descriptor, name, type_descriptor.c_str());
471 }
472 if (secondary_index < header->GetCollections().ProtoIdsSize()) {
473 dex_ir::ProtoId* proto_id = header->GetCollections().GetProtoId(secondary_index);
474 proto = GetSignatureForProtoId(proto_id);
475 }
476 outSize = snprintf(buf.get(), buf_size, "%s, %s // method@%0*x, proto@%0*x",
477 method.c_str(), proto.c_str(), width, index, width, secondary_index);
Jeff Haoea7c6292016-11-14 18:10:16 -0800478 }
479 break;
480 // SOME NOT SUPPORTED:
481 // case Instruction::kIndexVaries:
482 // case Instruction::kIndexInlineMethod:
David Sehr7629f602016-08-07 16:01:51 -0700483 default:
484 outSize = snprintf(buf.get(), buf_size, "<?>");
485 break;
486 } // switch
487
488 // Determine success of string construction.
489 if (outSize >= buf_size) {
490 // The buffer wasn't big enough; retry with computed size. Note: snprintf()
491 // doesn't count/ the '\0' as part of its returned size, so we add explicit
492 // space for it here.
493 return IndexString(header, dec_insn, outSize + 1);
494 }
495 return buf;
496}
497
498/*
Jeff Haoea7c6292016-11-14 18:10:16 -0800499 * Dumps encoded annotation.
500 */
501void DexLayout::DumpEncodedAnnotation(dex_ir::EncodedAnnotation* annotation) {
502 fputs(annotation->GetType()->GetStringId()->Data(), out_file_);
503 // Display all name=value pairs.
504 for (auto& subannotation : *annotation->GetAnnotationElements()) {
505 fputc(' ', out_file_);
506 fputs(subannotation->GetName()->Data(), out_file_);
507 fputc('=', out_file_);
508 DumpEncodedValue(subannotation->GetValue());
509 }
510}
511/*
512 * Dumps encoded value.
513 */
514void DexLayout::DumpEncodedValue(const dex_ir::EncodedValue* data) {
515 switch (data->Type()) {
516 case DexFile::kDexAnnotationByte:
517 fprintf(out_file_, "%" PRId8, data->GetByte());
518 break;
519 case DexFile::kDexAnnotationShort:
520 fprintf(out_file_, "%" PRId16, data->GetShort());
521 break;
522 case DexFile::kDexAnnotationChar:
523 fprintf(out_file_, "%" PRIu16, data->GetChar());
524 break;
525 case DexFile::kDexAnnotationInt:
526 fprintf(out_file_, "%" PRId32, data->GetInt());
527 break;
528 case DexFile::kDexAnnotationLong:
529 fprintf(out_file_, "%" PRId64, data->GetLong());
530 break;
531 case DexFile::kDexAnnotationFloat: {
532 fprintf(out_file_, "%g", data->GetFloat());
533 break;
534 }
535 case DexFile::kDexAnnotationDouble: {
536 fprintf(out_file_, "%g", data->GetDouble());
537 break;
538 }
539 case DexFile::kDexAnnotationString: {
540 dex_ir::StringId* string_id = data->GetStringId();
541 if (options_.output_format_ == kOutputPlain) {
542 DumpEscapedString(string_id->Data(), out_file_);
543 } else {
544 DumpXmlAttribute(string_id->Data(), out_file_);
545 }
546 break;
547 }
548 case DexFile::kDexAnnotationType: {
549 dex_ir::TypeId* type_id = data->GetTypeId();
550 fputs(type_id->GetStringId()->Data(), out_file_);
551 break;
552 }
553 case DexFile::kDexAnnotationField:
554 case DexFile::kDexAnnotationEnum: {
555 dex_ir::FieldId* field_id = data->GetFieldId();
556 fputs(field_id->Name()->Data(), out_file_);
557 break;
558 }
559 case DexFile::kDexAnnotationMethod: {
560 dex_ir::MethodId* method_id = data->GetMethodId();
561 fputs(method_id->Name()->Data(), out_file_);
562 break;
563 }
564 case DexFile::kDexAnnotationArray: {
565 fputc('{', out_file_);
566 // Display all elements.
567 for (auto& value : *data->GetEncodedArray()->GetEncodedValues()) {
568 fputc(' ', out_file_);
569 DumpEncodedValue(value.get());
570 }
571 fputs(" }", out_file_);
572 break;
573 }
574 case DexFile::kDexAnnotationAnnotation: {
575 DumpEncodedAnnotation(data->GetEncodedAnnotation());
576 break;
577 }
578 case DexFile::kDexAnnotationNull:
579 fputs("null", out_file_);
580 break;
581 case DexFile::kDexAnnotationBoolean:
582 fputs(StrBool(data->GetBoolean()), out_file_);
583 break;
584 default:
585 fputs("????", out_file_);
586 break;
587 } // switch
588}
589
590/*
591 * Dumps the file header.
592 */
593void DexLayout::DumpFileHeader() {
594 char sanitized[8 * 2 + 1];
595 dex_ir::Collections& collections = header_->GetCollections();
596 fprintf(out_file_, "DEX file header:\n");
597 Asciify(sanitized, header_->Magic(), 8);
598 fprintf(out_file_, "magic : '%s'\n", sanitized);
599 fprintf(out_file_, "checksum : %08x\n", header_->Checksum());
600 fprintf(out_file_, "signature : %02x%02x...%02x%02x\n",
601 header_->Signature()[0], header_->Signature()[1],
602 header_->Signature()[DexFile::kSha1DigestSize - 2],
603 header_->Signature()[DexFile::kSha1DigestSize - 1]);
604 fprintf(out_file_, "file_size : %d\n", header_->FileSize());
605 fprintf(out_file_, "header_size : %d\n", header_->HeaderSize());
606 fprintf(out_file_, "link_size : %d\n", header_->LinkSize());
607 fprintf(out_file_, "link_off : %d (0x%06x)\n",
608 header_->LinkOffset(), header_->LinkOffset());
609 fprintf(out_file_, "string_ids_size : %d\n", collections.StringIdsSize());
610 fprintf(out_file_, "string_ids_off : %d (0x%06x)\n",
611 collections.StringIdsOffset(), collections.StringIdsOffset());
612 fprintf(out_file_, "type_ids_size : %d\n", collections.TypeIdsSize());
613 fprintf(out_file_, "type_ids_off : %d (0x%06x)\n",
614 collections.TypeIdsOffset(), collections.TypeIdsOffset());
615 fprintf(out_file_, "proto_ids_size : %d\n", collections.ProtoIdsSize());
616 fprintf(out_file_, "proto_ids_off : %d (0x%06x)\n",
617 collections.ProtoIdsOffset(), collections.ProtoIdsOffset());
618 fprintf(out_file_, "field_ids_size : %d\n", collections.FieldIdsSize());
619 fprintf(out_file_, "field_ids_off : %d (0x%06x)\n",
620 collections.FieldIdsOffset(), collections.FieldIdsOffset());
621 fprintf(out_file_, "method_ids_size : %d\n", collections.MethodIdsSize());
622 fprintf(out_file_, "method_ids_off : %d (0x%06x)\n",
623 collections.MethodIdsOffset(), collections.MethodIdsOffset());
624 fprintf(out_file_, "class_defs_size : %d\n", collections.ClassDefsSize());
625 fprintf(out_file_, "class_defs_off : %d (0x%06x)\n",
626 collections.ClassDefsOffset(), collections.ClassDefsOffset());
627 fprintf(out_file_, "data_size : %d\n", header_->DataSize());
628 fprintf(out_file_, "data_off : %d (0x%06x)\n\n",
629 header_->DataOffset(), header_->DataOffset());
630}
631
632/*
633 * Dumps a class_def_item.
634 */
635void DexLayout::DumpClassDef(int idx) {
636 // General class information.
637 dex_ir::ClassDef* class_def = header_->GetCollections().GetClassDef(idx);
638 fprintf(out_file_, "Class #%d header:\n", idx);
639 fprintf(out_file_, "class_idx : %d\n", class_def->ClassType()->GetIndex());
640 fprintf(out_file_, "access_flags : %d (0x%04x)\n",
641 class_def->GetAccessFlags(), class_def->GetAccessFlags());
642 uint32_t superclass_idx = class_def->Superclass() == nullptr ?
643 DexFile::kDexNoIndex16 : class_def->Superclass()->GetIndex();
644 fprintf(out_file_, "superclass_idx : %d\n", superclass_idx);
645 fprintf(out_file_, "interfaces_off : %d (0x%06x)\n",
646 class_def->InterfacesOffset(), class_def->InterfacesOffset());
647 uint32_t source_file_offset = 0xffffffffU;
648 if (class_def->SourceFile() != nullptr) {
649 source_file_offset = class_def->SourceFile()->GetIndex();
650 }
651 fprintf(out_file_, "source_file_idx : %d\n", source_file_offset);
652 uint32_t annotations_offset = 0;
653 if (class_def->Annotations() != nullptr) {
654 annotations_offset = class_def->Annotations()->GetOffset();
655 }
656 fprintf(out_file_, "annotations_off : %d (0x%06x)\n",
657 annotations_offset, annotations_offset);
658 if (class_def->GetClassData() == nullptr) {
659 fprintf(out_file_, "class_data_off : %d (0x%06x)\n", 0, 0);
660 } else {
661 fprintf(out_file_, "class_data_off : %d (0x%06x)\n",
662 class_def->GetClassData()->GetOffset(), class_def->GetClassData()->GetOffset());
663 }
664
665 // Fields and methods.
666 dex_ir::ClassData* class_data = class_def->GetClassData();
667 if (class_data != nullptr && class_data->StaticFields() != nullptr) {
668 fprintf(out_file_, "static_fields_size : %zu\n", class_data->StaticFields()->size());
669 } else {
670 fprintf(out_file_, "static_fields_size : 0\n");
671 }
672 if (class_data != nullptr && class_data->InstanceFields() != nullptr) {
673 fprintf(out_file_, "instance_fields_size: %zu\n", class_data->InstanceFields()->size());
674 } else {
675 fprintf(out_file_, "instance_fields_size: 0\n");
676 }
677 if (class_data != nullptr && class_data->DirectMethods() != nullptr) {
678 fprintf(out_file_, "direct_methods_size : %zu\n", class_data->DirectMethods()->size());
679 } else {
680 fprintf(out_file_, "direct_methods_size : 0\n");
681 }
682 if (class_data != nullptr && class_data->VirtualMethods() != nullptr) {
683 fprintf(out_file_, "virtual_methods_size: %zu\n", class_data->VirtualMethods()->size());
684 } else {
685 fprintf(out_file_, "virtual_methods_size: 0\n");
686 }
687 fprintf(out_file_, "\n");
688}
689
690/**
691 * Dumps an annotation set item.
692 */
693void DexLayout::DumpAnnotationSetItem(dex_ir::AnnotationSetItem* set_item) {
694 if (set_item == nullptr || set_item->GetItems()->size() == 0) {
695 fputs(" empty-annotation-set\n", out_file_);
696 return;
697 }
698 for (dex_ir::AnnotationItem* annotation : *set_item->GetItems()) {
699 if (annotation == nullptr) {
700 continue;
701 }
702 fputs(" ", out_file_);
703 switch (annotation->GetVisibility()) {
704 case DexFile::kDexVisibilityBuild: fputs("VISIBILITY_BUILD ", out_file_); break;
705 case DexFile::kDexVisibilityRuntime: fputs("VISIBILITY_RUNTIME ", out_file_); break;
706 case DexFile::kDexVisibilitySystem: fputs("VISIBILITY_SYSTEM ", out_file_); break;
707 default: fputs("VISIBILITY_UNKNOWN ", out_file_); break;
708 } // switch
709 DumpEncodedAnnotation(annotation->GetAnnotation());
710 fputc('\n', out_file_);
711 }
712}
713
714/*
715 * Dumps class annotations.
716 */
717void DexLayout::DumpClassAnnotations(int idx) {
718 dex_ir::ClassDef* class_def = header_->GetCollections().GetClassDef(idx);
719 dex_ir::AnnotationsDirectoryItem* annotations_directory = class_def->Annotations();
720 if (annotations_directory == nullptr) {
721 return; // none
722 }
723
724 fprintf(out_file_, "Class #%d annotations:\n", idx);
725
726 dex_ir::AnnotationSetItem* class_set_item = annotations_directory->GetClassAnnotation();
727 dex_ir::FieldAnnotationVector* fields = annotations_directory->GetFieldAnnotations();
728 dex_ir::MethodAnnotationVector* methods = annotations_directory->GetMethodAnnotations();
729 dex_ir::ParameterAnnotationVector* parameters = annotations_directory->GetParameterAnnotations();
730
731 // Annotations on the class itself.
732 if (class_set_item != nullptr) {
733 fprintf(out_file_, "Annotations on class\n");
734 DumpAnnotationSetItem(class_set_item);
735 }
736
737 // Annotations on fields.
738 if (fields != nullptr) {
739 for (auto& field : *fields) {
740 const dex_ir::FieldId* field_id = field->GetFieldId();
741 const uint32_t field_idx = field_id->GetIndex();
742 const char* field_name = field_id->Name()->Data();
743 fprintf(out_file_, "Annotations on field #%u '%s'\n", field_idx, field_name);
744 DumpAnnotationSetItem(field->GetAnnotationSetItem());
745 }
746 }
747
748 // Annotations on methods.
749 if (methods != nullptr) {
750 for (auto& method : *methods) {
751 const dex_ir::MethodId* method_id = method->GetMethodId();
752 const uint32_t method_idx = method_id->GetIndex();
753 const char* method_name = method_id->Name()->Data();
754 fprintf(out_file_, "Annotations on method #%u '%s'\n", method_idx, method_name);
755 DumpAnnotationSetItem(method->GetAnnotationSetItem());
756 }
757 }
758
759 // Annotations on method parameters.
760 if (parameters != nullptr) {
761 for (auto& parameter : *parameters) {
762 const dex_ir::MethodId* method_id = parameter->GetMethodId();
763 const uint32_t method_idx = method_id->GetIndex();
764 const char* method_name = method_id->Name()->Data();
765 fprintf(out_file_, "Annotations on method #%u '%s' parameters\n", method_idx, method_name);
766 uint32_t j = 0;
767 for (dex_ir::AnnotationSetItem* annotation : *parameter->GetAnnotations()->GetItems()) {
768 fprintf(out_file_, "#%u\n", j);
769 DumpAnnotationSetItem(annotation);
770 ++j;
771 }
772 }
773 }
774
775 fputc('\n', out_file_);
776}
777
778/*
779 * Dumps an interface that a class declares to implement.
780 */
781void DexLayout::DumpInterface(const dex_ir::TypeId* type_item, int i) {
782 const char* interface_name = type_item->GetStringId()->Data();
783 if (options_.output_format_ == kOutputPlain) {
784 fprintf(out_file_, " #%d : '%s'\n", i, interface_name);
785 } else {
786 std::string dot(DescriptorToDotWrapper(interface_name));
787 fprintf(out_file_, "<implements name=\"%s\">\n</implements>\n", dot.c_str());
788 }
789}
790
791/*
792 * Dumps the catches table associated with the code.
793 */
794void DexLayout::DumpCatches(const dex_ir::CodeItem* code) {
795 const uint16_t tries_size = code->TriesSize();
796
797 // No catch table.
798 if (tries_size == 0) {
799 fprintf(out_file_, " catches : (none)\n");
800 return;
801 }
802
803 // Dump all table entries.
804 fprintf(out_file_, " catches : %d\n", tries_size);
805 std::vector<std::unique_ptr<const dex_ir::TryItem>>* tries = code->Tries();
806 for (uint32_t i = 0; i < tries_size; i++) {
807 const dex_ir::TryItem* try_item = (*tries)[i].get();
808 const uint32_t start = try_item->StartAddr();
809 const uint32_t end = start + try_item->InsnCount();
810 fprintf(out_file_, " 0x%04x - 0x%04x\n", start, end);
811 for (auto& handler : *try_item->GetHandlers()->GetHandlers()) {
812 const dex_ir::TypeId* type_id = handler->GetTypeId();
813 const char* descriptor = (type_id == nullptr) ? "<any>" : type_id->GetStringId()->Data();
814 fprintf(out_file_, " %s -> 0x%04x\n", descriptor, handler->GetAddress());
815 } // for
816 } // for
817}
818
819/*
820 * Dumps all positions table entries associated with the code.
821 */
822void DexLayout::DumpPositionInfo(const dex_ir::CodeItem* code) {
823 dex_ir::DebugInfoItem* debug_info = code->DebugInfo();
824 if (debug_info == nullptr) {
825 return;
826 }
827 std::vector<std::unique_ptr<dex_ir::PositionInfo>>& positions = debug_info->GetPositionInfo();
828 for (size_t i = 0; i < positions.size(); ++i) {
829 fprintf(out_file_, " 0x%04x line=%d\n", positions[i]->address_, positions[i]->line_);
830 }
831}
832
833/*
834 * Dumps all locals table entries associated with the code.
835 */
836void DexLayout::DumpLocalInfo(const dex_ir::CodeItem* code) {
837 dex_ir::DebugInfoItem* debug_info = code->DebugInfo();
838 if (debug_info == nullptr) {
839 return;
840 }
841 std::vector<std::unique_ptr<dex_ir::LocalInfo>>& locals = debug_info->GetLocalInfo();
842 for (size_t i = 0; i < locals.size(); ++i) {
843 dex_ir::LocalInfo* entry = locals[i].get();
844 fprintf(out_file_, " 0x%04x - 0x%04x reg=%d %s %s %s\n",
845 entry->start_address_, entry->end_address_, entry->reg_,
846 entry->name_.c_str(), entry->descriptor_.c_str(), entry->signature_.c_str());
847 }
848}
849
850/*
David Sehr7629f602016-08-07 16:01:51 -0700851 * Dumps a single instruction.
852 */
Jeff Haoea7c6292016-11-14 18:10:16 -0800853void DexLayout::DumpInstruction(const dex_ir::CodeItem* code,
854 uint32_t code_offset,
855 uint32_t insn_idx,
856 uint32_t insn_width,
857 const Instruction* dec_insn) {
David Sehr7629f602016-08-07 16:01:51 -0700858 // Address of instruction (expressed as byte offset).
859 fprintf(out_file_, "%06x:", code_offset + 0x10 + insn_idx * 2);
860
861 // Dump (part of) raw bytes.
862 const uint16_t* insns = code->Insns();
863 for (uint32_t i = 0; i < 8; i++) {
864 if (i < insn_width) {
865 if (i == 7) {
866 fprintf(out_file_, " ... ");
867 } else {
868 // Print 16-bit value in little-endian order.
869 const uint8_t* bytePtr = (const uint8_t*) &insns[insn_idx + i];
870 fprintf(out_file_, " %02x%02x", bytePtr[0], bytePtr[1]);
871 }
872 } else {
873 fputs(" ", out_file_);
874 }
875 } // for
876
877 // Dump pseudo-instruction or opcode.
878 if (dec_insn->Opcode() == Instruction::NOP) {
879 const uint16_t instr = Get2LE((const uint8_t*) &insns[insn_idx]);
880 if (instr == Instruction::kPackedSwitchSignature) {
881 fprintf(out_file_, "|%04x: packed-switch-data (%d units)", insn_idx, insn_width);
882 } else if (instr == Instruction::kSparseSwitchSignature) {
883 fprintf(out_file_, "|%04x: sparse-switch-data (%d units)", insn_idx, insn_width);
884 } else if (instr == Instruction::kArrayDataSignature) {
885 fprintf(out_file_, "|%04x: array-data (%d units)", insn_idx, insn_width);
886 } else {
887 fprintf(out_file_, "|%04x: nop // spacer", insn_idx);
888 }
889 } else {
890 fprintf(out_file_, "|%04x: %s", insn_idx, dec_insn->Name());
891 }
892
893 // Set up additional argument.
894 std::unique_ptr<char[]> index_buf;
895 if (Instruction::IndexTypeOf(dec_insn->Opcode()) != Instruction::kIndexNone) {
Jeff Haoea7c6292016-11-14 18:10:16 -0800896 index_buf = IndexString(header_, dec_insn, 200);
David Sehr7629f602016-08-07 16:01:51 -0700897 }
898
899 // Dump the instruction.
900 //
901 // NOTE: pDecInsn->DumpString(pDexFile) differs too much from original.
902 //
903 switch (Instruction::FormatOf(dec_insn->Opcode())) {
904 case Instruction::k10x: // op
905 break;
906 case Instruction::k12x: // op vA, vB
907 fprintf(out_file_, " v%d, v%d", dec_insn->VRegA(), dec_insn->VRegB());
908 break;
909 case Instruction::k11n: // op vA, #+B
910 fprintf(out_file_, " v%d, #int %d // #%x",
911 dec_insn->VRegA(), (int32_t) dec_insn->VRegB(), (uint8_t)dec_insn->VRegB());
912 break;
913 case Instruction::k11x: // op vAA
914 fprintf(out_file_, " v%d", dec_insn->VRegA());
915 break;
916 case Instruction::k10t: // op +AA
917 case Instruction::k20t: { // op +AAAA
918 const int32_t targ = (int32_t) dec_insn->VRegA();
919 fprintf(out_file_, " %04x // %c%04x",
920 insn_idx + targ,
921 (targ < 0) ? '-' : '+',
922 (targ < 0) ? -targ : targ);
923 break;
924 }
925 case Instruction::k22x: // op vAA, vBBBB
926 fprintf(out_file_, " v%d, v%d", dec_insn->VRegA(), dec_insn->VRegB());
927 break;
928 case Instruction::k21t: { // op vAA, +BBBB
929 const int32_t targ = (int32_t) dec_insn->VRegB();
930 fprintf(out_file_, " v%d, %04x // %c%04x", dec_insn->VRegA(),
931 insn_idx + targ,
932 (targ < 0) ? '-' : '+',
933 (targ < 0) ? -targ : targ);
934 break;
935 }
936 case Instruction::k21s: // op vAA, #+BBBB
937 fprintf(out_file_, " v%d, #int %d // #%x",
938 dec_insn->VRegA(), (int32_t) dec_insn->VRegB(), (uint16_t)dec_insn->VRegB());
939 break;
940 case Instruction::k21h: // op vAA, #+BBBB0000[00000000]
941 // The printed format varies a bit based on the actual opcode.
942 if (dec_insn->Opcode() == Instruction::CONST_HIGH16) {
943 const int32_t value = dec_insn->VRegB() << 16;
944 fprintf(out_file_, " v%d, #int %d // #%x",
945 dec_insn->VRegA(), value, (uint16_t) dec_insn->VRegB());
946 } else {
947 const int64_t value = ((int64_t) dec_insn->VRegB()) << 48;
948 fprintf(out_file_, " v%d, #long %" PRId64 " // #%x",
949 dec_insn->VRegA(), value, (uint16_t) dec_insn->VRegB());
950 }
951 break;
952 case Instruction::k21c: // op vAA, thing@BBBB
953 case Instruction::k31c: // op vAA, thing@BBBBBBBB
954 fprintf(out_file_, " v%d, %s", dec_insn->VRegA(), index_buf.get());
955 break;
956 case Instruction::k23x: // op vAA, vBB, vCC
957 fprintf(out_file_, " v%d, v%d, v%d",
958 dec_insn->VRegA(), dec_insn->VRegB(), dec_insn->VRegC());
959 break;
960 case Instruction::k22b: // op vAA, vBB, #+CC
961 fprintf(out_file_, " v%d, v%d, #int %d // #%02x",
962 dec_insn->VRegA(), dec_insn->VRegB(),
963 (int32_t) dec_insn->VRegC(), (uint8_t) dec_insn->VRegC());
964 break;
965 case Instruction::k22t: { // op vA, vB, +CCCC
966 const int32_t targ = (int32_t) dec_insn->VRegC();
967 fprintf(out_file_, " v%d, v%d, %04x // %c%04x",
968 dec_insn->VRegA(), dec_insn->VRegB(),
969 insn_idx + targ,
970 (targ < 0) ? '-' : '+',
971 (targ < 0) ? -targ : targ);
972 break;
973 }
974 case Instruction::k22s: // op vA, vB, #+CCCC
975 fprintf(out_file_, " v%d, v%d, #int %d // #%04x",
976 dec_insn->VRegA(), dec_insn->VRegB(),
977 (int32_t) dec_insn->VRegC(), (uint16_t) dec_insn->VRegC());
978 break;
979 case Instruction::k22c: // op vA, vB, thing@CCCC
980 // NOT SUPPORTED:
981 // case Instruction::k22cs: // [opt] op vA, vB, field offset CCCC
982 fprintf(out_file_, " v%d, v%d, %s",
983 dec_insn->VRegA(), dec_insn->VRegB(), index_buf.get());
984 break;
985 case Instruction::k30t:
986 fprintf(out_file_, " #%08x", dec_insn->VRegA());
987 break;
988 case Instruction::k31i: { // op vAA, #+BBBBBBBB
989 // This is often, but not always, a float.
990 union {
991 float f;
992 uint32_t i;
993 } conv;
994 conv.i = dec_insn->VRegB();
995 fprintf(out_file_, " v%d, #float %g // #%08x",
996 dec_insn->VRegA(), conv.f, dec_insn->VRegB());
997 break;
998 }
999 case Instruction::k31t: // op vAA, offset +BBBBBBBB
1000 fprintf(out_file_, " v%d, %08x // +%08x",
1001 dec_insn->VRegA(), insn_idx + dec_insn->VRegB(), dec_insn->VRegB());
1002 break;
1003 case Instruction::k32x: // op vAAAA, vBBBB
1004 fprintf(out_file_, " v%d, v%d", dec_insn->VRegA(), dec_insn->VRegB());
1005 break;
Orion Hodsonb34bb192016-10-18 17:02:58 +01001006 case Instruction::k35c: // op {vC, vD, vE, vF, vG}, thing@BBBB
1007 case Instruction::k45cc: { // op {vC, vD, vE, vF, vG}, meth@BBBB, proto@HHHH
David Sehr7629f602016-08-07 16:01:51 -07001008 // NOT SUPPORTED:
1009 // case Instruction::k35ms: // [opt] invoke-virtual+super
1010 // case Instruction::k35mi: // [opt] inline invoke
1011 uint32_t arg[Instruction::kMaxVarArgRegs];
1012 dec_insn->GetVarArgs(arg);
1013 fputs(" {", out_file_);
1014 for (int i = 0, n = dec_insn->VRegA(); i < n; i++) {
1015 if (i == 0) {
1016 fprintf(out_file_, "v%d", arg[i]);
1017 } else {
1018 fprintf(out_file_, ", v%d", arg[i]);
1019 }
1020 } // for
1021 fprintf(out_file_, "}, %s", index_buf.get());
1022 break;
1023 }
Orion Hodsonb34bb192016-10-18 17:02:58 +01001024 case Instruction::k3rc: // op {vCCCC .. v(CCCC+AA-1)}, thing@BBBB
1025 case Instruction::k4rcc: // op {vCCCC .. v(CCCC+AA-1)}, meth@BBBB, proto@HHHH
David Sehr7629f602016-08-07 16:01:51 -07001026 // NOT SUPPORTED:
1027 // case Instruction::k3rms: // [opt] invoke-virtual+super/range
1028 // case Instruction::k3rmi: // [opt] execute-inline/range
1029 {
1030 // This doesn't match the "dx" output when some of the args are
1031 // 64-bit values -- dx only shows the first register.
1032 fputs(" {", out_file_);
1033 for (int i = 0, n = dec_insn->VRegA(); i < n; i++) {
1034 if (i == 0) {
1035 fprintf(out_file_, "v%d", dec_insn->VRegC() + i);
1036 } else {
1037 fprintf(out_file_, ", v%d", dec_insn->VRegC() + i);
1038 }
1039 } // for
1040 fprintf(out_file_, "}, %s", index_buf.get());
1041 }
1042 break;
1043 case Instruction::k51l: { // op vAA, #+BBBBBBBBBBBBBBBB
1044 // This is often, but not always, a double.
1045 union {
1046 double d;
1047 uint64_t j;
1048 } conv;
1049 conv.j = dec_insn->WideVRegB();
1050 fprintf(out_file_, " v%d, #double %g // #%016" PRIx64,
1051 dec_insn->VRegA(), conv.d, dec_insn->WideVRegB());
1052 break;
1053 }
1054 // NOT SUPPORTED:
1055 // case Instruction::k00x: // unknown op or breakpoint
1056 // break;
1057 default:
1058 fprintf(out_file_, " ???");
1059 break;
1060 } // switch
1061
1062 fputc('\n', out_file_);
1063}
1064
1065/*
1066 * Dumps a bytecode disassembly.
1067 */
Jeff Haoea7c6292016-11-14 18:10:16 -08001068void DexLayout::DumpBytecodes(uint32_t idx, const dex_ir::CodeItem* code, uint32_t code_offset) {
1069 dex_ir::MethodId* method_id = header_->GetCollections().GetMethodId(idx);
David Sehr7629f602016-08-07 16:01:51 -07001070 const char* name = method_id->Name()->Data();
David Sehr72359222016-09-07 13:04:01 -07001071 std::string type_descriptor = GetSignatureForProtoId(method_id->Proto());
David Sehr7629f602016-08-07 16:01:51 -07001072 const char* back_descriptor = method_id->Class()->GetStringId()->Data();
1073
1074 // Generate header.
Jeff Haoc3acfc52016-08-29 14:18:26 -07001075 std::string dot(DescriptorToDotWrapper(back_descriptor));
David Sehr7629f602016-08-07 16:01:51 -07001076 fprintf(out_file_, "%06x: |[%06x] %s.%s:%s\n",
David Sehr72359222016-09-07 13:04:01 -07001077 code_offset, code_offset, dot.c_str(), name, type_descriptor.c_str());
David Sehr7629f602016-08-07 16:01:51 -07001078
1079 // Iterate over all instructions.
1080 const uint16_t* insns = code->Insns();
1081 for (uint32_t insn_idx = 0; insn_idx < code->InsnsSize();) {
1082 const Instruction* instruction = Instruction::At(&insns[insn_idx]);
1083 const uint32_t insn_width = instruction->SizeInCodeUnits();
1084 if (insn_width == 0) {
1085 fprintf(stderr, "GLITCH: zero-width instruction at idx=0x%04x\n", insn_idx);
1086 break;
1087 }
Jeff Haoea7c6292016-11-14 18:10:16 -08001088 DumpInstruction(code, code_offset, insn_idx, insn_width, instruction);
David Sehr7629f602016-08-07 16:01:51 -07001089 insn_idx += insn_width;
1090 } // for
1091}
1092
1093/*
1094 * Dumps code of a method.
1095 */
Jeff Haoea7c6292016-11-14 18:10:16 -08001096void DexLayout::DumpCode(uint32_t idx, const dex_ir::CodeItem* code, uint32_t code_offset) {
David Sehr7629f602016-08-07 16:01:51 -07001097 fprintf(out_file_, " registers : %d\n", code->RegistersSize());
1098 fprintf(out_file_, " ins : %d\n", code->InsSize());
1099 fprintf(out_file_, " outs : %d\n", code->OutsSize());
1100 fprintf(out_file_, " insns size : %d 16-bit code units\n",
1101 code->InsnsSize());
1102
1103 // Bytecode disassembly, if requested.
1104 if (options_.disassemble_) {
Jeff Haoea7c6292016-11-14 18:10:16 -08001105 DumpBytecodes(idx, code, code_offset);
David Sehr7629f602016-08-07 16:01:51 -07001106 }
1107
1108 // Try-catch blocks.
1109 DumpCatches(code);
1110
1111 // Positions and locals table in the debug info.
1112 fprintf(out_file_, " positions : \n");
1113 DumpPositionInfo(code);
1114 fprintf(out_file_, " locals : \n");
1115 DumpLocalInfo(code);
1116}
1117
1118/*
1119 * Dumps a method.
1120 */
Jeff Haoea7c6292016-11-14 18:10:16 -08001121void DexLayout::DumpMethod(uint32_t idx, uint32_t flags, const dex_ir::CodeItem* code, int i) {
David Sehr7629f602016-08-07 16:01:51 -07001122 // Bail for anything private if export only requested.
1123 if (options_.exports_only_ && (flags & (kAccPublic | kAccProtected)) == 0) {
1124 return;
1125 }
1126
Jeff Haoea7c6292016-11-14 18:10:16 -08001127 dex_ir::MethodId* method_id = header_->GetCollections().GetMethodId(idx);
David Sehr7629f602016-08-07 16:01:51 -07001128 const char* name = method_id->Name()->Data();
1129 char* type_descriptor = strdup(GetSignatureForProtoId(method_id->Proto()).c_str());
1130 const char* back_descriptor = method_id->Class()->GetStringId()->Data();
1131 char* access_str = CreateAccessFlagStr(flags, kAccessForMethod);
1132
1133 if (options_.output_format_ == kOutputPlain) {
1134 fprintf(out_file_, " #%d : (in %s)\n", i, back_descriptor);
1135 fprintf(out_file_, " name : '%s'\n", name);
1136 fprintf(out_file_, " type : '%s'\n", type_descriptor);
1137 fprintf(out_file_, " access : 0x%04x (%s)\n", flags, access_str);
1138 if (code == nullptr) {
1139 fprintf(out_file_, " code : (none)\n");
1140 } else {
1141 fprintf(out_file_, " code -\n");
Jeff Haoea7c6292016-11-14 18:10:16 -08001142 DumpCode(idx, code, code->GetOffset());
David Sehr7629f602016-08-07 16:01:51 -07001143 }
1144 if (options_.disassemble_) {
1145 fputc('\n', out_file_);
1146 }
1147 } else if (options_.output_format_ == kOutputXml) {
1148 const bool constructor = (name[0] == '<');
1149
1150 // Method name and prototype.
1151 if (constructor) {
1152 std::string dot(DescriptorClassToDot(back_descriptor));
1153 fprintf(out_file_, "<constructor name=\"%s\"\n", dot.c_str());
Jeff Haoc3acfc52016-08-29 14:18:26 -07001154 dot = DescriptorToDotWrapper(back_descriptor);
David Sehr7629f602016-08-07 16:01:51 -07001155 fprintf(out_file_, " type=\"%s\"\n", dot.c_str());
1156 } else {
1157 fprintf(out_file_, "<method name=\"%s\"\n", name);
1158 const char* return_type = strrchr(type_descriptor, ')');
1159 if (return_type == nullptr) {
1160 fprintf(stderr, "bad method type descriptor '%s'\n", type_descriptor);
1161 goto bail;
1162 }
Jeff Haoc3acfc52016-08-29 14:18:26 -07001163 std::string dot(DescriptorToDotWrapper(return_type + 1));
David Sehr7629f602016-08-07 16:01:51 -07001164 fprintf(out_file_, " return=\"%s\"\n", dot.c_str());
1165 fprintf(out_file_, " abstract=%s\n", QuotedBool((flags & kAccAbstract) != 0));
1166 fprintf(out_file_, " native=%s\n", QuotedBool((flags & kAccNative) != 0));
1167 fprintf(out_file_, " synchronized=%s\n", QuotedBool(
1168 (flags & (kAccSynchronized | kAccDeclaredSynchronized)) != 0));
1169 }
1170
1171 // Additional method flags.
1172 fprintf(out_file_, " static=%s\n", QuotedBool((flags & kAccStatic) != 0));
1173 fprintf(out_file_, " final=%s\n", QuotedBool((flags & kAccFinal) != 0));
1174 // The "deprecated=" not knowable w/o parsing annotations.
1175 fprintf(out_file_, " visibility=%s\n>\n", QuotedVisibility(flags));
1176
1177 // Parameters.
1178 if (type_descriptor[0] != '(') {
1179 fprintf(stderr, "ERROR: bad descriptor '%s'\n", type_descriptor);
1180 goto bail;
1181 }
1182 char* tmp_buf = reinterpret_cast<char*>(malloc(strlen(type_descriptor) + 1));
1183 const char* base = type_descriptor + 1;
1184 int arg_num = 0;
1185 while (*base != ')') {
1186 char* cp = tmp_buf;
1187 while (*base == '[') {
1188 *cp++ = *base++;
1189 }
1190 if (*base == 'L') {
1191 // Copy through ';'.
1192 do {
1193 *cp = *base++;
1194 } while (*cp++ != ';');
1195 } else {
1196 // Primitive char, copy it.
1197 if (strchr("ZBCSIFJD", *base) == nullptr) {
1198 fprintf(stderr, "ERROR: bad method signature '%s'\n", base);
1199 break; // while
1200 }
1201 *cp++ = *base++;
1202 }
1203 // Null terminate and display.
1204 *cp++ = '\0';
Jeff Haoc3acfc52016-08-29 14:18:26 -07001205 std::string dot(DescriptorToDotWrapper(tmp_buf));
David Sehr7629f602016-08-07 16:01:51 -07001206 fprintf(out_file_, "<parameter name=\"arg%d\" type=\"%s\">\n"
1207 "</parameter>\n", arg_num++, dot.c_str());
1208 } // while
1209 free(tmp_buf);
1210 if (constructor) {
1211 fprintf(out_file_, "</constructor>\n");
1212 } else {
1213 fprintf(out_file_, "</method>\n");
1214 }
1215 }
1216
1217 bail:
1218 free(type_descriptor);
1219 free(access_str);
1220}
1221
1222/*
1223 * Dumps a static (class) field.
1224 */
Jeff Haoea7c6292016-11-14 18:10:16 -08001225void DexLayout::DumpSField(uint32_t idx, uint32_t flags, int i, dex_ir::EncodedValue* init) {
David Sehr7629f602016-08-07 16:01:51 -07001226 // Bail for anything private if export only requested.
1227 if (options_.exports_only_ && (flags & (kAccPublic | kAccProtected)) == 0) {
1228 return;
1229 }
1230
Jeff Haoea7c6292016-11-14 18:10:16 -08001231 dex_ir::FieldId* field_id = header_->GetCollections().GetFieldId(idx);
David Sehr7629f602016-08-07 16:01:51 -07001232 const char* name = field_id->Name()->Data();
1233 const char* type_descriptor = field_id->Type()->GetStringId()->Data();
1234 const char* back_descriptor = field_id->Class()->GetStringId()->Data();
1235 char* access_str = CreateAccessFlagStr(flags, kAccessForField);
1236
1237 if (options_.output_format_ == kOutputPlain) {
1238 fprintf(out_file_, " #%d : (in %s)\n", i, back_descriptor);
1239 fprintf(out_file_, " name : '%s'\n", name);
1240 fprintf(out_file_, " type : '%s'\n", type_descriptor);
1241 fprintf(out_file_, " access : 0x%04x (%s)\n", flags, access_str);
1242 if (init != nullptr) {
1243 fputs(" value : ", out_file_);
1244 DumpEncodedValue(init);
1245 fputs("\n", out_file_);
1246 }
1247 } else if (options_.output_format_ == kOutputXml) {
1248 fprintf(out_file_, "<field name=\"%s\"\n", name);
Jeff Haoc3acfc52016-08-29 14:18:26 -07001249 std::string dot(DescriptorToDotWrapper(type_descriptor));
David Sehr7629f602016-08-07 16:01:51 -07001250 fprintf(out_file_, " type=\"%s\"\n", dot.c_str());
1251 fprintf(out_file_, " transient=%s\n", QuotedBool((flags & kAccTransient) != 0));
1252 fprintf(out_file_, " volatile=%s\n", QuotedBool((flags & kAccVolatile) != 0));
1253 // The "value=" is not knowable w/o parsing annotations.
1254 fprintf(out_file_, " static=%s\n", QuotedBool((flags & kAccStatic) != 0));
1255 fprintf(out_file_, " final=%s\n", QuotedBool((flags & kAccFinal) != 0));
1256 // The "deprecated=" is not knowable w/o parsing annotations.
1257 fprintf(out_file_, " visibility=%s\n", QuotedVisibility(flags));
1258 if (init != nullptr) {
1259 fputs(" value=\"", out_file_);
1260 DumpEncodedValue(init);
1261 fputs("\"\n", out_file_);
1262 }
1263 fputs(">\n</field>\n", out_file_);
1264 }
1265
1266 free(access_str);
1267}
1268
1269/*
1270 * Dumps an instance field.
1271 */
Jeff Haoea7c6292016-11-14 18:10:16 -08001272void DexLayout::DumpIField(uint32_t idx, uint32_t flags, int i) {
1273 DumpSField(idx, flags, i, nullptr);
David Sehr7629f602016-08-07 16:01:51 -07001274}
1275
1276/*
David Sehr7629f602016-08-07 16:01:51 -07001277 * Dumps the class.
1278 *
1279 * Note "idx" is a DexClassDef index, not a DexTypeId index.
1280 *
1281 * If "*last_package" is nullptr or does not match the current class' package,
1282 * the value will be replaced with a newly-allocated string.
1283 */
Jeff Haoea7c6292016-11-14 18:10:16 -08001284void DexLayout::DumpClass(int idx, char** last_package) {
1285 dex_ir::ClassDef* class_def = header_->GetCollections().GetClassDef(idx);
David Sehr7629f602016-08-07 16:01:51 -07001286 // Omitting non-public class.
1287 if (options_.exports_only_ && (class_def->GetAccessFlags() & kAccPublic) == 0) {
1288 return;
1289 }
1290
1291 if (options_.show_section_headers_) {
Jeff Haoea7c6292016-11-14 18:10:16 -08001292 DumpClassDef(idx);
David Sehr7629f602016-08-07 16:01:51 -07001293 }
1294
1295 if (options_.show_annotations_) {
Jeff Haoea7c6292016-11-14 18:10:16 -08001296 DumpClassAnnotations(idx);
David Sehr7629f602016-08-07 16:01:51 -07001297 }
1298
David Sehr7629f602016-08-07 16:01:51 -07001299 // For the XML output, show the package name. Ideally we'd gather
1300 // up the classes, sort them, and dump them alphabetically so the
1301 // package name wouldn't jump around, but that's not a great plan
1302 // for something that needs to run on the device.
Jeff Hao3ab96b42016-09-09 18:35:01 -07001303 const char* class_descriptor =
Jeff Haoea7c6292016-11-14 18:10:16 -08001304 header_->GetCollections().GetClassDef(idx)->ClassType()->GetStringId()->Data();
David Sehr7629f602016-08-07 16:01:51 -07001305 if (!(class_descriptor[0] == 'L' &&
1306 class_descriptor[strlen(class_descriptor)-1] == ';')) {
1307 // Arrays and primitives should not be defined explicitly. Keep going?
1308 fprintf(stderr, "Malformed class name '%s'\n", class_descriptor);
1309 } else if (options_.output_format_ == kOutputXml) {
1310 char* mangle = strdup(class_descriptor + 1);
1311 mangle[strlen(mangle)-1] = '\0';
1312
1313 // Reduce to just the package name.
1314 char* last_slash = strrchr(mangle, '/');
1315 if (last_slash != nullptr) {
1316 *last_slash = '\0';
1317 } else {
1318 *mangle = '\0';
1319 }
1320
1321 for (char* cp = mangle; *cp != '\0'; cp++) {
1322 if (*cp == '/') {
1323 *cp = '.';
1324 }
1325 } // for
1326
1327 if (*last_package == nullptr || strcmp(mangle, *last_package) != 0) {
1328 // Start of a new package.
1329 if (*last_package != nullptr) {
1330 fprintf(out_file_, "</package>\n");
1331 }
1332 fprintf(out_file_, "<package name=\"%s\"\n>\n", mangle);
1333 free(*last_package);
1334 *last_package = mangle;
1335 } else {
1336 free(mangle);
1337 }
1338 }
1339
1340 // General class information.
1341 char* access_str = CreateAccessFlagStr(class_def->GetAccessFlags(), kAccessForClass);
1342 const char* superclass_descriptor = nullptr;
1343 if (class_def->Superclass() != nullptr) {
1344 superclass_descriptor = class_def->Superclass()->GetStringId()->Data();
1345 }
1346 if (options_.output_format_ == kOutputPlain) {
1347 fprintf(out_file_, "Class #%d -\n", idx);
1348 fprintf(out_file_, " Class descriptor : '%s'\n", class_descriptor);
1349 fprintf(out_file_, " Access flags : 0x%04x (%s)\n",
1350 class_def->GetAccessFlags(), access_str);
1351 if (superclass_descriptor != nullptr) {
1352 fprintf(out_file_, " Superclass : '%s'\n", superclass_descriptor);
1353 }
1354 fprintf(out_file_, " Interfaces -\n");
1355 } else {
1356 std::string dot(DescriptorClassToDot(class_descriptor));
1357 fprintf(out_file_, "<class name=\"%s\"\n", dot.c_str());
1358 if (superclass_descriptor != nullptr) {
Jeff Haoc3acfc52016-08-29 14:18:26 -07001359 dot = DescriptorToDotWrapper(superclass_descriptor);
David Sehr7629f602016-08-07 16:01:51 -07001360 fprintf(out_file_, " extends=\"%s\"\n", dot.c_str());
1361 }
1362 fprintf(out_file_, " interface=%s\n",
1363 QuotedBool((class_def->GetAccessFlags() & kAccInterface) != 0));
1364 fprintf(out_file_, " abstract=%s\n",
1365 QuotedBool((class_def->GetAccessFlags() & kAccAbstract) != 0));
1366 fprintf(out_file_, " static=%s\n", QuotedBool((class_def->GetAccessFlags() & kAccStatic) != 0));
1367 fprintf(out_file_, " final=%s\n", QuotedBool((class_def->GetAccessFlags() & kAccFinal) != 0));
1368 // The "deprecated=" not knowable w/o parsing annotations.
1369 fprintf(out_file_, " visibility=%s\n", QuotedVisibility(class_def->GetAccessFlags()));
1370 fprintf(out_file_, ">\n");
1371 }
1372
1373 // Interfaces.
Jeff Haocc829592017-03-14 16:13:39 -07001374 const dex_ir::TypeList* interfaces = class_def->Interfaces();
David Sehr853a8e12016-09-01 13:03:50 -07001375 if (interfaces != nullptr) {
Jeff Haocc829592017-03-14 16:13:39 -07001376 const dex_ir::TypeIdVector* interfaces_vector = interfaces->GetTypeList();
1377 for (uint32_t i = 0; i < interfaces_vector->size(); i++) {
1378 DumpInterface((*interfaces_vector)[i], i);
David Sehr853a8e12016-09-01 13:03:50 -07001379 } // for
1380 }
David Sehr7629f602016-08-07 16:01:51 -07001381
1382 // Fields and methods.
1383 dex_ir::ClassData* class_data = class_def->GetClassData();
1384 // Prepare data for static fields.
Jeff Hao3ab96b42016-09-09 18:35:01 -07001385 dex_ir::EncodedArrayItem* static_values = class_def->StaticValues();
1386 dex_ir::EncodedValueVector* encoded_values =
1387 static_values == nullptr ? nullptr : static_values->GetEncodedValues();
1388 const uint32_t encoded_values_size = (encoded_values == nullptr) ? 0 : encoded_values->size();
David Sehr7629f602016-08-07 16:01:51 -07001389
1390 // Static fields.
1391 if (options_.output_format_ == kOutputPlain) {
1392 fprintf(out_file_, " Static fields -\n");
1393 }
David Sehr853a8e12016-09-01 13:03:50 -07001394 if (class_data != nullptr) {
1395 dex_ir::FieldItemVector* static_fields = class_data->StaticFields();
1396 if (static_fields != nullptr) {
1397 for (uint32_t i = 0; i < static_fields->size(); i++) {
Jeff Haoea7c6292016-11-14 18:10:16 -08001398 DumpSField((*static_fields)[i]->GetFieldId()->GetIndex(),
David Sehr853a8e12016-09-01 13:03:50 -07001399 (*static_fields)[i]->GetAccessFlags(),
1400 i,
Jeff Hao3ab96b42016-09-09 18:35:01 -07001401 i < encoded_values_size ? (*encoded_values)[i].get() : nullptr);
David Sehr853a8e12016-09-01 13:03:50 -07001402 } // for
1403 }
1404 }
David Sehr7629f602016-08-07 16:01:51 -07001405
1406 // Instance fields.
1407 if (options_.output_format_ == kOutputPlain) {
1408 fprintf(out_file_, " Instance fields -\n");
1409 }
David Sehr853a8e12016-09-01 13:03:50 -07001410 if (class_data != nullptr) {
1411 dex_ir::FieldItemVector* instance_fields = class_data->InstanceFields();
1412 if (instance_fields != nullptr) {
1413 for (uint32_t i = 0; i < instance_fields->size(); i++) {
Jeff Haoea7c6292016-11-14 18:10:16 -08001414 DumpIField((*instance_fields)[i]->GetFieldId()->GetIndex(),
David Sehr853a8e12016-09-01 13:03:50 -07001415 (*instance_fields)[i]->GetAccessFlags(),
1416 i);
1417 } // for
1418 }
1419 }
David Sehr7629f602016-08-07 16:01:51 -07001420
1421 // Direct methods.
1422 if (options_.output_format_ == kOutputPlain) {
1423 fprintf(out_file_, " Direct methods -\n");
1424 }
David Sehr853a8e12016-09-01 13:03:50 -07001425 if (class_data != nullptr) {
1426 dex_ir::MethodItemVector* direct_methods = class_data->DirectMethods();
1427 if (direct_methods != nullptr) {
1428 for (uint32_t i = 0; i < direct_methods->size(); i++) {
Jeff Haoea7c6292016-11-14 18:10:16 -08001429 DumpMethod((*direct_methods)[i]->GetMethodId()->GetIndex(),
David Sehr853a8e12016-09-01 13:03:50 -07001430 (*direct_methods)[i]->GetAccessFlags(),
1431 (*direct_methods)[i]->GetCodeItem(),
1432 i);
1433 } // for
1434 }
1435 }
David Sehr7629f602016-08-07 16:01:51 -07001436
1437 // Virtual methods.
1438 if (options_.output_format_ == kOutputPlain) {
1439 fprintf(out_file_, " Virtual methods -\n");
1440 }
David Sehr853a8e12016-09-01 13:03:50 -07001441 if (class_data != nullptr) {
1442 dex_ir::MethodItemVector* virtual_methods = class_data->VirtualMethods();
1443 if (virtual_methods != nullptr) {
1444 for (uint32_t i = 0; i < virtual_methods->size(); i++) {
Jeff Haoea7c6292016-11-14 18:10:16 -08001445 DumpMethod((*virtual_methods)[i]->GetMethodId()->GetIndex(),
David Sehr853a8e12016-09-01 13:03:50 -07001446 (*virtual_methods)[i]->GetAccessFlags(),
1447 (*virtual_methods)[i]->GetCodeItem(),
1448 i);
1449 } // for
1450 }
1451 }
David Sehr7629f602016-08-07 16:01:51 -07001452
1453 // End of class.
1454 if (options_.output_format_ == kOutputPlain) {
1455 const char* file_name = "unknown";
1456 if (class_def->SourceFile() != nullptr) {
1457 file_name = class_def->SourceFile()->Data();
1458 }
1459 const dex_ir::StringId* source_file = class_def->SourceFile();
1460 fprintf(out_file_, " source_file_idx : %d (%s)\n\n",
Jeff Hao3ab96b42016-09-09 18:35:01 -07001461 source_file == nullptr ? 0xffffffffU : source_file->GetIndex(), file_name);
David Sehr7629f602016-08-07 16:01:51 -07001462 } else if (options_.output_format_ == kOutputXml) {
1463 fprintf(out_file_, "</class>\n");
1464 }
1465
1466 free(access_str);
1467}
1468
Jeff Haoea7c6292016-11-14 18:10:16 -08001469void DexLayout::DumpDexFile() {
David Sehr7629f602016-08-07 16:01:51 -07001470 // Headers.
1471 if (options_.show_file_headers_) {
Jeff Haoea7c6292016-11-14 18:10:16 -08001472 DumpFileHeader();
David Sehr7629f602016-08-07 16:01:51 -07001473 }
1474
1475 // Open XML context.
1476 if (options_.output_format_ == kOutputXml) {
1477 fprintf(out_file_, "<api>\n");
1478 }
1479
1480 // Iterate over all classes.
1481 char* package = nullptr;
Jeff Haoea7c6292016-11-14 18:10:16 -08001482 const uint32_t class_defs_size = header_->GetCollections().ClassDefsSize();
David Sehr7629f602016-08-07 16:01:51 -07001483 for (uint32_t i = 0; i < class_defs_size; i++) {
Jeff Haoea7c6292016-11-14 18:10:16 -08001484 DumpClass(i, &package);
David Sehr7629f602016-08-07 16:01:51 -07001485 } // for
1486
1487 // Free the last package allocated.
1488 if (package != nullptr) {
1489 fprintf(out_file_, "</package>\n");
1490 free(package);
1491 }
1492
1493 // Close XML context.
1494 if (options_.output_format_ == kOutputXml) {
1495 fprintf(out_file_, "</api>\n");
1496 }
Jeff Haoea7c6292016-11-14 18:10:16 -08001497}
Jeff Hao3ab96b42016-09-09 18:35:01 -07001498
Jeff Haoe17f5892017-02-23 16:14:04 -08001499std::vector<dex_ir::ClassData*> DexLayout::LayoutClassDefsAndClassData(const DexFile* dex_file) {
Jeff Hao042e8982016-10-19 11:17:11 -07001500 std::vector<dex_ir::ClassDef*> new_class_def_order;
1501 for (std::unique_ptr<dex_ir::ClassDef>& class_def : header_->GetCollections().ClassDefs()) {
1502 dex::TypeIndex type_idx(class_def->ClassType()->GetIndex());
1503 if (info_->ContainsClass(*dex_file, type_idx)) {
1504 new_class_def_order.push_back(class_def.get());
1505 }
1506 }
1507 for (std::unique_ptr<dex_ir::ClassDef>& class_def : header_->GetCollections().ClassDefs()) {
1508 dex::TypeIndex type_idx(class_def->ClassType()->GetIndex());
1509 if (!info_->ContainsClass(*dex_file, type_idx)) {
1510 new_class_def_order.push_back(class_def.get());
1511 }
1512 }
1513 uint32_t class_defs_offset = header_->GetCollections().ClassDefsOffset();
1514 uint32_t class_data_offset = header_->GetCollections().ClassDatasOffset();
Jeff Haoe17f5892017-02-23 16:14:04 -08001515 std::unordered_set<dex_ir::ClassData*> visited_class_data;
1516 std::vector<dex_ir::ClassData*> new_class_data_order;
Jeff Hao042e8982016-10-19 11:17:11 -07001517 for (uint32_t i = 0; i < new_class_def_order.size(); ++i) {
1518 dex_ir::ClassDef* class_def = new_class_def_order[i];
1519 class_def->SetIndex(i);
1520 class_def->SetOffset(class_defs_offset);
1521 class_defs_offset += dex_ir::ClassDef::ItemSize();
Jeff Haoe17f5892017-02-23 16:14:04 -08001522 dex_ir::ClassData* class_data = class_def->GetClassData();
1523 if (class_data != nullptr && visited_class_data.find(class_data) == visited_class_data.end()) {
1524 class_data->SetOffset(class_data_offset);
1525 class_data_offset += class_data->GetSize();
1526 visited_class_data.insert(class_data);
1527 new_class_data_order.push_back(class_data);
Jeff Hao042e8982016-10-19 11:17:11 -07001528 }
1529 }
Jeff Haoe17f5892017-02-23 16:14:04 -08001530 return new_class_data_order;
Jeff Hao042e8982016-10-19 11:17:11 -07001531}
1532
Mathieu Chartierfa0aa092017-03-27 15:43:54 -07001533void DexLayout::LayoutStringData(const DexFile* dex_file) {
1534 const size_t num_strings = header_->GetCollections().StringIds().size();
1535 std::vector<bool> is_shorty(num_strings, false);
1536 std::vector<bool> from_hot_method(num_strings, false);
1537 for (std::unique_ptr<dex_ir::ClassDef>& class_def : header_->GetCollections().ClassDefs()) {
1538 // A name of a profile class is probably going to get looked up by ClassTable::Lookup, mark it
Jeff Haoacc83d72017-07-06 17:51:01 -07001539 // as hot. Add its super class and interfaces as well, which can be used during initialization.
Mathieu Chartierfa0aa092017-03-27 15:43:54 -07001540 const bool is_profile_class =
1541 info_->ContainsClass(*dex_file, dex::TypeIndex(class_def->ClassType()->GetIndex()));
1542 if (is_profile_class) {
1543 from_hot_method[class_def->ClassType()->GetStringId()->GetIndex()] = true;
Jeff Haoacc83d72017-07-06 17:51:01 -07001544 const dex_ir::TypeId* superclass = class_def->Superclass();
1545 if (superclass != nullptr) {
1546 from_hot_method[superclass->GetStringId()->GetIndex()] = true;
1547 }
1548 const dex_ir::TypeList* interfaces = class_def->Interfaces();
1549 if (interfaces != nullptr) {
1550 for (const dex_ir::TypeId* interface_type : *interfaces->GetTypeList()) {
1551 from_hot_method[interface_type->GetStringId()->GetIndex()] = true;
1552 }
1553 }
Mathieu Chartierfa0aa092017-03-27 15:43:54 -07001554 }
1555 dex_ir::ClassData* data = class_def->GetClassData();
1556 if (data == nullptr) {
1557 continue;
1558 }
1559 for (size_t i = 0; i < 2; ++i) {
1560 for (auto& method : *(i == 0 ? data->DirectMethods() : data->VirtualMethods())) {
1561 const dex_ir::MethodId* method_id = method->GetMethodId();
1562 dex_ir::CodeItem* code_item = method->GetCodeItem();
1563 if (code_item == nullptr) {
1564 continue;
1565 }
1566 const bool is_clinit = is_profile_class &&
1567 (method->GetAccessFlags() & kAccConstructor) != 0 &&
1568 (method->GetAccessFlags() & kAccStatic) != 0;
1569 const bool method_executed = is_clinit ||
Mathieu Chartiere46f3a82017-06-19 19:54:12 -07001570 info_->GetMethodHotness(MethodReference(dex_file, method_id->GetIndex())).IsInProfile();
Mathieu Chartierfa0aa092017-03-27 15:43:54 -07001571 if (!method_executed) {
1572 continue;
1573 }
1574 is_shorty[method_id->Proto()->Shorty()->GetIndex()] = true;
1575 dex_ir::CodeFixups* fixups = code_item->GetCodeFixups();
1576 if (fixups == nullptr) {
1577 continue;
1578 }
Jeff Haoacc83d72017-07-06 17:51:01 -07001579 // Add const-strings.
1580 for (dex_ir::StringId* id : *fixups->StringIds()) {
1581 from_hot_method[id->GetIndex()] = true;
Mathieu Chartierfa0aa092017-03-27 15:43:54 -07001582 }
Jeff Haoacc83d72017-07-06 17:51:01 -07001583 // Add field classes, names, and types.
Mathieu Chartierfa0aa092017-03-27 15:43:54 -07001584 for (dex_ir::FieldId* id : *fixups->FieldIds()) {
Jeff Haoacc83d72017-07-06 17:51:01 -07001585 // TODO: Only visit field ids from static getters and setters.
1586 from_hot_method[id->Class()->GetStringId()->GetIndex()] = true;
Mathieu Chartierfa0aa092017-03-27 15:43:54 -07001587 from_hot_method[id->Name()->GetIndex()] = true;
1588 from_hot_method[id->Type()->GetStringId()->GetIndex()] = true;
1589 }
Jeff Haoacc83d72017-07-06 17:51:01 -07001590 // For clinits, add referenced method classes, names, and protos.
1591 if (is_clinit) {
1592 for (dex_ir::MethodId* id : *fixups->MethodIds()) {
1593 from_hot_method[id->Class()->GetStringId()->GetIndex()] = true;
1594 from_hot_method[id->Name()->GetIndex()] = true;
1595 is_shorty[id->Proto()->Shorty()->GetIndex()] = true;
1596 }
1597 }
Mathieu Chartierfa0aa092017-03-27 15:43:54 -07001598 }
1599 }
1600 }
1601 // Sort string data by specified order.
1602 std::vector<dex_ir::StringId*> string_ids;
1603 size_t min_offset = std::numeric_limits<size_t>::max();
1604 size_t max_offset = 0;
1605 size_t hot_bytes = 0;
1606 for (auto& string_id : header_->GetCollections().StringIds()) {
1607 string_ids.push_back(string_id.get());
1608 const size_t cur_offset = string_id->DataItem()->GetOffset();
1609 CHECK_NE(cur_offset, 0u);
1610 min_offset = std::min(min_offset, cur_offset);
1611 dex_ir::StringData* data = string_id->DataItem();
1612 const size_t element_size = data->GetSize() + 1; // Add one extra for null.
1613 size_t end_offset = cur_offset + element_size;
1614 if (is_shorty[string_id->GetIndex()] || from_hot_method[string_id->GetIndex()]) {
1615 hot_bytes += element_size;
1616 }
1617 max_offset = std::max(max_offset, end_offset);
1618 }
1619 VLOG(compiler) << "Hot string data bytes " << hot_bytes << "/" << max_offset - min_offset;
1620 std::sort(string_ids.begin(),
1621 string_ids.end(),
1622 [&is_shorty, &from_hot_method](const dex_ir::StringId* a,
1623 const dex_ir::StringId* b) {
1624 const bool a_is_hot = from_hot_method[a->GetIndex()];
1625 const bool b_is_hot = from_hot_method[b->GetIndex()];
1626 if (a_is_hot != b_is_hot) {
1627 return a_is_hot < b_is_hot;
1628 }
1629 // After hot methods are partitioned, subpartition shorties.
1630 const bool a_is_shorty = is_shorty[a->GetIndex()];
1631 const bool b_is_shorty = is_shorty[b->GetIndex()];
1632 if (a_is_shorty != b_is_shorty) {
1633 return a_is_shorty < b_is_shorty;
1634 }
1635 // Preserve order.
1636 return a->DataItem()->GetOffset() < b->DataItem()->GetOffset();
1637 });
1638 // Now we know what order we want the string data, reorder the offsets.
1639 size_t offset = min_offset;
1640 for (dex_ir::StringId* string_id : string_ids) {
1641 dex_ir::StringData* data = string_id->DataItem();
1642 data->SetOffset(offset);
1643 offset += data->GetSize() + 1; // Add one extra for null.
1644 }
1645 if (offset > max_offset) {
1646 const uint32_t diff = offset - max_offset;
1647 // If we expanded the string data section, we need to update the offsets or else we will
1648 // corrupt the next section when writing out.
1649 FixupSections(header_->GetCollections().StringDatasOffset(), diff);
1650 // Update file size.
1651 header_->SetFileSize(header_->FileSize() + diff);
1652 }
1653}
1654
Jeff Haoe17f5892017-02-23 16:14:04 -08001655// Orders code items according to specified class data ordering.
1656// NOTE: If the section following the code items is byte aligned, the last code item is left in
1657// place to preserve alignment. Layout needs an overhaul to handle movement of other sections.
Shubham Ajmera36a282b2017-04-03 10:04:28 -07001658int32_t DexLayout::LayoutCodeItems(const DexFile* dex_file,
1659 std::vector<dex_ir::ClassData*> new_class_data_order) {
Jeff Hao863f1d72017-03-01 12:18:19 -08001660 // Do not move code items if class data section precedes code item section.
1661 // ULEB encoding is variable length, causing problems determining the offset of the code items.
1662 // TODO: We should swap the order of these sections in the future to avoid this issue.
1663 uint32_t class_data_offset = header_->GetCollections().ClassDatasOffset();
1664 uint32_t code_item_offset = header_->GetCollections().CodeItemsOffset();
1665 if (class_data_offset < code_item_offset) {
1666 return 0;
1667 }
1668
Jeff Haoe17f5892017-02-23 16:14:04 -08001669 // Find the last code item so we can leave it in place if the next section is not 4 byte aligned.
Shubham Ajmera36a282b2017-04-03 10:04:28 -07001670 dex_ir::CodeItem* last_code_item = nullptr;
Jeff Haoe17f5892017-02-23 16:14:04 -08001671 std::unordered_set<dex_ir::CodeItem*> visited_code_items;
Jeff Hao863f1d72017-03-01 12:18:19 -08001672 bool is_code_item_aligned = IsNextSectionCodeItemAligned(code_item_offset);
Jeff Haoe17f5892017-02-23 16:14:04 -08001673 if (!is_code_item_aligned) {
Jeff Haoe17f5892017-02-23 16:14:04 -08001674 for (auto& code_item_pair : header_->GetCollections().CodeItems()) {
1675 std::unique_ptr<dex_ir::CodeItem>& code_item = code_item_pair.second;
Shubham Ajmera36a282b2017-04-03 10:04:28 -07001676 if (last_code_item == nullptr
1677 || last_code_item->GetOffset() < code_item->GetOffset()) {
Jeff Haoe17f5892017-02-23 16:14:04 -08001678 last_code_item = code_item.get();
Jeff Hao042e8982016-10-19 11:17:11 -07001679 }
Jeff Haoe17f5892017-02-23 16:14:04 -08001680 }
Jeff Haoe17f5892017-02-23 16:14:04 -08001681 }
1682
Mathieu Chartier7c1be8b2017-06-15 13:56:05 -07001683 enum CodeItemState {
1684 kCodeItemStateExecStartupOnly = 0,
1685 kCodeItemStateHot,
1686 kCodeItemStateClinit,
1687 kCodeItemStateExec,
1688 kCodeItemStateNotExecuted,
1689 kCodeItemStateSize,
Shubham Ajmera36a282b2017-04-03 10:04:28 -07001690 };
1691
1692 static constexpr InvokeType invoke_types[] = {
Mathieu Chartier7c1be8b2017-06-15 13:56:05 -07001693 kDirect,
1694 kVirtual
Shubham Ajmera36a282b2017-04-03 10:04:28 -07001695 };
1696
Mathieu Chartier7c1be8b2017-06-15 13:56:05 -07001697 std::unordered_set<dex_ir::CodeItem*> code_items[kCodeItemStateSize];
Shubham Ajmera36a282b2017-04-03 10:04:28 -07001698 for (InvokeType invoke_type : invoke_types) {
1699 for (std::unique_ptr<dex_ir::ClassDef>& class_def : header_->GetCollections().ClassDefs()) {
1700 const bool is_profile_class =
1701 info_->ContainsClass(*dex_file, dex::TypeIndex(class_def->ClassType()->GetIndex()));
1702
1703 // Skip classes that are not defined in this dex file.
1704 dex_ir::ClassData* class_data = class_def->GetClassData();
1705 if (class_data == nullptr) {
1706 continue;
Jeff Haoe17f5892017-02-23 16:14:04 -08001707 }
Shubham Ajmera36a282b2017-04-03 10:04:28 -07001708 for (auto& method : *(invoke_type == InvokeType::kDirect
1709 ? class_data->DirectMethods()
1710 : class_data->VirtualMethods())) {
1711 const dex_ir::MethodId *method_id = method->GetMethodId();
1712 dex_ir::CodeItem *code_item = method->GetCodeItem();
1713 if (code_item == last_code_item || code_item == nullptr) {
1714 continue;
1715 }
1716 // Separate executed methods (clinits and profiled methods) from unexecuted methods.
Mathieu Chartier7c1be8b2017-06-15 13:56:05 -07001717 const bool is_clinit = (method->GetAccessFlags() & kAccConstructor) != 0 &&
Shubham Ajmera36a282b2017-04-03 10:04:28 -07001718 (method->GetAccessFlags() & kAccStatic) != 0;
Mathieu Chartier7c1be8b2017-06-15 13:56:05 -07001719 const bool is_startup_clinit = is_profile_class && is_clinit;
1720 using Hotness = ProfileCompilationInfo::MethodHotness;
1721 Hotness hotness = info_->GetMethodHotness(MethodReference(dex_file, method_id->GetIndex()));
1722 CodeItemState state = kCodeItemStateNotExecuted;
1723 if (hotness.IsHot()) {
1724 // Hot code is compiled, maybe one day it won't be accessed. So lay it out together for
1725 // now.
1726 state = kCodeItemStateHot;
1727 } else if (is_startup_clinit || hotness.GetFlags() == Hotness::kFlagStartup) {
1728 // Startup clinit or a method that only has the startup flag.
1729 state = kCodeItemStateExecStartupOnly;
1730 } else if (is_clinit) {
1731 state = kCodeItemStateClinit;
Mathieu Chartiere46f3a82017-06-19 19:54:12 -07001732 } else if (hotness.IsInProfile()) {
Mathieu Chartier7c1be8b2017-06-15 13:56:05 -07001733 state = kCodeItemStateExec;
Jeff Hao206cbaa2017-06-07 19:11:01 -07001734 }
Mathieu Chartier7c1be8b2017-06-15 13:56:05 -07001735 code_items[state].insert(code_item);
Jeff Hao042e8982016-10-19 11:17:11 -07001736 }
1737 }
1738 }
Shubham Ajmera36a282b2017-04-03 10:04:28 -07001739
Jeff Hao206cbaa2017-06-07 19:11:01 -07001740 // Total_diff includes diffs generated by clinits, executed, and non-executed methods.
Shubham Ajmera36a282b2017-04-03 10:04:28 -07001741 int32_t total_diff = 0;
1742 // The relative placement has no effect on correctness; it is used to ensure
1743 // the layout is deterministic
1744 for (std::unordered_set<dex_ir::CodeItem*>& code_items_set : code_items) {
Jeff Hao206cbaa2017-06-07 19:11:01 -07001745 // diff is reset for each class of code items.
Shubham Ajmera36a282b2017-04-03 10:04:28 -07001746 int32_t diff = 0;
Mathieu Chartier7c1be8b2017-06-15 13:56:05 -07001747 uint32_t start_offset = code_item_offset;
Shubham Ajmera36a282b2017-04-03 10:04:28 -07001748 for (dex_ir::ClassData* data : new_class_data_order) {
1749 data->SetOffset(data->GetOffset() + diff);
1750 for (InvokeType invoke_type : invoke_types) {
1751 for (auto &method : *(invoke_type == InvokeType::kDirect
1752 ? data->DirectMethods()
1753 : data->VirtualMethods())) {
1754 dex_ir::CodeItem* code_item = method->GetCodeItem();
1755 if (code_item != nullptr &&
1756 code_items_set.find(code_item) != code_items_set.end()) {
1757 diff += UnsignedLeb128Size(code_item_offset)
1758 - UnsignedLeb128Size(code_item->GetOffset());
1759 code_item->SetOffset(code_item_offset);
1760 code_item_offset +=
1761 RoundUp(code_item->GetSize(), kDexCodeItemAlignment);
1762 }
1763 }
1764 }
1765 }
Mathieu Chartier7c1be8b2017-06-15 13:56:05 -07001766 for (size_t i = 0; i < kCodeItemStateSize; ++i) {
1767 VLOG(dex) << "Code item layout bucket " << i << " count=" << code_items[i].size()
1768 << " bytes=" << code_item_offset - start_offset;
1769 }
Shubham Ajmera36a282b2017-04-03 10:04:28 -07001770 total_diff += diff;
1771 }
Jeff Haoe17f5892017-02-23 16:14:04 -08001772 // Adjust diff to be 4-byte aligned.
Shubham Ajmera36a282b2017-04-03 10:04:28 -07001773 return RoundUp(total_diff, kDexCodeItemAlignment);
Jeff Haoe17f5892017-02-23 16:14:04 -08001774}
Jeff Hao042e8982016-10-19 11:17:11 -07001775
Jeff Haoe17f5892017-02-23 16:14:04 -08001776bool DexLayout::IsNextSectionCodeItemAligned(uint32_t offset) {
1777 dex_ir::Collections& collections = header_->GetCollections();
1778 std::set<uint32_t> section_offsets;
1779 section_offsets.insert(collections.MapListOffset());
1780 section_offsets.insert(collections.TypeListsOffset());
1781 section_offsets.insert(collections.AnnotationSetRefListsOffset());
1782 section_offsets.insert(collections.AnnotationSetItemsOffset());
1783 section_offsets.insert(collections.ClassDatasOffset());
1784 section_offsets.insert(collections.CodeItemsOffset());
1785 section_offsets.insert(collections.StringDatasOffset());
1786 section_offsets.insert(collections.DebugInfoItemsOffset());
1787 section_offsets.insert(collections.AnnotationItemsOffset());
1788 section_offsets.insert(collections.EncodedArrayItemsOffset());
1789 section_offsets.insert(collections.AnnotationsDirectoryItemsOffset());
1790
1791 auto found = section_offsets.find(offset);
1792 if (found != section_offsets.end()) {
1793 found++;
1794 if (found != section_offsets.end()) {
1795 return *found % kDexCodeItemAlignment == 0;
1796 }
1797 }
1798 return false;
Jeff Hao042e8982016-10-19 11:17:11 -07001799}
1800
1801// Adjust offsets of every item in the specified section by diff bytes.
1802template<class T> void DexLayout::FixupSection(std::map<uint32_t, std::unique_ptr<T>>& map,
1803 uint32_t diff) {
1804 for (auto& pair : map) {
1805 std::unique_ptr<T>& item = pair.second;
1806 item->SetOffset(item->GetOffset() + diff);
1807 }
1808}
1809
1810// Adjust offsets of all sections with an address after the specified offset by diff bytes.
1811void DexLayout::FixupSections(uint32_t offset, uint32_t diff) {
1812 dex_ir::Collections& collections = header_->GetCollections();
1813 uint32_t map_list_offset = collections.MapListOffset();
1814 if (map_list_offset > offset) {
1815 collections.SetMapListOffset(map_list_offset + diff);
1816 }
1817
1818 uint32_t type_lists_offset = collections.TypeListsOffset();
1819 if (type_lists_offset > offset) {
1820 collections.SetTypeListsOffset(type_lists_offset + diff);
1821 FixupSection(collections.TypeLists(), diff);
1822 }
1823
1824 uint32_t annotation_set_ref_lists_offset = collections.AnnotationSetRefListsOffset();
1825 if (annotation_set_ref_lists_offset > offset) {
1826 collections.SetAnnotationSetRefListsOffset(annotation_set_ref_lists_offset + diff);
1827 FixupSection(collections.AnnotationSetRefLists(), diff);
1828 }
1829
1830 uint32_t annotation_set_items_offset = collections.AnnotationSetItemsOffset();
1831 if (annotation_set_items_offset > offset) {
1832 collections.SetAnnotationSetItemsOffset(annotation_set_items_offset + diff);
1833 FixupSection(collections.AnnotationSetItems(), diff);
1834 }
1835
1836 uint32_t class_datas_offset = collections.ClassDatasOffset();
1837 if (class_datas_offset > offset) {
1838 collections.SetClassDatasOffset(class_datas_offset + diff);
1839 FixupSection(collections.ClassDatas(), diff);
1840 }
1841
1842 uint32_t code_items_offset = collections.CodeItemsOffset();
1843 if (code_items_offset > offset) {
1844 collections.SetCodeItemsOffset(code_items_offset + diff);
1845 FixupSection(collections.CodeItems(), diff);
1846 }
1847
1848 uint32_t string_datas_offset = collections.StringDatasOffset();
1849 if (string_datas_offset > offset) {
1850 collections.SetStringDatasOffset(string_datas_offset + diff);
1851 FixupSection(collections.StringDatas(), diff);
1852 }
1853
1854 uint32_t debug_info_items_offset = collections.DebugInfoItemsOffset();
1855 if (debug_info_items_offset > offset) {
1856 collections.SetDebugInfoItemsOffset(debug_info_items_offset + diff);
1857 FixupSection(collections.DebugInfoItems(), diff);
1858 }
1859
1860 uint32_t annotation_items_offset = collections.AnnotationItemsOffset();
1861 if (annotation_items_offset > offset) {
1862 collections.SetAnnotationItemsOffset(annotation_items_offset + diff);
1863 FixupSection(collections.AnnotationItems(), diff);
1864 }
1865
1866 uint32_t encoded_array_items_offset = collections.EncodedArrayItemsOffset();
1867 if (encoded_array_items_offset > offset) {
1868 collections.SetEncodedArrayItemsOffset(encoded_array_items_offset + diff);
1869 FixupSection(collections.EncodedArrayItems(), diff);
1870 }
1871
1872 uint32_t annotations_directory_items_offset = collections.AnnotationsDirectoryItemsOffset();
1873 if (annotations_directory_items_offset > offset) {
1874 collections.SetAnnotationsDirectoryItemsOffset(annotations_directory_items_offset + diff);
1875 FixupSection(collections.AnnotationsDirectoryItems(), diff);
1876 }
1877}
1878
1879void DexLayout::LayoutOutputFile(const DexFile* dex_file) {
Mathieu Chartierfa0aa092017-03-27 15:43:54 -07001880 LayoutStringData(dex_file);
Jeff Haoe17f5892017-02-23 16:14:04 -08001881 std::vector<dex_ir::ClassData*> new_class_data_order = LayoutClassDefsAndClassData(dex_file);
Shubham Ajmera36a282b2017-04-03 10:04:28 -07001882 int32_t diff = LayoutCodeItems(dex_file, new_class_data_order);
Jeff Hao042e8982016-10-19 11:17:11 -07001883 // Move sections after ClassData by diff bytes.
1884 FixupSections(header_->GetCollections().ClassDatasOffset(), diff);
1885 // Update file size.
1886 header_->SetFileSize(header_->FileSize() + diff);
1887}
1888
Jeff Haoec7f1a92017-03-13 16:24:24 -07001889void DexLayout::OutputDexFile(const DexFile* dex_file) {
1890 const std::string& dex_file_location = dex_file->GetLocation();
Jeff Haoea7c6292016-11-14 18:10:16 -08001891 std::string error_msg;
1892 std::unique_ptr<File> new_file;
1893 if (!options_.output_to_memmap_) {
Jeff Haoa8621002016-10-04 18:13:44 +00001894 std::string output_location(options_.output_dex_directory_);
Andreas Gampe37c58462017-03-27 15:14:27 -07001895 size_t last_slash = dex_file_location.rfind('/');
Jeff Haoea7c6292016-11-14 18:10:16 -08001896 std::string dex_file_directory = dex_file_location.substr(0, last_slash + 1);
1897 if (output_location == dex_file_directory) {
1898 output_location = dex_file_location + ".new";
1899 } else if (last_slash != std::string::npos) {
1900 output_location += dex_file_location.substr(last_slash);
1901 } else {
1902 output_location += "/" + dex_file_location + ".new";
1903 }
1904 new_file.reset(OS::CreateEmptyFile(output_location.c_str()));
Jeff Hao3ba51e82017-04-12 16:14:54 -07001905 if (new_file == nullptr) {
1906 LOG(ERROR) << "Could not create dex writer output file: " << output_location;
1907 return;
1908 }
David Sehr7639cdc2017-04-15 10:06:21 -07001909 if (ftruncate(new_file->Fd(), header_->FileSize()) != 0) {
1910 LOG(ERROR) << "Could not grow dex writer output file: " << output_location;;
1911 new_file->Erase();
1912 return;
1913 }
Jeff Haoea7c6292016-11-14 18:10:16 -08001914 mem_map_.reset(MemMap::MapFile(header_->FileSize(), PROT_READ | PROT_WRITE, MAP_SHARED,
1915 new_file->Fd(), 0, /*low_4gb*/ false, output_location.c_str(), &error_msg));
1916 } else {
1917 mem_map_.reset(MemMap::MapAnonymous("layout dex", nullptr, header_->FileSize(),
1918 PROT_READ | PROT_WRITE, /* low_4gb */ false, /* reuse */ false, &error_msg));
1919 }
1920 if (mem_map_ == nullptr) {
1921 LOG(ERROR) << "Could not create mem map for dex writer output: " << error_msg;
Jeff Hao3ba51e82017-04-12 16:14:54 -07001922 if (new_file != nullptr) {
Jeff Haoea7c6292016-11-14 18:10:16 -08001923 new_file->Erase();
1924 }
1925 return;
1926 }
1927 DexWriter::Output(header_, mem_map_.get());
1928 if (new_file != nullptr) {
1929 UNUSED(new_file->FlushCloseOrErase());
1930 }
Jeff Haoec7f1a92017-03-13 16:24:24 -07001931 // Verify the output dex file's structure for debug builds.
Jeff Hao4a436ac2017-03-10 17:05:01 -08001932 if (kIsDebugBuild) {
1933 std::string location = "memory mapped file for " + dex_file_location;
Jeff Haoec7f1a92017-03-13 16:24:24 -07001934 std::unique_ptr<const DexFile> output_dex_file(DexFile::Open(mem_map_->Begin(),
1935 mem_map_->Size(),
1936 location,
1937 header_->Checksum(),
1938 /*oat_dex_file*/ nullptr,
1939 /*verify*/ true,
1940 /*verify_checksum*/ false,
1941 &error_msg));
1942 DCHECK(output_dex_file != nullptr) << "Failed to re-open output file:" << error_msg;
1943 }
1944 // Do IR-level comparison between input and output. This check ignores potential differences
1945 // due to layout, so offsets are not checked. Instead, it checks the data contents of each item.
Jeff Haoa07394a2017-05-17 10:29:56 -07001946 if (kIsDebugBuild || options_.verify_output_) {
Jeff Haoec7f1a92017-03-13 16:24:24 -07001947 std::unique_ptr<dex_ir::Header> orig_header(dex_ir::DexIrBuilder(*dex_file));
1948 CHECK(VerifyOutputDexFile(orig_header.get(), header_, &error_msg)) << error_msg;
Jeff Hao4a436ac2017-03-10 17:05:01 -08001949 }
Jeff Haoea7c6292016-11-14 18:10:16 -08001950}
1951
1952/*
1953 * Dumps the requested sections of the file.
1954 */
1955void DexLayout::ProcessDexFile(const char* file_name,
1956 const DexFile* dex_file,
1957 size_t dex_file_index) {
1958 std::unique_ptr<dex_ir::Header> header(dex_ir::DexIrBuilder(*dex_file));
1959 SetHeader(header.get());
1960
1961 if (options_.verbose_) {
1962 fprintf(out_file_, "Opened '%s', DEX version '%.3s'\n",
1963 file_name, dex_file->GetHeader().magic_ + 4);
1964 }
1965
1966 if (options_.visualize_pattern_) {
1967 VisualizeDexLayout(header_, dex_file, dex_file_index, info_);
1968 return;
1969 }
1970
David Sehr93357492017-03-09 08:02:44 -08001971 if (options_.show_section_statistics_) {
1972 ShowDexSectionStatistics(header_, dex_file_index);
1973 return;
1974 }
1975
Jeff Haoea7c6292016-11-14 18:10:16 -08001976 // Dump dex file.
1977 if (options_.dump_) {
1978 DumpDexFile();
1979 }
1980
1981 // Output dex file as file or memmap.
1982 if (options_.output_dex_directory_ != nullptr || options_.output_to_memmap_) {
Jeff Hao042e8982016-10-19 11:17:11 -07001983 if (info_ != nullptr) {
1984 LayoutOutputFile(dex_file);
1985 }
Jeff Haoec7f1a92017-03-13 16:24:24 -07001986 OutputDexFile(dex_file);
Jeff Hao3ab96b42016-09-09 18:35:01 -07001987 }
David Sehr7629f602016-08-07 16:01:51 -07001988}
1989
1990/*
1991 * Processes a single file (either direct .dex or indirect .zip/.jar/.apk).
1992 */
Jeff Haoea7c6292016-11-14 18:10:16 -08001993int DexLayout::ProcessFile(const char* file_name) {
David Sehr7629f602016-08-07 16:01:51 -07001994 if (options_.verbose_) {
1995 fprintf(out_file_, "Processing '%s'...\n", file_name);
1996 }
1997
1998 // If the file is not a .dex file, the function tries .zip/.jar/.apk files,
1999 // all of which are Zip archives with "classes.dex" inside.
2000 const bool verify_checksum = !options_.ignore_bad_checksum_;
2001 std::string error_msg;
2002 std::vector<std::unique_ptr<const DexFile>> dex_files;
2003 if (!DexFile::Open(file_name, file_name, verify_checksum, &error_msg, &dex_files)) {
2004 // Display returned error message to user. Note that this error behavior
2005 // differs from the error messages shown by the original Dalvik dexdump.
2006 fputs(error_msg.c_str(), stderr);
2007 fputc('\n', stderr);
2008 return -1;
2009 }
2010
2011 // Success. Either report checksum verification or process
2012 // all dex files found in given file.
2013 if (options_.checksum_only_) {
2014 fprintf(out_file_, "Checksum verified\n");
2015 } else {
2016 for (size_t i = 0; i < dex_files.size(); i++) {
David Sehrcdcfde72016-09-26 07:44:04 -07002017 ProcessDexFile(file_name, dex_files[i].get(), i);
David Sehr7629f602016-08-07 16:01:51 -07002018 }
2019 }
2020 return 0;
2021}
2022
2023} // namespace art