dexlayout.cc revision ca620d7bc03b23a0bcf0ef58df58603ee000dca0
1/* 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 "base/stringprintf.h" 34#include "dex_ir_builder.h" 35#include "dex_file-inl.h" 36#include "dex_instruction-inl.h" 37#include "dex_visualize.h" 38#include "dex_writer.h" 39#include "jit/offline_profiling_info.h" 40#include "os.h" 41#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/* 56 * Profile information file. 57 */ 58ProfileCompilationInfo* profile_info_ = nullptr; 59 60/* 61 * 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/* 76 * 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/* 92 * 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 255 std::string result("("); 256 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 } 261 } 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("&", out_file_); 338 break; 339 case '<': 340 fputs("<", out_file_); 341 break; 342 case '>': 343 fputs(">", out_file_); 344 break; 345 case '"': 346 fputs(""", out_file_); 347 break; 348 case '\t': 349 fputs("	", out_file_); 350 break; 351 case '\n': 352 fputs("
", out_file_); 353 break; 354 case '\r': 355 fputs("
", out_file_); 356 break; 357 default: 358 putc(*p, out_file_); 359 } // switch 360 } // for 361} 362 363// 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} 379/* 380 * Dumps encoded value. 381 */ 382static void DumpEncodedValue(const dex_ir::EncodedValue* data) { 383 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: { 417 dex_ir::TypeId* type_id = data->GetTypeId(); 418 fputs(type_id->GetStringId()->Data(), out_file_); 419 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. 435 for (auto& value : *data->GetEncodedArray()->GetEncodedValues()) { 436 fputc(' ', out_file_); 437 DumpEncodedValue(value.get()); 438 } 439 fputs(" }", out_file_); 440 break; 441 } 442 case DexFile::kDexAnnotationAnnotation: { 443 DumpEncodedAnnotation(data->GetEncodedAnnotation()); 444 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 */ 461static void DumpFileHeader(dex_ir::Header* header) { 462 char sanitized[8 * 2 + 1]; 463 dex_ir::Collections& collections = header->GetCollections(); 464 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()); 477 fprintf(out_file_, "string_ids_size : %d\n", collections.StringIdsSize()); 478 fprintf(out_file_, "string_ids_off : %d (0x%06x)\n", 479 collections.StringIdsOffset(), collections.StringIdsOffset()); 480 fprintf(out_file_, "type_ids_size : %d\n", collections.TypeIdsSize()); 481 fprintf(out_file_, "type_ids_off : %d (0x%06x)\n", 482 collections.TypeIdsOffset(), collections.TypeIdsOffset()); 483 fprintf(out_file_, "proto_ids_size : %d\n", collections.ProtoIdsSize()); 484 fprintf(out_file_, "proto_ids_off : %d (0x%06x)\n", 485 collections.ProtoIdsOffset(), collections.ProtoIdsOffset()); 486 fprintf(out_file_, "field_ids_size : %d\n", collections.FieldIdsSize()); 487 fprintf(out_file_, "field_ids_off : %d (0x%06x)\n", 488 collections.FieldIdsOffset(), collections.FieldIdsOffset()); 489 fprintf(out_file_, "method_ids_size : %d\n", collections.MethodIdsSize()); 490 fprintf(out_file_, "method_ids_off : %d (0x%06x)\n", 491 collections.MethodIdsOffset(), collections.MethodIdsOffset()); 492 fprintf(out_file_, "class_defs_size : %d\n", collections.ClassDefsSize()); 493 fprintf(out_file_, "class_defs_off : %d (0x%06x)\n", 494 collections.ClassDefsOffset(), collections.ClassDefsOffset()); 495 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. 505 dex_ir::ClassDef* class_def = header->GetCollections().GetClassDef(idx); 506 fprintf(out_file_, "Class #%d header:\n", idx); 507 fprintf(out_file_, "class_idx : %d\n", class_def->ClassType()->GetIndex()); 508 fprintf(out_file_, "access_flags : %d (0x%04x)\n", 509 class_def->GetAccessFlags(), class_def->GetAccessFlags()); 510 uint32_t superclass_idx = class_def->Superclass() == nullptr ? 511 DexFile::kDexNoIndex16 : class_def->Superclass()->GetIndex(); 512 fprintf(out_file_, "superclass_idx : %d\n", superclass_idx); 513 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) { 517 source_file_offset = class_def->SourceFile()->GetIndex(); 518 } 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); 526 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 } 532 533 // Fields and methods. 534 dex_ir::ClassData* class_data = class_def->GetClassData(); 535 if (class_data != nullptr && class_data->StaticFields() != nullptr) { 536 fprintf(out_file_, "static_fields_size : %zu\n", class_data->StaticFields()->size()); 537 } else { 538 fprintf(out_file_, "static_fields_size : 0\n"); 539 } 540 if (class_data != nullptr && class_data->InstanceFields() != nullptr) { 541 fprintf(out_file_, "instance_fields_size: %zu\n", class_data->InstanceFields()->size()); 542 } else { 543 fprintf(out_file_, "instance_fields_size: 0\n"); 544 } 545 if (class_data != nullptr && class_data->DirectMethods() != nullptr) { 546 fprintf(out_file_, "direct_methods_size : %zu\n", class_data->DirectMethods()->size()); 547 } else { 548 fprintf(out_file_, "direct_methods_size : 0\n"); 549 } 550 if (class_data != nullptr && class_data->VirtualMethods() != nullptr) { 551 fprintf(out_file_, "virtual_methods_size: %zu\n", class_data->VirtualMethods()->size()); 552 } else { 553 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) { 562 if (set_item == nullptr || set_item->GetItems()->size() == 0) { 563 fputs(" empty-annotation-set\n", out_file_); 564 return; 565 } 566 for (dex_ir::AnnotationItem* annotation : *set_item->GetItems()) { 567 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 577 DumpEncodedAnnotation(annotation->GetAnnotation()); 578 fputc('\n', out_file_); 579 } 580} 581 582/* 583 * Dumps class annotations. 584 */ 585static void DumpClassAnnotations(dex_ir::Header* header, int idx) { 586 dex_ir::ClassDef* class_def = header->GetCollections().GetClassDef(idx); 587 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(); 595 dex_ir::FieldAnnotationVector* fields = annotations_directory->GetFieldAnnotations(); 596 dex_ir::MethodAnnotationVector* methods = annotations_directory->GetMethodAnnotations(); 597 dex_ir::ParameterAnnotationVector* parameters = annotations_directory->GetParameterAnnotations(); 598 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. 606 if (fields != nullptr) { 607 for (auto& field : *fields) { 608 const dex_ir::FieldId* field_id = field->GetFieldId(); 609 const uint32_t field_idx = field_id->GetIndex(); 610 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 } 614 } 615 616 // Annotations on methods. 617 if (methods != nullptr) { 618 for (auto& method : *methods) { 619 const dex_ir::MethodId* method_id = method->GetMethodId(); 620 const uint32_t method_idx = method_id->GetIndex(); 621 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 } 625 } 626 627 // Annotations on method parameters. 628 if (parameters != nullptr) { 629 for (auto& parameter : *parameters) { 630 const dex_ir::MethodId* method_id = parameter->GetMethodId(); 631 const uint32_t method_idx = method_id->GetIndex(); 632 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; 635 for (dex_ir::AnnotationSetItem* annotation : *parameter->GetAnnotations()->GetItems()) { 636 fprintf(out_file_, "#%u\n", j); 637 DumpAnnotationSetItem(annotation); 638 ++j; 639 } 640 } 641 } 642 643 fputc('\n', out_file_); 644} 645 646/* 647 * Dumps an interface that a class declares to implement. 648 */ 649static void DumpInterface(const dex_ir::TypeId* type_item, int i) { 650 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 { 654 std::string dot(DescriptorToDotWrapper(interface_name)); 655 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); 679 for (auto& handler : *try_item->GetHandlers()->GetHandlers()) { 680 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) { 726 static const uint32_t kInvalidIndex = std::numeric_limits<uint32_t>::max(); 727 std::unique_ptr<char[]> buf(new char[buf_size]); 728 // Determine index and width of the string. 729 uint32_t index = 0; 730 uint32_t secondary_index = kInvalidIndex; 731 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; 754 case Instruction::k45cc: 755 case Instruction::k4rcc: 756 index = dec_insn->VRegB(); 757 secondary_index = dec_insn->VRegH(); 758 width = 4; 759 break; 760 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: 778 if (index < header->GetCollections().TypeIdsSize()) { 779 const char* tp = header->GetCollections().GetTypeId(index)->GetStringId()->Data(); 780 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: 786 if (index < header->GetCollections().StringIdsSize()) { 787 const char* st = header->GetCollections().GetStringId(index)->Data(); 788 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: 794 if (index < header->GetCollections().MethodIdsSize()) { 795 dex_ir::MethodId* method_id = header->GetCollections().GetMethodId(index); 796 const char* name = method_id->Name()->Data(); 797 std::string type_descriptor = GetSignatureForProtoId(method_id->Proto()); 798 const char* back_descriptor = method_id->Class()->GetStringId()->Data(); 799 outSize = snprintf(buf.get(), buf_size, "%s.%s:%s // method@%0*x", 800 back_descriptor, name, type_descriptor.c_str(), width, index); 801 } else { 802 outSize = snprintf(buf.get(), buf_size, "<method?> // method@%0*x", width, index); 803 } 804 break; 805 case Instruction::kIndexFieldRef: 806 if (index < header->GetCollections().FieldIdsSize()) { 807 dex_ir::FieldId* field_id = header->GetCollections().GetFieldId(index); 808 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: 827 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; 845 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; 1014 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 1016 // 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 } 1032 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 1034 // 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) { 1078 dex_ir::MethodId* method_id = header->GetCollections().GetMethodId(idx); 1079 const char* name = method_id->Name()->Data(); 1080 std::string type_descriptor = GetSignatureForProtoId(method_id->Proto()); 1081 const char* back_descriptor = method_id->Class()->GetStringId()->Data(); 1082 1083 // Generate header. 1084 std::string dot(DescriptorToDotWrapper(back_descriptor)); 1085 fprintf(out_file_, "%06x: |[%06x] %s.%s:%s\n", 1086 code_offset, code_offset, dot.c_str(), name, type_descriptor.c_str()); 1087 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 1138 dex_ir::MethodId* method_id = header->GetCollections().GetMethodId(idx); 1139 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()); 1165 dot = DescriptorToDotWrapper(back_descriptor); 1166 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 } 1174 std::string dot(DescriptorToDotWrapper(return_type + 1)); 1175 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'; 1216 std::string dot(DescriptorToDotWrapper(tmp_buf)); 1217 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, 1237 int i, dex_ir::EncodedValue* init) { 1238 // Bail for anything private if export only requested. 1239 if (options_.exports_only_ && (flags & (kAccPublic | kAccProtected)) == 0) { 1240 return; 1241 } 1242 1243 dex_ir::FieldId* field_id = header->GetCollections().GetFieldId(idx); 1244 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); 1261 std::string dot(DescriptorToDotWrapper(type_descriptor)); 1262 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/* 1289 * 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 */ 1296static void DumpClass(dex_ir::Header* header, int idx, char** last_package) { 1297 dex_ir::ClassDef* class_def = header->GetCollections().GetClassDef(idx); 1298 // 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 1311 // 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. 1315 const char* class_descriptor = 1316 header->GetCollections().GetClassDef(idx)->ClassType()->GetStringId()->Data(); 1317 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) { 1371 dot = DescriptorToDotWrapper(superclass_descriptor); 1372 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. 1386 const dex_ir::TypeIdVector* interfaces = class_def->Interfaces(); 1387 if (interfaces != nullptr) { 1388 for (uint32_t i = 0; i < interfaces->size(); i++) { 1389 DumpInterface((*interfaces)[i], i); 1390 } // for 1391 } 1392 1393 // Fields and methods. 1394 dex_ir::ClassData* class_data = class_def->GetClassData(); 1395 // Prepare data for static fields. 1396 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(); 1400 1401 // Static fields. 1402 if (options_.output_format_ == kOutputPlain) { 1403 fprintf(out_file_, " Static fields -\n"); 1404 } 1405 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, 1410 (*static_fields)[i]->GetFieldId()->GetIndex(), 1411 (*static_fields)[i]->GetAccessFlags(), 1412 i, 1413 i < encoded_values_size ? (*encoded_values)[i].get() : nullptr); 1414 } // for 1415 } 1416 } 1417 1418 // Instance fields. 1419 if (options_.output_format_ == kOutputPlain) { 1420 fprintf(out_file_, " Instance fields -\n"); 1421 } 1422 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, 1427 (*instance_fields)[i]->GetFieldId()->GetIndex(), 1428 (*instance_fields)[i]->GetAccessFlags(), 1429 i); 1430 } // for 1431 } 1432 } 1433 1434 // Direct methods. 1435 if (options_.output_format_ == kOutputPlain) { 1436 fprintf(out_file_, " Direct methods -\n"); 1437 } 1438 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, 1443 (*direct_methods)[i]->GetMethodId()->GetIndex(), 1444 (*direct_methods)[i]->GetAccessFlags(), 1445 (*direct_methods)[i]->GetCodeItem(), 1446 i); 1447 } // for 1448 } 1449 } 1450 1451 // Virtual methods. 1452 if (options_.output_format_ == kOutputPlain) { 1453 fprintf(out_file_, " Virtual methods -\n"); 1454 } 1455 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, 1460 (*virtual_methods)[i]->GetMethodId()->GetIndex(), 1461 (*virtual_methods)[i]->GetAccessFlags(), 1462 (*virtual_methods)[i]->GetCodeItem(), 1463 i); 1464 } // for 1465 } 1466 } 1467 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", 1476 source_file == nullptr ? 0xffffffffU : source_file->GetIndex(), file_name); 1477 } 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 */ 1487static void ProcessDexFile(const char* file_name, const DexFile* dex_file, size_t dex_file_index) { 1488 if (options_.verbose_) { 1489 fprintf(out_file_, "Opened '%s', DEX version '%.3s'\n", 1490 file_name, dex_file->GetHeader().magic_ + 4); 1491 } 1492 std::unique_ptr<dex_ir::Header> header(dex_ir::DexIrBuilder(*dex_file)); 1493 1494 if (options_.visualize_pattern_) { 1495 VisualizeDexLayout(header.get(), dex_file, dex_file_index); 1496 return; 1497 } 1498 1499 // Headers. 1500 if (options_.show_file_headers_) { 1501 DumpFileHeader(header.get()); 1502 } 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; 1511 const uint32_t class_defs_size = header->GetCollections().ClassDefsSize(); 1512 for (uint32_t i = 0; i < class_defs_size; i++) { 1513 DumpClass(header.get(), i, &package); 1514 } // 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 } 1526 1527 // Output dex file. 1528 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()); 1533 } 1534} 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++) { 1563 ProcessDexFile(file_name, dex_files[i].get(), i); 1564 } 1565 } 1566 return 0; 1567} 1568 1569} // namespace art 1570