blob: a9ae55fd8b04d546c4edee10fc230a405250579e [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
David Sehr853a8e12016-09-01 13:03:50 -070033#include "dex_ir_builder.h"
David Sehr7629f602016-08-07 16:01:51 -070034#include "dex_file-inl.h"
35#include "dex_instruction-inl.h"
David Sehrcdcfde72016-09-26 07:44:04 -070036#include "dex_visualize.h"
Jeff Haoa8621002016-10-04 18:13:44 +000037#include "dex_writer.h"
David Sehrcdcfde72016-09-26 07:44:04 -070038#include "jit/offline_profiling_info.h"
Nicolas Geoffrayfd1a6c22016-10-04 11:01:17 +000039#include "os.h"
David Sehr7629f602016-08-07 16:01:51 -070040#include "utils.h"
41
42namespace art {
43
44/*
45 * Options parsed in main driver.
46 */
47struct Options options_;
48
49/*
50 * Output file. Defaults to stdout.
51 */
52FILE* out_file_ = stdout;
53
54/*
David Sehrcdcfde72016-09-26 07:44:04 -070055 * Profile information file.
56 */
57ProfileCompilationInfo* profile_info_ = nullptr;
58
59/*
David Sehr7629f602016-08-07 16:01:51 -070060 * Flags for use with createAccessFlagStr().
61 */
62enum AccessFor {
63 kAccessForClass = 0, kAccessForMethod = 1, kAccessForField = 2, kAccessForMAX
64};
65const int kNumFlags = 18;
66
67/*
68 * Gets 2 little-endian bytes.
69 */
70static inline uint16_t Get2LE(unsigned char const* src) {
71 return src[0] | (src[1] << 8);
72}
73
74/*
Jeff Haoc3acfc52016-08-29 14:18:26 -070075 * Converts a type descriptor to human-readable "dotted" form. For
76 * example, "Ljava/lang/String;" becomes "java.lang.String", and
77 * "[I" becomes "int[]". Also converts '$' to '.', which means this
78 * form can't be converted back to a descriptor.
79 */
80static std::string DescriptorToDotWrapper(const char* descriptor) {
81 std::string result = DescriptorToDot(descriptor);
82 size_t found = result.find('$');
83 while (found != std::string::npos) {
84 result[found] = '.';
85 found = result.find('$', found);
86 }
87 return result;
88}
89
90/*
David Sehr7629f602016-08-07 16:01:51 -070091 * Converts the class name portion of a type descriptor to human-readable
92 * "dotted" form. For example, "Ljava/lang/String;" becomes "String".
93 */
94static std::string DescriptorClassToDot(const char* str) {
95 std::string descriptor(str);
96 // Reduce to just the class name prefix.
97 size_t last_slash = descriptor.rfind('/');
98 if (last_slash == std::string::npos) {
99 last_slash = 0;
100 }
101 // Start past the '/' or 'L'.
102 last_slash++;
103
104 // Copy class name over, trimming trailing ';'.
105 size_t size = descriptor.size() - 1 - last_slash;
106 std::string result(descriptor.substr(last_slash, size));
107
108 // Replace '$' with '.'.
109 size_t dollar_sign = result.find('$');
110 while (dollar_sign != std::string::npos) {
111 result[dollar_sign] = '.';
112 dollar_sign = result.find('$', dollar_sign);
113 }
114
115 return result;
116}
117
118/*
119 * Returns string representing the boolean value.
120 */
121static const char* StrBool(bool val) {
122 return val ? "true" : "false";
123}
124
125/*
126 * Returns a quoted string representing the boolean value.
127 */
128static const char* QuotedBool(bool val) {
129 return val ? "\"true\"" : "\"false\"";
130}
131
132/*
133 * Returns a quoted string representing the access flags.
134 */
135static const char* QuotedVisibility(uint32_t access_flags) {
136 if (access_flags & kAccPublic) {
137 return "\"public\"";
138 } else if (access_flags & kAccProtected) {
139 return "\"protected\"";
140 } else if (access_flags & kAccPrivate) {
141 return "\"private\"";
142 } else {
143 return "\"package\"";
144 }
145}
146
147/*
148 * Counts the number of '1' bits in a word.
149 */
150static int CountOnes(uint32_t val) {
151 val = val - ((val >> 1) & 0x55555555);
152 val = (val & 0x33333333) + ((val >> 2) & 0x33333333);
153 return (((val + (val >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24;
154}
155
156/*
157 * Creates a new string with human-readable access flags.
158 *
159 * In the base language the access_flags fields are type uint16_t; in Dalvik they're uint32_t.
160 */
161static char* CreateAccessFlagStr(uint32_t flags, AccessFor for_what) {
162 static const char* kAccessStrings[kAccessForMAX][kNumFlags] = {
163 {
164 "PUBLIC", /* 0x00001 */
165 "PRIVATE", /* 0x00002 */
166 "PROTECTED", /* 0x00004 */
167 "STATIC", /* 0x00008 */
168 "FINAL", /* 0x00010 */
169 "?", /* 0x00020 */
170 "?", /* 0x00040 */
171 "?", /* 0x00080 */
172 "?", /* 0x00100 */
173 "INTERFACE", /* 0x00200 */
174 "ABSTRACT", /* 0x00400 */
175 "?", /* 0x00800 */
176 "SYNTHETIC", /* 0x01000 */
177 "ANNOTATION", /* 0x02000 */
178 "ENUM", /* 0x04000 */
179 "?", /* 0x08000 */
180 "VERIFIED", /* 0x10000 */
181 "OPTIMIZED", /* 0x20000 */
182 }, {
183 "PUBLIC", /* 0x00001 */
184 "PRIVATE", /* 0x00002 */
185 "PROTECTED", /* 0x00004 */
186 "STATIC", /* 0x00008 */
187 "FINAL", /* 0x00010 */
188 "SYNCHRONIZED", /* 0x00020 */
189 "BRIDGE", /* 0x00040 */
190 "VARARGS", /* 0x00080 */
191 "NATIVE", /* 0x00100 */
192 "?", /* 0x00200 */
193 "ABSTRACT", /* 0x00400 */
194 "STRICT", /* 0x00800 */
195 "SYNTHETIC", /* 0x01000 */
196 "?", /* 0x02000 */
197 "?", /* 0x04000 */
198 "MIRANDA", /* 0x08000 */
199 "CONSTRUCTOR", /* 0x10000 */
200 "DECLARED_SYNCHRONIZED", /* 0x20000 */
201 }, {
202 "PUBLIC", /* 0x00001 */
203 "PRIVATE", /* 0x00002 */
204 "PROTECTED", /* 0x00004 */
205 "STATIC", /* 0x00008 */
206 "FINAL", /* 0x00010 */
207 "?", /* 0x00020 */
208 "VOLATILE", /* 0x00040 */
209 "TRANSIENT", /* 0x00080 */
210 "?", /* 0x00100 */
211 "?", /* 0x00200 */
212 "?", /* 0x00400 */
213 "?", /* 0x00800 */
214 "SYNTHETIC", /* 0x01000 */
215 "?", /* 0x02000 */
216 "ENUM", /* 0x04000 */
217 "?", /* 0x08000 */
218 "?", /* 0x10000 */
219 "?", /* 0x20000 */
220 },
221 };
222
223 // Allocate enough storage to hold the expected number of strings,
224 // plus a space between each. We over-allocate, using the longest
225 // string above as the base metric.
226 const int kLongest = 21; // The strlen of longest string above.
227 const int count = CountOnes(flags);
228 char* str;
229 char* cp;
230 cp = str = reinterpret_cast<char*>(malloc(count * (kLongest + 1) + 1));
231
232 for (int i = 0; i < kNumFlags; i++) {
233 if (flags & 0x01) {
234 const char* accessStr = kAccessStrings[for_what][i];
235 const int len = strlen(accessStr);
236 if (cp != str) {
237 *cp++ = ' ';
238 }
239 memcpy(cp, accessStr, len);
240 cp += len;
241 }
242 flags >>= 1;
243 } // for
244
245 *cp = '\0';
246 return str;
247}
248
249static std::string GetSignatureForProtoId(const dex_ir::ProtoId* proto) {
250 if (proto == nullptr) {
251 return "<no signature>";
252 }
253
David Sehr7629f602016-08-07 16:01:51 -0700254 std::string result("(");
Jeff Haoa8621002016-10-04 18:13:44 +0000255 const dex_ir::TypeList* type_list = proto->Parameters();
256 if (type_list != nullptr) {
257 for (const dex_ir::TypeId* type_id : *type_list->GetTypeList()) {
258 result += type_id->GetStringId()->Data();
259 }
David Sehr7629f602016-08-07 16:01:51 -0700260 }
261 result += ")";
262 result += proto->ReturnType()->GetStringId()->Data();
263 return result;
264}
265
266/*
267 * Copies character data from "data" to "out", converting non-ASCII values
268 * to fprintf format chars or an ASCII filler ('.' or '?').
269 *
270 * The output buffer must be able to hold (2*len)+1 bytes. The result is
271 * NULL-terminated.
272 */
273static void Asciify(char* out, const unsigned char* data, size_t len) {
274 while (len--) {
275 if (*data < 0x20) {
276 // Could do more here, but we don't need them yet.
277 switch (*data) {
278 case '\0':
279 *out++ = '\\';
280 *out++ = '0';
281 break;
282 case '\n':
283 *out++ = '\\';
284 *out++ = 'n';
285 break;
286 default:
287 *out++ = '.';
288 break;
289 } // switch
290 } else if (*data >= 0x80) {
291 *out++ = '?';
292 } else {
293 *out++ = *data;
294 }
295 data++;
296 } // while
297 *out = '\0';
298}
299
300/*
301 * Dumps a string value with some escape characters.
302 */
303static void DumpEscapedString(const char* p) {
304 fputs("\"", out_file_);
305 for (; *p; p++) {
306 switch (*p) {
307 case '\\':
308 fputs("\\\\", out_file_);
309 break;
310 case '\"':
311 fputs("\\\"", out_file_);
312 break;
313 case '\t':
314 fputs("\\t", out_file_);
315 break;
316 case '\n':
317 fputs("\\n", out_file_);
318 break;
319 case '\r':
320 fputs("\\r", out_file_);
321 break;
322 default:
323 putc(*p, out_file_);
324 } // switch
325 } // for
326 fputs("\"", out_file_);
327}
328
329/*
330 * Dumps a string as an XML attribute value.
331 */
332static void DumpXmlAttribute(const char* p) {
333 for (; *p; p++) {
334 switch (*p) {
335 case '&':
336 fputs("&amp;", out_file_);
337 break;
338 case '<':
339 fputs("&lt;", out_file_);
340 break;
341 case '>':
342 fputs("&gt;", out_file_);
343 break;
344 case '"':
345 fputs("&quot;", out_file_);
346 break;
347 case '\t':
348 fputs("&#x9;", out_file_);
349 break;
350 case '\n':
351 fputs("&#xA;", out_file_);
352 break;
353 case '\r':
354 fputs("&#xD;", out_file_);
355 break;
356 default:
357 putc(*p, out_file_);
358 } // switch
359 } // for
360}
361
Jeff Hao3ab96b42016-09-09 18:35:01 -0700362// Forward declare to resolve circular dependence.
363static void DumpEncodedValue(const dex_ir::EncodedValue* data);
364
365/*
366 * Dumps encoded annotation.
367 */
368static void DumpEncodedAnnotation(dex_ir::EncodedAnnotation* annotation) {
369 fputs(annotation->GetType()->GetStringId()->Data(), out_file_);
370 // Display all name=value pairs.
371 for (auto& subannotation : *annotation->GetAnnotationElements()) {
372 fputc(' ', out_file_);
373 fputs(subannotation->GetName()->Data(), out_file_);
374 fputc('=', out_file_);
375 DumpEncodedValue(subannotation->GetValue());
376 }
377}
David Sehr7629f602016-08-07 16:01:51 -0700378/*
379 * Dumps encoded value.
380 */
Jeff Hao3ab96b42016-09-09 18:35:01 -0700381static void DumpEncodedValue(const dex_ir::EncodedValue* data) {
David Sehr7629f602016-08-07 16:01:51 -0700382 switch (data->Type()) {
383 case DexFile::kDexAnnotationByte:
384 fprintf(out_file_, "%" PRId8, data->GetByte());
385 break;
386 case DexFile::kDexAnnotationShort:
387 fprintf(out_file_, "%" PRId16, data->GetShort());
388 break;
389 case DexFile::kDexAnnotationChar:
390 fprintf(out_file_, "%" PRIu16, data->GetChar());
391 break;
392 case DexFile::kDexAnnotationInt:
393 fprintf(out_file_, "%" PRId32, data->GetInt());
394 break;
395 case DexFile::kDexAnnotationLong:
396 fprintf(out_file_, "%" PRId64, data->GetLong());
397 break;
398 case DexFile::kDexAnnotationFloat: {
399 fprintf(out_file_, "%g", data->GetFloat());
400 break;
401 }
402 case DexFile::kDexAnnotationDouble: {
403 fprintf(out_file_, "%g", data->GetDouble());
404 break;
405 }
406 case DexFile::kDexAnnotationString: {
407 dex_ir::StringId* string_id = data->GetStringId();
408 if (options_.output_format_ == kOutputPlain) {
409 DumpEscapedString(string_id->Data());
410 } else {
411 DumpXmlAttribute(string_id->Data());
412 }
413 break;
414 }
415 case DexFile::kDexAnnotationType: {
Jeff Hao3ab96b42016-09-09 18:35:01 -0700416 dex_ir::TypeId* type_id = data->GetTypeId();
417 fputs(type_id->GetStringId()->Data(), out_file_);
David Sehr7629f602016-08-07 16:01:51 -0700418 break;
419 }
420 case DexFile::kDexAnnotationField:
421 case DexFile::kDexAnnotationEnum: {
422 dex_ir::FieldId* field_id = data->GetFieldId();
423 fputs(field_id->Name()->Data(), out_file_);
424 break;
425 }
426 case DexFile::kDexAnnotationMethod: {
427 dex_ir::MethodId* method_id = data->GetMethodId();
428 fputs(method_id->Name()->Data(), out_file_);
429 break;
430 }
431 case DexFile::kDexAnnotationArray: {
432 fputc('{', out_file_);
433 // Display all elements.
Jeff Hao3ab96b42016-09-09 18:35:01 -0700434 for (auto& value : *data->GetEncodedArray()->GetEncodedValues()) {
David Sehr7629f602016-08-07 16:01:51 -0700435 fputc(' ', out_file_);
Jeff Hao3ab96b42016-09-09 18:35:01 -0700436 DumpEncodedValue(value.get());
David Sehr7629f602016-08-07 16:01:51 -0700437 }
438 fputs(" }", out_file_);
439 break;
440 }
441 case DexFile::kDexAnnotationAnnotation: {
Jeff Hao3ab96b42016-09-09 18:35:01 -0700442 DumpEncodedAnnotation(data->GetEncodedAnnotation());
David Sehr7629f602016-08-07 16:01:51 -0700443 break;
444 }
445 case DexFile::kDexAnnotationNull:
446 fputs("null", out_file_);
447 break;
448 case DexFile::kDexAnnotationBoolean:
449 fputs(StrBool(data->GetBoolean()), out_file_);
450 break;
451 default:
452 fputs("????", out_file_);
453 break;
454 } // switch
455}
456
457/*
458 * Dumps the file header.
459 */
Jeff Hao3ab96b42016-09-09 18:35:01 -0700460static void DumpFileHeader(dex_ir::Header* header) {
David Sehr7629f602016-08-07 16:01:51 -0700461 char sanitized[8 * 2 + 1];
Jeff Hao3ab96b42016-09-09 18:35:01 -0700462 dex_ir::Collections& collections = header->GetCollections();
David Sehr7629f602016-08-07 16:01:51 -0700463 fprintf(out_file_, "DEX file header:\n");
464 Asciify(sanitized, header->Magic(), 8);
465 fprintf(out_file_, "magic : '%s'\n", sanitized);
466 fprintf(out_file_, "checksum : %08x\n", header->Checksum());
467 fprintf(out_file_, "signature : %02x%02x...%02x%02x\n",
468 header->Signature()[0], header->Signature()[1],
469 header->Signature()[DexFile::kSha1DigestSize - 2],
470 header->Signature()[DexFile::kSha1DigestSize - 1]);
471 fprintf(out_file_, "file_size : %d\n", header->FileSize());
472 fprintf(out_file_, "header_size : %d\n", header->HeaderSize());
473 fprintf(out_file_, "link_size : %d\n", header->LinkSize());
474 fprintf(out_file_, "link_off : %d (0x%06x)\n",
475 header->LinkOffset(), header->LinkOffset());
Jeff Hao3ab96b42016-09-09 18:35:01 -0700476 fprintf(out_file_, "string_ids_size : %d\n", collections.StringIdsSize());
David Sehr7629f602016-08-07 16:01:51 -0700477 fprintf(out_file_, "string_ids_off : %d (0x%06x)\n",
Jeff Hao3ab96b42016-09-09 18:35:01 -0700478 collections.StringIdsOffset(), collections.StringIdsOffset());
479 fprintf(out_file_, "type_ids_size : %d\n", collections.TypeIdsSize());
David Sehr7629f602016-08-07 16:01:51 -0700480 fprintf(out_file_, "type_ids_off : %d (0x%06x)\n",
Jeff Hao3ab96b42016-09-09 18:35:01 -0700481 collections.TypeIdsOffset(), collections.TypeIdsOffset());
482 fprintf(out_file_, "proto_ids_size : %d\n", collections.ProtoIdsSize());
David Sehr7629f602016-08-07 16:01:51 -0700483 fprintf(out_file_, "proto_ids_off : %d (0x%06x)\n",
Jeff Hao3ab96b42016-09-09 18:35:01 -0700484 collections.ProtoIdsOffset(), collections.ProtoIdsOffset());
485 fprintf(out_file_, "field_ids_size : %d\n", collections.FieldIdsSize());
David Sehr7629f602016-08-07 16:01:51 -0700486 fprintf(out_file_, "field_ids_off : %d (0x%06x)\n",
Jeff Hao3ab96b42016-09-09 18:35:01 -0700487 collections.FieldIdsOffset(), collections.FieldIdsOffset());
488 fprintf(out_file_, "method_ids_size : %d\n", collections.MethodIdsSize());
David Sehr7629f602016-08-07 16:01:51 -0700489 fprintf(out_file_, "method_ids_off : %d (0x%06x)\n",
Jeff Hao3ab96b42016-09-09 18:35:01 -0700490 collections.MethodIdsOffset(), collections.MethodIdsOffset());
491 fprintf(out_file_, "class_defs_size : %d\n", collections.ClassDefsSize());
David Sehr7629f602016-08-07 16:01:51 -0700492 fprintf(out_file_, "class_defs_off : %d (0x%06x)\n",
Jeff Hao3ab96b42016-09-09 18:35:01 -0700493 collections.ClassDefsOffset(), collections.ClassDefsOffset());
David Sehr7629f602016-08-07 16:01:51 -0700494 fprintf(out_file_, "data_size : %d\n", header->DataSize());
495 fprintf(out_file_, "data_off : %d (0x%06x)\n\n",
496 header->DataOffset(), header->DataOffset());
497}
498
499/*
500 * Dumps a class_def_item.
501 */
502static void DumpClassDef(dex_ir::Header* header, int idx) {
503 // General class information.
Jeff Hao3ab96b42016-09-09 18:35:01 -0700504 dex_ir::ClassDef* class_def = header->GetCollections().GetClassDef(idx);
David Sehr7629f602016-08-07 16:01:51 -0700505 fprintf(out_file_, "Class #%d header:\n", idx);
Jeff Hao3ab96b42016-09-09 18:35:01 -0700506 fprintf(out_file_, "class_idx : %d\n", class_def->ClassType()->GetIndex());
David Sehr7629f602016-08-07 16:01:51 -0700507 fprintf(out_file_, "access_flags : %d (0x%04x)\n",
508 class_def->GetAccessFlags(), class_def->GetAccessFlags());
Jeff Haoc3acfc52016-08-29 14:18:26 -0700509 uint32_t superclass_idx = class_def->Superclass() == nullptr ?
Jeff Hao3ab96b42016-09-09 18:35:01 -0700510 DexFile::kDexNoIndex16 : class_def->Superclass()->GetIndex();
Jeff Haoc3acfc52016-08-29 14:18:26 -0700511 fprintf(out_file_, "superclass_idx : %d\n", superclass_idx);
David Sehr7629f602016-08-07 16:01:51 -0700512 fprintf(out_file_, "interfaces_off : %d (0x%06x)\n",
513 class_def->InterfacesOffset(), class_def->InterfacesOffset());
514 uint32_t source_file_offset = 0xffffffffU;
515 if (class_def->SourceFile() != nullptr) {
Jeff Hao3ab96b42016-09-09 18:35:01 -0700516 source_file_offset = class_def->SourceFile()->GetIndex();
David Sehr7629f602016-08-07 16:01:51 -0700517 }
518 fprintf(out_file_, "source_file_idx : %d\n", source_file_offset);
519 uint32_t annotations_offset = 0;
520 if (class_def->Annotations() != nullptr) {
521 annotations_offset = class_def->Annotations()->GetOffset();
522 }
523 fprintf(out_file_, "annotations_off : %d (0x%06x)\n",
524 annotations_offset, annotations_offset);
David Sehr853a8e12016-09-01 13:03:50 -0700525 if (class_def->GetClassData() == nullptr) {
526 fprintf(out_file_, "class_data_off : %d (0x%06x)\n", 0, 0);
527 } else {
528 fprintf(out_file_, "class_data_off : %d (0x%06x)\n",
529 class_def->GetClassData()->GetOffset(), class_def->GetClassData()->GetOffset());
530 }
David Sehr7629f602016-08-07 16:01:51 -0700531
532 // Fields and methods.
533 dex_ir::ClassData* class_data = class_def->GetClassData();
David Sehr853a8e12016-09-01 13:03:50 -0700534 if (class_data != nullptr && class_data->StaticFields() != nullptr) {
535 fprintf(out_file_, "static_fields_size : %zu\n", class_data->StaticFields()->size());
David Sehr7629f602016-08-07 16:01:51 -0700536 } else {
537 fprintf(out_file_, "static_fields_size : 0\n");
David Sehr853a8e12016-09-01 13:03:50 -0700538 }
539 if (class_data != nullptr && class_data->InstanceFields() != nullptr) {
540 fprintf(out_file_, "instance_fields_size: %zu\n", class_data->InstanceFields()->size());
541 } else {
David Sehr7629f602016-08-07 16:01:51 -0700542 fprintf(out_file_, "instance_fields_size: 0\n");
David Sehr853a8e12016-09-01 13:03:50 -0700543 }
544 if (class_data != nullptr && class_data->DirectMethods() != nullptr) {
545 fprintf(out_file_, "direct_methods_size : %zu\n", class_data->DirectMethods()->size());
546 } else {
David Sehr7629f602016-08-07 16:01:51 -0700547 fprintf(out_file_, "direct_methods_size : 0\n");
David Sehr853a8e12016-09-01 13:03:50 -0700548 }
549 if (class_data != nullptr && class_data->VirtualMethods() != nullptr) {
550 fprintf(out_file_, "virtual_methods_size: %zu\n", class_data->VirtualMethods()->size());
551 } else {
David Sehr7629f602016-08-07 16:01:51 -0700552 fprintf(out_file_, "virtual_methods_size: 0\n");
553 }
554 fprintf(out_file_, "\n");
555}
556
557/**
558 * Dumps an annotation set item.
559 */
560static void DumpAnnotationSetItem(dex_ir::AnnotationSetItem* set_item) {
David Sehr853a8e12016-09-01 13:03:50 -0700561 if (set_item == nullptr || set_item->GetItems()->size() == 0) {
David Sehr7629f602016-08-07 16:01:51 -0700562 fputs(" empty-annotation-set\n", out_file_);
563 return;
564 }
Jeff Hao3ab96b42016-09-09 18:35:01 -0700565 for (dex_ir::AnnotationItem* annotation : *set_item->GetItems()) {
David Sehr7629f602016-08-07 16:01:51 -0700566 if (annotation == nullptr) {
567 continue;
568 }
569 fputs(" ", out_file_);
570 switch (annotation->GetVisibility()) {
571 case DexFile::kDexVisibilityBuild: fputs("VISIBILITY_BUILD ", out_file_); break;
572 case DexFile::kDexVisibilityRuntime: fputs("VISIBILITY_RUNTIME ", out_file_); break;
573 case DexFile::kDexVisibilitySystem: fputs("VISIBILITY_SYSTEM ", out_file_); break;
574 default: fputs("VISIBILITY_UNKNOWN ", out_file_); break;
575 } // switch
Jeff Hao3ab96b42016-09-09 18:35:01 -0700576 DumpEncodedAnnotation(annotation->GetAnnotation());
David Sehr7629f602016-08-07 16:01:51 -0700577 fputc('\n', out_file_);
578 }
579}
580
581/*
582 * Dumps class annotations.
583 */
584static void DumpClassAnnotations(dex_ir::Header* header, int idx) {
Jeff Hao3ab96b42016-09-09 18:35:01 -0700585 dex_ir::ClassDef* class_def = header->GetCollections().GetClassDef(idx);
David Sehr7629f602016-08-07 16:01:51 -0700586 dex_ir::AnnotationsDirectoryItem* annotations_directory = class_def->Annotations();
587 if (annotations_directory == nullptr) {
588 return; // none
589 }
590
591 fprintf(out_file_, "Class #%d annotations:\n", idx);
592
593 dex_ir::AnnotationSetItem* class_set_item = annotations_directory->GetClassAnnotation();
David Sehr853a8e12016-09-01 13:03:50 -0700594 dex_ir::FieldAnnotationVector* fields = annotations_directory->GetFieldAnnotations();
595 dex_ir::MethodAnnotationVector* methods = annotations_directory->GetMethodAnnotations();
596 dex_ir::ParameterAnnotationVector* parameters = annotations_directory->GetParameterAnnotations();
David Sehr7629f602016-08-07 16:01:51 -0700597
598 // Annotations on the class itself.
599 if (class_set_item != nullptr) {
600 fprintf(out_file_, "Annotations on class\n");
601 DumpAnnotationSetItem(class_set_item);
602 }
603
604 // Annotations on fields.
David Sehr853a8e12016-09-01 13:03:50 -0700605 if (fields != nullptr) {
606 for (auto& field : *fields) {
607 const dex_ir::FieldId* field_id = field->GetFieldId();
Jeff Hao3ab96b42016-09-09 18:35:01 -0700608 const uint32_t field_idx = field_id->GetIndex();
David Sehr853a8e12016-09-01 13:03:50 -0700609 const char* field_name = field_id->Name()->Data();
610 fprintf(out_file_, "Annotations on field #%u '%s'\n", field_idx, field_name);
611 DumpAnnotationSetItem(field->GetAnnotationSetItem());
612 }
David Sehr7629f602016-08-07 16:01:51 -0700613 }
614
615 // Annotations on methods.
David Sehr853a8e12016-09-01 13:03:50 -0700616 if (methods != nullptr) {
617 for (auto& method : *methods) {
618 const dex_ir::MethodId* method_id = method->GetMethodId();
Jeff Hao3ab96b42016-09-09 18:35:01 -0700619 const uint32_t method_idx = method_id->GetIndex();
David Sehr853a8e12016-09-01 13:03:50 -0700620 const char* method_name = method_id->Name()->Data();
621 fprintf(out_file_, "Annotations on method #%u '%s'\n", method_idx, method_name);
622 DumpAnnotationSetItem(method->GetAnnotationSetItem());
623 }
David Sehr7629f602016-08-07 16:01:51 -0700624 }
625
626 // Annotations on method parameters.
David Sehr853a8e12016-09-01 13:03:50 -0700627 if (parameters != nullptr) {
628 for (auto& parameter : *parameters) {
629 const dex_ir::MethodId* method_id = parameter->GetMethodId();
Jeff Hao3ab96b42016-09-09 18:35:01 -0700630 const uint32_t method_idx = method_id->GetIndex();
David Sehr853a8e12016-09-01 13:03:50 -0700631 const char* method_name = method_id->Name()->Data();
632 fprintf(out_file_, "Annotations on method #%u '%s' parameters\n", method_idx, method_name);
633 uint32_t j = 0;
Jeff Hao3ab96b42016-09-09 18:35:01 -0700634 for (dex_ir::AnnotationSetItem* annotation : *parameter->GetAnnotations()->GetItems()) {
David Sehr853a8e12016-09-01 13:03:50 -0700635 fprintf(out_file_, "#%u\n", j);
Jeff Hao3ab96b42016-09-09 18:35:01 -0700636 DumpAnnotationSetItem(annotation);
David Sehr853a8e12016-09-01 13:03:50 -0700637 ++j;
638 }
David Sehr7629f602016-08-07 16:01:51 -0700639 }
640 }
641
642 fputc('\n', out_file_);
643}
644
645/*
646 * Dumps an interface that a class declares to implement.
647 */
David Sehr853a8e12016-09-01 13:03:50 -0700648static void DumpInterface(const dex_ir::TypeId* type_item, int i) {
David Sehr7629f602016-08-07 16:01:51 -0700649 const char* interface_name = type_item->GetStringId()->Data();
650 if (options_.output_format_ == kOutputPlain) {
651 fprintf(out_file_, " #%d : '%s'\n", i, interface_name);
652 } else {
Jeff Haoc3acfc52016-08-29 14:18:26 -0700653 std::string dot(DescriptorToDotWrapper(interface_name));
David Sehr7629f602016-08-07 16:01:51 -0700654 fprintf(out_file_, "<implements name=\"%s\">\n</implements>\n", dot.c_str());
655 }
656}
657
658/*
659 * Dumps the catches table associated with the code.
660 */
661static void DumpCatches(const dex_ir::CodeItem* code) {
662 const uint16_t tries_size = code->TriesSize();
663
664 // No catch table.
665 if (tries_size == 0) {
666 fprintf(out_file_, " catches : (none)\n");
667 return;
668 }
669
670 // Dump all table entries.
671 fprintf(out_file_, " catches : %d\n", tries_size);
672 std::vector<std::unique_ptr<const dex_ir::TryItem>>* tries = code->Tries();
673 for (uint32_t i = 0; i < tries_size; i++) {
674 const dex_ir::TryItem* try_item = (*tries)[i].get();
675 const uint32_t start = try_item->StartAddr();
676 const uint32_t end = start + try_item->InsnCount();
677 fprintf(out_file_, " 0x%04x - 0x%04x\n", start, end);
Jeff Haoa8621002016-10-04 18:13:44 +0000678 for (auto& handler : *try_item->GetHandlers()->GetHandlers()) {
David Sehr7629f602016-08-07 16:01:51 -0700679 const dex_ir::TypeId* type_id = handler->GetTypeId();
680 const char* descriptor = (type_id == nullptr) ? "<any>" : type_id->GetStringId()->Data();
681 fprintf(out_file_, " %s -> 0x%04x\n", descriptor, handler->GetAddress());
682 } // for
683 } // for
684}
685
686/*
687 * Dumps all positions table entries associated with the code.
688 */
689static void DumpPositionInfo(const dex_ir::CodeItem* code) {
690 dex_ir::DebugInfoItem* debug_info = code->DebugInfo();
691 if (debug_info == nullptr) {
692 return;
693 }
694 std::vector<std::unique_ptr<dex_ir::PositionInfo>>& positions = debug_info->GetPositionInfo();
695 for (size_t i = 0; i < positions.size(); ++i) {
696 fprintf(out_file_, " 0x%04x line=%d\n", positions[i]->address_, positions[i]->line_);
697 }
698}
699
700/*
701 * Dumps all locals table entries associated with the code.
702 */
703static void DumpLocalInfo(const dex_ir::CodeItem* code) {
704 dex_ir::DebugInfoItem* debug_info = code->DebugInfo();
705 if (debug_info == nullptr) {
706 return;
707 }
708 std::vector<std::unique_ptr<dex_ir::LocalInfo>>& locals = debug_info->GetLocalInfo();
709 for (size_t i = 0; i < locals.size(); ++i) {
710 dex_ir::LocalInfo* entry = locals[i].get();
711 fprintf(out_file_, " 0x%04x - 0x%04x reg=%d %s %s %s\n",
712 entry->start_address_, entry->end_address_, entry->reg_,
713 entry->name_.c_str(), entry->descriptor_.c_str(), entry->signature_.c_str());
714 }
715}
716
717/*
718 * Helper for dumpInstruction(), which builds the string
719 * representation for the index in the given instruction.
720 * Returns a pointer to a buffer of sufficient size.
721 */
722static std::unique_ptr<char[]> IndexString(dex_ir::Header* header,
723 const Instruction* dec_insn,
724 size_t buf_size) {
725 std::unique_ptr<char[]> buf(new char[buf_size]);
726 // Determine index and width of the string.
727 uint32_t index = 0;
728 uint32_t width = 4;
729 switch (Instruction::FormatOf(dec_insn->Opcode())) {
730 // SOME NOT SUPPORTED:
731 // case Instruction::k20bc:
732 case Instruction::k21c:
733 case Instruction::k35c:
734 // case Instruction::k35ms:
735 case Instruction::k3rc:
736 // case Instruction::k3rms:
737 // case Instruction::k35mi:
738 // case Instruction::k3rmi:
739 index = dec_insn->VRegB();
740 width = 4;
741 break;
742 case Instruction::k31c:
743 index = dec_insn->VRegB();
744 width = 8;
745 break;
746 case Instruction::k22c:
747 // case Instruction::k22cs:
748 index = dec_insn->VRegC();
749 width = 4;
750 break;
751 default:
752 break;
753 } // switch
754
755 // Determine index type.
756 size_t outSize = 0;
757 switch (Instruction::IndexTypeOf(dec_insn->Opcode())) {
758 case Instruction::kIndexUnknown:
759 // This function should never get called for this type, but do
760 // something sensible here, just to help with debugging.
761 outSize = snprintf(buf.get(), buf_size, "<unknown-index>");
762 break;
763 case Instruction::kIndexNone:
764 // This function should never get called for this type, but do
765 // something sensible here, just to help with debugging.
766 outSize = snprintf(buf.get(), buf_size, "<no-index>");
767 break;
768 case Instruction::kIndexTypeRef:
Jeff Hao3ab96b42016-09-09 18:35:01 -0700769 if (index < header->GetCollections().TypeIdsSize()) {
770 const char* tp = header->GetCollections().GetTypeId(index)->GetStringId()->Data();
David Sehr7629f602016-08-07 16:01:51 -0700771 outSize = snprintf(buf.get(), buf_size, "%s // type@%0*x", tp, width, index);
772 } else {
773 outSize = snprintf(buf.get(), buf_size, "<type?> // type@%0*x", width, index);
774 }
775 break;
776 case Instruction::kIndexStringRef:
Jeff Hao3ab96b42016-09-09 18:35:01 -0700777 if (index < header->GetCollections().StringIdsSize()) {
778 const char* st = header->GetCollections().GetStringId(index)->Data();
David Sehr7629f602016-08-07 16:01:51 -0700779 outSize = snprintf(buf.get(), buf_size, "\"%s\" // string@%0*x", st, width, index);
780 } else {
781 outSize = snprintf(buf.get(), buf_size, "<string?> // string@%0*x", width, index);
782 }
783 break;
784 case Instruction::kIndexMethodRef:
Jeff Hao3ab96b42016-09-09 18:35:01 -0700785 if (index < header->GetCollections().MethodIdsSize()) {
786 dex_ir::MethodId* method_id = header->GetCollections().GetMethodId(index);
David Sehr7629f602016-08-07 16:01:51 -0700787 const char* name = method_id->Name()->Data();
David Sehr72359222016-09-07 13:04:01 -0700788 std::string type_descriptor = GetSignatureForProtoId(method_id->Proto());
David Sehr7629f602016-08-07 16:01:51 -0700789 const char* back_descriptor = method_id->Class()->GetStringId()->Data();
790 outSize = snprintf(buf.get(), buf_size, "%s.%s:%s // method@%0*x",
David Sehr72359222016-09-07 13:04:01 -0700791 back_descriptor, name, type_descriptor.c_str(), width, index);
David Sehr7629f602016-08-07 16:01:51 -0700792 } else {
793 outSize = snprintf(buf.get(), buf_size, "<method?> // method@%0*x", width, index);
794 }
795 break;
796 case Instruction::kIndexFieldRef:
Jeff Hao3ab96b42016-09-09 18:35:01 -0700797 if (index < header->GetCollections().FieldIdsSize()) {
798 dex_ir::FieldId* field_id = header->GetCollections().GetFieldId(index);
David Sehr7629f602016-08-07 16:01:51 -0700799 const char* name = field_id->Name()->Data();
800 const char* type_descriptor = field_id->Type()->GetStringId()->Data();
801 const char* back_descriptor = field_id->Class()->GetStringId()->Data();
802 outSize = snprintf(buf.get(), buf_size, "%s.%s:%s // field@%0*x",
803 back_descriptor, name, type_descriptor, width, index);
804 } else {
805 outSize = snprintf(buf.get(), buf_size, "<field?> // field@%0*x", width, index);
806 }
807 break;
808 case Instruction::kIndexVtableOffset:
809 outSize = snprintf(buf.get(), buf_size, "[%0*x] // vtable #%0*x",
810 width, index, width, index);
811 break;
812 case Instruction::kIndexFieldOffset:
813 outSize = snprintf(buf.get(), buf_size, "[obj+%0*x]", width, index);
814 break;
815 // SOME NOT SUPPORTED:
816 // case Instruction::kIndexVaries:
817 // case Instruction::kIndexInlineMethod:
818 default:
819 outSize = snprintf(buf.get(), buf_size, "<?>");
820 break;
821 } // switch
822
823 // Determine success of string construction.
824 if (outSize >= buf_size) {
825 // The buffer wasn't big enough; retry with computed size. Note: snprintf()
826 // doesn't count/ the '\0' as part of its returned size, so we add explicit
827 // space for it here.
828 return IndexString(header, dec_insn, outSize + 1);
829 }
830 return buf;
831}
832
833/*
834 * Dumps a single instruction.
835 */
836static void DumpInstruction(dex_ir::Header* header, const dex_ir::CodeItem* code,
837 uint32_t code_offset, uint32_t insn_idx, uint32_t insn_width,
838 const Instruction* dec_insn) {
839 // Address of instruction (expressed as byte offset).
840 fprintf(out_file_, "%06x:", code_offset + 0x10 + insn_idx * 2);
841
842 // Dump (part of) raw bytes.
843 const uint16_t* insns = code->Insns();
844 for (uint32_t i = 0; i < 8; i++) {
845 if (i < insn_width) {
846 if (i == 7) {
847 fprintf(out_file_, " ... ");
848 } else {
849 // Print 16-bit value in little-endian order.
850 const uint8_t* bytePtr = (const uint8_t*) &insns[insn_idx + i];
851 fprintf(out_file_, " %02x%02x", bytePtr[0], bytePtr[1]);
852 }
853 } else {
854 fputs(" ", out_file_);
855 }
856 } // for
857
858 // Dump pseudo-instruction or opcode.
859 if (dec_insn->Opcode() == Instruction::NOP) {
860 const uint16_t instr = Get2LE((const uint8_t*) &insns[insn_idx]);
861 if (instr == Instruction::kPackedSwitchSignature) {
862 fprintf(out_file_, "|%04x: packed-switch-data (%d units)", insn_idx, insn_width);
863 } else if (instr == Instruction::kSparseSwitchSignature) {
864 fprintf(out_file_, "|%04x: sparse-switch-data (%d units)", insn_idx, insn_width);
865 } else if (instr == Instruction::kArrayDataSignature) {
866 fprintf(out_file_, "|%04x: array-data (%d units)", insn_idx, insn_width);
867 } else {
868 fprintf(out_file_, "|%04x: nop // spacer", insn_idx);
869 }
870 } else {
871 fprintf(out_file_, "|%04x: %s", insn_idx, dec_insn->Name());
872 }
873
874 // Set up additional argument.
875 std::unique_ptr<char[]> index_buf;
876 if (Instruction::IndexTypeOf(dec_insn->Opcode()) != Instruction::kIndexNone) {
877 index_buf = IndexString(header, dec_insn, 200);
878 }
879
880 // Dump the instruction.
881 //
882 // NOTE: pDecInsn->DumpString(pDexFile) differs too much from original.
883 //
884 switch (Instruction::FormatOf(dec_insn->Opcode())) {
885 case Instruction::k10x: // op
886 break;
887 case Instruction::k12x: // op vA, vB
888 fprintf(out_file_, " v%d, v%d", dec_insn->VRegA(), dec_insn->VRegB());
889 break;
890 case Instruction::k11n: // op vA, #+B
891 fprintf(out_file_, " v%d, #int %d // #%x",
892 dec_insn->VRegA(), (int32_t) dec_insn->VRegB(), (uint8_t)dec_insn->VRegB());
893 break;
894 case Instruction::k11x: // op vAA
895 fprintf(out_file_, " v%d", dec_insn->VRegA());
896 break;
897 case Instruction::k10t: // op +AA
898 case Instruction::k20t: { // op +AAAA
899 const int32_t targ = (int32_t) dec_insn->VRegA();
900 fprintf(out_file_, " %04x // %c%04x",
901 insn_idx + targ,
902 (targ < 0) ? '-' : '+',
903 (targ < 0) ? -targ : targ);
904 break;
905 }
906 case Instruction::k22x: // op vAA, vBBBB
907 fprintf(out_file_, " v%d, v%d", dec_insn->VRegA(), dec_insn->VRegB());
908 break;
909 case Instruction::k21t: { // op vAA, +BBBB
910 const int32_t targ = (int32_t) dec_insn->VRegB();
911 fprintf(out_file_, " v%d, %04x // %c%04x", dec_insn->VRegA(),
912 insn_idx + targ,
913 (targ < 0) ? '-' : '+',
914 (targ < 0) ? -targ : targ);
915 break;
916 }
917 case Instruction::k21s: // op vAA, #+BBBB
918 fprintf(out_file_, " v%d, #int %d // #%x",
919 dec_insn->VRegA(), (int32_t) dec_insn->VRegB(), (uint16_t)dec_insn->VRegB());
920 break;
921 case Instruction::k21h: // op vAA, #+BBBB0000[00000000]
922 // The printed format varies a bit based on the actual opcode.
923 if (dec_insn->Opcode() == Instruction::CONST_HIGH16) {
924 const int32_t value = dec_insn->VRegB() << 16;
925 fprintf(out_file_, " v%d, #int %d // #%x",
926 dec_insn->VRegA(), value, (uint16_t) dec_insn->VRegB());
927 } else {
928 const int64_t value = ((int64_t) dec_insn->VRegB()) << 48;
929 fprintf(out_file_, " v%d, #long %" PRId64 " // #%x",
930 dec_insn->VRegA(), value, (uint16_t) dec_insn->VRegB());
931 }
932 break;
933 case Instruction::k21c: // op vAA, thing@BBBB
934 case Instruction::k31c: // op vAA, thing@BBBBBBBB
935 fprintf(out_file_, " v%d, %s", dec_insn->VRegA(), index_buf.get());
936 break;
937 case Instruction::k23x: // op vAA, vBB, vCC
938 fprintf(out_file_, " v%d, v%d, v%d",
939 dec_insn->VRegA(), dec_insn->VRegB(), dec_insn->VRegC());
940 break;
941 case Instruction::k22b: // op vAA, vBB, #+CC
942 fprintf(out_file_, " v%d, v%d, #int %d // #%02x",
943 dec_insn->VRegA(), dec_insn->VRegB(),
944 (int32_t) dec_insn->VRegC(), (uint8_t) dec_insn->VRegC());
945 break;
946 case Instruction::k22t: { // op vA, vB, +CCCC
947 const int32_t targ = (int32_t) dec_insn->VRegC();
948 fprintf(out_file_, " v%d, v%d, %04x // %c%04x",
949 dec_insn->VRegA(), dec_insn->VRegB(),
950 insn_idx + targ,
951 (targ < 0) ? '-' : '+',
952 (targ < 0) ? -targ : targ);
953 break;
954 }
955 case Instruction::k22s: // op vA, vB, #+CCCC
956 fprintf(out_file_, " v%d, v%d, #int %d // #%04x",
957 dec_insn->VRegA(), dec_insn->VRegB(),
958 (int32_t) dec_insn->VRegC(), (uint16_t) dec_insn->VRegC());
959 break;
960 case Instruction::k22c: // op vA, vB, thing@CCCC
961 // NOT SUPPORTED:
962 // case Instruction::k22cs: // [opt] op vA, vB, field offset CCCC
963 fprintf(out_file_, " v%d, v%d, %s",
964 dec_insn->VRegA(), dec_insn->VRegB(), index_buf.get());
965 break;
966 case Instruction::k30t:
967 fprintf(out_file_, " #%08x", dec_insn->VRegA());
968 break;
969 case Instruction::k31i: { // op vAA, #+BBBBBBBB
970 // This is often, but not always, a float.
971 union {
972 float f;
973 uint32_t i;
974 } conv;
975 conv.i = dec_insn->VRegB();
976 fprintf(out_file_, " v%d, #float %g // #%08x",
977 dec_insn->VRegA(), conv.f, dec_insn->VRegB());
978 break;
979 }
980 case Instruction::k31t: // op vAA, offset +BBBBBBBB
981 fprintf(out_file_, " v%d, %08x // +%08x",
982 dec_insn->VRegA(), insn_idx + dec_insn->VRegB(), dec_insn->VRegB());
983 break;
984 case Instruction::k32x: // op vAAAA, vBBBB
985 fprintf(out_file_, " v%d, v%d", dec_insn->VRegA(), dec_insn->VRegB());
986 break;
987 case Instruction::k35c: { // op {vC, vD, vE, vF, vG}, thing@BBBB
988 // NOT SUPPORTED:
989 // case Instruction::k35ms: // [opt] invoke-virtual+super
990 // case Instruction::k35mi: // [opt] inline invoke
991 uint32_t arg[Instruction::kMaxVarArgRegs];
992 dec_insn->GetVarArgs(arg);
993 fputs(" {", out_file_);
994 for (int i = 0, n = dec_insn->VRegA(); i < n; i++) {
995 if (i == 0) {
996 fprintf(out_file_, "v%d", arg[i]);
997 } else {
998 fprintf(out_file_, ", v%d", arg[i]);
999 }
1000 } // for
1001 fprintf(out_file_, "}, %s", index_buf.get());
1002 break;
1003 }
1004 case Instruction::k3rc: // op {vCCCC .. v(CCCC+AA-1)}, thing@BBBB
1005 // NOT SUPPORTED:
1006 // case Instruction::k3rms: // [opt] invoke-virtual+super/range
1007 // case Instruction::k3rmi: // [opt] execute-inline/range
1008 {
1009 // This doesn't match the "dx" output when some of the args are
1010 // 64-bit values -- dx only shows the first register.
1011 fputs(" {", out_file_);
1012 for (int i = 0, n = dec_insn->VRegA(); i < n; i++) {
1013 if (i == 0) {
1014 fprintf(out_file_, "v%d", dec_insn->VRegC() + i);
1015 } else {
1016 fprintf(out_file_, ", v%d", dec_insn->VRegC() + i);
1017 }
1018 } // for
1019 fprintf(out_file_, "}, %s", index_buf.get());
1020 }
1021 break;
1022 case Instruction::k51l: { // op vAA, #+BBBBBBBBBBBBBBBB
1023 // This is often, but not always, a double.
1024 union {
1025 double d;
1026 uint64_t j;
1027 } conv;
1028 conv.j = dec_insn->WideVRegB();
1029 fprintf(out_file_, " v%d, #double %g // #%016" PRIx64,
1030 dec_insn->VRegA(), conv.d, dec_insn->WideVRegB());
1031 break;
1032 }
1033 // NOT SUPPORTED:
1034 // case Instruction::k00x: // unknown op or breakpoint
1035 // break;
1036 default:
1037 fprintf(out_file_, " ???");
1038 break;
1039 } // switch
1040
1041 fputc('\n', out_file_);
1042}
1043
1044/*
1045 * Dumps a bytecode disassembly.
1046 */
1047static void DumpBytecodes(dex_ir::Header* header, uint32_t idx,
1048 const dex_ir::CodeItem* code, uint32_t code_offset) {
Jeff Hao3ab96b42016-09-09 18:35:01 -07001049 dex_ir::MethodId* method_id = header->GetCollections().GetMethodId(idx);
David Sehr7629f602016-08-07 16:01:51 -07001050 const char* name = method_id->Name()->Data();
David Sehr72359222016-09-07 13:04:01 -07001051 std::string type_descriptor = GetSignatureForProtoId(method_id->Proto());
David Sehr7629f602016-08-07 16:01:51 -07001052 const char* back_descriptor = method_id->Class()->GetStringId()->Data();
1053
1054 // Generate header.
Jeff Haoc3acfc52016-08-29 14:18:26 -07001055 std::string dot(DescriptorToDotWrapper(back_descriptor));
David Sehr7629f602016-08-07 16:01:51 -07001056 fprintf(out_file_, "%06x: |[%06x] %s.%s:%s\n",
David Sehr72359222016-09-07 13:04:01 -07001057 code_offset, code_offset, dot.c_str(), name, type_descriptor.c_str());
David Sehr7629f602016-08-07 16:01:51 -07001058
1059 // Iterate over all instructions.
1060 const uint16_t* insns = code->Insns();
1061 for (uint32_t insn_idx = 0; insn_idx < code->InsnsSize();) {
1062 const Instruction* instruction = Instruction::At(&insns[insn_idx]);
1063 const uint32_t insn_width = instruction->SizeInCodeUnits();
1064 if (insn_width == 0) {
1065 fprintf(stderr, "GLITCH: zero-width instruction at idx=0x%04x\n", insn_idx);
1066 break;
1067 }
1068 DumpInstruction(header, code, code_offset, insn_idx, insn_width, instruction);
1069 insn_idx += insn_width;
1070 } // for
1071}
1072
1073/*
1074 * Dumps code of a method.
1075 */
1076static void DumpCode(dex_ir::Header* header, uint32_t idx, const dex_ir::CodeItem* code,
1077 uint32_t code_offset) {
1078 fprintf(out_file_, " registers : %d\n", code->RegistersSize());
1079 fprintf(out_file_, " ins : %d\n", code->InsSize());
1080 fprintf(out_file_, " outs : %d\n", code->OutsSize());
1081 fprintf(out_file_, " insns size : %d 16-bit code units\n",
1082 code->InsnsSize());
1083
1084 // Bytecode disassembly, if requested.
1085 if (options_.disassemble_) {
1086 DumpBytecodes(header, idx, code, code_offset);
1087 }
1088
1089 // Try-catch blocks.
1090 DumpCatches(code);
1091
1092 // Positions and locals table in the debug info.
1093 fprintf(out_file_, " positions : \n");
1094 DumpPositionInfo(code);
1095 fprintf(out_file_, " locals : \n");
1096 DumpLocalInfo(code);
1097}
1098
1099/*
1100 * Dumps a method.
1101 */
1102static void DumpMethod(dex_ir::Header* header, uint32_t idx, uint32_t flags,
1103 const dex_ir::CodeItem* code, int i) {
1104 // Bail for anything private if export only requested.
1105 if (options_.exports_only_ && (flags & (kAccPublic | kAccProtected)) == 0) {
1106 return;
1107 }
1108
Jeff Hao3ab96b42016-09-09 18:35:01 -07001109 dex_ir::MethodId* method_id = header->GetCollections().GetMethodId(idx);
David Sehr7629f602016-08-07 16:01:51 -07001110 const char* name = method_id->Name()->Data();
1111 char* type_descriptor = strdup(GetSignatureForProtoId(method_id->Proto()).c_str());
1112 const char* back_descriptor = method_id->Class()->GetStringId()->Data();
1113 char* access_str = CreateAccessFlagStr(flags, kAccessForMethod);
1114
1115 if (options_.output_format_ == kOutputPlain) {
1116 fprintf(out_file_, " #%d : (in %s)\n", i, back_descriptor);
1117 fprintf(out_file_, " name : '%s'\n", name);
1118 fprintf(out_file_, " type : '%s'\n", type_descriptor);
1119 fprintf(out_file_, " access : 0x%04x (%s)\n", flags, access_str);
1120 if (code == nullptr) {
1121 fprintf(out_file_, " code : (none)\n");
1122 } else {
1123 fprintf(out_file_, " code -\n");
1124 DumpCode(header, idx, code, code->GetOffset());
1125 }
1126 if (options_.disassemble_) {
1127 fputc('\n', out_file_);
1128 }
1129 } else if (options_.output_format_ == kOutputXml) {
1130 const bool constructor = (name[0] == '<');
1131
1132 // Method name and prototype.
1133 if (constructor) {
1134 std::string dot(DescriptorClassToDot(back_descriptor));
1135 fprintf(out_file_, "<constructor name=\"%s\"\n", dot.c_str());
Jeff Haoc3acfc52016-08-29 14:18:26 -07001136 dot = DescriptorToDotWrapper(back_descriptor);
David Sehr7629f602016-08-07 16:01:51 -07001137 fprintf(out_file_, " type=\"%s\"\n", dot.c_str());
1138 } else {
1139 fprintf(out_file_, "<method name=\"%s\"\n", name);
1140 const char* return_type = strrchr(type_descriptor, ')');
1141 if (return_type == nullptr) {
1142 fprintf(stderr, "bad method type descriptor '%s'\n", type_descriptor);
1143 goto bail;
1144 }
Jeff Haoc3acfc52016-08-29 14:18:26 -07001145 std::string dot(DescriptorToDotWrapper(return_type + 1));
David Sehr7629f602016-08-07 16:01:51 -07001146 fprintf(out_file_, " return=\"%s\"\n", dot.c_str());
1147 fprintf(out_file_, " abstract=%s\n", QuotedBool((flags & kAccAbstract) != 0));
1148 fprintf(out_file_, " native=%s\n", QuotedBool((flags & kAccNative) != 0));
1149 fprintf(out_file_, " synchronized=%s\n", QuotedBool(
1150 (flags & (kAccSynchronized | kAccDeclaredSynchronized)) != 0));
1151 }
1152
1153 // Additional method flags.
1154 fprintf(out_file_, " static=%s\n", QuotedBool((flags & kAccStatic) != 0));
1155 fprintf(out_file_, " final=%s\n", QuotedBool((flags & kAccFinal) != 0));
1156 // The "deprecated=" not knowable w/o parsing annotations.
1157 fprintf(out_file_, " visibility=%s\n>\n", QuotedVisibility(flags));
1158
1159 // Parameters.
1160 if (type_descriptor[0] != '(') {
1161 fprintf(stderr, "ERROR: bad descriptor '%s'\n", type_descriptor);
1162 goto bail;
1163 }
1164 char* tmp_buf = reinterpret_cast<char*>(malloc(strlen(type_descriptor) + 1));
1165 const char* base = type_descriptor + 1;
1166 int arg_num = 0;
1167 while (*base != ')') {
1168 char* cp = tmp_buf;
1169 while (*base == '[') {
1170 *cp++ = *base++;
1171 }
1172 if (*base == 'L') {
1173 // Copy through ';'.
1174 do {
1175 *cp = *base++;
1176 } while (*cp++ != ';');
1177 } else {
1178 // Primitive char, copy it.
1179 if (strchr("ZBCSIFJD", *base) == nullptr) {
1180 fprintf(stderr, "ERROR: bad method signature '%s'\n", base);
1181 break; // while
1182 }
1183 *cp++ = *base++;
1184 }
1185 // Null terminate and display.
1186 *cp++ = '\0';
Jeff Haoc3acfc52016-08-29 14:18:26 -07001187 std::string dot(DescriptorToDotWrapper(tmp_buf));
David Sehr7629f602016-08-07 16:01:51 -07001188 fprintf(out_file_, "<parameter name=\"arg%d\" type=\"%s\">\n"
1189 "</parameter>\n", arg_num++, dot.c_str());
1190 } // while
1191 free(tmp_buf);
1192 if (constructor) {
1193 fprintf(out_file_, "</constructor>\n");
1194 } else {
1195 fprintf(out_file_, "</method>\n");
1196 }
1197 }
1198
1199 bail:
1200 free(type_descriptor);
1201 free(access_str);
1202}
1203
1204/*
1205 * Dumps a static (class) field.
1206 */
1207static void DumpSField(dex_ir::Header* header, uint32_t idx, uint32_t flags,
Jeff Hao3ab96b42016-09-09 18:35:01 -07001208 int i, dex_ir::EncodedValue* init) {
David Sehr7629f602016-08-07 16:01:51 -07001209 // Bail for anything private if export only requested.
1210 if (options_.exports_only_ && (flags & (kAccPublic | kAccProtected)) == 0) {
1211 return;
1212 }
1213
Jeff Hao3ab96b42016-09-09 18:35:01 -07001214 dex_ir::FieldId* field_id = header->GetCollections().GetFieldId(idx);
David Sehr7629f602016-08-07 16:01:51 -07001215 const char* name = field_id->Name()->Data();
1216 const char* type_descriptor = field_id->Type()->GetStringId()->Data();
1217 const char* back_descriptor = field_id->Class()->GetStringId()->Data();
1218 char* access_str = CreateAccessFlagStr(flags, kAccessForField);
1219
1220 if (options_.output_format_ == kOutputPlain) {
1221 fprintf(out_file_, " #%d : (in %s)\n", i, back_descriptor);
1222 fprintf(out_file_, " name : '%s'\n", name);
1223 fprintf(out_file_, " type : '%s'\n", type_descriptor);
1224 fprintf(out_file_, " access : 0x%04x (%s)\n", flags, access_str);
1225 if (init != nullptr) {
1226 fputs(" value : ", out_file_);
1227 DumpEncodedValue(init);
1228 fputs("\n", out_file_);
1229 }
1230 } else if (options_.output_format_ == kOutputXml) {
1231 fprintf(out_file_, "<field name=\"%s\"\n", name);
Jeff Haoc3acfc52016-08-29 14:18:26 -07001232 std::string dot(DescriptorToDotWrapper(type_descriptor));
David Sehr7629f602016-08-07 16:01:51 -07001233 fprintf(out_file_, " type=\"%s\"\n", dot.c_str());
1234 fprintf(out_file_, " transient=%s\n", QuotedBool((flags & kAccTransient) != 0));
1235 fprintf(out_file_, " volatile=%s\n", QuotedBool((flags & kAccVolatile) != 0));
1236 // The "value=" is not knowable w/o parsing annotations.
1237 fprintf(out_file_, " static=%s\n", QuotedBool((flags & kAccStatic) != 0));
1238 fprintf(out_file_, " final=%s\n", QuotedBool((flags & kAccFinal) != 0));
1239 // The "deprecated=" is not knowable w/o parsing annotations.
1240 fprintf(out_file_, " visibility=%s\n", QuotedVisibility(flags));
1241 if (init != nullptr) {
1242 fputs(" value=\"", out_file_);
1243 DumpEncodedValue(init);
1244 fputs("\"\n", out_file_);
1245 }
1246 fputs(">\n</field>\n", out_file_);
1247 }
1248
1249 free(access_str);
1250}
1251
1252/*
1253 * Dumps an instance field.
1254 */
1255static void DumpIField(dex_ir::Header* header, uint32_t idx, uint32_t flags, int i) {
1256 DumpSField(header, idx, flags, i, nullptr);
1257}
1258
1259/*
1260 * Dumping a CFG. Note that this will do duplicate work. utils.h doesn't expose the code-item
1261 * version, so the DumpMethodCFG code will have to iterate again to find it. But dexdump is a
1262 * tool, so this is not performance-critical.
1263 */
1264
1265static void DumpCFG(const DexFile* dex_file,
1266 uint32_t dex_method_idx,
1267 const DexFile::CodeItem* code) {
1268 if (code != nullptr) {
1269 std::ostringstream oss;
1270 DumpMethodCFG(dex_file, dex_method_idx, oss);
1271 fprintf(out_file_, "%s", oss.str().c_str());
1272 }
1273}
1274
1275static void DumpCFG(const DexFile* dex_file, int idx) {
1276 const DexFile::ClassDef& class_def = dex_file->GetClassDef(idx);
1277 const uint8_t* class_data = dex_file->GetClassData(class_def);
1278 if (class_data == nullptr) { // empty class such as a marker interface?
1279 return;
1280 }
1281 ClassDataItemIterator it(*dex_file, class_data);
1282 while (it.HasNextStaticField()) {
1283 it.Next();
1284 }
1285 while (it.HasNextInstanceField()) {
1286 it.Next();
1287 }
1288 while (it.HasNextDirectMethod()) {
1289 DumpCFG(dex_file,
1290 it.GetMemberIndex(),
1291 it.GetMethodCodeItem());
1292 it.Next();
1293 }
1294 while (it.HasNextVirtualMethod()) {
1295 DumpCFG(dex_file,
David Sehr853a8e12016-09-01 13:03:50 -07001296 it.GetMemberIndex(),
1297 it.GetMethodCodeItem());
David Sehr7629f602016-08-07 16:01:51 -07001298 it.Next();
1299 }
1300}
1301
1302/*
1303 * Dumps the class.
1304 *
1305 * Note "idx" is a DexClassDef index, not a DexTypeId index.
1306 *
1307 * If "*last_package" is nullptr or does not match the current class' package,
1308 * the value will be replaced with a newly-allocated string.
1309 */
David Sehr853a8e12016-09-01 13:03:50 -07001310static void DumpClass(const DexFile* dex_file,
1311 dex_ir::Header* header,
1312 int idx,
1313 char** last_package) {
Jeff Hao3ab96b42016-09-09 18:35:01 -07001314 dex_ir::ClassDef* class_def = header->GetCollections().GetClassDef(idx);
David Sehr7629f602016-08-07 16:01:51 -07001315 // Omitting non-public class.
1316 if (options_.exports_only_ && (class_def->GetAccessFlags() & kAccPublic) == 0) {
1317 return;
1318 }
1319
1320 if (options_.show_section_headers_) {
1321 DumpClassDef(header, idx);
1322 }
1323
1324 if (options_.show_annotations_) {
1325 DumpClassAnnotations(header, idx);
1326 }
1327
1328 if (options_.show_cfg_) {
David Sehr853a8e12016-09-01 13:03:50 -07001329 DumpCFG(dex_file, idx);
David Sehr7629f602016-08-07 16:01:51 -07001330 return;
1331 }
1332
1333 // For the XML output, show the package name. Ideally we'd gather
1334 // up the classes, sort them, and dump them alphabetically so the
1335 // package name wouldn't jump around, but that's not a great plan
1336 // for something that needs to run on the device.
Jeff Hao3ab96b42016-09-09 18:35:01 -07001337 const char* class_descriptor =
1338 header->GetCollections().GetClassDef(idx)->ClassType()->GetStringId()->Data();
David Sehr7629f602016-08-07 16:01:51 -07001339 if (!(class_descriptor[0] == 'L' &&
1340 class_descriptor[strlen(class_descriptor)-1] == ';')) {
1341 // Arrays and primitives should not be defined explicitly. Keep going?
1342 fprintf(stderr, "Malformed class name '%s'\n", class_descriptor);
1343 } else if (options_.output_format_ == kOutputXml) {
1344 char* mangle = strdup(class_descriptor + 1);
1345 mangle[strlen(mangle)-1] = '\0';
1346
1347 // Reduce to just the package name.
1348 char* last_slash = strrchr(mangle, '/');
1349 if (last_slash != nullptr) {
1350 *last_slash = '\0';
1351 } else {
1352 *mangle = '\0';
1353 }
1354
1355 for (char* cp = mangle; *cp != '\0'; cp++) {
1356 if (*cp == '/') {
1357 *cp = '.';
1358 }
1359 } // for
1360
1361 if (*last_package == nullptr || strcmp(mangle, *last_package) != 0) {
1362 // Start of a new package.
1363 if (*last_package != nullptr) {
1364 fprintf(out_file_, "</package>\n");
1365 }
1366 fprintf(out_file_, "<package name=\"%s\"\n>\n", mangle);
1367 free(*last_package);
1368 *last_package = mangle;
1369 } else {
1370 free(mangle);
1371 }
1372 }
1373
1374 // General class information.
1375 char* access_str = CreateAccessFlagStr(class_def->GetAccessFlags(), kAccessForClass);
1376 const char* superclass_descriptor = nullptr;
1377 if (class_def->Superclass() != nullptr) {
1378 superclass_descriptor = class_def->Superclass()->GetStringId()->Data();
1379 }
1380 if (options_.output_format_ == kOutputPlain) {
1381 fprintf(out_file_, "Class #%d -\n", idx);
1382 fprintf(out_file_, " Class descriptor : '%s'\n", class_descriptor);
1383 fprintf(out_file_, " Access flags : 0x%04x (%s)\n",
1384 class_def->GetAccessFlags(), access_str);
1385 if (superclass_descriptor != nullptr) {
1386 fprintf(out_file_, " Superclass : '%s'\n", superclass_descriptor);
1387 }
1388 fprintf(out_file_, " Interfaces -\n");
1389 } else {
1390 std::string dot(DescriptorClassToDot(class_descriptor));
1391 fprintf(out_file_, "<class name=\"%s\"\n", dot.c_str());
1392 if (superclass_descriptor != nullptr) {
Jeff Haoc3acfc52016-08-29 14:18:26 -07001393 dot = DescriptorToDotWrapper(superclass_descriptor);
David Sehr7629f602016-08-07 16:01:51 -07001394 fprintf(out_file_, " extends=\"%s\"\n", dot.c_str());
1395 }
1396 fprintf(out_file_, " interface=%s\n",
1397 QuotedBool((class_def->GetAccessFlags() & kAccInterface) != 0));
1398 fprintf(out_file_, " abstract=%s\n",
1399 QuotedBool((class_def->GetAccessFlags() & kAccAbstract) != 0));
1400 fprintf(out_file_, " static=%s\n", QuotedBool((class_def->GetAccessFlags() & kAccStatic) != 0));
1401 fprintf(out_file_, " final=%s\n", QuotedBool((class_def->GetAccessFlags() & kAccFinal) != 0));
1402 // The "deprecated=" not knowable w/o parsing annotations.
1403 fprintf(out_file_, " visibility=%s\n", QuotedVisibility(class_def->GetAccessFlags()));
1404 fprintf(out_file_, ">\n");
1405 }
1406
1407 // Interfaces.
Jeff Hao3ab96b42016-09-09 18:35:01 -07001408 const dex_ir::TypeIdVector* interfaces = class_def->Interfaces();
David Sehr853a8e12016-09-01 13:03:50 -07001409 if (interfaces != nullptr) {
1410 for (uint32_t i = 0; i < interfaces->size(); i++) {
1411 DumpInterface((*interfaces)[i], i);
1412 } // for
1413 }
David Sehr7629f602016-08-07 16:01:51 -07001414
1415 // Fields and methods.
1416 dex_ir::ClassData* class_data = class_def->GetClassData();
1417 // Prepare data for static fields.
Jeff Hao3ab96b42016-09-09 18:35:01 -07001418 dex_ir::EncodedArrayItem* static_values = class_def->StaticValues();
1419 dex_ir::EncodedValueVector* encoded_values =
1420 static_values == nullptr ? nullptr : static_values->GetEncodedValues();
1421 const uint32_t encoded_values_size = (encoded_values == nullptr) ? 0 : encoded_values->size();
David Sehr7629f602016-08-07 16:01:51 -07001422
1423 // Static fields.
1424 if (options_.output_format_ == kOutputPlain) {
1425 fprintf(out_file_, " Static fields -\n");
1426 }
David Sehr853a8e12016-09-01 13:03:50 -07001427 if (class_data != nullptr) {
1428 dex_ir::FieldItemVector* static_fields = class_data->StaticFields();
1429 if (static_fields != nullptr) {
1430 for (uint32_t i = 0; i < static_fields->size(); i++) {
1431 DumpSField(header,
Jeff Hao3ab96b42016-09-09 18:35:01 -07001432 (*static_fields)[i]->GetFieldId()->GetIndex(),
David Sehr853a8e12016-09-01 13:03:50 -07001433 (*static_fields)[i]->GetAccessFlags(),
1434 i,
Jeff Hao3ab96b42016-09-09 18:35:01 -07001435 i < encoded_values_size ? (*encoded_values)[i].get() : nullptr);
David Sehr853a8e12016-09-01 13:03:50 -07001436 } // for
1437 }
1438 }
David Sehr7629f602016-08-07 16:01:51 -07001439
1440 // Instance fields.
1441 if (options_.output_format_ == kOutputPlain) {
1442 fprintf(out_file_, " Instance fields -\n");
1443 }
David Sehr853a8e12016-09-01 13:03:50 -07001444 if (class_data != nullptr) {
1445 dex_ir::FieldItemVector* instance_fields = class_data->InstanceFields();
1446 if (instance_fields != nullptr) {
1447 for (uint32_t i = 0; i < instance_fields->size(); i++) {
1448 DumpIField(header,
Jeff Hao3ab96b42016-09-09 18:35:01 -07001449 (*instance_fields)[i]->GetFieldId()->GetIndex(),
David Sehr853a8e12016-09-01 13:03:50 -07001450 (*instance_fields)[i]->GetAccessFlags(),
1451 i);
1452 } // for
1453 }
1454 }
David Sehr7629f602016-08-07 16:01:51 -07001455
1456 // Direct methods.
1457 if (options_.output_format_ == kOutputPlain) {
1458 fprintf(out_file_, " Direct methods -\n");
1459 }
David Sehr853a8e12016-09-01 13:03:50 -07001460 if (class_data != nullptr) {
1461 dex_ir::MethodItemVector* direct_methods = class_data->DirectMethods();
1462 if (direct_methods != nullptr) {
1463 for (uint32_t i = 0; i < direct_methods->size(); i++) {
1464 DumpMethod(header,
Jeff Hao3ab96b42016-09-09 18:35:01 -07001465 (*direct_methods)[i]->GetMethodId()->GetIndex(),
David Sehr853a8e12016-09-01 13:03:50 -07001466 (*direct_methods)[i]->GetAccessFlags(),
1467 (*direct_methods)[i]->GetCodeItem(),
1468 i);
1469 } // for
1470 }
1471 }
David Sehr7629f602016-08-07 16:01:51 -07001472
1473 // Virtual methods.
1474 if (options_.output_format_ == kOutputPlain) {
1475 fprintf(out_file_, " Virtual methods -\n");
1476 }
David Sehr853a8e12016-09-01 13:03:50 -07001477 if (class_data != nullptr) {
1478 dex_ir::MethodItemVector* virtual_methods = class_data->VirtualMethods();
1479 if (virtual_methods != nullptr) {
1480 for (uint32_t i = 0; i < virtual_methods->size(); i++) {
1481 DumpMethod(header,
Jeff Hao3ab96b42016-09-09 18:35:01 -07001482 (*virtual_methods)[i]->GetMethodId()->GetIndex(),
David Sehr853a8e12016-09-01 13:03:50 -07001483 (*virtual_methods)[i]->GetAccessFlags(),
1484 (*virtual_methods)[i]->GetCodeItem(),
1485 i);
1486 } // for
1487 }
1488 }
David Sehr7629f602016-08-07 16:01:51 -07001489
1490 // End of class.
1491 if (options_.output_format_ == kOutputPlain) {
1492 const char* file_name = "unknown";
1493 if (class_def->SourceFile() != nullptr) {
1494 file_name = class_def->SourceFile()->Data();
1495 }
1496 const dex_ir::StringId* source_file = class_def->SourceFile();
1497 fprintf(out_file_, " source_file_idx : %d (%s)\n\n",
Jeff Hao3ab96b42016-09-09 18:35:01 -07001498 source_file == nullptr ? 0xffffffffU : source_file->GetIndex(), file_name);
David Sehr7629f602016-08-07 16:01:51 -07001499 } else if (options_.output_format_ == kOutputXml) {
1500 fprintf(out_file_, "</class>\n");
1501 }
1502
1503 free(access_str);
1504}
1505
1506/*
1507 * Dumps the requested sections of the file.
1508 */
David Sehrcdcfde72016-09-26 07:44:04 -07001509static void ProcessDexFile(const char* file_name, const DexFile* dex_file, size_t dex_file_index) {
David Sehr7629f602016-08-07 16:01:51 -07001510 if (options_.verbose_) {
1511 fprintf(out_file_, "Opened '%s', DEX version '%.3s'\n",
1512 file_name, dex_file->GetHeader().magic_ + 4);
1513 }
David Sehr72359222016-09-07 13:04:01 -07001514 std::unique_ptr<dex_ir::Header> header(dex_ir::DexIrBuilder(*dex_file));
David Sehr7629f602016-08-07 16:01:51 -07001515
David Sehrcdcfde72016-09-26 07:44:04 -07001516 if (options_.visualize_pattern_) {
1517 VisualizeDexLayout(header.get(), dex_file, dex_file_index);
1518 return;
1519 }
1520
David Sehr7629f602016-08-07 16:01:51 -07001521 // Headers.
1522 if (options_.show_file_headers_) {
David Sehr72359222016-09-07 13:04:01 -07001523 DumpFileHeader(header.get());
David Sehr7629f602016-08-07 16:01:51 -07001524 }
1525
1526 // Open XML context.
1527 if (options_.output_format_ == kOutputXml) {
1528 fprintf(out_file_, "<api>\n");
1529 }
1530
1531 // Iterate over all classes.
1532 char* package = nullptr;
Jeff Hao3ab96b42016-09-09 18:35:01 -07001533 const uint32_t class_defs_size = header->GetCollections().ClassDefsSize();
David Sehr7629f602016-08-07 16:01:51 -07001534 for (uint32_t i = 0; i < class_defs_size; i++) {
David Sehr72359222016-09-07 13:04:01 -07001535 DumpClass(dex_file, header.get(), i, &package);
David Sehr7629f602016-08-07 16:01:51 -07001536 } // for
1537
1538 // Free the last package allocated.
1539 if (package != nullptr) {
1540 fprintf(out_file_, "</package>\n");
1541 free(package);
1542 }
1543
1544 // Close XML context.
1545 if (options_.output_format_ == kOutputXml) {
1546 fprintf(out_file_, "</api>\n");
1547 }
Jeff Hao3ab96b42016-09-09 18:35:01 -07001548
Jeff Hao3ab96b42016-09-09 18:35:01 -07001549 // Output dex file.
Jeff Haoa8621002016-10-04 18:13:44 +00001550 if (options_.output_dex_directory_ != nullptr) {
1551 std::string output_location(options_.output_dex_directory_);
1552 size_t last_slash = dex_file->GetLocation().rfind("/");
1553 output_location.append(dex_file->GetLocation().substr(last_slash));
1554 DexWriter::OutputDexFile(*header, output_location.c_str());
Jeff Hao3ab96b42016-09-09 18:35:01 -07001555 }
David Sehr7629f602016-08-07 16:01:51 -07001556}
1557
1558/*
1559 * Processes a single file (either direct .dex or indirect .zip/.jar/.apk).
1560 */
1561int ProcessFile(const char* file_name) {
1562 if (options_.verbose_) {
1563 fprintf(out_file_, "Processing '%s'...\n", file_name);
1564 }
1565
1566 // If the file is not a .dex file, the function tries .zip/.jar/.apk files,
1567 // all of which are Zip archives with "classes.dex" inside.
1568 const bool verify_checksum = !options_.ignore_bad_checksum_;
1569 std::string error_msg;
1570 std::vector<std::unique_ptr<const DexFile>> dex_files;
1571 if (!DexFile::Open(file_name, file_name, verify_checksum, &error_msg, &dex_files)) {
1572 // Display returned error message to user. Note that this error behavior
1573 // differs from the error messages shown by the original Dalvik dexdump.
1574 fputs(error_msg.c_str(), stderr);
1575 fputc('\n', stderr);
1576 return -1;
1577 }
1578
1579 // Success. Either report checksum verification or process
1580 // all dex files found in given file.
1581 if (options_.checksum_only_) {
1582 fprintf(out_file_, "Checksum verified\n");
1583 } else {
1584 for (size_t i = 0; i < dex_files.size(); i++) {
David Sehrcdcfde72016-09-26 07:44:04 -07001585 ProcessDexFile(file_name, dex_files[i].get(), i);
David Sehr7629f602016-08-07 16:01:51 -07001586 }
1587 }
1588 return 0;
1589}
1590
1591} // namespace art