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