blob: 01b28b55cff9a3e23b10bc902e23c310c46d1275 [file] [log] [blame]
Aart Bik69ae54a2015-07-01 14:52:26 -07001/*
2 * Copyright (C) 2015 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 dexdump utility.
17 *
18 * This is a re-implementation of the original dexdump utility that was
19 * based on Dalvik functions in libdex into a new dexdump that is now
Aart Bikdce50862016-06-10 16:04:03 -070020 * based on Art functions in libart instead. The output is very similar to
21 * to the original for correct DEX files. Error messages may differ, however.
Aart Bik69ae54a2015-07-01 14:52:26 -070022 * Also, ODEX files are no longer supported.
23 *
24 * The dexdump tool is intended to mimic objdump. When possible, use
25 * similar command-line arguments.
26 *
27 * Differences between XML output and the "current.xml" file:
28 * - classes in same package are not all grouped together; nothing is sorted
29 * - no "deprecated" on fields and methods
Aart Bik69ae54a2015-07-01 14:52:26 -070030 * - no parameter names
31 * - no generic signatures on parameters, e.g. type="java.lang.Class<?>"
32 * - class shows declared fields and methods; does not show inherited fields
33 */
34
35#include "dexdump.h"
36
David Sehr5a1f6292018-01-19 11:08:51 -080037#include <fcntl.h>
Aart Bik69ae54a2015-07-01 14:52:26 -070038#include <inttypes.h>
39#include <stdio.h>
David Sehr5a1f6292018-01-19 11:08:51 -080040#include <sys/mman.h>
41#include <sys/types.h>
42#include <sys/stat.h>
43#include <unistd.h>
Aart Bik69ae54a2015-07-01 14:52:26 -070044
Andreas Gampe5073fed2015-08-10 11:40:25 -070045#include <iostream>
Aart Bik69ae54a2015-07-01 14:52:26 -070046#include <memory>
Andreas Gampe5073fed2015-08-10 11:40:25 -070047#include <sstream>
Aart Bik69ae54a2015-07-01 14:52:26 -070048#include <vector>
49
Andreas Gampe221d9812018-01-22 17:48:56 -080050#include "android-base/logging.h"
Andreas Gampe46ee31b2016-12-14 10:11:49 -080051#include "android-base/stringprintf.h"
52
David Sehr0225f8e2018-01-31 08:52:24 +000053#include "dex/code_item_accessors-inl.h"
David Sehr9e734c72018-01-04 17:56:19 -080054#include "dex/dex_file-inl.h"
55#include "dex/dex_file_exception_helpers.h"
56#include "dex/dex_file_loader.h"
57#include "dex/dex_file_types.h"
58#include "dex/dex_instruction-inl.h"
Andreas Gampe8cf9cb32017-07-19 09:28:38 -070059#include "dexdump_cfg.h"
Aart Bik69ae54a2015-07-01 14:52:26 -070060
61namespace art {
62
63/*
64 * Options parsed in main driver.
65 */
66struct Options gOptions;
67
68/*
Aart Bik4e149602015-07-09 11:45:28 -070069 * Output file. Defaults to stdout.
Aart Bik69ae54a2015-07-01 14:52:26 -070070 */
71FILE* gOutFile = stdout;
72
73/*
74 * Data types that match the definitions in the VM specification.
75 */
76typedef uint8_t u1;
77typedef uint16_t u2;
78typedef uint32_t u4;
79typedef uint64_t u8;
Aart Bikdce50862016-06-10 16:04:03 -070080typedef int8_t s1;
81typedef int16_t s2;
Aart Bik69ae54a2015-07-01 14:52:26 -070082typedef int32_t s4;
83typedef int64_t s8;
84
85/*
86 * Basic information about a field or a method.
87 */
88struct FieldMethodInfo {
89 const char* classDescriptor;
90 const char* name;
91 const char* signature;
92};
93
94/*
95 * Flags for use with createAccessFlagStr().
96 */
97enum AccessFor {
98 kAccessForClass = 0, kAccessForMethod = 1, kAccessForField = 2, kAccessForMAX
99};
100const int kNumFlags = 18;
101
102/*
103 * Gets 2 little-endian bytes.
104 */
105static inline u2 get2LE(unsigned char const* pSrc) {
106 return pSrc[0] | (pSrc[1] << 8);
107}
108
109/*
110 * Converts a single-character primitive type into human-readable form.
111 */
112static const char* primitiveTypeLabel(char typeChar) {
113 switch (typeChar) {
114 case 'B': return "byte";
115 case 'C': return "char";
116 case 'D': return "double";
117 case 'F': return "float";
118 case 'I': return "int";
119 case 'J': return "long";
120 case 'S': return "short";
121 case 'V': return "void";
122 case 'Z': return "boolean";
123 default: return "UNKNOWN";
124 } // switch
125}
126
127/*
128 * Converts a type descriptor to human-readable "dotted" form. For
129 * example, "Ljava/lang/String;" becomes "java.lang.String", and
130 * "[I" becomes "int[]". Also converts '$' to '.', which means this
131 * form can't be converted back to a descriptor.
132 */
Aart Bikc05e2f22016-07-12 15:53:13 -0700133static std::unique_ptr<char[]> descriptorToDot(const char* str) {
Aart Bik69ae54a2015-07-01 14:52:26 -0700134 int targetLen = strlen(str);
135 int offset = 0;
136
137 // Strip leading [s; will be added to end.
138 while (targetLen > 1 && str[offset] == '[') {
139 offset++;
140 targetLen--;
141 } // while
142
143 const int arrayDepth = offset;
144
145 if (targetLen == 1) {
146 // Primitive type.
147 str = primitiveTypeLabel(str[offset]);
148 offset = 0;
149 targetLen = strlen(str);
150 } else {
151 // Account for leading 'L' and trailing ';'.
152 if (targetLen >= 2 && str[offset] == 'L' &&
153 str[offset + targetLen - 1] == ';') {
154 targetLen -= 2;
155 offset++;
156 }
157 }
158
159 // Copy class name over.
Aart Bikc05e2f22016-07-12 15:53:13 -0700160 std::unique_ptr<char[]> newStr(new char[targetLen + arrayDepth * 2 + 1]);
Aart Bik69ae54a2015-07-01 14:52:26 -0700161 int i = 0;
162 for (; i < targetLen; i++) {
163 const char ch = str[offset + i];
164 newStr[i] = (ch == '/' || ch == '$') ? '.' : ch;
165 } // for
166
167 // Add the appropriate number of brackets for arrays.
168 for (int j = 0; j < arrayDepth; j++) {
169 newStr[i++] = '[';
170 newStr[i++] = ']';
171 } // for
172
173 newStr[i] = '\0';
174 return newStr;
175}
176
177/*
178 * Converts the class name portion of a type descriptor to human-readable
Aart Bikc05e2f22016-07-12 15:53:13 -0700179 * "dotted" form. For example, "Ljava/lang/String;" becomes "String".
Aart Bik69ae54a2015-07-01 14:52:26 -0700180 */
Aart Bikc05e2f22016-07-12 15:53:13 -0700181static std::unique_ptr<char[]> descriptorClassToDot(const char* str) {
182 // Reduce to just the class name prefix.
Aart Bik69ae54a2015-07-01 14:52:26 -0700183 const char* lastSlash = strrchr(str, '/');
184 if (lastSlash == nullptr) {
185 lastSlash = str + 1; // start past 'L'
186 } else {
187 lastSlash++; // start past '/'
188 }
189
Aart Bikc05e2f22016-07-12 15:53:13 -0700190 // Copy class name over, trimming trailing ';'.
191 const int targetLen = strlen(lastSlash);
192 std::unique_ptr<char[]> newStr(new char[targetLen]);
193 for (int i = 0; i < targetLen - 1; i++) {
194 const char ch = lastSlash[i];
195 newStr[i] = ch == '$' ? '.' : ch;
Aart Bik69ae54a2015-07-01 14:52:26 -0700196 } // for
Aart Bikc05e2f22016-07-12 15:53:13 -0700197 newStr[targetLen - 1] = '\0';
Aart Bik69ae54a2015-07-01 14:52:26 -0700198 return newStr;
199}
200
201/*
Aart Bikdce50862016-06-10 16:04:03 -0700202 * Returns string representing the boolean value.
203 */
204static const char* strBool(bool val) {
205 return val ? "true" : "false";
206}
207
208/*
Aart Bik69ae54a2015-07-01 14:52:26 -0700209 * Returns a quoted string representing the boolean value.
210 */
211static const char* quotedBool(bool val) {
212 return val ? "\"true\"" : "\"false\"";
213}
214
215/*
216 * Returns a quoted string representing the access flags.
217 */
218static const char* quotedVisibility(u4 accessFlags) {
219 if (accessFlags & kAccPublic) {
220 return "\"public\"";
221 } else if (accessFlags & kAccProtected) {
222 return "\"protected\"";
223 } else if (accessFlags & kAccPrivate) {
224 return "\"private\"";
225 } else {
226 return "\"package\"";
227 }
228}
229
230/*
231 * Counts the number of '1' bits in a word.
232 */
233static int countOnes(u4 val) {
234 val = val - ((val >> 1) & 0x55555555);
235 val = (val & 0x33333333) + ((val >> 2) & 0x33333333);
236 return (((val + (val >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24;
237}
238
239/*
240 * Creates a new string with human-readable access flags.
241 *
242 * In the base language the access_flags fields are type u2; in Dalvik
243 * they're u4.
244 */
245static char* createAccessFlagStr(u4 flags, AccessFor forWhat) {
246 static const char* kAccessStrings[kAccessForMAX][kNumFlags] = {
247 {
248 "PUBLIC", /* 0x00001 */
249 "PRIVATE", /* 0x00002 */
250 "PROTECTED", /* 0x00004 */
251 "STATIC", /* 0x00008 */
252 "FINAL", /* 0x00010 */
253 "?", /* 0x00020 */
254 "?", /* 0x00040 */
255 "?", /* 0x00080 */
256 "?", /* 0x00100 */
257 "INTERFACE", /* 0x00200 */
258 "ABSTRACT", /* 0x00400 */
259 "?", /* 0x00800 */
260 "SYNTHETIC", /* 0x01000 */
261 "ANNOTATION", /* 0x02000 */
262 "ENUM", /* 0x04000 */
263 "?", /* 0x08000 */
264 "VERIFIED", /* 0x10000 */
265 "OPTIMIZED", /* 0x20000 */
266 }, {
267 "PUBLIC", /* 0x00001 */
268 "PRIVATE", /* 0x00002 */
269 "PROTECTED", /* 0x00004 */
270 "STATIC", /* 0x00008 */
271 "FINAL", /* 0x00010 */
272 "SYNCHRONIZED", /* 0x00020 */
273 "BRIDGE", /* 0x00040 */
274 "VARARGS", /* 0x00080 */
275 "NATIVE", /* 0x00100 */
276 "?", /* 0x00200 */
277 "ABSTRACT", /* 0x00400 */
278 "STRICT", /* 0x00800 */
279 "SYNTHETIC", /* 0x01000 */
280 "?", /* 0x02000 */
281 "?", /* 0x04000 */
282 "MIRANDA", /* 0x08000 */
283 "CONSTRUCTOR", /* 0x10000 */
284 "DECLARED_SYNCHRONIZED", /* 0x20000 */
285 }, {
286 "PUBLIC", /* 0x00001 */
287 "PRIVATE", /* 0x00002 */
288 "PROTECTED", /* 0x00004 */
289 "STATIC", /* 0x00008 */
290 "FINAL", /* 0x00010 */
291 "?", /* 0x00020 */
292 "VOLATILE", /* 0x00040 */
293 "TRANSIENT", /* 0x00080 */
294 "?", /* 0x00100 */
295 "?", /* 0x00200 */
296 "?", /* 0x00400 */
297 "?", /* 0x00800 */
298 "SYNTHETIC", /* 0x01000 */
299 "?", /* 0x02000 */
300 "ENUM", /* 0x04000 */
301 "?", /* 0x08000 */
302 "?", /* 0x10000 */
303 "?", /* 0x20000 */
304 },
305 };
306
307 // Allocate enough storage to hold the expected number of strings,
308 // plus a space between each. We over-allocate, using the longest
309 // string above as the base metric.
310 const int kLongest = 21; // The strlen of longest string above.
311 const int count = countOnes(flags);
312 char* str;
313 char* cp;
314 cp = str = reinterpret_cast<char*>(malloc(count * (kLongest + 1) + 1));
315
316 for (int i = 0; i < kNumFlags; i++) {
317 if (flags & 0x01) {
318 const char* accessStr = kAccessStrings[forWhat][i];
319 const int len = strlen(accessStr);
320 if (cp != str) {
321 *cp++ = ' ';
322 }
323 memcpy(cp, accessStr, len);
324 cp += len;
325 }
326 flags >>= 1;
327 } // for
328
329 *cp = '\0';
330 return str;
331}
332
333/*
334 * Copies character data from "data" to "out", converting non-ASCII values
335 * to fprintf format chars or an ASCII filler ('.' or '?').
336 *
337 * The output buffer must be able to hold (2*len)+1 bytes. The result is
338 * NULL-terminated.
339 */
340static void asciify(char* out, const unsigned char* data, size_t len) {
341 while (len--) {
342 if (*data < 0x20) {
343 // Could do more here, but we don't need them yet.
344 switch (*data) {
345 case '\0':
346 *out++ = '\\';
347 *out++ = '0';
348 break;
349 case '\n':
350 *out++ = '\\';
351 *out++ = 'n';
352 break;
353 default:
354 *out++ = '.';
355 break;
356 } // switch
357 } else if (*data >= 0x80) {
358 *out++ = '?';
359 } else {
360 *out++ = *data;
361 }
362 data++;
363 } // while
364 *out = '\0';
365}
366
367/*
Aart Bikdce50862016-06-10 16:04:03 -0700368 * Dumps a string value with some escape characters.
369 */
370static void dumpEscapedString(const char* p) {
371 fputs("\"", gOutFile);
372 for (; *p; p++) {
373 switch (*p) {
374 case '\\':
375 fputs("\\\\", gOutFile);
376 break;
377 case '\"':
378 fputs("\\\"", gOutFile);
379 break;
380 case '\t':
381 fputs("\\t", gOutFile);
382 break;
383 case '\n':
384 fputs("\\n", gOutFile);
385 break;
386 case '\r':
387 fputs("\\r", gOutFile);
388 break;
389 default:
390 putc(*p, gOutFile);
391 } // switch
392 } // for
393 fputs("\"", gOutFile);
394}
395
396/*
397 * Dumps a string as an XML attribute value.
398 */
399static void dumpXmlAttribute(const char* p) {
400 for (; *p; p++) {
401 switch (*p) {
402 case '&':
403 fputs("&amp;", gOutFile);
404 break;
405 case '<':
406 fputs("&lt;", gOutFile);
407 break;
408 case '>':
409 fputs("&gt;", gOutFile);
410 break;
411 case '"':
412 fputs("&quot;", gOutFile);
413 break;
414 case '\t':
415 fputs("&#x9;", gOutFile);
416 break;
417 case '\n':
418 fputs("&#xA;", gOutFile);
419 break;
420 case '\r':
421 fputs("&#xD;", gOutFile);
422 break;
423 default:
424 putc(*p, gOutFile);
425 } // switch
426 } // for
427}
428
429/*
430 * Reads variable width value, possibly sign extended at the last defined byte.
431 */
432static u8 readVarWidth(const u1** data, u1 arg, bool sign_extend) {
433 u8 value = 0;
434 for (u4 i = 0; i <= arg; i++) {
435 value |= static_cast<u8>(*(*data)++) << (i * 8);
436 }
437 if (sign_extend) {
438 int shift = (7 - arg) * 8;
439 return (static_cast<s8>(value) << shift) >> shift;
440 }
441 return value;
442}
443
444/*
445 * Dumps encoded value.
446 */
447static void dumpEncodedValue(const DexFile* pDexFile, const u1** data); // forward
448static void dumpEncodedValue(const DexFile* pDexFile, const u1** data, u1 type, u1 arg) {
449 switch (type) {
450 case DexFile::kDexAnnotationByte:
451 fprintf(gOutFile, "%" PRId8, static_cast<s1>(readVarWidth(data, arg, false)));
452 break;
453 case DexFile::kDexAnnotationShort:
454 fprintf(gOutFile, "%" PRId16, static_cast<s2>(readVarWidth(data, arg, true)));
455 break;
456 case DexFile::kDexAnnotationChar:
457 fprintf(gOutFile, "%" PRIu16, static_cast<u2>(readVarWidth(data, arg, false)));
458 break;
459 case DexFile::kDexAnnotationInt:
460 fprintf(gOutFile, "%" PRId32, static_cast<s4>(readVarWidth(data, arg, true)));
461 break;
462 case DexFile::kDexAnnotationLong:
463 fprintf(gOutFile, "%" PRId64, static_cast<s8>(readVarWidth(data, arg, true)));
464 break;
465 case DexFile::kDexAnnotationFloat: {
466 // Fill on right.
467 union {
468 float f;
469 u4 data;
470 } conv;
471 conv.data = static_cast<u4>(readVarWidth(data, arg, false)) << (3 - arg) * 8;
472 fprintf(gOutFile, "%g", conv.f);
473 break;
474 }
475 case DexFile::kDexAnnotationDouble: {
476 // Fill on right.
477 union {
478 double d;
479 u8 data;
480 } conv;
481 conv.data = readVarWidth(data, arg, false) << (7 - arg) * 8;
482 fprintf(gOutFile, "%g", conv.d);
483 break;
484 }
485 case DexFile::kDexAnnotationString: {
486 const u4 idx = static_cast<u4>(readVarWidth(data, arg, false));
487 if (gOptions.outputFormat == OUTPUT_PLAIN) {
Andreas Gampe8a0128a2016-11-28 07:38:35 -0800488 dumpEscapedString(pDexFile->StringDataByIdx(dex::StringIndex(idx)));
Aart Bikdce50862016-06-10 16:04:03 -0700489 } else {
Andreas Gampe8a0128a2016-11-28 07:38:35 -0800490 dumpXmlAttribute(pDexFile->StringDataByIdx(dex::StringIndex(idx)));
Aart Bikdce50862016-06-10 16:04:03 -0700491 }
492 break;
493 }
494 case DexFile::kDexAnnotationType: {
495 const u4 str_idx = static_cast<u4>(readVarWidth(data, arg, false));
Andreas Gampea5b09a62016-11-17 15:21:22 -0800496 fputs(pDexFile->StringByTypeIdx(dex::TypeIndex(str_idx)), gOutFile);
Aart Bikdce50862016-06-10 16:04:03 -0700497 break;
498 }
499 case DexFile::kDexAnnotationField:
500 case DexFile::kDexAnnotationEnum: {
501 const u4 field_idx = static_cast<u4>(readVarWidth(data, arg, false));
502 const DexFile::FieldId& pFieldId = pDexFile->GetFieldId(field_idx);
503 fputs(pDexFile->StringDataByIdx(pFieldId.name_idx_), gOutFile);
504 break;
505 }
506 case DexFile::kDexAnnotationMethod: {
507 const u4 method_idx = static_cast<u4>(readVarWidth(data, arg, false));
508 const DexFile::MethodId& pMethodId = pDexFile->GetMethodId(method_idx);
509 fputs(pDexFile->StringDataByIdx(pMethodId.name_idx_), gOutFile);
510 break;
511 }
512 case DexFile::kDexAnnotationArray: {
513 fputc('{', gOutFile);
514 // Decode and display all elements.
515 const u4 size = DecodeUnsignedLeb128(data);
516 for (u4 i = 0; i < size; i++) {
517 fputc(' ', gOutFile);
518 dumpEncodedValue(pDexFile, data);
519 }
520 fputs(" }", gOutFile);
521 break;
522 }
523 case DexFile::kDexAnnotationAnnotation: {
524 const u4 type_idx = DecodeUnsignedLeb128(data);
Andreas Gampea5b09a62016-11-17 15:21:22 -0800525 fputs(pDexFile->StringByTypeIdx(dex::TypeIndex(type_idx)), gOutFile);
Aart Bikdce50862016-06-10 16:04:03 -0700526 // Decode and display all name=value pairs.
527 const u4 size = DecodeUnsignedLeb128(data);
528 for (u4 i = 0; i < size; i++) {
529 const u4 name_idx = DecodeUnsignedLeb128(data);
530 fputc(' ', gOutFile);
Andreas Gampe8a0128a2016-11-28 07:38:35 -0800531 fputs(pDexFile->StringDataByIdx(dex::StringIndex(name_idx)), gOutFile);
Aart Bikdce50862016-06-10 16:04:03 -0700532 fputc('=', gOutFile);
533 dumpEncodedValue(pDexFile, data);
534 }
535 break;
536 }
537 case DexFile::kDexAnnotationNull:
538 fputs("null", gOutFile);
539 break;
540 case DexFile::kDexAnnotationBoolean:
541 fputs(strBool(arg), gOutFile);
542 break;
543 default:
544 fputs("????", gOutFile);
545 break;
546 } // switch
547}
548
549/*
550 * Dumps encoded value with prefix.
551 */
552static void dumpEncodedValue(const DexFile* pDexFile, const u1** data) {
553 const u1 enc = *(*data)++;
554 dumpEncodedValue(pDexFile, data, enc & 0x1f, enc >> 5);
555}
556
557/*
Aart Bik69ae54a2015-07-01 14:52:26 -0700558 * Dumps the file header.
Aart Bik69ae54a2015-07-01 14:52:26 -0700559 */
560static void dumpFileHeader(const DexFile* pDexFile) {
561 const DexFile::Header& pHeader = pDexFile->GetHeader();
562 char sanitized[sizeof(pHeader.magic_) * 2 + 1];
563 fprintf(gOutFile, "DEX file header:\n");
564 asciify(sanitized, pHeader.magic_, sizeof(pHeader.magic_));
565 fprintf(gOutFile, "magic : '%s'\n", sanitized);
566 fprintf(gOutFile, "checksum : %08x\n", pHeader.checksum_);
567 fprintf(gOutFile, "signature : %02x%02x...%02x%02x\n",
568 pHeader.signature_[0], pHeader.signature_[1],
569 pHeader.signature_[DexFile::kSha1DigestSize - 2],
570 pHeader.signature_[DexFile::kSha1DigestSize - 1]);
571 fprintf(gOutFile, "file_size : %d\n", pHeader.file_size_);
572 fprintf(gOutFile, "header_size : %d\n", pHeader.header_size_);
573 fprintf(gOutFile, "link_size : %d\n", pHeader.link_size_);
574 fprintf(gOutFile, "link_off : %d (0x%06x)\n",
575 pHeader.link_off_, pHeader.link_off_);
576 fprintf(gOutFile, "string_ids_size : %d\n", pHeader.string_ids_size_);
577 fprintf(gOutFile, "string_ids_off : %d (0x%06x)\n",
578 pHeader.string_ids_off_, pHeader.string_ids_off_);
579 fprintf(gOutFile, "type_ids_size : %d\n", pHeader.type_ids_size_);
580 fprintf(gOutFile, "type_ids_off : %d (0x%06x)\n",
581 pHeader.type_ids_off_, pHeader.type_ids_off_);
Aart Bikdce50862016-06-10 16:04:03 -0700582 fprintf(gOutFile, "proto_ids_size : %d\n", pHeader.proto_ids_size_);
583 fprintf(gOutFile, "proto_ids_off : %d (0x%06x)\n",
Aart Bik69ae54a2015-07-01 14:52:26 -0700584 pHeader.proto_ids_off_, pHeader.proto_ids_off_);
585 fprintf(gOutFile, "field_ids_size : %d\n", pHeader.field_ids_size_);
586 fprintf(gOutFile, "field_ids_off : %d (0x%06x)\n",
587 pHeader.field_ids_off_, pHeader.field_ids_off_);
588 fprintf(gOutFile, "method_ids_size : %d\n", pHeader.method_ids_size_);
589 fprintf(gOutFile, "method_ids_off : %d (0x%06x)\n",
590 pHeader.method_ids_off_, pHeader.method_ids_off_);
591 fprintf(gOutFile, "class_defs_size : %d\n", pHeader.class_defs_size_);
592 fprintf(gOutFile, "class_defs_off : %d (0x%06x)\n",
593 pHeader.class_defs_off_, pHeader.class_defs_off_);
594 fprintf(gOutFile, "data_size : %d\n", pHeader.data_size_);
595 fprintf(gOutFile, "data_off : %d (0x%06x)\n\n",
596 pHeader.data_off_, pHeader.data_off_);
597}
598
599/*
600 * Dumps a class_def_item.
601 */
602static void dumpClassDef(const DexFile* pDexFile, int idx) {
603 // General class information.
604 const DexFile::ClassDef& pClassDef = pDexFile->GetClassDef(idx);
605 fprintf(gOutFile, "Class #%d header:\n", idx);
Andreas Gampea5b09a62016-11-17 15:21:22 -0800606 fprintf(gOutFile, "class_idx : %d\n", pClassDef.class_idx_.index_);
Aart Bik69ae54a2015-07-01 14:52:26 -0700607 fprintf(gOutFile, "access_flags : %d (0x%04x)\n",
608 pClassDef.access_flags_, pClassDef.access_flags_);
Andreas Gampea5b09a62016-11-17 15:21:22 -0800609 fprintf(gOutFile, "superclass_idx : %d\n", pClassDef.superclass_idx_.index_);
Aart Bik69ae54a2015-07-01 14:52:26 -0700610 fprintf(gOutFile, "interfaces_off : %d (0x%06x)\n",
611 pClassDef.interfaces_off_, pClassDef.interfaces_off_);
Andreas Gampe8a0128a2016-11-28 07:38:35 -0800612 fprintf(gOutFile, "source_file_idx : %d\n", pClassDef.source_file_idx_.index_);
Aart Bik69ae54a2015-07-01 14:52:26 -0700613 fprintf(gOutFile, "annotations_off : %d (0x%06x)\n",
614 pClassDef.annotations_off_, pClassDef.annotations_off_);
615 fprintf(gOutFile, "class_data_off : %d (0x%06x)\n",
616 pClassDef.class_data_off_, pClassDef.class_data_off_);
617
618 // Fields and methods.
619 const u1* pEncodedData = pDexFile->GetClassData(pClassDef);
620 if (pEncodedData != nullptr) {
621 ClassDataItemIterator pClassData(*pDexFile, pEncodedData);
622 fprintf(gOutFile, "static_fields_size : %d\n", pClassData.NumStaticFields());
623 fprintf(gOutFile, "instance_fields_size: %d\n", pClassData.NumInstanceFields());
624 fprintf(gOutFile, "direct_methods_size : %d\n", pClassData.NumDirectMethods());
625 fprintf(gOutFile, "virtual_methods_size: %d\n", pClassData.NumVirtualMethods());
626 } else {
627 fprintf(gOutFile, "static_fields_size : 0\n");
628 fprintf(gOutFile, "instance_fields_size: 0\n");
629 fprintf(gOutFile, "direct_methods_size : 0\n");
630 fprintf(gOutFile, "virtual_methods_size: 0\n");
631 }
632 fprintf(gOutFile, "\n");
633}
634
Aart Bikdce50862016-06-10 16:04:03 -0700635/**
636 * Dumps an annotation set item.
637 */
638static void dumpAnnotationSetItem(const DexFile* pDexFile, const DexFile::AnnotationSetItem* set_item) {
639 if (set_item == nullptr || set_item->size_ == 0) {
640 fputs(" empty-annotation-set\n", gOutFile);
641 return;
642 }
643 for (u4 i = 0; i < set_item->size_; i++) {
644 const DexFile::AnnotationItem* annotation = pDexFile->GetAnnotationItem(set_item, i);
645 if (annotation == nullptr) {
646 continue;
647 }
648 fputs(" ", gOutFile);
649 switch (annotation->visibility_) {
650 case DexFile::kDexVisibilityBuild: fputs("VISIBILITY_BUILD ", gOutFile); break;
651 case DexFile::kDexVisibilityRuntime: fputs("VISIBILITY_RUNTIME ", gOutFile); break;
652 case DexFile::kDexVisibilitySystem: fputs("VISIBILITY_SYSTEM ", gOutFile); break;
653 default: fputs("VISIBILITY_UNKNOWN ", gOutFile); break;
654 } // switch
655 // Decode raw bytes in annotation.
656 const u1* rData = annotation->annotation_;
657 dumpEncodedValue(pDexFile, &rData, DexFile::kDexAnnotationAnnotation, 0);
658 fputc('\n', gOutFile);
659 }
660}
661
662/*
663 * Dumps class annotations.
664 */
665static void dumpClassAnnotations(const DexFile* pDexFile, int idx) {
666 const DexFile::ClassDef& pClassDef = pDexFile->GetClassDef(idx);
667 const DexFile::AnnotationsDirectoryItem* dir = pDexFile->GetAnnotationsDirectory(pClassDef);
668 if (dir == nullptr) {
669 return; // none
670 }
671
672 fprintf(gOutFile, "Class #%d annotations:\n", idx);
673
674 const DexFile::AnnotationSetItem* class_set_item = pDexFile->GetClassAnnotationSet(dir);
675 const DexFile::FieldAnnotationsItem* fields = pDexFile->GetFieldAnnotations(dir);
676 const DexFile::MethodAnnotationsItem* methods = pDexFile->GetMethodAnnotations(dir);
677 const DexFile::ParameterAnnotationsItem* pars = pDexFile->GetParameterAnnotations(dir);
678
679 // Annotations on the class itself.
680 if (class_set_item != nullptr) {
681 fprintf(gOutFile, "Annotations on class\n");
682 dumpAnnotationSetItem(pDexFile, class_set_item);
683 }
684
685 // Annotations on fields.
686 if (fields != nullptr) {
687 for (u4 i = 0; i < dir->fields_size_; i++) {
688 const u4 field_idx = fields[i].field_idx_;
689 const DexFile::FieldId& pFieldId = pDexFile->GetFieldId(field_idx);
690 const char* field_name = pDexFile->StringDataByIdx(pFieldId.name_idx_);
691 fprintf(gOutFile, "Annotations on field #%u '%s'\n", field_idx, field_name);
692 dumpAnnotationSetItem(pDexFile, pDexFile->GetFieldAnnotationSetItem(fields[i]));
693 }
694 }
695
696 // Annotations on methods.
697 if (methods != nullptr) {
698 for (u4 i = 0; i < dir->methods_size_; i++) {
699 const u4 method_idx = methods[i].method_idx_;
700 const DexFile::MethodId& pMethodId = pDexFile->GetMethodId(method_idx);
701 const char* method_name = pDexFile->StringDataByIdx(pMethodId.name_idx_);
702 fprintf(gOutFile, "Annotations on method #%u '%s'\n", method_idx, method_name);
703 dumpAnnotationSetItem(pDexFile, pDexFile->GetMethodAnnotationSetItem(methods[i]));
704 }
705 }
706
707 // Annotations on method parameters.
708 if (pars != nullptr) {
709 for (u4 i = 0; i < dir->parameters_size_; i++) {
710 const u4 method_idx = pars[i].method_idx_;
711 const DexFile::MethodId& pMethodId = pDexFile->GetMethodId(method_idx);
712 const char* method_name = pDexFile->StringDataByIdx(pMethodId.name_idx_);
713 fprintf(gOutFile, "Annotations on method #%u '%s' parameters\n", method_idx, method_name);
714 const DexFile::AnnotationSetRefList*
715 list = pDexFile->GetParameterAnnotationSetRefList(&pars[i]);
716 if (list != nullptr) {
717 for (u4 j = 0; j < list->size_; j++) {
718 fprintf(gOutFile, "#%u\n", j);
719 dumpAnnotationSetItem(pDexFile, pDexFile->GetSetRefItemItem(&list->list_[j]));
720 }
721 }
722 }
723 }
724
725 fputc('\n', gOutFile);
726}
727
Aart Bik69ae54a2015-07-01 14:52:26 -0700728/*
729 * Dumps an interface that a class declares to implement.
730 */
731static void dumpInterface(const DexFile* pDexFile, const DexFile::TypeItem& pTypeItem, int i) {
732 const char* interfaceName = pDexFile->StringByTypeIdx(pTypeItem.type_idx_);
733 if (gOptions.outputFormat == OUTPUT_PLAIN) {
734 fprintf(gOutFile, " #%d : '%s'\n", i, interfaceName);
735 } else {
Aart Bikc05e2f22016-07-12 15:53:13 -0700736 std::unique_ptr<char[]> dot(descriptorToDot(interfaceName));
737 fprintf(gOutFile, "<implements name=\"%s\">\n</implements>\n", dot.get());
Aart Bik69ae54a2015-07-01 14:52:26 -0700738 }
739}
740
741/*
742 * Dumps the catches table associated with the code.
743 */
744static void dumpCatches(const DexFile* pDexFile, const DexFile::CodeItem* pCode) {
Mathieu Chartier698ebbc2018-01-05 11:00:42 -0800745 CodeItemDataAccessor accessor(*pDexFile, pCode);
Mathieu Chartierdc578c72017-12-27 11:51:45 -0800746 const u4 triesSize = accessor.TriesSize();
Aart Bik69ae54a2015-07-01 14:52:26 -0700747
748 // No catch table.
749 if (triesSize == 0) {
750 fprintf(gOutFile, " catches : (none)\n");
751 return;
752 }
753
754 // Dump all table entries.
755 fprintf(gOutFile, " catches : %d\n", triesSize);
Mathieu Chartierdc578c72017-12-27 11:51:45 -0800756 for (const DexFile::TryItem& try_item : accessor.TryItems()) {
757 const u4 start = try_item.start_addr_;
758 const u4 end = start + try_item.insn_count_;
Aart Bik69ae54a2015-07-01 14:52:26 -0700759 fprintf(gOutFile, " 0x%04x - 0x%04x\n", start, end);
Mathieu Chartierdc578c72017-12-27 11:51:45 -0800760 for (CatchHandlerIterator it(accessor, try_item); it.HasNext(); it.Next()) {
Andreas Gampea5b09a62016-11-17 15:21:22 -0800761 const dex::TypeIndex tidx = it.GetHandlerTypeIndex();
762 const char* descriptor = (!tidx.IsValid()) ? "<any>" : pDexFile->StringByTypeIdx(tidx);
Aart Bik69ae54a2015-07-01 14:52:26 -0700763 fprintf(gOutFile, " %s -> 0x%04x\n", descriptor, it.GetHandlerAddress());
764 } // for
765 } // for
766}
767
768/*
769 * Callback for dumping each positions table entry.
770 */
David Srbeckyb06e28e2015-12-10 13:15:00 +0000771static bool dumpPositionsCb(void* /*context*/, const DexFile::PositionInfo& entry) {
772 fprintf(gOutFile, " 0x%04x line=%d\n", entry.address_, entry.line_);
Aart Bik69ae54a2015-07-01 14:52:26 -0700773 return false;
774}
775
776/*
777 * Callback for dumping locals table entry.
778 */
David Srbeckyb06e28e2015-12-10 13:15:00 +0000779static void dumpLocalsCb(void* /*context*/, const DexFile::LocalInfo& entry) {
780 const char* signature = entry.signature_ != nullptr ? entry.signature_ : "";
Aart Bik69ae54a2015-07-01 14:52:26 -0700781 fprintf(gOutFile, " 0x%04x - 0x%04x reg=%d %s %s %s\n",
David Srbeckyb06e28e2015-12-10 13:15:00 +0000782 entry.start_address_, entry.end_address_, entry.reg_,
783 entry.name_, entry.descriptor_, signature);
Aart Bik69ae54a2015-07-01 14:52:26 -0700784}
785
786/*
787 * Helper for dumpInstruction(), which builds the string
Aart Bika0e33fd2016-07-08 18:32:45 -0700788 * representation for the index in the given instruction.
789 * Returns a pointer to a buffer of sufficient size.
Aart Bik69ae54a2015-07-01 14:52:26 -0700790 */
Aart Bika0e33fd2016-07-08 18:32:45 -0700791static std::unique_ptr<char[]> indexString(const DexFile* pDexFile,
792 const Instruction* pDecInsn,
793 size_t bufSize) {
Orion Hodsonb34bb192016-10-18 17:02:58 +0100794 static const u4 kInvalidIndex = std::numeric_limits<u4>::max();
Aart Bika0e33fd2016-07-08 18:32:45 -0700795 std::unique_ptr<char[]> buf(new char[bufSize]);
Aart Bik69ae54a2015-07-01 14:52:26 -0700796 // Determine index and width of the string.
797 u4 index = 0;
Orion Hodsonb34bb192016-10-18 17:02:58 +0100798 u4 secondary_index = kInvalidIndex;
Aart Bik69ae54a2015-07-01 14:52:26 -0700799 u4 width = 4;
800 switch (Instruction::FormatOf(pDecInsn->Opcode())) {
801 // SOME NOT SUPPORTED:
802 // case Instruction::k20bc:
803 case Instruction::k21c:
804 case Instruction::k35c:
805 // case Instruction::k35ms:
806 case Instruction::k3rc:
807 // case Instruction::k3rms:
808 // case Instruction::k35mi:
809 // case Instruction::k3rmi:
810 index = pDecInsn->VRegB();
811 width = 4;
812 break;
813 case Instruction::k31c:
814 index = pDecInsn->VRegB();
815 width = 8;
816 break;
817 case Instruction::k22c:
818 // case Instruction::k22cs:
819 index = pDecInsn->VRegC();
820 width = 4;
821 break;
Orion Hodsonb34bb192016-10-18 17:02:58 +0100822 case Instruction::k45cc:
823 case Instruction::k4rcc:
824 index = pDecInsn->VRegB();
825 secondary_index = pDecInsn->VRegH();
826 width = 4;
827 break;
Aart Bik69ae54a2015-07-01 14:52:26 -0700828 default:
829 break;
830 } // switch
831
832 // Determine index type.
833 size_t outSize = 0;
834 switch (Instruction::IndexTypeOf(pDecInsn->Opcode())) {
835 case Instruction::kIndexUnknown:
836 // This function should never get called for this type, but do
837 // something sensible here, just to help with debugging.
Aart Bika0e33fd2016-07-08 18:32:45 -0700838 outSize = snprintf(buf.get(), bufSize, "<unknown-index>");
Aart Bik69ae54a2015-07-01 14:52:26 -0700839 break;
840 case Instruction::kIndexNone:
841 // This function should never get called for this type, but do
842 // something sensible here, just to help with debugging.
Aart Bika0e33fd2016-07-08 18:32:45 -0700843 outSize = snprintf(buf.get(), bufSize, "<no-index>");
Aart Bik69ae54a2015-07-01 14:52:26 -0700844 break;
845 case Instruction::kIndexTypeRef:
846 if (index < pDexFile->GetHeader().type_ids_size_) {
Andreas Gampea5b09a62016-11-17 15:21:22 -0800847 const char* tp = pDexFile->StringByTypeIdx(dex::TypeIndex(index));
Aart Bika0e33fd2016-07-08 18:32:45 -0700848 outSize = snprintf(buf.get(), bufSize, "%s // type@%0*x", tp, width, index);
Aart Bik69ae54a2015-07-01 14:52:26 -0700849 } else {
Aart Bika0e33fd2016-07-08 18:32:45 -0700850 outSize = snprintf(buf.get(), bufSize, "<type?> // type@%0*x", width, index);
Aart Bik69ae54a2015-07-01 14:52:26 -0700851 }
852 break;
853 case Instruction::kIndexStringRef:
854 if (index < pDexFile->GetHeader().string_ids_size_) {
Andreas Gampe8a0128a2016-11-28 07:38:35 -0800855 const char* st = pDexFile->StringDataByIdx(dex::StringIndex(index));
Aart Bika0e33fd2016-07-08 18:32:45 -0700856 outSize = snprintf(buf.get(), bufSize, "\"%s\" // string@%0*x", st, width, index);
Aart Bik69ae54a2015-07-01 14:52:26 -0700857 } else {
Aart Bika0e33fd2016-07-08 18:32:45 -0700858 outSize = snprintf(buf.get(), bufSize, "<string?> // string@%0*x", width, index);
Aart Bik69ae54a2015-07-01 14:52:26 -0700859 }
860 break;
861 case Instruction::kIndexMethodRef:
862 if (index < pDexFile->GetHeader().method_ids_size_) {
863 const DexFile::MethodId& pMethodId = pDexFile->GetMethodId(index);
864 const char* name = pDexFile->StringDataByIdx(pMethodId.name_idx_);
865 const Signature signature = pDexFile->GetMethodSignature(pMethodId);
866 const char* backDescriptor = pDexFile->StringByTypeIdx(pMethodId.class_idx_);
Aart Bika0e33fd2016-07-08 18:32:45 -0700867 outSize = snprintf(buf.get(), bufSize, "%s.%s:%s // method@%0*x",
Aart Bik69ae54a2015-07-01 14:52:26 -0700868 backDescriptor, name, signature.ToString().c_str(), width, index);
869 } else {
Aart Bika0e33fd2016-07-08 18:32:45 -0700870 outSize = snprintf(buf.get(), bufSize, "<method?> // method@%0*x", width, index);
Aart Bik69ae54a2015-07-01 14:52:26 -0700871 }
872 break;
873 case Instruction::kIndexFieldRef:
874 if (index < pDexFile->GetHeader().field_ids_size_) {
875 const DexFile::FieldId& pFieldId = pDexFile->GetFieldId(index);
876 const char* name = pDexFile->StringDataByIdx(pFieldId.name_idx_);
877 const char* typeDescriptor = pDexFile->StringByTypeIdx(pFieldId.type_idx_);
878 const char* backDescriptor = pDexFile->StringByTypeIdx(pFieldId.class_idx_);
Aart Bika0e33fd2016-07-08 18:32:45 -0700879 outSize = snprintf(buf.get(), bufSize, "%s.%s:%s // field@%0*x",
Aart Bik69ae54a2015-07-01 14:52:26 -0700880 backDescriptor, name, typeDescriptor, width, index);
881 } else {
Aart Bika0e33fd2016-07-08 18:32:45 -0700882 outSize = snprintf(buf.get(), bufSize, "<field?> // field@%0*x", width, index);
Aart Bik69ae54a2015-07-01 14:52:26 -0700883 }
884 break;
885 case Instruction::kIndexVtableOffset:
Aart Bika0e33fd2016-07-08 18:32:45 -0700886 outSize = snprintf(buf.get(), bufSize, "[%0*x] // vtable #%0*x",
Aart Bik69ae54a2015-07-01 14:52:26 -0700887 width, index, width, index);
888 break;
889 case Instruction::kIndexFieldOffset:
Aart Bika0e33fd2016-07-08 18:32:45 -0700890 outSize = snprintf(buf.get(), bufSize, "[obj+%0*x]", width, index);
Aart Bik69ae54a2015-07-01 14:52:26 -0700891 break;
Orion Hodsonb34bb192016-10-18 17:02:58 +0100892 case Instruction::kIndexMethodAndProtoRef: {
Orion Hodsonc069a302017-01-18 09:23:12 +0000893 std::string method("<method?>");
894 std::string proto("<proto?>");
895 if (index < pDexFile->GetHeader().method_ids_size_) {
896 const DexFile::MethodId& pMethodId = pDexFile->GetMethodId(index);
897 const char* name = pDexFile->StringDataByIdx(pMethodId.name_idx_);
898 const Signature signature = pDexFile->GetMethodSignature(pMethodId);
899 const char* backDescriptor = pDexFile->StringByTypeIdx(pMethodId.class_idx_);
900 method = android::base::StringPrintf("%s.%s:%s",
901 backDescriptor,
902 name,
903 signature.ToString().c_str());
Orion Hodsonb34bb192016-10-18 17:02:58 +0100904 }
Orion Hodsonc069a302017-01-18 09:23:12 +0000905 if (secondary_index < pDexFile->GetHeader().proto_ids_size_) {
906 const DexFile::ProtoId& protoId = pDexFile->GetProtoId(secondary_index);
907 const Signature signature = pDexFile->GetProtoSignature(protoId);
908 proto = signature.ToString();
909 }
910 outSize = snprintf(buf.get(), bufSize, "%s, %s // method@%0*x, proto@%0*x",
911 method.c_str(), proto.c_str(), width, index, width, secondary_index);
912 break;
913 }
914 case Instruction::kIndexCallSiteRef:
915 // Call site information is too large to detail in disassembly so just output the index.
916 outSize = snprintf(buf.get(), bufSize, "call_site@%0*x", width, index);
Orion Hodsonb34bb192016-10-18 17:02:58 +0100917 break;
Orion Hodson2e599942017-09-22 16:17:41 +0100918 case Instruction::kIndexMethodHandleRef:
919 // Method handle information is too large to detail in disassembly so just output the index.
920 outSize = snprintf(buf.get(), bufSize, "method_handle@%0*x", width, index);
921 break;
922 case Instruction::kIndexProtoRef:
923 if (index < pDexFile->GetHeader().proto_ids_size_) {
924 const DexFile::ProtoId& protoId = pDexFile->GetProtoId(index);
925 const Signature signature = pDexFile->GetProtoSignature(protoId);
926 const std::string& proto = signature.ToString();
927 outSize = snprintf(buf.get(), bufSize, "%s // proto@%0*x", proto.c_str(), width, index);
928 } else {
929 outSize = snprintf(buf.get(), bufSize, "<?> // proto@%0*x", width, index);
930 }
Aart Bik69ae54a2015-07-01 14:52:26 -0700931 break;
932 } // switch
933
Orion Hodson2e599942017-09-22 16:17:41 +0100934 if (outSize == 0) {
935 // The index type has not been handled in the switch above.
936 outSize = snprintf(buf.get(), bufSize, "<?>");
937 }
938
Aart Bik69ae54a2015-07-01 14:52:26 -0700939 // Determine success of string construction.
940 if (outSize >= bufSize) {
Aart Bika0e33fd2016-07-08 18:32:45 -0700941 // The buffer wasn't big enough; retry with computed size. Note: snprintf()
942 // doesn't count/ the '\0' as part of its returned size, so we add explicit
943 // space for it here.
944 return indexString(pDexFile, pDecInsn, outSize + 1);
Aart Bik69ae54a2015-07-01 14:52:26 -0700945 }
946 return buf;
947}
948
949/*
950 * Dumps a single instruction.
951 */
952static void dumpInstruction(const DexFile* pDexFile,
953 const DexFile::CodeItem* pCode,
954 u4 codeOffset, u4 insnIdx, u4 insnWidth,
955 const Instruction* pDecInsn) {
956 // Address of instruction (expressed as byte offset).
957 fprintf(gOutFile, "%06x:", codeOffset + 0x10 + insnIdx * 2);
958
959 // Dump (part of) raw bytes.
Mathieu Chartier698ebbc2018-01-05 11:00:42 -0800960 CodeItemInstructionAccessor accessor(*pDexFile, pCode);
Aart Bik69ae54a2015-07-01 14:52:26 -0700961 for (u4 i = 0; i < 8; i++) {
962 if (i < insnWidth) {
963 if (i == 7) {
964 fprintf(gOutFile, " ... ");
965 } else {
966 // Print 16-bit value in little-endian order.
Mathieu Chartier641a3af2017-12-15 11:42:58 -0800967 const u1* bytePtr = (const u1*) &accessor.Insns()[insnIdx + i];
Aart Bik69ae54a2015-07-01 14:52:26 -0700968 fprintf(gOutFile, " %02x%02x", bytePtr[0], bytePtr[1]);
969 }
970 } else {
971 fputs(" ", gOutFile);
972 }
973 } // for
974
975 // Dump pseudo-instruction or opcode.
976 if (pDecInsn->Opcode() == Instruction::NOP) {
Mathieu Chartier641a3af2017-12-15 11:42:58 -0800977 const u2 instr = get2LE((const u1*) &accessor.Insns()[insnIdx]);
Aart Bik69ae54a2015-07-01 14:52:26 -0700978 if (instr == Instruction::kPackedSwitchSignature) {
979 fprintf(gOutFile, "|%04x: packed-switch-data (%d units)", insnIdx, insnWidth);
980 } else if (instr == Instruction::kSparseSwitchSignature) {
981 fprintf(gOutFile, "|%04x: sparse-switch-data (%d units)", insnIdx, insnWidth);
982 } else if (instr == Instruction::kArrayDataSignature) {
983 fprintf(gOutFile, "|%04x: array-data (%d units)", insnIdx, insnWidth);
984 } else {
985 fprintf(gOutFile, "|%04x: nop // spacer", insnIdx);
986 }
987 } else {
988 fprintf(gOutFile, "|%04x: %s", insnIdx, pDecInsn->Name());
989 }
990
991 // Set up additional argument.
Aart Bika0e33fd2016-07-08 18:32:45 -0700992 std::unique_ptr<char[]> indexBuf;
Aart Bik69ae54a2015-07-01 14:52:26 -0700993 if (Instruction::IndexTypeOf(pDecInsn->Opcode()) != Instruction::kIndexNone) {
Aart Bika0e33fd2016-07-08 18:32:45 -0700994 indexBuf = indexString(pDexFile, pDecInsn, 200);
Aart Bik69ae54a2015-07-01 14:52:26 -0700995 }
996
997 // Dump the instruction.
998 //
999 // NOTE: pDecInsn->DumpString(pDexFile) differs too much from original.
1000 //
1001 switch (Instruction::FormatOf(pDecInsn->Opcode())) {
1002 case Instruction::k10x: // op
1003 break;
1004 case Instruction::k12x: // op vA, vB
1005 fprintf(gOutFile, " v%d, v%d", pDecInsn->VRegA(), pDecInsn->VRegB());
1006 break;
1007 case Instruction::k11n: // op vA, #+B
1008 fprintf(gOutFile, " v%d, #int %d // #%x",
1009 pDecInsn->VRegA(), (s4) pDecInsn->VRegB(), (u1)pDecInsn->VRegB());
1010 break;
1011 case Instruction::k11x: // op vAA
1012 fprintf(gOutFile, " v%d", pDecInsn->VRegA());
1013 break;
1014 case Instruction::k10t: // op +AA
Aart Bikdce50862016-06-10 16:04:03 -07001015 case Instruction::k20t: { // op +AAAA
1016 const s4 targ = (s4) pDecInsn->VRegA();
1017 fprintf(gOutFile, " %04x // %c%04x",
1018 insnIdx + targ,
1019 (targ < 0) ? '-' : '+',
1020 (targ < 0) ? -targ : targ);
Aart Bik69ae54a2015-07-01 14:52:26 -07001021 break;
Aart Bikdce50862016-06-10 16:04:03 -07001022 }
Aart Bik69ae54a2015-07-01 14:52:26 -07001023 case Instruction::k22x: // op vAA, vBBBB
1024 fprintf(gOutFile, " v%d, v%d", pDecInsn->VRegA(), pDecInsn->VRegB());
1025 break;
Aart Bikdce50862016-06-10 16:04:03 -07001026 case Instruction::k21t: { // op vAA, +BBBB
1027 const s4 targ = (s4) pDecInsn->VRegB();
1028 fprintf(gOutFile, " v%d, %04x // %c%04x", pDecInsn->VRegA(),
1029 insnIdx + targ,
1030 (targ < 0) ? '-' : '+',
1031 (targ < 0) ? -targ : targ);
Aart Bik69ae54a2015-07-01 14:52:26 -07001032 break;
Aart Bikdce50862016-06-10 16:04:03 -07001033 }
Aart Bik69ae54a2015-07-01 14:52:26 -07001034 case Instruction::k21s: // op vAA, #+BBBB
1035 fprintf(gOutFile, " v%d, #int %d // #%x",
1036 pDecInsn->VRegA(), (s4) pDecInsn->VRegB(), (u2)pDecInsn->VRegB());
1037 break;
1038 case Instruction::k21h: // op vAA, #+BBBB0000[00000000]
1039 // The printed format varies a bit based on the actual opcode.
1040 if (pDecInsn->Opcode() == Instruction::CONST_HIGH16) {
1041 const s4 value = pDecInsn->VRegB() << 16;
1042 fprintf(gOutFile, " v%d, #int %d // #%x",
1043 pDecInsn->VRegA(), value, (u2) pDecInsn->VRegB());
1044 } else {
1045 const s8 value = ((s8) pDecInsn->VRegB()) << 48;
1046 fprintf(gOutFile, " v%d, #long %" PRId64 " // #%x",
1047 pDecInsn->VRegA(), value, (u2) pDecInsn->VRegB());
1048 }
1049 break;
1050 case Instruction::k21c: // op vAA, thing@BBBB
1051 case Instruction::k31c: // op vAA, thing@BBBBBBBB
Aart Bika0e33fd2016-07-08 18:32:45 -07001052 fprintf(gOutFile, " v%d, %s", pDecInsn->VRegA(), indexBuf.get());
Aart Bik69ae54a2015-07-01 14:52:26 -07001053 break;
1054 case Instruction::k23x: // op vAA, vBB, vCC
1055 fprintf(gOutFile, " v%d, v%d, v%d",
1056 pDecInsn->VRegA(), pDecInsn->VRegB(), pDecInsn->VRegC());
1057 break;
1058 case Instruction::k22b: // op vAA, vBB, #+CC
1059 fprintf(gOutFile, " v%d, v%d, #int %d // #%02x",
1060 pDecInsn->VRegA(), pDecInsn->VRegB(),
1061 (s4) pDecInsn->VRegC(), (u1) pDecInsn->VRegC());
1062 break;
Aart Bikdce50862016-06-10 16:04:03 -07001063 case Instruction::k22t: { // op vA, vB, +CCCC
1064 const s4 targ = (s4) pDecInsn->VRegC();
1065 fprintf(gOutFile, " v%d, v%d, %04x // %c%04x",
1066 pDecInsn->VRegA(), pDecInsn->VRegB(),
1067 insnIdx + targ,
1068 (targ < 0) ? '-' : '+',
1069 (targ < 0) ? -targ : targ);
Aart Bik69ae54a2015-07-01 14:52:26 -07001070 break;
Aart Bikdce50862016-06-10 16:04:03 -07001071 }
Aart Bik69ae54a2015-07-01 14:52:26 -07001072 case Instruction::k22s: // op vA, vB, #+CCCC
1073 fprintf(gOutFile, " v%d, v%d, #int %d // #%04x",
1074 pDecInsn->VRegA(), pDecInsn->VRegB(),
1075 (s4) pDecInsn->VRegC(), (u2) pDecInsn->VRegC());
1076 break;
1077 case Instruction::k22c: // op vA, vB, thing@CCCC
1078 // NOT SUPPORTED:
1079 // case Instruction::k22cs: // [opt] op vA, vB, field offset CCCC
1080 fprintf(gOutFile, " v%d, v%d, %s",
Aart Bika0e33fd2016-07-08 18:32:45 -07001081 pDecInsn->VRegA(), pDecInsn->VRegB(), indexBuf.get());
Aart Bik69ae54a2015-07-01 14:52:26 -07001082 break;
1083 case Instruction::k30t:
1084 fprintf(gOutFile, " #%08x", pDecInsn->VRegA());
1085 break;
Aart Bikdce50862016-06-10 16:04:03 -07001086 case Instruction::k31i: { // op vAA, #+BBBBBBBB
1087 // This is often, but not always, a float.
1088 union {
1089 float f;
1090 u4 i;
1091 } conv;
1092 conv.i = pDecInsn->VRegB();
1093 fprintf(gOutFile, " v%d, #float %g // #%08x",
1094 pDecInsn->VRegA(), conv.f, pDecInsn->VRegB());
Aart Bik69ae54a2015-07-01 14:52:26 -07001095 break;
Aart Bikdce50862016-06-10 16:04:03 -07001096 }
Aart Bik69ae54a2015-07-01 14:52:26 -07001097 case Instruction::k31t: // op vAA, offset +BBBBBBBB
1098 fprintf(gOutFile, " v%d, %08x // +%08x",
1099 pDecInsn->VRegA(), insnIdx + pDecInsn->VRegB(), pDecInsn->VRegB());
1100 break;
1101 case Instruction::k32x: // op vAAAA, vBBBB
1102 fprintf(gOutFile, " v%d, v%d", pDecInsn->VRegA(), pDecInsn->VRegB());
1103 break;
Orion Hodsonb34bb192016-10-18 17:02:58 +01001104 case Instruction::k35c: // op {vC, vD, vE, vF, vG}, thing@BBBB
1105 case Instruction::k45cc: { // op {vC, vD, vE, vF, vG}, method@BBBB, proto@HHHH
Aart Bik69ae54a2015-07-01 14:52:26 -07001106 // NOT SUPPORTED:
1107 // case Instruction::k35ms: // [opt] invoke-virtual+super
1108 // case Instruction::k35mi: // [opt] inline invoke
Aart Bikdce50862016-06-10 16:04:03 -07001109 u4 arg[Instruction::kMaxVarArgRegs];
1110 pDecInsn->GetVarArgs(arg);
1111 fputs(" {", gOutFile);
1112 for (int i = 0, n = pDecInsn->VRegA(); i < n; i++) {
1113 if (i == 0) {
1114 fprintf(gOutFile, "v%d", arg[i]);
1115 } else {
1116 fprintf(gOutFile, ", v%d", arg[i]);
1117 }
1118 } // for
Aart Bika0e33fd2016-07-08 18:32:45 -07001119 fprintf(gOutFile, "}, %s", indexBuf.get());
Aart Bik69ae54a2015-07-01 14:52:26 -07001120 break;
Aart Bikdce50862016-06-10 16:04:03 -07001121 }
Aart Bik69ae54a2015-07-01 14:52:26 -07001122 case Instruction::k3rc: // op {vCCCC .. v(CCCC+AA-1)}, thing@BBBB
Orion Hodsonb34bb192016-10-18 17:02:58 +01001123 case Instruction::k4rcc: { // op {vCCCC .. v(CCCC+AA-1)}, method@BBBB, proto@HHHH
Aart Bik69ae54a2015-07-01 14:52:26 -07001124 // NOT SUPPORTED:
1125 // case Instruction::k3rms: // [opt] invoke-virtual+super/range
1126 // case Instruction::k3rmi: // [opt] execute-inline/range
Aart Bik69ae54a2015-07-01 14:52:26 -07001127 // This doesn't match the "dx" output when some of the args are
1128 // 64-bit values -- dx only shows the first register.
1129 fputs(" {", gOutFile);
1130 for (int i = 0, n = pDecInsn->VRegA(); i < n; i++) {
1131 if (i == 0) {
1132 fprintf(gOutFile, "v%d", pDecInsn->VRegC() + i);
1133 } else {
1134 fprintf(gOutFile, ", v%d", pDecInsn->VRegC() + i);
1135 }
1136 } // for
Aart Bika0e33fd2016-07-08 18:32:45 -07001137 fprintf(gOutFile, "}, %s", indexBuf.get());
Aart Bik69ae54a2015-07-01 14:52:26 -07001138 }
1139 break;
Aart Bikdce50862016-06-10 16:04:03 -07001140 case Instruction::k51l: { // op vAA, #+BBBBBBBBBBBBBBBB
1141 // This is often, but not always, a double.
1142 union {
1143 double d;
1144 u8 j;
1145 } conv;
1146 conv.j = pDecInsn->WideVRegB();
1147 fprintf(gOutFile, " v%d, #double %g // #%016" PRIx64,
1148 pDecInsn->VRegA(), conv.d, pDecInsn->WideVRegB());
Aart Bik69ae54a2015-07-01 14:52:26 -07001149 break;
Aart Bikdce50862016-06-10 16:04:03 -07001150 }
Aart Bik69ae54a2015-07-01 14:52:26 -07001151 // NOT SUPPORTED:
1152 // case Instruction::k00x: // unknown op or breakpoint
1153 // break;
1154 default:
1155 fprintf(gOutFile, " ???");
1156 break;
1157 } // switch
1158
1159 fputc('\n', gOutFile);
Aart Bik69ae54a2015-07-01 14:52:26 -07001160}
1161
1162/*
1163 * Dumps a bytecode disassembly.
1164 */
1165static void dumpBytecodes(const DexFile* pDexFile, u4 idx,
1166 const DexFile::CodeItem* pCode, u4 codeOffset) {
1167 const DexFile::MethodId& pMethodId = pDexFile->GetMethodId(idx);
1168 const char* name = pDexFile->StringDataByIdx(pMethodId.name_idx_);
1169 const Signature signature = pDexFile->GetMethodSignature(pMethodId);
1170 const char* backDescriptor = pDexFile->StringByTypeIdx(pMethodId.class_idx_);
1171
1172 // Generate header.
Aart Bikc05e2f22016-07-12 15:53:13 -07001173 std::unique_ptr<char[]> dot(descriptorToDot(backDescriptor));
1174 fprintf(gOutFile, "%06x: |[%06x] %s.%s:%s\n",
1175 codeOffset, codeOffset, dot.get(), name, signature.ToString().c_str());
Aart Bik69ae54a2015-07-01 14:52:26 -07001176
1177 // Iterate over all instructions.
Mathieu Chartier698ebbc2018-01-05 11:00:42 -08001178 CodeItemDataAccessor accessor(*pDexFile, pCode);
Mathieu Chartier641a3af2017-12-15 11:42:58 -08001179 for (const DexInstructionPcPair& pair : accessor) {
1180 const Instruction* instruction = &pair.Inst();
Aart Bik69ae54a2015-07-01 14:52:26 -07001181 const u4 insnWidth = instruction->SizeInCodeUnits();
1182 if (insnWidth == 0) {
Andreas Gampe221d9812018-01-22 17:48:56 -08001183 LOG(WARNING) << "GLITCH: zero-width instruction at idx=0x" << std::hex << pair.DexPc();
Aart Bik69ae54a2015-07-01 14:52:26 -07001184 break;
1185 }
Mathieu Chartier641a3af2017-12-15 11:42:58 -08001186 dumpInstruction(pDexFile, pCode, codeOffset, pair.DexPc(), insnWidth, instruction);
Aart Bik69ae54a2015-07-01 14:52:26 -07001187 } // for
1188}
1189
1190/*
1191 * Dumps code of a method.
1192 */
1193static void dumpCode(const DexFile* pDexFile, u4 idx, u4 flags,
1194 const DexFile::CodeItem* pCode, u4 codeOffset) {
Mathieu Chartier8892c6b2018-01-09 15:10:17 -08001195 CodeItemDebugInfoAccessor accessor(*pDexFile, pCode, idx);
Mathieu Chartier641a3af2017-12-15 11:42:58 -08001196
1197 fprintf(gOutFile, " registers : %d\n", accessor.RegistersSize());
1198 fprintf(gOutFile, " ins : %d\n", accessor.InsSize());
1199 fprintf(gOutFile, " outs : %d\n", accessor.OutsSize());
Aart Bik69ae54a2015-07-01 14:52:26 -07001200 fprintf(gOutFile, " insns size : %d 16-bit code units\n",
Mathieu Chartier641a3af2017-12-15 11:42:58 -08001201 accessor.InsnsSizeInCodeUnits());
Aart Bik69ae54a2015-07-01 14:52:26 -07001202
1203 // Bytecode disassembly, if requested.
1204 if (gOptions.disassemble) {
1205 dumpBytecodes(pDexFile, idx, pCode, codeOffset);
1206 }
1207
1208 // Try-catch blocks.
1209 dumpCatches(pDexFile, pCode);
1210
1211 // Positions and locals table in the debug info.
1212 bool is_static = (flags & kAccStatic) != 0;
1213 fprintf(gOutFile, " positions : \n");
Mathieu Chartier641a3af2017-12-15 11:42:58 -08001214 pDexFile->DecodeDebugPositionInfo(accessor.DebugInfoOffset(), dumpPositionsCb, nullptr);
Aart Bik69ae54a2015-07-01 14:52:26 -07001215 fprintf(gOutFile, " locals : \n");
Mathieu Chartier641a3af2017-12-15 11:42:58 -08001216 accessor.DecodeDebugLocalInfo(is_static, idx, dumpLocalsCb, nullptr);
Aart Bik69ae54a2015-07-01 14:52:26 -07001217}
1218
1219/*
1220 * Dumps a method.
1221 */
1222static void dumpMethod(const DexFile* pDexFile, u4 idx, u4 flags,
1223 const DexFile::CodeItem* pCode, u4 codeOffset, int i) {
1224 // Bail for anything private if export only requested.
1225 if (gOptions.exportsOnly && (flags & (kAccPublic | kAccProtected)) == 0) {
1226 return;
1227 }
1228
1229 const DexFile::MethodId& pMethodId = pDexFile->GetMethodId(idx);
1230 const char* name = pDexFile->StringDataByIdx(pMethodId.name_idx_);
1231 const Signature signature = pDexFile->GetMethodSignature(pMethodId);
1232 char* typeDescriptor = strdup(signature.ToString().c_str());
1233 const char* backDescriptor = pDexFile->StringByTypeIdx(pMethodId.class_idx_);
1234 char* accessStr = createAccessFlagStr(flags, kAccessForMethod);
1235
1236 if (gOptions.outputFormat == OUTPUT_PLAIN) {
1237 fprintf(gOutFile, " #%d : (in %s)\n", i, backDescriptor);
1238 fprintf(gOutFile, " name : '%s'\n", name);
1239 fprintf(gOutFile, " type : '%s'\n", typeDescriptor);
1240 fprintf(gOutFile, " access : 0x%04x (%s)\n", flags, accessStr);
1241 if (pCode == nullptr) {
1242 fprintf(gOutFile, " code : (none)\n");
1243 } else {
1244 fprintf(gOutFile, " code -\n");
1245 dumpCode(pDexFile, idx, flags, pCode, codeOffset);
1246 }
1247 if (gOptions.disassemble) {
1248 fputc('\n', gOutFile);
1249 }
1250 } else if (gOptions.outputFormat == OUTPUT_XML) {
1251 const bool constructor = (name[0] == '<');
1252
1253 // Method name and prototype.
1254 if (constructor) {
Aart Bikc05e2f22016-07-12 15:53:13 -07001255 std::unique_ptr<char[]> dot(descriptorClassToDot(backDescriptor));
1256 fprintf(gOutFile, "<constructor name=\"%s\"\n", dot.get());
1257 dot = descriptorToDot(backDescriptor);
1258 fprintf(gOutFile, " type=\"%s\"\n", dot.get());
Aart Bik69ae54a2015-07-01 14:52:26 -07001259 } else {
1260 fprintf(gOutFile, "<method name=\"%s\"\n", name);
1261 const char* returnType = strrchr(typeDescriptor, ')');
1262 if (returnType == nullptr) {
Andreas Gampe221d9812018-01-22 17:48:56 -08001263 LOG(ERROR) << "bad method type descriptor '" << typeDescriptor << "'";
Aart Bik69ae54a2015-07-01 14:52:26 -07001264 goto bail;
1265 }
Aart Bikc05e2f22016-07-12 15:53:13 -07001266 std::unique_ptr<char[]> dot(descriptorToDot(returnType + 1));
1267 fprintf(gOutFile, " return=\"%s\"\n", dot.get());
Aart Bik69ae54a2015-07-01 14:52:26 -07001268 fprintf(gOutFile, " abstract=%s\n", quotedBool((flags & kAccAbstract) != 0));
1269 fprintf(gOutFile, " native=%s\n", quotedBool((flags & kAccNative) != 0));
1270 fprintf(gOutFile, " synchronized=%s\n", quotedBool(
1271 (flags & (kAccSynchronized | kAccDeclaredSynchronized)) != 0));
1272 }
1273
1274 // Additional method flags.
1275 fprintf(gOutFile, " static=%s\n", quotedBool((flags & kAccStatic) != 0));
1276 fprintf(gOutFile, " final=%s\n", quotedBool((flags & kAccFinal) != 0));
1277 // The "deprecated=" not knowable w/o parsing annotations.
1278 fprintf(gOutFile, " visibility=%s\n>\n", quotedVisibility(flags));
1279
1280 // Parameters.
1281 if (typeDescriptor[0] != '(') {
Andreas Gampe221d9812018-01-22 17:48:56 -08001282 LOG(ERROR) << "ERROR: bad descriptor '" << typeDescriptor << "'";
Aart Bik69ae54a2015-07-01 14:52:26 -07001283 goto bail;
1284 }
1285 char* tmpBuf = reinterpret_cast<char*>(malloc(strlen(typeDescriptor) + 1));
1286 const char* base = typeDescriptor + 1;
1287 int argNum = 0;
1288 while (*base != ')') {
1289 char* cp = tmpBuf;
1290 while (*base == '[') {
1291 *cp++ = *base++;
1292 }
1293 if (*base == 'L') {
1294 // Copy through ';'.
1295 do {
1296 *cp = *base++;
1297 } while (*cp++ != ';');
1298 } else {
1299 // Primitive char, copy it.
Aart Bikc05e2f22016-07-12 15:53:13 -07001300 if (strchr("ZBCSIFJD", *base) == nullptr) {
Andreas Gampe221d9812018-01-22 17:48:56 -08001301 LOG(ERROR) << "ERROR: bad method signature '" << base << "'";
Aart Bika0e33fd2016-07-08 18:32:45 -07001302 break; // while
Aart Bik69ae54a2015-07-01 14:52:26 -07001303 }
1304 *cp++ = *base++;
1305 }
1306 // Null terminate and display.
1307 *cp++ = '\0';
Aart Bikc05e2f22016-07-12 15:53:13 -07001308 std::unique_ptr<char[]> dot(descriptorToDot(tmpBuf));
Aart Bik69ae54a2015-07-01 14:52:26 -07001309 fprintf(gOutFile, "<parameter name=\"arg%d\" type=\"%s\">\n"
Aart Bikc05e2f22016-07-12 15:53:13 -07001310 "</parameter>\n", argNum++, dot.get());
Aart Bik69ae54a2015-07-01 14:52:26 -07001311 } // while
1312 free(tmpBuf);
1313 if (constructor) {
1314 fprintf(gOutFile, "</constructor>\n");
1315 } else {
1316 fprintf(gOutFile, "</method>\n");
1317 }
1318 }
1319
1320 bail:
1321 free(typeDescriptor);
1322 free(accessStr);
1323}
1324
1325/*
1326 * Dumps a static (class) field.
1327 */
Aart Bikdce50862016-06-10 16:04:03 -07001328static void dumpSField(const DexFile* pDexFile, u4 idx, u4 flags, int i, const u1** data) {
Aart Bik69ae54a2015-07-01 14:52:26 -07001329 // Bail for anything private if export only requested.
1330 if (gOptions.exportsOnly && (flags & (kAccPublic | kAccProtected)) == 0) {
1331 return;
1332 }
1333
1334 const DexFile::FieldId& pFieldId = pDexFile->GetFieldId(idx);
1335 const char* name = pDexFile->StringDataByIdx(pFieldId.name_idx_);
1336 const char* typeDescriptor = pDexFile->StringByTypeIdx(pFieldId.type_idx_);
1337 const char* backDescriptor = pDexFile->StringByTypeIdx(pFieldId.class_idx_);
1338 char* accessStr = createAccessFlagStr(flags, kAccessForField);
1339
1340 if (gOptions.outputFormat == OUTPUT_PLAIN) {
1341 fprintf(gOutFile, " #%d : (in %s)\n", i, backDescriptor);
1342 fprintf(gOutFile, " name : '%s'\n", name);
1343 fprintf(gOutFile, " type : '%s'\n", typeDescriptor);
1344 fprintf(gOutFile, " access : 0x%04x (%s)\n", flags, accessStr);
Aart Bikdce50862016-06-10 16:04:03 -07001345 if (data != nullptr) {
Shinichiro Hamaji82863f02015-11-05 16:51:33 +09001346 fputs(" value : ", gOutFile);
Aart Bikdce50862016-06-10 16:04:03 -07001347 dumpEncodedValue(pDexFile, data);
Shinichiro Hamaji82863f02015-11-05 16:51:33 +09001348 fputs("\n", gOutFile);
1349 }
Aart Bik69ae54a2015-07-01 14:52:26 -07001350 } else if (gOptions.outputFormat == OUTPUT_XML) {
1351 fprintf(gOutFile, "<field name=\"%s\"\n", name);
Aart Bikc05e2f22016-07-12 15:53:13 -07001352 std::unique_ptr<char[]> dot(descriptorToDot(typeDescriptor));
1353 fprintf(gOutFile, " type=\"%s\"\n", dot.get());
Aart Bik69ae54a2015-07-01 14:52:26 -07001354 fprintf(gOutFile, " transient=%s\n", quotedBool((flags & kAccTransient) != 0));
1355 fprintf(gOutFile, " volatile=%s\n", quotedBool((flags & kAccVolatile) != 0));
1356 // The "value=" is not knowable w/o parsing annotations.
1357 fprintf(gOutFile, " static=%s\n", quotedBool((flags & kAccStatic) != 0));
1358 fprintf(gOutFile, " final=%s\n", quotedBool((flags & kAccFinal) != 0));
1359 // The "deprecated=" is not knowable w/o parsing annotations.
1360 fprintf(gOutFile, " visibility=%s\n", quotedVisibility(flags));
Aart Bikdce50862016-06-10 16:04:03 -07001361 if (data != nullptr) {
Shinichiro Hamaji82863f02015-11-05 16:51:33 +09001362 fputs(" value=\"", gOutFile);
Aart Bikdce50862016-06-10 16:04:03 -07001363 dumpEncodedValue(pDexFile, data);
Shinichiro Hamaji82863f02015-11-05 16:51:33 +09001364 fputs("\"\n", gOutFile);
1365 }
1366 fputs(">\n</field>\n", gOutFile);
Aart Bik69ae54a2015-07-01 14:52:26 -07001367 }
1368
1369 free(accessStr);
1370}
1371
1372/*
1373 * Dumps an instance field.
1374 */
1375static void dumpIField(const DexFile* pDexFile, u4 idx, u4 flags, int i) {
Aart Bikdce50862016-06-10 16:04:03 -07001376 dumpSField(pDexFile, idx, flags, i, nullptr);
Aart Bik69ae54a2015-07-01 14:52:26 -07001377}
1378
1379/*
Andreas Gampe5073fed2015-08-10 11:40:25 -07001380 * Dumping a CFG. Note that this will do duplicate work. utils.h doesn't expose the code-item
1381 * version, so the DumpMethodCFG code will have to iterate again to find it. But dexdump is a
1382 * tool, so this is not performance-critical.
1383 */
1384
1385static void dumpCfg(const DexFile* dex_file,
Aart Bikdce50862016-06-10 16:04:03 -07001386 u4 dex_method_idx,
Andreas Gampe5073fed2015-08-10 11:40:25 -07001387 const DexFile::CodeItem* code_item) {
1388 if (code_item != nullptr) {
1389 std::ostringstream oss;
1390 DumpMethodCFG(dex_file, dex_method_idx, oss);
David Sehrcaacd112016-10-20 16:27:02 -07001391 fputs(oss.str().c_str(), gOutFile);
Andreas Gampe5073fed2015-08-10 11:40:25 -07001392 }
1393}
1394
1395static void dumpCfg(const DexFile* dex_file, int idx) {
1396 const DexFile::ClassDef& class_def = dex_file->GetClassDef(idx);
Aart Bikdce50862016-06-10 16:04:03 -07001397 const u1* class_data = dex_file->GetClassData(class_def);
Andreas Gampe5073fed2015-08-10 11:40:25 -07001398 if (class_data == nullptr) { // empty class such as a marker interface?
1399 return;
1400 }
1401 ClassDataItemIterator it(*dex_file, class_data);
Mathieu Chartiere17cf242017-06-19 11:05:51 -07001402 it.SkipAllFields();
Mathieu Chartierb7c273c2017-11-10 18:07:56 -08001403 while (it.HasNextMethod()) {
Andreas Gampe5073fed2015-08-10 11:40:25 -07001404 dumpCfg(dex_file,
1405 it.GetMemberIndex(),
1406 it.GetMethodCodeItem());
1407 it.Next();
1408 }
Andreas Gampe5073fed2015-08-10 11:40:25 -07001409}
1410
1411/*
Aart Bik69ae54a2015-07-01 14:52:26 -07001412 * Dumps the class.
1413 *
1414 * Note "idx" is a DexClassDef index, not a DexTypeId index.
1415 *
1416 * If "*pLastPackage" is nullptr or does not match the current class' package,
1417 * the value will be replaced with a newly-allocated string.
1418 */
1419static void dumpClass(const DexFile* pDexFile, int idx, char** pLastPackage) {
1420 const DexFile::ClassDef& pClassDef = pDexFile->GetClassDef(idx);
1421
1422 // Omitting non-public class.
1423 if (gOptions.exportsOnly && (pClassDef.access_flags_ & kAccPublic) == 0) {
1424 return;
1425 }
1426
Aart Bikdce50862016-06-10 16:04:03 -07001427 if (gOptions.showSectionHeaders) {
1428 dumpClassDef(pDexFile, idx);
1429 }
1430
1431 if (gOptions.showAnnotations) {
1432 dumpClassAnnotations(pDexFile, idx);
1433 }
1434
1435 if (gOptions.showCfg) {
Andreas Gampe5073fed2015-08-10 11:40:25 -07001436 dumpCfg(pDexFile, idx);
1437 return;
1438 }
1439
Aart Bik69ae54a2015-07-01 14:52:26 -07001440 // For the XML output, show the package name. Ideally we'd gather
1441 // up the classes, sort them, and dump them alphabetically so the
1442 // package name wouldn't jump around, but that's not a great plan
1443 // for something that needs to run on the device.
1444 const char* classDescriptor = pDexFile->StringByTypeIdx(pClassDef.class_idx_);
1445 if (!(classDescriptor[0] == 'L' &&
1446 classDescriptor[strlen(classDescriptor)-1] == ';')) {
1447 // Arrays and primitives should not be defined explicitly. Keep going?
Andreas Gampe221d9812018-01-22 17:48:56 -08001448 LOG(WARNING) << "Malformed class name '" << classDescriptor << "'";
Aart Bik69ae54a2015-07-01 14:52:26 -07001449 } else if (gOptions.outputFormat == OUTPUT_XML) {
1450 char* mangle = strdup(classDescriptor + 1);
1451 mangle[strlen(mangle)-1] = '\0';
1452
1453 // Reduce to just the package name.
1454 char* lastSlash = strrchr(mangle, '/');
1455 if (lastSlash != nullptr) {
1456 *lastSlash = '\0';
1457 } else {
1458 *mangle = '\0';
1459 }
1460
1461 for (char* cp = mangle; *cp != '\0'; cp++) {
1462 if (*cp == '/') {
1463 *cp = '.';
1464 }
1465 } // for
1466
1467 if (*pLastPackage == nullptr || strcmp(mangle, *pLastPackage) != 0) {
1468 // Start of a new package.
1469 if (*pLastPackage != nullptr) {
1470 fprintf(gOutFile, "</package>\n");
1471 }
1472 fprintf(gOutFile, "<package name=\"%s\"\n>\n", mangle);
1473 free(*pLastPackage);
1474 *pLastPackage = mangle;
1475 } else {
1476 free(mangle);
1477 }
1478 }
1479
1480 // General class information.
1481 char* accessStr = createAccessFlagStr(pClassDef.access_flags_, kAccessForClass);
1482 const char* superclassDescriptor;
Andreas Gampea5b09a62016-11-17 15:21:22 -08001483 if (!pClassDef.superclass_idx_.IsValid()) {
Aart Bik69ae54a2015-07-01 14:52:26 -07001484 superclassDescriptor = nullptr;
1485 } else {
1486 superclassDescriptor = pDexFile->StringByTypeIdx(pClassDef.superclass_idx_);
1487 }
1488 if (gOptions.outputFormat == OUTPUT_PLAIN) {
1489 fprintf(gOutFile, "Class #%d -\n", idx);
1490 fprintf(gOutFile, " Class descriptor : '%s'\n", classDescriptor);
1491 fprintf(gOutFile, " Access flags : 0x%04x (%s)\n", pClassDef.access_flags_, accessStr);
1492 if (superclassDescriptor != nullptr) {
1493 fprintf(gOutFile, " Superclass : '%s'\n", superclassDescriptor);
1494 }
1495 fprintf(gOutFile, " Interfaces -\n");
1496 } else {
Aart Bikc05e2f22016-07-12 15:53:13 -07001497 std::unique_ptr<char[]> dot(descriptorClassToDot(classDescriptor));
1498 fprintf(gOutFile, "<class name=\"%s\"\n", dot.get());
Aart Bik69ae54a2015-07-01 14:52:26 -07001499 if (superclassDescriptor != nullptr) {
Aart Bikc05e2f22016-07-12 15:53:13 -07001500 dot = descriptorToDot(superclassDescriptor);
1501 fprintf(gOutFile, " extends=\"%s\"\n", dot.get());
Aart Bik69ae54a2015-07-01 14:52:26 -07001502 }
Alex Light1f12e282015-12-10 16:49:47 -08001503 fprintf(gOutFile, " interface=%s\n",
1504 quotedBool((pClassDef.access_flags_ & kAccInterface) != 0));
Aart Bik69ae54a2015-07-01 14:52:26 -07001505 fprintf(gOutFile, " abstract=%s\n", quotedBool((pClassDef.access_flags_ & kAccAbstract) != 0));
1506 fprintf(gOutFile, " static=%s\n", quotedBool((pClassDef.access_flags_ & kAccStatic) != 0));
1507 fprintf(gOutFile, " final=%s\n", quotedBool((pClassDef.access_flags_ & kAccFinal) != 0));
1508 // The "deprecated=" not knowable w/o parsing annotations.
1509 fprintf(gOutFile, " visibility=%s\n", quotedVisibility(pClassDef.access_flags_));
1510 fprintf(gOutFile, ">\n");
1511 }
1512
1513 // Interfaces.
1514 const DexFile::TypeList* pInterfaces = pDexFile->GetInterfacesList(pClassDef);
1515 if (pInterfaces != nullptr) {
1516 for (u4 i = 0; i < pInterfaces->Size(); i++) {
1517 dumpInterface(pDexFile, pInterfaces->GetTypeItem(i), i);
1518 } // for
1519 }
1520
1521 // Fields and methods.
1522 const u1* pEncodedData = pDexFile->GetClassData(pClassDef);
1523 if (pEncodedData == nullptr) {
1524 if (gOptions.outputFormat == OUTPUT_PLAIN) {
1525 fprintf(gOutFile, " Static fields -\n");
1526 fprintf(gOutFile, " Instance fields -\n");
1527 fprintf(gOutFile, " Direct methods -\n");
1528 fprintf(gOutFile, " Virtual methods -\n");
1529 }
1530 } else {
1531 ClassDataItemIterator pClassData(*pDexFile, pEncodedData);
Aart Bikdce50862016-06-10 16:04:03 -07001532
1533 // Prepare data for static fields.
1534 const u1* sData = pDexFile->GetEncodedStaticFieldValuesArray(pClassDef);
1535 const u4 sSize = sData != nullptr ? DecodeUnsignedLeb128(&sData) : 0;
1536
1537 // Static fields.
Aart Bik69ae54a2015-07-01 14:52:26 -07001538 if (gOptions.outputFormat == OUTPUT_PLAIN) {
1539 fprintf(gOutFile, " Static fields -\n");
1540 }
Aart Bikdce50862016-06-10 16:04:03 -07001541 for (u4 i = 0; pClassData.HasNextStaticField(); i++, pClassData.Next()) {
1542 dumpSField(pDexFile,
1543 pClassData.GetMemberIndex(),
1544 pClassData.GetRawMemberAccessFlags(),
1545 i,
1546 i < sSize ? &sData : nullptr);
Aart Bik69ae54a2015-07-01 14:52:26 -07001547 } // for
Aart Bikdce50862016-06-10 16:04:03 -07001548
1549 // Instance fields.
Aart Bik69ae54a2015-07-01 14:52:26 -07001550 if (gOptions.outputFormat == OUTPUT_PLAIN) {
1551 fprintf(gOutFile, " Instance fields -\n");
1552 }
Aart Bikdce50862016-06-10 16:04:03 -07001553 for (u4 i = 0; pClassData.HasNextInstanceField(); i++, pClassData.Next()) {
1554 dumpIField(pDexFile,
1555 pClassData.GetMemberIndex(),
1556 pClassData.GetRawMemberAccessFlags(),
1557 i);
Aart Bik69ae54a2015-07-01 14:52:26 -07001558 } // for
Aart Bikdce50862016-06-10 16:04:03 -07001559
1560 // Direct methods.
Aart Bik69ae54a2015-07-01 14:52:26 -07001561 if (gOptions.outputFormat == OUTPUT_PLAIN) {
1562 fprintf(gOutFile, " Direct methods -\n");
1563 }
1564 for (int i = 0; pClassData.HasNextDirectMethod(); i++, pClassData.Next()) {
1565 dumpMethod(pDexFile, pClassData.GetMemberIndex(),
1566 pClassData.GetRawMemberAccessFlags(),
1567 pClassData.GetMethodCodeItem(),
1568 pClassData.GetMethodCodeItemOffset(), i);
1569 } // for
Aart Bikdce50862016-06-10 16:04:03 -07001570
1571 // Virtual methods.
Aart Bik69ae54a2015-07-01 14:52:26 -07001572 if (gOptions.outputFormat == OUTPUT_PLAIN) {
1573 fprintf(gOutFile, " Virtual methods -\n");
1574 }
1575 for (int i = 0; pClassData.HasNextVirtualMethod(); i++, pClassData.Next()) {
1576 dumpMethod(pDexFile, pClassData.GetMemberIndex(),
1577 pClassData.GetRawMemberAccessFlags(),
1578 pClassData.GetMethodCodeItem(),
1579 pClassData.GetMethodCodeItemOffset(), i);
1580 } // for
1581 }
1582
1583 // End of class.
1584 if (gOptions.outputFormat == OUTPUT_PLAIN) {
1585 const char* fileName;
Andreas Gampe8a0128a2016-11-28 07:38:35 -08001586 if (pClassDef.source_file_idx_.IsValid()) {
Aart Bik69ae54a2015-07-01 14:52:26 -07001587 fileName = pDexFile->StringDataByIdx(pClassDef.source_file_idx_);
1588 } else {
1589 fileName = "unknown";
1590 }
1591 fprintf(gOutFile, " source_file_idx : %d (%s)\n\n",
Andreas Gampe8a0128a2016-11-28 07:38:35 -08001592 pClassDef.source_file_idx_.index_, fileName);
Aart Bik69ae54a2015-07-01 14:52:26 -07001593 } else if (gOptions.outputFormat == OUTPUT_XML) {
1594 fprintf(gOutFile, "</class>\n");
1595 }
1596
1597 free(accessStr);
1598}
1599
Orion Hodsonc069a302017-01-18 09:23:12 +00001600static void dumpMethodHandle(const DexFile* pDexFile, u4 idx) {
1601 const DexFile::MethodHandleItem& mh = pDexFile->GetMethodHandle(idx);
Orion Hodson631827d2017-04-10 14:53:47 +01001602 const char* type = nullptr;
1603 bool is_instance = false;
Orion Hodsonc069a302017-01-18 09:23:12 +00001604 bool is_invoke = false;
Orion Hodsonc069a302017-01-18 09:23:12 +00001605 switch (static_cast<DexFile::MethodHandleType>(mh.method_handle_type_)) {
1606 case DexFile::MethodHandleType::kStaticPut:
1607 type = "put-static";
Orion Hodson631827d2017-04-10 14:53:47 +01001608 is_instance = false;
1609 is_invoke = false;
Orion Hodsonc069a302017-01-18 09:23:12 +00001610 break;
1611 case DexFile::MethodHandleType::kStaticGet:
1612 type = "get-static";
Orion Hodson631827d2017-04-10 14:53:47 +01001613 is_instance = false;
1614 is_invoke = false;
Orion Hodsonc069a302017-01-18 09:23:12 +00001615 break;
1616 case DexFile::MethodHandleType::kInstancePut:
1617 type = "put-instance";
Orion Hodson631827d2017-04-10 14:53:47 +01001618 is_instance = true;
1619 is_invoke = false;
Orion Hodsonc069a302017-01-18 09:23:12 +00001620 break;
1621 case DexFile::MethodHandleType::kInstanceGet:
1622 type = "get-instance";
Orion Hodson631827d2017-04-10 14:53:47 +01001623 is_instance = true;
1624 is_invoke = false;
Orion Hodsonc069a302017-01-18 09:23:12 +00001625 break;
1626 case DexFile::MethodHandleType::kInvokeStatic:
1627 type = "invoke-static";
Orion Hodson631827d2017-04-10 14:53:47 +01001628 is_instance = false;
Orion Hodsonc069a302017-01-18 09:23:12 +00001629 is_invoke = true;
1630 break;
1631 case DexFile::MethodHandleType::kInvokeInstance:
1632 type = "invoke-instance";
Orion Hodson631827d2017-04-10 14:53:47 +01001633 is_instance = true;
Orion Hodsonc069a302017-01-18 09:23:12 +00001634 is_invoke = true;
1635 break;
1636 case DexFile::MethodHandleType::kInvokeConstructor:
1637 type = "invoke-constructor";
Orion Hodson631827d2017-04-10 14:53:47 +01001638 is_instance = true;
1639 is_invoke = true;
1640 break;
1641 case DexFile::MethodHandleType::kInvokeDirect:
1642 type = "invoke-direct";
1643 is_instance = true;
1644 is_invoke = true;
1645 break;
1646 case DexFile::MethodHandleType::kInvokeInterface:
1647 type = "invoke-interface";
1648 is_instance = true;
Orion Hodsonc069a302017-01-18 09:23:12 +00001649 is_invoke = true;
1650 break;
1651 }
1652
1653 const char* declaring_class;
1654 const char* member;
1655 std::string member_type;
Orion Hodson631827d2017-04-10 14:53:47 +01001656 if (type != nullptr) {
1657 if (is_invoke) {
1658 const DexFile::MethodId& method_id = pDexFile->GetMethodId(mh.field_or_method_idx_);
1659 declaring_class = pDexFile->GetMethodDeclaringClassDescriptor(method_id);
1660 member = pDexFile->GetMethodName(method_id);
1661 member_type = pDexFile->GetMethodSignature(method_id).ToString();
1662 } else {
1663 const DexFile::FieldId& field_id = pDexFile->GetFieldId(mh.field_or_method_idx_);
1664 declaring_class = pDexFile->GetFieldDeclaringClassDescriptor(field_id);
1665 member = pDexFile->GetFieldName(field_id);
1666 member_type = pDexFile->GetFieldTypeDescriptor(field_id);
1667 }
1668 if (is_instance) {
1669 member_type = android::base::StringPrintf("(%s%s", declaring_class, member_type.c_str() + 1);
1670 }
Orion Hodsonc069a302017-01-18 09:23:12 +00001671 } else {
Orion Hodson631827d2017-04-10 14:53:47 +01001672 type = "?";
1673 declaring_class = "?";
1674 member = "?";
1675 member_type = "?";
Orion Hodsonc069a302017-01-18 09:23:12 +00001676 }
1677
1678 if (gOptions.outputFormat == OUTPUT_PLAIN) {
1679 fprintf(gOutFile, "Method handle #%u:\n", idx);
1680 fprintf(gOutFile, " type : %s\n", type);
1681 fprintf(gOutFile, " target : %s %s\n", declaring_class, member);
1682 fprintf(gOutFile, " target_type : %s\n", member_type.c_str());
1683 } else {
1684 fprintf(gOutFile, "<method_handle index=\"%u\"\n", idx);
1685 fprintf(gOutFile, " type=\"%s\"\n", type);
1686 fprintf(gOutFile, " target_class=\"%s\"\n", declaring_class);
1687 fprintf(gOutFile, " target_member=\"%s\"\n", member);
1688 fprintf(gOutFile, " target_member_type=");
1689 dumpEscapedString(member_type.c_str());
1690 fprintf(gOutFile, "\n>\n</method_handle>\n");
1691 }
1692}
1693
1694static void dumpCallSite(const DexFile* pDexFile, u4 idx) {
1695 const DexFile::CallSiteIdItem& call_site_id = pDexFile->GetCallSiteId(idx);
1696 CallSiteArrayValueIterator it(*pDexFile, call_site_id);
1697 if (it.Size() < 3) {
Andreas Gampe221d9812018-01-22 17:48:56 -08001698 LOG(ERROR) << "ERROR: Call site " << idx << " has too few values.";
Orion Hodsonc069a302017-01-18 09:23:12 +00001699 return;
1700 }
1701
1702 uint32_t method_handle_idx = static_cast<uint32_t>(it.GetJavaValue().i);
1703 it.Next();
1704 dex::StringIndex method_name_idx = static_cast<dex::StringIndex>(it.GetJavaValue().i);
1705 const char* method_name = pDexFile->StringDataByIdx(method_name_idx);
1706 it.Next();
1707 uint32_t method_type_idx = static_cast<uint32_t>(it.GetJavaValue().i);
1708 const DexFile::ProtoId& method_type_id = pDexFile->GetProtoId(method_type_idx);
1709 std::string method_type = pDexFile->GetProtoSignature(method_type_id).ToString();
1710 it.Next();
1711
1712 if (gOptions.outputFormat == OUTPUT_PLAIN) {
Orion Hodson775224d2017-07-05 11:04:01 +01001713 fprintf(gOutFile, "Call site #%u: // offset %u\n", idx, call_site_id.data_off_);
Orion Hodsonc069a302017-01-18 09:23:12 +00001714 fprintf(gOutFile, " link_argument[0] : %u (MethodHandle)\n", method_handle_idx);
1715 fprintf(gOutFile, " link_argument[1] : %s (String)\n", method_name);
1716 fprintf(gOutFile, " link_argument[2] : %s (MethodType)\n", method_type.c_str());
1717 } else {
Orion Hodson775224d2017-07-05 11:04:01 +01001718 fprintf(gOutFile, "<call_site index=\"%u\" offset=\"%u\">\n", idx, call_site_id.data_off_);
Orion Hodsonc069a302017-01-18 09:23:12 +00001719 fprintf(gOutFile,
1720 "<link_argument index=\"0\" type=\"MethodHandle\" value=\"%u\"/>\n",
1721 method_handle_idx);
1722 fprintf(gOutFile,
1723 "<link_argument index=\"1\" type=\"String\" values=\"%s\"/>\n",
1724 method_name);
1725 fprintf(gOutFile,
1726 "<link_argument index=\"2\" type=\"MethodType\" value=\"%s\"/>\n",
1727 method_type.c_str());
1728 }
1729
1730 size_t argument = 3;
1731 while (it.HasNext()) {
1732 const char* type;
1733 std::string value;
1734 switch (it.GetValueType()) {
1735 case EncodedArrayValueIterator::ValueType::kByte:
1736 type = "byte";
1737 value = android::base::StringPrintf("%u", it.GetJavaValue().b);
1738 break;
1739 case EncodedArrayValueIterator::ValueType::kShort:
1740 type = "short";
1741 value = android::base::StringPrintf("%d", it.GetJavaValue().s);
1742 break;
1743 case EncodedArrayValueIterator::ValueType::kChar:
1744 type = "char";
1745 value = android::base::StringPrintf("%u", it.GetJavaValue().c);
1746 break;
1747 case EncodedArrayValueIterator::ValueType::kInt:
1748 type = "int";
1749 value = android::base::StringPrintf("%d", it.GetJavaValue().i);
1750 break;
1751 case EncodedArrayValueIterator::ValueType::kLong:
1752 type = "long";
1753 value = android::base::StringPrintf("%" PRId64, it.GetJavaValue().j);
1754 break;
1755 case EncodedArrayValueIterator::ValueType::kFloat:
1756 type = "float";
1757 value = android::base::StringPrintf("%g", it.GetJavaValue().f);
1758 break;
1759 case EncodedArrayValueIterator::ValueType::kDouble:
1760 type = "double";
1761 value = android::base::StringPrintf("%g", it.GetJavaValue().d);
1762 break;
1763 case EncodedArrayValueIterator::ValueType::kMethodType: {
1764 type = "MethodType";
1765 uint32_t proto_idx = static_cast<uint32_t>(it.GetJavaValue().i);
1766 const DexFile::ProtoId& proto_id = pDexFile->GetProtoId(proto_idx);
1767 value = pDexFile->GetProtoSignature(proto_id).ToString();
1768 break;
1769 }
1770 case EncodedArrayValueIterator::ValueType::kMethodHandle:
1771 type = "MethodHandle";
1772 value = android::base::StringPrintf("%d", it.GetJavaValue().i);
1773 break;
1774 case EncodedArrayValueIterator::ValueType::kString: {
1775 type = "String";
1776 dex::StringIndex string_idx = static_cast<dex::StringIndex>(it.GetJavaValue().i);
1777 value = pDexFile->StringDataByIdx(string_idx);
1778 break;
1779 }
1780 case EncodedArrayValueIterator::ValueType::kType: {
1781 type = "Class";
1782 dex::TypeIndex type_idx = static_cast<dex::TypeIndex>(it.GetJavaValue().i);
1783 const DexFile::ClassDef* class_def = pDexFile->FindClassDef(type_idx);
1784 value = pDexFile->GetClassDescriptor(*class_def);
1785 value = descriptorClassToDot(value.c_str()).get();
1786 break;
1787 }
1788 case EncodedArrayValueIterator::ValueType::kField:
1789 case EncodedArrayValueIterator::ValueType::kMethod:
1790 case EncodedArrayValueIterator::ValueType::kEnum:
1791 case EncodedArrayValueIterator::ValueType::kArray:
1792 case EncodedArrayValueIterator::ValueType::kAnnotation:
1793 // Unreachable based on current EncodedArrayValueIterator::Next().
Andreas Gampef45d61c2017-06-07 10:29:33 -07001794 UNIMPLEMENTED(FATAL) << " type " << it.GetValueType();
Orion Hodsonc069a302017-01-18 09:23:12 +00001795 UNREACHABLE();
Orion Hodsonc069a302017-01-18 09:23:12 +00001796 case EncodedArrayValueIterator::ValueType::kNull:
1797 type = "Null";
1798 value = "null";
1799 break;
1800 case EncodedArrayValueIterator::ValueType::kBoolean:
1801 type = "boolean";
1802 value = it.GetJavaValue().z ? "true" : "false";
1803 break;
1804 }
1805
1806 if (gOptions.outputFormat == OUTPUT_PLAIN) {
1807 fprintf(gOutFile, " link_argument[%zu] : %s (%s)\n", argument, value.c_str(), type);
1808 } else {
1809 fprintf(gOutFile, "<link_argument index=\"%zu\" type=\"%s\" value=", argument, type);
1810 dumpEscapedString(value.c_str());
1811 fprintf(gOutFile, "/>\n");
1812 }
1813
1814 it.Next();
1815 argument++;
1816 }
1817
1818 if (gOptions.outputFormat == OUTPUT_XML) {
1819 fprintf(gOutFile, "</call_site>\n");
1820 }
1821}
1822
Aart Bik69ae54a2015-07-01 14:52:26 -07001823/*
1824 * Dumps the requested sections of the file.
1825 */
Aart Bik7b45a8a2016-10-24 16:07:59 -07001826static void processDexFile(const char* fileName,
1827 const DexFile* pDexFile, size_t i, size_t n) {
Aart Bik69ae54a2015-07-01 14:52:26 -07001828 if (gOptions.verbose) {
Aart Bik7b45a8a2016-10-24 16:07:59 -07001829 fputs("Opened '", gOutFile);
1830 fputs(fileName, gOutFile);
1831 if (n > 1) {
Mathieu Chartier79c87da2017-10-10 11:54:29 -07001832 fprintf(gOutFile, ":%s", DexFileLoader::GetMultiDexClassesDexName(i).c_str());
Aart Bik7b45a8a2016-10-24 16:07:59 -07001833 }
1834 fprintf(gOutFile, "', DEX version '%.3s'\n", pDexFile->GetHeader().magic_ + 4);
Aart Bik69ae54a2015-07-01 14:52:26 -07001835 }
1836
1837 // Headers.
1838 if (gOptions.showFileHeaders) {
1839 dumpFileHeader(pDexFile);
1840 }
1841
1842 // Open XML context.
1843 if (gOptions.outputFormat == OUTPUT_XML) {
1844 fprintf(gOutFile, "<api>\n");
1845 }
1846
1847 // Iterate over all classes.
1848 char* package = nullptr;
1849 const u4 classDefsSize = pDexFile->GetHeader().class_defs_size_;
1850 for (u4 i = 0; i < classDefsSize; i++) {
Aart Bik69ae54a2015-07-01 14:52:26 -07001851 dumpClass(pDexFile, i, &package);
1852 } // for
1853
Orion Hodsonc069a302017-01-18 09:23:12 +00001854 // Iterate over all method handles.
1855 for (u4 i = 0; i < pDexFile->NumMethodHandles(); ++i) {
1856 dumpMethodHandle(pDexFile, i);
1857 } // for
1858
1859 // Iterate over all call site ids.
1860 for (u4 i = 0; i < pDexFile->NumCallSiteIds(); ++i) {
1861 dumpCallSite(pDexFile, i);
1862 } // for
1863
Aart Bik69ae54a2015-07-01 14:52:26 -07001864 // Free the last package allocated.
1865 if (package != nullptr) {
1866 fprintf(gOutFile, "</package>\n");
1867 free(package);
1868 }
1869
1870 // Close XML context.
1871 if (gOptions.outputFormat == OUTPUT_XML) {
1872 fprintf(gOutFile, "</api>\n");
1873 }
1874}
1875
David Sehr5a1f6292018-01-19 11:08:51 -08001876static bool openAndMapFile(const char* fileName,
1877 const uint8_t** base,
1878 size_t* size,
1879 std::string* error_msg) {
1880 int fd = open(fileName, O_RDONLY);
1881 if (fd < 0) {
1882 *error_msg = "open failed";
1883 return false;
1884 }
1885 struct stat st;
1886 if (fstat(fd, &st) < 0) {
1887 *error_msg = "stat failed";
1888 return false;
1889 }
1890 *size = st.st_size;
1891 if (*size == 0) {
1892 *error_msg = "size == 0";
1893 return false;
1894 }
1895 void* addr = mmap(nullptr /*addr*/, *size, PROT_READ, MAP_PRIVATE, fd, 0 /*offset*/);
1896 if (addr == MAP_FAILED) {
1897 *error_msg = "mmap failed";
1898 return false;
1899 }
1900 *base = reinterpret_cast<const uint8_t*>(addr);
1901 return true;
1902}
1903
Aart Bik69ae54a2015-07-01 14:52:26 -07001904/*
1905 * Processes a single file (either direct .dex or indirect .zip/.jar/.apk).
1906 */
1907int processFile(const char* fileName) {
1908 if (gOptions.verbose) {
1909 fprintf(gOutFile, "Processing '%s'...\n", fileName);
1910 }
1911
1912 // If the file is not a .dex file, the function tries .zip/.jar/.apk files,
Aart Bikdce50862016-06-10 16:04:03 -07001913 // all of which are Zip archives with "classes.dex" inside.
Aart Bik37d6a3b2016-06-21 18:30:10 -07001914 const bool kVerifyChecksum = !gOptions.ignoreBadChecksum;
David Sehr5a1f6292018-01-19 11:08:51 -08001915 const uint8_t* base = nullptr;
1916 size_t size = 0;
Aart Bik69ae54a2015-07-01 14:52:26 -07001917 std::string error_msg;
David Sehr5a1f6292018-01-19 11:08:51 -08001918 if (!openAndMapFile(fileName, &base, &size, &error_msg)) {
Andreas Gampe221d9812018-01-22 17:48:56 -08001919 LOG(ERROR) << error_msg;
David Sehr5a1f6292018-01-19 11:08:51 -08001920 return -1;
1921 }
1922 const DexFileLoader dex_file_loader;
Aart Bik69ae54a2015-07-01 14:52:26 -07001923 std::vector<std::unique_ptr<const DexFile>> dex_files;
David Sehr5a1f6292018-01-19 11:08:51 -08001924 if (!dex_file_loader.OpenAll(
1925 base, size, fileName, /*verify*/ true, kVerifyChecksum, &error_msg, &dex_files)) {
Aart Bik69ae54a2015-07-01 14:52:26 -07001926 // Display returned error message to user. Note that this error behavior
1927 // differs from the error messages shown by the original Dalvik dexdump.
Andreas Gampe221d9812018-01-22 17:48:56 -08001928 LOG(ERROR) << error_msg;
Aart Bik69ae54a2015-07-01 14:52:26 -07001929 return -1;
1930 }
1931
Aart Bik4e149602015-07-09 11:45:28 -07001932 // Success. Either report checksum verification or process
1933 // all dex files found in given file.
Aart Bik69ae54a2015-07-01 14:52:26 -07001934 if (gOptions.checksumOnly) {
1935 fprintf(gOutFile, "Checksum verified\n");
1936 } else {
Aart Bik7b45a8a2016-10-24 16:07:59 -07001937 for (size_t i = 0, n = dex_files.size(); i < n; i++) {
1938 processDexFile(fileName, dex_files[i].get(), i, n);
Aart Bik4e149602015-07-09 11:45:28 -07001939 }
Aart Bik69ae54a2015-07-01 14:52:26 -07001940 }
1941 return 0;
1942}
1943
1944} // namespace art