blob: 005b7874d9a4d1ba62f42e48d37e33b31e2596ed [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>
27
28#include <iostream>
29#include <memory>
30#include <sstream>
31#include <vector>
32
Andreas Gampe46ee31b2016-12-14 10:11:49 -080033#include "android-base/stringprintf.h"
34
David Sehr853a8e12016-09-01 13:03:50 -070035#include "dex_ir_builder.h"
David Sehr7629f602016-08-07 16:01:51 -070036#include "dex_file-inl.h"
37#include "dex_instruction-inl.h"
David Sehrcdcfde72016-09-26 07:44:04 -070038#include "dex_visualize.h"
Jeff Haoa8621002016-10-04 18:13:44 +000039#include "dex_writer.h"
Calin Juravle33083d62017-01-18 15:29:12 -080040#include "jit/profile_compilation_info.h"
Jeff Haoea7c6292016-11-14 18:10:16 -080041#include "mem_map.h"
Nicolas Geoffrayfd1a6c22016-10-04 11:01:17 +000042#include "os.h"
David Sehr7629f602016-08-07 16:01:51 -070043#include "utils.h"
44
45namespace art {
46
Andreas Gampe46ee31b2016-12-14 10:11:49 -080047using android::base::StringPrintf;
48
Jeff Haoe17f5892017-02-23 16:14:04 -080049static constexpr uint32_t kDexCodeItemAlignment = 4;
50
David Sehr7629f602016-08-07 16:01:51 -070051/*
David Sehr7629f602016-08-07 16:01:51 -070052 * Flags for use with createAccessFlagStr().
53 */
54enum AccessFor {
55 kAccessForClass = 0, kAccessForMethod = 1, kAccessForField = 2, kAccessForMAX
56};
57const int kNumFlags = 18;
58
59/*
60 * Gets 2 little-endian bytes.
61 */
62static inline uint16_t Get2LE(unsigned char const* src) {
63 return src[0] | (src[1] << 8);
64}
65
66/*
Jeff Haoc3acfc52016-08-29 14:18:26 -070067 * Converts a type descriptor to human-readable "dotted" form. For
68 * example, "Ljava/lang/String;" becomes "java.lang.String", and
69 * "[I" becomes "int[]". Also converts '$' to '.', which means this
70 * form can't be converted back to a descriptor.
71 */
72static std::string DescriptorToDotWrapper(const char* descriptor) {
73 std::string result = DescriptorToDot(descriptor);
74 size_t found = result.find('$');
75 while (found != std::string::npos) {
76 result[found] = '.';
77 found = result.find('$', found);
78 }
79 return result;
80}
81
82/*
David Sehr7629f602016-08-07 16:01:51 -070083 * Converts the class name portion of a type descriptor to human-readable
84 * "dotted" form. For example, "Ljava/lang/String;" becomes "String".
85 */
86static std::string DescriptorClassToDot(const char* str) {
87 std::string descriptor(str);
88 // Reduce to just the class name prefix.
89 size_t last_slash = descriptor.rfind('/');
90 if (last_slash == std::string::npos) {
91 last_slash = 0;
92 }
93 // Start past the '/' or 'L'.
94 last_slash++;
95
96 // Copy class name over, trimming trailing ';'.
97 size_t size = descriptor.size() - 1 - last_slash;
98 std::string result(descriptor.substr(last_slash, size));
99
100 // Replace '$' with '.'.
101 size_t dollar_sign = result.find('$');
102 while (dollar_sign != std::string::npos) {
103 result[dollar_sign] = '.';
104 dollar_sign = result.find('$', dollar_sign);
105 }
106
107 return result;
108}
109
110/*
111 * Returns string representing the boolean value.
112 */
113static const char* StrBool(bool val) {
114 return val ? "true" : "false";
115}
116
117/*
118 * Returns a quoted string representing the boolean value.
119 */
120static const char* QuotedBool(bool val) {
121 return val ? "\"true\"" : "\"false\"";
122}
123
124/*
125 * Returns a quoted string representing the access flags.
126 */
127static const char* QuotedVisibility(uint32_t access_flags) {
128 if (access_flags & kAccPublic) {
129 return "\"public\"";
130 } else if (access_flags & kAccProtected) {
131 return "\"protected\"";
132 } else if (access_flags & kAccPrivate) {
133 return "\"private\"";
134 } else {
135 return "\"package\"";
136 }
137}
138
139/*
140 * Counts the number of '1' bits in a word.
141 */
142static int CountOnes(uint32_t val) {
143 val = val - ((val >> 1) & 0x55555555);
144 val = (val & 0x33333333) + ((val >> 2) & 0x33333333);
145 return (((val + (val >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24;
146}
147
148/*
149 * Creates a new string with human-readable access flags.
150 *
151 * In the base language the access_flags fields are type uint16_t; in Dalvik they're uint32_t.
152 */
153static char* CreateAccessFlagStr(uint32_t flags, AccessFor for_what) {
154 static const char* kAccessStrings[kAccessForMAX][kNumFlags] = {
155 {
156 "PUBLIC", /* 0x00001 */
157 "PRIVATE", /* 0x00002 */
158 "PROTECTED", /* 0x00004 */
159 "STATIC", /* 0x00008 */
160 "FINAL", /* 0x00010 */
161 "?", /* 0x00020 */
162 "?", /* 0x00040 */
163 "?", /* 0x00080 */
164 "?", /* 0x00100 */
165 "INTERFACE", /* 0x00200 */
166 "ABSTRACT", /* 0x00400 */
167 "?", /* 0x00800 */
168 "SYNTHETIC", /* 0x01000 */
169 "ANNOTATION", /* 0x02000 */
170 "ENUM", /* 0x04000 */
171 "?", /* 0x08000 */
172 "VERIFIED", /* 0x10000 */
173 "OPTIMIZED", /* 0x20000 */
174 }, {
175 "PUBLIC", /* 0x00001 */
176 "PRIVATE", /* 0x00002 */
177 "PROTECTED", /* 0x00004 */
178 "STATIC", /* 0x00008 */
179 "FINAL", /* 0x00010 */
180 "SYNCHRONIZED", /* 0x00020 */
181 "BRIDGE", /* 0x00040 */
182 "VARARGS", /* 0x00080 */
183 "NATIVE", /* 0x00100 */
184 "?", /* 0x00200 */
185 "ABSTRACT", /* 0x00400 */
186 "STRICT", /* 0x00800 */
187 "SYNTHETIC", /* 0x01000 */
188 "?", /* 0x02000 */
189 "?", /* 0x04000 */
190 "MIRANDA", /* 0x08000 */
191 "CONSTRUCTOR", /* 0x10000 */
192 "DECLARED_SYNCHRONIZED", /* 0x20000 */
193 }, {
194 "PUBLIC", /* 0x00001 */
195 "PRIVATE", /* 0x00002 */
196 "PROTECTED", /* 0x00004 */
197 "STATIC", /* 0x00008 */
198 "FINAL", /* 0x00010 */
199 "?", /* 0x00020 */
200 "VOLATILE", /* 0x00040 */
201 "TRANSIENT", /* 0x00080 */
202 "?", /* 0x00100 */
203 "?", /* 0x00200 */
204 "?", /* 0x00400 */
205 "?", /* 0x00800 */
206 "SYNTHETIC", /* 0x01000 */
207 "?", /* 0x02000 */
208 "ENUM", /* 0x04000 */
209 "?", /* 0x08000 */
210 "?", /* 0x10000 */
211 "?", /* 0x20000 */
212 },
213 };
214
215 // Allocate enough storage to hold the expected number of strings,
216 // plus a space between each. We over-allocate, using the longest
217 // string above as the base metric.
218 const int kLongest = 21; // The strlen of longest string above.
219 const int count = CountOnes(flags);
220 char* str;
221 char* cp;
222 cp = str = reinterpret_cast<char*>(malloc(count * (kLongest + 1) + 1));
223
224 for (int i = 0; i < kNumFlags; i++) {
225 if (flags & 0x01) {
226 const char* accessStr = kAccessStrings[for_what][i];
227 const int len = strlen(accessStr);
228 if (cp != str) {
229 *cp++ = ' ';
230 }
231 memcpy(cp, accessStr, len);
232 cp += len;
233 }
234 flags >>= 1;
235 } // for
236
237 *cp = '\0';
238 return str;
239}
240
241static std::string GetSignatureForProtoId(const dex_ir::ProtoId* proto) {
242 if (proto == nullptr) {
243 return "<no signature>";
244 }
245
David Sehr7629f602016-08-07 16:01:51 -0700246 std::string result("(");
Jeff Haoa8621002016-10-04 18:13:44 +0000247 const dex_ir::TypeList* type_list = proto->Parameters();
248 if (type_list != nullptr) {
249 for (const dex_ir::TypeId* type_id : *type_list->GetTypeList()) {
250 result += type_id->GetStringId()->Data();
251 }
David Sehr7629f602016-08-07 16:01:51 -0700252 }
253 result += ")";
254 result += proto->ReturnType()->GetStringId()->Data();
255 return result;
256}
257
258/*
259 * Copies character data from "data" to "out", converting non-ASCII values
260 * to fprintf format chars or an ASCII filler ('.' or '?').
261 *
262 * The output buffer must be able to hold (2*len)+1 bytes. The result is
263 * NULL-terminated.
264 */
265static void Asciify(char* out, const unsigned char* data, size_t len) {
266 while (len--) {
267 if (*data < 0x20) {
268 // Could do more here, but we don't need them yet.
269 switch (*data) {
270 case '\0':
271 *out++ = '\\';
272 *out++ = '0';
273 break;
274 case '\n':
275 *out++ = '\\';
276 *out++ = 'n';
277 break;
278 default:
279 *out++ = '.';
280 break;
281 } // switch
282 } else if (*data >= 0x80) {
283 *out++ = '?';
284 } else {
285 *out++ = *data;
286 }
287 data++;
288 } // while
289 *out = '\0';
290}
291
292/*
293 * Dumps a string value with some escape characters.
294 */
Jeff Haoea7c6292016-11-14 18:10:16 -0800295static void DumpEscapedString(const char* p, FILE* out_file) {
296 fputs("\"", out_file);
David Sehr7629f602016-08-07 16:01:51 -0700297 for (; *p; p++) {
298 switch (*p) {
299 case '\\':
Jeff Haoea7c6292016-11-14 18:10:16 -0800300 fputs("\\\\", out_file);
David Sehr7629f602016-08-07 16:01:51 -0700301 break;
302 case '\"':
Jeff Haoea7c6292016-11-14 18:10:16 -0800303 fputs("\\\"", out_file);
David Sehr7629f602016-08-07 16:01:51 -0700304 break;
305 case '\t':
Jeff Haoea7c6292016-11-14 18:10:16 -0800306 fputs("\\t", out_file);
David Sehr7629f602016-08-07 16:01:51 -0700307 break;
308 case '\n':
Jeff Haoea7c6292016-11-14 18:10:16 -0800309 fputs("\\n", out_file);
David Sehr7629f602016-08-07 16:01:51 -0700310 break;
311 case '\r':
Jeff Haoea7c6292016-11-14 18:10:16 -0800312 fputs("\\r", out_file);
David Sehr7629f602016-08-07 16:01:51 -0700313 break;
314 default:
Jeff Haoea7c6292016-11-14 18:10:16 -0800315 putc(*p, out_file);
David Sehr7629f602016-08-07 16:01:51 -0700316 } // switch
317 } // for
Jeff Haoea7c6292016-11-14 18:10:16 -0800318 fputs("\"", out_file);
David Sehr7629f602016-08-07 16:01:51 -0700319}
320
321/*
322 * Dumps a string as an XML attribute value.
323 */
Jeff Haoea7c6292016-11-14 18:10:16 -0800324static void DumpXmlAttribute(const char* p, FILE* out_file) {
David Sehr7629f602016-08-07 16:01:51 -0700325 for (; *p; p++) {
326 switch (*p) {
327 case '&':
Jeff Haoea7c6292016-11-14 18:10:16 -0800328 fputs("&amp;", out_file);
David Sehr7629f602016-08-07 16:01:51 -0700329 break;
330 case '<':
Jeff Haoea7c6292016-11-14 18:10:16 -0800331 fputs("&lt;", out_file);
David Sehr7629f602016-08-07 16:01:51 -0700332 break;
333 case '>':
Jeff Haoea7c6292016-11-14 18:10:16 -0800334 fputs("&gt;", out_file);
David Sehr7629f602016-08-07 16:01:51 -0700335 break;
336 case '"':
Jeff Haoea7c6292016-11-14 18:10:16 -0800337 fputs("&quot;", out_file);
David Sehr7629f602016-08-07 16:01:51 -0700338 break;
339 case '\t':
Jeff Haoea7c6292016-11-14 18:10:16 -0800340 fputs("&#x9;", out_file);
David Sehr7629f602016-08-07 16:01:51 -0700341 break;
342 case '\n':
Jeff Haoea7c6292016-11-14 18:10:16 -0800343 fputs("&#xA;", out_file);
David Sehr7629f602016-08-07 16:01:51 -0700344 break;
345 case '\r':
Jeff Haoea7c6292016-11-14 18:10:16 -0800346 fputs("&#xD;", out_file);
David Sehr7629f602016-08-07 16:01:51 -0700347 break;
348 default:
Jeff Haoea7c6292016-11-14 18:10:16 -0800349 putc(*p, out_file);
David Sehr7629f602016-08-07 16:01:51 -0700350 } // switch
351 } // for
352}
353
David Sehr7629f602016-08-07 16:01:51 -0700354/*
355 * Helper for dumpInstruction(), which builds the string
356 * representation for the index in the given instruction.
357 * Returns a pointer to a buffer of sufficient size.
358 */
359static std::unique_ptr<char[]> IndexString(dex_ir::Header* header,
360 const Instruction* dec_insn,
361 size_t buf_size) {
362 std::unique_ptr<char[]> buf(new char[buf_size]);
363 // Determine index and width of the string.
364 uint32_t index = 0;
Jeff Haoea7c6292016-11-14 18:10:16 -0800365 uint32_t secondary_index = DexFile::kDexNoIndex;
David Sehr7629f602016-08-07 16:01:51 -0700366 uint32_t width = 4;
367 switch (Instruction::FormatOf(dec_insn->Opcode())) {
368 // SOME NOT SUPPORTED:
369 // case Instruction::k20bc:
370 case Instruction::k21c:
371 case Instruction::k35c:
372 // case Instruction::k35ms:
373 case Instruction::k3rc:
374 // case Instruction::k3rms:
375 // case Instruction::k35mi:
376 // case Instruction::k3rmi:
377 index = dec_insn->VRegB();
378 width = 4;
379 break;
380 case Instruction::k31c:
381 index = dec_insn->VRegB();
382 width = 8;
383 break;
384 case Instruction::k22c:
385 // case Instruction::k22cs:
386 index = dec_insn->VRegC();
387 width = 4;
388 break;
Orion Hodsonb34bb192016-10-18 17:02:58 +0100389 case Instruction::k45cc:
390 case Instruction::k4rcc:
391 index = dec_insn->VRegB();
392 secondary_index = dec_insn->VRegH();
393 width = 4;
David Sehr7629f602016-08-07 16:01:51 -0700394 default:
395 break;
396 } // switch
397
398 // Determine index type.
399 size_t outSize = 0;
400 switch (Instruction::IndexTypeOf(dec_insn->Opcode())) {
401 case Instruction::kIndexUnknown:
402 // This function should never get called for this type, but do
403 // something sensible here, just to help with debugging.
404 outSize = snprintf(buf.get(), buf_size, "<unknown-index>");
405 break;
406 case Instruction::kIndexNone:
407 // This function should never get called for this type, but do
408 // something sensible here, just to help with debugging.
409 outSize = snprintf(buf.get(), buf_size, "<no-index>");
410 break;
411 case Instruction::kIndexTypeRef:
Jeff Hao3ab96b42016-09-09 18:35:01 -0700412 if (index < header->GetCollections().TypeIdsSize()) {
413 const char* tp = header->GetCollections().GetTypeId(index)->GetStringId()->Data();
David Sehr7629f602016-08-07 16:01:51 -0700414 outSize = snprintf(buf.get(), buf_size, "%s // type@%0*x", tp, width, index);
415 } else {
416 outSize = snprintf(buf.get(), buf_size, "<type?> // type@%0*x", width, index);
417 }
418 break;
419 case Instruction::kIndexStringRef:
Jeff Hao3ab96b42016-09-09 18:35:01 -0700420 if (index < header->GetCollections().StringIdsSize()) {
421 const char* st = header->GetCollections().GetStringId(index)->Data();
David Sehr7629f602016-08-07 16:01:51 -0700422 outSize = snprintf(buf.get(), buf_size, "\"%s\" // string@%0*x", st, width, index);
423 } else {
424 outSize = snprintf(buf.get(), buf_size, "<string?> // string@%0*x", width, index);
425 }
426 break;
427 case Instruction::kIndexMethodRef:
Jeff Hao3ab96b42016-09-09 18:35:01 -0700428 if (index < header->GetCollections().MethodIdsSize()) {
429 dex_ir::MethodId* method_id = header->GetCollections().GetMethodId(index);
David Sehr7629f602016-08-07 16:01:51 -0700430 const char* name = method_id->Name()->Data();
David Sehr72359222016-09-07 13:04:01 -0700431 std::string type_descriptor = GetSignatureForProtoId(method_id->Proto());
David Sehr7629f602016-08-07 16:01:51 -0700432 const char* back_descriptor = method_id->Class()->GetStringId()->Data();
433 outSize = snprintf(buf.get(), buf_size, "%s.%s:%s // method@%0*x",
David Sehr72359222016-09-07 13:04:01 -0700434 back_descriptor, name, type_descriptor.c_str(), width, index);
David Sehr7629f602016-08-07 16:01:51 -0700435 } else {
436 outSize = snprintf(buf.get(), buf_size, "<method?> // method@%0*x", width, index);
437 }
438 break;
439 case Instruction::kIndexFieldRef:
Jeff Hao3ab96b42016-09-09 18:35:01 -0700440 if (index < header->GetCollections().FieldIdsSize()) {
441 dex_ir::FieldId* field_id = header->GetCollections().GetFieldId(index);
David Sehr7629f602016-08-07 16:01:51 -0700442 const char* name = field_id->Name()->Data();
443 const char* type_descriptor = field_id->Type()->GetStringId()->Data();
444 const char* back_descriptor = field_id->Class()->GetStringId()->Data();
445 outSize = snprintf(buf.get(), buf_size, "%s.%s:%s // field@%0*x",
446 back_descriptor, name, type_descriptor, width, index);
447 } else {
448 outSize = snprintf(buf.get(), buf_size, "<field?> // field@%0*x", width, index);
449 }
450 break;
451 case Instruction::kIndexVtableOffset:
452 outSize = snprintf(buf.get(), buf_size, "[%0*x] // vtable #%0*x",
453 width, index, width, index);
454 break;
455 case Instruction::kIndexFieldOffset:
456 outSize = snprintf(buf.get(), buf_size, "[obj+%0*x]", width, index);
457 break;
Orion Hodsonb34bb192016-10-18 17:02:58 +0100458 case Instruction::kIndexMethodAndProtoRef: {
459 std::string method("<method?>");
460 std::string proto("<proto?>");
461 if (index < header->GetCollections().MethodIdsSize()) {
462 dex_ir::MethodId* method_id = header->GetCollections().GetMethodId(index);
463 const char* name = method_id->Name()->Data();
464 std::string type_descriptor = GetSignatureForProtoId(method_id->Proto());
465 const char* back_descriptor = method_id->Class()->GetStringId()->Data();
466 method = StringPrintf("%s.%s:%s", back_descriptor, name, type_descriptor.c_str());
467 }
468 if (secondary_index < header->GetCollections().ProtoIdsSize()) {
469 dex_ir::ProtoId* proto_id = header->GetCollections().GetProtoId(secondary_index);
470 proto = GetSignatureForProtoId(proto_id);
471 }
472 outSize = snprintf(buf.get(), buf_size, "%s, %s // method@%0*x, proto@%0*x",
473 method.c_str(), proto.c_str(), width, index, width, secondary_index);
Jeff Haoea7c6292016-11-14 18:10:16 -0800474 }
475 break;
476 // SOME NOT SUPPORTED:
477 // case Instruction::kIndexVaries:
478 // case Instruction::kIndexInlineMethod:
David Sehr7629f602016-08-07 16:01:51 -0700479 default:
480 outSize = snprintf(buf.get(), buf_size, "<?>");
481 break;
482 } // switch
483
484 // Determine success of string construction.
485 if (outSize >= buf_size) {
486 // The buffer wasn't big enough; retry with computed size. Note: snprintf()
487 // doesn't count/ the '\0' as part of its returned size, so we add explicit
488 // space for it here.
489 return IndexString(header, dec_insn, outSize + 1);
490 }
491 return buf;
492}
493
494/*
Jeff Haoea7c6292016-11-14 18:10:16 -0800495 * Dumps encoded annotation.
496 */
497void DexLayout::DumpEncodedAnnotation(dex_ir::EncodedAnnotation* annotation) {
498 fputs(annotation->GetType()->GetStringId()->Data(), out_file_);
499 // Display all name=value pairs.
500 for (auto& subannotation : *annotation->GetAnnotationElements()) {
501 fputc(' ', out_file_);
502 fputs(subannotation->GetName()->Data(), out_file_);
503 fputc('=', out_file_);
504 DumpEncodedValue(subannotation->GetValue());
505 }
506}
507/*
508 * Dumps encoded value.
509 */
510void DexLayout::DumpEncodedValue(const dex_ir::EncodedValue* data) {
511 switch (data->Type()) {
512 case DexFile::kDexAnnotationByte:
513 fprintf(out_file_, "%" PRId8, data->GetByte());
514 break;
515 case DexFile::kDexAnnotationShort:
516 fprintf(out_file_, "%" PRId16, data->GetShort());
517 break;
518 case DexFile::kDexAnnotationChar:
519 fprintf(out_file_, "%" PRIu16, data->GetChar());
520 break;
521 case DexFile::kDexAnnotationInt:
522 fprintf(out_file_, "%" PRId32, data->GetInt());
523 break;
524 case DexFile::kDexAnnotationLong:
525 fprintf(out_file_, "%" PRId64, data->GetLong());
526 break;
527 case DexFile::kDexAnnotationFloat: {
528 fprintf(out_file_, "%g", data->GetFloat());
529 break;
530 }
531 case DexFile::kDexAnnotationDouble: {
532 fprintf(out_file_, "%g", data->GetDouble());
533 break;
534 }
535 case DexFile::kDexAnnotationString: {
536 dex_ir::StringId* string_id = data->GetStringId();
537 if (options_.output_format_ == kOutputPlain) {
538 DumpEscapedString(string_id->Data(), out_file_);
539 } else {
540 DumpXmlAttribute(string_id->Data(), out_file_);
541 }
542 break;
543 }
544 case DexFile::kDexAnnotationType: {
545 dex_ir::TypeId* type_id = data->GetTypeId();
546 fputs(type_id->GetStringId()->Data(), out_file_);
547 break;
548 }
549 case DexFile::kDexAnnotationField:
550 case DexFile::kDexAnnotationEnum: {
551 dex_ir::FieldId* field_id = data->GetFieldId();
552 fputs(field_id->Name()->Data(), out_file_);
553 break;
554 }
555 case DexFile::kDexAnnotationMethod: {
556 dex_ir::MethodId* method_id = data->GetMethodId();
557 fputs(method_id->Name()->Data(), out_file_);
558 break;
559 }
560 case DexFile::kDexAnnotationArray: {
561 fputc('{', out_file_);
562 // Display all elements.
563 for (auto& value : *data->GetEncodedArray()->GetEncodedValues()) {
564 fputc(' ', out_file_);
565 DumpEncodedValue(value.get());
566 }
567 fputs(" }", out_file_);
568 break;
569 }
570 case DexFile::kDexAnnotationAnnotation: {
571 DumpEncodedAnnotation(data->GetEncodedAnnotation());
572 break;
573 }
574 case DexFile::kDexAnnotationNull:
575 fputs("null", out_file_);
576 break;
577 case DexFile::kDexAnnotationBoolean:
578 fputs(StrBool(data->GetBoolean()), out_file_);
579 break;
580 default:
581 fputs("????", out_file_);
582 break;
583 } // switch
584}
585
586/*
587 * Dumps the file header.
588 */
589void DexLayout::DumpFileHeader() {
590 char sanitized[8 * 2 + 1];
591 dex_ir::Collections& collections = header_->GetCollections();
592 fprintf(out_file_, "DEX file header:\n");
593 Asciify(sanitized, header_->Magic(), 8);
594 fprintf(out_file_, "magic : '%s'\n", sanitized);
595 fprintf(out_file_, "checksum : %08x\n", header_->Checksum());
596 fprintf(out_file_, "signature : %02x%02x...%02x%02x\n",
597 header_->Signature()[0], header_->Signature()[1],
598 header_->Signature()[DexFile::kSha1DigestSize - 2],
599 header_->Signature()[DexFile::kSha1DigestSize - 1]);
600 fprintf(out_file_, "file_size : %d\n", header_->FileSize());
601 fprintf(out_file_, "header_size : %d\n", header_->HeaderSize());
602 fprintf(out_file_, "link_size : %d\n", header_->LinkSize());
603 fprintf(out_file_, "link_off : %d (0x%06x)\n",
604 header_->LinkOffset(), header_->LinkOffset());
605 fprintf(out_file_, "string_ids_size : %d\n", collections.StringIdsSize());
606 fprintf(out_file_, "string_ids_off : %d (0x%06x)\n",
607 collections.StringIdsOffset(), collections.StringIdsOffset());
608 fprintf(out_file_, "type_ids_size : %d\n", collections.TypeIdsSize());
609 fprintf(out_file_, "type_ids_off : %d (0x%06x)\n",
610 collections.TypeIdsOffset(), collections.TypeIdsOffset());
611 fprintf(out_file_, "proto_ids_size : %d\n", collections.ProtoIdsSize());
612 fprintf(out_file_, "proto_ids_off : %d (0x%06x)\n",
613 collections.ProtoIdsOffset(), collections.ProtoIdsOffset());
614 fprintf(out_file_, "field_ids_size : %d\n", collections.FieldIdsSize());
615 fprintf(out_file_, "field_ids_off : %d (0x%06x)\n",
616 collections.FieldIdsOffset(), collections.FieldIdsOffset());
617 fprintf(out_file_, "method_ids_size : %d\n", collections.MethodIdsSize());
618 fprintf(out_file_, "method_ids_off : %d (0x%06x)\n",
619 collections.MethodIdsOffset(), collections.MethodIdsOffset());
620 fprintf(out_file_, "class_defs_size : %d\n", collections.ClassDefsSize());
621 fprintf(out_file_, "class_defs_off : %d (0x%06x)\n",
622 collections.ClassDefsOffset(), collections.ClassDefsOffset());
623 fprintf(out_file_, "data_size : %d\n", header_->DataSize());
624 fprintf(out_file_, "data_off : %d (0x%06x)\n\n",
625 header_->DataOffset(), header_->DataOffset());
626}
627
628/*
629 * Dumps a class_def_item.
630 */
631void DexLayout::DumpClassDef(int idx) {
632 // General class information.
633 dex_ir::ClassDef* class_def = header_->GetCollections().GetClassDef(idx);
634 fprintf(out_file_, "Class #%d header:\n", idx);
635 fprintf(out_file_, "class_idx : %d\n", class_def->ClassType()->GetIndex());
636 fprintf(out_file_, "access_flags : %d (0x%04x)\n",
637 class_def->GetAccessFlags(), class_def->GetAccessFlags());
638 uint32_t superclass_idx = class_def->Superclass() == nullptr ?
639 DexFile::kDexNoIndex16 : class_def->Superclass()->GetIndex();
640 fprintf(out_file_, "superclass_idx : %d\n", superclass_idx);
641 fprintf(out_file_, "interfaces_off : %d (0x%06x)\n",
642 class_def->InterfacesOffset(), class_def->InterfacesOffset());
643 uint32_t source_file_offset = 0xffffffffU;
644 if (class_def->SourceFile() != nullptr) {
645 source_file_offset = class_def->SourceFile()->GetIndex();
646 }
647 fprintf(out_file_, "source_file_idx : %d\n", source_file_offset);
648 uint32_t annotations_offset = 0;
649 if (class_def->Annotations() != nullptr) {
650 annotations_offset = class_def->Annotations()->GetOffset();
651 }
652 fprintf(out_file_, "annotations_off : %d (0x%06x)\n",
653 annotations_offset, annotations_offset);
654 if (class_def->GetClassData() == nullptr) {
655 fprintf(out_file_, "class_data_off : %d (0x%06x)\n", 0, 0);
656 } else {
657 fprintf(out_file_, "class_data_off : %d (0x%06x)\n",
658 class_def->GetClassData()->GetOffset(), class_def->GetClassData()->GetOffset());
659 }
660
661 // Fields and methods.
662 dex_ir::ClassData* class_data = class_def->GetClassData();
663 if (class_data != nullptr && class_data->StaticFields() != nullptr) {
664 fprintf(out_file_, "static_fields_size : %zu\n", class_data->StaticFields()->size());
665 } else {
666 fprintf(out_file_, "static_fields_size : 0\n");
667 }
668 if (class_data != nullptr && class_data->InstanceFields() != nullptr) {
669 fprintf(out_file_, "instance_fields_size: %zu\n", class_data->InstanceFields()->size());
670 } else {
671 fprintf(out_file_, "instance_fields_size: 0\n");
672 }
673 if (class_data != nullptr && class_data->DirectMethods() != nullptr) {
674 fprintf(out_file_, "direct_methods_size : %zu\n", class_data->DirectMethods()->size());
675 } else {
676 fprintf(out_file_, "direct_methods_size : 0\n");
677 }
678 if (class_data != nullptr && class_data->VirtualMethods() != nullptr) {
679 fprintf(out_file_, "virtual_methods_size: %zu\n", class_data->VirtualMethods()->size());
680 } else {
681 fprintf(out_file_, "virtual_methods_size: 0\n");
682 }
683 fprintf(out_file_, "\n");
684}
685
686/**
687 * Dumps an annotation set item.
688 */
689void DexLayout::DumpAnnotationSetItem(dex_ir::AnnotationSetItem* set_item) {
690 if (set_item == nullptr || set_item->GetItems()->size() == 0) {
691 fputs(" empty-annotation-set\n", out_file_);
692 return;
693 }
694 for (dex_ir::AnnotationItem* annotation : *set_item->GetItems()) {
695 if (annotation == nullptr) {
696 continue;
697 }
698 fputs(" ", out_file_);
699 switch (annotation->GetVisibility()) {
700 case DexFile::kDexVisibilityBuild: fputs("VISIBILITY_BUILD ", out_file_); break;
701 case DexFile::kDexVisibilityRuntime: fputs("VISIBILITY_RUNTIME ", out_file_); break;
702 case DexFile::kDexVisibilitySystem: fputs("VISIBILITY_SYSTEM ", out_file_); break;
703 default: fputs("VISIBILITY_UNKNOWN ", out_file_); break;
704 } // switch
705 DumpEncodedAnnotation(annotation->GetAnnotation());
706 fputc('\n', out_file_);
707 }
708}
709
710/*
711 * Dumps class annotations.
712 */
713void DexLayout::DumpClassAnnotations(int idx) {
714 dex_ir::ClassDef* class_def = header_->GetCollections().GetClassDef(idx);
715 dex_ir::AnnotationsDirectoryItem* annotations_directory = class_def->Annotations();
716 if (annotations_directory == nullptr) {
717 return; // none
718 }
719
720 fprintf(out_file_, "Class #%d annotations:\n", idx);
721
722 dex_ir::AnnotationSetItem* class_set_item = annotations_directory->GetClassAnnotation();
723 dex_ir::FieldAnnotationVector* fields = annotations_directory->GetFieldAnnotations();
724 dex_ir::MethodAnnotationVector* methods = annotations_directory->GetMethodAnnotations();
725 dex_ir::ParameterAnnotationVector* parameters = annotations_directory->GetParameterAnnotations();
726
727 // Annotations on the class itself.
728 if (class_set_item != nullptr) {
729 fprintf(out_file_, "Annotations on class\n");
730 DumpAnnotationSetItem(class_set_item);
731 }
732
733 // Annotations on fields.
734 if (fields != nullptr) {
735 for (auto& field : *fields) {
736 const dex_ir::FieldId* field_id = field->GetFieldId();
737 const uint32_t field_idx = field_id->GetIndex();
738 const char* field_name = field_id->Name()->Data();
739 fprintf(out_file_, "Annotations on field #%u '%s'\n", field_idx, field_name);
740 DumpAnnotationSetItem(field->GetAnnotationSetItem());
741 }
742 }
743
744 // Annotations on methods.
745 if (methods != nullptr) {
746 for (auto& method : *methods) {
747 const dex_ir::MethodId* method_id = method->GetMethodId();
748 const uint32_t method_idx = method_id->GetIndex();
749 const char* method_name = method_id->Name()->Data();
750 fprintf(out_file_, "Annotations on method #%u '%s'\n", method_idx, method_name);
751 DumpAnnotationSetItem(method->GetAnnotationSetItem());
752 }
753 }
754
755 // Annotations on method parameters.
756 if (parameters != nullptr) {
757 for (auto& parameter : *parameters) {
758 const dex_ir::MethodId* method_id = parameter->GetMethodId();
759 const uint32_t method_idx = method_id->GetIndex();
760 const char* method_name = method_id->Name()->Data();
761 fprintf(out_file_, "Annotations on method #%u '%s' parameters\n", method_idx, method_name);
762 uint32_t j = 0;
763 for (dex_ir::AnnotationSetItem* annotation : *parameter->GetAnnotations()->GetItems()) {
764 fprintf(out_file_, "#%u\n", j);
765 DumpAnnotationSetItem(annotation);
766 ++j;
767 }
768 }
769 }
770
771 fputc('\n', out_file_);
772}
773
774/*
775 * Dumps an interface that a class declares to implement.
776 */
777void DexLayout::DumpInterface(const dex_ir::TypeId* type_item, int i) {
778 const char* interface_name = type_item->GetStringId()->Data();
779 if (options_.output_format_ == kOutputPlain) {
780 fprintf(out_file_, " #%d : '%s'\n", i, interface_name);
781 } else {
782 std::string dot(DescriptorToDotWrapper(interface_name));
783 fprintf(out_file_, "<implements name=\"%s\">\n</implements>\n", dot.c_str());
784 }
785}
786
787/*
788 * Dumps the catches table associated with the code.
789 */
790void DexLayout::DumpCatches(const dex_ir::CodeItem* code) {
791 const uint16_t tries_size = code->TriesSize();
792
793 // No catch table.
794 if (tries_size == 0) {
795 fprintf(out_file_, " catches : (none)\n");
796 return;
797 }
798
799 // Dump all table entries.
800 fprintf(out_file_, " catches : %d\n", tries_size);
801 std::vector<std::unique_ptr<const dex_ir::TryItem>>* tries = code->Tries();
802 for (uint32_t i = 0; i < tries_size; i++) {
803 const dex_ir::TryItem* try_item = (*tries)[i].get();
804 const uint32_t start = try_item->StartAddr();
805 const uint32_t end = start + try_item->InsnCount();
806 fprintf(out_file_, " 0x%04x - 0x%04x\n", start, end);
807 for (auto& handler : *try_item->GetHandlers()->GetHandlers()) {
808 const dex_ir::TypeId* type_id = handler->GetTypeId();
809 const char* descriptor = (type_id == nullptr) ? "<any>" : type_id->GetStringId()->Data();
810 fprintf(out_file_, " %s -> 0x%04x\n", descriptor, handler->GetAddress());
811 } // for
812 } // for
813}
814
815/*
816 * Dumps all positions table entries associated with the code.
817 */
818void DexLayout::DumpPositionInfo(const dex_ir::CodeItem* code) {
819 dex_ir::DebugInfoItem* debug_info = code->DebugInfo();
820 if (debug_info == nullptr) {
821 return;
822 }
823 std::vector<std::unique_ptr<dex_ir::PositionInfo>>& positions = debug_info->GetPositionInfo();
824 for (size_t i = 0; i < positions.size(); ++i) {
825 fprintf(out_file_, " 0x%04x line=%d\n", positions[i]->address_, positions[i]->line_);
826 }
827}
828
829/*
830 * Dumps all locals table entries associated with the code.
831 */
832void DexLayout::DumpLocalInfo(const dex_ir::CodeItem* code) {
833 dex_ir::DebugInfoItem* debug_info = code->DebugInfo();
834 if (debug_info == nullptr) {
835 return;
836 }
837 std::vector<std::unique_ptr<dex_ir::LocalInfo>>& locals = debug_info->GetLocalInfo();
838 for (size_t i = 0; i < locals.size(); ++i) {
839 dex_ir::LocalInfo* entry = locals[i].get();
840 fprintf(out_file_, " 0x%04x - 0x%04x reg=%d %s %s %s\n",
841 entry->start_address_, entry->end_address_, entry->reg_,
842 entry->name_.c_str(), entry->descriptor_.c_str(), entry->signature_.c_str());
843 }
844}
845
846/*
David Sehr7629f602016-08-07 16:01:51 -0700847 * Dumps a single instruction.
848 */
Jeff Haoea7c6292016-11-14 18:10:16 -0800849void DexLayout::DumpInstruction(const dex_ir::CodeItem* code,
850 uint32_t code_offset,
851 uint32_t insn_idx,
852 uint32_t insn_width,
853 const Instruction* dec_insn) {
David Sehr7629f602016-08-07 16:01:51 -0700854 // Address of instruction (expressed as byte offset).
855 fprintf(out_file_, "%06x:", code_offset + 0x10 + insn_idx * 2);
856
857 // Dump (part of) raw bytes.
858 const uint16_t* insns = code->Insns();
859 for (uint32_t i = 0; i < 8; i++) {
860 if (i < insn_width) {
861 if (i == 7) {
862 fprintf(out_file_, " ... ");
863 } else {
864 // Print 16-bit value in little-endian order.
865 const uint8_t* bytePtr = (const uint8_t*) &insns[insn_idx + i];
866 fprintf(out_file_, " %02x%02x", bytePtr[0], bytePtr[1]);
867 }
868 } else {
869 fputs(" ", out_file_);
870 }
871 } // for
872
873 // Dump pseudo-instruction or opcode.
874 if (dec_insn->Opcode() == Instruction::NOP) {
875 const uint16_t instr = Get2LE((const uint8_t*) &insns[insn_idx]);
876 if (instr == Instruction::kPackedSwitchSignature) {
877 fprintf(out_file_, "|%04x: packed-switch-data (%d units)", insn_idx, insn_width);
878 } else if (instr == Instruction::kSparseSwitchSignature) {
879 fprintf(out_file_, "|%04x: sparse-switch-data (%d units)", insn_idx, insn_width);
880 } else if (instr == Instruction::kArrayDataSignature) {
881 fprintf(out_file_, "|%04x: array-data (%d units)", insn_idx, insn_width);
882 } else {
883 fprintf(out_file_, "|%04x: nop // spacer", insn_idx);
884 }
885 } else {
886 fprintf(out_file_, "|%04x: %s", insn_idx, dec_insn->Name());
887 }
888
889 // Set up additional argument.
890 std::unique_ptr<char[]> index_buf;
891 if (Instruction::IndexTypeOf(dec_insn->Opcode()) != Instruction::kIndexNone) {
Jeff Haoea7c6292016-11-14 18:10:16 -0800892 index_buf = IndexString(header_, dec_insn, 200);
David Sehr7629f602016-08-07 16:01:51 -0700893 }
894
895 // Dump the instruction.
896 //
897 // NOTE: pDecInsn->DumpString(pDexFile) differs too much from original.
898 //
899 switch (Instruction::FormatOf(dec_insn->Opcode())) {
900 case Instruction::k10x: // op
901 break;
902 case Instruction::k12x: // op vA, vB
903 fprintf(out_file_, " v%d, v%d", dec_insn->VRegA(), dec_insn->VRegB());
904 break;
905 case Instruction::k11n: // op vA, #+B
906 fprintf(out_file_, " v%d, #int %d // #%x",
907 dec_insn->VRegA(), (int32_t) dec_insn->VRegB(), (uint8_t)dec_insn->VRegB());
908 break;
909 case Instruction::k11x: // op vAA
910 fprintf(out_file_, " v%d", dec_insn->VRegA());
911 break;
912 case Instruction::k10t: // op +AA
913 case Instruction::k20t: { // op +AAAA
914 const int32_t targ = (int32_t) dec_insn->VRegA();
915 fprintf(out_file_, " %04x // %c%04x",
916 insn_idx + targ,
917 (targ < 0) ? '-' : '+',
918 (targ < 0) ? -targ : targ);
919 break;
920 }
921 case Instruction::k22x: // op vAA, vBBBB
922 fprintf(out_file_, " v%d, v%d", dec_insn->VRegA(), dec_insn->VRegB());
923 break;
924 case Instruction::k21t: { // op vAA, +BBBB
925 const int32_t targ = (int32_t) dec_insn->VRegB();
926 fprintf(out_file_, " v%d, %04x // %c%04x", dec_insn->VRegA(),
927 insn_idx + targ,
928 (targ < 0) ? '-' : '+',
929 (targ < 0) ? -targ : targ);
930 break;
931 }
932 case Instruction::k21s: // op vAA, #+BBBB
933 fprintf(out_file_, " v%d, #int %d // #%x",
934 dec_insn->VRegA(), (int32_t) dec_insn->VRegB(), (uint16_t)dec_insn->VRegB());
935 break;
936 case Instruction::k21h: // op vAA, #+BBBB0000[00000000]
937 // The printed format varies a bit based on the actual opcode.
938 if (dec_insn->Opcode() == Instruction::CONST_HIGH16) {
939 const int32_t value = dec_insn->VRegB() << 16;
940 fprintf(out_file_, " v%d, #int %d // #%x",
941 dec_insn->VRegA(), value, (uint16_t) dec_insn->VRegB());
942 } else {
943 const int64_t value = ((int64_t) dec_insn->VRegB()) << 48;
944 fprintf(out_file_, " v%d, #long %" PRId64 " // #%x",
945 dec_insn->VRegA(), value, (uint16_t) dec_insn->VRegB());
946 }
947 break;
948 case Instruction::k21c: // op vAA, thing@BBBB
949 case Instruction::k31c: // op vAA, thing@BBBBBBBB
950 fprintf(out_file_, " v%d, %s", dec_insn->VRegA(), index_buf.get());
951 break;
952 case Instruction::k23x: // op vAA, vBB, vCC
953 fprintf(out_file_, " v%d, v%d, v%d",
954 dec_insn->VRegA(), dec_insn->VRegB(), dec_insn->VRegC());
955 break;
956 case Instruction::k22b: // op vAA, vBB, #+CC
957 fprintf(out_file_, " v%d, v%d, #int %d // #%02x",
958 dec_insn->VRegA(), dec_insn->VRegB(),
959 (int32_t) dec_insn->VRegC(), (uint8_t) dec_insn->VRegC());
960 break;
961 case Instruction::k22t: { // op vA, vB, +CCCC
962 const int32_t targ = (int32_t) dec_insn->VRegC();
963 fprintf(out_file_, " v%d, v%d, %04x // %c%04x",
964 dec_insn->VRegA(), dec_insn->VRegB(),
965 insn_idx + targ,
966 (targ < 0) ? '-' : '+',
967 (targ < 0) ? -targ : targ);
968 break;
969 }
970 case Instruction::k22s: // op vA, vB, #+CCCC
971 fprintf(out_file_, " v%d, v%d, #int %d // #%04x",
972 dec_insn->VRegA(), dec_insn->VRegB(),
973 (int32_t) dec_insn->VRegC(), (uint16_t) dec_insn->VRegC());
974 break;
975 case Instruction::k22c: // op vA, vB, thing@CCCC
976 // NOT SUPPORTED:
977 // case Instruction::k22cs: // [opt] op vA, vB, field offset CCCC
978 fprintf(out_file_, " v%d, v%d, %s",
979 dec_insn->VRegA(), dec_insn->VRegB(), index_buf.get());
980 break;
981 case Instruction::k30t:
982 fprintf(out_file_, " #%08x", dec_insn->VRegA());
983 break;
984 case Instruction::k31i: { // op vAA, #+BBBBBBBB
985 // This is often, but not always, a float.
986 union {
987 float f;
988 uint32_t i;
989 } conv;
990 conv.i = dec_insn->VRegB();
991 fprintf(out_file_, " v%d, #float %g // #%08x",
992 dec_insn->VRegA(), conv.f, dec_insn->VRegB());
993 break;
994 }
995 case Instruction::k31t: // op vAA, offset +BBBBBBBB
996 fprintf(out_file_, " v%d, %08x // +%08x",
997 dec_insn->VRegA(), insn_idx + dec_insn->VRegB(), dec_insn->VRegB());
998 break;
999 case Instruction::k32x: // op vAAAA, vBBBB
1000 fprintf(out_file_, " v%d, v%d", dec_insn->VRegA(), dec_insn->VRegB());
1001 break;
Orion Hodsonb34bb192016-10-18 17:02:58 +01001002 case Instruction::k35c: // op {vC, vD, vE, vF, vG}, thing@BBBB
1003 case Instruction::k45cc: { // op {vC, vD, vE, vF, vG}, meth@BBBB, proto@HHHH
David Sehr7629f602016-08-07 16:01:51 -07001004 // NOT SUPPORTED:
1005 // case Instruction::k35ms: // [opt] invoke-virtual+super
1006 // case Instruction::k35mi: // [opt] inline invoke
1007 uint32_t arg[Instruction::kMaxVarArgRegs];
1008 dec_insn->GetVarArgs(arg);
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", arg[i]);
1013 } else {
1014 fprintf(out_file_, ", v%d", arg[i]);
1015 }
1016 } // for
1017 fprintf(out_file_, "}, %s", index_buf.get());
1018 break;
1019 }
Orion Hodsonb34bb192016-10-18 17:02:58 +01001020 case Instruction::k3rc: // op {vCCCC .. v(CCCC+AA-1)}, thing@BBBB
1021 case Instruction::k4rcc: // op {vCCCC .. v(CCCC+AA-1)}, meth@BBBB, proto@HHHH
David Sehr7629f602016-08-07 16:01:51 -07001022 // NOT SUPPORTED:
1023 // case Instruction::k3rms: // [opt] invoke-virtual+super/range
1024 // case Instruction::k3rmi: // [opt] execute-inline/range
1025 {
1026 // This doesn't match the "dx" output when some of the args are
1027 // 64-bit values -- dx only shows the first register.
1028 fputs(" {", out_file_);
1029 for (int i = 0, n = dec_insn->VRegA(); i < n; i++) {
1030 if (i == 0) {
1031 fprintf(out_file_, "v%d", dec_insn->VRegC() + i);
1032 } else {
1033 fprintf(out_file_, ", v%d", dec_insn->VRegC() + i);
1034 }
1035 } // for
1036 fprintf(out_file_, "}, %s", index_buf.get());
1037 }
1038 break;
1039 case Instruction::k51l: { // op vAA, #+BBBBBBBBBBBBBBBB
1040 // This is often, but not always, a double.
1041 union {
1042 double d;
1043 uint64_t j;
1044 } conv;
1045 conv.j = dec_insn->WideVRegB();
1046 fprintf(out_file_, " v%d, #double %g // #%016" PRIx64,
1047 dec_insn->VRegA(), conv.d, dec_insn->WideVRegB());
1048 break;
1049 }
1050 // NOT SUPPORTED:
1051 // case Instruction::k00x: // unknown op or breakpoint
1052 // break;
1053 default:
1054 fprintf(out_file_, " ???");
1055 break;
1056 } // switch
1057
1058 fputc('\n', out_file_);
1059}
1060
1061/*
1062 * Dumps a bytecode disassembly.
1063 */
Jeff Haoea7c6292016-11-14 18:10:16 -08001064void DexLayout::DumpBytecodes(uint32_t idx, const dex_ir::CodeItem* code, uint32_t code_offset) {
1065 dex_ir::MethodId* method_id = header_->GetCollections().GetMethodId(idx);
David Sehr7629f602016-08-07 16:01:51 -07001066 const char* name = method_id->Name()->Data();
David Sehr72359222016-09-07 13:04:01 -07001067 std::string type_descriptor = GetSignatureForProtoId(method_id->Proto());
David Sehr7629f602016-08-07 16:01:51 -07001068 const char* back_descriptor = method_id->Class()->GetStringId()->Data();
1069
1070 // Generate header.
Jeff Haoc3acfc52016-08-29 14:18:26 -07001071 std::string dot(DescriptorToDotWrapper(back_descriptor));
David Sehr7629f602016-08-07 16:01:51 -07001072 fprintf(out_file_, "%06x: |[%06x] %s.%s:%s\n",
David Sehr72359222016-09-07 13:04:01 -07001073 code_offset, code_offset, dot.c_str(), name, type_descriptor.c_str());
David Sehr7629f602016-08-07 16:01:51 -07001074
1075 // Iterate over all instructions.
1076 const uint16_t* insns = code->Insns();
1077 for (uint32_t insn_idx = 0; insn_idx < code->InsnsSize();) {
1078 const Instruction* instruction = Instruction::At(&insns[insn_idx]);
1079 const uint32_t insn_width = instruction->SizeInCodeUnits();
1080 if (insn_width == 0) {
1081 fprintf(stderr, "GLITCH: zero-width instruction at idx=0x%04x\n", insn_idx);
1082 break;
1083 }
Jeff Haoea7c6292016-11-14 18:10:16 -08001084 DumpInstruction(code, code_offset, insn_idx, insn_width, instruction);
David Sehr7629f602016-08-07 16:01:51 -07001085 insn_idx += insn_width;
1086 } // for
1087}
1088
1089/*
1090 * Dumps code of a method.
1091 */
Jeff Haoea7c6292016-11-14 18:10:16 -08001092void DexLayout::DumpCode(uint32_t idx, const dex_ir::CodeItem* code, uint32_t code_offset) {
David Sehr7629f602016-08-07 16:01:51 -07001093 fprintf(out_file_, " registers : %d\n", code->RegistersSize());
1094 fprintf(out_file_, " ins : %d\n", code->InsSize());
1095 fprintf(out_file_, " outs : %d\n", code->OutsSize());
1096 fprintf(out_file_, " insns size : %d 16-bit code units\n",
1097 code->InsnsSize());
1098
1099 // Bytecode disassembly, if requested.
1100 if (options_.disassemble_) {
Jeff Haoea7c6292016-11-14 18:10:16 -08001101 DumpBytecodes(idx, code, code_offset);
David Sehr7629f602016-08-07 16:01:51 -07001102 }
1103
1104 // Try-catch blocks.
1105 DumpCatches(code);
1106
1107 // Positions and locals table in the debug info.
1108 fprintf(out_file_, " positions : \n");
1109 DumpPositionInfo(code);
1110 fprintf(out_file_, " locals : \n");
1111 DumpLocalInfo(code);
1112}
1113
1114/*
1115 * Dumps a method.
1116 */
Jeff Haoea7c6292016-11-14 18:10:16 -08001117void DexLayout::DumpMethod(uint32_t idx, uint32_t flags, const dex_ir::CodeItem* code, int i) {
David Sehr7629f602016-08-07 16:01:51 -07001118 // Bail for anything private if export only requested.
1119 if (options_.exports_only_ && (flags & (kAccPublic | kAccProtected)) == 0) {
1120 return;
1121 }
1122
Jeff Haoea7c6292016-11-14 18:10:16 -08001123 dex_ir::MethodId* method_id = header_->GetCollections().GetMethodId(idx);
David Sehr7629f602016-08-07 16:01:51 -07001124 const char* name = method_id->Name()->Data();
1125 char* type_descriptor = strdup(GetSignatureForProtoId(method_id->Proto()).c_str());
1126 const char* back_descriptor = method_id->Class()->GetStringId()->Data();
1127 char* access_str = CreateAccessFlagStr(flags, kAccessForMethod);
1128
1129 if (options_.output_format_ == kOutputPlain) {
1130 fprintf(out_file_, " #%d : (in %s)\n", i, back_descriptor);
1131 fprintf(out_file_, " name : '%s'\n", name);
1132 fprintf(out_file_, " type : '%s'\n", type_descriptor);
1133 fprintf(out_file_, " access : 0x%04x (%s)\n", flags, access_str);
1134 if (code == nullptr) {
1135 fprintf(out_file_, " code : (none)\n");
1136 } else {
1137 fprintf(out_file_, " code -\n");
Jeff Haoea7c6292016-11-14 18:10:16 -08001138 DumpCode(idx, code, code->GetOffset());
David Sehr7629f602016-08-07 16:01:51 -07001139 }
1140 if (options_.disassemble_) {
1141 fputc('\n', out_file_);
1142 }
1143 } else if (options_.output_format_ == kOutputXml) {
1144 const bool constructor = (name[0] == '<');
1145
1146 // Method name and prototype.
1147 if (constructor) {
1148 std::string dot(DescriptorClassToDot(back_descriptor));
1149 fprintf(out_file_, "<constructor name=\"%s\"\n", dot.c_str());
Jeff Haoc3acfc52016-08-29 14:18:26 -07001150 dot = DescriptorToDotWrapper(back_descriptor);
David Sehr7629f602016-08-07 16:01:51 -07001151 fprintf(out_file_, " type=\"%s\"\n", dot.c_str());
1152 } else {
1153 fprintf(out_file_, "<method name=\"%s\"\n", name);
1154 const char* return_type = strrchr(type_descriptor, ')');
1155 if (return_type == nullptr) {
1156 fprintf(stderr, "bad method type descriptor '%s'\n", type_descriptor);
1157 goto bail;
1158 }
Jeff Haoc3acfc52016-08-29 14:18:26 -07001159 std::string dot(DescriptorToDotWrapper(return_type + 1));
David Sehr7629f602016-08-07 16:01:51 -07001160 fprintf(out_file_, " return=\"%s\"\n", dot.c_str());
1161 fprintf(out_file_, " abstract=%s\n", QuotedBool((flags & kAccAbstract) != 0));
1162 fprintf(out_file_, " native=%s\n", QuotedBool((flags & kAccNative) != 0));
1163 fprintf(out_file_, " synchronized=%s\n", QuotedBool(
1164 (flags & (kAccSynchronized | kAccDeclaredSynchronized)) != 0));
1165 }
1166
1167 // Additional method flags.
1168 fprintf(out_file_, " static=%s\n", QuotedBool((flags & kAccStatic) != 0));
1169 fprintf(out_file_, " final=%s\n", QuotedBool((flags & kAccFinal) != 0));
1170 // The "deprecated=" not knowable w/o parsing annotations.
1171 fprintf(out_file_, " visibility=%s\n>\n", QuotedVisibility(flags));
1172
1173 // Parameters.
1174 if (type_descriptor[0] != '(') {
1175 fprintf(stderr, "ERROR: bad descriptor '%s'\n", type_descriptor);
1176 goto bail;
1177 }
1178 char* tmp_buf = reinterpret_cast<char*>(malloc(strlen(type_descriptor) + 1));
1179 const char* base = type_descriptor + 1;
1180 int arg_num = 0;
1181 while (*base != ')') {
1182 char* cp = tmp_buf;
1183 while (*base == '[') {
1184 *cp++ = *base++;
1185 }
1186 if (*base == 'L') {
1187 // Copy through ';'.
1188 do {
1189 *cp = *base++;
1190 } while (*cp++ != ';');
1191 } else {
1192 // Primitive char, copy it.
1193 if (strchr("ZBCSIFJD", *base) == nullptr) {
1194 fprintf(stderr, "ERROR: bad method signature '%s'\n", base);
1195 break; // while
1196 }
1197 *cp++ = *base++;
1198 }
1199 // Null terminate and display.
1200 *cp++ = '\0';
Jeff Haoc3acfc52016-08-29 14:18:26 -07001201 std::string dot(DescriptorToDotWrapper(tmp_buf));
David Sehr7629f602016-08-07 16:01:51 -07001202 fprintf(out_file_, "<parameter name=\"arg%d\" type=\"%s\">\n"
1203 "</parameter>\n", arg_num++, dot.c_str());
1204 } // while
1205 free(tmp_buf);
1206 if (constructor) {
1207 fprintf(out_file_, "</constructor>\n");
1208 } else {
1209 fprintf(out_file_, "</method>\n");
1210 }
1211 }
1212
1213 bail:
1214 free(type_descriptor);
1215 free(access_str);
1216}
1217
1218/*
1219 * Dumps a static (class) field.
1220 */
Jeff Haoea7c6292016-11-14 18:10:16 -08001221void DexLayout::DumpSField(uint32_t idx, uint32_t flags, int i, dex_ir::EncodedValue* init) {
David Sehr7629f602016-08-07 16:01:51 -07001222 // Bail for anything private if export only requested.
1223 if (options_.exports_only_ && (flags & (kAccPublic | kAccProtected)) == 0) {
1224 return;
1225 }
1226
Jeff Haoea7c6292016-11-14 18:10:16 -08001227 dex_ir::FieldId* field_id = header_->GetCollections().GetFieldId(idx);
David Sehr7629f602016-08-07 16:01:51 -07001228 const char* name = field_id->Name()->Data();
1229 const char* type_descriptor = field_id->Type()->GetStringId()->Data();
1230 const char* back_descriptor = field_id->Class()->GetStringId()->Data();
1231 char* access_str = CreateAccessFlagStr(flags, kAccessForField);
1232
1233 if (options_.output_format_ == kOutputPlain) {
1234 fprintf(out_file_, " #%d : (in %s)\n", i, back_descriptor);
1235 fprintf(out_file_, " name : '%s'\n", name);
1236 fprintf(out_file_, " type : '%s'\n", type_descriptor);
1237 fprintf(out_file_, " access : 0x%04x (%s)\n", flags, access_str);
1238 if (init != nullptr) {
1239 fputs(" value : ", out_file_);
1240 DumpEncodedValue(init);
1241 fputs("\n", out_file_);
1242 }
1243 } else if (options_.output_format_ == kOutputXml) {
1244 fprintf(out_file_, "<field name=\"%s\"\n", name);
Jeff Haoc3acfc52016-08-29 14:18:26 -07001245 std::string dot(DescriptorToDotWrapper(type_descriptor));
David Sehr7629f602016-08-07 16:01:51 -07001246 fprintf(out_file_, " type=\"%s\"\n", dot.c_str());
1247 fprintf(out_file_, " transient=%s\n", QuotedBool((flags & kAccTransient) != 0));
1248 fprintf(out_file_, " volatile=%s\n", QuotedBool((flags & kAccVolatile) != 0));
1249 // The "value=" is not knowable w/o parsing annotations.
1250 fprintf(out_file_, " static=%s\n", QuotedBool((flags & kAccStatic) != 0));
1251 fprintf(out_file_, " final=%s\n", QuotedBool((flags & kAccFinal) != 0));
1252 // The "deprecated=" is not knowable w/o parsing annotations.
1253 fprintf(out_file_, " visibility=%s\n", QuotedVisibility(flags));
1254 if (init != nullptr) {
1255 fputs(" value=\"", out_file_);
1256 DumpEncodedValue(init);
1257 fputs("\"\n", out_file_);
1258 }
1259 fputs(">\n</field>\n", out_file_);
1260 }
1261
1262 free(access_str);
1263}
1264
1265/*
1266 * Dumps an instance field.
1267 */
Jeff Haoea7c6292016-11-14 18:10:16 -08001268void DexLayout::DumpIField(uint32_t idx, uint32_t flags, int i) {
1269 DumpSField(idx, flags, i, nullptr);
David Sehr7629f602016-08-07 16:01:51 -07001270}
1271
1272/*
David Sehr7629f602016-08-07 16:01:51 -07001273 * Dumps the class.
1274 *
1275 * Note "idx" is a DexClassDef index, not a DexTypeId index.
1276 *
1277 * If "*last_package" is nullptr or does not match the current class' package,
1278 * the value will be replaced with a newly-allocated string.
1279 */
Jeff Haoea7c6292016-11-14 18:10:16 -08001280void DexLayout::DumpClass(int idx, char** last_package) {
1281 dex_ir::ClassDef* class_def = header_->GetCollections().GetClassDef(idx);
David Sehr7629f602016-08-07 16:01:51 -07001282 // Omitting non-public class.
1283 if (options_.exports_only_ && (class_def->GetAccessFlags() & kAccPublic) == 0) {
1284 return;
1285 }
1286
1287 if (options_.show_section_headers_) {
Jeff Haoea7c6292016-11-14 18:10:16 -08001288 DumpClassDef(idx);
David Sehr7629f602016-08-07 16:01:51 -07001289 }
1290
1291 if (options_.show_annotations_) {
Jeff Haoea7c6292016-11-14 18:10:16 -08001292 DumpClassAnnotations(idx);
David Sehr7629f602016-08-07 16:01:51 -07001293 }
1294
David Sehr7629f602016-08-07 16:01:51 -07001295 // For the XML output, show the package name. Ideally we'd gather
1296 // up the classes, sort them, and dump them alphabetically so the
1297 // package name wouldn't jump around, but that's not a great plan
1298 // for something that needs to run on the device.
Jeff Hao3ab96b42016-09-09 18:35:01 -07001299 const char* class_descriptor =
Jeff Haoea7c6292016-11-14 18:10:16 -08001300 header_->GetCollections().GetClassDef(idx)->ClassType()->GetStringId()->Data();
David Sehr7629f602016-08-07 16:01:51 -07001301 if (!(class_descriptor[0] == 'L' &&
1302 class_descriptor[strlen(class_descriptor)-1] == ';')) {
1303 // Arrays and primitives should not be defined explicitly. Keep going?
1304 fprintf(stderr, "Malformed class name '%s'\n", class_descriptor);
1305 } else if (options_.output_format_ == kOutputXml) {
1306 char* mangle = strdup(class_descriptor + 1);
1307 mangle[strlen(mangle)-1] = '\0';
1308
1309 // Reduce to just the package name.
1310 char* last_slash = strrchr(mangle, '/');
1311 if (last_slash != nullptr) {
1312 *last_slash = '\0';
1313 } else {
1314 *mangle = '\0';
1315 }
1316
1317 for (char* cp = mangle; *cp != '\0'; cp++) {
1318 if (*cp == '/') {
1319 *cp = '.';
1320 }
1321 } // for
1322
1323 if (*last_package == nullptr || strcmp(mangle, *last_package) != 0) {
1324 // Start of a new package.
1325 if (*last_package != nullptr) {
1326 fprintf(out_file_, "</package>\n");
1327 }
1328 fprintf(out_file_, "<package name=\"%s\"\n>\n", mangle);
1329 free(*last_package);
1330 *last_package = mangle;
1331 } else {
1332 free(mangle);
1333 }
1334 }
1335
1336 // General class information.
1337 char* access_str = CreateAccessFlagStr(class_def->GetAccessFlags(), kAccessForClass);
1338 const char* superclass_descriptor = nullptr;
1339 if (class_def->Superclass() != nullptr) {
1340 superclass_descriptor = class_def->Superclass()->GetStringId()->Data();
1341 }
1342 if (options_.output_format_ == kOutputPlain) {
1343 fprintf(out_file_, "Class #%d -\n", idx);
1344 fprintf(out_file_, " Class descriptor : '%s'\n", class_descriptor);
1345 fprintf(out_file_, " Access flags : 0x%04x (%s)\n",
1346 class_def->GetAccessFlags(), access_str);
1347 if (superclass_descriptor != nullptr) {
1348 fprintf(out_file_, " Superclass : '%s'\n", superclass_descriptor);
1349 }
1350 fprintf(out_file_, " Interfaces -\n");
1351 } else {
1352 std::string dot(DescriptorClassToDot(class_descriptor));
1353 fprintf(out_file_, "<class name=\"%s\"\n", dot.c_str());
1354 if (superclass_descriptor != nullptr) {
Jeff Haoc3acfc52016-08-29 14:18:26 -07001355 dot = DescriptorToDotWrapper(superclass_descriptor);
David Sehr7629f602016-08-07 16:01:51 -07001356 fprintf(out_file_, " extends=\"%s\"\n", dot.c_str());
1357 }
1358 fprintf(out_file_, " interface=%s\n",
1359 QuotedBool((class_def->GetAccessFlags() & kAccInterface) != 0));
1360 fprintf(out_file_, " abstract=%s\n",
1361 QuotedBool((class_def->GetAccessFlags() & kAccAbstract) != 0));
1362 fprintf(out_file_, " static=%s\n", QuotedBool((class_def->GetAccessFlags() & kAccStatic) != 0));
1363 fprintf(out_file_, " final=%s\n", QuotedBool((class_def->GetAccessFlags() & kAccFinal) != 0));
1364 // The "deprecated=" not knowable w/o parsing annotations.
1365 fprintf(out_file_, " visibility=%s\n", QuotedVisibility(class_def->GetAccessFlags()));
1366 fprintf(out_file_, ">\n");
1367 }
1368
1369 // Interfaces.
Jeff Hao3ab96b42016-09-09 18:35:01 -07001370 const dex_ir::TypeIdVector* interfaces = class_def->Interfaces();
David Sehr853a8e12016-09-01 13:03:50 -07001371 if (interfaces != nullptr) {
1372 for (uint32_t i = 0; i < interfaces->size(); i++) {
1373 DumpInterface((*interfaces)[i], i);
1374 } // for
1375 }
David Sehr7629f602016-08-07 16:01:51 -07001376
1377 // Fields and methods.
1378 dex_ir::ClassData* class_data = class_def->GetClassData();
1379 // Prepare data for static fields.
Jeff Hao3ab96b42016-09-09 18:35:01 -07001380 dex_ir::EncodedArrayItem* static_values = class_def->StaticValues();
1381 dex_ir::EncodedValueVector* encoded_values =
1382 static_values == nullptr ? nullptr : static_values->GetEncodedValues();
1383 const uint32_t encoded_values_size = (encoded_values == nullptr) ? 0 : encoded_values->size();
David Sehr7629f602016-08-07 16:01:51 -07001384
1385 // Static fields.
1386 if (options_.output_format_ == kOutputPlain) {
1387 fprintf(out_file_, " Static fields -\n");
1388 }
David Sehr853a8e12016-09-01 13:03:50 -07001389 if (class_data != nullptr) {
1390 dex_ir::FieldItemVector* static_fields = class_data->StaticFields();
1391 if (static_fields != nullptr) {
1392 for (uint32_t i = 0; i < static_fields->size(); i++) {
Jeff Haoea7c6292016-11-14 18:10:16 -08001393 DumpSField((*static_fields)[i]->GetFieldId()->GetIndex(),
David Sehr853a8e12016-09-01 13:03:50 -07001394 (*static_fields)[i]->GetAccessFlags(),
1395 i,
Jeff Hao3ab96b42016-09-09 18:35:01 -07001396 i < encoded_values_size ? (*encoded_values)[i].get() : nullptr);
David Sehr853a8e12016-09-01 13:03:50 -07001397 } // for
1398 }
1399 }
David Sehr7629f602016-08-07 16:01:51 -07001400
1401 // Instance fields.
1402 if (options_.output_format_ == kOutputPlain) {
1403 fprintf(out_file_, " Instance fields -\n");
1404 }
David Sehr853a8e12016-09-01 13:03:50 -07001405 if (class_data != nullptr) {
1406 dex_ir::FieldItemVector* instance_fields = class_data->InstanceFields();
1407 if (instance_fields != nullptr) {
1408 for (uint32_t i = 0; i < instance_fields->size(); i++) {
Jeff Haoea7c6292016-11-14 18:10:16 -08001409 DumpIField((*instance_fields)[i]->GetFieldId()->GetIndex(),
David Sehr853a8e12016-09-01 13:03:50 -07001410 (*instance_fields)[i]->GetAccessFlags(),
1411 i);
1412 } // for
1413 }
1414 }
David Sehr7629f602016-08-07 16:01:51 -07001415
1416 // Direct methods.
1417 if (options_.output_format_ == kOutputPlain) {
1418 fprintf(out_file_, " Direct methods -\n");
1419 }
David Sehr853a8e12016-09-01 13:03:50 -07001420 if (class_data != nullptr) {
1421 dex_ir::MethodItemVector* direct_methods = class_data->DirectMethods();
1422 if (direct_methods != nullptr) {
1423 for (uint32_t i = 0; i < direct_methods->size(); i++) {
Jeff Haoea7c6292016-11-14 18:10:16 -08001424 DumpMethod((*direct_methods)[i]->GetMethodId()->GetIndex(),
David Sehr853a8e12016-09-01 13:03:50 -07001425 (*direct_methods)[i]->GetAccessFlags(),
1426 (*direct_methods)[i]->GetCodeItem(),
1427 i);
1428 } // for
1429 }
1430 }
David Sehr7629f602016-08-07 16:01:51 -07001431
1432 // Virtual methods.
1433 if (options_.output_format_ == kOutputPlain) {
1434 fprintf(out_file_, " Virtual methods -\n");
1435 }
David Sehr853a8e12016-09-01 13:03:50 -07001436 if (class_data != nullptr) {
1437 dex_ir::MethodItemVector* virtual_methods = class_data->VirtualMethods();
1438 if (virtual_methods != nullptr) {
1439 for (uint32_t i = 0; i < virtual_methods->size(); i++) {
Jeff Haoea7c6292016-11-14 18:10:16 -08001440 DumpMethod((*virtual_methods)[i]->GetMethodId()->GetIndex(),
David Sehr853a8e12016-09-01 13:03:50 -07001441 (*virtual_methods)[i]->GetAccessFlags(),
1442 (*virtual_methods)[i]->GetCodeItem(),
1443 i);
1444 } // for
1445 }
1446 }
David Sehr7629f602016-08-07 16:01:51 -07001447
1448 // End of class.
1449 if (options_.output_format_ == kOutputPlain) {
1450 const char* file_name = "unknown";
1451 if (class_def->SourceFile() != nullptr) {
1452 file_name = class_def->SourceFile()->Data();
1453 }
1454 const dex_ir::StringId* source_file = class_def->SourceFile();
1455 fprintf(out_file_, " source_file_idx : %d (%s)\n\n",
Jeff Hao3ab96b42016-09-09 18:35:01 -07001456 source_file == nullptr ? 0xffffffffU : source_file->GetIndex(), file_name);
David Sehr7629f602016-08-07 16:01:51 -07001457 } else if (options_.output_format_ == kOutputXml) {
1458 fprintf(out_file_, "</class>\n");
1459 }
1460
1461 free(access_str);
1462}
1463
Jeff Haoea7c6292016-11-14 18:10:16 -08001464void DexLayout::DumpDexFile() {
David Sehr7629f602016-08-07 16:01:51 -07001465 // Headers.
1466 if (options_.show_file_headers_) {
Jeff Haoea7c6292016-11-14 18:10:16 -08001467 DumpFileHeader();
David Sehr7629f602016-08-07 16:01:51 -07001468 }
1469
1470 // Open XML context.
1471 if (options_.output_format_ == kOutputXml) {
1472 fprintf(out_file_, "<api>\n");
1473 }
1474
1475 // Iterate over all classes.
1476 char* package = nullptr;
Jeff Haoea7c6292016-11-14 18:10:16 -08001477 const uint32_t class_defs_size = header_->GetCollections().ClassDefsSize();
David Sehr7629f602016-08-07 16:01:51 -07001478 for (uint32_t i = 0; i < class_defs_size; i++) {
Jeff Haoea7c6292016-11-14 18:10:16 -08001479 DumpClass(i, &package);
David Sehr7629f602016-08-07 16:01:51 -07001480 } // for
1481
1482 // Free the last package allocated.
1483 if (package != nullptr) {
1484 fprintf(out_file_, "</package>\n");
1485 free(package);
1486 }
1487
1488 // Close XML context.
1489 if (options_.output_format_ == kOutputXml) {
1490 fprintf(out_file_, "</api>\n");
1491 }
Jeff Haoea7c6292016-11-14 18:10:16 -08001492}
Jeff Hao3ab96b42016-09-09 18:35:01 -07001493
Jeff Haoe17f5892017-02-23 16:14:04 -08001494std::vector<dex_ir::ClassData*> DexLayout::LayoutClassDefsAndClassData(const DexFile* dex_file) {
Jeff Hao042e8982016-10-19 11:17:11 -07001495 std::vector<dex_ir::ClassDef*> new_class_def_order;
1496 for (std::unique_ptr<dex_ir::ClassDef>& class_def : header_->GetCollections().ClassDefs()) {
1497 dex::TypeIndex type_idx(class_def->ClassType()->GetIndex());
1498 if (info_->ContainsClass(*dex_file, type_idx)) {
1499 new_class_def_order.push_back(class_def.get());
1500 }
1501 }
1502 for (std::unique_ptr<dex_ir::ClassDef>& class_def : header_->GetCollections().ClassDefs()) {
1503 dex::TypeIndex type_idx(class_def->ClassType()->GetIndex());
1504 if (!info_->ContainsClass(*dex_file, type_idx)) {
1505 new_class_def_order.push_back(class_def.get());
1506 }
1507 }
1508 uint32_t class_defs_offset = header_->GetCollections().ClassDefsOffset();
1509 uint32_t class_data_offset = header_->GetCollections().ClassDatasOffset();
Jeff Haoe17f5892017-02-23 16:14:04 -08001510 std::unordered_set<dex_ir::ClassData*> visited_class_data;
1511 std::vector<dex_ir::ClassData*> new_class_data_order;
Jeff Hao042e8982016-10-19 11:17:11 -07001512 for (uint32_t i = 0; i < new_class_def_order.size(); ++i) {
1513 dex_ir::ClassDef* class_def = new_class_def_order[i];
1514 class_def->SetIndex(i);
1515 class_def->SetOffset(class_defs_offset);
1516 class_defs_offset += dex_ir::ClassDef::ItemSize();
Jeff Haoe17f5892017-02-23 16:14:04 -08001517 dex_ir::ClassData* class_data = class_def->GetClassData();
1518 if (class_data != nullptr && visited_class_data.find(class_data) == visited_class_data.end()) {
1519 class_data->SetOffset(class_data_offset);
1520 class_data_offset += class_data->GetSize();
1521 visited_class_data.insert(class_data);
1522 new_class_data_order.push_back(class_data);
Jeff Hao042e8982016-10-19 11:17:11 -07001523 }
1524 }
Jeff Haoe17f5892017-02-23 16:14:04 -08001525 return new_class_data_order;
Jeff Hao042e8982016-10-19 11:17:11 -07001526}
1527
Jeff Haoe17f5892017-02-23 16:14:04 -08001528// Orders code items according to specified class data ordering.
1529// NOTE: If the section following the code items is byte aligned, the last code item is left in
1530// place to preserve alignment. Layout needs an overhaul to handle movement of other sections.
1531int32_t DexLayout::LayoutCodeItems(std::vector<dex_ir::ClassData*> new_class_data_order) {
Jeff Hao863f1d72017-03-01 12:18:19 -08001532 // Do not move code items if class data section precedes code item section.
1533 // ULEB encoding is variable length, causing problems determining the offset of the code items.
1534 // TODO: We should swap the order of these sections in the future to avoid this issue.
1535 uint32_t class_data_offset = header_->GetCollections().ClassDatasOffset();
1536 uint32_t code_item_offset = header_->GetCollections().CodeItemsOffset();
1537 if (class_data_offset < code_item_offset) {
1538 return 0;
1539 }
1540
Jeff Haoe17f5892017-02-23 16:14:04 -08001541 // Find the last code item so we can leave it in place if the next section is not 4 byte aligned.
1542 std::unordered_set<dex_ir::CodeItem*> visited_code_items;
Jeff Hao863f1d72017-03-01 12:18:19 -08001543 bool is_code_item_aligned = IsNextSectionCodeItemAligned(code_item_offset);
Jeff Haoe17f5892017-02-23 16:14:04 -08001544 if (!is_code_item_aligned) {
1545 dex_ir::CodeItem* last_code_item = nullptr;
1546 for (auto& code_item_pair : header_->GetCollections().CodeItems()) {
1547 std::unique_ptr<dex_ir::CodeItem>& code_item = code_item_pair.second;
1548 if (last_code_item == nullptr || last_code_item->GetOffset() < code_item->GetOffset()) {
1549 last_code_item = code_item.get();
Jeff Hao042e8982016-10-19 11:17:11 -07001550 }
Jeff Haoe17f5892017-02-23 16:14:04 -08001551 }
1552 // Preserve the last code item by marking it already visited.
1553 visited_code_items.insert(last_code_item);
1554 }
1555
1556 int32_t diff = 0;
1557 for (dex_ir::ClassData* class_data : new_class_data_order) {
1558 class_data->SetOffset(class_data->GetOffset() + diff);
1559 for (auto& method : *class_data->DirectMethods()) {
1560 dex_ir::CodeItem* code_item = method->GetCodeItem();
1561 if (code_item != nullptr && visited_code_items.find(code_item) == visited_code_items.end()) {
1562 visited_code_items.insert(code_item);
Jeff Hao863f1d72017-03-01 12:18:19 -08001563 diff += UnsignedLeb128Size(code_item_offset) - UnsignedLeb128Size(code_item->GetOffset());
1564 code_item->SetOffset(code_item_offset);
1565 code_item_offset += RoundUp(code_item->GetSize(), kDexCodeItemAlignment);
Jeff Haoe17f5892017-02-23 16:14:04 -08001566 }
1567 }
1568 for (auto& method : *class_data->VirtualMethods()) {
1569 dex_ir::CodeItem* code_item = method->GetCodeItem();
1570 if (code_item != nullptr && visited_code_items.find(code_item) == visited_code_items.end()) {
1571 visited_code_items.insert(code_item);
Jeff Hao863f1d72017-03-01 12:18:19 -08001572 diff += UnsignedLeb128Size(code_item_offset) - UnsignedLeb128Size(code_item->GetOffset());
1573 code_item->SetOffset(code_item_offset);
1574 code_item_offset += RoundUp(code_item->GetSize(), kDexCodeItemAlignment);
Jeff Hao042e8982016-10-19 11:17:11 -07001575 }
1576 }
1577 }
Jeff Haoe17f5892017-02-23 16:14:04 -08001578 // Adjust diff to be 4-byte aligned.
1579 return RoundUp(diff, kDexCodeItemAlignment);
1580}
Jeff Hao042e8982016-10-19 11:17:11 -07001581
Jeff Haoe17f5892017-02-23 16:14:04 -08001582bool DexLayout::IsNextSectionCodeItemAligned(uint32_t offset) {
1583 dex_ir::Collections& collections = header_->GetCollections();
1584 std::set<uint32_t> section_offsets;
1585 section_offsets.insert(collections.MapListOffset());
1586 section_offsets.insert(collections.TypeListsOffset());
1587 section_offsets.insert(collections.AnnotationSetRefListsOffset());
1588 section_offsets.insert(collections.AnnotationSetItemsOffset());
1589 section_offsets.insert(collections.ClassDatasOffset());
1590 section_offsets.insert(collections.CodeItemsOffset());
1591 section_offsets.insert(collections.StringDatasOffset());
1592 section_offsets.insert(collections.DebugInfoItemsOffset());
1593 section_offsets.insert(collections.AnnotationItemsOffset());
1594 section_offsets.insert(collections.EncodedArrayItemsOffset());
1595 section_offsets.insert(collections.AnnotationsDirectoryItemsOffset());
1596
1597 auto found = section_offsets.find(offset);
1598 if (found != section_offsets.end()) {
1599 found++;
1600 if (found != section_offsets.end()) {
1601 return *found % kDexCodeItemAlignment == 0;
1602 }
1603 }
1604 return false;
Jeff Hao042e8982016-10-19 11:17:11 -07001605}
1606
1607// Adjust offsets of every item in the specified section by diff bytes.
1608template<class T> void DexLayout::FixupSection(std::map<uint32_t, std::unique_ptr<T>>& map,
1609 uint32_t diff) {
1610 for (auto& pair : map) {
1611 std::unique_ptr<T>& item = pair.second;
1612 item->SetOffset(item->GetOffset() + diff);
1613 }
1614}
1615
1616// Adjust offsets of all sections with an address after the specified offset by diff bytes.
1617void DexLayout::FixupSections(uint32_t offset, uint32_t diff) {
1618 dex_ir::Collections& collections = header_->GetCollections();
1619 uint32_t map_list_offset = collections.MapListOffset();
1620 if (map_list_offset > offset) {
1621 collections.SetMapListOffset(map_list_offset + diff);
1622 }
1623
1624 uint32_t type_lists_offset = collections.TypeListsOffset();
1625 if (type_lists_offset > offset) {
1626 collections.SetTypeListsOffset(type_lists_offset + diff);
1627 FixupSection(collections.TypeLists(), diff);
1628 }
1629
1630 uint32_t annotation_set_ref_lists_offset = collections.AnnotationSetRefListsOffset();
1631 if (annotation_set_ref_lists_offset > offset) {
1632 collections.SetAnnotationSetRefListsOffset(annotation_set_ref_lists_offset + diff);
1633 FixupSection(collections.AnnotationSetRefLists(), diff);
1634 }
1635
1636 uint32_t annotation_set_items_offset = collections.AnnotationSetItemsOffset();
1637 if (annotation_set_items_offset > offset) {
1638 collections.SetAnnotationSetItemsOffset(annotation_set_items_offset + diff);
1639 FixupSection(collections.AnnotationSetItems(), diff);
1640 }
1641
1642 uint32_t class_datas_offset = collections.ClassDatasOffset();
1643 if (class_datas_offset > offset) {
1644 collections.SetClassDatasOffset(class_datas_offset + diff);
1645 FixupSection(collections.ClassDatas(), diff);
1646 }
1647
1648 uint32_t code_items_offset = collections.CodeItemsOffset();
1649 if (code_items_offset > offset) {
1650 collections.SetCodeItemsOffset(code_items_offset + diff);
1651 FixupSection(collections.CodeItems(), diff);
1652 }
1653
1654 uint32_t string_datas_offset = collections.StringDatasOffset();
1655 if (string_datas_offset > offset) {
1656 collections.SetStringDatasOffset(string_datas_offset + diff);
1657 FixupSection(collections.StringDatas(), diff);
1658 }
1659
1660 uint32_t debug_info_items_offset = collections.DebugInfoItemsOffset();
1661 if (debug_info_items_offset > offset) {
1662 collections.SetDebugInfoItemsOffset(debug_info_items_offset + diff);
1663 FixupSection(collections.DebugInfoItems(), diff);
1664 }
1665
1666 uint32_t annotation_items_offset = collections.AnnotationItemsOffset();
1667 if (annotation_items_offset > offset) {
1668 collections.SetAnnotationItemsOffset(annotation_items_offset + diff);
1669 FixupSection(collections.AnnotationItems(), diff);
1670 }
1671
1672 uint32_t encoded_array_items_offset = collections.EncodedArrayItemsOffset();
1673 if (encoded_array_items_offset > offset) {
1674 collections.SetEncodedArrayItemsOffset(encoded_array_items_offset + diff);
1675 FixupSection(collections.EncodedArrayItems(), diff);
1676 }
1677
1678 uint32_t annotations_directory_items_offset = collections.AnnotationsDirectoryItemsOffset();
1679 if (annotations_directory_items_offset > offset) {
1680 collections.SetAnnotationsDirectoryItemsOffset(annotations_directory_items_offset + diff);
1681 FixupSection(collections.AnnotationsDirectoryItems(), diff);
1682 }
1683}
1684
1685void DexLayout::LayoutOutputFile(const DexFile* dex_file) {
Jeff Haoe17f5892017-02-23 16:14:04 -08001686 std::vector<dex_ir::ClassData*> new_class_data_order = LayoutClassDefsAndClassData(dex_file);
1687 int32_t diff = LayoutCodeItems(new_class_data_order);
Jeff Hao042e8982016-10-19 11:17:11 -07001688 // Move sections after ClassData by diff bytes.
1689 FixupSections(header_->GetCollections().ClassDatasOffset(), diff);
1690 // Update file size.
1691 header_->SetFileSize(header_->FileSize() + diff);
1692}
1693
Jeff Haoea7c6292016-11-14 18:10:16 -08001694void DexLayout::OutputDexFile(const std::string& dex_file_location) {
1695 std::string error_msg;
1696 std::unique_ptr<File> new_file;
1697 if (!options_.output_to_memmap_) {
Jeff Haoa8621002016-10-04 18:13:44 +00001698 std::string output_location(options_.output_dex_directory_);
Jeff Haoea7c6292016-11-14 18:10:16 -08001699 size_t last_slash = dex_file_location.rfind("/");
1700 std::string dex_file_directory = dex_file_location.substr(0, last_slash + 1);
1701 if (output_location == dex_file_directory) {
1702 output_location = dex_file_location + ".new";
1703 } else if (last_slash != std::string::npos) {
1704 output_location += dex_file_location.substr(last_slash);
1705 } else {
1706 output_location += "/" + dex_file_location + ".new";
1707 }
1708 new_file.reset(OS::CreateEmptyFile(output_location.c_str()));
1709 ftruncate(new_file->Fd(), header_->FileSize());
1710 mem_map_.reset(MemMap::MapFile(header_->FileSize(), PROT_READ | PROT_WRITE, MAP_SHARED,
1711 new_file->Fd(), 0, /*low_4gb*/ false, output_location.c_str(), &error_msg));
1712 } else {
1713 mem_map_.reset(MemMap::MapAnonymous("layout dex", nullptr, header_->FileSize(),
1714 PROT_READ | PROT_WRITE, /* low_4gb */ false, /* reuse */ false, &error_msg));
1715 }
1716 if (mem_map_ == nullptr) {
1717 LOG(ERROR) << "Could not create mem map for dex writer output: " << error_msg;
1718 if (new_file.get() != nullptr) {
1719 new_file->Erase();
1720 }
1721 return;
1722 }
1723 DexWriter::Output(header_, mem_map_.get());
1724 if (new_file != nullptr) {
1725 UNUSED(new_file->FlushCloseOrErase());
1726 }
1727}
1728
1729/*
1730 * Dumps the requested sections of the file.
1731 */
1732void DexLayout::ProcessDexFile(const char* file_name,
1733 const DexFile* dex_file,
1734 size_t dex_file_index) {
1735 std::unique_ptr<dex_ir::Header> header(dex_ir::DexIrBuilder(*dex_file));
1736 SetHeader(header.get());
1737
1738 if (options_.verbose_) {
1739 fprintf(out_file_, "Opened '%s', DEX version '%.3s'\n",
1740 file_name, dex_file->GetHeader().magic_ + 4);
1741 }
1742
1743 if (options_.visualize_pattern_) {
1744 VisualizeDexLayout(header_, dex_file, dex_file_index, info_);
1745 return;
1746 }
1747
David Sehr93357492017-03-09 08:02:44 -08001748 if (options_.show_section_statistics_) {
1749 ShowDexSectionStatistics(header_, dex_file_index);
1750 return;
1751 }
1752
Jeff Haoea7c6292016-11-14 18:10:16 -08001753 // Dump dex file.
1754 if (options_.dump_) {
1755 DumpDexFile();
1756 }
1757
1758 // Output dex file as file or memmap.
1759 if (options_.output_dex_directory_ != nullptr || options_.output_to_memmap_) {
Jeff Hao042e8982016-10-19 11:17:11 -07001760 if (info_ != nullptr) {
1761 LayoutOutputFile(dex_file);
1762 }
Jeff Haoea7c6292016-11-14 18:10:16 -08001763 OutputDexFile(dex_file->GetLocation());
Jeff Hao3ab96b42016-09-09 18:35:01 -07001764 }
David Sehr7629f602016-08-07 16:01:51 -07001765}
1766
1767/*
1768 * Processes a single file (either direct .dex or indirect .zip/.jar/.apk).
1769 */
Jeff Haoea7c6292016-11-14 18:10:16 -08001770int DexLayout::ProcessFile(const char* file_name) {
David Sehr7629f602016-08-07 16:01:51 -07001771 if (options_.verbose_) {
1772 fprintf(out_file_, "Processing '%s'...\n", file_name);
1773 }
1774
1775 // If the file is not a .dex file, the function tries .zip/.jar/.apk files,
1776 // all of which are Zip archives with "classes.dex" inside.
1777 const bool verify_checksum = !options_.ignore_bad_checksum_;
1778 std::string error_msg;
1779 std::vector<std::unique_ptr<const DexFile>> dex_files;
1780 if (!DexFile::Open(file_name, file_name, verify_checksum, &error_msg, &dex_files)) {
1781 // Display returned error message to user. Note that this error behavior
1782 // differs from the error messages shown by the original Dalvik dexdump.
1783 fputs(error_msg.c_str(), stderr);
1784 fputc('\n', stderr);
1785 return -1;
1786 }
1787
1788 // Success. Either report checksum verification or process
1789 // all dex files found in given file.
1790 if (options_.checksum_only_) {
1791 fprintf(out_file_, "Checksum verified\n");
1792 } else {
1793 for (size_t i = 0; i < dex_files.size(); i++) {
David Sehrcdcfde72016-09-26 07:44:04 -07001794 ProcessDexFile(file_name, dex_files[i].get(), i);
David Sehr7629f602016-08-07 16:01:51 -07001795 }
1796 }
1797 return 0;
1798}
1799
1800} // namespace art