blob: dd2e809a9269bfd7c489a7d749fbda8a20bc6b87 [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"
Mathieu Chartier120aa282017-08-05 16:03:03 -070037#include "dex_file_layout.h"
Mathieu Chartier79c87da2017-10-10 11:54:29 -070038#include "dex_file_loader.h"
Andreas Gampee2abbc62017-09-15 11:59:26 -070039#include "dex_file_types.h"
Jeff Haob7568152017-03-09 18:14:48 -080040#include "dex_file_verifier.h"
David Sehr7629f602016-08-07 16:01:51 -070041#include "dex_instruction-inl.h"
Andreas Gampe8cf9cb32017-07-19 09:28:38 -070042#include "dex_ir_builder.h"
Jeff Haoec7f1a92017-03-13 16:24:24 -070043#include "dex_verify.h"
David Sehrcdcfde72016-09-26 07:44:04 -070044#include "dex_visualize.h"
Jeff Haoa8621002016-10-04 18:13:44 +000045#include "dex_writer.h"
Calin Juravle33083d62017-01-18 15:29:12 -080046#include "jit/profile_compilation_info.h"
Jeff Haoea7c6292016-11-14 18:10:16 -080047#include "mem_map.h"
Nicolas Geoffrayfd1a6c22016-10-04 11:01:17 +000048#include "os.h"
David Sehr7629f602016-08-07 16:01:51 -070049#include "utils.h"
50
51namespace art {
52
Andreas Gampe46ee31b2016-12-14 10:11:49 -080053using android::base::StringPrintf;
54
Mathieu Chartier24066ec2017-10-21 16:01:08 -070055// Setting this to false disables class def layout entirely, which is stronger than strictly
56// necessary to ensure the partial order w.r.t. class derivation. TODO: Re-enable (b/68317550).
57static constexpr bool kChangeClassDefOrder = false;
58
59static constexpr uint32_t kDataSectionAlignment = sizeof(uint32_t) * 2;
Jeff Haoe17f5892017-02-23 16:14:04 -080060static constexpr uint32_t kDexCodeItemAlignment = 4;
61
David Sehr7629f602016-08-07 16:01:51 -070062/*
David Sehr7629f602016-08-07 16:01:51 -070063 * Flags for use with createAccessFlagStr().
64 */
65enum AccessFor {
66 kAccessForClass = 0, kAccessForMethod = 1, kAccessForField = 2, kAccessForMAX
67};
68const int kNumFlags = 18;
69
70/*
71 * Gets 2 little-endian bytes.
72 */
73static inline uint16_t Get2LE(unsigned char const* src) {
74 return src[0] | (src[1] << 8);
75}
76
77/*
Jeff Haoc3acfc52016-08-29 14:18:26 -070078 * Converts a type descriptor to human-readable "dotted" form. For
79 * example, "Ljava/lang/String;" becomes "java.lang.String", and
80 * "[I" becomes "int[]". Also converts '$' to '.', which means this
81 * form can't be converted back to a descriptor.
82 */
83static std::string DescriptorToDotWrapper(const char* descriptor) {
84 std::string result = DescriptorToDot(descriptor);
85 size_t found = result.find('$');
86 while (found != std::string::npos) {
87 result[found] = '.';
88 found = result.find('$', found);
89 }
90 return result;
91}
92
93/*
David Sehr7629f602016-08-07 16:01:51 -070094 * Converts the class name portion of a type descriptor to human-readable
95 * "dotted" form. For example, "Ljava/lang/String;" becomes "String".
96 */
97static std::string DescriptorClassToDot(const char* str) {
98 std::string descriptor(str);
99 // Reduce to just the class name prefix.
100 size_t last_slash = descriptor.rfind('/');
101 if (last_slash == std::string::npos) {
102 last_slash = 0;
103 }
104 // Start past the '/' or 'L'.
105 last_slash++;
106
107 // Copy class name over, trimming trailing ';'.
108 size_t size = descriptor.size() - 1 - last_slash;
109 std::string result(descriptor.substr(last_slash, size));
110
111 // Replace '$' with '.'.
112 size_t dollar_sign = result.find('$');
113 while (dollar_sign != std::string::npos) {
114 result[dollar_sign] = '.';
115 dollar_sign = result.find('$', dollar_sign);
116 }
117
118 return result;
119}
120
121/*
122 * Returns string representing the boolean value.
123 */
124static const char* StrBool(bool val) {
125 return val ? "true" : "false";
126}
127
128/*
129 * Returns a quoted string representing the boolean value.
130 */
131static const char* QuotedBool(bool val) {
132 return val ? "\"true\"" : "\"false\"";
133}
134
135/*
136 * Returns a quoted string representing the access flags.
137 */
138static const char* QuotedVisibility(uint32_t access_flags) {
139 if (access_flags & kAccPublic) {
140 return "\"public\"";
141 } else if (access_flags & kAccProtected) {
142 return "\"protected\"";
143 } else if (access_flags & kAccPrivate) {
144 return "\"private\"";
145 } else {
146 return "\"package\"";
147 }
148}
149
150/*
151 * Counts the number of '1' bits in a word.
152 */
153static int CountOnes(uint32_t val) {
154 val = val - ((val >> 1) & 0x55555555);
155 val = (val & 0x33333333) + ((val >> 2) & 0x33333333);
156 return (((val + (val >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24;
157}
158
159/*
160 * Creates a new string with human-readable access flags.
161 *
162 * In the base language the access_flags fields are type uint16_t; in Dalvik they're uint32_t.
163 */
164static char* CreateAccessFlagStr(uint32_t flags, AccessFor for_what) {
165 static const char* kAccessStrings[kAccessForMAX][kNumFlags] = {
166 {
167 "PUBLIC", /* 0x00001 */
168 "PRIVATE", /* 0x00002 */
169 "PROTECTED", /* 0x00004 */
170 "STATIC", /* 0x00008 */
171 "FINAL", /* 0x00010 */
172 "?", /* 0x00020 */
173 "?", /* 0x00040 */
174 "?", /* 0x00080 */
175 "?", /* 0x00100 */
176 "INTERFACE", /* 0x00200 */
177 "ABSTRACT", /* 0x00400 */
178 "?", /* 0x00800 */
179 "SYNTHETIC", /* 0x01000 */
180 "ANNOTATION", /* 0x02000 */
181 "ENUM", /* 0x04000 */
182 "?", /* 0x08000 */
183 "VERIFIED", /* 0x10000 */
184 "OPTIMIZED", /* 0x20000 */
185 }, {
186 "PUBLIC", /* 0x00001 */
187 "PRIVATE", /* 0x00002 */
188 "PROTECTED", /* 0x00004 */
189 "STATIC", /* 0x00008 */
190 "FINAL", /* 0x00010 */
191 "SYNCHRONIZED", /* 0x00020 */
192 "BRIDGE", /* 0x00040 */
193 "VARARGS", /* 0x00080 */
194 "NATIVE", /* 0x00100 */
195 "?", /* 0x00200 */
196 "ABSTRACT", /* 0x00400 */
197 "STRICT", /* 0x00800 */
198 "SYNTHETIC", /* 0x01000 */
199 "?", /* 0x02000 */
200 "?", /* 0x04000 */
201 "MIRANDA", /* 0x08000 */
202 "CONSTRUCTOR", /* 0x10000 */
203 "DECLARED_SYNCHRONIZED", /* 0x20000 */
204 }, {
205 "PUBLIC", /* 0x00001 */
206 "PRIVATE", /* 0x00002 */
207 "PROTECTED", /* 0x00004 */
208 "STATIC", /* 0x00008 */
209 "FINAL", /* 0x00010 */
210 "?", /* 0x00020 */
211 "VOLATILE", /* 0x00040 */
212 "TRANSIENT", /* 0x00080 */
213 "?", /* 0x00100 */
214 "?", /* 0x00200 */
215 "?", /* 0x00400 */
216 "?", /* 0x00800 */
217 "SYNTHETIC", /* 0x01000 */
218 "?", /* 0x02000 */
219 "ENUM", /* 0x04000 */
220 "?", /* 0x08000 */
221 "?", /* 0x10000 */
222 "?", /* 0x20000 */
223 },
224 };
225
226 // Allocate enough storage to hold the expected number of strings,
227 // plus a space between each. We over-allocate, using the longest
228 // string above as the base metric.
229 const int kLongest = 21; // The strlen of longest string above.
230 const int count = CountOnes(flags);
231 char* str;
232 char* cp;
233 cp = str = reinterpret_cast<char*>(malloc(count * (kLongest + 1) + 1));
234
235 for (int i = 0; i < kNumFlags; i++) {
236 if (flags & 0x01) {
237 const char* accessStr = kAccessStrings[for_what][i];
238 const int len = strlen(accessStr);
239 if (cp != str) {
240 *cp++ = ' ';
241 }
242 memcpy(cp, accessStr, len);
243 cp += len;
244 }
245 flags >>= 1;
246 } // for
247
248 *cp = '\0';
249 return str;
250}
251
252static std::string GetSignatureForProtoId(const dex_ir::ProtoId* proto) {
253 if (proto == nullptr) {
254 return "<no signature>";
255 }
256
David Sehr7629f602016-08-07 16:01:51 -0700257 std::string result("(");
Jeff Haoa8621002016-10-04 18:13:44 +0000258 const dex_ir::TypeList* type_list = proto->Parameters();
259 if (type_list != nullptr) {
260 for (const dex_ir::TypeId* type_id : *type_list->GetTypeList()) {
261 result += type_id->GetStringId()->Data();
262 }
David Sehr7629f602016-08-07 16:01:51 -0700263 }
264 result += ")";
265 result += proto->ReturnType()->GetStringId()->Data();
266 return result;
267}
268
269/*
270 * Copies character data from "data" to "out", converting non-ASCII values
271 * to fprintf format chars or an ASCII filler ('.' or '?').
272 *
273 * The output buffer must be able to hold (2*len)+1 bytes. The result is
274 * NULL-terminated.
275 */
276static void Asciify(char* out, const unsigned char* data, size_t len) {
277 while (len--) {
278 if (*data < 0x20) {
279 // Could do more here, but we don't need them yet.
280 switch (*data) {
281 case '\0':
282 *out++ = '\\';
283 *out++ = '0';
284 break;
285 case '\n':
286 *out++ = '\\';
287 *out++ = 'n';
288 break;
289 default:
290 *out++ = '.';
291 break;
292 } // switch
293 } else if (*data >= 0x80) {
294 *out++ = '?';
295 } else {
296 *out++ = *data;
297 }
298 data++;
299 } // while
300 *out = '\0';
301}
302
303/*
304 * Dumps a string value with some escape characters.
305 */
Jeff Haoea7c6292016-11-14 18:10:16 -0800306static void DumpEscapedString(const char* p, FILE* out_file) {
307 fputs("\"", out_file);
David Sehr7629f602016-08-07 16:01:51 -0700308 for (; *p; p++) {
309 switch (*p) {
310 case '\\':
Jeff Haoea7c6292016-11-14 18:10:16 -0800311 fputs("\\\\", out_file);
David Sehr7629f602016-08-07 16:01:51 -0700312 break;
313 case '\"':
Jeff Haoea7c6292016-11-14 18:10:16 -0800314 fputs("\\\"", out_file);
David Sehr7629f602016-08-07 16:01:51 -0700315 break;
316 case '\t':
Jeff Haoea7c6292016-11-14 18:10:16 -0800317 fputs("\\t", out_file);
David Sehr7629f602016-08-07 16:01:51 -0700318 break;
319 case '\n':
Jeff Haoea7c6292016-11-14 18:10:16 -0800320 fputs("\\n", out_file);
David Sehr7629f602016-08-07 16:01:51 -0700321 break;
322 case '\r':
Jeff Haoea7c6292016-11-14 18:10:16 -0800323 fputs("\\r", out_file);
David Sehr7629f602016-08-07 16:01:51 -0700324 break;
325 default:
Jeff Haoea7c6292016-11-14 18:10:16 -0800326 putc(*p, out_file);
David Sehr7629f602016-08-07 16:01:51 -0700327 } // switch
328 } // for
Jeff Haoea7c6292016-11-14 18:10:16 -0800329 fputs("\"", out_file);
David Sehr7629f602016-08-07 16:01:51 -0700330}
331
332/*
333 * Dumps a string as an XML attribute value.
334 */
Jeff Haoea7c6292016-11-14 18:10:16 -0800335static void DumpXmlAttribute(const char* p, FILE* out_file) {
David Sehr7629f602016-08-07 16:01:51 -0700336 for (; *p; p++) {
337 switch (*p) {
338 case '&':
Jeff Haoea7c6292016-11-14 18:10:16 -0800339 fputs("&amp;", out_file);
David Sehr7629f602016-08-07 16:01:51 -0700340 break;
341 case '<':
Jeff Haoea7c6292016-11-14 18:10:16 -0800342 fputs("&lt;", out_file);
David Sehr7629f602016-08-07 16:01:51 -0700343 break;
344 case '>':
Jeff Haoea7c6292016-11-14 18:10:16 -0800345 fputs("&gt;", out_file);
David Sehr7629f602016-08-07 16:01:51 -0700346 break;
347 case '"':
Jeff Haoea7c6292016-11-14 18:10:16 -0800348 fputs("&quot;", out_file);
David Sehr7629f602016-08-07 16:01:51 -0700349 break;
350 case '\t':
Jeff Haoea7c6292016-11-14 18:10:16 -0800351 fputs("&#x9;", out_file);
David Sehr7629f602016-08-07 16:01:51 -0700352 break;
353 case '\n':
Jeff Haoea7c6292016-11-14 18:10:16 -0800354 fputs("&#xA;", out_file);
David Sehr7629f602016-08-07 16:01:51 -0700355 break;
356 case '\r':
Jeff Haoea7c6292016-11-14 18:10:16 -0800357 fputs("&#xD;", out_file);
David Sehr7629f602016-08-07 16:01:51 -0700358 break;
359 default:
Jeff Haoea7c6292016-11-14 18:10:16 -0800360 putc(*p, out_file);
David Sehr7629f602016-08-07 16:01:51 -0700361 } // switch
362 } // for
363}
364
David Sehr7629f602016-08-07 16:01:51 -0700365/*
366 * Helper for dumpInstruction(), which builds the string
367 * representation for the index in the given instruction.
368 * Returns a pointer to a buffer of sufficient size.
369 */
370static std::unique_ptr<char[]> IndexString(dex_ir::Header* header,
371 const Instruction* dec_insn,
372 size_t buf_size) {
373 std::unique_ptr<char[]> buf(new char[buf_size]);
374 // Determine index and width of the string.
375 uint32_t index = 0;
Andreas Gampee2abbc62017-09-15 11:59:26 -0700376 uint32_t secondary_index = dex::kDexNoIndex;
David Sehr7629f602016-08-07 16:01:51 -0700377 uint32_t width = 4;
378 switch (Instruction::FormatOf(dec_insn->Opcode())) {
379 // SOME NOT SUPPORTED:
380 // case Instruction::k20bc:
381 case Instruction::k21c:
382 case Instruction::k35c:
383 // case Instruction::k35ms:
384 case Instruction::k3rc:
385 // case Instruction::k3rms:
386 // case Instruction::k35mi:
387 // case Instruction::k3rmi:
388 index = dec_insn->VRegB();
389 width = 4;
390 break;
391 case Instruction::k31c:
392 index = dec_insn->VRegB();
393 width = 8;
394 break;
395 case Instruction::k22c:
396 // case Instruction::k22cs:
397 index = dec_insn->VRegC();
398 width = 4;
399 break;
Orion Hodsonb34bb192016-10-18 17:02:58 +0100400 case Instruction::k45cc:
401 case Instruction::k4rcc:
402 index = dec_insn->VRegB();
403 secondary_index = dec_insn->VRegH();
404 width = 4;
David Sehr7639cdc2017-04-15 10:06:21 -0700405 break;
David Sehr7629f602016-08-07 16:01:51 -0700406 default:
407 break;
408 } // switch
409
410 // Determine index type.
411 size_t outSize = 0;
412 switch (Instruction::IndexTypeOf(dec_insn->Opcode())) {
413 case Instruction::kIndexUnknown:
414 // This function should never get called for this type, but do
415 // something sensible here, just to help with debugging.
416 outSize = snprintf(buf.get(), buf_size, "<unknown-index>");
417 break;
418 case Instruction::kIndexNone:
419 // This function should never get called for this type, but do
420 // something sensible here, just to help with debugging.
421 outSize = snprintf(buf.get(), buf_size, "<no-index>");
422 break;
423 case Instruction::kIndexTypeRef:
Jeff Hao3ab96b42016-09-09 18:35:01 -0700424 if (index < header->GetCollections().TypeIdsSize()) {
425 const char* tp = header->GetCollections().GetTypeId(index)->GetStringId()->Data();
David Sehr7629f602016-08-07 16:01:51 -0700426 outSize = snprintf(buf.get(), buf_size, "%s // type@%0*x", tp, width, index);
427 } else {
428 outSize = snprintf(buf.get(), buf_size, "<type?> // type@%0*x", width, index);
429 }
430 break;
431 case Instruction::kIndexStringRef:
Jeff Hao3ab96b42016-09-09 18:35:01 -0700432 if (index < header->GetCollections().StringIdsSize()) {
433 const char* st = header->GetCollections().GetStringId(index)->Data();
David Sehr7629f602016-08-07 16:01:51 -0700434 outSize = snprintf(buf.get(), buf_size, "\"%s\" // string@%0*x", st, width, index);
435 } else {
436 outSize = snprintf(buf.get(), buf_size, "<string?> // string@%0*x", width, index);
437 }
438 break;
439 case Instruction::kIndexMethodRef:
Jeff Hao3ab96b42016-09-09 18:35:01 -0700440 if (index < header->GetCollections().MethodIdsSize()) {
441 dex_ir::MethodId* method_id = header->GetCollections().GetMethodId(index);
David Sehr7629f602016-08-07 16:01:51 -0700442 const char* name = method_id->Name()->Data();
David Sehr72359222016-09-07 13:04:01 -0700443 std::string type_descriptor = GetSignatureForProtoId(method_id->Proto());
David Sehr7629f602016-08-07 16:01:51 -0700444 const char* back_descriptor = method_id->Class()->GetStringId()->Data();
445 outSize = snprintf(buf.get(), buf_size, "%s.%s:%s // method@%0*x",
David Sehr72359222016-09-07 13:04:01 -0700446 back_descriptor, name, type_descriptor.c_str(), width, index);
David Sehr7629f602016-08-07 16:01:51 -0700447 } else {
448 outSize = snprintf(buf.get(), buf_size, "<method?> // method@%0*x", width, index);
449 }
450 break;
451 case Instruction::kIndexFieldRef:
Jeff Hao3ab96b42016-09-09 18:35:01 -0700452 if (index < header->GetCollections().FieldIdsSize()) {
453 dex_ir::FieldId* field_id = header->GetCollections().GetFieldId(index);
David Sehr7629f602016-08-07 16:01:51 -0700454 const char* name = field_id->Name()->Data();
455 const char* type_descriptor = field_id->Type()->GetStringId()->Data();
456 const char* back_descriptor = field_id->Class()->GetStringId()->Data();
457 outSize = snprintf(buf.get(), buf_size, "%s.%s:%s // field@%0*x",
458 back_descriptor, name, type_descriptor, width, index);
459 } else {
460 outSize = snprintf(buf.get(), buf_size, "<field?> // field@%0*x", width, index);
461 }
462 break;
463 case Instruction::kIndexVtableOffset:
464 outSize = snprintf(buf.get(), buf_size, "[%0*x] // vtable #%0*x",
465 width, index, width, index);
466 break;
467 case Instruction::kIndexFieldOffset:
468 outSize = snprintf(buf.get(), buf_size, "[obj+%0*x]", width, index);
469 break;
Orion Hodsonb34bb192016-10-18 17:02:58 +0100470 case Instruction::kIndexMethodAndProtoRef: {
471 std::string method("<method?>");
472 std::string proto("<proto?>");
473 if (index < header->GetCollections().MethodIdsSize()) {
474 dex_ir::MethodId* method_id = header->GetCollections().GetMethodId(index);
475 const char* name = method_id->Name()->Data();
476 std::string type_descriptor = GetSignatureForProtoId(method_id->Proto());
477 const char* back_descriptor = method_id->Class()->GetStringId()->Data();
478 method = StringPrintf("%s.%s:%s", back_descriptor, name, type_descriptor.c_str());
479 }
480 if (secondary_index < header->GetCollections().ProtoIdsSize()) {
481 dex_ir::ProtoId* proto_id = header->GetCollections().GetProtoId(secondary_index);
482 proto = GetSignatureForProtoId(proto_id);
483 }
484 outSize = snprintf(buf.get(), buf_size, "%s, %s // method@%0*x, proto@%0*x",
485 method.c_str(), proto.c_str(), width, index, width, secondary_index);
Jeff Haoea7c6292016-11-14 18:10:16 -0800486 }
487 break;
488 // SOME NOT SUPPORTED:
489 // case Instruction::kIndexVaries:
490 // case Instruction::kIndexInlineMethod:
David Sehr7629f602016-08-07 16:01:51 -0700491 default:
492 outSize = snprintf(buf.get(), buf_size, "<?>");
493 break;
494 } // switch
495
496 // Determine success of string construction.
497 if (outSize >= buf_size) {
498 // The buffer wasn't big enough; retry with computed size. Note: snprintf()
499 // doesn't count/ the '\0' as part of its returned size, so we add explicit
500 // space for it here.
501 return IndexString(header, dec_insn, outSize + 1);
502 }
503 return buf;
504}
505
506/*
Jeff Haoea7c6292016-11-14 18:10:16 -0800507 * Dumps encoded annotation.
508 */
509void DexLayout::DumpEncodedAnnotation(dex_ir::EncodedAnnotation* annotation) {
510 fputs(annotation->GetType()->GetStringId()->Data(), out_file_);
511 // Display all name=value pairs.
512 for (auto& subannotation : *annotation->GetAnnotationElements()) {
513 fputc(' ', out_file_);
514 fputs(subannotation->GetName()->Data(), out_file_);
515 fputc('=', out_file_);
516 DumpEncodedValue(subannotation->GetValue());
517 }
518}
519/*
520 * Dumps encoded value.
521 */
522void DexLayout::DumpEncodedValue(const dex_ir::EncodedValue* data) {
523 switch (data->Type()) {
524 case DexFile::kDexAnnotationByte:
525 fprintf(out_file_, "%" PRId8, data->GetByte());
526 break;
527 case DexFile::kDexAnnotationShort:
528 fprintf(out_file_, "%" PRId16, data->GetShort());
529 break;
530 case DexFile::kDexAnnotationChar:
531 fprintf(out_file_, "%" PRIu16, data->GetChar());
532 break;
533 case DexFile::kDexAnnotationInt:
534 fprintf(out_file_, "%" PRId32, data->GetInt());
535 break;
536 case DexFile::kDexAnnotationLong:
537 fprintf(out_file_, "%" PRId64, data->GetLong());
538 break;
539 case DexFile::kDexAnnotationFloat: {
540 fprintf(out_file_, "%g", data->GetFloat());
541 break;
542 }
543 case DexFile::kDexAnnotationDouble: {
544 fprintf(out_file_, "%g", data->GetDouble());
545 break;
546 }
547 case DexFile::kDexAnnotationString: {
548 dex_ir::StringId* string_id = data->GetStringId();
549 if (options_.output_format_ == kOutputPlain) {
550 DumpEscapedString(string_id->Data(), out_file_);
551 } else {
552 DumpXmlAttribute(string_id->Data(), out_file_);
553 }
554 break;
555 }
556 case DexFile::kDexAnnotationType: {
557 dex_ir::TypeId* type_id = data->GetTypeId();
558 fputs(type_id->GetStringId()->Data(), out_file_);
559 break;
560 }
561 case DexFile::kDexAnnotationField:
562 case DexFile::kDexAnnotationEnum: {
563 dex_ir::FieldId* field_id = data->GetFieldId();
564 fputs(field_id->Name()->Data(), out_file_);
565 break;
566 }
567 case DexFile::kDexAnnotationMethod: {
568 dex_ir::MethodId* method_id = data->GetMethodId();
569 fputs(method_id->Name()->Data(), out_file_);
570 break;
571 }
572 case DexFile::kDexAnnotationArray: {
573 fputc('{', out_file_);
574 // Display all elements.
575 for (auto& value : *data->GetEncodedArray()->GetEncodedValues()) {
576 fputc(' ', out_file_);
577 DumpEncodedValue(value.get());
578 }
579 fputs(" }", out_file_);
580 break;
581 }
582 case DexFile::kDexAnnotationAnnotation: {
583 DumpEncodedAnnotation(data->GetEncodedAnnotation());
584 break;
585 }
586 case DexFile::kDexAnnotationNull:
587 fputs("null", out_file_);
588 break;
589 case DexFile::kDexAnnotationBoolean:
590 fputs(StrBool(data->GetBoolean()), out_file_);
591 break;
592 default:
593 fputs("????", out_file_);
594 break;
595 } // switch
596}
597
598/*
599 * Dumps the file header.
600 */
601void DexLayout::DumpFileHeader() {
602 char sanitized[8 * 2 + 1];
603 dex_ir::Collections& collections = header_->GetCollections();
604 fprintf(out_file_, "DEX file header:\n");
605 Asciify(sanitized, header_->Magic(), 8);
606 fprintf(out_file_, "magic : '%s'\n", sanitized);
607 fprintf(out_file_, "checksum : %08x\n", header_->Checksum());
608 fprintf(out_file_, "signature : %02x%02x...%02x%02x\n",
609 header_->Signature()[0], header_->Signature()[1],
610 header_->Signature()[DexFile::kSha1DigestSize - 2],
611 header_->Signature()[DexFile::kSha1DigestSize - 1]);
612 fprintf(out_file_, "file_size : %d\n", header_->FileSize());
613 fprintf(out_file_, "header_size : %d\n", header_->HeaderSize());
614 fprintf(out_file_, "link_size : %d\n", header_->LinkSize());
615 fprintf(out_file_, "link_off : %d (0x%06x)\n",
616 header_->LinkOffset(), header_->LinkOffset());
617 fprintf(out_file_, "string_ids_size : %d\n", collections.StringIdsSize());
618 fprintf(out_file_, "string_ids_off : %d (0x%06x)\n",
619 collections.StringIdsOffset(), collections.StringIdsOffset());
620 fprintf(out_file_, "type_ids_size : %d\n", collections.TypeIdsSize());
621 fprintf(out_file_, "type_ids_off : %d (0x%06x)\n",
622 collections.TypeIdsOffset(), collections.TypeIdsOffset());
623 fprintf(out_file_, "proto_ids_size : %d\n", collections.ProtoIdsSize());
624 fprintf(out_file_, "proto_ids_off : %d (0x%06x)\n",
625 collections.ProtoIdsOffset(), collections.ProtoIdsOffset());
626 fprintf(out_file_, "field_ids_size : %d\n", collections.FieldIdsSize());
627 fprintf(out_file_, "field_ids_off : %d (0x%06x)\n",
628 collections.FieldIdsOffset(), collections.FieldIdsOffset());
629 fprintf(out_file_, "method_ids_size : %d\n", collections.MethodIdsSize());
630 fprintf(out_file_, "method_ids_off : %d (0x%06x)\n",
631 collections.MethodIdsOffset(), collections.MethodIdsOffset());
632 fprintf(out_file_, "class_defs_size : %d\n", collections.ClassDefsSize());
633 fprintf(out_file_, "class_defs_off : %d (0x%06x)\n",
634 collections.ClassDefsOffset(), collections.ClassDefsOffset());
635 fprintf(out_file_, "data_size : %d\n", header_->DataSize());
636 fprintf(out_file_, "data_off : %d (0x%06x)\n\n",
637 header_->DataOffset(), header_->DataOffset());
638}
639
640/*
641 * Dumps a class_def_item.
642 */
643void DexLayout::DumpClassDef(int idx) {
644 // General class information.
645 dex_ir::ClassDef* class_def = header_->GetCollections().GetClassDef(idx);
646 fprintf(out_file_, "Class #%d header:\n", idx);
647 fprintf(out_file_, "class_idx : %d\n", class_def->ClassType()->GetIndex());
648 fprintf(out_file_, "access_flags : %d (0x%04x)\n",
649 class_def->GetAccessFlags(), class_def->GetAccessFlags());
650 uint32_t superclass_idx = class_def->Superclass() == nullptr ?
651 DexFile::kDexNoIndex16 : class_def->Superclass()->GetIndex();
652 fprintf(out_file_, "superclass_idx : %d\n", superclass_idx);
653 fprintf(out_file_, "interfaces_off : %d (0x%06x)\n",
654 class_def->InterfacesOffset(), class_def->InterfacesOffset());
655 uint32_t source_file_offset = 0xffffffffU;
656 if (class_def->SourceFile() != nullptr) {
657 source_file_offset = class_def->SourceFile()->GetIndex();
658 }
659 fprintf(out_file_, "source_file_idx : %d\n", source_file_offset);
660 uint32_t annotations_offset = 0;
661 if (class_def->Annotations() != nullptr) {
662 annotations_offset = class_def->Annotations()->GetOffset();
663 }
664 fprintf(out_file_, "annotations_off : %d (0x%06x)\n",
665 annotations_offset, annotations_offset);
666 if (class_def->GetClassData() == nullptr) {
667 fprintf(out_file_, "class_data_off : %d (0x%06x)\n", 0, 0);
668 } else {
669 fprintf(out_file_, "class_data_off : %d (0x%06x)\n",
670 class_def->GetClassData()->GetOffset(), class_def->GetClassData()->GetOffset());
671 }
672
673 // Fields and methods.
674 dex_ir::ClassData* class_data = class_def->GetClassData();
675 if (class_data != nullptr && class_data->StaticFields() != nullptr) {
676 fprintf(out_file_, "static_fields_size : %zu\n", class_data->StaticFields()->size());
677 } else {
678 fprintf(out_file_, "static_fields_size : 0\n");
679 }
680 if (class_data != nullptr && class_data->InstanceFields() != nullptr) {
681 fprintf(out_file_, "instance_fields_size: %zu\n", class_data->InstanceFields()->size());
682 } else {
683 fprintf(out_file_, "instance_fields_size: 0\n");
684 }
685 if (class_data != nullptr && class_data->DirectMethods() != nullptr) {
686 fprintf(out_file_, "direct_methods_size : %zu\n", class_data->DirectMethods()->size());
687 } else {
688 fprintf(out_file_, "direct_methods_size : 0\n");
689 }
690 if (class_data != nullptr && class_data->VirtualMethods() != nullptr) {
691 fprintf(out_file_, "virtual_methods_size: %zu\n", class_data->VirtualMethods()->size());
692 } else {
693 fprintf(out_file_, "virtual_methods_size: 0\n");
694 }
695 fprintf(out_file_, "\n");
696}
697
698/**
699 * Dumps an annotation set item.
700 */
701void DexLayout::DumpAnnotationSetItem(dex_ir::AnnotationSetItem* set_item) {
702 if (set_item == nullptr || set_item->GetItems()->size() == 0) {
703 fputs(" empty-annotation-set\n", out_file_);
704 return;
705 }
706 for (dex_ir::AnnotationItem* annotation : *set_item->GetItems()) {
707 if (annotation == nullptr) {
708 continue;
709 }
710 fputs(" ", out_file_);
711 switch (annotation->GetVisibility()) {
712 case DexFile::kDexVisibilityBuild: fputs("VISIBILITY_BUILD ", out_file_); break;
713 case DexFile::kDexVisibilityRuntime: fputs("VISIBILITY_RUNTIME ", out_file_); break;
714 case DexFile::kDexVisibilitySystem: fputs("VISIBILITY_SYSTEM ", out_file_); break;
715 default: fputs("VISIBILITY_UNKNOWN ", out_file_); break;
716 } // switch
717 DumpEncodedAnnotation(annotation->GetAnnotation());
718 fputc('\n', out_file_);
719 }
720}
721
722/*
723 * Dumps class annotations.
724 */
725void DexLayout::DumpClassAnnotations(int idx) {
726 dex_ir::ClassDef* class_def = header_->GetCollections().GetClassDef(idx);
727 dex_ir::AnnotationsDirectoryItem* annotations_directory = class_def->Annotations();
728 if (annotations_directory == nullptr) {
729 return; // none
730 }
731
732 fprintf(out_file_, "Class #%d annotations:\n", idx);
733
734 dex_ir::AnnotationSetItem* class_set_item = annotations_directory->GetClassAnnotation();
735 dex_ir::FieldAnnotationVector* fields = annotations_directory->GetFieldAnnotations();
736 dex_ir::MethodAnnotationVector* methods = annotations_directory->GetMethodAnnotations();
737 dex_ir::ParameterAnnotationVector* parameters = annotations_directory->GetParameterAnnotations();
738
739 // Annotations on the class itself.
740 if (class_set_item != nullptr) {
741 fprintf(out_file_, "Annotations on class\n");
742 DumpAnnotationSetItem(class_set_item);
743 }
744
745 // Annotations on fields.
746 if (fields != nullptr) {
747 for (auto& field : *fields) {
748 const dex_ir::FieldId* field_id = field->GetFieldId();
749 const uint32_t field_idx = field_id->GetIndex();
750 const char* field_name = field_id->Name()->Data();
751 fprintf(out_file_, "Annotations on field #%u '%s'\n", field_idx, field_name);
752 DumpAnnotationSetItem(field->GetAnnotationSetItem());
753 }
754 }
755
756 // Annotations on methods.
757 if (methods != nullptr) {
758 for (auto& method : *methods) {
759 const dex_ir::MethodId* method_id = method->GetMethodId();
760 const uint32_t method_idx = method_id->GetIndex();
761 const char* method_name = method_id->Name()->Data();
762 fprintf(out_file_, "Annotations on method #%u '%s'\n", method_idx, method_name);
763 DumpAnnotationSetItem(method->GetAnnotationSetItem());
764 }
765 }
766
767 // Annotations on method parameters.
768 if (parameters != nullptr) {
769 for (auto& parameter : *parameters) {
770 const dex_ir::MethodId* method_id = parameter->GetMethodId();
771 const uint32_t method_idx = method_id->GetIndex();
772 const char* method_name = method_id->Name()->Data();
773 fprintf(out_file_, "Annotations on method #%u '%s' parameters\n", method_idx, method_name);
774 uint32_t j = 0;
775 for (dex_ir::AnnotationSetItem* annotation : *parameter->GetAnnotations()->GetItems()) {
776 fprintf(out_file_, "#%u\n", j);
777 DumpAnnotationSetItem(annotation);
778 ++j;
779 }
780 }
781 }
782
783 fputc('\n', out_file_);
784}
785
786/*
787 * Dumps an interface that a class declares to implement.
788 */
789void DexLayout::DumpInterface(const dex_ir::TypeId* type_item, int i) {
790 const char* interface_name = type_item->GetStringId()->Data();
791 if (options_.output_format_ == kOutputPlain) {
792 fprintf(out_file_, " #%d : '%s'\n", i, interface_name);
793 } else {
794 std::string dot(DescriptorToDotWrapper(interface_name));
795 fprintf(out_file_, "<implements name=\"%s\">\n</implements>\n", dot.c_str());
796 }
797}
798
799/*
800 * Dumps the catches table associated with the code.
801 */
802void DexLayout::DumpCatches(const dex_ir::CodeItem* code) {
803 const uint16_t tries_size = code->TriesSize();
804
805 // No catch table.
806 if (tries_size == 0) {
807 fprintf(out_file_, " catches : (none)\n");
808 return;
809 }
810
811 // Dump all table entries.
812 fprintf(out_file_, " catches : %d\n", tries_size);
813 std::vector<std::unique_ptr<const dex_ir::TryItem>>* tries = code->Tries();
814 for (uint32_t i = 0; i < tries_size; i++) {
815 const dex_ir::TryItem* try_item = (*tries)[i].get();
816 const uint32_t start = try_item->StartAddr();
817 const uint32_t end = start + try_item->InsnCount();
818 fprintf(out_file_, " 0x%04x - 0x%04x\n", start, end);
819 for (auto& handler : *try_item->GetHandlers()->GetHandlers()) {
820 const dex_ir::TypeId* type_id = handler->GetTypeId();
821 const char* descriptor = (type_id == nullptr) ? "<any>" : type_id->GetStringId()->Data();
822 fprintf(out_file_, " %s -> 0x%04x\n", descriptor, handler->GetAddress());
823 } // for
824 } // for
825}
826
827/*
David Sehr7629f602016-08-07 16:01:51 -0700828 * Dumps a single instruction.
829 */
Jeff Haoea7c6292016-11-14 18:10:16 -0800830void DexLayout::DumpInstruction(const dex_ir::CodeItem* code,
831 uint32_t code_offset,
832 uint32_t insn_idx,
833 uint32_t insn_width,
834 const Instruction* dec_insn) {
David Sehr7629f602016-08-07 16:01:51 -0700835 // Address of instruction (expressed as byte offset).
836 fprintf(out_file_, "%06x:", code_offset + 0x10 + insn_idx * 2);
837
838 // Dump (part of) raw bytes.
839 const uint16_t* insns = code->Insns();
840 for (uint32_t i = 0; i < 8; i++) {
841 if (i < insn_width) {
842 if (i == 7) {
843 fprintf(out_file_, " ... ");
844 } else {
845 // Print 16-bit value in little-endian order.
846 const uint8_t* bytePtr = (const uint8_t*) &insns[insn_idx + i];
847 fprintf(out_file_, " %02x%02x", bytePtr[0], bytePtr[1]);
848 }
849 } else {
850 fputs(" ", out_file_);
851 }
852 } // for
853
854 // Dump pseudo-instruction or opcode.
855 if (dec_insn->Opcode() == Instruction::NOP) {
856 const uint16_t instr = Get2LE((const uint8_t*) &insns[insn_idx]);
857 if (instr == Instruction::kPackedSwitchSignature) {
858 fprintf(out_file_, "|%04x: packed-switch-data (%d units)", insn_idx, insn_width);
859 } else if (instr == Instruction::kSparseSwitchSignature) {
860 fprintf(out_file_, "|%04x: sparse-switch-data (%d units)", insn_idx, insn_width);
861 } else if (instr == Instruction::kArrayDataSignature) {
862 fprintf(out_file_, "|%04x: array-data (%d units)", insn_idx, insn_width);
863 } else {
864 fprintf(out_file_, "|%04x: nop // spacer", insn_idx);
865 }
866 } else {
867 fprintf(out_file_, "|%04x: %s", insn_idx, dec_insn->Name());
868 }
869
870 // Set up additional argument.
871 std::unique_ptr<char[]> index_buf;
872 if (Instruction::IndexTypeOf(dec_insn->Opcode()) != Instruction::kIndexNone) {
Jeff Haoea7c6292016-11-14 18:10:16 -0800873 index_buf = IndexString(header_, dec_insn, 200);
David Sehr7629f602016-08-07 16:01:51 -0700874 }
875
876 // Dump the instruction.
877 //
878 // NOTE: pDecInsn->DumpString(pDexFile) differs too much from original.
879 //
880 switch (Instruction::FormatOf(dec_insn->Opcode())) {
881 case Instruction::k10x: // op
882 break;
883 case Instruction::k12x: // op vA, vB
884 fprintf(out_file_, " v%d, v%d", dec_insn->VRegA(), dec_insn->VRegB());
885 break;
886 case Instruction::k11n: // op vA, #+B
887 fprintf(out_file_, " v%d, #int %d // #%x",
888 dec_insn->VRegA(), (int32_t) dec_insn->VRegB(), (uint8_t)dec_insn->VRegB());
889 break;
890 case Instruction::k11x: // op vAA
891 fprintf(out_file_, " v%d", dec_insn->VRegA());
892 break;
893 case Instruction::k10t: // op +AA
894 case Instruction::k20t: { // op +AAAA
895 const int32_t targ = (int32_t) dec_insn->VRegA();
896 fprintf(out_file_, " %04x // %c%04x",
897 insn_idx + targ,
898 (targ < 0) ? '-' : '+',
899 (targ < 0) ? -targ : targ);
900 break;
901 }
902 case Instruction::k22x: // op vAA, vBBBB
903 fprintf(out_file_, " v%d, v%d", dec_insn->VRegA(), dec_insn->VRegB());
904 break;
905 case Instruction::k21t: { // op vAA, +BBBB
906 const int32_t targ = (int32_t) dec_insn->VRegB();
907 fprintf(out_file_, " v%d, %04x // %c%04x", dec_insn->VRegA(),
908 insn_idx + targ,
909 (targ < 0) ? '-' : '+',
910 (targ < 0) ? -targ : targ);
911 break;
912 }
913 case Instruction::k21s: // op vAA, #+BBBB
914 fprintf(out_file_, " v%d, #int %d // #%x",
915 dec_insn->VRegA(), (int32_t) dec_insn->VRegB(), (uint16_t)dec_insn->VRegB());
916 break;
917 case Instruction::k21h: // op vAA, #+BBBB0000[00000000]
918 // The printed format varies a bit based on the actual opcode.
919 if (dec_insn->Opcode() == Instruction::CONST_HIGH16) {
920 const int32_t value = dec_insn->VRegB() << 16;
921 fprintf(out_file_, " v%d, #int %d // #%x",
922 dec_insn->VRegA(), value, (uint16_t) dec_insn->VRegB());
923 } else {
924 const int64_t value = ((int64_t) dec_insn->VRegB()) << 48;
925 fprintf(out_file_, " v%d, #long %" PRId64 " // #%x",
926 dec_insn->VRegA(), value, (uint16_t) dec_insn->VRegB());
927 }
928 break;
929 case Instruction::k21c: // op vAA, thing@BBBB
930 case Instruction::k31c: // op vAA, thing@BBBBBBBB
931 fprintf(out_file_, " v%d, %s", dec_insn->VRegA(), index_buf.get());
932 break;
933 case Instruction::k23x: // op vAA, vBB, vCC
934 fprintf(out_file_, " v%d, v%d, v%d",
935 dec_insn->VRegA(), dec_insn->VRegB(), dec_insn->VRegC());
936 break;
937 case Instruction::k22b: // op vAA, vBB, #+CC
938 fprintf(out_file_, " v%d, v%d, #int %d // #%02x",
939 dec_insn->VRegA(), dec_insn->VRegB(),
940 (int32_t) dec_insn->VRegC(), (uint8_t) dec_insn->VRegC());
941 break;
942 case Instruction::k22t: { // op vA, vB, +CCCC
943 const int32_t targ = (int32_t) dec_insn->VRegC();
944 fprintf(out_file_, " v%d, v%d, %04x // %c%04x",
945 dec_insn->VRegA(), dec_insn->VRegB(),
946 insn_idx + targ,
947 (targ < 0) ? '-' : '+',
948 (targ < 0) ? -targ : targ);
949 break;
950 }
951 case Instruction::k22s: // op vA, vB, #+CCCC
952 fprintf(out_file_, " v%d, v%d, #int %d // #%04x",
953 dec_insn->VRegA(), dec_insn->VRegB(),
954 (int32_t) dec_insn->VRegC(), (uint16_t) dec_insn->VRegC());
955 break;
956 case Instruction::k22c: // op vA, vB, thing@CCCC
957 // NOT SUPPORTED:
958 // case Instruction::k22cs: // [opt] op vA, vB, field offset CCCC
959 fprintf(out_file_, " v%d, v%d, %s",
960 dec_insn->VRegA(), dec_insn->VRegB(), index_buf.get());
961 break;
962 case Instruction::k30t:
963 fprintf(out_file_, " #%08x", dec_insn->VRegA());
964 break;
965 case Instruction::k31i: { // op vAA, #+BBBBBBBB
966 // This is often, but not always, a float.
967 union {
968 float f;
969 uint32_t i;
970 } conv;
971 conv.i = dec_insn->VRegB();
972 fprintf(out_file_, " v%d, #float %g // #%08x",
973 dec_insn->VRegA(), conv.f, dec_insn->VRegB());
974 break;
975 }
976 case Instruction::k31t: // op vAA, offset +BBBBBBBB
977 fprintf(out_file_, " v%d, %08x // +%08x",
978 dec_insn->VRegA(), insn_idx + dec_insn->VRegB(), dec_insn->VRegB());
979 break;
980 case Instruction::k32x: // op vAAAA, vBBBB
981 fprintf(out_file_, " v%d, v%d", dec_insn->VRegA(), dec_insn->VRegB());
982 break;
Orion Hodsonb34bb192016-10-18 17:02:58 +0100983 case Instruction::k35c: // op {vC, vD, vE, vF, vG}, thing@BBBB
984 case Instruction::k45cc: { // op {vC, vD, vE, vF, vG}, meth@BBBB, proto@HHHH
David Sehr7629f602016-08-07 16:01:51 -0700985 // NOT SUPPORTED:
986 // case Instruction::k35ms: // [opt] invoke-virtual+super
987 // case Instruction::k35mi: // [opt] inline invoke
988 uint32_t arg[Instruction::kMaxVarArgRegs];
989 dec_insn->GetVarArgs(arg);
990 fputs(" {", out_file_);
991 for (int i = 0, n = dec_insn->VRegA(); i < n; i++) {
992 if (i == 0) {
993 fprintf(out_file_, "v%d", arg[i]);
994 } else {
995 fprintf(out_file_, ", v%d", arg[i]);
996 }
997 } // for
998 fprintf(out_file_, "}, %s", index_buf.get());
999 break;
1000 }
Orion Hodsonb34bb192016-10-18 17:02:58 +01001001 case Instruction::k3rc: // op {vCCCC .. v(CCCC+AA-1)}, thing@BBBB
1002 case Instruction::k4rcc: // op {vCCCC .. v(CCCC+AA-1)}, meth@BBBB, proto@HHHH
David Sehr7629f602016-08-07 16:01:51 -07001003 // NOT SUPPORTED:
1004 // case Instruction::k3rms: // [opt] invoke-virtual+super/range
1005 // case Instruction::k3rmi: // [opt] execute-inline/range
1006 {
1007 // This doesn't match the "dx" output when some of the args are
1008 // 64-bit values -- dx only shows the first register.
1009 fputs(" {", out_file_);
1010 for (int i = 0, n = dec_insn->VRegA(); i < n; i++) {
1011 if (i == 0) {
1012 fprintf(out_file_, "v%d", dec_insn->VRegC() + i);
1013 } else {
1014 fprintf(out_file_, ", v%d", dec_insn->VRegC() + i);
1015 }
1016 } // for
1017 fprintf(out_file_, "}, %s", index_buf.get());
1018 }
1019 break;
1020 case Instruction::k51l: { // op vAA, #+BBBBBBBBBBBBBBBB
1021 // This is often, but not always, a double.
1022 union {
1023 double d;
1024 uint64_t j;
1025 } conv;
1026 conv.j = dec_insn->WideVRegB();
1027 fprintf(out_file_, " v%d, #double %g // #%016" PRIx64,
1028 dec_insn->VRegA(), conv.d, dec_insn->WideVRegB());
1029 break;
1030 }
1031 // NOT SUPPORTED:
1032 // case Instruction::k00x: // unknown op or breakpoint
1033 // break;
1034 default:
1035 fprintf(out_file_, " ???");
1036 break;
1037 } // switch
1038
1039 fputc('\n', out_file_);
1040}
1041
1042/*
1043 * Dumps a bytecode disassembly.
1044 */
Jeff Haoea7c6292016-11-14 18:10:16 -08001045void DexLayout::DumpBytecodes(uint32_t idx, const dex_ir::CodeItem* code, uint32_t code_offset) {
1046 dex_ir::MethodId* method_id = header_->GetCollections().GetMethodId(idx);
David Sehr7629f602016-08-07 16:01:51 -07001047 const char* name = method_id->Name()->Data();
David Sehr72359222016-09-07 13:04:01 -07001048 std::string type_descriptor = GetSignatureForProtoId(method_id->Proto());
David Sehr7629f602016-08-07 16:01:51 -07001049 const char* back_descriptor = method_id->Class()->GetStringId()->Data();
1050
1051 // Generate header.
Jeff Haoc3acfc52016-08-29 14:18:26 -07001052 std::string dot(DescriptorToDotWrapper(back_descriptor));
David Sehr7629f602016-08-07 16:01:51 -07001053 fprintf(out_file_, "%06x: |[%06x] %s.%s:%s\n",
David Sehr72359222016-09-07 13:04:01 -07001054 code_offset, code_offset, dot.c_str(), name, type_descriptor.c_str());
David Sehr7629f602016-08-07 16:01:51 -07001055
1056 // Iterate over all instructions.
Mathieu Chartier2b2bef22017-10-26 17:10:19 -07001057 for (const DexInstructionPcPair& inst : code->Instructions()) {
Mathieu Chartier1d2d4ff2017-09-23 16:11:06 -07001058 const uint32_t insn_width = inst->SizeInCodeUnits();
David Sehr7629f602016-08-07 16:01:51 -07001059 if (insn_width == 0) {
Mathieu Chartier2b2bef22017-10-26 17:10:19 -07001060 fprintf(stderr, "GLITCH: zero-width instruction at idx=0x%04x\n", inst.DexPc());
David Sehr7629f602016-08-07 16:01:51 -07001061 break;
1062 }
Mathieu Chartier2b2bef22017-10-26 17:10:19 -07001063 DumpInstruction(code, code_offset, inst.DexPc(), insn_width, &inst.Inst());
David Sehr7629f602016-08-07 16:01:51 -07001064 } // for
1065}
1066
1067/*
David Sehraa6abb02017-10-12 08:25:11 -07001068 * Callback for dumping each positions table entry.
1069 */
1070static bool DumpPositionsCb(void* context, const DexFile::PositionInfo& entry) {
1071 FILE* out_file = reinterpret_cast<FILE*>(context);
1072 fprintf(out_file, " 0x%04x line=%d\n", entry.address_, entry.line_);
1073 return false;
1074}
1075
1076/*
1077 * Callback for dumping locals table entry.
1078 */
1079static void DumpLocalsCb(void* context, const DexFile::LocalInfo& entry) {
1080 const char* signature = entry.signature_ != nullptr ? entry.signature_ : "";
1081 FILE* out_file = reinterpret_cast<FILE*>(context);
1082 fprintf(out_file, " 0x%04x - 0x%04x reg=%d %s %s %s\n",
1083 entry.start_address_, entry.end_address_, entry.reg_,
1084 entry.name_, entry.descriptor_, signature);
1085}
1086
1087/*
1088 * Lookup functions.
1089 */
1090static const char* StringDataByIdx(uint32_t idx, dex_ir::Collections& collections) {
1091 dex_ir::StringId* string_id = collections.GetStringIdOrNullPtr(idx);
1092 if (string_id == nullptr) {
1093 return nullptr;
1094 }
1095 return string_id->Data();
1096}
1097
1098static const char* StringDataByTypeIdx(uint16_t idx, dex_ir::Collections& collections) {
1099 dex_ir::TypeId* type_id = collections.GetTypeIdOrNullPtr(idx);
1100 if (type_id == nullptr) {
1101 return nullptr;
1102 }
1103 dex_ir::StringId* string_id = type_id->GetStringId();
1104 if (string_id == nullptr) {
1105 return nullptr;
1106 }
1107 return string_id->Data();
1108}
1109
1110
1111/*
David Sehr7629f602016-08-07 16:01:51 -07001112 * Dumps code of a method.
1113 */
David Sehraa6abb02017-10-12 08:25:11 -07001114void DexLayout::DumpCode(uint32_t idx,
1115 const dex_ir::CodeItem* code,
1116 uint32_t code_offset,
1117 const char* declaring_class_descriptor,
1118 const char* method_name,
1119 bool is_static,
1120 const dex_ir::ProtoId* proto) {
David Sehr7629f602016-08-07 16:01:51 -07001121 fprintf(out_file_, " registers : %d\n", code->RegistersSize());
1122 fprintf(out_file_, " ins : %d\n", code->InsSize());
1123 fprintf(out_file_, " outs : %d\n", code->OutsSize());
1124 fprintf(out_file_, " insns size : %d 16-bit code units\n",
1125 code->InsnsSize());
1126
1127 // Bytecode disassembly, if requested.
1128 if (options_.disassemble_) {
Jeff Haoea7c6292016-11-14 18:10:16 -08001129 DumpBytecodes(idx, code, code_offset);
David Sehr7629f602016-08-07 16:01:51 -07001130 }
1131
1132 // Try-catch blocks.
1133 DumpCatches(code);
1134
1135 // Positions and locals table in the debug info.
David Sehraa6abb02017-10-12 08:25:11 -07001136 dex_ir::DebugInfoItem* debug_info = code->DebugInfo();
David Sehr7629f602016-08-07 16:01:51 -07001137 fprintf(out_file_, " positions : \n");
David Sehraa6abb02017-10-12 08:25:11 -07001138 if (debug_info != nullptr) {
1139 DexFile::DecodeDebugPositionInfo(debug_info->GetDebugInfo(),
1140 [this](uint32_t idx) {
1141 return StringDataByIdx(idx, this->header_->GetCollections());
1142 },
1143 DumpPositionsCb,
1144 out_file_);
1145 }
David Sehr7629f602016-08-07 16:01:51 -07001146 fprintf(out_file_, " locals : \n");
David Sehraa6abb02017-10-12 08:25:11 -07001147 if (debug_info != nullptr) {
1148 std::vector<const char*> arg_descriptors;
1149 const dex_ir::TypeList* parameters = proto->Parameters();
1150 if (parameters != nullptr) {
1151 const dex_ir::TypeIdVector* parameter_type_vector = parameters->GetTypeList();
1152 if (parameter_type_vector != nullptr) {
1153 for (const dex_ir::TypeId* type_id : *parameter_type_vector) {
1154 arg_descriptors.push_back(type_id->GetStringId()->Data());
1155 }
1156 }
1157 }
1158 DexFile::DecodeDebugLocalInfo(debug_info->GetDebugInfo(),
1159 "DexLayout in-memory",
1160 declaring_class_descriptor,
1161 arg_descriptors,
1162 method_name,
1163 is_static,
1164 code->RegistersSize(),
1165 code->InsSize(),
1166 code->InsnsSize(),
1167 [this](uint32_t idx) {
1168 return StringDataByIdx(idx, this->header_->GetCollections());
1169 },
1170 [this](uint32_t idx) {
1171 return
1172 StringDataByTypeIdx(dchecked_integral_cast<uint16_t>(idx),
1173 this->header_->GetCollections());
1174 },
1175 DumpLocalsCb,
1176 out_file_);
1177 }
David Sehr7629f602016-08-07 16:01:51 -07001178}
1179
1180/*
1181 * Dumps a method.
1182 */
Jeff Haoea7c6292016-11-14 18:10:16 -08001183void DexLayout::DumpMethod(uint32_t idx, uint32_t flags, const dex_ir::CodeItem* code, int i) {
David Sehr7629f602016-08-07 16:01:51 -07001184 // Bail for anything private if export only requested.
1185 if (options_.exports_only_ && (flags & (kAccPublic | kAccProtected)) == 0) {
1186 return;
1187 }
1188
Jeff Haoea7c6292016-11-14 18:10:16 -08001189 dex_ir::MethodId* method_id = header_->GetCollections().GetMethodId(idx);
David Sehr7629f602016-08-07 16:01:51 -07001190 const char* name = method_id->Name()->Data();
1191 char* type_descriptor = strdup(GetSignatureForProtoId(method_id->Proto()).c_str());
1192 const char* back_descriptor = method_id->Class()->GetStringId()->Data();
1193 char* access_str = CreateAccessFlagStr(flags, kAccessForMethod);
1194
1195 if (options_.output_format_ == kOutputPlain) {
1196 fprintf(out_file_, " #%d : (in %s)\n", i, back_descriptor);
1197 fprintf(out_file_, " name : '%s'\n", name);
1198 fprintf(out_file_, " type : '%s'\n", type_descriptor);
1199 fprintf(out_file_, " access : 0x%04x (%s)\n", flags, access_str);
1200 if (code == nullptr) {
1201 fprintf(out_file_, " code : (none)\n");
1202 } else {
1203 fprintf(out_file_, " code -\n");
David Sehraa6abb02017-10-12 08:25:11 -07001204 DumpCode(idx,
1205 code,
1206 code->GetOffset(),
1207 back_descriptor,
1208 name,
1209 (flags & kAccStatic) != 0,
1210 method_id->Proto());
David Sehr7629f602016-08-07 16:01:51 -07001211 }
1212 if (options_.disassemble_) {
1213 fputc('\n', out_file_);
1214 }
1215 } else if (options_.output_format_ == kOutputXml) {
1216 const bool constructor = (name[0] == '<');
1217
1218 // Method name and prototype.
1219 if (constructor) {
1220 std::string dot(DescriptorClassToDot(back_descriptor));
1221 fprintf(out_file_, "<constructor name=\"%s\"\n", dot.c_str());
Jeff Haoc3acfc52016-08-29 14:18:26 -07001222 dot = DescriptorToDotWrapper(back_descriptor);
David Sehr7629f602016-08-07 16:01:51 -07001223 fprintf(out_file_, " type=\"%s\"\n", dot.c_str());
1224 } else {
1225 fprintf(out_file_, "<method name=\"%s\"\n", name);
1226 const char* return_type = strrchr(type_descriptor, ')');
1227 if (return_type == nullptr) {
1228 fprintf(stderr, "bad method type descriptor '%s'\n", type_descriptor);
1229 goto bail;
1230 }
Jeff Haoc3acfc52016-08-29 14:18:26 -07001231 std::string dot(DescriptorToDotWrapper(return_type + 1));
David Sehr7629f602016-08-07 16:01:51 -07001232 fprintf(out_file_, " return=\"%s\"\n", dot.c_str());
1233 fprintf(out_file_, " abstract=%s\n", QuotedBool((flags & kAccAbstract) != 0));
1234 fprintf(out_file_, " native=%s\n", QuotedBool((flags & kAccNative) != 0));
1235 fprintf(out_file_, " synchronized=%s\n", QuotedBool(
1236 (flags & (kAccSynchronized | kAccDeclaredSynchronized)) != 0));
1237 }
1238
1239 // Additional method flags.
1240 fprintf(out_file_, " static=%s\n", QuotedBool((flags & kAccStatic) != 0));
1241 fprintf(out_file_, " final=%s\n", QuotedBool((flags & kAccFinal) != 0));
1242 // The "deprecated=" not knowable w/o parsing annotations.
1243 fprintf(out_file_, " visibility=%s\n>\n", QuotedVisibility(flags));
1244
1245 // Parameters.
1246 if (type_descriptor[0] != '(') {
1247 fprintf(stderr, "ERROR: bad descriptor '%s'\n", type_descriptor);
1248 goto bail;
1249 }
1250 char* tmp_buf = reinterpret_cast<char*>(malloc(strlen(type_descriptor) + 1));
1251 const char* base = type_descriptor + 1;
1252 int arg_num = 0;
1253 while (*base != ')') {
1254 char* cp = tmp_buf;
1255 while (*base == '[') {
1256 *cp++ = *base++;
1257 }
1258 if (*base == 'L') {
1259 // Copy through ';'.
1260 do {
1261 *cp = *base++;
1262 } while (*cp++ != ';');
1263 } else {
1264 // Primitive char, copy it.
1265 if (strchr("ZBCSIFJD", *base) == nullptr) {
1266 fprintf(stderr, "ERROR: bad method signature '%s'\n", base);
1267 break; // while
1268 }
1269 *cp++ = *base++;
1270 }
1271 // Null terminate and display.
1272 *cp++ = '\0';
Jeff Haoc3acfc52016-08-29 14:18:26 -07001273 std::string dot(DescriptorToDotWrapper(tmp_buf));
David Sehr7629f602016-08-07 16:01:51 -07001274 fprintf(out_file_, "<parameter name=\"arg%d\" type=\"%s\">\n"
1275 "</parameter>\n", arg_num++, dot.c_str());
1276 } // while
1277 free(tmp_buf);
1278 if (constructor) {
1279 fprintf(out_file_, "</constructor>\n");
1280 } else {
1281 fprintf(out_file_, "</method>\n");
1282 }
1283 }
1284
1285 bail:
1286 free(type_descriptor);
1287 free(access_str);
1288}
1289
1290/*
1291 * Dumps a static (class) field.
1292 */
Jeff Haoea7c6292016-11-14 18:10:16 -08001293void DexLayout::DumpSField(uint32_t idx, uint32_t flags, int i, dex_ir::EncodedValue* init) {
David Sehr7629f602016-08-07 16:01:51 -07001294 // Bail for anything private if export only requested.
1295 if (options_.exports_only_ && (flags & (kAccPublic | kAccProtected)) == 0) {
1296 return;
1297 }
1298
Jeff Haoea7c6292016-11-14 18:10:16 -08001299 dex_ir::FieldId* field_id = header_->GetCollections().GetFieldId(idx);
David Sehr7629f602016-08-07 16:01:51 -07001300 const char* name = field_id->Name()->Data();
1301 const char* type_descriptor = field_id->Type()->GetStringId()->Data();
1302 const char* back_descriptor = field_id->Class()->GetStringId()->Data();
1303 char* access_str = CreateAccessFlagStr(flags, kAccessForField);
1304
1305 if (options_.output_format_ == kOutputPlain) {
1306 fprintf(out_file_, " #%d : (in %s)\n", i, back_descriptor);
1307 fprintf(out_file_, " name : '%s'\n", name);
1308 fprintf(out_file_, " type : '%s'\n", type_descriptor);
1309 fprintf(out_file_, " access : 0x%04x (%s)\n", flags, access_str);
1310 if (init != nullptr) {
1311 fputs(" value : ", out_file_);
1312 DumpEncodedValue(init);
1313 fputs("\n", out_file_);
1314 }
1315 } else if (options_.output_format_ == kOutputXml) {
1316 fprintf(out_file_, "<field name=\"%s\"\n", name);
Jeff Haoc3acfc52016-08-29 14:18:26 -07001317 std::string dot(DescriptorToDotWrapper(type_descriptor));
David Sehr7629f602016-08-07 16:01:51 -07001318 fprintf(out_file_, " type=\"%s\"\n", dot.c_str());
1319 fprintf(out_file_, " transient=%s\n", QuotedBool((flags & kAccTransient) != 0));
1320 fprintf(out_file_, " volatile=%s\n", QuotedBool((flags & kAccVolatile) != 0));
1321 // The "value=" is not knowable w/o parsing annotations.
1322 fprintf(out_file_, " static=%s\n", QuotedBool((flags & kAccStatic) != 0));
1323 fprintf(out_file_, " final=%s\n", QuotedBool((flags & kAccFinal) != 0));
1324 // The "deprecated=" is not knowable w/o parsing annotations.
1325 fprintf(out_file_, " visibility=%s\n", QuotedVisibility(flags));
1326 if (init != nullptr) {
1327 fputs(" value=\"", out_file_);
1328 DumpEncodedValue(init);
1329 fputs("\"\n", out_file_);
1330 }
1331 fputs(">\n</field>\n", out_file_);
1332 }
1333
1334 free(access_str);
1335}
1336
1337/*
1338 * Dumps an instance field.
1339 */
Jeff Haoea7c6292016-11-14 18:10:16 -08001340void DexLayout::DumpIField(uint32_t idx, uint32_t flags, int i) {
1341 DumpSField(idx, flags, i, nullptr);
David Sehr7629f602016-08-07 16:01:51 -07001342}
1343
1344/*
David Sehr7629f602016-08-07 16:01:51 -07001345 * Dumps the class.
1346 *
1347 * Note "idx" is a DexClassDef index, not a DexTypeId index.
1348 *
1349 * If "*last_package" is nullptr or does not match the current class' package,
1350 * the value will be replaced with a newly-allocated string.
1351 */
Jeff Haoea7c6292016-11-14 18:10:16 -08001352void DexLayout::DumpClass(int idx, char** last_package) {
1353 dex_ir::ClassDef* class_def = header_->GetCollections().GetClassDef(idx);
David Sehr7629f602016-08-07 16:01:51 -07001354 // Omitting non-public class.
1355 if (options_.exports_only_ && (class_def->GetAccessFlags() & kAccPublic) == 0) {
1356 return;
1357 }
1358
1359 if (options_.show_section_headers_) {
Jeff Haoea7c6292016-11-14 18:10:16 -08001360 DumpClassDef(idx);
David Sehr7629f602016-08-07 16:01:51 -07001361 }
1362
1363 if (options_.show_annotations_) {
Jeff Haoea7c6292016-11-14 18:10:16 -08001364 DumpClassAnnotations(idx);
David Sehr7629f602016-08-07 16:01:51 -07001365 }
1366
David Sehr7629f602016-08-07 16:01:51 -07001367 // For the XML output, show the package name. Ideally we'd gather
1368 // up the classes, sort them, and dump them alphabetically so the
1369 // package name wouldn't jump around, but that's not a great plan
1370 // for something that needs to run on the device.
Jeff Hao3ab96b42016-09-09 18:35:01 -07001371 const char* class_descriptor =
Jeff Haoea7c6292016-11-14 18:10:16 -08001372 header_->GetCollections().GetClassDef(idx)->ClassType()->GetStringId()->Data();
David Sehr7629f602016-08-07 16:01:51 -07001373 if (!(class_descriptor[0] == 'L' &&
1374 class_descriptor[strlen(class_descriptor)-1] == ';')) {
1375 // Arrays and primitives should not be defined explicitly. Keep going?
1376 fprintf(stderr, "Malformed class name '%s'\n", class_descriptor);
1377 } else if (options_.output_format_ == kOutputXml) {
1378 char* mangle = strdup(class_descriptor + 1);
1379 mangle[strlen(mangle)-1] = '\0';
1380
1381 // Reduce to just the package name.
1382 char* last_slash = strrchr(mangle, '/');
1383 if (last_slash != nullptr) {
1384 *last_slash = '\0';
1385 } else {
1386 *mangle = '\0';
1387 }
1388
1389 for (char* cp = mangle; *cp != '\0'; cp++) {
1390 if (*cp == '/') {
1391 *cp = '.';
1392 }
1393 } // for
1394
1395 if (*last_package == nullptr || strcmp(mangle, *last_package) != 0) {
1396 // Start of a new package.
1397 if (*last_package != nullptr) {
1398 fprintf(out_file_, "</package>\n");
1399 }
1400 fprintf(out_file_, "<package name=\"%s\"\n>\n", mangle);
1401 free(*last_package);
1402 *last_package = mangle;
1403 } else {
1404 free(mangle);
1405 }
1406 }
1407
1408 // General class information.
1409 char* access_str = CreateAccessFlagStr(class_def->GetAccessFlags(), kAccessForClass);
1410 const char* superclass_descriptor = nullptr;
1411 if (class_def->Superclass() != nullptr) {
1412 superclass_descriptor = class_def->Superclass()->GetStringId()->Data();
1413 }
1414 if (options_.output_format_ == kOutputPlain) {
1415 fprintf(out_file_, "Class #%d -\n", idx);
1416 fprintf(out_file_, " Class descriptor : '%s'\n", class_descriptor);
1417 fprintf(out_file_, " Access flags : 0x%04x (%s)\n",
1418 class_def->GetAccessFlags(), access_str);
1419 if (superclass_descriptor != nullptr) {
1420 fprintf(out_file_, " Superclass : '%s'\n", superclass_descriptor);
1421 }
1422 fprintf(out_file_, " Interfaces -\n");
1423 } else {
1424 std::string dot(DescriptorClassToDot(class_descriptor));
1425 fprintf(out_file_, "<class name=\"%s\"\n", dot.c_str());
1426 if (superclass_descriptor != nullptr) {
Jeff Haoc3acfc52016-08-29 14:18:26 -07001427 dot = DescriptorToDotWrapper(superclass_descriptor);
David Sehr7629f602016-08-07 16:01:51 -07001428 fprintf(out_file_, " extends=\"%s\"\n", dot.c_str());
1429 }
1430 fprintf(out_file_, " interface=%s\n",
1431 QuotedBool((class_def->GetAccessFlags() & kAccInterface) != 0));
1432 fprintf(out_file_, " abstract=%s\n",
1433 QuotedBool((class_def->GetAccessFlags() & kAccAbstract) != 0));
1434 fprintf(out_file_, " static=%s\n", QuotedBool((class_def->GetAccessFlags() & kAccStatic) != 0));
1435 fprintf(out_file_, " final=%s\n", QuotedBool((class_def->GetAccessFlags() & kAccFinal) != 0));
1436 // The "deprecated=" not knowable w/o parsing annotations.
1437 fprintf(out_file_, " visibility=%s\n", QuotedVisibility(class_def->GetAccessFlags()));
1438 fprintf(out_file_, ">\n");
1439 }
1440
1441 // Interfaces.
Jeff Haocc829592017-03-14 16:13:39 -07001442 const dex_ir::TypeList* interfaces = class_def->Interfaces();
David Sehr853a8e12016-09-01 13:03:50 -07001443 if (interfaces != nullptr) {
Jeff Haocc829592017-03-14 16:13:39 -07001444 const dex_ir::TypeIdVector* interfaces_vector = interfaces->GetTypeList();
1445 for (uint32_t i = 0; i < interfaces_vector->size(); i++) {
1446 DumpInterface((*interfaces_vector)[i], i);
David Sehr853a8e12016-09-01 13:03:50 -07001447 } // for
1448 }
David Sehr7629f602016-08-07 16:01:51 -07001449
1450 // Fields and methods.
1451 dex_ir::ClassData* class_data = class_def->GetClassData();
1452 // Prepare data for static fields.
Jeff Hao3ab96b42016-09-09 18:35:01 -07001453 dex_ir::EncodedArrayItem* static_values = class_def->StaticValues();
1454 dex_ir::EncodedValueVector* encoded_values =
1455 static_values == nullptr ? nullptr : static_values->GetEncodedValues();
1456 const uint32_t encoded_values_size = (encoded_values == nullptr) ? 0 : encoded_values->size();
David Sehr7629f602016-08-07 16:01:51 -07001457
1458 // Static fields.
1459 if (options_.output_format_ == kOutputPlain) {
1460 fprintf(out_file_, " Static fields -\n");
1461 }
David Sehr853a8e12016-09-01 13:03:50 -07001462 if (class_data != nullptr) {
1463 dex_ir::FieldItemVector* static_fields = class_data->StaticFields();
1464 if (static_fields != nullptr) {
1465 for (uint32_t i = 0; i < static_fields->size(); i++) {
Jeff Haoea7c6292016-11-14 18:10:16 -08001466 DumpSField((*static_fields)[i]->GetFieldId()->GetIndex(),
David Sehr853a8e12016-09-01 13:03:50 -07001467 (*static_fields)[i]->GetAccessFlags(),
1468 i,
Jeff Hao3ab96b42016-09-09 18:35:01 -07001469 i < encoded_values_size ? (*encoded_values)[i].get() : nullptr);
David Sehr853a8e12016-09-01 13:03:50 -07001470 } // for
1471 }
1472 }
David Sehr7629f602016-08-07 16:01:51 -07001473
1474 // Instance fields.
1475 if (options_.output_format_ == kOutputPlain) {
1476 fprintf(out_file_, " Instance fields -\n");
1477 }
David Sehr853a8e12016-09-01 13:03:50 -07001478 if (class_data != nullptr) {
1479 dex_ir::FieldItemVector* instance_fields = class_data->InstanceFields();
1480 if (instance_fields != nullptr) {
1481 for (uint32_t i = 0; i < instance_fields->size(); i++) {
Jeff Haoea7c6292016-11-14 18:10:16 -08001482 DumpIField((*instance_fields)[i]->GetFieldId()->GetIndex(),
David Sehr853a8e12016-09-01 13:03:50 -07001483 (*instance_fields)[i]->GetAccessFlags(),
1484 i);
1485 } // for
1486 }
1487 }
David Sehr7629f602016-08-07 16:01:51 -07001488
1489 // Direct methods.
1490 if (options_.output_format_ == kOutputPlain) {
1491 fprintf(out_file_, " Direct methods -\n");
1492 }
David Sehr853a8e12016-09-01 13:03:50 -07001493 if (class_data != nullptr) {
1494 dex_ir::MethodItemVector* direct_methods = class_data->DirectMethods();
1495 if (direct_methods != nullptr) {
1496 for (uint32_t i = 0; i < direct_methods->size(); i++) {
Jeff Haoea7c6292016-11-14 18:10:16 -08001497 DumpMethod((*direct_methods)[i]->GetMethodId()->GetIndex(),
David Sehr853a8e12016-09-01 13:03:50 -07001498 (*direct_methods)[i]->GetAccessFlags(),
1499 (*direct_methods)[i]->GetCodeItem(),
1500 i);
1501 } // for
1502 }
1503 }
David Sehr7629f602016-08-07 16:01:51 -07001504
1505 // Virtual methods.
1506 if (options_.output_format_ == kOutputPlain) {
1507 fprintf(out_file_, " Virtual methods -\n");
1508 }
David Sehr853a8e12016-09-01 13:03:50 -07001509 if (class_data != nullptr) {
1510 dex_ir::MethodItemVector* virtual_methods = class_data->VirtualMethods();
1511 if (virtual_methods != nullptr) {
1512 for (uint32_t i = 0; i < virtual_methods->size(); i++) {
Jeff Haoea7c6292016-11-14 18:10:16 -08001513 DumpMethod((*virtual_methods)[i]->GetMethodId()->GetIndex(),
David Sehr853a8e12016-09-01 13:03:50 -07001514 (*virtual_methods)[i]->GetAccessFlags(),
1515 (*virtual_methods)[i]->GetCodeItem(),
1516 i);
1517 } // for
1518 }
1519 }
David Sehr7629f602016-08-07 16:01:51 -07001520
1521 // End of class.
1522 if (options_.output_format_ == kOutputPlain) {
1523 const char* file_name = "unknown";
1524 if (class_def->SourceFile() != nullptr) {
1525 file_name = class_def->SourceFile()->Data();
1526 }
1527 const dex_ir::StringId* source_file = class_def->SourceFile();
1528 fprintf(out_file_, " source_file_idx : %d (%s)\n\n",
Jeff Hao3ab96b42016-09-09 18:35:01 -07001529 source_file == nullptr ? 0xffffffffU : source_file->GetIndex(), file_name);
David Sehr7629f602016-08-07 16:01:51 -07001530 } else if (options_.output_format_ == kOutputXml) {
1531 fprintf(out_file_, "</class>\n");
1532 }
1533
1534 free(access_str);
1535}
1536
Jeff Haoea7c6292016-11-14 18:10:16 -08001537void DexLayout::DumpDexFile() {
David Sehr7629f602016-08-07 16:01:51 -07001538 // Headers.
1539 if (options_.show_file_headers_) {
Jeff Haoea7c6292016-11-14 18:10:16 -08001540 DumpFileHeader();
David Sehr7629f602016-08-07 16:01:51 -07001541 }
1542
1543 // Open XML context.
1544 if (options_.output_format_ == kOutputXml) {
1545 fprintf(out_file_, "<api>\n");
1546 }
1547
1548 // Iterate over all classes.
1549 char* package = nullptr;
Jeff Haoea7c6292016-11-14 18:10:16 -08001550 const uint32_t class_defs_size = header_->GetCollections().ClassDefsSize();
David Sehr7629f602016-08-07 16:01:51 -07001551 for (uint32_t i = 0; i < class_defs_size; i++) {
Jeff Haoea7c6292016-11-14 18:10:16 -08001552 DumpClass(i, &package);
David Sehr7629f602016-08-07 16:01:51 -07001553 } // for
1554
1555 // Free the last package allocated.
1556 if (package != nullptr) {
1557 fprintf(out_file_, "</package>\n");
1558 free(package);
1559 }
1560
1561 // Close XML context.
1562 if (options_.output_format_ == kOutputXml) {
1563 fprintf(out_file_, "</api>\n");
1564 }
Jeff Haoea7c6292016-11-14 18:10:16 -08001565}
Jeff Hao3ab96b42016-09-09 18:35:01 -07001566
Jeff Haoe17f5892017-02-23 16:14:04 -08001567std::vector<dex_ir::ClassData*> DexLayout::LayoutClassDefsAndClassData(const DexFile* dex_file) {
Jeff Hao042e8982016-10-19 11:17:11 -07001568 std::vector<dex_ir::ClassDef*> new_class_def_order;
1569 for (std::unique_ptr<dex_ir::ClassDef>& class_def : header_->GetCollections().ClassDefs()) {
1570 dex::TypeIndex type_idx(class_def->ClassType()->GetIndex());
1571 if (info_->ContainsClass(*dex_file, type_idx)) {
1572 new_class_def_order.push_back(class_def.get());
1573 }
1574 }
1575 for (std::unique_ptr<dex_ir::ClassDef>& class_def : header_->GetCollections().ClassDefs()) {
1576 dex::TypeIndex type_idx(class_def->ClassType()->GetIndex());
1577 if (!info_->ContainsClass(*dex_file, type_idx)) {
1578 new_class_def_order.push_back(class_def.get());
1579 }
1580 }
1581 uint32_t class_defs_offset = header_->GetCollections().ClassDefsOffset();
1582 uint32_t class_data_offset = header_->GetCollections().ClassDatasOffset();
Jeff Haoe17f5892017-02-23 16:14:04 -08001583 std::unordered_set<dex_ir::ClassData*> visited_class_data;
1584 std::vector<dex_ir::ClassData*> new_class_data_order;
Jeff Hao042e8982016-10-19 11:17:11 -07001585 for (uint32_t i = 0; i < new_class_def_order.size(); ++i) {
1586 dex_ir::ClassDef* class_def = new_class_def_order[i];
Mathieu Chartier24066ec2017-10-21 16:01:08 -07001587 if (kChangeClassDefOrder) {
1588 // This produces dex files that violate the spec since the super class class_def is supposed
1589 // to occur before any subclasses.
1590 class_def->SetIndex(i);
1591 class_def->SetOffset(class_defs_offset);
1592 class_defs_offset += dex_ir::ClassDef::ItemSize();
1593 }
Jeff Haoe17f5892017-02-23 16:14:04 -08001594 dex_ir::ClassData* class_data = class_def->GetClassData();
1595 if (class_data != nullptr && visited_class_data.find(class_data) == visited_class_data.end()) {
1596 class_data->SetOffset(class_data_offset);
1597 class_data_offset += class_data->GetSize();
1598 visited_class_data.insert(class_data);
1599 new_class_data_order.push_back(class_data);
Jeff Hao042e8982016-10-19 11:17:11 -07001600 }
1601 }
Jeff Haoe17f5892017-02-23 16:14:04 -08001602 return new_class_data_order;
Jeff Hao042e8982016-10-19 11:17:11 -07001603}
1604
Mathieu Chartier24066ec2017-10-21 16:01:08 -07001605int32_t DexLayout::LayoutStringData(const DexFile* dex_file) {
Mathieu Chartierfa0aa092017-03-27 15:43:54 -07001606 const size_t num_strings = header_->GetCollections().StringIds().size();
1607 std::vector<bool> is_shorty(num_strings, false);
1608 std::vector<bool> from_hot_method(num_strings, false);
1609 for (std::unique_ptr<dex_ir::ClassDef>& class_def : header_->GetCollections().ClassDefs()) {
1610 // 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 -07001611 // as hot. Add its super class and interfaces as well, which can be used during initialization.
Mathieu Chartierfa0aa092017-03-27 15:43:54 -07001612 const bool is_profile_class =
1613 info_->ContainsClass(*dex_file, dex::TypeIndex(class_def->ClassType()->GetIndex()));
1614 if (is_profile_class) {
1615 from_hot_method[class_def->ClassType()->GetStringId()->GetIndex()] = true;
Jeff Haoacc83d72017-07-06 17:51:01 -07001616 const dex_ir::TypeId* superclass = class_def->Superclass();
1617 if (superclass != nullptr) {
1618 from_hot_method[superclass->GetStringId()->GetIndex()] = true;
1619 }
1620 const dex_ir::TypeList* interfaces = class_def->Interfaces();
1621 if (interfaces != nullptr) {
1622 for (const dex_ir::TypeId* interface_type : *interfaces->GetTypeList()) {
1623 from_hot_method[interface_type->GetStringId()->GetIndex()] = true;
1624 }
1625 }
Mathieu Chartierfa0aa092017-03-27 15:43:54 -07001626 }
1627 dex_ir::ClassData* data = class_def->GetClassData();
1628 if (data == nullptr) {
1629 continue;
1630 }
1631 for (size_t i = 0; i < 2; ++i) {
1632 for (auto& method : *(i == 0 ? data->DirectMethods() : data->VirtualMethods())) {
1633 const dex_ir::MethodId* method_id = method->GetMethodId();
1634 dex_ir::CodeItem* code_item = method->GetCodeItem();
1635 if (code_item == nullptr) {
1636 continue;
1637 }
1638 const bool is_clinit = is_profile_class &&
1639 (method->GetAccessFlags() & kAccConstructor) != 0 &&
1640 (method->GetAccessFlags() & kAccStatic) != 0;
1641 const bool method_executed = is_clinit ||
Mathieu Chartiere46f3a82017-06-19 19:54:12 -07001642 info_->GetMethodHotness(MethodReference(dex_file, method_id->GetIndex())).IsInProfile();
Mathieu Chartierfa0aa092017-03-27 15:43:54 -07001643 if (!method_executed) {
1644 continue;
1645 }
1646 is_shorty[method_id->Proto()->Shorty()->GetIndex()] = true;
1647 dex_ir::CodeFixups* fixups = code_item->GetCodeFixups();
1648 if (fixups == nullptr) {
1649 continue;
1650 }
Jeff Haoacc83d72017-07-06 17:51:01 -07001651 // Add const-strings.
1652 for (dex_ir::StringId* id : *fixups->StringIds()) {
1653 from_hot_method[id->GetIndex()] = true;
Mathieu Chartierfa0aa092017-03-27 15:43:54 -07001654 }
Jeff Haoacc83d72017-07-06 17:51:01 -07001655 // Add field classes, names, and types.
Mathieu Chartierfa0aa092017-03-27 15:43:54 -07001656 for (dex_ir::FieldId* id : *fixups->FieldIds()) {
Jeff Haoacc83d72017-07-06 17:51:01 -07001657 // TODO: Only visit field ids from static getters and setters.
1658 from_hot_method[id->Class()->GetStringId()->GetIndex()] = true;
Mathieu Chartierfa0aa092017-03-27 15:43:54 -07001659 from_hot_method[id->Name()->GetIndex()] = true;
1660 from_hot_method[id->Type()->GetStringId()->GetIndex()] = true;
1661 }
Jeff Haoacc83d72017-07-06 17:51:01 -07001662 // For clinits, add referenced method classes, names, and protos.
1663 if (is_clinit) {
1664 for (dex_ir::MethodId* id : *fixups->MethodIds()) {
1665 from_hot_method[id->Class()->GetStringId()->GetIndex()] = true;
1666 from_hot_method[id->Name()->GetIndex()] = true;
1667 is_shorty[id->Proto()->Shorty()->GetIndex()] = true;
1668 }
1669 }
Mathieu Chartierfa0aa092017-03-27 15:43:54 -07001670 }
1671 }
1672 }
1673 // Sort string data by specified order.
1674 std::vector<dex_ir::StringId*> string_ids;
1675 size_t min_offset = std::numeric_limits<size_t>::max();
1676 size_t max_offset = 0;
1677 size_t hot_bytes = 0;
1678 for (auto& string_id : header_->GetCollections().StringIds()) {
1679 string_ids.push_back(string_id.get());
1680 const size_t cur_offset = string_id->DataItem()->GetOffset();
1681 CHECK_NE(cur_offset, 0u);
1682 min_offset = std::min(min_offset, cur_offset);
1683 dex_ir::StringData* data = string_id->DataItem();
1684 const size_t element_size = data->GetSize() + 1; // Add one extra for null.
1685 size_t end_offset = cur_offset + element_size;
1686 if (is_shorty[string_id->GetIndex()] || from_hot_method[string_id->GetIndex()]) {
1687 hot_bytes += element_size;
1688 }
1689 max_offset = std::max(max_offset, end_offset);
1690 }
1691 VLOG(compiler) << "Hot string data bytes " << hot_bytes << "/" << max_offset - min_offset;
1692 std::sort(string_ids.begin(),
1693 string_ids.end(),
1694 [&is_shorty, &from_hot_method](const dex_ir::StringId* a,
1695 const dex_ir::StringId* b) {
1696 const bool a_is_hot = from_hot_method[a->GetIndex()];
1697 const bool b_is_hot = from_hot_method[b->GetIndex()];
1698 if (a_is_hot != b_is_hot) {
1699 return a_is_hot < b_is_hot;
1700 }
1701 // After hot methods are partitioned, subpartition shorties.
1702 const bool a_is_shorty = is_shorty[a->GetIndex()];
1703 const bool b_is_shorty = is_shorty[b->GetIndex()];
1704 if (a_is_shorty != b_is_shorty) {
1705 return a_is_shorty < b_is_shorty;
1706 }
1707 // Preserve order.
1708 return a->DataItem()->GetOffset() < b->DataItem()->GetOffset();
1709 });
1710 // Now we know what order we want the string data, reorder the offsets.
1711 size_t offset = min_offset;
1712 for (dex_ir::StringId* string_id : string_ids) {
1713 dex_ir::StringData* data = string_id->DataItem();
1714 data->SetOffset(offset);
1715 offset += data->GetSize() + 1; // Add one extra for null.
1716 }
1717 if (offset > max_offset) {
Mathieu Chartier24066ec2017-10-21 16:01:08 -07001718 return offset - max_offset;
Mathieu Chartierfa0aa092017-03-27 15:43:54 -07001719 // If we expanded the string data section, we need to update the offsets or else we will
1720 // corrupt the next section when writing out.
Mathieu Chartierfa0aa092017-03-27 15:43:54 -07001721 }
Mathieu Chartier24066ec2017-10-21 16:01:08 -07001722 return 0;
Mathieu Chartierfa0aa092017-03-27 15:43:54 -07001723}
1724
Jeff Haoe17f5892017-02-23 16:14:04 -08001725// Orders code items according to specified class data ordering.
1726// NOTE: If the section following the code items is byte aligned, the last code item is left in
1727// place to preserve alignment. Layout needs an overhaul to handle movement of other sections.
Shubham Ajmera36a282b2017-04-03 10:04:28 -07001728int32_t DexLayout::LayoutCodeItems(const DexFile* dex_file,
1729 std::vector<dex_ir::ClassData*> new_class_data_order) {
Jeff Hao863f1d72017-03-01 12:18:19 -08001730 // Do not move code items if class data section precedes code item section.
1731 // ULEB encoding is variable length, causing problems determining the offset of the code items.
1732 // TODO: We should swap the order of these sections in the future to avoid this issue.
1733 uint32_t class_data_offset = header_->GetCollections().ClassDatasOffset();
1734 uint32_t code_item_offset = header_->GetCollections().CodeItemsOffset();
1735 if (class_data_offset < code_item_offset) {
1736 return 0;
1737 }
1738
Jeff Haoe17f5892017-02-23 16:14:04 -08001739 // 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 -07001740 dex_ir::CodeItem* last_code_item = nullptr;
Jeff Haoe17f5892017-02-23 16:14:04 -08001741 std::unordered_set<dex_ir::CodeItem*> visited_code_items;
Jeff Hao863f1d72017-03-01 12:18:19 -08001742 bool is_code_item_aligned = IsNextSectionCodeItemAligned(code_item_offset);
Jeff Haoe17f5892017-02-23 16:14:04 -08001743 if (!is_code_item_aligned) {
Jeff Haoe17f5892017-02-23 16:14:04 -08001744 for (auto& code_item_pair : header_->GetCollections().CodeItems()) {
1745 std::unique_ptr<dex_ir::CodeItem>& code_item = code_item_pair.second;
Shubham Ajmera36a282b2017-04-03 10:04:28 -07001746 if (last_code_item == nullptr
1747 || last_code_item->GetOffset() < code_item->GetOffset()) {
Jeff Haoe17f5892017-02-23 16:14:04 -08001748 last_code_item = code_item.get();
Jeff Hao042e8982016-10-19 11:17:11 -07001749 }
Jeff Haoe17f5892017-02-23 16:14:04 -08001750 }
Jeff Haoe17f5892017-02-23 16:14:04 -08001751 }
1752
Shubham Ajmera36a282b2017-04-03 10:04:28 -07001753 static constexpr InvokeType invoke_types[] = {
Mathieu Chartier7c1be8b2017-06-15 13:56:05 -07001754 kDirect,
1755 kVirtual
Shubham Ajmera36a282b2017-04-03 10:04:28 -07001756 };
1757
Mathieu Chartier120aa282017-08-05 16:03:03 -07001758 const size_t num_layout_types = static_cast<size_t>(LayoutType::kLayoutTypeCount);
1759 std::unordered_set<dex_ir::CodeItem*> code_items[num_layout_types];
Shubham Ajmera36a282b2017-04-03 10:04:28 -07001760 for (InvokeType invoke_type : invoke_types) {
1761 for (std::unique_ptr<dex_ir::ClassDef>& class_def : header_->GetCollections().ClassDefs()) {
1762 const bool is_profile_class =
1763 info_->ContainsClass(*dex_file, dex::TypeIndex(class_def->ClassType()->GetIndex()));
1764
1765 // Skip classes that are not defined in this dex file.
1766 dex_ir::ClassData* class_data = class_def->GetClassData();
1767 if (class_data == nullptr) {
1768 continue;
Jeff Haoe17f5892017-02-23 16:14:04 -08001769 }
Shubham Ajmera36a282b2017-04-03 10:04:28 -07001770 for (auto& method : *(invoke_type == InvokeType::kDirect
1771 ? class_data->DirectMethods()
1772 : class_data->VirtualMethods())) {
1773 const dex_ir::MethodId *method_id = method->GetMethodId();
1774 dex_ir::CodeItem *code_item = method->GetCodeItem();
1775 if (code_item == last_code_item || code_item == nullptr) {
1776 continue;
1777 }
1778 // Separate executed methods (clinits and profiled methods) from unexecuted methods.
Mathieu Chartier7c1be8b2017-06-15 13:56:05 -07001779 const bool is_clinit = (method->GetAccessFlags() & kAccConstructor) != 0 &&
Shubham Ajmera36a282b2017-04-03 10:04:28 -07001780 (method->GetAccessFlags() & kAccStatic) != 0;
Mathieu Chartier7c1be8b2017-06-15 13:56:05 -07001781 const bool is_startup_clinit = is_profile_class && is_clinit;
1782 using Hotness = ProfileCompilationInfo::MethodHotness;
1783 Hotness hotness = info_->GetMethodHotness(MethodReference(dex_file, method_id->GetIndex()));
Mathieu Chartier120aa282017-08-05 16:03:03 -07001784 LayoutType state = LayoutType::kLayoutTypeUnused;
Mathieu Chartier7c1be8b2017-06-15 13:56:05 -07001785 if (hotness.IsHot()) {
1786 // Hot code is compiled, maybe one day it won't be accessed. So lay it out together for
1787 // now.
Mathieu Chartier120aa282017-08-05 16:03:03 -07001788 state = LayoutType::kLayoutTypeHot;
Mathieu Chartier7c1be8b2017-06-15 13:56:05 -07001789 } else if (is_startup_clinit || hotness.GetFlags() == Hotness::kFlagStartup) {
1790 // Startup clinit or a method that only has the startup flag.
Mathieu Chartier120aa282017-08-05 16:03:03 -07001791 state = LayoutType::kLayoutTypeStartupOnly;
Mathieu Chartier7c1be8b2017-06-15 13:56:05 -07001792 } else if (is_clinit) {
Mathieu Chartier120aa282017-08-05 16:03:03 -07001793 state = LayoutType::kLayoutTypeUsedOnce;
Mathieu Chartiere46f3a82017-06-19 19:54:12 -07001794 } else if (hotness.IsInProfile()) {
Mathieu Chartier120aa282017-08-05 16:03:03 -07001795 state = LayoutType::kLayoutTypeSometimesUsed;
Jeff Hao206cbaa2017-06-07 19:11:01 -07001796 }
Mathieu Chartier120aa282017-08-05 16:03:03 -07001797 code_items[static_cast<size_t>(state)].insert(code_item);
Jeff Hao042e8982016-10-19 11:17:11 -07001798 }
1799 }
1800 }
Shubham Ajmera36a282b2017-04-03 10:04:28 -07001801
David Sehrb4156282017-10-19 17:57:02 -07001802 // Removing duplicate CodeItems may expose other issues with downstream
1803 // optimizations such as quickening. But we need to ensure at least the weak
1804 // forms of it currently in use do not break layout optimizations.
1805 std::map<dex_ir::CodeItem*, uint32_t> original_code_item_offset;
Jeff Hao206cbaa2017-06-07 19:11:01 -07001806 // Total_diff includes diffs generated by clinits, executed, and non-executed methods.
Shubham Ajmera36a282b2017-04-03 10:04:28 -07001807 int32_t total_diff = 0;
1808 // The relative placement has no effect on correctness; it is used to ensure
1809 // the layout is deterministic
Mathieu Chartier120aa282017-08-05 16:03:03 -07001810 for (size_t index = 0; index < num_layout_types; ++index) {
1811 const std::unordered_set<dex_ir::CodeItem*>& code_items_set = code_items[index];
Jeff Hao206cbaa2017-06-07 19:11:01 -07001812 // diff is reset for each class of code items.
Shubham Ajmera36a282b2017-04-03 10:04:28 -07001813 int32_t diff = 0;
Mathieu Chartier120aa282017-08-05 16:03:03 -07001814 const uint32_t start_offset = code_item_offset;
Shubham Ajmera36a282b2017-04-03 10:04:28 -07001815 for (dex_ir::ClassData* data : new_class_data_order) {
1816 data->SetOffset(data->GetOffset() + diff);
1817 for (InvokeType invoke_type : invoke_types) {
1818 for (auto &method : *(invoke_type == InvokeType::kDirect
1819 ? data->DirectMethods()
1820 : data->VirtualMethods())) {
1821 dex_ir::CodeItem* code_item = method->GetCodeItem();
1822 if (code_item != nullptr &&
1823 code_items_set.find(code_item) != code_items_set.end()) {
David Sehrb4156282017-10-19 17:57:02 -07001824 // Compute where the CodeItem was originally laid out.
1825 uint32_t original_offset = code_item->GetOffset();
1826 auto it = original_code_item_offset.find(code_item);
1827 if (it != original_code_item_offset.end()) {
1828 original_offset = it->second;
1829 } else {
1830 original_code_item_offset[code_item] = code_item->GetOffset();
1831 // Assign the new offset and move the pointer to allocate space.
1832 code_item->SetOffset(code_item_offset);
1833 code_item_offset +=
1834 RoundUp(code_item->GetSize(), kDexCodeItemAlignment);
1835 }
1836 // Update the size of the encoded methods to reflect that the offset difference
1837 // may have changed the ULEB128 length.
1838 diff +=
1839 UnsignedLeb128Size(code_item->GetOffset()) - UnsignedLeb128Size(original_offset);
Shubham Ajmera36a282b2017-04-03 10:04:28 -07001840 }
1841 }
1842 }
1843 }
Mathieu Chartier120aa282017-08-05 16:03:03 -07001844 DexLayoutSection& code_section = dex_sections_.sections_[static_cast<size_t>(
1845 DexLayoutSections::SectionType::kSectionTypeCode)];
1846 code_section.parts_[index].offset_ = start_offset;
1847 code_section.parts_[index].size_ = code_item_offset - start_offset;
1848 for (size_t i = 0; i < num_layout_types; ++i) {
Mathieu Chartier7c1be8b2017-06-15 13:56:05 -07001849 VLOG(dex) << "Code item layout bucket " << i << " count=" << code_items[i].size()
Mathieu Chartier120aa282017-08-05 16:03:03 -07001850 << " bytes=" << code_section.parts_[i].size_;
Mathieu Chartier7c1be8b2017-06-15 13:56:05 -07001851 }
Shubham Ajmera36a282b2017-04-03 10:04:28 -07001852 total_diff += diff;
1853 }
Jeff Haoe17f5892017-02-23 16:14:04 -08001854 // Adjust diff to be 4-byte aligned.
Shubham Ajmera36a282b2017-04-03 10:04:28 -07001855 return RoundUp(total_diff, kDexCodeItemAlignment);
Jeff Haoe17f5892017-02-23 16:14:04 -08001856}
Jeff Hao042e8982016-10-19 11:17:11 -07001857
Jeff Haoe17f5892017-02-23 16:14:04 -08001858bool DexLayout::IsNextSectionCodeItemAligned(uint32_t offset) {
1859 dex_ir::Collections& collections = header_->GetCollections();
1860 std::set<uint32_t> section_offsets;
1861 section_offsets.insert(collections.MapListOffset());
1862 section_offsets.insert(collections.TypeListsOffset());
1863 section_offsets.insert(collections.AnnotationSetRefListsOffset());
1864 section_offsets.insert(collections.AnnotationSetItemsOffset());
1865 section_offsets.insert(collections.ClassDatasOffset());
1866 section_offsets.insert(collections.CodeItemsOffset());
1867 section_offsets.insert(collections.StringDatasOffset());
1868 section_offsets.insert(collections.DebugInfoItemsOffset());
1869 section_offsets.insert(collections.AnnotationItemsOffset());
1870 section_offsets.insert(collections.EncodedArrayItemsOffset());
1871 section_offsets.insert(collections.AnnotationsDirectoryItemsOffset());
1872
1873 auto found = section_offsets.find(offset);
1874 if (found != section_offsets.end()) {
1875 found++;
1876 if (found != section_offsets.end()) {
1877 return *found % kDexCodeItemAlignment == 0;
1878 }
1879 }
1880 return false;
Jeff Hao042e8982016-10-19 11:17:11 -07001881}
1882
1883// Adjust offsets of every item in the specified section by diff bytes.
1884template<class T> void DexLayout::FixupSection(std::map<uint32_t, std::unique_ptr<T>>& map,
1885 uint32_t diff) {
1886 for (auto& pair : map) {
1887 std::unique_ptr<T>& item = pair.second;
1888 item->SetOffset(item->GetOffset() + diff);
1889 }
1890}
1891
1892// Adjust offsets of all sections with an address after the specified offset by diff bytes.
1893void DexLayout::FixupSections(uint32_t offset, uint32_t diff) {
1894 dex_ir::Collections& collections = header_->GetCollections();
1895 uint32_t map_list_offset = collections.MapListOffset();
1896 if (map_list_offset > offset) {
1897 collections.SetMapListOffset(map_list_offset + diff);
1898 }
1899
1900 uint32_t type_lists_offset = collections.TypeListsOffset();
1901 if (type_lists_offset > offset) {
1902 collections.SetTypeListsOffset(type_lists_offset + diff);
1903 FixupSection(collections.TypeLists(), diff);
1904 }
1905
1906 uint32_t annotation_set_ref_lists_offset = collections.AnnotationSetRefListsOffset();
1907 if (annotation_set_ref_lists_offset > offset) {
1908 collections.SetAnnotationSetRefListsOffset(annotation_set_ref_lists_offset + diff);
1909 FixupSection(collections.AnnotationSetRefLists(), diff);
1910 }
1911
1912 uint32_t annotation_set_items_offset = collections.AnnotationSetItemsOffset();
1913 if (annotation_set_items_offset > offset) {
1914 collections.SetAnnotationSetItemsOffset(annotation_set_items_offset + diff);
1915 FixupSection(collections.AnnotationSetItems(), diff);
1916 }
1917
1918 uint32_t class_datas_offset = collections.ClassDatasOffset();
1919 if (class_datas_offset > offset) {
1920 collections.SetClassDatasOffset(class_datas_offset + diff);
1921 FixupSection(collections.ClassDatas(), diff);
1922 }
1923
1924 uint32_t code_items_offset = collections.CodeItemsOffset();
1925 if (code_items_offset > offset) {
1926 collections.SetCodeItemsOffset(code_items_offset + diff);
1927 FixupSection(collections.CodeItems(), diff);
1928 }
1929
1930 uint32_t string_datas_offset = collections.StringDatasOffset();
1931 if (string_datas_offset > offset) {
1932 collections.SetStringDatasOffset(string_datas_offset + diff);
1933 FixupSection(collections.StringDatas(), diff);
1934 }
1935
1936 uint32_t debug_info_items_offset = collections.DebugInfoItemsOffset();
1937 if (debug_info_items_offset > offset) {
1938 collections.SetDebugInfoItemsOffset(debug_info_items_offset + diff);
1939 FixupSection(collections.DebugInfoItems(), diff);
1940 }
1941
1942 uint32_t annotation_items_offset = collections.AnnotationItemsOffset();
1943 if (annotation_items_offset > offset) {
1944 collections.SetAnnotationItemsOffset(annotation_items_offset + diff);
1945 FixupSection(collections.AnnotationItems(), diff);
1946 }
1947
1948 uint32_t encoded_array_items_offset = collections.EncodedArrayItemsOffset();
1949 if (encoded_array_items_offset > offset) {
1950 collections.SetEncodedArrayItemsOffset(encoded_array_items_offset + diff);
1951 FixupSection(collections.EncodedArrayItems(), diff);
1952 }
1953
1954 uint32_t annotations_directory_items_offset = collections.AnnotationsDirectoryItemsOffset();
1955 if (annotations_directory_items_offset > offset) {
1956 collections.SetAnnotationsDirectoryItemsOffset(annotations_directory_items_offset + diff);
1957 FixupSection(collections.AnnotationsDirectoryItems(), diff);
1958 }
1959}
1960
1961void DexLayout::LayoutOutputFile(const DexFile* dex_file) {
Mathieu Chartier24066ec2017-10-21 16:01:08 -07001962 const int32_t string_diff = LayoutStringData(dex_file);
1963 // If we expanded the string data section, we need to update the offsets or else we will
1964 // corrupt the next section when writing out.
1965 FixupSections(header_->GetCollections().StringDatasOffset(), string_diff);
Jeff Hao042e8982016-10-19 11:17:11 -07001966 // Update file size.
Mathieu Chartier24066ec2017-10-21 16:01:08 -07001967 header_->SetFileSize(header_->FileSize() + string_diff);
1968
1969 std::vector<dex_ir::ClassData*> new_class_data_order = LayoutClassDefsAndClassData(dex_file);
1970 const int32_t code_item_diff = LayoutCodeItems(dex_file, new_class_data_order);
1971 // Move sections after ClassData by diff bytes.
1972 FixupSections(header_->GetCollections().ClassDatasOffset(), code_item_diff);
1973
1974 // Update file and data size.
1975 // The data size must be aligned to kDataSectionAlignment.
1976 const int32_t total_diff = code_item_diff + string_diff;
1977 header_->SetDataSize(RoundUp(header_->DataSize() + total_diff, kDataSectionAlignment));
1978 header_->SetFileSize(header_->FileSize() + total_diff);
Jeff Hao042e8982016-10-19 11:17:11 -07001979}
1980
Jeff Haoec7f1a92017-03-13 16:24:24 -07001981void DexLayout::OutputDexFile(const DexFile* dex_file) {
1982 const std::string& dex_file_location = dex_file->GetLocation();
Jeff Haoea7c6292016-11-14 18:10:16 -08001983 std::string error_msg;
1984 std::unique_ptr<File> new_file;
1985 if (!options_.output_to_memmap_) {
Jeff Haoa8621002016-10-04 18:13:44 +00001986 std::string output_location(options_.output_dex_directory_);
Andreas Gampe37c58462017-03-27 15:14:27 -07001987 size_t last_slash = dex_file_location.rfind('/');
Jeff Haoea7c6292016-11-14 18:10:16 -08001988 std::string dex_file_directory = dex_file_location.substr(0, last_slash + 1);
1989 if (output_location == dex_file_directory) {
1990 output_location = dex_file_location + ".new";
1991 } else if (last_slash != std::string::npos) {
1992 output_location += dex_file_location.substr(last_slash);
1993 } else {
1994 output_location += "/" + dex_file_location + ".new";
1995 }
1996 new_file.reset(OS::CreateEmptyFile(output_location.c_str()));
Jeff Hao3ba51e82017-04-12 16:14:54 -07001997 if (new_file == nullptr) {
1998 LOG(ERROR) << "Could not create dex writer output file: " << output_location;
1999 return;
2000 }
David Sehr7639cdc2017-04-15 10:06:21 -07002001 if (ftruncate(new_file->Fd(), header_->FileSize()) != 0) {
2002 LOG(ERROR) << "Could not grow dex writer output file: " << output_location;;
2003 new_file->Erase();
2004 return;
2005 }
Jeff Haoea7c6292016-11-14 18:10:16 -08002006 mem_map_.reset(MemMap::MapFile(header_->FileSize(), PROT_READ | PROT_WRITE, MAP_SHARED,
2007 new_file->Fd(), 0, /*low_4gb*/ false, output_location.c_str(), &error_msg));
2008 } else {
2009 mem_map_.reset(MemMap::MapAnonymous("layout dex", nullptr, header_->FileSize(),
2010 PROT_READ | PROT_WRITE, /* low_4gb */ false, /* reuse */ false, &error_msg));
2011 }
2012 if (mem_map_ == nullptr) {
2013 LOG(ERROR) << "Could not create mem map for dex writer output: " << error_msg;
Jeff Hao3ba51e82017-04-12 16:14:54 -07002014 if (new_file != nullptr) {
Jeff Haoea7c6292016-11-14 18:10:16 -08002015 new_file->Erase();
2016 }
2017 return;
2018 }
Mathieu Chartier603ccab2017-10-20 14:34:28 -07002019 DexWriter::Output(header_, mem_map_.get(), options_.compact_dex_level_);
Jeff Haoea7c6292016-11-14 18:10:16 -08002020 if (new_file != nullptr) {
2021 UNUSED(new_file->FlushCloseOrErase());
2022 }
2023}
2024
2025/*
2026 * Dumps the requested sections of the file.
2027 */
2028void DexLayout::ProcessDexFile(const char* file_name,
2029 const DexFile* dex_file,
2030 size_t dex_file_index) {
2031 std::unique_ptr<dex_ir::Header> header(dex_ir::DexIrBuilder(*dex_file));
2032 SetHeader(header.get());
2033
2034 if (options_.verbose_) {
2035 fprintf(out_file_, "Opened '%s', DEX version '%.3s'\n",
2036 file_name, dex_file->GetHeader().magic_ + 4);
2037 }
2038
2039 if (options_.visualize_pattern_) {
2040 VisualizeDexLayout(header_, dex_file, dex_file_index, info_);
2041 return;
2042 }
2043
David Sehr93357492017-03-09 08:02:44 -08002044 if (options_.show_section_statistics_) {
2045 ShowDexSectionStatistics(header_, dex_file_index);
2046 return;
2047 }
2048
Jeff Haoea7c6292016-11-14 18:10:16 -08002049 // Dump dex file.
2050 if (options_.dump_) {
2051 DumpDexFile();
2052 }
2053
Mathieu Chartier2ef3b882017-10-20 19:50:39 -07002054 // In case we are outputting to a file, keep it open so we can verify.
Jeff Haoea7c6292016-11-14 18:10:16 -08002055 if (options_.output_dex_directory_ != nullptr || options_.output_to_memmap_) {
Jeff Hao042e8982016-10-19 11:17:11 -07002056 if (info_ != nullptr) {
2057 LayoutOutputFile(dex_file);
2058 }
Jeff Haoec7f1a92017-03-13 16:24:24 -07002059 OutputDexFile(dex_file);
Mathieu Chartier2ef3b882017-10-20 19:50:39 -07002060
2061 // Clear header before verifying to reduce peak RAM usage.
2062 header.reset();
2063
2064 // Verify the output dex file's structure, only enabled by default for debug builds.
2065 if (options_.verify_output_) {
2066 std::string error_msg;
2067 std::string location = "memory mapped file for " + std::string(file_name);
2068 std::unique_ptr<const DexFile> output_dex_file(DexFileLoader::Open(mem_map_->Begin(),
2069 mem_map_->Size(),
2070 location,
2071 /* checksum */ 0,
2072 /*oat_dex_file*/ nullptr,
2073 /*verify*/ true,
2074 /*verify_checksum*/ false,
2075 &error_msg));
2076 CHECK(output_dex_file != nullptr) << "Failed to re-open output file:" << error_msg;
2077
2078 // Do IR-level comparison between input and output. This check ignores potential differences
2079 // due to layout, so offsets are not checked. Instead, it checks the data contents of each item.
2080 //
2081 // Regenerate output IR to catch any bugs that might happen during writing.
2082 std::unique_ptr<dex_ir::Header> output_header(dex_ir::DexIrBuilder(*output_dex_file));
2083 std::unique_ptr<dex_ir::Header> orig_header(dex_ir::DexIrBuilder(*dex_file));
2084 CHECK(VerifyOutputDexFile(output_header.get(), orig_header.get(), &error_msg)) << error_msg;
2085 }
Jeff Hao3ab96b42016-09-09 18:35:01 -07002086 }
David Sehr7629f602016-08-07 16:01:51 -07002087}
2088
2089/*
2090 * Processes a single file (either direct .dex or indirect .zip/.jar/.apk).
2091 */
Jeff Haoea7c6292016-11-14 18:10:16 -08002092int DexLayout::ProcessFile(const char* file_name) {
David Sehr7629f602016-08-07 16:01:51 -07002093 if (options_.verbose_) {
2094 fprintf(out_file_, "Processing '%s'...\n", file_name);
2095 }
2096
2097 // If the file is not a .dex file, the function tries .zip/.jar/.apk files,
2098 // all of which are Zip archives with "classes.dex" inside.
2099 const bool verify_checksum = !options_.ignore_bad_checksum_;
2100 std::string error_msg;
2101 std::vector<std::unique_ptr<const DexFile>> dex_files;
Nicolas Geoffray095c6c92017-10-19 13:59:55 +01002102 if (!DexFileLoader::Open(
2103 file_name, file_name, /* verify */ true, verify_checksum, &error_msg, &dex_files)) {
David Sehr7629f602016-08-07 16:01:51 -07002104 // Display returned error message to user. Note that this error behavior
2105 // differs from the error messages shown by the original Dalvik dexdump.
2106 fputs(error_msg.c_str(), stderr);
2107 fputc('\n', stderr);
2108 return -1;
2109 }
2110
2111 // Success. Either report checksum verification or process
2112 // all dex files found in given file.
2113 if (options_.checksum_only_) {
2114 fprintf(out_file_, "Checksum verified\n");
2115 } else {
2116 for (size_t i = 0; i < dex_files.size(); i++) {
David Sehrcdcfde72016-09-26 07:44:04 -07002117 ProcessDexFile(file_name, dex_files[i].get(), i);
David Sehr7629f602016-08-07 16:01:51 -07002118 }
2119 }
2120 return 0;
2121}
2122
2123} // namespace art