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