blob: 2b30a1be08b057278b2c210c0b95bf63e7d5c4e8 [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
Orion Hodsonb34bb192016-10-18 17:02:58 +010033#include "base/stringprintf.h"
David Sehr853a8e12016-09-01 13:03:50 -070034#include "dex_ir_builder.h"
David Sehr7629f602016-08-07 16:01:51 -070035#include "dex_file-inl.h"
36#include "dex_instruction-inl.h"
David Sehrcdcfde72016-09-26 07:44:04 -070037#include "dex_visualize.h"
Jeff Haoa8621002016-10-04 18:13:44 +000038#include "dex_writer.h"
David Sehrcdcfde72016-09-26 07:44:04 -070039#include "jit/offline_profiling_info.h"
Nicolas Geoffrayfd1a6c22016-10-04 11:01:17 +000040#include "os.h"
David Sehr7629f602016-08-07 16:01:51 -070041#include "utils.h"
42
43namespace art {
44
45/*
46 * Options parsed in main driver.
47 */
48struct Options options_;
49
50/*
51 * Output file. Defaults to stdout.
52 */
53FILE* out_file_ = stdout;
54
55/*
David Sehrcdcfde72016-09-26 07:44:04 -070056 * Profile information file.
57 */
58ProfileCompilationInfo* profile_info_ = nullptr;
59
60/*
David Sehr7629f602016-08-07 16:01:51 -070061 * Flags for use with createAccessFlagStr().
62 */
63enum AccessFor {
64 kAccessForClass = 0, kAccessForMethod = 1, kAccessForField = 2, kAccessForMAX
65};
66const int kNumFlags = 18;
67
68/*
69 * Gets 2 little-endian bytes.
70 */
71static inline uint16_t Get2LE(unsigned char const* src) {
72 return src[0] | (src[1] << 8);
73}
74
75/*
Jeff Haoc3acfc52016-08-29 14:18:26 -070076 * Converts a type descriptor to human-readable "dotted" form. For
77 * example, "Ljava/lang/String;" becomes "java.lang.String", and
78 * "[I" becomes "int[]". Also converts '$' to '.', which means this
79 * form can't be converted back to a descriptor.
80 */
81static std::string DescriptorToDotWrapper(const char* descriptor) {
82 std::string result = DescriptorToDot(descriptor);
83 size_t found = result.find('$');
84 while (found != std::string::npos) {
85 result[found] = '.';
86 found = result.find('$', found);
87 }
88 return result;
89}
90
91/*
David Sehr7629f602016-08-07 16:01:51 -070092 * Converts the class name portion of a type descriptor to human-readable
93 * "dotted" form. For example, "Ljava/lang/String;" becomes "String".
94 */
95static std::string DescriptorClassToDot(const char* str) {
96 std::string descriptor(str);
97 // Reduce to just the class name prefix.
98 size_t last_slash = descriptor.rfind('/');
99 if (last_slash == std::string::npos) {
100 last_slash = 0;
101 }
102 // Start past the '/' or 'L'.
103 last_slash++;
104
105 // Copy class name over, trimming trailing ';'.
106 size_t size = descriptor.size() - 1 - last_slash;
107 std::string result(descriptor.substr(last_slash, size));
108
109 // Replace '$' with '.'.
110 size_t dollar_sign = result.find('$');
111 while (dollar_sign != std::string::npos) {
112 result[dollar_sign] = '.';
113 dollar_sign = result.find('$', dollar_sign);
114 }
115
116 return result;
117}
118
119/*
120 * Returns string representing the boolean value.
121 */
122static const char* StrBool(bool val) {
123 return val ? "true" : "false";
124}
125
126/*
127 * Returns a quoted string representing the boolean value.
128 */
129static const char* QuotedBool(bool val) {
130 return val ? "\"true\"" : "\"false\"";
131}
132
133/*
134 * Returns a quoted string representing the access flags.
135 */
136static const char* QuotedVisibility(uint32_t access_flags) {
137 if (access_flags & kAccPublic) {
138 return "\"public\"";
139 } else if (access_flags & kAccProtected) {
140 return "\"protected\"";
141 } else if (access_flags & kAccPrivate) {
142 return "\"private\"";
143 } else {
144 return "\"package\"";
145 }
146}
147
148/*
149 * Counts the number of '1' bits in a word.
150 */
151static int CountOnes(uint32_t val) {
152 val = val - ((val >> 1) & 0x55555555);
153 val = (val & 0x33333333) + ((val >> 2) & 0x33333333);
154 return (((val + (val >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24;
155}
156
157/*
158 * Creates a new string with human-readable access flags.
159 *
160 * In the base language the access_flags fields are type uint16_t; in Dalvik they're uint32_t.
161 */
162static char* CreateAccessFlagStr(uint32_t flags, AccessFor for_what) {
163 static const char* kAccessStrings[kAccessForMAX][kNumFlags] = {
164 {
165 "PUBLIC", /* 0x00001 */
166 "PRIVATE", /* 0x00002 */
167 "PROTECTED", /* 0x00004 */
168 "STATIC", /* 0x00008 */
169 "FINAL", /* 0x00010 */
170 "?", /* 0x00020 */
171 "?", /* 0x00040 */
172 "?", /* 0x00080 */
173 "?", /* 0x00100 */
174 "INTERFACE", /* 0x00200 */
175 "ABSTRACT", /* 0x00400 */
176 "?", /* 0x00800 */
177 "SYNTHETIC", /* 0x01000 */
178 "ANNOTATION", /* 0x02000 */
179 "ENUM", /* 0x04000 */
180 "?", /* 0x08000 */
181 "VERIFIED", /* 0x10000 */
182 "OPTIMIZED", /* 0x20000 */
183 }, {
184 "PUBLIC", /* 0x00001 */
185 "PRIVATE", /* 0x00002 */
186 "PROTECTED", /* 0x00004 */
187 "STATIC", /* 0x00008 */
188 "FINAL", /* 0x00010 */
189 "SYNCHRONIZED", /* 0x00020 */
190 "BRIDGE", /* 0x00040 */
191 "VARARGS", /* 0x00080 */
192 "NATIVE", /* 0x00100 */
193 "?", /* 0x00200 */
194 "ABSTRACT", /* 0x00400 */
195 "STRICT", /* 0x00800 */
196 "SYNTHETIC", /* 0x01000 */
197 "?", /* 0x02000 */
198 "?", /* 0x04000 */
199 "MIRANDA", /* 0x08000 */
200 "CONSTRUCTOR", /* 0x10000 */
201 "DECLARED_SYNCHRONIZED", /* 0x20000 */
202 }, {
203 "PUBLIC", /* 0x00001 */
204 "PRIVATE", /* 0x00002 */
205 "PROTECTED", /* 0x00004 */
206 "STATIC", /* 0x00008 */
207 "FINAL", /* 0x00010 */
208 "?", /* 0x00020 */
209 "VOLATILE", /* 0x00040 */
210 "TRANSIENT", /* 0x00080 */
211 "?", /* 0x00100 */
212 "?", /* 0x00200 */
213 "?", /* 0x00400 */
214 "?", /* 0x00800 */
215 "SYNTHETIC", /* 0x01000 */
216 "?", /* 0x02000 */
217 "ENUM", /* 0x04000 */
218 "?", /* 0x08000 */
219 "?", /* 0x10000 */
220 "?", /* 0x20000 */
221 },
222 };
223
224 // Allocate enough storage to hold the expected number of strings,
225 // plus a space between each. We over-allocate, using the longest
226 // string above as the base metric.
227 const int kLongest = 21; // The strlen of longest string above.
228 const int count = CountOnes(flags);
229 char* str;
230 char* cp;
231 cp = str = reinterpret_cast<char*>(malloc(count * (kLongest + 1) + 1));
232
233 for (int i = 0; i < kNumFlags; i++) {
234 if (flags & 0x01) {
235 const char* accessStr = kAccessStrings[for_what][i];
236 const int len = strlen(accessStr);
237 if (cp != str) {
238 *cp++ = ' ';
239 }
240 memcpy(cp, accessStr, len);
241 cp += len;
242 }
243 flags >>= 1;
244 } // for
245
246 *cp = '\0';
247 return str;
248}
249
250static std::string GetSignatureForProtoId(const dex_ir::ProtoId* proto) {
251 if (proto == nullptr) {
252 return "<no signature>";
253 }
254
David Sehr7629f602016-08-07 16:01:51 -0700255 std::string result("(");
Jeff Haoa8621002016-10-04 18:13:44 +0000256 const dex_ir::TypeList* type_list = proto->Parameters();
257 if (type_list != nullptr) {
258 for (const dex_ir::TypeId* type_id : *type_list->GetTypeList()) {
259 result += type_id->GetStringId()->Data();
260 }
David Sehr7629f602016-08-07 16:01:51 -0700261 }
262 result += ")";
263 result += proto->ReturnType()->GetStringId()->Data();
264 return result;
265}
266
267/*
268 * Copies character data from "data" to "out", converting non-ASCII values
269 * to fprintf format chars or an ASCII filler ('.' or '?').
270 *
271 * The output buffer must be able to hold (2*len)+1 bytes. The result is
272 * NULL-terminated.
273 */
274static void Asciify(char* out, const unsigned char* data, size_t len) {
275 while (len--) {
276 if (*data < 0x20) {
277 // Could do more here, but we don't need them yet.
278 switch (*data) {
279 case '\0':
280 *out++ = '\\';
281 *out++ = '0';
282 break;
283 case '\n':
284 *out++ = '\\';
285 *out++ = 'n';
286 break;
287 default:
288 *out++ = '.';
289 break;
290 } // switch
291 } else if (*data >= 0x80) {
292 *out++ = '?';
293 } else {
294 *out++ = *data;
295 }
296 data++;
297 } // while
298 *out = '\0';
299}
300
301/*
302 * Dumps a string value with some escape characters.
303 */
304static void DumpEscapedString(const char* p) {
305 fputs("\"", out_file_);
306 for (; *p; p++) {
307 switch (*p) {
308 case '\\':
309 fputs("\\\\", out_file_);
310 break;
311 case '\"':
312 fputs("\\\"", out_file_);
313 break;
314 case '\t':
315 fputs("\\t", out_file_);
316 break;
317 case '\n':
318 fputs("\\n", out_file_);
319 break;
320 case '\r':
321 fputs("\\r", out_file_);
322 break;
323 default:
324 putc(*p, out_file_);
325 } // switch
326 } // for
327 fputs("\"", out_file_);
328}
329
330/*
331 * Dumps a string as an XML attribute value.
332 */
333static void DumpXmlAttribute(const char* p) {
334 for (; *p; p++) {
335 switch (*p) {
336 case '&':
337 fputs("&amp;", out_file_);
338 break;
339 case '<':
340 fputs("&lt;", out_file_);
341 break;
342 case '>':
343 fputs("&gt;", out_file_);
344 break;
345 case '"':
346 fputs("&quot;", out_file_);
347 break;
348 case '\t':
349 fputs("&#x9;", out_file_);
350 break;
351 case '\n':
352 fputs("&#xA;", out_file_);
353 break;
354 case '\r':
355 fputs("&#xD;", out_file_);
356 break;
357 default:
358 putc(*p, out_file_);
359 } // switch
360 } // for
361}
362
Jeff Hao3ab96b42016-09-09 18:35:01 -0700363// Forward declare to resolve circular dependence.
364static void DumpEncodedValue(const dex_ir::EncodedValue* data);
365
366/*
367 * Dumps encoded annotation.
368 */
369static void DumpEncodedAnnotation(dex_ir::EncodedAnnotation* annotation) {
370 fputs(annotation->GetType()->GetStringId()->Data(), out_file_);
371 // Display all name=value pairs.
372 for (auto& subannotation : *annotation->GetAnnotationElements()) {
373 fputc(' ', out_file_);
374 fputs(subannotation->GetName()->Data(), out_file_);
375 fputc('=', out_file_);
376 DumpEncodedValue(subannotation->GetValue());
377 }
378}
David Sehr7629f602016-08-07 16:01:51 -0700379/*
380 * Dumps encoded value.
381 */
Jeff Hao3ab96b42016-09-09 18:35:01 -0700382static void DumpEncodedValue(const dex_ir::EncodedValue* data) {
David Sehr7629f602016-08-07 16:01:51 -0700383 switch (data->Type()) {
384 case DexFile::kDexAnnotationByte:
385 fprintf(out_file_, "%" PRId8, data->GetByte());
386 break;
387 case DexFile::kDexAnnotationShort:
388 fprintf(out_file_, "%" PRId16, data->GetShort());
389 break;
390 case DexFile::kDexAnnotationChar:
391 fprintf(out_file_, "%" PRIu16, data->GetChar());
392 break;
393 case DexFile::kDexAnnotationInt:
394 fprintf(out_file_, "%" PRId32, data->GetInt());
395 break;
396 case DexFile::kDexAnnotationLong:
397 fprintf(out_file_, "%" PRId64, data->GetLong());
398 break;
399 case DexFile::kDexAnnotationFloat: {
400 fprintf(out_file_, "%g", data->GetFloat());
401 break;
402 }
403 case DexFile::kDexAnnotationDouble: {
404 fprintf(out_file_, "%g", data->GetDouble());
405 break;
406 }
407 case DexFile::kDexAnnotationString: {
408 dex_ir::StringId* string_id = data->GetStringId();
409 if (options_.output_format_ == kOutputPlain) {
410 DumpEscapedString(string_id->Data());
411 } else {
412 DumpXmlAttribute(string_id->Data());
413 }
414 break;
415 }
416 case DexFile::kDexAnnotationType: {
Jeff Hao3ab96b42016-09-09 18:35:01 -0700417 dex_ir::TypeId* type_id = data->GetTypeId();
418 fputs(type_id->GetStringId()->Data(), out_file_);
David Sehr7629f602016-08-07 16:01:51 -0700419 break;
420 }
421 case DexFile::kDexAnnotationField:
422 case DexFile::kDexAnnotationEnum: {
423 dex_ir::FieldId* field_id = data->GetFieldId();
424 fputs(field_id->Name()->Data(), out_file_);
425 break;
426 }
427 case DexFile::kDexAnnotationMethod: {
428 dex_ir::MethodId* method_id = data->GetMethodId();
429 fputs(method_id->Name()->Data(), out_file_);
430 break;
431 }
432 case DexFile::kDexAnnotationArray: {
433 fputc('{', out_file_);
434 // Display all elements.
Jeff Hao3ab96b42016-09-09 18:35:01 -0700435 for (auto& value : *data->GetEncodedArray()->GetEncodedValues()) {
David Sehr7629f602016-08-07 16:01:51 -0700436 fputc(' ', out_file_);
Jeff Hao3ab96b42016-09-09 18:35:01 -0700437 DumpEncodedValue(value.get());
David Sehr7629f602016-08-07 16:01:51 -0700438 }
439 fputs(" }", out_file_);
440 break;
441 }
442 case DexFile::kDexAnnotationAnnotation: {
Jeff Hao3ab96b42016-09-09 18:35:01 -0700443 DumpEncodedAnnotation(data->GetEncodedAnnotation());
David Sehr7629f602016-08-07 16:01:51 -0700444 break;
445 }
446 case DexFile::kDexAnnotationNull:
447 fputs("null", out_file_);
448 break;
449 case DexFile::kDexAnnotationBoolean:
450 fputs(StrBool(data->GetBoolean()), out_file_);
451 break;
452 default:
453 fputs("????", out_file_);
454 break;
455 } // switch
456}
457
458/*
459 * Dumps the file header.
460 */
Jeff Hao3ab96b42016-09-09 18:35:01 -0700461static void DumpFileHeader(dex_ir::Header* header) {
David Sehr7629f602016-08-07 16:01:51 -0700462 char sanitized[8 * 2 + 1];
Jeff Hao3ab96b42016-09-09 18:35:01 -0700463 dex_ir::Collections& collections = header->GetCollections();
David Sehr7629f602016-08-07 16:01:51 -0700464 fprintf(out_file_, "DEX file header:\n");
465 Asciify(sanitized, header->Magic(), 8);
466 fprintf(out_file_, "magic : '%s'\n", sanitized);
467 fprintf(out_file_, "checksum : %08x\n", header->Checksum());
468 fprintf(out_file_, "signature : %02x%02x...%02x%02x\n",
469 header->Signature()[0], header->Signature()[1],
470 header->Signature()[DexFile::kSha1DigestSize - 2],
471 header->Signature()[DexFile::kSha1DigestSize - 1]);
472 fprintf(out_file_, "file_size : %d\n", header->FileSize());
473 fprintf(out_file_, "header_size : %d\n", header->HeaderSize());
474 fprintf(out_file_, "link_size : %d\n", header->LinkSize());
475 fprintf(out_file_, "link_off : %d (0x%06x)\n",
476 header->LinkOffset(), header->LinkOffset());
Jeff Hao3ab96b42016-09-09 18:35:01 -0700477 fprintf(out_file_, "string_ids_size : %d\n", collections.StringIdsSize());
David Sehr7629f602016-08-07 16:01:51 -0700478 fprintf(out_file_, "string_ids_off : %d (0x%06x)\n",
Jeff Hao3ab96b42016-09-09 18:35:01 -0700479 collections.StringIdsOffset(), collections.StringIdsOffset());
480 fprintf(out_file_, "type_ids_size : %d\n", collections.TypeIdsSize());
David Sehr7629f602016-08-07 16:01:51 -0700481 fprintf(out_file_, "type_ids_off : %d (0x%06x)\n",
Jeff Hao3ab96b42016-09-09 18:35:01 -0700482 collections.TypeIdsOffset(), collections.TypeIdsOffset());
483 fprintf(out_file_, "proto_ids_size : %d\n", collections.ProtoIdsSize());
David Sehr7629f602016-08-07 16:01:51 -0700484 fprintf(out_file_, "proto_ids_off : %d (0x%06x)\n",
Jeff Hao3ab96b42016-09-09 18:35:01 -0700485 collections.ProtoIdsOffset(), collections.ProtoIdsOffset());
486 fprintf(out_file_, "field_ids_size : %d\n", collections.FieldIdsSize());
David Sehr7629f602016-08-07 16:01:51 -0700487 fprintf(out_file_, "field_ids_off : %d (0x%06x)\n",
Jeff Hao3ab96b42016-09-09 18:35:01 -0700488 collections.FieldIdsOffset(), collections.FieldIdsOffset());
489 fprintf(out_file_, "method_ids_size : %d\n", collections.MethodIdsSize());
David Sehr7629f602016-08-07 16:01:51 -0700490 fprintf(out_file_, "method_ids_off : %d (0x%06x)\n",
Jeff Hao3ab96b42016-09-09 18:35:01 -0700491 collections.MethodIdsOffset(), collections.MethodIdsOffset());
492 fprintf(out_file_, "class_defs_size : %d\n", collections.ClassDefsSize());
David Sehr7629f602016-08-07 16:01:51 -0700493 fprintf(out_file_, "class_defs_off : %d (0x%06x)\n",
Jeff Hao3ab96b42016-09-09 18:35:01 -0700494 collections.ClassDefsOffset(), collections.ClassDefsOffset());
David Sehr7629f602016-08-07 16:01:51 -0700495 fprintf(out_file_, "data_size : %d\n", header->DataSize());
496 fprintf(out_file_, "data_off : %d (0x%06x)\n\n",
497 header->DataOffset(), header->DataOffset());
498}
499
500/*
501 * Dumps a class_def_item.
502 */
503static void DumpClassDef(dex_ir::Header* header, int idx) {
504 // General class information.
Jeff Hao3ab96b42016-09-09 18:35:01 -0700505 dex_ir::ClassDef* class_def = header->GetCollections().GetClassDef(idx);
David Sehr7629f602016-08-07 16:01:51 -0700506 fprintf(out_file_, "Class #%d header:\n", idx);
Jeff Hao3ab96b42016-09-09 18:35:01 -0700507 fprintf(out_file_, "class_idx : %d\n", class_def->ClassType()->GetIndex());
David Sehr7629f602016-08-07 16:01:51 -0700508 fprintf(out_file_, "access_flags : %d (0x%04x)\n",
509 class_def->GetAccessFlags(), class_def->GetAccessFlags());
Jeff Haoc3acfc52016-08-29 14:18:26 -0700510 uint32_t superclass_idx = class_def->Superclass() == nullptr ?
Jeff Hao3ab96b42016-09-09 18:35:01 -0700511 DexFile::kDexNoIndex16 : class_def->Superclass()->GetIndex();
Jeff Haoc3acfc52016-08-29 14:18:26 -0700512 fprintf(out_file_, "superclass_idx : %d\n", superclass_idx);
David Sehr7629f602016-08-07 16:01:51 -0700513 fprintf(out_file_, "interfaces_off : %d (0x%06x)\n",
514 class_def->InterfacesOffset(), class_def->InterfacesOffset());
515 uint32_t source_file_offset = 0xffffffffU;
516 if (class_def->SourceFile() != nullptr) {
Jeff Hao3ab96b42016-09-09 18:35:01 -0700517 source_file_offset = class_def->SourceFile()->GetIndex();
David Sehr7629f602016-08-07 16:01:51 -0700518 }
519 fprintf(out_file_, "source_file_idx : %d\n", source_file_offset);
520 uint32_t annotations_offset = 0;
521 if (class_def->Annotations() != nullptr) {
522 annotations_offset = class_def->Annotations()->GetOffset();
523 }
524 fprintf(out_file_, "annotations_off : %d (0x%06x)\n",
525 annotations_offset, annotations_offset);
David Sehr853a8e12016-09-01 13:03:50 -0700526 if (class_def->GetClassData() == nullptr) {
527 fprintf(out_file_, "class_data_off : %d (0x%06x)\n", 0, 0);
528 } else {
529 fprintf(out_file_, "class_data_off : %d (0x%06x)\n",
530 class_def->GetClassData()->GetOffset(), class_def->GetClassData()->GetOffset());
531 }
David Sehr7629f602016-08-07 16:01:51 -0700532
533 // Fields and methods.
534 dex_ir::ClassData* class_data = class_def->GetClassData();
David Sehr853a8e12016-09-01 13:03:50 -0700535 if (class_data != nullptr && class_data->StaticFields() != nullptr) {
536 fprintf(out_file_, "static_fields_size : %zu\n", class_data->StaticFields()->size());
David Sehr7629f602016-08-07 16:01:51 -0700537 } else {
538 fprintf(out_file_, "static_fields_size : 0\n");
David Sehr853a8e12016-09-01 13:03:50 -0700539 }
540 if (class_data != nullptr && class_data->InstanceFields() != nullptr) {
541 fprintf(out_file_, "instance_fields_size: %zu\n", class_data->InstanceFields()->size());
542 } else {
David Sehr7629f602016-08-07 16:01:51 -0700543 fprintf(out_file_, "instance_fields_size: 0\n");
David Sehr853a8e12016-09-01 13:03:50 -0700544 }
545 if (class_data != nullptr && class_data->DirectMethods() != nullptr) {
546 fprintf(out_file_, "direct_methods_size : %zu\n", class_data->DirectMethods()->size());
547 } else {
David Sehr7629f602016-08-07 16:01:51 -0700548 fprintf(out_file_, "direct_methods_size : 0\n");
David Sehr853a8e12016-09-01 13:03:50 -0700549 }
550 if (class_data != nullptr && class_data->VirtualMethods() != nullptr) {
551 fprintf(out_file_, "virtual_methods_size: %zu\n", class_data->VirtualMethods()->size());
552 } else {
David Sehr7629f602016-08-07 16:01:51 -0700553 fprintf(out_file_, "virtual_methods_size: 0\n");
554 }
555 fprintf(out_file_, "\n");
556}
557
558/**
559 * Dumps an annotation set item.
560 */
561static void DumpAnnotationSetItem(dex_ir::AnnotationSetItem* set_item) {
David Sehr853a8e12016-09-01 13:03:50 -0700562 if (set_item == nullptr || set_item->GetItems()->size() == 0) {
David Sehr7629f602016-08-07 16:01:51 -0700563 fputs(" empty-annotation-set\n", out_file_);
564 return;
565 }
Jeff Hao3ab96b42016-09-09 18:35:01 -0700566 for (dex_ir::AnnotationItem* annotation : *set_item->GetItems()) {
David Sehr7629f602016-08-07 16:01:51 -0700567 if (annotation == nullptr) {
568 continue;
569 }
570 fputs(" ", out_file_);
571 switch (annotation->GetVisibility()) {
572 case DexFile::kDexVisibilityBuild: fputs("VISIBILITY_BUILD ", out_file_); break;
573 case DexFile::kDexVisibilityRuntime: fputs("VISIBILITY_RUNTIME ", out_file_); break;
574 case DexFile::kDexVisibilitySystem: fputs("VISIBILITY_SYSTEM ", out_file_); break;
575 default: fputs("VISIBILITY_UNKNOWN ", out_file_); break;
576 } // switch
Jeff Hao3ab96b42016-09-09 18:35:01 -0700577 DumpEncodedAnnotation(annotation->GetAnnotation());
David Sehr7629f602016-08-07 16:01:51 -0700578 fputc('\n', out_file_);
579 }
580}
581
582/*
583 * Dumps class annotations.
584 */
585static void DumpClassAnnotations(dex_ir::Header* header, int idx) {
Jeff Hao3ab96b42016-09-09 18:35:01 -0700586 dex_ir::ClassDef* class_def = header->GetCollections().GetClassDef(idx);
David Sehr7629f602016-08-07 16:01:51 -0700587 dex_ir::AnnotationsDirectoryItem* annotations_directory = class_def->Annotations();
588 if (annotations_directory == nullptr) {
589 return; // none
590 }
591
592 fprintf(out_file_, "Class #%d annotations:\n", idx);
593
594 dex_ir::AnnotationSetItem* class_set_item = annotations_directory->GetClassAnnotation();
David Sehr853a8e12016-09-01 13:03:50 -0700595 dex_ir::FieldAnnotationVector* fields = annotations_directory->GetFieldAnnotations();
596 dex_ir::MethodAnnotationVector* methods = annotations_directory->GetMethodAnnotations();
597 dex_ir::ParameterAnnotationVector* parameters = annotations_directory->GetParameterAnnotations();
David Sehr7629f602016-08-07 16:01:51 -0700598
599 // Annotations on the class itself.
600 if (class_set_item != nullptr) {
601 fprintf(out_file_, "Annotations on class\n");
602 DumpAnnotationSetItem(class_set_item);
603 }
604
605 // Annotations on fields.
David Sehr853a8e12016-09-01 13:03:50 -0700606 if (fields != nullptr) {
607 for (auto& field : *fields) {
608 const dex_ir::FieldId* field_id = field->GetFieldId();
Jeff Hao3ab96b42016-09-09 18:35:01 -0700609 const uint32_t field_idx = field_id->GetIndex();
David Sehr853a8e12016-09-01 13:03:50 -0700610 const char* field_name = field_id->Name()->Data();
611 fprintf(out_file_, "Annotations on field #%u '%s'\n", field_idx, field_name);
612 DumpAnnotationSetItem(field->GetAnnotationSetItem());
613 }
David Sehr7629f602016-08-07 16:01:51 -0700614 }
615
616 // Annotations on methods.
David Sehr853a8e12016-09-01 13:03:50 -0700617 if (methods != nullptr) {
618 for (auto& method : *methods) {
619 const dex_ir::MethodId* method_id = method->GetMethodId();
Jeff Hao3ab96b42016-09-09 18:35:01 -0700620 const uint32_t method_idx = method_id->GetIndex();
David Sehr853a8e12016-09-01 13:03:50 -0700621 const char* method_name = method_id->Name()->Data();
622 fprintf(out_file_, "Annotations on method #%u '%s'\n", method_idx, method_name);
623 DumpAnnotationSetItem(method->GetAnnotationSetItem());
624 }
David Sehr7629f602016-08-07 16:01:51 -0700625 }
626
627 // Annotations on method parameters.
David Sehr853a8e12016-09-01 13:03:50 -0700628 if (parameters != nullptr) {
629 for (auto& parameter : *parameters) {
630 const dex_ir::MethodId* method_id = parameter->GetMethodId();
Jeff Hao3ab96b42016-09-09 18:35:01 -0700631 const uint32_t method_idx = method_id->GetIndex();
David Sehr853a8e12016-09-01 13:03:50 -0700632 const char* method_name = method_id->Name()->Data();
633 fprintf(out_file_, "Annotations on method #%u '%s' parameters\n", method_idx, method_name);
634 uint32_t j = 0;
Jeff Hao3ab96b42016-09-09 18:35:01 -0700635 for (dex_ir::AnnotationSetItem* annotation : *parameter->GetAnnotations()->GetItems()) {
David Sehr853a8e12016-09-01 13:03:50 -0700636 fprintf(out_file_, "#%u\n", j);
Jeff Hao3ab96b42016-09-09 18:35:01 -0700637 DumpAnnotationSetItem(annotation);
David Sehr853a8e12016-09-01 13:03:50 -0700638 ++j;
639 }
David Sehr7629f602016-08-07 16:01:51 -0700640 }
641 }
642
643 fputc('\n', out_file_);
644}
645
646/*
647 * Dumps an interface that a class declares to implement.
648 */
David Sehr853a8e12016-09-01 13:03:50 -0700649static void DumpInterface(const dex_ir::TypeId* type_item, int i) {
David Sehr7629f602016-08-07 16:01:51 -0700650 const char* interface_name = type_item->GetStringId()->Data();
651 if (options_.output_format_ == kOutputPlain) {
652 fprintf(out_file_, " #%d : '%s'\n", i, interface_name);
653 } else {
Jeff Haoc3acfc52016-08-29 14:18:26 -0700654 std::string dot(DescriptorToDotWrapper(interface_name));
David Sehr7629f602016-08-07 16:01:51 -0700655 fprintf(out_file_, "<implements name=\"%s\">\n</implements>\n", dot.c_str());
656 }
657}
658
659/*
660 * Dumps the catches table associated with the code.
661 */
662static void DumpCatches(const dex_ir::CodeItem* code) {
663 const uint16_t tries_size = code->TriesSize();
664
665 // No catch table.
666 if (tries_size == 0) {
667 fprintf(out_file_, " catches : (none)\n");
668 return;
669 }
670
671 // Dump all table entries.
672 fprintf(out_file_, " catches : %d\n", tries_size);
673 std::vector<std::unique_ptr<const dex_ir::TryItem>>* tries = code->Tries();
674 for (uint32_t i = 0; i < tries_size; i++) {
675 const dex_ir::TryItem* try_item = (*tries)[i].get();
676 const uint32_t start = try_item->StartAddr();
677 const uint32_t end = start + try_item->InsnCount();
678 fprintf(out_file_, " 0x%04x - 0x%04x\n", start, end);
Jeff Haoa8621002016-10-04 18:13:44 +0000679 for (auto& handler : *try_item->GetHandlers()->GetHandlers()) {
David Sehr7629f602016-08-07 16:01:51 -0700680 const dex_ir::TypeId* type_id = handler->GetTypeId();
681 const char* descriptor = (type_id == nullptr) ? "<any>" : type_id->GetStringId()->Data();
682 fprintf(out_file_, " %s -> 0x%04x\n", descriptor, handler->GetAddress());
683 } // for
684 } // for
685}
686
687/*
688 * Dumps all positions table entries associated with the code.
689 */
690static void DumpPositionInfo(const dex_ir::CodeItem* code) {
691 dex_ir::DebugInfoItem* debug_info = code->DebugInfo();
692 if (debug_info == nullptr) {
693 return;
694 }
695 std::vector<std::unique_ptr<dex_ir::PositionInfo>>& positions = debug_info->GetPositionInfo();
696 for (size_t i = 0; i < positions.size(); ++i) {
697 fprintf(out_file_, " 0x%04x line=%d\n", positions[i]->address_, positions[i]->line_);
698 }
699}
700
701/*
702 * Dumps all locals table entries associated with the code.
703 */
704static void DumpLocalInfo(const dex_ir::CodeItem* code) {
705 dex_ir::DebugInfoItem* debug_info = code->DebugInfo();
706 if (debug_info == nullptr) {
707 return;
708 }
709 std::vector<std::unique_ptr<dex_ir::LocalInfo>>& locals = debug_info->GetLocalInfo();
710 for (size_t i = 0; i < locals.size(); ++i) {
711 dex_ir::LocalInfo* entry = locals[i].get();
712 fprintf(out_file_, " 0x%04x - 0x%04x reg=%d %s %s %s\n",
713 entry->start_address_, entry->end_address_, entry->reg_,
714 entry->name_.c_str(), entry->descriptor_.c_str(), entry->signature_.c_str());
715 }
716}
717
718/*
719 * Helper for dumpInstruction(), which builds the string
720 * representation for the index in the given instruction.
721 * Returns a pointer to a buffer of sufficient size.
722 */
723static std::unique_ptr<char[]> IndexString(dex_ir::Header* header,
724 const Instruction* dec_insn,
725 size_t buf_size) {
Orion Hodsonb34bb192016-10-18 17:02:58 +0100726 static const uint32_t kInvalidIndex = std::numeric_limits<uint32_t>::max();
David Sehr7629f602016-08-07 16:01:51 -0700727 std::unique_ptr<char[]> buf(new char[buf_size]);
728 // Determine index and width of the string.
729 uint32_t index = 0;
Orion Hodsonb34bb192016-10-18 17:02:58 +0100730 uint32_t secondary_index = kInvalidIndex;
David Sehr7629f602016-08-07 16:01:51 -0700731 uint32_t width = 4;
732 switch (Instruction::FormatOf(dec_insn->Opcode())) {
733 // SOME NOT SUPPORTED:
734 // case Instruction::k20bc:
735 case Instruction::k21c:
736 case Instruction::k35c:
737 // case Instruction::k35ms:
738 case Instruction::k3rc:
739 // case Instruction::k3rms:
740 // case Instruction::k35mi:
741 // case Instruction::k3rmi:
742 index = dec_insn->VRegB();
743 width = 4;
744 break;
745 case Instruction::k31c:
746 index = dec_insn->VRegB();
747 width = 8;
748 break;
749 case Instruction::k22c:
750 // case Instruction::k22cs:
751 index = dec_insn->VRegC();
752 width = 4;
753 break;
Orion Hodsonb34bb192016-10-18 17:02:58 +0100754 case Instruction::k45cc:
755 case Instruction::k4rcc:
756 index = dec_insn->VRegB();
757 secondary_index = dec_insn->VRegH();
758 width = 4;
759 break;
David Sehr7629f602016-08-07 16:01:51 -0700760 default:
761 break;
762 } // switch
763
764 // Determine index type.
765 size_t outSize = 0;
766 switch (Instruction::IndexTypeOf(dec_insn->Opcode())) {
767 case Instruction::kIndexUnknown:
768 // This function should never get called for this type, but do
769 // something sensible here, just to help with debugging.
770 outSize = snprintf(buf.get(), buf_size, "<unknown-index>");
771 break;
772 case Instruction::kIndexNone:
773 // This function should never get called for this type, but do
774 // something sensible here, just to help with debugging.
775 outSize = snprintf(buf.get(), buf_size, "<no-index>");
776 break;
777 case Instruction::kIndexTypeRef:
Jeff Hao3ab96b42016-09-09 18:35:01 -0700778 if (index < header->GetCollections().TypeIdsSize()) {
779 const char* tp = header->GetCollections().GetTypeId(index)->GetStringId()->Data();
David Sehr7629f602016-08-07 16:01:51 -0700780 outSize = snprintf(buf.get(), buf_size, "%s // type@%0*x", tp, width, index);
781 } else {
782 outSize = snprintf(buf.get(), buf_size, "<type?> // type@%0*x", width, index);
783 }
784 break;
785 case Instruction::kIndexStringRef:
Jeff Hao3ab96b42016-09-09 18:35:01 -0700786 if (index < header->GetCollections().StringIdsSize()) {
787 const char* st = header->GetCollections().GetStringId(index)->Data();
David Sehr7629f602016-08-07 16:01:51 -0700788 outSize = snprintf(buf.get(), buf_size, "\"%s\" // string@%0*x", st, width, index);
789 } else {
790 outSize = snprintf(buf.get(), buf_size, "<string?> // string@%0*x", width, index);
791 }
792 break;
793 case Instruction::kIndexMethodRef:
Jeff Hao3ab96b42016-09-09 18:35:01 -0700794 if (index < header->GetCollections().MethodIdsSize()) {
795 dex_ir::MethodId* method_id = header->GetCollections().GetMethodId(index);
David Sehr7629f602016-08-07 16:01:51 -0700796 const char* name = method_id->Name()->Data();
David Sehr72359222016-09-07 13:04:01 -0700797 std::string type_descriptor = GetSignatureForProtoId(method_id->Proto());
David Sehr7629f602016-08-07 16:01:51 -0700798 const char* back_descriptor = method_id->Class()->GetStringId()->Data();
799 outSize = snprintf(buf.get(), buf_size, "%s.%s:%s // method@%0*x",
David Sehr72359222016-09-07 13:04:01 -0700800 back_descriptor, name, type_descriptor.c_str(), width, index);
David Sehr7629f602016-08-07 16:01:51 -0700801 } else {
802 outSize = snprintf(buf.get(), buf_size, "<method?> // method@%0*x", width, index);
803 }
804 break;
805 case Instruction::kIndexFieldRef:
Jeff Hao3ab96b42016-09-09 18:35:01 -0700806 if (index < header->GetCollections().FieldIdsSize()) {
807 dex_ir::FieldId* field_id = header->GetCollections().GetFieldId(index);
David Sehr7629f602016-08-07 16:01:51 -0700808 const char* name = field_id->Name()->Data();
809 const char* type_descriptor = field_id->Type()->GetStringId()->Data();
810 const char* back_descriptor = field_id->Class()->GetStringId()->Data();
811 outSize = snprintf(buf.get(), buf_size, "%s.%s:%s // field@%0*x",
812 back_descriptor, name, type_descriptor, width, index);
813 } else {
814 outSize = snprintf(buf.get(), buf_size, "<field?> // field@%0*x", width, index);
815 }
816 break;
817 case Instruction::kIndexVtableOffset:
818 outSize = snprintf(buf.get(), buf_size, "[%0*x] // vtable #%0*x",
819 width, index, width, index);
820 break;
821 case Instruction::kIndexFieldOffset:
822 outSize = snprintf(buf.get(), buf_size, "[obj+%0*x]", width, index);
823 break;
824 // SOME NOT SUPPORTED:
825 // case Instruction::kIndexVaries:
826 // case Instruction::kIndexInlineMethod:
Orion Hodsonb34bb192016-10-18 17:02:58 +0100827 case Instruction::kIndexMethodAndProtoRef: {
828 std::string method("<method?>");
829 std::string proto("<proto?>");
830 if (index < header->GetCollections().MethodIdsSize()) {
831 dex_ir::MethodId* method_id = header->GetCollections().GetMethodId(index);
832 const char* name = method_id->Name()->Data();
833 std::string type_descriptor = GetSignatureForProtoId(method_id->Proto());
834 const char* back_descriptor = method_id->Class()->GetStringId()->Data();
835 method = StringPrintf("%s.%s:%s", back_descriptor, name, type_descriptor.c_str());
836 }
837 if (secondary_index < header->GetCollections().ProtoIdsSize()) {
838 dex_ir::ProtoId* proto_id = header->GetCollections().GetProtoId(secondary_index);
839 proto = GetSignatureForProtoId(proto_id);
840 }
841 outSize = snprintf(buf.get(), buf_size, "%s, %s // method@%0*x, proto@%0*x",
842 method.c_str(), proto.c_str(), width, index, width, secondary_index);
843 }
844 break;
David Sehr7629f602016-08-07 16:01:51 -0700845 default:
846 outSize = snprintf(buf.get(), buf_size, "<?>");
847 break;
848 } // switch
849
850 // Determine success of string construction.
851 if (outSize >= buf_size) {
852 // The buffer wasn't big enough; retry with computed size. Note: snprintf()
853 // doesn't count/ the '\0' as part of its returned size, so we add explicit
854 // space for it here.
855 return IndexString(header, dec_insn, outSize + 1);
856 }
857 return buf;
858}
859
860/*
861 * Dumps a single instruction.
862 */
863static void DumpInstruction(dex_ir::Header* header, const dex_ir::CodeItem* code,
864 uint32_t code_offset, uint32_t insn_idx, uint32_t insn_width,
865 const Instruction* dec_insn) {
866 // Address of instruction (expressed as byte offset).
867 fprintf(out_file_, "%06x:", code_offset + 0x10 + insn_idx * 2);
868
869 // Dump (part of) raw bytes.
870 const uint16_t* insns = code->Insns();
871 for (uint32_t i = 0; i < 8; i++) {
872 if (i < insn_width) {
873 if (i == 7) {
874 fprintf(out_file_, " ... ");
875 } else {
876 // Print 16-bit value in little-endian order.
877 const uint8_t* bytePtr = (const uint8_t*) &insns[insn_idx + i];
878 fprintf(out_file_, " %02x%02x", bytePtr[0], bytePtr[1]);
879 }
880 } else {
881 fputs(" ", out_file_);
882 }
883 } // for
884
885 // Dump pseudo-instruction or opcode.
886 if (dec_insn->Opcode() == Instruction::NOP) {
887 const uint16_t instr = Get2LE((const uint8_t*) &insns[insn_idx]);
888 if (instr == Instruction::kPackedSwitchSignature) {
889 fprintf(out_file_, "|%04x: packed-switch-data (%d units)", insn_idx, insn_width);
890 } else if (instr == Instruction::kSparseSwitchSignature) {
891 fprintf(out_file_, "|%04x: sparse-switch-data (%d units)", insn_idx, insn_width);
892 } else if (instr == Instruction::kArrayDataSignature) {
893 fprintf(out_file_, "|%04x: array-data (%d units)", insn_idx, insn_width);
894 } else {
895 fprintf(out_file_, "|%04x: nop // spacer", insn_idx);
896 }
897 } else {
898 fprintf(out_file_, "|%04x: %s", insn_idx, dec_insn->Name());
899 }
900
901 // Set up additional argument.
902 std::unique_ptr<char[]> index_buf;
903 if (Instruction::IndexTypeOf(dec_insn->Opcode()) != Instruction::kIndexNone) {
904 index_buf = IndexString(header, dec_insn, 200);
905 }
906
907 // Dump the instruction.
908 //
909 // NOTE: pDecInsn->DumpString(pDexFile) differs too much from original.
910 //
911 switch (Instruction::FormatOf(dec_insn->Opcode())) {
912 case Instruction::k10x: // op
913 break;
914 case Instruction::k12x: // op vA, vB
915 fprintf(out_file_, " v%d, v%d", dec_insn->VRegA(), dec_insn->VRegB());
916 break;
917 case Instruction::k11n: // op vA, #+B
918 fprintf(out_file_, " v%d, #int %d // #%x",
919 dec_insn->VRegA(), (int32_t) dec_insn->VRegB(), (uint8_t)dec_insn->VRegB());
920 break;
921 case Instruction::k11x: // op vAA
922 fprintf(out_file_, " v%d", dec_insn->VRegA());
923 break;
924 case Instruction::k10t: // op +AA
925 case Instruction::k20t: { // op +AAAA
926 const int32_t targ = (int32_t) dec_insn->VRegA();
927 fprintf(out_file_, " %04x // %c%04x",
928 insn_idx + targ,
929 (targ < 0) ? '-' : '+',
930 (targ < 0) ? -targ : targ);
931 break;
932 }
933 case Instruction::k22x: // op vAA, vBBBB
934 fprintf(out_file_, " v%d, v%d", dec_insn->VRegA(), dec_insn->VRegB());
935 break;
936 case Instruction::k21t: { // op vAA, +BBBB
937 const int32_t targ = (int32_t) dec_insn->VRegB();
938 fprintf(out_file_, " v%d, %04x // %c%04x", dec_insn->VRegA(),
939 insn_idx + targ,
940 (targ < 0) ? '-' : '+',
941 (targ < 0) ? -targ : targ);
942 break;
943 }
944 case Instruction::k21s: // op vAA, #+BBBB
945 fprintf(out_file_, " v%d, #int %d // #%x",
946 dec_insn->VRegA(), (int32_t) dec_insn->VRegB(), (uint16_t)dec_insn->VRegB());
947 break;
948 case Instruction::k21h: // op vAA, #+BBBB0000[00000000]
949 // The printed format varies a bit based on the actual opcode.
950 if (dec_insn->Opcode() == Instruction::CONST_HIGH16) {
951 const int32_t value = dec_insn->VRegB() << 16;
952 fprintf(out_file_, " v%d, #int %d // #%x",
953 dec_insn->VRegA(), value, (uint16_t) dec_insn->VRegB());
954 } else {
955 const int64_t value = ((int64_t) dec_insn->VRegB()) << 48;
956 fprintf(out_file_, " v%d, #long %" PRId64 " // #%x",
957 dec_insn->VRegA(), value, (uint16_t) dec_insn->VRegB());
958 }
959 break;
960 case Instruction::k21c: // op vAA, thing@BBBB
961 case Instruction::k31c: // op vAA, thing@BBBBBBBB
962 fprintf(out_file_, " v%d, %s", dec_insn->VRegA(), index_buf.get());
963 break;
964 case Instruction::k23x: // op vAA, vBB, vCC
965 fprintf(out_file_, " v%d, v%d, v%d",
966 dec_insn->VRegA(), dec_insn->VRegB(), dec_insn->VRegC());
967 break;
968 case Instruction::k22b: // op vAA, vBB, #+CC
969 fprintf(out_file_, " v%d, v%d, #int %d // #%02x",
970 dec_insn->VRegA(), dec_insn->VRegB(),
971 (int32_t) dec_insn->VRegC(), (uint8_t) dec_insn->VRegC());
972 break;
973 case Instruction::k22t: { // op vA, vB, +CCCC
974 const int32_t targ = (int32_t) dec_insn->VRegC();
975 fprintf(out_file_, " v%d, v%d, %04x // %c%04x",
976 dec_insn->VRegA(), dec_insn->VRegB(),
977 insn_idx + targ,
978 (targ < 0) ? '-' : '+',
979 (targ < 0) ? -targ : targ);
980 break;
981 }
982 case Instruction::k22s: // op vA, vB, #+CCCC
983 fprintf(out_file_, " v%d, v%d, #int %d // #%04x",
984 dec_insn->VRegA(), dec_insn->VRegB(),
985 (int32_t) dec_insn->VRegC(), (uint16_t) dec_insn->VRegC());
986 break;
987 case Instruction::k22c: // op vA, vB, thing@CCCC
988 // NOT SUPPORTED:
989 // case Instruction::k22cs: // [opt] op vA, vB, field offset CCCC
990 fprintf(out_file_, " v%d, v%d, %s",
991 dec_insn->VRegA(), dec_insn->VRegB(), index_buf.get());
992 break;
993 case Instruction::k30t:
994 fprintf(out_file_, " #%08x", dec_insn->VRegA());
995 break;
996 case Instruction::k31i: { // op vAA, #+BBBBBBBB
997 // This is often, but not always, a float.
998 union {
999 float f;
1000 uint32_t i;
1001 } conv;
1002 conv.i = dec_insn->VRegB();
1003 fprintf(out_file_, " v%d, #float %g // #%08x",
1004 dec_insn->VRegA(), conv.f, dec_insn->VRegB());
1005 break;
1006 }
1007 case Instruction::k31t: // op vAA, offset +BBBBBBBB
1008 fprintf(out_file_, " v%d, %08x // +%08x",
1009 dec_insn->VRegA(), insn_idx + dec_insn->VRegB(), dec_insn->VRegB());
1010 break;
1011 case Instruction::k32x: // op vAAAA, vBBBB
1012 fprintf(out_file_, " v%d, v%d", dec_insn->VRegA(), dec_insn->VRegB());
1013 break;
Orion Hodsonb34bb192016-10-18 17:02:58 +01001014 case Instruction::k35c: // op {vC, vD, vE, vF, vG}, thing@BBBB
1015 case Instruction::k45cc: { // op {vC, vD, vE, vF, vG}, meth@BBBB, proto@HHHH
David Sehr7629f602016-08-07 16:01:51 -07001016 // NOT SUPPORTED:
1017 // case Instruction::k35ms: // [opt] invoke-virtual+super
1018 // case Instruction::k35mi: // [opt] inline invoke
1019 uint32_t arg[Instruction::kMaxVarArgRegs];
1020 dec_insn->GetVarArgs(arg);
1021 fputs(" {", out_file_);
1022 for (int i = 0, n = dec_insn->VRegA(); i < n; i++) {
1023 if (i == 0) {
1024 fprintf(out_file_, "v%d", arg[i]);
1025 } else {
1026 fprintf(out_file_, ", v%d", arg[i]);
1027 }
1028 } // for
1029 fprintf(out_file_, "}, %s", index_buf.get());
1030 break;
1031 }
Orion Hodsonb34bb192016-10-18 17:02:58 +01001032 case Instruction::k3rc: // op {vCCCC .. v(CCCC+AA-1)}, thing@BBBB
1033 case Instruction::k4rcc: // op {vCCCC .. v(CCCC+AA-1)}, meth@BBBB, proto@HHHH
David Sehr7629f602016-08-07 16:01:51 -07001034 // NOT SUPPORTED:
1035 // case Instruction::k3rms: // [opt] invoke-virtual+super/range
1036 // case Instruction::k3rmi: // [opt] execute-inline/range
1037 {
1038 // This doesn't match the "dx" output when some of the args are
1039 // 64-bit values -- dx only shows the first register.
1040 fputs(" {", out_file_);
1041 for (int i = 0, n = dec_insn->VRegA(); i < n; i++) {
1042 if (i == 0) {
1043 fprintf(out_file_, "v%d", dec_insn->VRegC() + i);
1044 } else {
1045 fprintf(out_file_, ", v%d", dec_insn->VRegC() + i);
1046 }
1047 } // for
1048 fprintf(out_file_, "}, %s", index_buf.get());
1049 }
1050 break;
1051 case Instruction::k51l: { // op vAA, #+BBBBBBBBBBBBBBBB
1052 // This is often, but not always, a double.
1053 union {
1054 double d;
1055 uint64_t j;
1056 } conv;
1057 conv.j = dec_insn->WideVRegB();
1058 fprintf(out_file_, " v%d, #double %g // #%016" PRIx64,
1059 dec_insn->VRegA(), conv.d, dec_insn->WideVRegB());
1060 break;
1061 }
1062 // NOT SUPPORTED:
1063 // case Instruction::k00x: // unknown op or breakpoint
1064 // break;
1065 default:
1066 fprintf(out_file_, " ???");
1067 break;
1068 } // switch
1069
1070 fputc('\n', out_file_);
1071}
1072
1073/*
1074 * Dumps a bytecode disassembly.
1075 */
1076static void DumpBytecodes(dex_ir::Header* header, uint32_t idx,
1077 const dex_ir::CodeItem* code, uint32_t code_offset) {
Jeff Hao3ab96b42016-09-09 18:35:01 -07001078 dex_ir::MethodId* method_id = header->GetCollections().GetMethodId(idx);
David Sehr7629f602016-08-07 16:01:51 -07001079 const char* name = method_id->Name()->Data();
David Sehr72359222016-09-07 13:04:01 -07001080 std::string type_descriptor = GetSignatureForProtoId(method_id->Proto());
David Sehr7629f602016-08-07 16:01:51 -07001081 const char* back_descriptor = method_id->Class()->GetStringId()->Data();
1082
1083 // Generate header.
Jeff Haoc3acfc52016-08-29 14:18:26 -07001084 std::string dot(DescriptorToDotWrapper(back_descriptor));
David Sehr7629f602016-08-07 16:01:51 -07001085 fprintf(out_file_, "%06x: |[%06x] %s.%s:%s\n",
David Sehr72359222016-09-07 13:04:01 -07001086 code_offset, code_offset, dot.c_str(), name, type_descriptor.c_str());
David Sehr7629f602016-08-07 16:01:51 -07001087
1088 // Iterate over all instructions.
1089 const uint16_t* insns = code->Insns();
1090 for (uint32_t insn_idx = 0; insn_idx < code->InsnsSize();) {
1091 const Instruction* instruction = Instruction::At(&insns[insn_idx]);
1092 const uint32_t insn_width = instruction->SizeInCodeUnits();
1093 if (insn_width == 0) {
1094 fprintf(stderr, "GLITCH: zero-width instruction at idx=0x%04x\n", insn_idx);
1095 break;
1096 }
1097 DumpInstruction(header, code, code_offset, insn_idx, insn_width, instruction);
1098 insn_idx += insn_width;
1099 } // for
1100}
1101
1102/*
1103 * Dumps code of a method.
1104 */
1105static void DumpCode(dex_ir::Header* header, uint32_t idx, const dex_ir::CodeItem* code,
1106 uint32_t code_offset) {
1107 fprintf(out_file_, " registers : %d\n", code->RegistersSize());
1108 fprintf(out_file_, " ins : %d\n", code->InsSize());
1109 fprintf(out_file_, " outs : %d\n", code->OutsSize());
1110 fprintf(out_file_, " insns size : %d 16-bit code units\n",
1111 code->InsnsSize());
1112
1113 // Bytecode disassembly, if requested.
1114 if (options_.disassemble_) {
1115 DumpBytecodes(header, idx, code, code_offset);
1116 }
1117
1118 // Try-catch blocks.
1119 DumpCatches(code);
1120
1121 // Positions and locals table in the debug info.
1122 fprintf(out_file_, " positions : \n");
1123 DumpPositionInfo(code);
1124 fprintf(out_file_, " locals : \n");
1125 DumpLocalInfo(code);
1126}
1127
1128/*
1129 * Dumps a method.
1130 */
1131static void DumpMethod(dex_ir::Header* header, uint32_t idx, uint32_t flags,
1132 const dex_ir::CodeItem* code, int i) {
1133 // Bail for anything private if export only requested.
1134 if (options_.exports_only_ && (flags & (kAccPublic | kAccProtected)) == 0) {
1135 return;
1136 }
1137
Jeff Hao3ab96b42016-09-09 18:35:01 -07001138 dex_ir::MethodId* method_id = header->GetCollections().GetMethodId(idx);
David Sehr7629f602016-08-07 16:01:51 -07001139 const char* name = method_id->Name()->Data();
1140 char* type_descriptor = strdup(GetSignatureForProtoId(method_id->Proto()).c_str());
1141 const char* back_descriptor = method_id->Class()->GetStringId()->Data();
1142 char* access_str = CreateAccessFlagStr(flags, kAccessForMethod);
1143
1144 if (options_.output_format_ == kOutputPlain) {
1145 fprintf(out_file_, " #%d : (in %s)\n", i, back_descriptor);
1146 fprintf(out_file_, " name : '%s'\n", name);
1147 fprintf(out_file_, " type : '%s'\n", type_descriptor);
1148 fprintf(out_file_, " access : 0x%04x (%s)\n", flags, access_str);
1149 if (code == nullptr) {
1150 fprintf(out_file_, " code : (none)\n");
1151 } else {
1152 fprintf(out_file_, " code -\n");
1153 DumpCode(header, idx, code, code->GetOffset());
1154 }
1155 if (options_.disassemble_) {
1156 fputc('\n', out_file_);
1157 }
1158 } else if (options_.output_format_ == kOutputXml) {
1159 const bool constructor = (name[0] == '<');
1160
1161 // Method name and prototype.
1162 if (constructor) {
1163 std::string dot(DescriptorClassToDot(back_descriptor));
1164 fprintf(out_file_, "<constructor name=\"%s\"\n", dot.c_str());
Jeff Haoc3acfc52016-08-29 14:18:26 -07001165 dot = DescriptorToDotWrapper(back_descriptor);
David Sehr7629f602016-08-07 16:01:51 -07001166 fprintf(out_file_, " type=\"%s\"\n", dot.c_str());
1167 } else {
1168 fprintf(out_file_, "<method name=\"%s\"\n", name);
1169 const char* return_type = strrchr(type_descriptor, ')');
1170 if (return_type == nullptr) {
1171 fprintf(stderr, "bad method type descriptor '%s'\n", type_descriptor);
1172 goto bail;
1173 }
Jeff Haoc3acfc52016-08-29 14:18:26 -07001174 std::string dot(DescriptorToDotWrapper(return_type + 1));
David Sehr7629f602016-08-07 16:01:51 -07001175 fprintf(out_file_, " return=\"%s\"\n", dot.c_str());
1176 fprintf(out_file_, " abstract=%s\n", QuotedBool((flags & kAccAbstract) != 0));
1177 fprintf(out_file_, " native=%s\n", QuotedBool((flags & kAccNative) != 0));
1178 fprintf(out_file_, " synchronized=%s\n", QuotedBool(
1179 (flags & (kAccSynchronized | kAccDeclaredSynchronized)) != 0));
1180 }
1181
1182 // Additional method flags.
1183 fprintf(out_file_, " static=%s\n", QuotedBool((flags & kAccStatic) != 0));
1184 fprintf(out_file_, " final=%s\n", QuotedBool((flags & kAccFinal) != 0));
1185 // The "deprecated=" not knowable w/o parsing annotations.
1186 fprintf(out_file_, " visibility=%s\n>\n", QuotedVisibility(flags));
1187
1188 // Parameters.
1189 if (type_descriptor[0] != '(') {
1190 fprintf(stderr, "ERROR: bad descriptor '%s'\n", type_descriptor);
1191 goto bail;
1192 }
1193 char* tmp_buf = reinterpret_cast<char*>(malloc(strlen(type_descriptor) + 1));
1194 const char* base = type_descriptor + 1;
1195 int arg_num = 0;
1196 while (*base != ')') {
1197 char* cp = tmp_buf;
1198 while (*base == '[') {
1199 *cp++ = *base++;
1200 }
1201 if (*base == 'L') {
1202 // Copy through ';'.
1203 do {
1204 *cp = *base++;
1205 } while (*cp++ != ';');
1206 } else {
1207 // Primitive char, copy it.
1208 if (strchr("ZBCSIFJD", *base) == nullptr) {
1209 fprintf(stderr, "ERROR: bad method signature '%s'\n", base);
1210 break; // while
1211 }
1212 *cp++ = *base++;
1213 }
1214 // Null terminate and display.
1215 *cp++ = '\0';
Jeff Haoc3acfc52016-08-29 14:18:26 -07001216 std::string dot(DescriptorToDotWrapper(tmp_buf));
David Sehr7629f602016-08-07 16:01:51 -07001217 fprintf(out_file_, "<parameter name=\"arg%d\" type=\"%s\">\n"
1218 "</parameter>\n", arg_num++, dot.c_str());
1219 } // while
1220 free(tmp_buf);
1221 if (constructor) {
1222 fprintf(out_file_, "</constructor>\n");
1223 } else {
1224 fprintf(out_file_, "</method>\n");
1225 }
1226 }
1227
1228 bail:
1229 free(type_descriptor);
1230 free(access_str);
1231}
1232
1233/*
1234 * Dumps a static (class) field.
1235 */
1236static void DumpSField(dex_ir::Header* header, uint32_t idx, uint32_t flags,
Jeff Hao3ab96b42016-09-09 18:35:01 -07001237 int i, dex_ir::EncodedValue* init) {
David Sehr7629f602016-08-07 16:01:51 -07001238 // Bail for anything private if export only requested.
1239 if (options_.exports_only_ && (flags & (kAccPublic | kAccProtected)) == 0) {
1240 return;
1241 }
1242
Jeff Hao3ab96b42016-09-09 18:35:01 -07001243 dex_ir::FieldId* field_id = header->GetCollections().GetFieldId(idx);
David Sehr7629f602016-08-07 16:01:51 -07001244 const char* name = field_id->Name()->Data();
1245 const char* type_descriptor = field_id->Type()->GetStringId()->Data();
1246 const char* back_descriptor = field_id->Class()->GetStringId()->Data();
1247 char* access_str = CreateAccessFlagStr(flags, kAccessForField);
1248
1249 if (options_.output_format_ == kOutputPlain) {
1250 fprintf(out_file_, " #%d : (in %s)\n", i, back_descriptor);
1251 fprintf(out_file_, " name : '%s'\n", name);
1252 fprintf(out_file_, " type : '%s'\n", type_descriptor);
1253 fprintf(out_file_, " access : 0x%04x (%s)\n", flags, access_str);
1254 if (init != nullptr) {
1255 fputs(" value : ", out_file_);
1256 DumpEncodedValue(init);
1257 fputs("\n", out_file_);
1258 }
1259 } else if (options_.output_format_ == kOutputXml) {
1260 fprintf(out_file_, "<field name=\"%s\"\n", name);
Jeff Haoc3acfc52016-08-29 14:18:26 -07001261 std::string dot(DescriptorToDotWrapper(type_descriptor));
David Sehr7629f602016-08-07 16:01:51 -07001262 fprintf(out_file_, " type=\"%s\"\n", dot.c_str());
1263 fprintf(out_file_, " transient=%s\n", QuotedBool((flags & kAccTransient) != 0));
1264 fprintf(out_file_, " volatile=%s\n", QuotedBool((flags & kAccVolatile) != 0));
1265 // The "value=" is not knowable w/o parsing annotations.
1266 fprintf(out_file_, " static=%s\n", QuotedBool((flags & kAccStatic) != 0));
1267 fprintf(out_file_, " final=%s\n", QuotedBool((flags & kAccFinal) != 0));
1268 // The "deprecated=" is not knowable w/o parsing annotations.
1269 fprintf(out_file_, " visibility=%s\n", QuotedVisibility(flags));
1270 if (init != nullptr) {
1271 fputs(" value=\"", out_file_);
1272 DumpEncodedValue(init);
1273 fputs("\"\n", out_file_);
1274 }
1275 fputs(">\n</field>\n", out_file_);
1276 }
1277
1278 free(access_str);
1279}
1280
1281/*
1282 * Dumps an instance field.
1283 */
1284static void DumpIField(dex_ir::Header* header, uint32_t idx, uint32_t flags, int i) {
1285 DumpSField(header, idx, flags, i, nullptr);
1286}
1287
1288/*
David Sehr7629f602016-08-07 16:01:51 -07001289 * Dumps the class.
1290 *
1291 * Note "idx" is a DexClassDef index, not a DexTypeId index.
1292 *
1293 * If "*last_package" is nullptr or does not match the current class' package,
1294 * the value will be replaced with a newly-allocated string.
1295 */
David Sehrcaacd112016-10-20 16:27:02 -07001296static void DumpClass(dex_ir::Header* header, int idx, char** last_package) {
Jeff Hao3ab96b42016-09-09 18:35:01 -07001297 dex_ir::ClassDef* class_def = header->GetCollections().GetClassDef(idx);
David Sehr7629f602016-08-07 16:01:51 -07001298 // Omitting non-public class.
1299 if (options_.exports_only_ && (class_def->GetAccessFlags() & kAccPublic) == 0) {
1300 return;
1301 }
1302
1303 if (options_.show_section_headers_) {
1304 DumpClassDef(header, idx);
1305 }
1306
1307 if (options_.show_annotations_) {
1308 DumpClassAnnotations(header, idx);
1309 }
1310
David Sehr7629f602016-08-07 16:01:51 -07001311 // For the XML output, show the package name. Ideally we'd gather
1312 // up the classes, sort them, and dump them alphabetically so the
1313 // package name wouldn't jump around, but that's not a great plan
1314 // for something that needs to run on the device.
Jeff Hao3ab96b42016-09-09 18:35:01 -07001315 const char* class_descriptor =
1316 header->GetCollections().GetClassDef(idx)->ClassType()->GetStringId()->Data();
David Sehr7629f602016-08-07 16:01:51 -07001317 if (!(class_descriptor[0] == 'L' &&
1318 class_descriptor[strlen(class_descriptor)-1] == ';')) {
1319 // Arrays and primitives should not be defined explicitly. Keep going?
1320 fprintf(stderr, "Malformed class name '%s'\n", class_descriptor);
1321 } else if (options_.output_format_ == kOutputXml) {
1322 char* mangle = strdup(class_descriptor + 1);
1323 mangle[strlen(mangle)-1] = '\0';
1324
1325 // Reduce to just the package name.
1326 char* last_slash = strrchr(mangle, '/');
1327 if (last_slash != nullptr) {
1328 *last_slash = '\0';
1329 } else {
1330 *mangle = '\0';
1331 }
1332
1333 for (char* cp = mangle; *cp != '\0'; cp++) {
1334 if (*cp == '/') {
1335 *cp = '.';
1336 }
1337 } // for
1338
1339 if (*last_package == nullptr || strcmp(mangle, *last_package) != 0) {
1340 // Start of a new package.
1341 if (*last_package != nullptr) {
1342 fprintf(out_file_, "</package>\n");
1343 }
1344 fprintf(out_file_, "<package name=\"%s\"\n>\n", mangle);
1345 free(*last_package);
1346 *last_package = mangle;
1347 } else {
1348 free(mangle);
1349 }
1350 }
1351
1352 // General class information.
1353 char* access_str = CreateAccessFlagStr(class_def->GetAccessFlags(), kAccessForClass);
1354 const char* superclass_descriptor = nullptr;
1355 if (class_def->Superclass() != nullptr) {
1356 superclass_descriptor = class_def->Superclass()->GetStringId()->Data();
1357 }
1358 if (options_.output_format_ == kOutputPlain) {
1359 fprintf(out_file_, "Class #%d -\n", idx);
1360 fprintf(out_file_, " Class descriptor : '%s'\n", class_descriptor);
1361 fprintf(out_file_, " Access flags : 0x%04x (%s)\n",
1362 class_def->GetAccessFlags(), access_str);
1363 if (superclass_descriptor != nullptr) {
1364 fprintf(out_file_, " Superclass : '%s'\n", superclass_descriptor);
1365 }
1366 fprintf(out_file_, " Interfaces -\n");
1367 } else {
1368 std::string dot(DescriptorClassToDot(class_descriptor));
1369 fprintf(out_file_, "<class name=\"%s\"\n", dot.c_str());
1370 if (superclass_descriptor != nullptr) {
Jeff Haoc3acfc52016-08-29 14:18:26 -07001371 dot = DescriptorToDotWrapper(superclass_descriptor);
David Sehr7629f602016-08-07 16:01:51 -07001372 fprintf(out_file_, " extends=\"%s\"\n", dot.c_str());
1373 }
1374 fprintf(out_file_, " interface=%s\n",
1375 QuotedBool((class_def->GetAccessFlags() & kAccInterface) != 0));
1376 fprintf(out_file_, " abstract=%s\n",
1377 QuotedBool((class_def->GetAccessFlags() & kAccAbstract) != 0));
1378 fprintf(out_file_, " static=%s\n", QuotedBool((class_def->GetAccessFlags() & kAccStatic) != 0));
1379 fprintf(out_file_, " final=%s\n", QuotedBool((class_def->GetAccessFlags() & kAccFinal) != 0));
1380 // The "deprecated=" not knowable w/o parsing annotations.
1381 fprintf(out_file_, " visibility=%s\n", QuotedVisibility(class_def->GetAccessFlags()));
1382 fprintf(out_file_, ">\n");
1383 }
1384
1385 // Interfaces.
Jeff Hao3ab96b42016-09-09 18:35:01 -07001386 const dex_ir::TypeIdVector* interfaces = class_def->Interfaces();
David Sehr853a8e12016-09-01 13:03:50 -07001387 if (interfaces != nullptr) {
1388 for (uint32_t i = 0; i < interfaces->size(); i++) {
1389 DumpInterface((*interfaces)[i], i);
1390 } // for
1391 }
David Sehr7629f602016-08-07 16:01:51 -07001392
1393 // Fields and methods.
1394 dex_ir::ClassData* class_data = class_def->GetClassData();
1395 // Prepare data for static fields.
Jeff Hao3ab96b42016-09-09 18:35:01 -07001396 dex_ir::EncodedArrayItem* static_values = class_def->StaticValues();
1397 dex_ir::EncodedValueVector* encoded_values =
1398 static_values == nullptr ? nullptr : static_values->GetEncodedValues();
1399 const uint32_t encoded_values_size = (encoded_values == nullptr) ? 0 : encoded_values->size();
David Sehr7629f602016-08-07 16:01:51 -07001400
1401 // Static fields.
1402 if (options_.output_format_ == kOutputPlain) {
1403 fprintf(out_file_, " Static fields -\n");
1404 }
David Sehr853a8e12016-09-01 13:03:50 -07001405 if (class_data != nullptr) {
1406 dex_ir::FieldItemVector* static_fields = class_data->StaticFields();
1407 if (static_fields != nullptr) {
1408 for (uint32_t i = 0; i < static_fields->size(); i++) {
1409 DumpSField(header,
Jeff Hao3ab96b42016-09-09 18:35:01 -07001410 (*static_fields)[i]->GetFieldId()->GetIndex(),
David Sehr853a8e12016-09-01 13:03:50 -07001411 (*static_fields)[i]->GetAccessFlags(),
1412 i,
Jeff Hao3ab96b42016-09-09 18:35:01 -07001413 i < encoded_values_size ? (*encoded_values)[i].get() : nullptr);
David Sehr853a8e12016-09-01 13:03:50 -07001414 } // for
1415 }
1416 }
David Sehr7629f602016-08-07 16:01:51 -07001417
1418 // Instance fields.
1419 if (options_.output_format_ == kOutputPlain) {
1420 fprintf(out_file_, " Instance fields -\n");
1421 }
David Sehr853a8e12016-09-01 13:03:50 -07001422 if (class_data != nullptr) {
1423 dex_ir::FieldItemVector* instance_fields = class_data->InstanceFields();
1424 if (instance_fields != nullptr) {
1425 for (uint32_t i = 0; i < instance_fields->size(); i++) {
1426 DumpIField(header,
Jeff Hao3ab96b42016-09-09 18:35:01 -07001427 (*instance_fields)[i]->GetFieldId()->GetIndex(),
David Sehr853a8e12016-09-01 13:03:50 -07001428 (*instance_fields)[i]->GetAccessFlags(),
1429 i);
1430 } // for
1431 }
1432 }
David Sehr7629f602016-08-07 16:01:51 -07001433
1434 // Direct methods.
1435 if (options_.output_format_ == kOutputPlain) {
1436 fprintf(out_file_, " Direct methods -\n");
1437 }
David Sehr853a8e12016-09-01 13:03:50 -07001438 if (class_data != nullptr) {
1439 dex_ir::MethodItemVector* direct_methods = class_data->DirectMethods();
1440 if (direct_methods != nullptr) {
1441 for (uint32_t i = 0; i < direct_methods->size(); i++) {
1442 DumpMethod(header,
Jeff Hao3ab96b42016-09-09 18:35:01 -07001443 (*direct_methods)[i]->GetMethodId()->GetIndex(),
David Sehr853a8e12016-09-01 13:03:50 -07001444 (*direct_methods)[i]->GetAccessFlags(),
1445 (*direct_methods)[i]->GetCodeItem(),
1446 i);
1447 } // for
1448 }
1449 }
David Sehr7629f602016-08-07 16:01:51 -07001450
1451 // Virtual methods.
1452 if (options_.output_format_ == kOutputPlain) {
1453 fprintf(out_file_, " Virtual methods -\n");
1454 }
David Sehr853a8e12016-09-01 13:03:50 -07001455 if (class_data != nullptr) {
1456 dex_ir::MethodItemVector* virtual_methods = class_data->VirtualMethods();
1457 if (virtual_methods != nullptr) {
1458 for (uint32_t i = 0; i < virtual_methods->size(); i++) {
1459 DumpMethod(header,
Jeff Hao3ab96b42016-09-09 18:35:01 -07001460 (*virtual_methods)[i]->GetMethodId()->GetIndex(),
David Sehr853a8e12016-09-01 13:03:50 -07001461 (*virtual_methods)[i]->GetAccessFlags(),
1462 (*virtual_methods)[i]->GetCodeItem(),
1463 i);
1464 } // for
1465 }
1466 }
David Sehr7629f602016-08-07 16:01:51 -07001467
1468 // End of class.
1469 if (options_.output_format_ == kOutputPlain) {
1470 const char* file_name = "unknown";
1471 if (class_def->SourceFile() != nullptr) {
1472 file_name = class_def->SourceFile()->Data();
1473 }
1474 const dex_ir::StringId* source_file = class_def->SourceFile();
1475 fprintf(out_file_, " source_file_idx : %d (%s)\n\n",
Jeff Hao3ab96b42016-09-09 18:35:01 -07001476 source_file == nullptr ? 0xffffffffU : source_file->GetIndex(), file_name);
David Sehr7629f602016-08-07 16:01:51 -07001477 } else if (options_.output_format_ == kOutputXml) {
1478 fprintf(out_file_, "</class>\n");
1479 }
1480
1481 free(access_str);
1482}
1483
1484/*
1485 * Dumps the requested sections of the file.
1486 */
David Sehrcdcfde72016-09-26 07:44:04 -07001487static void ProcessDexFile(const char* file_name, const DexFile* dex_file, size_t dex_file_index) {
David Sehr7629f602016-08-07 16:01:51 -07001488 if (options_.verbose_) {
1489 fprintf(out_file_, "Opened '%s', DEX version '%.3s'\n",
1490 file_name, dex_file->GetHeader().magic_ + 4);
1491 }
David Sehr72359222016-09-07 13:04:01 -07001492 std::unique_ptr<dex_ir::Header> header(dex_ir::DexIrBuilder(*dex_file));
David Sehr7629f602016-08-07 16:01:51 -07001493
David Sehrcdcfde72016-09-26 07:44:04 -07001494 if (options_.visualize_pattern_) {
1495 VisualizeDexLayout(header.get(), dex_file, dex_file_index);
1496 return;
1497 }
1498
David Sehr7629f602016-08-07 16:01:51 -07001499 // Headers.
1500 if (options_.show_file_headers_) {
David Sehr72359222016-09-07 13:04:01 -07001501 DumpFileHeader(header.get());
David Sehr7629f602016-08-07 16:01:51 -07001502 }
1503
1504 // Open XML context.
1505 if (options_.output_format_ == kOutputXml) {
1506 fprintf(out_file_, "<api>\n");
1507 }
1508
1509 // Iterate over all classes.
1510 char* package = nullptr;
Jeff Hao3ab96b42016-09-09 18:35:01 -07001511 const uint32_t class_defs_size = header->GetCollections().ClassDefsSize();
David Sehr7629f602016-08-07 16:01:51 -07001512 for (uint32_t i = 0; i < class_defs_size; i++) {
David Sehrcaacd112016-10-20 16:27:02 -07001513 DumpClass(header.get(), i, &package);
David Sehr7629f602016-08-07 16:01:51 -07001514 } // for
1515
1516 // Free the last package allocated.
1517 if (package != nullptr) {
1518 fprintf(out_file_, "</package>\n");
1519 free(package);
1520 }
1521
1522 // Close XML context.
1523 if (options_.output_format_ == kOutputXml) {
1524 fprintf(out_file_, "</api>\n");
1525 }
Jeff Hao3ab96b42016-09-09 18:35:01 -07001526
Jeff Hao3ab96b42016-09-09 18:35:01 -07001527 // Output dex file.
Jeff Haoa8621002016-10-04 18:13:44 +00001528 if (options_.output_dex_directory_ != nullptr) {
1529 std::string output_location(options_.output_dex_directory_);
1530 size_t last_slash = dex_file->GetLocation().rfind("/");
1531 output_location.append(dex_file->GetLocation().substr(last_slash));
1532 DexWriter::OutputDexFile(*header, output_location.c_str());
Jeff Hao3ab96b42016-09-09 18:35:01 -07001533 }
David Sehr7629f602016-08-07 16:01:51 -07001534}
1535
1536/*
1537 * Processes a single file (either direct .dex or indirect .zip/.jar/.apk).
1538 */
1539int ProcessFile(const char* file_name) {
1540 if (options_.verbose_) {
1541 fprintf(out_file_, "Processing '%s'...\n", file_name);
1542 }
1543
1544 // If the file is not a .dex file, the function tries .zip/.jar/.apk files,
1545 // all of which are Zip archives with "classes.dex" inside.
1546 const bool verify_checksum = !options_.ignore_bad_checksum_;
1547 std::string error_msg;
1548 std::vector<std::unique_ptr<const DexFile>> dex_files;
1549 if (!DexFile::Open(file_name, file_name, verify_checksum, &error_msg, &dex_files)) {
1550 // Display returned error message to user. Note that this error behavior
1551 // differs from the error messages shown by the original Dalvik dexdump.
1552 fputs(error_msg.c_str(), stderr);
1553 fputc('\n', stderr);
1554 return -1;
1555 }
1556
1557 // Success. Either report checksum verification or process
1558 // all dex files found in given file.
1559 if (options_.checksum_only_) {
1560 fprintf(out_file_, "Checksum verified\n");
1561 } else {
1562 for (size_t i = 0; i < dex_files.size(); i++) {
David Sehrcdcfde72016-09-26 07:44:04 -07001563 ProcessDexFile(file_name, dex_files[i].get(), i);
David Sehr7629f602016-08-07 16:01:51 -07001564 }
1565 }
1566 return 0;
1567}
1568
1569} // namespace art