dexlayout.cc revision 219cb9021fa74af7773066ffb8fc77ac85f3d0de
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#include <sys/mman.h> // For the PROT_* and MAP_* constants. 28 29#include <iostream> 30#include <memory> 31#include <sstream> 32#include <vector> 33 34#include "android-base/stringprintf.h" 35 36#include "dex_file-inl.h" 37#include "dex_file_layout.h" 38#include "dex_file_loader.h" 39#include "dex_file_types.h" 40#include "dex_file_verifier.h" 41#include "dex_instruction-inl.h" 42#include "dex_ir_builder.h" 43#include "dex_verify.h" 44#include "dex_visualize.h" 45#include "dex_writer.h" 46#include "jit/profile_compilation_info.h" 47#include "mem_map.h" 48#include "os.h" 49#include "utils.h" 50 51namespace art { 52 53using android::base::StringPrintf; 54 55// Setting this to false disables class def layout entirely, which is stronger than strictly 56// necessary to ensure the partial order w.r.t. class derivation. TODO: Re-enable (b/68317550). 57static constexpr bool kChangeClassDefOrder = false; 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, FILE* out_file) { 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, FILE* out_file) { 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/* 363 * Helper for dumpInstruction(), which builds the string 364 * representation for the index in the given instruction. 365 * Returns a pointer to a buffer of sufficient size. 366 */ 367static std::unique_ptr<char[]> IndexString(dex_ir::Header* header, 368 const Instruction* dec_insn, 369 size_t buf_size) { 370 std::unique_ptr<char[]> buf(new char[buf_size]); 371 // Determine index and width of the string. 372 uint32_t index = 0; 373 uint32_t secondary_index = dex::kDexNoIndex; 374 uint32_t width = 4; 375 switch (Instruction::FormatOf(dec_insn->Opcode())) { 376 // SOME NOT SUPPORTED: 377 // case Instruction::k20bc: 378 case Instruction::k21c: 379 case Instruction::k35c: 380 // case Instruction::k35ms: 381 case Instruction::k3rc: 382 // case Instruction::k3rms: 383 // case Instruction::k35mi: 384 // case Instruction::k3rmi: 385 index = dec_insn->VRegB(); 386 width = 4; 387 break; 388 case Instruction::k31c: 389 index = dec_insn->VRegB(); 390 width = 8; 391 break; 392 case Instruction::k22c: 393 // case Instruction::k22cs: 394 index = dec_insn->VRegC(); 395 width = 4; 396 break; 397 case Instruction::k45cc: 398 case Instruction::k4rcc: 399 index = dec_insn->VRegB(); 400 secondary_index = dec_insn->VRegH(); 401 width = 4; 402 break; 403 default: 404 break; 405 } // switch 406 407 // Determine index type. 408 size_t outSize = 0; 409 switch (Instruction::IndexTypeOf(dec_insn->Opcode())) { 410 case Instruction::kIndexUnknown: 411 // This function should never get called for this type, but do 412 // something sensible here, just to help with debugging. 413 outSize = snprintf(buf.get(), buf_size, "<unknown-index>"); 414 break; 415 case Instruction::kIndexNone: 416 // This function should never get called for this type, but do 417 // something sensible here, just to help with debugging. 418 outSize = snprintf(buf.get(), buf_size, "<no-index>"); 419 break; 420 case Instruction::kIndexTypeRef: 421 if (index < header->GetCollections().TypeIdsSize()) { 422 const char* tp = header->GetCollections().GetTypeId(index)->GetStringId()->Data(); 423 outSize = snprintf(buf.get(), buf_size, "%s // type@%0*x", tp, width, index); 424 } else { 425 outSize = snprintf(buf.get(), buf_size, "<type?> // type@%0*x", width, index); 426 } 427 break; 428 case Instruction::kIndexStringRef: 429 if (index < header->GetCollections().StringIdsSize()) { 430 const char* st = header->GetCollections().GetStringId(index)->Data(); 431 outSize = snprintf(buf.get(), buf_size, "\"%s\" // string@%0*x", st, width, index); 432 } else { 433 outSize = snprintf(buf.get(), buf_size, "<string?> // string@%0*x", width, index); 434 } 435 break; 436 case Instruction::kIndexMethodRef: 437 if (index < header->GetCollections().MethodIdsSize()) { 438 dex_ir::MethodId* method_id = header->GetCollections().GetMethodId(index); 439 const char* name = method_id->Name()->Data(); 440 std::string type_descriptor = GetSignatureForProtoId(method_id->Proto()); 441 const char* back_descriptor = method_id->Class()->GetStringId()->Data(); 442 outSize = snprintf(buf.get(), buf_size, "%s.%s:%s // method@%0*x", 443 back_descriptor, name, type_descriptor.c_str(), width, index); 444 } else { 445 outSize = snprintf(buf.get(), buf_size, "<method?> // method@%0*x", width, index); 446 } 447 break; 448 case Instruction::kIndexFieldRef: 449 if (index < header->GetCollections().FieldIdsSize()) { 450 dex_ir::FieldId* field_id = header->GetCollections().GetFieldId(index); 451 const char* name = field_id->Name()->Data(); 452 const char* type_descriptor = field_id->Type()->GetStringId()->Data(); 453 const char* back_descriptor = field_id->Class()->GetStringId()->Data(); 454 outSize = snprintf(buf.get(), buf_size, "%s.%s:%s // field@%0*x", 455 back_descriptor, name, type_descriptor, width, index); 456 } else { 457 outSize = snprintf(buf.get(), buf_size, "<field?> // field@%0*x", width, index); 458 } 459 break; 460 case Instruction::kIndexVtableOffset: 461 outSize = snprintf(buf.get(), buf_size, "[%0*x] // vtable #%0*x", 462 width, index, width, index); 463 break; 464 case Instruction::kIndexFieldOffset: 465 outSize = snprintf(buf.get(), buf_size, "[obj+%0*x]", width, index); 466 break; 467 case Instruction::kIndexMethodAndProtoRef: { 468 std::string method("<method?>"); 469 std::string proto("<proto?>"); 470 if (index < header->GetCollections().MethodIdsSize()) { 471 dex_ir::MethodId* method_id = header->GetCollections().GetMethodId(index); 472 const char* name = method_id->Name()->Data(); 473 std::string type_descriptor = GetSignatureForProtoId(method_id->Proto()); 474 const char* back_descriptor = method_id->Class()->GetStringId()->Data(); 475 method = StringPrintf("%s.%s:%s", back_descriptor, name, type_descriptor.c_str()); 476 } 477 if (secondary_index < header->GetCollections().ProtoIdsSize()) { 478 dex_ir::ProtoId* proto_id = header->GetCollections().GetProtoId(secondary_index); 479 proto = GetSignatureForProtoId(proto_id); 480 } 481 outSize = snprintf(buf.get(), buf_size, "%s, %s // method@%0*x, proto@%0*x", 482 method.c_str(), proto.c_str(), width, index, width, secondary_index); 483 } 484 break; 485 // SOME NOT SUPPORTED: 486 // case Instruction::kIndexVaries: 487 // case Instruction::kIndexInlineMethod: 488 default: 489 outSize = snprintf(buf.get(), buf_size, "<?>"); 490 break; 491 } // switch 492 493 // Determine success of string construction. 494 if (outSize >= buf_size) { 495 // The buffer wasn't big enough; retry with computed size. Note: snprintf() 496 // doesn't count/ the '\0' as part of its returned size, so we add explicit 497 // space for it here. 498 return IndexString(header, dec_insn, outSize + 1); 499 } 500 return buf; 501} 502 503/* 504 * Dumps encoded annotation. 505 */ 506void DexLayout::DumpEncodedAnnotation(dex_ir::EncodedAnnotation* annotation) { 507 fputs(annotation->GetType()->GetStringId()->Data(), out_file_); 508 // Display all name=value pairs. 509 for (auto& subannotation : *annotation->GetAnnotationElements()) { 510 fputc(' ', out_file_); 511 fputs(subannotation->GetName()->Data(), out_file_); 512 fputc('=', out_file_); 513 DumpEncodedValue(subannotation->GetValue()); 514 } 515} 516/* 517 * Dumps encoded value. 518 */ 519void DexLayout::DumpEncodedValue(const dex_ir::EncodedValue* data) { 520 switch (data->Type()) { 521 case DexFile::kDexAnnotationByte: 522 fprintf(out_file_, "%" PRId8, data->GetByte()); 523 break; 524 case DexFile::kDexAnnotationShort: 525 fprintf(out_file_, "%" PRId16, data->GetShort()); 526 break; 527 case DexFile::kDexAnnotationChar: 528 fprintf(out_file_, "%" PRIu16, data->GetChar()); 529 break; 530 case DexFile::kDexAnnotationInt: 531 fprintf(out_file_, "%" PRId32, data->GetInt()); 532 break; 533 case DexFile::kDexAnnotationLong: 534 fprintf(out_file_, "%" PRId64, data->GetLong()); 535 break; 536 case DexFile::kDexAnnotationFloat: { 537 fprintf(out_file_, "%g", data->GetFloat()); 538 break; 539 } 540 case DexFile::kDexAnnotationDouble: { 541 fprintf(out_file_, "%g", data->GetDouble()); 542 break; 543 } 544 case DexFile::kDexAnnotationString: { 545 dex_ir::StringId* string_id = data->GetStringId(); 546 if (options_.output_format_ == kOutputPlain) { 547 DumpEscapedString(string_id->Data(), out_file_); 548 } else { 549 DumpXmlAttribute(string_id->Data(), out_file_); 550 } 551 break; 552 } 553 case DexFile::kDexAnnotationType: { 554 dex_ir::TypeId* type_id = data->GetTypeId(); 555 fputs(type_id->GetStringId()->Data(), out_file_); 556 break; 557 } 558 case DexFile::kDexAnnotationField: 559 case DexFile::kDexAnnotationEnum: { 560 dex_ir::FieldId* field_id = data->GetFieldId(); 561 fputs(field_id->Name()->Data(), out_file_); 562 break; 563 } 564 case DexFile::kDexAnnotationMethod: { 565 dex_ir::MethodId* method_id = data->GetMethodId(); 566 fputs(method_id->Name()->Data(), out_file_); 567 break; 568 } 569 case DexFile::kDexAnnotationArray: { 570 fputc('{', out_file_); 571 // Display all elements. 572 for (auto& value : *data->GetEncodedArray()->GetEncodedValues()) { 573 fputc(' ', out_file_); 574 DumpEncodedValue(value.get()); 575 } 576 fputs(" }", out_file_); 577 break; 578 } 579 case DexFile::kDexAnnotationAnnotation: { 580 DumpEncodedAnnotation(data->GetEncodedAnnotation()); 581 break; 582 } 583 case DexFile::kDexAnnotationNull: 584 fputs("null", out_file_); 585 break; 586 case DexFile::kDexAnnotationBoolean: 587 fputs(StrBool(data->GetBoolean()), out_file_); 588 break; 589 default: 590 fputs("????", out_file_); 591 break; 592 } // switch 593} 594 595/* 596 * Dumps the file header. 597 */ 598void DexLayout::DumpFileHeader() { 599 char sanitized[8 * 2 + 1]; 600 dex_ir::Collections& collections = header_->GetCollections(); 601 fprintf(out_file_, "DEX file header:\n"); 602 Asciify(sanitized, header_->Magic(), 8); 603 fprintf(out_file_, "magic : '%s'\n", sanitized); 604 fprintf(out_file_, "checksum : %08x\n", header_->Checksum()); 605 fprintf(out_file_, "signature : %02x%02x...%02x%02x\n", 606 header_->Signature()[0], header_->Signature()[1], 607 header_->Signature()[DexFile::kSha1DigestSize - 2], 608 header_->Signature()[DexFile::kSha1DigestSize - 1]); 609 fprintf(out_file_, "file_size : %d\n", header_->FileSize()); 610 fprintf(out_file_, "header_size : %d\n", header_->HeaderSize()); 611 fprintf(out_file_, "link_size : %d\n", header_->LinkSize()); 612 fprintf(out_file_, "link_off : %d (0x%06x)\n", 613 header_->LinkOffset(), header_->LinkOffset()); 614 fprintf(out_file_, "string_ids_size : %d\n", collections.StringIdsSize()); 615 fprintf(out_file_, "string_ids_off : %d (0x%06x)\n", 616 collections.StringIdsOffset(), collections.StringIdsOffset()); 617 fprintf(out_file_, "type_ids_size : %d\n", collections.TypeIdsSize()); 618 fprintf(out_file_, "type_ids_off : %d (0x%06x)\n", 619 collections.TypeIdsOffset(), collections.TypeIdsOffset()); 620 fprintf(out_file_, "proto_ids_size : %d\n", collections.ProtoIdsSize()); 621 fprintf(out_file_, "proto_ids_off : %d (0x%06x)\n", 622 collections.ProtoIdsOffset(), collections.ProtoIdsOffset()); 623 fprintf(out_file_, "field_ids_size : %d\n", collections.FieldIdsSize()); 624 fprintf(out_file_, "field_ids_off : %d (0x%06x)\n", 625 collections.FieldIdsOffset(), collections.FieldIdsOffset()); 626 fprintf(out_file_, "method_ids_size : %d\n", collections.MethodIdsSize()); 627 fprintf(out_file_, "method_ids_off : %d (0x%06x)\n", 628 collections.MethodIdsOffset(), collections.MethodIdsOffset()); 629 fprintf(out_file_, "class_defs_size : %d\n", collections.ClassDefsSize()); 630 fprintf(out_file_, "class_defs_off : %d (0x%06x)\n", 631 collections.ClassDefsOffset(), collections.ClassDefsOffset()); 632 fprintf(out_file_, "data_size : %d\n", header_->DataSize()); 633 fprintf(out_file_, "data_off : %d (0x%06x)\n\n", 634 header_->DataOffset(), header_->DataOffset()); 635} 636 637/* 638 * Dumps a class_def_item. 639 */ 640void DexLayout::DumpClassDef(int idx) { 641 // General class information. 642 dex_ir::ClassDef* class_def = header_->GetCollections().GetClassDef(idx); 643 fprintf(out_file_, "Class #%d header:\n", idx); 644 fprintf(out_file_, "class_idx : %d\n", class_def->ClassType()->GetIndex()); 645 fprintf(out_file_, "access_flags : %d (0x%04x)\n", 646 class_def->GetAccessFlags(), class_def->GetAccessFlags()); 647 uint32_t superclass_idx = class_def->Superclass() == nullptr ? 648 DexFile::kDexNoIndex16 : class_def->Superclass()->GetIndex(); 649 fprintf(out_file_, "superclass_idx : %d\n", superclass_idx); 650 fprintf(out_file_, "interfaces_off : %d (0x%06x)\n", 651 class_def->InterfacesOffset(), class_def->InterfacesOffset()); 652 uint32_t source_file_offset = 0xffffffffU; 653 if (class_def->SourceFile() != nullptr) { 654 source_file_offset = class_def->SourceFile()->GetIndex(); 655 } 656 fprintf(out_file_, "source_file_idx : %d\n", source_file_offset); 657 uint32_t annotations_offset = 0; 658 if (class_def->Annotations() != nullptr) { 659 annotations_offset = class_def->Annotations()->GetOffset(); 660 } 661 fprintf(out_file_, "annotations_off : %d (0x%06x)\n", 662 annotations_offset, annotations_offset); 663 if (class_def->GetClassData() == nullptr) { 664 fprintf(out_file_, "class_data_off : %d (0x%06x)\n", 0, 0); 665 } else { 666 fprintf(out_file_, "class_data_off : %d (0x%06x)\n", 667 class_def->GetClassData()->GetOffset(), class_def->GetClassData()->GetOffset()); 668 } 669 670 // Fields and methods. 671 dex_ir::ClassData* class_data = class_def->GetClassData(); 672 if (class_data != nullptr && class_data->StaticFields() != nullptr) { 673 fprintf(out_file_, "static_fields_size : %zu\n", class_data->StaticFields()->size()); 674 } else { 675 fprintf(out_file_, "static_fields_size : 0\n"); 676 } 677 if (class_data != nullptr && class_data->InstanceFields() != nullptr) { 678 fprintf(out_file_, "instance_fields_size: %zu\n", class_data->InstanceFields()->size()); 679 } else { 680 fprintf(out_file_, "instance_fields_size: 0\n"); 681 } 682 if (class_data != nullptr && class_data->DirectMethods() != nullptr) { 683 fprintf(out_file_, "direct_methods_size : %zu\n", class_data->DirectMethods()->size()); 684 } else { 685 fprintf(out_file_, "direct_methods_size : 0\n"); 686 } 687 if (class_data != nullptr && class_data->VirtualMethods() != nullptr) { 688 fprintf(out_file_, "virtual_methods_size: %zu\n", class_data->VirtualMethods()->size()); 689 } else { 690 fprintf(out_file_, "virtual_methods_size: 0\n"); 691 } 692 fprintf(out_file_, "\n"); 693} 694 695/** 696 * Dumps an annotation set item. 697 */ 698void DexLayout::DumpAnnotationSetItem(dex_ir::AnnotationSetItem* set_item) { 699 if (set_item == nullptr || set_item->GetItems()->size() == 0) { 700 fputs(" empty-annotation-set\n", out_file_); 701 return; 702 } 703 for (dex_ir::AnnotationItem* annotation : *set_item->GetItems()) { 704 if (annotation == nullptr) { 705 continue; 706 } 707 fputs(" ", out_file_); 708 switch (annotation->GetVisibility()) { 709 case DexFile::kDexVisibilityBuild: fputs("VISIBILITY_BUILD ", out_file_); break; 710 case DexFile::kDexVisibilityRuntime: fputs("VISIBILITY_RUNTIME ", out_file_); break; 711 case DexFile::kDexVisibilitySystem: fputs("VISIBILITY_SYSTEM ", out_file_); break; 712 default: fputs("VISIBILITY_UNKNOWN ", out_file_); break; 713 } // switch 714 DumpEncodedAnnotation(annotation->GetAnnotation()); 715 fputc('\n', out_file_); 716 } 717} 718 719/* 720 * Dumps class annotations. 721 */ 722void DexLayout::DumpClassAnnotations(int idx) { 723 dex_ir::ClassDef* class_def = header_->GetCollections().GetClassDef(idx); 724 dex_ir::AnnotationsDirectoryItem* annotations_directory = class_def->Annotations(); 725 if (annotations_directory == nullptr) { 726 return; // none 727 } 728 729 fprintf(out_file_, "Class #%d annotations:\n", idx); 730 731 dex_ir::AnnotationSetItem* class_set_item = annotations_directory->GetClassAnnotation(); 732 dex_ir::FieldAnnotationVector* fields = annotations_directory->GetFieldAnnotations(); 733 dex_ir::MethodAnnotationVector* methods = annotations_directory->GetMethodAnnotations(); 734 dex_ir::ParameterAnnotationVector* parameters = annotations_directory->GetParameterAnnotations(); 735 736 // Annotations on the class itself. 737 if (class_set_item != nullptr) { 738 fprintf(out_file_, "Annotations on class\n"); 739 DumpAnnotationSetItem(class_set_item); 740 } 741 742 // Annotations on fields. 743 if (fields != nullptr) { 744 for (auto& field : *fields) { 745 const dex_ir::FieldId* field_id = field->GetFieldId(); 746 const uint32_t field_idx = field_id->GetIndex(); 747 const char* field_name = field_id->Name()->Data(); 748 fprintf(out_file_, "Annotations on field #%u '%s'\n", field_idx, field_name); 749 DumpAnnotationSetItem(field->GetAnnotationSetItem()); 750 } 751 } 752 753 // Annotations on methods. 754 if (methods != nullptr) { 755 for (auto& method : *methods) { 756 const dex_ir::MethodId* method_id = method->GetMethodId(); 757 const uint32_t method_idx = method_id->GetIndex(); 758 const char* method_name = method_id->Name()->Data(); 759 fprintf(out_file_, "Annotations on method #%u '%s'\n", method_idx, method_name); 760 DumpAnnotationSetItem(method->GetAnnotationSetItem()); 761 } 762 } 763 764 // Annotations on method parameters. 765 if (parameters != nullptr) { 766 for (auto& parameter : *parameters) { 767 const dex_ir::MethodId* method_id = parameter->GetMethodId(); 768 const uint32_t method_idx = method_id->GetIndex(); 769 const char* method_name = method_id->Name()->Data(); 770 fprintf(out_file_, "Annotations on method #%u '%s' parameters\n", method_idx, method_name); 771 uint32_t j = 0; 772 for (dex_ir::AnnotationSetItem* annotation : *parameter->GetAnnotations()->GetItems()) { 773 fprintf(out_file_, "#%u\n", j); 774 DumpAnnotationSetItem(annotation); 775 ++j; 776 } 777 } 778 } 779 780 fputc('\n', out_file_); 781} 782 783/* 784 * Dumps an interface that a class declares to implement. 785 */ 786void DexLayout::DumpInterface(const dex_ir::TypeId* type_item, int i) { 787 const char* interface_name = type_item->GetStringId()->Data(); 788 if (options_.output_format_ == kOutputPlain) { 789 fprintf(out_file_, " #%d : '%s'\n", i, interface_name); 790 } else { 791 std::string dot(DescriptorToDotWrapper(interface_name)); 792 fprintf(out_file_, "<implements name=\"%s\">\n</implements>\n", dot.c_str()); 793 } 794} 795 796/* 797 * Dumps the catches table associated with the code. 798 */ 799void DexLayout::DumpCatches(const dex_ir::CodeItem* code) { 800 const uint16_t tries_size = code->TriesSize(); 801 802 // No catch table. 803 if (tries_size == 0) { 804 fprintf(out_file_, " catches : (none)\n"); 805 return; 806 } 807 808 // Dump all table entries. 809 fprintf(out_file_, " catches : %d\n", tries_size); 810 std::vector<std::unique_ptr<const dex_ir::TryItem>>* tries = code->Tries(); 811 for (uint32_t i = 0; i < tries_size; i++) { 812 const dex_ir::TryItem* try_item = (*tries)[i].get(); 813 const uint32_t start = try_item->StartAddr(); 814 const uint32_t end = start + try_item->InsnCount(); 815 fprintf(out_file_, " 0x%04x - 0x%04x\n", start, end); 816 for (auto& handler : *try_item->GetHandlers()->GetHandlers()) { 817 const dex_ir::TypeId* type_id = handler->GetTypeId(); 818 const char* descriptor = (type_id == nullptr) ? "<any>" : type_id->GetStringId()->Data(); 819 fprintf(out_file_, " %s -> 0x%04x\n", descriptor, handler->GetAddress()); 820 } // for 821 } // for 822} 823 824/* 825 * Dumps a single instruction. 826 */ 827void DexLayout::DumpInstruction(const dex_ir::CodeItem* code, 828 uint32_t code_offset, 829 uint32_t insn_idx, 830 uint32_t insn_width, 831 const Instruction* dec_insn) { 832 // Address of instruction (expressed as byte offset). 833 fprintf(out_file_, "%06x:", code_offset + 0x10 + insn_idx * 2); 834 835 // Dump (part of) raw bytes. 836 const uint16_t* insns = code->Insns(); 837 for (uint32_t i = 0; i < 8; i++) { 838 if (i < insn_width) { 839 if (i == 7) { 840 fprintf(out_file_, " ... "); 841 } else { 842 // Print 16-bit value in little-endian order. 843 const uint8_t* bytePtr = (const uint8_t*) &insns[insn_idx + i]; 844 fprintf(out_file_, " %02x%02x", bytePtr[0], bytePtr[1]); 845 } 846 } else { 847 fputs(" ", out_file_); 848 } 849 } // for 850 851 // Dump pseudo-instruction or opcode. 852 if (dec_insn->Opcode() == Instruction::NOP) { 853 const uint16_t instr = Get2LE((const uint8_t*) &insns[insn_idx]); 854 if (instr == Instruction::kPackedSwitchSignature) { 855 fprintf(out_file_, "|%04x: packed-switch-data (%d units)", insn_idx, insn_width); 856 } else if (instr == Instruction::kSparseSwitchSignature) { 857 fprintf(out_file_, "|%04x: sparse-switch-data (%d units)", insn_idx, insn_width); 858 } else if (instr == Instruction::kArrayDataSignature) { 859 fprintf(out_file_, "|%04x: array-data (%d units)", insn_idx, insn_width); 860 } else { 861 fprintf(out_file_, "|%04x: nop // spacer", insn_idx); 862 } 863 } else { 864 fprintf(out_file_, "|%04x: %s", insn_idx, dec_insn->Name()); 865 } 866 867 // Set up additional argument. 868 std::unique_ptr<char[]> index_buf; 869 if (Instruction::IndexTypeOf(dec_insn->Opcode()) != Instruction::kIndexNone) { 870 index_buf = IndexString(header_, dec_insn, 200); 871 } 872 873 // Dump the instruction. 874 // 875 // NOTE: pDecInsn->DumpString(pDexFile) differs too much from original. 876 // 877 switch (Instruction::FormatOf(dec_insn->Opcode())) { 878 case Instruction::k10x: // op 879 break; 880 case Instruction::k12x: // op vA, vB 881 fprintf(out_file_, " v%d, v%d", dec_insn->VRegA(), dec_insn->VRegB()); 882 break; 883 case Instruction::k11n: // op vA, #+B 884 fprintf(out_file_, " v%d, #int %d // #%x", 885 dec_insn->VRegA(), (int32_t) dec_insn->VRegB(), (uint8_t)dec_insn->VRegB()); 886 break; 887 case Instruction::k11x: // op vAA 888 fprintf(out_file_, " v%d", dec_insn->VRegA()); 889 break; 890 case Instruction::k10t: // op +AA 891 case Instruction::k20t: { // op +AAAA 892 const int32_t targ = (int32_t) dec_insn->VRegA(); 893 fprintf(out_file_, " %04x // %c%04x", 894 insn_idx + targ, 895 (targ < 0) ? '-' : '+', 896 (targ < 0) ? -targ : targ); 897 break; 898 } 899 case Instruction::k22x: // op vAA, vBBBB 900 fprintf(out_file_, " v%d, v%d", dec_insn->VRegA(), dec_insn->VRegB()); 901 break; 902 case Instruction::k21t: { // op vAA, +BBBB 903 const int32_t targ = (int32_t) dec_insn->VRegB(); 904 fprintf(out_file_, " v%d, %04x // %c%04x", dec_insn->VRegA(), 905 insn_idx + targ, 906 (targ < 0) ? '-' : '+', 907 (targ < 0) ? -targ : targ); 908 break; 909 } 910 case Instruction::k21s: // op vAA, #+BBBB 911 fprintf(out_file_, " v%d, #int %d // #%x", 912 dec_insn->VRegA(), (int32_t) dec_insn->VRegB(), (uint16_t)dec_insn->VRegB()); 913 break; 914 case Instruction::k21h: // op vAA, #+BBBB0000[00000000] 915 // The printed format varies a bit based on the actual opcode. 916 if (dec_insn->Opcode() == Instruction::CONST_HIGH16) { 917 const int32_t value = dec_insn->VRegB() << 16; 918 fprintf(out_file_, " v%d, #int %d // #%x", 919 dec_insn->VRegA(), value, (uint16_t) dec_insn->VRegB()); 920 } else { 921 const int64_t value = ((int64_t) dec_insn->VRegB()) << 48; 922 fprintf(out_file_, " v%d, #long %" PRId64 " // #%x", 923 dec_insn->VRegA(), value, (uint16_t) dec_insn->VRegB()); 924 } 925 break; 926 case Instruction::k21c: // op vAA, thing@BBBB 927 case Instruction::k31c: // op vAA, thing@BBBBBBBB 928 fprintf(out_file_, " v%d, %s", dec_insn->VRegA(), index_buf.get()); 929 break; 930 case Instruction::k23x: // op vAA, vBB, vCC 931 fprintf(out_file_, " v%d, v%d, v%d", 932 dec_insn->VRegA(), dec_insn->VRegB(), dec_insn->VRegC()); 933 break; 934 case Instruction::k22b: // op vAA, vBB, #+CC 935 fprintf(out_file_, " v%d, v%d, #int %d // #%02x", 936 dec_insn->VRegA(), dec_insn->VRegB(), 937 (int32_t) dec_insn->VRegC(), (uint8_t) dec_insn->VRegC()); 938 break; 939 case Instruction::k22t: { // op vA, vB, +CCCC 940 const int32_t targ = (int32_t) dec_insn->VRegC(); 941 fprintf(out_file_, " v%d, v%d, %04x // %c%04x", 942 dec_insn->VRegA(), dec_insn->VRegB(), 943 insn_idx + targ, 944 (targ < 0) ? '-' : '+', 945 (targ < 0) ? -targ : targ); 946 break; 947 } 948 case Instruction::k22s: // op vA, vB, #+CCCC 949 fprintf(out_file_, " v%d, v%d, #int %d // #%04x", 950 dec_insn->VRegA(), dec_insn->VRegB(), 951 (int32_t) dec_insn->VRegC(), (uint16_t) dec_insn->VRegC()); 952 break; 953 case Instruction::k22c: // op vA, vB, thing@CCCC 954 // NOT SUPPORTED: 955 // case Instruction::k22cs: // [opt] op vA, vB, field offset CCCC 956 fprintf(out_file_, " v%d, v%d, %s", 957 dec_insn->VRegA(), dec_insn->VRegB(), index_buf.get()); 958 break; 959 case Instruction::k30t: 960 fprintf(out_file_, " #%08x", dec_insn->VRegA()); 961 break; 962 case Instruction::k31i: { // op vAA, #+BBBBBBBB 963 // This is often, but not always, a float. 964 union { 965 float f; 966 uint32_t i; 967 } conv; 968 conv.i = dec_insn->VRegB(); 969 fprintf(out_file_, " v%d, #float %g // #%08x", 970 dec_insn->VRegA(), conv.f, dec_insn->VRegB()); 971 break; 972 } 973 case Instruction::k31t: // op vAA, offset +BBBBBBBB 974 fprintf(out_file_, " v%d, %08x // +%08x", 975 dec_insn->VRegA(), insn_idx + dec_insn->VRegB(), dec_insn->VRegB()); 976 break; 977 case Instruction::k32x: // op vAAAA, vBBBB 978 fprintf(out_file_, " v%d, v%d", dec_insn->VRegA(), dec_insn->VRegB()); 979 break; 980 case Instruction::k35c: // op {vC, vD, vE, vF, vG}, thing@BBBB 981 case Instruction::k45cc: { // op {vC, vD, vE, vF, vG}, meth@BBBB, proto@HHHH 982 // NOT SUPPORTED: 983 // case Instruction::k35ms: // [opt] invoke-virtual+super 984 // case Instruction::k35mi: // [opt] inline invoke 985 uint32_t arg[Instruction::kMaxVarArgRegs]; 986 dec_insn->GetVarArgs(arg); 987 fputs(" {", out_file_); 988 for (int i = 0, n = dec_insn->VRegA(); i < n; i++) { 989 if (i == 0) { 990 fprintf(out_file_, "v%d", arg[i]); 991 } else { 992 fprintf(out_file_, ", v%d", arg[i]); 993 } 994 } // for 995 fprintf(out_file_, "}, %s", index_buf.get()); 996 break; 997 } 998 case Instruction::k3rc: // op {vCCCC .. v(CCCC+AA-1)}, thing@BBBB 999 case Instruction::k4rcc: // op {vCCCC .. v(CCCC+AA-1)}, meth@BBBB, proto@HHHH 1000 // NOT SUPPORTED: 1001 // case Instruction::k3rms: // [opt] invoke-virtual+super/range 1002 // case Instruction::k3rmi: // [opt] execute-inline/range 1003 { 1004 // This doesn't match the "dx" output when some of the args are 1005 // 64-bit values -- dx only shows the first register. 1006 fputs(" {", out_file_); 1007 for (int i = 0, n = dec_insn->VRegA(); i < n; i++) { 1008 if (i == 0) { 1009 fprintf(out_file_, "v%d", dec_insn->VRegC() + i); 1010 } else { 1011 fprintf(out_file_, ", v%d", dec_insn->VRegC() + i); 1012 } 1013 } // for 1014 fprintf(out_file_, "}, %s", index_buf.get()); 1015 } 1016 break; 1017 case Instruction::k51l: { // op vAA, #+BBBBBBBBBBBBBBBB 1018 // This is often, but not always, a double. 1019 union { 1020 double d; 1021 uint64_t j; 1022 } conv; 1023 conv.j = dec_insn->WideVRegB(); 1024 fprintf(out_file_, " v%d, #double %g // #%016" PRIx64, 1025 dec_insn->VRegA(), conv.d, dec_insn->WideVRegB()); 1026 break; 1027 } 1028 // NOT SUPPORTED: 1029 // case Instruction::k00x: // unknown op or breakpoint 1030 // break; 1031 default: 1032 fprintf(out_file_, " ???"); 1033 break; 1034 } // switch 1035 1036 fputc('\n', out_file_); 1037} 1038 1039/* 1040 * Dumps a bytecode disassembly. 1041 */ 1042void DexLayout::DumpBytecodes(uint32_t idx, const dex_ir::CodeItem* code, uint32_t code_offset) { 1043 dex_ir::MethodId* method_id = header_->GetCollections().GetMethodId(idx); 1044 const char* name = method_id->Name()->Data(); 1045 std::string type_descriptor = GetSignatureForProtoId(method_id->Proto()); 1046 const char* back_descriptor = method_id->Class()->GetStringId()->Data(); 1047 1048 // Generate header. 1049 std::string dot(DescriptorToDotWrapper(back_descriptor)); 1050 fprintf(out_file_, "%06x: |[%06x] %s.%s:%s\n", 1051 code_offset, code_offset, dot.c_str(), name, type_descriptor.c_str()); 1052 1053 // Iterate over all instructions. 1054 for (const DexInstructionPcPair& inst : code->Instructions()) { 1055 const uint32_t insn_width = inst->SizeInCodeUnits(); 1056 if (insn_width == 0) { 1057 fprintf(stderr, "GLITCH: zero-width instruction at idx=0x%04x\n", inst.DexPc()); 1058 break; 1059 } 1060 DumpInstruction(code, code_offset, inst.DexPc(), insn_width, &inst.Inst()); 1061 } // for 1062} 1063 1064/* 1065 * Callback for dumping each positions table entry. 1066 */ 1067static bool DumpPositionsCb(void* context, const DexFile::PositionInfo& entry) { 1068 FILE* out_file = reinterpret_cast<FILE*>(context); 1069 fprintf(out_file, " 0x%04x line=%d\n", entry.address_, entry.line_); 1070 return false; 1071} 1072 1073/* 1074 * Callback for dumping locals table entry. 1075 */ 1076static void DumpLocalsCb(void* context, const DexFile::LocalInfo& entry) { 1077 const char* signature = entry.signature_ != nullptr ? entry.signature_ : ""; 1078 FILE* out_file = reinterpret_cast<FILE*>(context); 1079 fprintf(out_file, " 0x%04x - 0x%04x reg=%d %s %s %s\n", 1080 entry.start_address_, entry.end_address_, entry.reg_, 1081 entry.name_, entry.descriptor_, signature); 1082} 1083 1084/* 1085 * Lookup functions. 1086 */ 1087static const char* StringDataByIdx(uint32_t idx, dex_ir::Collections& collections) { 1088 dex_ir::StringId* string_id = collections.GetStringIdOrNullPtr(idx); 1089 if (string_id == nullptr) { 1090 return nullptr; 1091 } 1092 return string_id->Data(); 1093} 1094 1095static const char* StringDataByTypeIdx(uint16_t idx, dex_ir::Collections& collections) { 1096 dex_ir::TypeId* type_id = collections.GetTypeIdOrNullPtr(idx); 1097 if (type_id == nullptr) { 1098 return nullptr; 1099 } 1100 dex_ir::StringId* string_id = type_id->GetStringId(); 1101 if (string_id == nullptr) { 1102 return nullptr; 1103 } 1104 return string_id->Data(); 1105} 1106 1107 1108/* 1109 * Dumps code of a method. 1110 */ 1111void DexLayout::DumpCode(uint32_t idx, 1112 const dex_ir::CodeItem* code, 1113 uint32_t code_offset, 1114 const char* declaring_class_descriptor, 1115 const char* method_name, 1116 bool is_static, 1117 const dex_ir::ProtoId* proto) { 1118 fprintf(out_file_, " registers : %d\n", code->RegistersSize()); 1119 fprintf(out_file_, " ins : %d\n", code->InsSize()); 1120 fprintf(out_file_, " outs : %d\n", code->OutsSize()); 1121 fprintf(out_file_, " insns size : %d 16-bit code units\n", 1122 code->InsnsSize()); 1123 1124 // Bytecode disassembly, if requested. 1125 if (options_.disassemble_) { 1126 DumpBytecodes(idx, code, code_offset); 1127 } 1128 1129 // Try-catch blocks. 1130 DumpCatches(code); 1131 1132 // Positions and locals table in the debug info. 1133 dex_ir::DebugInfoItem* debug_info = code->DebugInfo(); 1134 fprintf(out_file_, " positions : \n"); 1135 if (debug_info != nullptr) { 1136 DexFile::DecodeDebugPositionInfo(debug_info->GetDebugInfo(), 1137 [this](uint32_t idx) { 1138 return StringDataByIdx(idx, this->header_->GetCollections()); 1139 }, 1140 DumpPositionsCb, 1141 out_file_); 1142 } 1143 fprintf(out_file_, " locals : \n"); 1144 if (debug_info != nullptr) { 1145 std::vector<const char*> arg_descriptors; 1146 const dex_ir::TypeList* parameters = proto->Parameters(); 1147 if (parameters != nullptr) { 1148 const dex_ir::TypeIdVector* parameter_type_vector = parameters->GetTypeList(); 1149 if (parameter_type_vector != nullptr) { 1150 for (const dex_ir::TypeId* type_id : *parameter_type_vector) { 1151 arg_descriptors.push_back(type_id->GetStringId()->Data()); 1152 } 1153 } 1154 } 1155 DexFile::DecodeDebugLocalInfo(debug_info->GetDebugInfo(), 1156 "DexLayout in-memory", 1157 declaring_class_descriptor, 1158 arg_descriptors, 1159 method_name, 1160 is_static, 1161 code->RegistersSize(), 1162 code->InsSize(), 1163 code->InsnsSize(), 1164 [this](uint32_t idx) { 1165 return StringDataByIdx(idx, this->header_->GetCollections()); 1166 }, 1167 [this](uint32_t idx) { 1168 return 1169 StringDataByTypeIdx(dchecked_integral_cast<uint16_t>(idx), 1170 this->header_->GetCollections()); 1171 }, 1172 DumpLocalsCb, 1173 out_file_); 1174 } 1175} 1176 1177/* 1178 * Dumps a method. 1179 */ 1180void DexLayout::DumpMethod(uint32_t idx, uint32_t flags, const dex_ir::CodeItem* code, int i) { 1181 // Bail for anything private if export only requested. 1182 if (options_.exports_only_ && (flags & (kAccPublic | kAccProtected)) == 0) { 1183 return; 1184 } 1185 1186 dex_ir::MethodId* method_id = header_->GetCollections().GetMethodId(idx); 1187 const char* name = method_id->Name()->Data(); 1188 char* type_descriptor = strdup(GetSignatureForProtoId(method_id->Proto()).c_str()); 1189 const char* back_descriptor = method_id->Class()->GetStringId()->Data(); 1190 char* access_str = CreateAccessFlagStr(flags, kAccessForMethod); 1191 1192 if (options_.output_format_ == kOutputPlain) { 1193 fprintf(out_file_, " #%d : (in %s)\n", i, back_descriptor); 1194 fprintf(out_file_, " name : '%s'\n", name); 1195 fprintf(out_file_, " type : '%s'\n", type_descriptor); 1196 fprintf(out_file_, " access : 0x%04x (%s)\n", flags, access_str); 1197 if (code == nullptr) { 1198 fprintf(out_file_, " code : (none)\n"); 1199 } else { 1200 fprintf(out_file_, " code -\n"); 1201 DumpCode(idx, 1202 code, 1203 code->GetOffset(), 1204 back_descriptor, 1205 name, 1206 (flags & kAccStatic) != 0, 1207 method_id->Proto()); 1208 } 1209 if (options_.disassemble_) { 1210 fputc('\n', out_file_); 1211 } 1212 } else if (options_.output_format_ == kOutputXml) { 1213 const bool constructor = (name[0] == '<'); 1214 1215 // Method name and prototype. 1216 if (constructor) { 1217 std::string dot(DescriptorClassToDot(back_descriptor)); 1218 fprintf(out_file_, "<constructor name=\"%s\"\n", dot.c_str()); 1219 dot = DescriptorToDotWrapper(back_descriptor); 1220 fprintf(out_file_, " type=\"%s\"\n", dot.c_str()); 1221 } else { 1222 fprintf(out_file_, "<method name=\"%s\"\n", name); 1223 const char* return_type = strrchr(type_descriptor, ')'); 1224 if (return_type == nullptr) { 1225 fprintf(stderr, "bad method type descriptor '%s'\n", type_descriptor); 1226 goto bail; 1227 } 1228 std::string dot(DescriptorToDotWrapper(return_type + 1)); 1229 fprintf(out_file_, " return=\"%s\"\n", dot.c_str()); 1230 fprintf(out_file_, " abstract=%s\n", QuotedBool((flags & kAccAbstract) != 0)); 1231 fprintf(out_file_, " native=%s\n", QuotedBool((flags & kAccNative) != 0)); 1232 fprintf(out_file_, " synchronized=%s\n", QuotedBool( 1233 (flags & (kAccSynchronized | kAccDeclaredSynchronized)) != 0)); 1234 } 1235 1236 // Additional method flags. 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=" not knowable w/o parsing annotations. 1240 fprintf(out_file_, " visibility=%s\n>\n", QuotedVisibility(flags)); 1241 1242 // Parameters. 1243 if (type_descriptor[0] != '(') { 1244 fprintf(stderr, "ERROR: bad descriptor '%s'\n", type_descriptor); 1245 goto bail; 1246 } 1247 char* tmp_buf = reinterpret_cast<char*>(malloc(strlen(type_descriptor) + 1)); 1248 const char* base = type_descriptor + 1; 1249 int arg_num = 0; 1250 while (*base != ')') { 1251 char* cp = tmp_buf; 1252 while (*base == '[') { 1253 *cp++ = *base++; 1254 } 1255 if (*base == 'L') { 1256 // Copy through ';'. 1257 do { 1258 *cp = *base++; 1259 } while (*cp++ != ';'); 1260 } else { 1261 // Primitive char, copy it. 1262 if (strchr("ZBCSIFJD", *base) == nullptr) { 1263 fprintf(stderr, "ERROR: bad method signature '%s'\n", base); 1264 break; // while 1265 } 1266 *cp++ = *base++; 1267 } 1268 // Null terminate and display. 1269 *cp++ = '\0'; 1270 std::string dot(DescriptorToDotWrapper(tmp_buf)); 1271 fprintf(out_file_, "<parameter name=\"arg%d\" type=\"%s\">\n" 1272 "</parameter>\n", arg_num++, dot.c_str()); 1273 } // while 1274 free(tmp_buf); 1275 if (constructor) { 1276 fprintf(out_file_, "</constructor>\n"); 1277 } else { 1278 fprintf(out_file_, "</method>\n"); 1279 } 1280 } 1281 1282 bail: 1283 free(type_descriptor); 1284 free(access_str); 1285} 1286 1287/* 1288 * Dumps a static (class) field. 1289 */ 1290void DexLayout::DumpSField(uint32_t idx, uint32_t flags, int i, dex_ir::EncodedValue* init) { 1291 // Bail for anything private if export only requested. 1292 if (options_.exports_only_ && (flags & (kAccPublic | kAccProtected)) == 0) { 1293 return; 1294 } 1295 1296 dex_ir::FieldId* field_id = header_->GetCollections().GetFieldId(idx); 1297 const char* name = field_id->Name()->Data(); 1298 const char* type_descriptor = field_id->Type()->GetStringId()->Data(); 1299 const char* back_descriptor = field_id->Class()->GetStringId()->Data(); 1300 char* access_str = CreateAccessFlagStr(flags, kAccessForField); 1301 1302 if (options_.output_format_ == kOutputPlain) { 1303 fprintf(out_file_, " #%d : (in %s)\n", i, back_descriptor); 1304 fprintf(out_file_, " name : '%s'\n", name); 1305 fprintf(out_file_, " type : '%s'\n", type_descriptor); 1306 fprintf(out_file_, " access : 0x%04x (%s)\n", flags, access_str); 1307 if (init != nullptr) { 1308 fputs(" value : ", out_file_); 1309 DumpEncodedValue(init); 1310 fputs("\n", out_file_); 1311 } 1312 } else if (options_.output_format_ == kOutputXml) { 1313 fprintf(out_file_, "<field name=\"%s\"\n", name); 1314 std::string dot(DescriptorToDotWrapper(type_descriptor)); 1315 fprintf(out_file_, " type=\"%s\"\n", dot.c_str()); 1316 fprintf(out_file_, " transient=%s\n", QuotedBool((flags & kAccTransient) != 0)); 1317 fprintf(out_file_, " volatile=%s\n", QuotedBool((flags & kAccVolatile) != 0)); 1318 // The "value=" is not knowable w/o parsing annotations. 1319 fprintf(out_file_, " static=%s\n", QuotedBool((flags & kAccStatic) != 0)); 1320 fprintf(out_file_, " final=%s\n", QuotedBool((flags & kAccFinal) != 0)); 1321 // The "deprecated=" is not knowable w/o parsing annotations. 1322 fprintf(out_file_, " visibility=%s\n", QuotedVisibility(flags)); 1323 if (init != nullptr) { 1324 fputs(" value=\"", out_file_); 1325 DumpEncodedValue(init); 1326 fputs("\"\n", out_file_); 1327 } 1328 fputs(">\n</field>\n", out_file_); 1329 } 1330 1331 free(access_str); 1332} 1333 1334/* 1335 * Dumps an instance field. 1336 */ 1337void DexLayout::DumpIField(uint32_t idx, uint32_t flags, int i) { 1338 DumpSField(idx, flags, i, nullptr); 1339} 1340 1341/* 1342 * Dumps the class. 1343 * 1344 * Note "idx" is a DexClassDef index, not a DexTypeId index. 1345 * 1346 * If "*last_package" is nullptr or does not match the current class' package, 1347 * the value will be replaced with a newly-allocated string. 1348 */ 1349void DexLayout::DumpClass(int idx, char** last_package) { 1350 dex_ir::ClassDef* class_def = header_->GetCollections().GetClassDef(idx); 1351 // Omitting non-public class. 1352 if (options_.exports_only_ && (class_def->GetAccessFlags() & kAccPublic) == 0) { 1353 return; 1354 } 1355 1356 if (options_.show_section_headers_) { 1357 DumpClassDef(idx); 1358 } 1359 1360 if (options_.show_annotations_) { 1361 DumpClassAnnotations(idx); 1362 } 1363 1364 // For the XML output, show the package name. Ideally we'd gather 1365 // up the classes, sort them, and dump them alphabetically so the 1366 // package name wouldn't jump around, but that's not a great plan 1367 // for something that needs to run on the device. 1368 const char* class_descriptor = 1369 header_->GetCollections().GetClassDef(idx)->ClassType()->GetStringId()->Data(); 1370 if (!(class_descriptor[0] == 'L' && 1371 class_descriptor[strlen(class_descriptor)-1] == ';')) { 1372 // Arrays and primitives should not be defined explicitly. Keep going? 1373 fprintf(stderr, "Malformed class name '%s'\n", class_descriptor); 1374 } else if (options_.output_format_ == kOutputXml) { 1375 char* mangle = strdup(class_descriptor + 1); 1376 mangle[strlen(mangle)-1] = '\0'; 1377 1378 // Reduce to just the package name. 1379 char* last_slash = strrchr(mangle, '/'); 1380 if (last_slash != nullptr) { 1381 *last_slash = '\0'; 1382 } else { 1383 *mangle = '\0'; 1384 } 1385 1386 for (char* cp = mangle; *cp != '\0'; cp++) { 1387 if (*cp == '/') { 1388 *cp = '.'; 1389 } 1390 } // for 1391 1392 if (*last_package == nullptr || strcmp(mangle, *last_package) != 0) { 1393 // Start of a new package. 1394 if (*last_package != nullptr) { 1395 fprintf(out_file_, "</package>\n"); 1396 } 1397 fprintf(out_file_, "<package name=\"%s\"\n>\n", mangle); 1398 free(*last_package); 1399 *last_package = mangle; 1400 } else { 1401 free(mangle); 1402 } 1403 } 1404 1405 // General class information. 1406 char* access_str = CreateAccessFlagStr(class_def->GetAccessFlags(), kAccessForClass); 1407 const char* superclass_descriptor = nullptr; 1408 if (class_def->Superclass() != nullptr) { 1409 superclass_descriptor = class_def->Superclass()->GetStringId()->Data(); 1410 } 1411 if (options_.output_format_ == kOutputPlain) { 1412 fprintf(out_file_, "Class #%d -\n", idx); 1413 fprintf(out_file_, " Class descriptor : '%s'\n", class_descriptor); 1414 fprintf(out_file_, " Access flags : 0x%04x (%s)\n", 1415 class_def->GetAccessFlags(), access_str); 1416 if (superclass_descriptor != nullptr) { 1417 fprintf(out_file_, " Superclass : '%s'\n", superclass_descriptor); 1418 } 1419 fprintf(out_file_, " Interfaces -\n"); 1420 } else { 1421 std::string dot(DescriptorClassToDot(class_descriptor)); 1422 fprintf(out_file_, "<class name=\"%s\"\n", dot.c_str()); 1423 if (superclass_descriptor != nullptr) { 1424 dot = DescriptorToDotWrapper(superclass_descriptor); 1425 fprintf(out_file_, " extends=\"%s\"\n", dot.c_str()); 1426 } 1427 fprintf(out_file_, " interface=%s\n", 1428 QuotedBool((class_def->GetAccessFlags() & kAccInterface) != 0)); 1429 fprintf(out_file_, " abstract=%s\n", 1430 QuotedBool((class_def->GetAccessFlags() & kAccAbstract) != 0)); 1431 fprintf(out_file_, " static=%s\n", QuotedBool((class_def->GetAccessFlags() & kAccStatic) != 0)); 1432 fprintf(out_file_, " final=%s\n", QuotedBool((class_def->GetAccessFlags() & kAccFinal) != 0)); 1433 // The "deprecated=" not knowable w/o parsing annotations. 1434 fprintf(out_file_, " visibility=%s\n", QuotedVisibility(class_def->GetAccessFlags())); 1435 fprintf(out_file_, ">\n"); 1436 } 1437 1438 // Interfaces. 1439 const dex_ir::TypeList* interfaces = class_def->Interfaces(); 1440 if (interfaces != nullptr) { 1441 const dex_ir::TypeIdVector* interfaces_vector = interfaces->GetTypeList(); 1442 for (uint32_t i = 0; i < interfaces_vector->size(); i++) { 1443 DumpInterface((*interfaces_vector)[i], i); 1444 } // for 1445 } 1446 1447 // Fields and methods. 1448 dex_ir::ClassData* class_data = class_def->GetClassData(); 1449 // Prepare data for static fields. 1450 dex_ir::EncodedArrayItem* static_values = class_def->StaticValues(); 1451 dex_ir::EncodedValueVector* encoded_values = 1452 static_values == nullptr ? nullptr : static_values->GetEncodedValues(); 1453 const uint32_t encoded_values_size = (encoded_values == nullptr) ? 0 : encoded_values->size(); 1454 1455 // Static fields. 1456 if (options_.output_format_ == kOutputPlain) { 1457 fprintf(out_file_, " Static fields -\n"); 1458 } 1459 if (class_data != nullptr) { 1460 dex_ir::FieldItemVector* static_fields = class_data->StaticFields(); 1461 if (static_fields != nullptr) { 1462 for (uint32_t i = 0; i < static_fields->size(); i++) { 1463 DumpSField((*static_fields)[i]->GetFieldId()->GetIndex(), 1464 (*static_fields)[i]->GetAccessFlags(), 1465 i, 1466 i < encoded_values_size ? (*encoded_values)[i].get() : nullptr); 1467 } // for 1468 } 1469 } 1470 1471 // Instance fields. 1472 if (options_.output_format_ == kOutputPlain) { 1473 fprintf(out_file_, " Instance fields -\n"); 1474 } 1475 if (class_data != nullptr) { 1476 dex_ir::FieldItemVector* instance_fields = class_data->InstanceFields(); 1477 if (instance_fields != nullptr) { 1478 for (uint32_t i = 0; i < instance_fields->size(); i++) { 1479 DumpIField((*instance_fields)[i]->GetFieldId()->GetIndex(), 1480 (*instance_fields)[i]->GetAccessFlags(), 1481 i); 1482 } // for 1483 } 1484 } 1485 1486 // Direct methods. 1487 if (options_.output_format_ == kOutputPlain) { 1488 fprintf(out_file_, " Direct methods -\n"); 1489 } 1490 if (class_data != nullptr) { 1491 dex_ir::MethodItemVector* direct_methods = class_data->DirectMethods(); 1492 if (direct_methods != nullptr) { 1493 for (uint32_t i = 0; i < direct_methods->size(); i++) { 1494 DumpMethod((*direct_methods)[i]->GetMethodId()->GetIndex(), 1495 (*direct_methods)[i]->GetAccessFlags(), 1496 (*direct_methods)[i]->GetCodeItem(), 1497 i); 1498 } // for 1499 } 1500 } 1501 1502 // Virtual methods. 1503 if (options_.output_format_ == kOutputPlain) { 1504 fprintf(out_file_, " Virtual methods -\n"); 1505 } 1506 if (class_data != nullptr) { 1507 dex_ir::MethodItemVector* virtual_methods = class_data->VirtualMethods(); 1508 if (virtual_methods != nullptr) { 1509 for (uint32_t i = 0; i < virtual_methods->size(); i++) { 1510 DumpMethod((*virtual_methods)[i]->GetMethodId()->GetIndex(), 1511 (*virtual_methods)[i]->GetAccessFlags(), 1512 (*virtual_methods)[i]->GetCodeItem(), 1513 i); 1514 } // for 1515 } 1516 } 1517 1518 // End of class. 1519 if (options_.output_format_ == kOutputPlain) { 1520 const char* file_name = "unknown"; 1521 if (class_def->SourceFile() != nullptr) { 1522 file_name = class_def->SourceFile()->Data(); 1523 } 1524 const dex_ir::StringId* source_file = class_def->SourceFile(); 1525 fprintf(out_file_, " source_file_idx : %d (%s)\n\n", 1526 source_file == nullptr ? 0xffffffffU : source_file->GetIndex(), file_name); 1527 } else if (options_.output_format_ == kOutputXml) { 1528 fprintf(out_file_, "</class>\n"); 1529 } 1530 1531 free(access_str); 1532} 1533 1534void DexLayout::DumpDexFile() { 1535 // Headers. 1536 if (options_.show_file_headers_) { 1537 DumpFileHeader(); 1538 } 1539 1540 // Open XML context. 1541 if (options_.output_format_ == kOutputXml) { 1542 fprintf(out_file_, "<api>\n"); 1543 } 1544 1545 // Iterate over all classes. 1546 char* package = nullptr; 1547 const uint32_t class_defs_size = header_->GetCollections().ClassDefsSize(); 1548 for (uint32_t i = 0; i < class_defs_size; i++) { 1549 DumpClass(i, &package); 1550 } // for 1551 1552 // Free the last package allocated. 1553 if (package != nullptr) { 1554 fprintf(out_file_, "</package>\n"); 1555 free(package); 1556 } 1557 1558 // Close XML context. 1559 if (options_.output_format_ == kOutputXml) { 1560 fprintf(out_file_, "</api>\n"); 1561 } 1562} 1563 1564void DexLayout::LayoutClassDefsAndClassData(const DexFile* dex_file) { 1565 std::vector<dex_ir::ClassDef*> new_class_def_order; 1566 for (std::unique_ptr<dex_ir::ClassDef>& class_def : header_->GetCollections().ClassDefs()) { 1567 dex::TypeIndex type_idx(class_def->ClassType()->GetIndex()); 1568 if (info_->ContainsClass(*dex_file, type_idx)) { 1569 new_class_def_order.push_back(class_def.get()); 1570 } 1571 } 1572 for (std::unique_ptr<dex_ir::ClassDef>& class_def : header_->GetCollections().ClassDefs()) { 1573 dex::TypeIndex type_idx(class_def->ClassType()->GetIndex()); 1574 if (!info_->ContainsClass(*dex_file, type_idx)) { 1575 new_class_def_order.push_back(class_def.get()); 1576 } 1577 } 1578 std::unordered_set<dex_ir::ClassData*> visited_class_data; 1579 size_t class_data_index = 0; 1580 dex_ir::CollectionVector<dex_ir::ClassData>::Vector& class_datas = 1581 header_->GetCollections().ClassDatas(); 1582 for (dex_ir::ClassDef* class_def : new_class_def_order) { 1583 dex_ir::ClassData* class_data = class_def->GetClassData(); 1584 if (class_data != nullptr && visited_class_data.find(class_data) == visited_class_data.end()) { 1585 visited_class_data.insert(class_data); 1586 // Overwrite the existing vector with the new ordering, note that the sets of objects are 1587 // equivalent, but the order changes. This is why this is not a memory leak. 1588 // TODO: Consider cleaning this up with a shared_ptr. 1589 class_datas[class_data_index].release(); 1590 class_datas[class_data_index].reset(class_data); 1591 ++class_data_index; 1592 } 1593 } 1594 CHECK_EQ(class_data_index, class_datas.size()); 1595 1596 if (kChangeClassDefOrder) { 1597 // This currently produces dex files that violate the spec since the super class class_def is 1598 // supposed to occur before any subclasses. 1599 dex_ir::CollectionVector<dex_ir::ClassDef>::Vector& class_defs = 1600 header_->GetCollections().ClassDefs(); 1601 CHECK_EQ(new_class_def_order.size(), class_defs.size()); 1602 for (size_t i = 0; i < class_defs.size(); ++i) { 1603 // Overwrite the existing vector with the new ordering, note that the sets of objects are 1604 // equivalent, but the order changes. This is why this is not a memory leak. 1605 // TODO: Consider cleaning this up with a shared_ptr. 1606 class_defs[i].release(); 1607 class_defs[i].reset(new_class_def_order[i]); 1608 } 1609 } 1610} 1611 1612void DexLayout::LayoutStringData(const DexFile* dex_file) { 1613 const size_t num_strings = header_->GetCollections().StringIds().size(); 1614 std::vector<bool> is_shorty(num_strings, false); 1615 std::vector<bool> from_hot_method(num_strings, false); 1616 for (std::unique_ptr<dex_ir::ClassDef>& class_def : header_->GetCollections().ClassDefs()) { 1617 // A name of a profile class is probably going to get looked up by ClassTable::Lookup, mark it 1618 // as hot. Add its super class and interfaces as well, which can be used during initialization. 1619 const bool is_profile_class = 1620 info_->ContainsClass(*dex_file, dex::TypeIndex(class_def->ClassType()->GetIndex())); 1621 if (is_profile_class) { 1622 from_hot_method[class_def->ClassType()->GetStringId()->GetIndex()] = true; 1623 const dex_ir::TypeId* superclass = class_def->Superclass(); 1624 if (superclass != nullptr) { 1625 from_hot_method[superclass->GetStringId()->GetIndex()] = true; 1626 } 1627 const dex_ir::TypeList* interfaces = class_def->Interfaces(); 1628 if (interfaces != nullptr) { 1629 for (const dex_ir::TypeId* interface_type : *interfaces->GetTypeList()) { 1630 from_hot_method[interface_type->GetStringId()->GetIndex()] = true; 1631 } 1632 } 1633 } 1634 dex_ir::ClassData* data = class_def->GetClassData(); 1635 if (data == nullptr) { 1636 continue; 1637 } 1638 for (size_t i = 0; i < 2; ++i) { 1639 for (auto& method : *(i == 0 ? data->DirectMethods() : data->VirtualMethods())) { 1640 const dex_ir::MethodId* method_id = method->GetMethodId(); 1641 dex_ir::CodeItem* code_item = method->GetCodeItem(); 1642 if (code_item == nullptr) { 1643 continue; 1644 } 1645 const bool is_clinit = is_profile_class && 1646 (method->GetAccessFlags() & kAccConstructor) != 0 && 1647 (method->GetAccessFlags() & kAccStatic) != 0; 1648 const bool method_executed = is_clinit || 1649 info_->GetMethodHotness(MethodReference(dex_file, method_id->GetIndex())).IsInProfile(); 1650 if (!method_executed) { 1651 continue; 1652 } 1653 is_shorty[method_id->Proto()->Shorty()->GetIndex()] = true; 1654 dex_ir::CodeFixups* fixups = code_item->GetCodeFixups(); 1655 if (fixups == nullptr) { 1656 continue; 1657 } 1658 // Add const-strings. 1659 for (dex_ir::StringId* id : fixups->StringIds()) { 1660 from_hot_method[id->GetIndex()] = true; 1661 } 1662 // Add field classes, names, and types. 1663 for (dex_ir::FieldId* id : fixups->FieldIds()) { 1664 // TODO: Only visit field ids from static getters and setters. 1665 from_hot_method[id->Class()->GetStringId()->GetIndex()] = true; 1666 from_hot_method[id->Name()->GetIndex()] = true; 1667 from_hot_method[id->Type()->GetStringId()->GetIndex()] = true; 1668 } 1669 // For clinits, add referenced method classes, names, and protos. 1670 if (is_clinit) { 1671 for (dex_ir::MethodId* id : fixups->MethodIds()) { 1672 from_hot_method[id->Class()->GetStringId()->GetIndex()] = true; 1673 from_hot_method[id->Name()->GetIndex()] = true; 1674 is_shorty[id->Proto()->Shorty()->GetIndex()] = true; 1675 } 1676 } 1677 } 1678 } 1679 } 1680 // Sort string data by specified order. 1681 std::vector<dex_ir::StringId*> string_ids; 1682 for (auto& string_id : header_->GetCollections().StringIds()) { 1683 string_ids.push_back(string_id.get()); 1684 } 1685 std::sort(string_ids.begin(), 1686 string_ids.end(), 1687 [&is_shorty, &from_hot_method](const dex_ir::StringId* a, 1688 const dex_ir::StringId* b) { 1689 const bool a_is_hot = from_hot_method[a->GetIndex()]; 1690 const bool b_is_hot = from_hot_method[b->GetIndex()]; 1691 if (a_is_hot != b_is_hot) { 1692 return a_is_hot < b_is_hot; 1693 } 1694 // After hot methods are partitioned, subpartition shorties. 1695 const bool a_is_shorty = is_shorty[a->GetIndex()]; 1696 const bool b_is_shorty = is_shorty[b->GetIndex()]; 1697 if (a_is_shorty != b_is_shorty) { 1698 return a_is_shorty < b_is_shorty; 1699 } 1700 // Order by index by default. 1701 return a->GetIndex() < b->GetIndex(); 1702 }); 1703 dex_ir::CollectionVector<dex_ir::StringData>::Vector& string_datas = 1704 header_->GetCollections().StringDatas(); 1705 // Now we know what order we want the string data, reorder them. 1706 size_t data_index = 0; 1707 for (dex_ir::StringId* string_id : string_ids) { 1708 string_datas[data_index].release(); 1709 string_datas[data_index].reset(string_id->DataItem()); 1710 ++data_index; 1711 } 1712 if (kIsDebugBuild) { 1713 std::unordered_set<dex_ir::StringData*> visited; 1714 for (const std::unique_ptr<dex_ir::StringData>& data : string_datas) { 1715 visited.insert(data.get()); 1716 } 1717 for (auto& string_id : header_->GetCollections().StringIds()) { 1718 CHECK(visited.find(string_id->DataItem()) != visited.end()); 1719 } 1720 } 1721 CHECK_EQ(data_index, string_datas.size()); 1722} 1723 1724// Orders code items according to specified class data ordering. 1725void DexLayout::LayoutCodeItems(const DexFile* dex_file) { 1726 static constexpr InvokeType invoke_types[] = { 1727 kDirect, 1728 kVirtual 1729 }; 1730 1731 std::unordered_map<dex_ir::CodeItem*, LayoutType>& code_item_layout = 1732 layout_hotness_info_.code_item_layout_; 1733 1734 // Assign hotness flags to all code items. 1735 for (InvokeType invoke_type : invoke_types) { 1736 for (std::unique_ptr<dex_ir::ClassDef>& class_def : header_->GetCollections().ClassDefs()) { 1737 const bool is_profile_class = 1738 info_->ContainsClass(*dex_file, dex::TypeIndex(class_def->ClassType()->GetIndex())); 1739 1740 // Skip classes that are not defined in this dex file. 1741 dex_ir::ClassData* class_data = class_def->GetClassData(); 1742 if (class_data == nullptr) { 1743 continue; 1744 } 1745 for (auto& method : *(invoke_type == InvokeType::kDirect 1746 ? class_data->DirectMethods() 1747 : class_data->VirtualMethods())) { 1748 const dex_ir::MethodId *method_id = method->GetMethodId(); 1749 dex_ir::CodeItem *code_item = method->GetCodeItem(); 1750 if (code_item == nullptr) { 1751 continue; 1752 } 1753 // Separate executed methods (clinits and profiled methods) from unexecuted methods. 1754 const bool is_clinit = (method->GetAccessFlags() & kAccConstructor) != 0 && 1755 (method->GetAccessFlags() & kAccStatic) != 0; 1756 const bool is_startup_clinit = is_profile_class && is_clinit; 1757 using Hotness = ProfileCompilationInfo::MethodHotness; 1758 Hotness hotness = info_->GetMethodHotness(MethodReference(dex_file, method_id->GetIndex())); 1759 LayoutType state = LayoutType::kLayoutTypeUnused; 1760 if (hotness.IsHot()) { 1761 // Hot code is compiled, maybe one day it won't be accessed. So lay it out together for 1762 // now. 1763 state = LayoutType::kLayoutTypeHot; 1764 } else if (is_startup_clinit || hotness.GetFlags() == Hotness::kFlagStartup) { 1765 // Startup clinit or a method that only has the startup flag. 1766 state = LayoutType::kLayoutTypeStartupOnly; 1767 } else if (is_clinit) { 1768 state = LayoutType::kLayoutTypeUsedOnce; 1769 } else if (hotness.IsInProfile()) { 1770 state = LayoutType::kLayoutTypeSometimesUsed; 1771 } 1772 auto it = code_item_layout.emplace(code_item, state); 1773 if (!it.second) { 1774 LayoutType& layout_type = it.first->second; 1775 // Already exists, merge the hotness. 1776 layout_type = MergeLayoutType(layout_type, state); 1777 } 1778 } 1779 } 1780 } 1781 1782 dex_ir::CollectionVector<dex_ir::CodeItem>::Vector& code_items = 1783 header_->GetCollections().CodeItems(); 1784 if (VLOG_IS_ON(dex)) { 1785 size_t layout_count[static_cast<size_t>(LayoutType::kLayoutTypeCount)] = {}; 1786 for (const std::unique_ptr<dex_ir::CodeItem>& code_item : code_items) { 1787 auto it = code_item_layout.find(code_item.get()); 1788 DCHECK(it != code_item_layout.end()); 1789 ++layout_count[static_cast<size_t>(it->second)]; 1790 } 1791 for (size_t i = 0; i < static_cast<size_t>(LayoutType::kLayoutTypeCount); ++i) { 1792 LOG(INFO) << "Code items in category " << i << " count=" << layout_count[i]; 1793 } 1794 } 1795 1796 // Sort the code items vector by new layout. The writing process will take care of calculating 1797 // all the offsets. Stable sort to preserve any existing locality that might be there. 1798 std::stable_sort(code_items.begin(), 1799 code_items.end(), 1800 [&](const std::unique_ptr<dex_ir::CodeItem>& a, 1801 const std::unique_ptr<dex_ir::CodeItem>& b) { 1802 auto it_a = code_item_layout.find(a.get()); 1803 auto it_b = code_item_layout.find(b.get()); 1804 DCHECK(it_a != code_item_layout.end()); 1805 DCHECK(it_b != code_item_layout.end()); 1806 const LayoutType layout_type_a = it_a->second; 1807 const LayoutType layout_type_b = it_b->second; 1808 return layout_type_a < layout_type_b; 1809 }); 1810} 1811 1812void DexLayout::LayoutOutputFile(const DexFile* dex_file) { 1813 LayoutStringData(dex_file); 1814 LayoutClassDefsAndClassData(dex_file); 1815 LayoutCodeItems(dex_file); 1816} 1817 1818void DexLayout::OutputDexFile(const DexFile* dex_file, bool compute_offsets) { 1819 const std::string& dex_file_location = dex_file->GetLocation(); 1820 std::string error_msg; 1821 std::unique_ptr<File> new_file; 1822 // Since we allow dex growth, we need to size the map larger than the original input to be safe. 1823 // Reserve an extra 10% to add some buffer room. Note that this is probably more than 1824 // necessary. 1825 constexpr size_t kReserveFraction = 10; 1826 const size_t max_size = header_->FileSize() + header_->FileSize() / kReserveFraction; 1827 if (!options_.output_to_memmap_) { 1828 std::string output_location(options_.output_dex_directory_); 1829 size_t last_slash = dex_file_location.rfind('/'); 1830 std::string dex_file_directory = dex_file_location.substr(0, last_slash + 1); 1831 if (output_location == dex_file_directory) { 1832 output_location = dex_file_location + ".new"; 1833 } else if (last_slash != std::string::npos) { 1834 output_location += dex_file_location.substr(last_slash); 1835 } else { 1836 output_location += "/" + dex_file_location + ".new"; 1837 } 1838 new_file.reset(OS::CreateEmptyFile(output_location.c_str())); 1839 if (new_file == nullptr) { 1840 LOG(ERROR) << "Could not create dex writer output file: " << output_location; 1841 return; 1842 } 1843 if (ftruncate(new_file->Fd(), max_size) != 0) { 1844 LOG(ERROR) << "Could not grow dex writer output file: " << output_location;; 1845 new_file->Erase(); 1846 return; 1847 } 1848 mem_map_.reset(MemMap::MapFile(max_size, PROT_READ | PROT_WRITE, MAP_SHARED, 1849 new_file->Fd(), 0, /*low_4gb*/ false, output_location.c_str(), &error_msg)); 1850 } else { 1851 mem_map_.reset(MemMap::MapAnonymous("layout dex", nullptr, max_size, 1852 PROT_READ | PROT_WRITE, /* low_4gb */ false, /* reuse */ false, &error_msg)); 1853 } 1854 if (mem_map_ == nullptr) { 1855 LOG(ERROR) << "Could not create mem map for dex writer output: " << error_msg; 1856 if (new_file != nullptr) { 1857 new_file->Erase(); 1858 } 1859 return; 1860 } 1861 DexWriter::Output(header_, mem_map_.get(), this, compute_offsets, options_.compact_dex_level_); 1862 if (new_file != nullptr) { 1863 // Since we make the memmap larger than needed, shrink the file back down to not leave extra 1864 // padding. 1865 int res = new_file->SetLength(header_->FileSize()); 1866 if (res != 0) { 1867 LOG(ERROR) << "Truncating file resulted in " << res; 1868 } 1869 UNUSED(new_file->FlushCloseOrErase()); 1870 } 1871} 1872 1873/* 1874 * Dumps the requested sections of the file. 1875 */ 1876void DexLayout::ProcessDexFile(const char* file_name, 1877 const DexFile* dex_file, 1878 size_t dex_file_index) { 1879 const bool output = options_.output_dex_directory_ != nullptr || options_.output_to_memmap_; 1880 // Try to avoid eagerly assigning offsets to find bugs since GetOffset will abort if the offset 1881 // is unassigned. 1882 bool eagerly_assign_offsets = false; 1883 if (options_.visualize_pattern_ || options_.show_section_statistics_ || options_.dump_) { 1884 // These options required the offsets for dumping purposes. 1885 eagerly_assign_offsets = true; 1886 } 1887 std::unique_ptr<dex_ir::Header> header(dex_ir::DexIrBuilder(*dex_file, eagerly_assign_offsets)); 1888 SetHeader(header.get()); 1889 1890 if (options_.verbose_) { 1891 fprintf(out_file_, "Opened '%s', DEX version '%.3s'\n", 1892 file_name, dex_file->GetHeader().magic_ + 4); 1893 } 1894 1895 if (options_.visualize_pattern_) { 1896 VisualizeDexLayout(header_, dex_file, dex_file_index, info_); 1897 return; 1898 } 1899 1900 if (options_.show_section_statistics_) { 1901 ShowDexSectionStatistics(header_, dex_file_index); 1902 return; 1903 } 1904 1905 // Dump dex file. 1906 if (options_.dump_) { 1907 DumpDexFile(); 1908 } 1909 1910 // In case we are outputting to a file, keep it open so we can verify. 1911 if (output) { 1912 // Layout information about what strings and code items are hot. Used by the writing process 1913 // to generate the sections that are stored in the oat file. 1914 bool do_layout = info_ != nullptr; 1915 if (do_layout) { 1916 LayoutOutputFile(dex_file); 1917 } 1918 OutputDexFile(dex_file, do_layout); 1919 1920 // Clear header before verifying to reduce peak RAM usage. 1921 const size_t file_size = header_->FileSize(); 1922 header.reset(); 1923 1924 // Verify the output dex file's structure, only enabled by default for debug builds. 1925 if (options_.verify_output_) { 1926 std::string error_msg; 1927 std::string location = "memory mapped file for " + std::string(file_name); 1928 std::unique_ptr<const DexFile> output_dex_file(DexFileLoader::Open(mem_map_->Begin(), 1929 file_size, 1930 location, 1931 /* checksum */ 0, 1932 /*oat_dex_file*/ nullptr, 1933 /*verify*/ true, 1934 /*verify_checksum*/ false, 1935 &error_msg)); 1936 CHECK(output_dex_file != nullptr) << "Failed to re-open output file:" << error_msg; 1937 1938 // Do IR-level comparison between input and output. This check ignores potential differences 1939 // due to layout, so offsets are not checked. Instead, it checks the data contents of each 1940 // item. 1941 // 1942 // Regenerate output IR to catch any bugs that might happen during writing. 1943 std::unique_ptr<dex_ir::Header> output_header( 1944 dex_ir::DexIrBuilder(*output_dex_file, 1945 /*eagerly_assign_offsets*/ true)); 1946 std::unique_ptr<dex_ir::Header> orig_header( 1947 dex_ir::DexIrBuilder(*dex_file, 1948 /*eagerly_assign_offsets*/ true)); 1949 CHECK(VerifyOutputDexFile(output_header.get(), orig_header.get(), &error_msg)) << error_msg; 1950 } 1951 } 1952} 1953 1954/* 1955 * Processes a single file (either direct .dex or indirect .zip/.jar/.apk). 1956 */ 1957int DexLayout::ProcessFile(const char* file_name) { 1958 if (options_.verbose_) { 1959 fprintf(out_file_, "Processing '%s'...\n", file_name); 1960 } 1961 1962 // If the file is not a .dex file, the function tries .zip/.jar/.apk files, 1963 // all of which are Zip archives with "classes.dex" inside. 1964 const bool verify_checksum = !options_.ignore_bad_checksum_; 1965 std::string error_msg; 1966 std::vector<std::unique_ptr<const DexFile>> dex_files; 1967 if (!DexFileLoader::Open( 1968 file_name, file_name, /* verify */ true, verify_checksum, &error_msg, &dex_files)) { 1969 // Display returned error message to user. Note that this error behavior 1970 // differs from the error messages shown by the original Dalvik dexdump. 1971 fputs(error_msg.c_str(), stderr); 1972 fputc('\n', stderr); 1973 return -1; 1974 } 1975 1976 // Success. Either report checksum verification or process 1977 // all dex files found in given file. 1978 if (options_.checksum_only_) { 1979 fprintf(out_file_, "Checksum verified\n"); 1980 } else { 1981 for (size_t i = 0; i < dex_files.size(); i++) { 1982 ProcessDexFile(file_name, dex_files[i].get(), i); 1983 } 1984 } 1985 return 0; 1986} 1987 1988} // namespace art 1989