dexlayout.cc revision ea650f3bc4f54eb2c647cf0f7134398ef5038792
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_ir_builder.h" 37#include "dex_file-inl.h" 38#include "dex_file_verifier.h" 39#include "dex_instruction-inl.h" 40#include "dex_verify.h" 41#include "dex_visualize.h" 42#include "dex_writer.h" 43#include "jit/profile_compilation_info.h" 44#include "mem_map.h" 45#include "os.h" 46#include "utils.h" 47 48namespace art { 49 50using android::base::StringPrintf; 51 52static constexpr uint32_t kDexCodeItemAlignment = 4; 53 54/* 55 * Flags for use with createAccessFlagStr(). 56 */ 57enum AccessFor { 58 kAccessForClass = 0, kAccessForMethod = 1, kAccessForField = 2, kAccessForMAX 59}; 60const int kNumFlags = 18; 61 62/* 63 * Gets 2 little-endian bytes. 64 */ 65static inline uint16_t Get2LE(unsigned char const* src) { 66 return src[0] | (src[1] << 8); 67} 68 69/* 70 * Converts a type descriptor to human-readable "dotted" form. For 71 * example, "Ljava/lang/String;" becomes "java.lang.String", and 72 * "[I" becomes "int[]". Also converts '$' to '.', which means this 73 * form can't be converted back to a descriptor. 74 */ 75static std::string DescriptorToDotWrapper(const char* descriptor) { 76 std::string result = DescriptorToDot(descriptor); 77 size_t found = result.find('$'); 78 while (found != std::string::npos) { 79 result[found] = '.'; 80 found = result.find('$', found); 81 } 82 return result; 83} 84 85/* 86 * Converts the class name portion of a type descriptor to human-readable 87 * "dotted" form. For example, "Ljava/lang/String;" becomes "String". 88 */ 89static std::string DescriptorClassToDot(const char* str) { 90 std::string descriptor(str); 91 // Reduce to just the class name prefix. 92 size_t last_slash = descriptor.rfind('/'); 93 if (last_slash == std::string::npos) { 94 last_slash = 0; 95 } 96 // Start past the '/' or 'L'. 97 last_slash++; 98 99 // Copy class name over, trimming trailing ';'. 100 size_t size = descriptor.size() - 1 - last_slash; 101 std::string result(descriptor.substr(last_slash, size)); 102 103 // Replace '$' with '.'. 104 size_t dollar_sign = result.find('$'); 105 while (dollar_sign != std::string::npos) { 106 result[dollar_sign] = '.'; 107 dollar_sign = result.find('$', dollar_sign); 108 } 109 110 return result; 111} 112 113/* 114 * Returns string representing the boolean value. 115 */ 116static const char* StrBool(bool val) { 117 return val ? "true" : "false"; 118} 119 120/* 121 * Returns a quoted string representing the boolean value. 122 */ 123static const char* QuotedBool(bool val) { 124 return val ? "\"true\"" : "\"false\""; 125} 126 127/* 128 * Returns a quoted string representing the access flags. 129 */ 130static const char* QuotedVisibility(uint32_t access_flags) { 131 if (access_flags & kAccPublic) { 132 return "\"public\""; 133 } else if (access_flags & kAccProtected) { 134 return "\"protected\""; 135 } else if (access_flags & kAccPrivate) { 136 return "\"private\""; 137 } else { 138 return "\"package\""; 139 } 140} 141 142/* 143 * Counts the number of '1' bits in a word. 144 */ 145static int CountOnes(uint32_t val) { 146 val = val - ((val >> 1) & 0x55555555); 147 val = (val & 0x33333333) + ((val >> 2) & 0x33333333); 148 return (((val + (val >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24; 149} 150 151/* 152 * Creates a new string with human-readable access flags. 153 * 154 * In the base language the access_flags fields are type uint16_t; in Dalvik they're uint32_t. 155 */ 156static char* CreateAccessFlagStr(uint32_t flags, AccessFor for_what) { 157 static const char* kAccessStrings[kAccessForMAX][kNumFlags] = { 158 { 159 "PUBLIC", /* 0x00001 */ 160 "PRIVATE", /* 0x00002 */ 161 "PROTECTED", /* 0x00004 */ 162 "STATIC", /* 0x00008 */ 163 "FINAL", /* 0x00010 */ 164 "?", /* 0x00020 */ 165 "?", /* 0x00040 */ 166 "?", /* 0x00080 */ 167 "?", /* 0x00100 */ 168 "INTERFACE", /* 0x00200 */ 169 "ABSTRACT", /* 0x00400 */ 170 "?", /* 0x00800 */ 171 "SYNTHETIC", /* 0x01000 */ 172 "ANNOTATION", /* 0x02000 */ 173 "ENUM", /* 0x04000 */ 174 "?", /* 0x08000 */ 175 "VERIFIED", /* 0x10000 */ 176 "OPTIMIZED", /* 0x20000 */ 177 }, { 178 "PUBLIC", /* 0x00001 */ 179 "PRIVATE", /* 0x00002 */ 180 "PROTECTED", /* 0x00004 */ 181 "STATIC", /* 0x00008 */ 182 "FINAL", /* 0x00010 */ 183 "SYNCHRONIZED", /* 0x00020 */ 184 "BRIDGE", /* 0x00040 */ 185 "VARARGS", /* 0x00080 */ 186 "NATIVE", /* 0x00100 */ 187 "?", /* 0x00200 */ 188 "ABSTRACT", /* 0x00400 */ 189 "STRICT", /* 0x00800 */ 190 "SYNTHETIC", /* 0x01000 */ 191 "?", /* 0x02000 */ 192 "?", /* 0x04000 */ 193 "MIRANDA", /* 0x08000 */ 194 "CONSTRUCTOR", /* 0x10000 */ 195 "DECLARED_SYNCHRONIZED", /* 0x20000 */ 196 }, { 197 "PUBLIC", /* 0x00001 */ 198 "PRIVATE", /* 0x00002 */ 199 "PROTECTED", /* 0x00004 */ 200 "STATIC", /* 0x00008 */ 201 "FINAL", /* 0x00010 */ 202 "?", /* 0x00020 */ 203 "VOLATILE", /* 0x00040 */ 204 "TRANSIENT", /* 0x00080 */ 205 "?", /* 0x00100 */ 206 "?", /* 0x00200 */ 207 "?", /* 0x00400 */ 208 "?", /* 0x00800 */ 209 "SYNTHETIC", /* 0x01000 */ 210 "?", /* 0x02000 */ 211 "ENUM", /* 0x04000 */ 212 "?", /* 0x08000 */ 213 "?", /* 0x10000 */ 214 "?", /* 0x20000 */ 215 }, 216 }; 217 218 // Allocate enough storage to hold the expected number of strings, 219 // plus a space between each. We over-allocate, using the longest 220 // string above as the base metric. 221 const int kLongest = 21; // The strlen of longest string above. 222 const int count = CountOnes(flags); 223 char* str; 224 char* cp; 225 cp = str = reinterpret_cast<char*>(malloc(count * (kLongest + 1) + 1)); 226 227 for (int i = 0; i < kNumFlags; i++) { 228 if (flags & 0x01) { 229 const char* accessStr = kAccessStrings[for_what][i]; 230 const int len = strlen(accessStr); 231 if (cp != str) { 232 *cp++ = ' '; 233 } 234 memcpy(cp, accessStr, len); 235 cp += len; 236 } 237 flags >>= 1; 238 } // for 239 240 *cp = '\0'; 241 return str; 242} 243 244static std::string GetSignatureForProtoId(const dex_ir::ProtoId* proto) { 245 if (proto == nullptr) { 246 return "<no signature>"; 247 } 248 249 std::string result("("); 250 const dex_ir::TypeList* type_list = proto->Parameters(); 251 if (type_list != nullptr) { 252 for (const dex_ir::TypeId* type_id : *type_list->GetTypeList()) { 253 result += type_id->GetStringId()->Data(); 254 } 255 } 256 result += ")"; 257 result += proto->ReturnType()->GetStringId()->Data(); 258 return result; 259} 260 261/* 262 * Copies character data from "data" to "out", converting non-ASCII values 263 * to fprintf format chars or an ASCII filler ('.' or '?'). 264 * 265 * The output buffer must be able to hold (2*len)+1 bytes. The result is 266 * NULL-terminated. 267 */ 268static void Asciify(char* out, const unsigned char* data, size_t len) { 269 while (len--) { 270 if (*data < 0x20) { 271 // Could do more here, but we don't need them yet. 272 switch (*data) { 273 case '\0': 274 *out++ = '\\'; 275 *out++ = '0'; 276 break; 277 case '\n': 278 *out++ = '\\'; 279 *out++ = 'n'; 280 break; 281 default: 282 *out++ = '.'; 283 break; 284 } // switch 285 } else if (*data >= 0x80) { 286 *out++ = '?'; 287 } else { 288 *out++ = *data; 289 } 290 data++; 291 } // while 292 *out = '\0'; 293} 294 295/* 296 * Dumps a string value with some escape characters. 297 */ 298static void DumpEscapedString(const char* p, FILE* out_file) { 299 fputs("\"", out_file); 300 for (; *p; p++) { 301 switch (*p) { 302 case '\\': 303 fputs("\\\\", out_file); 304 break; 305 case '\"': 306 fputs("\\\"", out_file); 307 break; 308 case '\t': 309 fputs("\\t", out_file); 310 break; 311 case '\n': 312 fputs("\\n", out_file); 313 break; 314 case '\r': 315 fputs("\\r", out_file); 316 break; 317 default: 318 putc(*p, out_file); 319 } // switch 320 } // for 321 fputs("\"", out_file); 322} 323 324/* 325 * Dumps a string as an XML attribute value. 326 */ 327static void DumpXmlAttribute(const char* p, FILE* out_file) { 328 for (; *p; p++) { 329 switch (*p) { 330 case '&': 331 fputs("&", out_file); 332 break; 333 case '<': 334 fputs("<", out_file); 335 break; 336 case '>': 337 fputs(">", out_file); 338 break; 339 case '"': 340 fputs(""", out_file); 341 break; 342 case '\t': 343 fputs("	", out_file); 344 break; 345 case '\n': 346 fputs("
", out_file); 347 break; 348 case '\r': 349 fputs("
", out_file); 350 break; 351 default: 352 putc(*p, out_file); 353 } // switch 354 } // for 355} 356 357/* 358 * Helper for dumpInstruction(), which builds the string 359 * representation for the index in the given instruction. 360 * Returns a pointer to a buffer of sufficient size. 361 */ 362static std::unique_ptr<char[]> IndexString(dex_ir::Header* header, 363 const Instruction* dec_insn, 364 size_t buf_size) { 365 std::unique_ptr<char[]> buf(new char[buf_size]); 366 // Determine index and width of the string. 367 uint32_t index = 0; 368 uint32_t secondary_index = DexFile::kDexNoIndex; 369 uint32_t width = 4; 370 switch (Instruction::FormatOf(dec_insn->Opcode())) { 371 // SOME NOT SUPPORTED: 372 // case Instruction::k20bc: 373 case Instruction::k21c: 374 case Instruction::k35c: 375 // case Instruction::k35ms: 376 case Instruction::k3rc: 377 // case Instruction::k3rms: 378 // case Instruction::k35mi: 379 // case Instruction::k3rmi: 380 index = dec_insn->VRegB(); 381 width = 4; 382 break; 383 case Instruction::k31c: 384 index = dec_insn->VRegB(); 385 width = 8; 386 break; 387 case Instruction::k22c: 388 // case Instruction::k22cs: 389 index = dec_insn->VRegC(); 390 width = 4; 391 break; 392 case Instruction::k45cc: 393 case Instruction::k4rcc: 394 index = dec_insn->VRegB(); 395 secondary_index = dec_insn->VRegH(); 396 width = 4; 397 break; 398 default: 399 break; 400 } // switch 401 402 // Determine index type. 403 size_t outSize = 0; 404 switch (Instruction::IndexTypeOf(dec_insn->Opcode())) { 405 case Instruction::kIndexUnknown: 406 // This function should never get called for this type, but do 407 // something sensible here, just to help with debugging. 408 outSize = snprintf(buf.get(), buf_size, "<unknown-index>"); 409 break; 410 case Instruction::kIndexNone: 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, "<no-index>"); 414 break; 415 case Instruction::kIndexTypeRef: 416 if (index < header->GetCollections().TypeIdsSize()) { 417 const char* tp = header->GetCollections().GetTypeId(index)->GetStringId()->Data(); 418 outSize = snprintf(buf.get(), buf_size, "%s // type@%0*x", tp, width, index); 419 } else { 420 outSize = snprintf(buf.get(), buf_size, "<type?> // type@%0*x", width, index); 421 } 422 break; 423 case Instruction::kIndexStringRef: 424 if (index < header->GetCollections().StringIdsSize()) { 425 const char* st = header->GetCollections().GetStringId(index)->Data(); 426 outSize = snprintf(buf.get(), buf_size, "\"%s\" // string@%0*x", st, width, index); 427 } else { 428 outSize = snprintf(buf.get(), buf_size, "<string?> // string@%0*x", width, index); 429 } 430 break; 431 case Instruction::kIndexMethodRef: 432 if (index < header->GetCollections().MethodIdsSize()) { 433 dex_ir::MethodId* method_id = header->GetCollections().GetMethodId(index); 434 const char* name = method_id->Name()->Data(); 435 std::string type_descriptor = GetSignatureForProtoId(method_id->Proto()); 436 const char* back_descriptor = method_id->Class()->GetStringId()->Data(); 437 outSize = snprintf(buf.get(), buf_size, "%s.%s:%s // method@%0*x", 438 back_descriptor, name, type_descriptor.c_str(), width, index); 439 } else { 440 outSize = snprintf(buf.get(), buf_size, "<method?> // method@%0*x", width, index); 441 } 442 break; 443 case Instruction::kIndexFieldRef: 444 if (index < header->GetCollections().FieldIdsSize()) { 445 dex_ir::FieldId* field_id = header->GetCollections().GetFieldId(index); 446 const char* name = field_id->Name()->Data(); 447 const char* type_descriptor = field_id->Type()->GetStringId()->Data(); 448 const char* back_descriptor = field_id->Class()->GetStringId()->Data(); 449 outSize = snprintf(buf.get(), buf_size, "%s.%s:%s // field@%0*x", 450 back_descriptor, name, type_descriptor, width, index); 451 } else { 452 outSize = snprintf(buf.get(), buf_size, "<field?> // field@%0*x", width, index); 453 } 454 break; 455 case Instruction::kIndexVtableOffset: 456 outSize = snprintf(buf.get(), buf_size, "[%0*x] // vtable #%0*x", 457 width, index, width, index); 458 break; 459 case Instruction::kIndexFieldOffset: 460 outSize = snprintf(buf.get(), buf_size, "[obj+%0*x]", width, index); 461 break; 462 case Instruction::kIndexMethodAndProtoRef: { 463 std::string method("<method?>"); 464 std::string proto("<proto?>"); 465 if (index < header->GetCollections().MethodIdsSize()) { 466 dex_ir::MethodId* method_id = header->GetCollections().GetMethodId(index); 467 const char* name = method_id->Name()->Data(); 468 std::string type_descriptor = GetSignatureForProtoId(method_id->Proto()); 469 const char* back_descriptor = method_id->Class()->GetStringId()->Data(); 470 method = StringPrintf("%s.%s:%s", back_descriptor, name, type_descriptor.c_str()); 471 } 472 if (secondary_index < header->GetCollections().ProtoIdsSize()) { 473 dex_ir::ProtoId* proto_id = header->GetCollections().GetProtoId(secondary_index); 474 proto = GetSignatureForProtoId(proto_id); 475 } 476 outSize = snprintf(buf.get(), buf_size, "%s, %s // method@%0*x, proto@%0*x", 477 method.c_str(), proto.c_str(), width, index, width, secondary_index); 478 } 479 break; 480 // SOME NOT SUPPORTED: 481 // case Instruction::kIndexVaries: 482 // case Instruction::kIndexInlineMethod: 483 default: 484 outSize = snprintf(buf.get(), buf_size, "<?>"); 485 break; 486 } // switch 487 488 // Determine success of string construction. 489 if (outSize >= buf_size) { 490 // The buffer wasn't big enough; retry with computed size. Note: snprintf() 491 // doesn't count/ the '\0' as part of its returned size, so we add explicit 492 // space for it here. 493 return IndexString(header, dec_insn, outSize + 1); 494 } 495 return buf; 496} 497 498/* 499 * Dumps encoded annotation. 500 */ 501void DexLayout::DumpEncodedAnnotation(dex_ir::EncodedAnnotation* annotation) { 502 fputs(annotation->GetType()->GetStringId()->Data(), out_file_); 503 // Display all name=value pairs. 504 for (auto& subannotation : *annotation->GetAnnotationElements()) { 505 fputc(' ', out_file_); 506 fputs(subannotation->GetName()->Data(), out_file_); 507 fputc('=', out_file_); 508 DumpEncodedValue(subannotation->GetValue()); 509 } 510} 511/* 512 * Dumps encoded value. 513 */ 514void DexLayout::DumpEncodedValue(const dex_ir::EncodedValue* data) { 515 switch (data->Type()) { 516 case DexFile::kDexAnnotationByte: 517 fprintf(out_file_, "%" PRId8, data->GetByte()); 518 break; 519 case DexFile::kDexAnnotationShort: 520 fprintf(out_file_, "%" PRId16, data->GetShort()); 521 break; 522 case DexFile::kDexAnnotationChar: 523 fprintf(out_file_, "%" PRIu16, data->GetChar()); 524 break; 525 case DexFile::kDexAnnotationInt: 526 fprintf(out_file_, "%" PRId32, data->GetInt()); 527 break; 528 case DexFile::kDexAnnotationLong: 529 fprintf(out_file_, "%" PRId64, data->GetLong()); 530 break; 531 case DexFile::kDexAnnotationFloat: { 532 fprintf(out_file_, "%g", data->GetFloat()); 533 break; 534 } 535 case DexFile::kDexAnnotationDouble: { 536 fprintf(out_file_, "%g", data->GetDouble()); 537 break; 538 } 539 case DexFile::kDexAnnotationString: { 540 dex_ir::StringId* string_id = data->GetStringId(); 541 if (options_.output_format_ == kOutputPlain) { 542 DumpEscapedString(string_id->Data(), out_file_); 543 } else { 544 DumpXmlAttribute(string_id->Data(), out_file_); 545 } 546 break; 547 } 548 case DexFile::kDexAnnotationType: { 549 dex_ir::TypeId* type_id = data->GetTypeId(); 550 fputs(type_id->GetStringId()->Data(), out_file_); 551 break; 552 } 553 case DexFile::kDexAnnotationField: 554 case DexFile::kDexAnnotationEnum: { 555 dex_ir::FieldId* field_id = data->GetFieldId(); 556 fputs(field_id->Name()->Data(), out_file_); 557 break; 558 } 559 case DexFile::kDexAnnotationMethod: { 560 dex_ir::MethodId* method_id = data->GetMethodId(); 561 fputs(method_id->Name()->Data(), out_file_); 562 break; 563 } 564 case DexFile::kDexAnnotationArray: { 565 fputc('{', out_file_); 566 // Display all elements. 567 for (auto& value : *data->GetEncodedArray()->GetEncodedValues()) { 568 fputc(' ', out_file_); 569 DumpEncodedValue(value.get()); 570 } 571 fputs(" }", out_file_); 572 break; 573 } 574 case DexFile::kDexAnnotationAnnotation: { 575 DumpEncodedAnnotation(data->GetEncodedAnnotation()); 576 break; 577 } 578 case DexFile::kDexAnnotationNull: 579 fputs("null", out_file_); 580 break; 581 case DexFile::kDexAnnotationBoolean: 582 fputs(StrBool(data->GetBoolean()), out_file_); 583 break; 584 default: 585 fputs("????", out_file_); 586 break; 587 } // switch 588} 589 590/* 591 * Dumps the file header. 592 */ 593void DexLayout::DumpFileHeader() { 594 char sanitized[8 * 2 + 1]; 595 dex_ir::Collections& collections = header_->GetCollections(); 596 fprintf(out_file_, "DEX file header:\n"); 597 Asciify(sanitized, header_->Magic(), 8); 598 fprintf(out_file_, "magic : '%s'\n", sanitized); 599 fprintf(out_file_, "checksum : %08x\n", header_->Checksum()); 600 fprintf(out_file_, "signature : %02x%02x...%02x%02x\n", 601 header_->Signature()[0], header_->Signature()[1], 602 header_->Signature()[DexFile::kSha1DigestSize - 2], 603 header_->Signature()[DexFile::kSha1DigestSize - 1]); 604 fprintf(out_file_, "file_size : %d\n", header_->FileSize()); 605 fprintf(out_file_, "header_size : %d\n", header_->HeaderSize()); 606 fprintf(out_file_, "link_size : %d\n", header_->LinkSize()); 607 fprintf(out_file_, "link_off : %d (0x%06x)\n", 608 header_->LinkOffset(), header_->LinkOffset()); 609 fprintf(out_file_, "string_ids_size : %d\n", collections.StringIdsSize()); 610 fprintf(out_file_, "string_ids_off : %d (0x%06x)\n", 611 collections.StringIdsOffset(), collections.StringIdsOffset()); 612 fprintf(out_file_, "type_ids_size : %d\n", collections.TypeIdsSize()); 613 fprintf(out_file_, "type_ids_off : %d (0x%06x)\n", 614 collections.TypeIdsOffset(), collections.TypeIdsOffset()); 615 fprintf(out_file_, "proto_ids_size : %d\n", collections.ProtoIdsSize()); 616 fprintf(out_file_, "proto_ids_off : %d (0x%06x)\n", 617 collections.ProtoIdsOffset(), collections.ProtoIdsOffset()); 618 fprintf(out_file_, "field_ids_size : %d\n", collections.FieldIdsSize()); 619 fprintf(out_file_, "field_ids_off : %d (0x%06x)\n", 620 collections.FieldIdsOffset(), collections.FieldIdsOffset()); 621 fprintf(out_file_, "method_ids_size : %d\n", collections.MethodIdsSize()); 622 fprintf(out_file_, "method_ids_off : %d (0x%06x)\n", 623 collections.MethodIdsOffset(), collections.MethodIdsOffset()); 624 fprintf(out_file_, "class_defs_size : %d\n", collections.ClassDefsSize()); 625 fprintf(out_file_, "class_defs_off : %d (0x%06x)\n", 626 collections.ClassDefsOffset(), collections.ClassDefsOffset()); 627 fprintf(out_file_, "data_size : %d\n", header_->DataSize()); 628 fprintf(out_file_, "data_off : %d (0x%06x)\n\n", 629 header_->DataOffset(), header_->DataOffset()); 630} 631 632/* 633 * Dumps a class_def_item. 634 */ 635void DexLayout::DumpClassDef(int idx) { 636 // General class information. 637 dex_ir::ClassDef* class_def = header_->GetCollections().GetClassDef(idx); 638 fprintf(out_file_, "Class #%d header:\n", idx); 639 fprintf(out_file_, "class_idx : %d\n", class_def->ClassType()->GetIndex()); 640 fprintf(out_file_, "access_flags : %d (0x%04x)\n", 641 class_def->GetAccessFlags(), class_def->GetAccessFlags()); 642 uint32_t superclass_idx = class_def->Superclass() == nullptr ? 643 DexFile::kDexNoIndex16 : class_def->Superclass()->GetIndex(); 644 fprintf(out_file_, "superclass_idx : %d\n", superclass_idx); 645 fprintf(out_file_, "interfaces_off : %d (0x%06x)\n", 646 class_def->InterfacesOffset(), class_def->InterfacesOffset()); 647 uint32_t source_file_offset = 0xffffffffU; 648 if (class_def->SourceFile() != nullptr) { 649 source_file_offset = class_def->SourceFile()->GetIndex(); 650 } 651 fprintf(out_file_, "source_file_idx : %d\n", source_file_offset); 652 uint32_t annotations_offset = 0; 653 if (class_def->Annotations() != nullptr) { 654 annotations_offset = class_def->Annotations()->GetOffset(); 655 } 656 fprintf(out_file_, "annotations_off : %d (0x%06x)\n", 657 annotations_offset, annotations_offset); 658 if (class_def->GetClassData() == nullptr) { 659 fprintf(out_file_, "class_data_off : %d (0x%06x)\n", 0, 0); 660 } else { 661 fprintf(out_file_, "class_data_off : %d (0x%06x)\n", 662 class_def->GetClassData()->GetOffset(), class_def->GetClassData()->GetOffset()); 663 } 664 665 // Fields and methods. 666 dex_ir::ClassData* class_data = class_def->GetClassData(); 667 if (class_data != nullptr && class_data->StaticFields() != nullptr) { 668 fprintf(out_file_, "static_fields_size : %zu\n", class_data->StaticFields()->size()); 669 } else { 670 fprintf(out_file_, "static_fields_size : 0\n"); 671 } 672 if (class_data != nullptr && class_data->InstanceFields() != nullptr) { 673 fprintf(out_file_, "instance_fields_size: %zu\n", class_data->InstanceFields()->size()); 674 } else { 675 fprintf(out_file_, "instance_fields_size: 0\n"); 676 } 677 if (class_data != nullptr && class_data->DirectMethods() != nullptr) { 678 fprintf(out_file_, "direct_methods_size : %zu\n", class_data->DirectMethods()->size()); 679 } else { 680 fprintf(out_file_, "direct_methods_size : 0\n"); 681 } 682 if (class_data != nullptr && class_data->VirtualMethods() != nullptr) { 683 fprintf(out_file_, "virtual_methods_size: %zu\n", class_data->VirtualMethods()->size()); 684 } else { 685 fprintf(out_file_, "virtual_methods_size: 0\n"); 686 } 687 fprintf(out_file_, "\n"); 688} 689 690/** 691 * Dumps an annotation set item. 692 */ 693void DexLayout::DumpAnnotationSetItem(dex_ir::AnnotationSetItem* set_item) { 694 if (set_item == nullptr || set_item->GetItems()->size() == 0) { 695 fputs(" empty-annotation-set\n", out_file_); 696 return; 697 } 698 for (dex_ir::AnnotationItem* annotation : *set_item->GetItems()) { 699 if (annotation == nullptr) { 700 continue; 701 } 702 fputs(" ", out_file_); 703 switch (annotation->GetVisibility()) { 704 case DexFile::kDexVisibilityBuild: fputs("VISIBILITY_BUILD ", out_file_); break; 705 case DexFile::kDexVisibilityRuntime: fputs("VISIBILITY_RUNTIME ", out_file_); break; 706 case DexFile::kDexVisibilitySystem: fputs("VISIBILITY_SYSTEM ", out_file_); break; 707 default: fputs("VISIBILITY_UNKNOWN ", out_file_); break; 708 } // switch 709 DumpEncodedAnnotation(annotation->GetAnnotation()); 710 fputc('\n', out_file_); 711 } 712} 713 714/* 715 * Dumps class annotations. 716 */ 717void DexLayout::DumpClassAnnotations(int idx) { 718 dex_ir::ClassDef* class_def = header_->GetCollections().GetClassDef(idx); 719 dex_ir::AnnotationsDirectoryItem* annotations_directory = class_def->Annotations(); 720 if (annotations_directory == nullptr) { 721 return; // none 722 } 723 724 fprintf(out_file_, "Class #%d annotations:\n", idx); 725 726 dex_ir::AnnotationSetItem* class_set_item = annotations_directory->GetClassAnnotation(); 727 dex_ir::FieldAnnotationVector* fields = annotations_directory->GetFieldAnnotations(); 728 dex_ir::MethodAnnotationVector* methods = annotations_directory->GetMethodAnnotations(); 729 dex_ir::ParameterAnnotationVector* parameters = annotations_directory->GetParameterAnnotations(); 730 731 // Annotations on the class itself. 732 if (class_set_item != nullptr) { 733 fprintf(out_file_, "Annotations on class\n"); 734 DumpAnnotationSetItem(class_set_item); 735 } 736 737 // Annotations on fields. 738 if (fields != nullptr) { 739 for (auto& field : *fields) { 740 const dex_ir::FieldId* field_id = field->GetFieldId(); 741 const uint32_t field_idx = field_id->GetIndex(); 742 const char* field_name = field_id->Name()->Data(); 743 fprintf(out_file_, "Annotations on field #%u '%s'\n", field_idx, field_name); 744 DumpAnnotationSetItem(field->GetAnnotationSetItem()); 745 } 746 } 747 748 // Annotations on methods. 749 if (methods != nullptr) { 750 for (auto& method : *methods) { 751 const dex_ir::MethodId* method_id = method->GetMethodId(); 752 const uint32_t method_idx = method_id->GetIndex(); 753 const char* method_name = method_id->Name()->Data(); 754 fprintf(out_file_, "Annotations on method #%u '%s'\n", method_idx, method_name); 755 DumpAnnotationSetItem(method->GetAnnotationSetItem()); 756 } 757 } 758 759 // Annotations on method parameters. 760 if (parameters != nullptr) { 761 for (auto& parameter : *parameters) { 762 const dex_ir::MethodId* method_id = parameter->GetMethodId(); 763 const uint32_t method_idx = method_id->GetIndex(); 764 const char* method_name = method_id->Name()->Data(); 765 fprintf(out_file_, "Annotations on method #%u '%s' parameters\n", method_idx, method_name); 766 uint32_t j = 0; 767 for (dex_ir::AnnotationSetItem* annotation : *parameter->GetAnnotations()->GetItems()) { 768 fprintf(out_file_, "#%u\n", j); 769 DumpAnnotationSetItem(annotation); 770 ++j; 771 } 772 } 773 } 774 775 fputc('\n', out_file_); 776} 777 778/* 779 * Dumps an interface that a class declares to implement. 780 */ 781void DexLayout::DumpInterface(const dex_ir::TypeId* type_item, int i) { 782 const char* interface_name = type_item->GetStringId()->Data(); 783 if (options_.output_format_ == kOutputPlain) { 784 fprintf(out_file_, " #%d : '%s'\n", i, interface_name); 785 } else { 786 std::string dot(DescriptorToDotWrapper(interface_name)); 787 fprintf(out_file_, "<implements name=\"%s\">\n</implements>\n", dot.c_str()); 788 } 789} 790 791/* 792 * Dumps the catches table associated with the code. 793 */ 794void DexLayout::DumpCatches(const dex_ir::CodeItem* code) { 795 const uint16_t tries_size = code->TriesSize(); 796 797 // No catch table. 798 if (tries_size == 0) { 799 fprintf(out_file_, " catches : (none)\n"); 800 return; 801 } 802 803 // Dump all table entries. 804 fprintf(out_file_, " catches : %d\n", tries_size); 805 std::vector<std::unique_ptr<const dex_ir::TryItem>>* tries = code->Tries(); 806 for (uint32_t i = 0; i < tries_size; i++) { 807 const dex_ir::TryItem* try_item = (*tries)[i].get(); 808 const uint32_t start = try_item->StartAddr(); 809 const uint32_t end = start + try_item->InsnCount(); 810 fprintf(out_file_, " 0x%04x - 0x%04x\n", start, end); 811 for (auto& handler : *try_item->GetHandlers()->GetHandlers()) { 812 const dex_ir::TypeId* type_id = handler->GetTypeId(); 813 const char* descriptor = (type_id == nullptr) ? "<any>" : type_id->GetStringId()->Data(); 814 fprintf(out_file_, " %s -> 0x%04x\n", descriptor, handler->GetAddress()); 815 } // for 816 } // for 817} 818 819/* 820 * Dumps all positions table entries associated with the code. 821 */ 822void DexLayout::DumpPositionInfo(const dex_ir::CodeItem* code) { 823 dex_ir::DebugInfoItem* debug_info = code->DebugInfo(); 824 if (debug_info == nullptr) { 825 return; 826 } 827 std::vector<std::unique_ptr<dex_ir::PositionInfo>>& positions = debug_info->GetPositionInfo(); 828 for (size_t i = 0; i < positions.size(); ++i) { 829 fprintf(out_file_, " 0x%04x line=%d\n", positions[i]->address_, positions[i]->line_); 830 } 831} 832 833/* 834 * Dumps all locals table entries associated with the code. 835 */ 836void DexLayout::DumpLocalInfo(const dex_ir::CodeItem* code) { 837 dex_ir::DebugInfoItem* debug_info = code->DebugInfo(); 838 if (debug_info == nullptr) { 839 return; 840 } 841 std::vector<std::unique_ptr<dex_ir::LocalInfo>>& locals = debug_info->GetLocalInfo(); 842 for (size_t i = 0; i < locals.size(); ++i) { 843 dex_ir::LocalInfo* entry = locals[i].get(); 844 fprintf(out_file_, " 0x%04x - 0x%04x reg=%d %s %s %s\n", 845 entry->start_address_, entry->end_address_, entry->reg_, 846 entry->name_.c_str(), entry->descriptor_.c_str(), entry->signature_.c_str()); 847 } 848} 849 850/* 851 * Dumps a single instruction. 852 */ 853void DexLayout::DumpInstruction(const dex_ir::CodeItem* code, 854 uint32_t code_offset, 855 uint32_t insn_idx, 856 uint32_t insn_width, 857 const Instruction* dec_insn) { 858 // Address of instruction (expressed as byte offset). 859 fprintf(out_file_, "%06x:", code_offset + 0x10 + insn_idx * 2); 860 861 // Dump (part of) raw bytes. 862 const uint16_t* insns = code->Insns(); 863 for (uint32_t i = 0; i < 8; i++) { 864 if (i < insn_width) { 865 if (i == 7) { 866 fprintf(out_file_, " ... "); 867 } else { 868 // Print 16-bit value in little-endian order. 869 const uint8_t* bytePtr = (const uint8_t*) &insns[insn_idx + i]; 870 fprintf(out_file_, " %02x%02x", bytePtr[0], bytePtr[1]); 871 } 872 } else { 873 fputs(" ", out_file_); 874 } 875 } // for 876 877 // Dump pseudo-instruction or opcode. 878 if (dec_insn->Opcode() == Instruction::NOP) { 879 const uint16_t instr = Get2LE((const uint8_t*) &insns[insn_idx]); 880 if (instr == Instruction::kPackedSwitchSignature) { 881 fprintf(out_file_, "|%04x: packed-switch-data (%d units)", insn_idx, insn_width); 882 } else if (instr == Instruction::kSparseSwitchSignature) { 883 fprintf(out_file_, "|%04x: sparse-switch-data (%d units)", insn_idx, insn_width); 884 } else if (instr == Instruction::kArrayDataSignature) { 885 fprintf(out_file_, "|%04x: array-data (%d units)", insn_idx, insn_width); 886 } else { 887 fprintf(out_file_, "|%04x: nop // spacer", insn_idx); 888 } 889 } else { 890 fprintf(out_file_, "|%04x: %s", insn_idx, dec_insn->Name()); 891 } 892 893 // Set up additional argument. 894 std::unique_ptr<char[]> index_buf; 895 if (Instruction::IndexTypeOf(dec_insn->Opcode()) != Instruction::kIndexNone) { 896 index_buf = IndexString(header_, dec_insn, 200); 897 } 898 899 // Dump the instruction. 900 // 901 // NOTE: pDecInsn->DumpString(pDexFile) differs too much from original. 902 // 903 switch (Instruction::FormatOf(dec_insn->Opcode())) { 904 case Instruction::k10x: // op 905 break; 906 case Instruction::k12x: // op vA, vB 907 fprintf(out_file_, " v%d, v%d", dec_insn->VRegA(), dec_insn->VRegB()); 908 break; 909 case Instruction::k11n: // op vA, #+B 910 fprintf(out_file_, " v%d, #int %d // #%x", 911 dec_insn->VRegA(), (int32_t) dec_insn->VRegB(), (uint8_t)dec_insn->VRegB()); 912 break; 913 case Instruction::k11x: // op vAA 914 fprintf(out_file_, " v%d", dec_insn->VRegA()); 915 break; 916 case Instruction::k10t: // op +AA 917 case Instruction::k20t: { // op +AAAA 918 const int32_t targ = (int32_t) dec_insn->VRegA(); 919 fprintf(out_file_, " %04x // %c%04x", 920 insn_idx + targ, 921 (targ < 0) ? '-' : '+', 922 (targ < 0) ? -targ : targ); 923 break; 924 } 925 case Instruction::k22x: // op vAA, vBBBB 926 fprintf(out_file_, " v%d, v%d", dec_insn->VRegA(), dec_insn->VRegB()); 927 break; 928 case Instruction::k21t: { // op vAA, +BBBB 929 const int32_t targ = (int32_t) dec_insn->VRegB(); 930 fprintf(out_file_, " v%d, %04x // %c%04x", dec_insn->VRegA(), 931 insn_idx + targ, 932 (targ < 0) ? '-' : '+', 933 (targ < 0) ? -targ : targ); 934 break; 935 } 936 case Instruction::k21s: // op vAA, #+BBBB 937 fprintf(out_file_, " v%d, #int %d // #%x", 938 dec_insn->VRegA(), (int32_t) dec_insn->VRegB(), (uint16_t)dec_insn->VRegB()); 939 break; 940 case Instruction::k21h: // op vAA, #+BBBB0000[00000000] 941 // The printed format varies a bit based on the actual opcode. 942 if (dec_insn->Opcode() == Instruction::CONST_HIGH16) { 943 const int32_t value = dec_insn->VRegB() << 16; 944 fprintf(out_file_, " v%d, #int %d // #%x", 945 dec_insn->VRegA(), value, (uint16_t) dec_insn->VRegB()); 946 } else { 947 const int64_t value = ((int64_t) dec_insn->VRegB()) << 48; 948 fprintf(out_file_, " v%d, #long %" PRId64 " // #%x", 949 dec_insn->VRegA(), value, (uint16_t) dec_insn->VRegB()); 950 } 951 break; 952 case Instruction::k21c: // op vAA, thing@BBBB 953 case Instruction::k31c: // op vAA, thing@BBBBBBBB 954 fprintf(out_file_, " v%d, %s", dec_insn->VRegA(), index_buf.get()); 955 break; 956 case Instruction::k23x: // op vAA, vBB, vCC 957 fprintf(out_file_, " v%d, v%d, v%d", 958 dec_insn->VRegA(), dec_insn->VRegB(), dec_insn->VRegC()); 959 break; 960 case Instruction::k22b: // op vAA, vBB, #+CC 961 fprintf(out_file_, " v%d, v%d, #int %d // #%02x", 962 dec_insn->VRegA(), dec_insn->VRegB(), 963 (int32_t) dec_insn->VRegC(), (uint8_t) dec_insn->VRegC()); 964 break; 965 case Instruction::k22t: { // op vA, vB, +CCCC 966 const int32_t targ = (int32_t) dec_insn->VRegC(); 967 fprintf(out_file_, " v%d, v%d, %04x // %c%04x", 968 dec_insn->VRegA(), dec_insn->VRegB(), 969 insn_idx + targ, 970 (targ < 0) ? '-' : '+', 971 (targ < 0) ? -targ : targ); 972 break; 973 } 974 case Instruction::k22s: // op vA, vB, #+CCCC 975 fprintf(out_file_, " v%d, v%d, #int %d // #%04x", 976 dec_insn->VRegA(), dec_insn->VRegB(), 977 (int32_t) dec_insn->VRegC(), (uint16_t) dec_insn->VRegC()); 978 break; 979 case Instruction::k22c: // op vA, vB, thing@CCCC 980 // NOT SUPPORTED: 981 // case Instruction::k22cs: // [opt] op vA, vB, field offset CCCC 982 fprintf(out_file_, " v%d, v%d, %s", 983 dec_insn->VRegA(), dec_insn->VRegB(), index_buf.get()); 984 break; 985 case Instruction::k30t: 986 fprintf(out_file_, " #%08x", dec_insn->VRegA()); 987 break; 988 case Instruction::k31i: { // op vAA, #+BBBBBBBB 989 // This is often, but not always, a float. 990 union { 991 float f; 992 uint32_t i; 993 } conv; 994 conv.i = dec_insn->VRegB(); 995 fprintf(out_file_, " v%d, #float %g // #%08x", 996 dec_insn->VRegA(), conv.f, dec_insn->VRegB()); 997 break; 998 } 999 case Instruction::k31t: // op vAA, offset +BBBBBBBB 1000 fprintf(out_file_, " v%d, %08x // +%08x", 1001 dec_insn->VRegA(), insn_idx + dec_insn->VRegB(), dec_insn->VRegB()); 1002 break; 1003 case Instruction::k32x: // op vAAAA, vBBBB 1004 fprintf(out_file_, " v%d, v%d", dec_insn->VRegA(), dec_insn->VRegB()); 1005 break; 1006 case Instruction::k35c: // op {vC, vD, vE, vF, vG}, thing@BBBB 1007 case Instruction::k45cc: { // op {vC, vD, vE, vF, vG}, meth@BBBB, proto@HHHH 1008 // NOT SUPPORTED: 1009 // case Instruction::k35ms: // [opt] invoke-virtual+super 1010 // case Instruction::k35mi: // [opt] inline invoke 1011 uint32_t arg[Instruction::kMaxVarArgRegs]; 1012 dec_insn->GetVarArgs(arg); 1013 fputs(" {", out_file_); 1014 for (int i = 0, n = dec_insn->VRegA(); i < n; i++) { 1015 if (i == 0) { 1016 fprintf(out_file_, "v%d", arg[i]); 1017 } else { 1018 fprintf(out_file_, ", v%d", arg[i]); 1019 } 1020 } // for 1021 fprintf(out_file_, "}, %s", index_buf.get()); 1022 break; 1023 } 1024 case Instruction::k3rc: // op {vCCCC .. v(CCCC+AA-1)}, thing@BBBB 1025 case Instruction::k4rcc: // op {vCCCC .. v(CCCC+AA-1)}, meth@BBBB, proto@HHHH 1026 // NOT SUPPORTED: 1027 // case Instruction::k3rms: // [opt] invoke-virtual+super/range 1028 // case Instruction::k3rmi: // [opt] execute-inline/range 1029 { 1030 // This doesn't match the "dx" output when some of the args are 1031 // 64-bit values -- dx only shows the first register. 1032 fputs(" {", out_file_); 1033 for (int i = 0, n = dec_insn->VRegA(); i < n; i++) { 1034 if (i == 0) { 1035 fprintf(out_file_, "v%d", dec_insn->VRegC() + i); 1036 } else { 1037 fprintf(out_file_, ", v%d", dec_insn->VRegC() + i); 1038 } 1039 } // for 1040 fprintf(out_file_, "}, %s", index_buf.get()); 1041 } 1042 break; 1043 case Instruction::k51l: { // op vAA, #+BBBBBBBBBBBBBBBB 1044 // This is often, but not always, a double. 1045 union { 1046 double d; 1047 uint64_t j; 1048 } conv; 1049 conv.j = dec_insn->WideVRegB(); 1050 fprintf(out_file_, " v%d, #double %g // #%016" PRIx64, 1051 dec_insn->VRegA(), conv.d, dec_insn->WideVRegB()); 1052 break; 1053 } 1054 // NOT SUPPORTED: 1055 // case Instruction::k00x: // unknown op or breakpoint 1056 // break; 1057 default: 1058 fprintf(out_file_, " ???"); 1059 break; 1060 } // switch 1061 1062 fputc('\n', out_file_); 1063} 1064 1065/* 1066 * Dumps a bytecode disassembly. 1067 */ 1068void DexLayout::DumpBytecodes(uint32_t idx, const dex_ir::CodeItem* code, uint32_t code_offset) { 1069 dex_ir::MethodId* method_id = header_->GetCollections().GetMethodId(idx); 1070 const char* name = method_id->Name()->Data(); 1071 std::string type_descriptor = GetSignatureForProtoId(method_id->Proto()); 1072 const char* back_descriptor = method_id->Class()->GetStringId()->Data(); 1073 1074 // Generate header. 1075 std::string dot(DescriptorToDotWrapper(back_descriptor)); 1076 fprintf(out_file_, "%06x: |[%06x] %s.%s:%s\n", 1077 code_offset, code_offset, dot.c_str(), name, type_descriptor.c_str()); 1078 1079 // Iterate over all instructions. 1080 const uint16_t* insns = code->Insns(); 1081 for (uint32_t insn_idx = 0; insn_idx < code->InsnsSize();) { 1082 const Instruction* instruction = Instruction::At(&insns[insn_idx]); 1083 const uint32_t insn_width = instruction->SizeInCodeUnits(); 1084 if (insn_width == 0) { 1085 fprintf(stderr, "GLITCH: zero-width instruction at idx=0x%04x\n", insn_idx); 1086 break; 1087 } 1088 DumpInstruction(code, code_offset, insn_idx, insn_width, instruction); 1089 insn_idx += insn_width; 1090 } // for 1091} 1092 1093/* 1094 * Dumps code of a method. 1095 */ 1096void DexLayout::DumpCode(uint32_t idx, const dex_ir::CodeItem* code, uint32_t code_offset) { 1097 fprintf(out_file_, " registers : %d\n", code->RegistersSize()); 1098 fprintf(out_file_, " ins : %d\n", code->InsSize()); 1099 fprintf(out_file_, " outs : %d\n", code->OutsSize()); 1100 fprintf(out_file_, " insns size : %d 16-bit code units\n", 1101 code->InsnsSize()); 1102 1103 // Bytecode disassembly, if requested. 1104 if (options_.disassemble_) { 1105 DumpBytecodes(idx, code, code_offset); 1106 } 1107 1108 // Try-catch blocks. 1109 DumpCatches(code); 1110 1111 // Positions and locals table in the debug info. 1112 fprintf(out_file_, " positions : \n"); 1113 DumpPositionInfo(code); 1114 fprintf(out_file_, " locals : \n"); 1115 DumpLocalInfo(code); 1116} 1117 1118/* 1119 * Dumps a method. 1120 */ 1121void DexLayout::DumpMethod(uint32_t idx, uint32_t flags, const dex_ir::CodeItem* code, int i) { 1122 // Bail for anything private if export only requested. 1123 if (options_.exports_only_ && (flags & (kAccPublic | kAccProtected)) == 0) { 1124 return; 1125 } 1126 1127 dex_ir::MethodId* method_id = header_->GetCollections().GetMethodId(idx); 1128 const char* name = method_id->Name()->Data(); 1129 char* type_descriptor = strdup(GetSignatureForProtoId(method_id->Proto()).c_str()); 1130 const char* back_descriptor = method_id->Class()->GetStringId()->Data(); 1131 char* access_str = CreateAccessFlagStr(flags, kAccessForMethod); 1132 1133 if (options_.output_format_ == kOutputPlain) { 1134 fprintf(out_file_, " #%d : (in %s)\n", i, back_descriptor); 1135 fprintf(out_file_, " name : '%s'\n", name); 1136 fprintf(out_file_, " type : '%s'\n", type_descriptor); 1137 fprintf(out_file_, " access : 0x%04x (%s)\n", flags, access_str); 1138 if (code == nullptr) { 1139 fprintf(out_file_, " code : (none)\n"); 1140 } else { 1141 fprintf(out_file_, " code -\n"); 1142 DumpCode(idx, code, code->GetOffset()); 1143 } 1144 if (options_.disassemble_) { 1145 fputc('\n', out_file_); 1146 } 1147 } else if (options_.output_format_ == kOutputXml) { 1148 const bool constructor = (name[0] == '<'); 1149 1150 // Method name and prototype. 1151 if (constructor) { 1152 std::string dot(DescriptorClassToDot(back_descriptor)); 1153 fprintf(out_file_, "<constructor name=\"%s\"\n", dot.c_str()); 1154 dot = DescriptorToDotWrapper(back_descriptor); 1155 fprintf(out_file_, " type=\"%s\"\n", dot.c_str()); 1156 } else { 1157 fprintf(out_file_, "<method name=\"%s\"\n", name); 1158 const char* return_type = strrchr(type_descriptor, ')'); 1159 if (return_type == nullptr) { 1160 fprintf(stderr, "bad method type descriptor '%s'\n", type_descriptor); 1161 goto bail; 1162 } 1163 std::string dot(DescriptorToDotWrapper(return_type + 1)); 1164 fprintf(out_file_, " return=\"%s\"\n", dot.c_str()); 1165 fprintf(out_file_, " abstract=%s\n", QuotedBool((flags & kAccAbstract) != 0)); 1166 fprintf(out_file_, " native=%s\n", QuotedBool((flags & kAccNative) != 0)); 1167 fprintf(out_file_, " synchronized=%s\n", QuotedBool( 1168 (flags & (kAccSynchronized | kAccDeclaredSynchronized)) != 0)); 1169 } 1170 1171 // Additional method flags. 1172 fprintf(out_file_, " static=%s\n", QuotedBool((flags & kAccStatic) != 0)); 1173 fprintf(out_file_, " final=%s\n", QuotedBool((flags & kAccFinal) != 0)); 1174 // The "deprecated=" not knowable w/o parsing annotations. 1175 fprintf(out_file_, " visibility=%s\n>\n", QuotedVisibility(flags)); 1176 1177 // Parameters. 1178 if (type_descriptor[0] != '(') { 1179 fprintf(stderr, "ERROR: bad descriptor '%s'\n", type_descriptor); 1180 goto bail; 1181 } 1182 char* tmp_buf = reinterpret_cast<char*>(malloc(strlen(type_descriptor) + 1)); 1183 const char* base = type_descriptor + 1; 1184 int arg_num = 0; 1185 while (*base != ')') { 1186 char* cp = tmp_buf; 1187 while (*base == '[') { 1188 *cp++ = *base++; 1189 } 1190 if (*base == 'L') { 1191 // Copy through ';'. 1192 do { 1193 *cp = *base++; 1194 } while (*cp++ != ';'); 1195 } else { 1196 // Primitive char, copy it. 1197 if (strchr("ZBCSIFJD", *base) == nullptr) { 1198 fprintf(stderr, "ERROR: bad method signature '%s'\n", base); 1199 break; // while 1200 } 1201 *cp++ = *base++; 1202 } 1203 // Null terminate and display. 1204 *cp++ = '\0'; 1205 std::string dot(DescriptorToDotWrapper(tmp_buf)); 1206 fprintf(out_file_, "<parameter name=\"arg%d\" type=\"%s\">\n" 1207 "</parameter>\n", arg_num++, dot.c_str()); 1208 } // while 1209 free(tmp_buf); 1210 if (constructor) { 1211 fprintf(out_file_, "</constructor>\n"); 1212 } else { 1213 fprintf(out_file_, "</method>\n"); 1214 } 1215 } 1216 1217 bail: 1218 free(type_descriptor); 1219 free(access_str); 1220} 1221 1222/* 1223 * Dumps a static (class) field. 1224 */ 1225void DexLayout::DumpSField(uint32_t idx, uint32_t flags, int i, dex_ir::EncodedValue* init) { 1226 // Bail for anything private if export only requested. 1227 if (options_.exports_only_ && (flags & (kAccPublic | kAccProtected)) == 0) { 1228 return; 1229 } 1230 1231 dex_ir::FieldId* field_id = header_->GetCollections().GetFieldId(idx); 1232 const char* name = field_id->Name()->Data(); 1233 const char* type_descriptor = field_id->Type()->GetStringId()->Data(); 1234 const char* back_descriptor = field_id->Class()->GetStringId()->Data(); 1235 char* access_str = CreateAccessFlagStr(flags, kAccessForField); 1236 1237 if (options_.output_format_ == kOutputPlain) { 1238 fprintf(out_file_, " #%d : (in %s)\n", i, back_descriptor); 1239 fprintf(out_file_, " name : '%s'\n", name); 1240 fprintf(out_file_, " type : '%s'\n", type_descriptor); 1241 fprintf(out_file_, " access : 0x%04x (%s)\n", flags, access_str); 1242 if (init != nullptr) { 1243 fputs(" value : ", out_file_); 1244 DumpEncodedValue(init); 1245 fputs("\n", out_file_); 1246 } 1247 } else if (options_.output_format_ == kOutputXml) { 1248 fprintf(out_file_, "<field name=\"%s\"\n", name); 1249 std::string dot(DescriptorToDotWrapper(type_descriptor)); 1250 fprintf(out_file_, " type=\"%s\"\n", dot.c_str()); 1251 fprintf(out_file_, " transient=%s\n", QuotedBool((flags & kAccTransient) != 0)); 1252 fprintf(out_file_, " volatile=%s\n", QuotedBool((flags & kAccVolatile) != 0)); 1253 // The "value=" is not knowable w/o parsing annotations. 1254 fprintf(out_file_, " static=%s\n", QuotedBool((flags & kAccStatic) != 0)); 1255 fprintf(out_file_, " final=%s\n", QuotedBool((flags & kAccFinal) != 0)); 1256 // The "deprecated=" is not knowable w/o parsing annotations. 1257 fprintf(out_file_, " visibility=%s\n", QuotedVisibility(flags)); 1258 if (init != nullptr) { 1259 fputs(" value=\"", out_file_); 1260 DumpEncodedValue(init); 1261 fputs("\"\n", out_file_); 1262 } 1263 fputs(">\n</field>\n", out_file_); 1264 } 1265 1266 free(access_str); 1267} 1268 1269/* 1270 * Dumps an instance field. 1271 */ 1272void DexLayout::DumpIField(uint32_t idx, uint32_t flags, int i) { 1273 DumpSField(idx, flags, i, nullptr); 1274} 1275 1276/* 1277 * Dumps the class. 1278 * 1279 * Note "idx" is a DexClassDef index, not a DexTypeId index. 1280 * 1281 * If "*last_package" is nullptr or does not match the current class' package, 1282 * the value will be replaced with a newly-allocated string. 1283 */ 1284void DexLayout::DumpClass(int idx, char** last_package) { 1285 dex_ir::ClassDef* class_def = header_->GetCollections().GetClassDef(idx); 1286 // Omitting non-public class. 1287 if (options_.exports_only_ && (class_def->GetAccessFlags() & kAccPublic) == 0) { 1288 return; 1289 } 1290 1291 if (options_.show_section_headers_) { 1292 DumpClassDef(idx); 1293 } 1294 1295 if (options_.show_annotations_) { 1296 DumpClassAnnotations(idx); 1297 } 1298 1299 // For the XML output, show the package name. Ideally we'd gather 1300 // up the classes, sort them, and dump them alphabetically so the 1301 // package name wouldn't jump around, but that's not a great plan 1302 // for something that needs to run on the device. 1303 const char* class_descriptor = 1304 header_->GetCollections().GetClassDef(idx)->ClassType()->GetStringId()->Data(); 1305 if (!(class_descriptor[0] == 'L' && 1306 class_descriptor[strlen(class_descriptor)-1] == ';')) { 1307 // Arrays and primitives should not be defined explicitly. Keep going? 1308 fprintf(stderr, "Malformed class name '%s'\n", class_descriptor); 1309 } else if (options_.output_format_ == kOutputXml) { 1310 char* mangle = strdup(class_descriptor + 1); 1311 mangle[strlen(mangle)-1] = '\0'; 1312 1313 // Reduce to just the package name. 1314 char* last_slash = strrchr(mangle, '/'); 1315 if (last_slash != nullptr) { 1316 *last_slash = '\0'; 1317 } else { 1318 *mangle = '\0'; 1319 } 1320 1321 for (char* cp = mangle; *cp != '\0'; cp++) { 1322 if (*cp == '/') { 1323 *cp = '.'; 1324 } 1325 } // for 1326 1327 if (*last_package == nullptr || strcmp(mangle, *last_package) != 0) { 1328 // Start of a new package. 1329 if (*last_package != nullptr) { 1330 fprintf(out_file_, "</package>\n"); 1331 } 1332 fprintf(out_file_, "<package name=\"%s\"\n>\n", mangle); 1333 free(*last_package); 1334 *last_package = mangle; 1335 } else { 1336 free(mangle); 1337 } 1338 } 1339 1340 // General class information. 1341 char* access_str = CreateAccessFlagStr(class_def->GetAccessFlags(), kAccessForClass); 1342 const char* superclass_descriptor = nullptr; 1343 if (class_def->Superclass() != nullptr) { 1344 superclass_descriptor = class_def->Superclass()->GetStringId()->Data(); 1345 } 1346 if (options_.output_format_ == kOutputPlain) { 1347 fprintf(out_file_, "Class #%d -\n", idx); 1348 fprintf(out_file_, " Class descriptor : '%s'\n", class_descriptor); 1349 fprintf(out_file_, " Access flags : 0x%04x (%s)\n", 1350 class_def->GetAccessFlags(), access_str); 1351 if (superclass_descriptor != nullptr) { 1352 fprintf(out_file_, " Superclass : '%s'\n", superclass_descriptor); 1353 } 1354 fprintf(out_file_, " Interfaces -\n"); 1355 } else { 1356 std::string dot(DescriptorClassToDot(class_descriptor)); 1357 fprintf(out_file_, "<class name=\"%s\"\n", dot.c_str()); 1358 if (superclass_descriptor != nullptr) { 1359 dot = DescriptorToDotWrapper(superclass_descriptor); 1360 fprintf(out_file_, " extends=\"%s\"\n", dot.c_str()); 1361 } 1362 fprintf(out_file_, " interface=%s\n", 1363 QuotedBool((class_def->GetAccessFlags() & kAccInterface) != 0)); 1364 fprintf(out_file_, " abstract=%s\n", 1365 QuotedBool((class_def->GetAccessFlags() & kAccAbstract) != 0)); 1366 fprintf(out_file_, " static=%s\n", QuotedBool((class_def->GetAccessFlags() & kAccStatic) != 0)); 1367 fprintf(out_file_, " final=%s\n", QuotedBool((class_def->GetAccessFlags() & kAccFinal) != 0)); 1368 // The "deprecated=" not knowable w/o parsing annotations. 1369 fprintf(out_file_, " visibility=%s\n", QuotedVisibility(class_def->GetAccessFlags())); 1370 fprintf(out_file_, ">\n"); 1371 } 1372 1373 // Interfaces. 1374 const dex_ir::TypeList* interfaces = class_def->Interfaces(); 1375 if (interfaces != nullptr) { 1376 const dex_ir::TypeIdVector* interfaces_vector = interfaces->GetTypeList(); 1377 for (uint32_t i = 0; i < interfaces_vector->size(); i++) { 1378 DumpInterface((*interfaces_vector)[i], i); 1379 } // for 1380 } 1381 1382 // Fields and methods. 1383 dex_ir::ClassData* class_data = class_def->GetClassData(); 1384 // Prepare data for static fields. 1385 dex_ir::EncodedArrayItem* static_values = class_def->StaticValues(); 1386 dex_ir::EncodedValueVector* encoded_values = 1387 static_values == nullptr ? nullptr : static_values->GetEncodedValues(); 1388 const uint32_t encoded_values_size = (encoded_values == nullptr) ? 0 : encoded_values->size(); 1389 1390 // Static fields. 1391 if (options_.output_format_ == kOutputPlain) { 1392 fprintf(out_file_, " Static fields -\n"); 1393 } 1394 if (class_data != nullptr) { 1395 dex_ir::FieldItemVector* static_fields = class_data->StaticFields(); 1396 if (static_fields != nullptr) { 1397 for (uint32_t i = 0; i < static_fields->size(); i++) { 1398 DumpSField((*static_fields)[i]->GetFieldId()->GetIndex(), 1399 (*static_fields)[i]->GetAccessFlags(), 1400 i, 1401 i < encoded_values_size ? (*encoded_values)[i].get() : nullptr); 1402 } // for 1403 } 1404 } 1405 1406 // Instance fields. 1407 if (options_.output_format_ == kOutputPlain) { 1408 fprintf(out_file_, " Instance fields -\n"); 1409 } 1410 if (class_data != nullptr) { 1411 dex_ir::FieldItemVector* instance_fields = class_data->InstanceFields(); 1412 if (instance_fields != nullptr) { 1413 for (uint32_t i = 0; i < instance_fields->size(); i++) { 1414 DumpIField((*instance_fields)[i]->GetFieldId()->GetIndex(), 1415 (*instance_fields)[i]->GetAccessFlags(), 1416 i); 1417 } // for 1418 } 1419 } 1420 1421 // Direct methods. 1422 if (options_.output_format_ == kOutputPlain) { 1423 fprintf(out_file_, " Direct methods -\n"); 1424 } 1425 if (class_data != nullptr) { 1426 dex_ir::MethodItemVector* direct_methods = class_data->DirectMethods(); 1427 if (direct_methods != nullptr) { 1428 for (uint32_t i = 0; i < direct_methods->size(); i++) { 1429 DumpMethod((*direct_methods)[i]->GetMethodId()->GetIndex(), 1430 (*direct_methods)[i]->GetAccessFlags(), 1431 (*direct_methods)[i]->GetCodeItem(), 1432 i); 1433 } // for 1434 } 1435 } 1436 1437 // Virtual methods. 1438 if (options_.output_format_ == kOutputPlain) { 1439 fprintf(out_file_, " Virtual methods -\n"); 1440 } 1441 if (class_data != nullptr) { 1442 dex_ir::MethodItemVector* virtual_methods = class_data->VirtualMethods(); 1443 if (virtual_methods != nullptr) { 1444 for (uint32_t i = 0; i < virtual_methods->size(); i++) { 1445 DumpMethod((*virtual_methods)[i]->GetMethodId()->GetIndex(), 1446 (*virtual_methods)[i]->GetAccessFlags(), 1447 (*virtual_methods)[i]->GetCodeItem(), 1448 i); 1449 } // for 1450 } 1451 } 1452 1453 // End of class. 1454 if (options_.output_format_ == kOutputPlain) { 1455 const char* file_name = "unknown"; 1456 if (class_def->SourceFile() != nullptr) { 1457 file_name = class_def->SourceFile()->Data(); 1458 } 1459 const dex_ir::StringId* source_file = class_def->SourceFile(); 1460 fprintf(out_file_, " source_file_idx : %d (%s)\n\n", 1461 source_file == nullptr ? 0xffffffffU : source_file->GetIndex(), file_name); 1462 } else if (options_.output_format_ == kOutputXml) { 1463 fprintf(out_file_, "</class>\n"); 1464 } 1465 1466 free(access_str); 1467} 1468 1469void DexLayout::DumpDexFile() { 1470 // Headers. 1471 if (options_.show_file_headers_) { 1472 DumpFileHeader(); 1473 } 1474 1475 // Open XML context. 1476 if (options_.output_format_ == kOutputXml) { 1477 fprintf(out_file_, "<api>\n"); 1478 } 1479 1480 // Iterate over all classes. 1481 char* package = nullptr; 1482 const uint32_t class_defs_size = header_->GetCollections().ClassDefsSize(); 1483 for (uint32_t i = 0; i < class_defs_size; i++) { 1484 DumpClass(i, &package); 1485 } // for 1486 1487 // Free the last package allocated. 1488 if (package != nullptr) { 1489 fprintf(out_file_, "</package>\n"); 1490 free(package); 1491 } 1492 1493 // Close XML context. 1494 if (options_.output_format_ == kOutputXml) { 1495 fprintf(out_file_, "</api>\n"); 1496 } 1497} 1498 1499std::vector<dex_ir::ClassData*> DexLayout::LayoutClassDefsAndClassData(const DexFile* dex_file) { 1500 std::vector<dex_ir::ClassDef*> new_class_def_order; 1501 for (std::unique_ptr<dex_ir::ClassDef>& class_def : header_->GetCollections().ClassDefs()) { 1502 dex::TypeIndex type_idx(class_def->ClassType()->GetIndex()); 1503 if (info_->ContainsClass(*dex_file, type_idx)) { 1504 new_class_def_order.push_back(class_def.get()); 1505 } 1506 } 1507 for (std::unique_ptr<dex_ir::ClassDef>& class_def : header_->GetCollections().ClassDefs()) { 1508 dex::TypeIndex type_idx(class_def->ClassType()->GetIndex()); 1509 if (!info_->ContainsClass(*dex_file, type_idx)) { 1510 new_class_def_order.push_back(class_def.get()); 1511 } 1512 } 1513 uint32_t class_defs_offset = header_->GetCollections().ClassDefsOffset(); 1514 uint32_t class_data_offset = header_->GetCollections().ClassDatasOffset(); 1515 std::unordered_set<dex_ir::ClassData*> visited_class_data; 1516 std::vector<dex_ir::ClassData*> new_class_data_order; 1517 for (uint32_t i = 0; i < new_class_def_order.size(); ++i) { 1518 dex_ir::ClassDef* class_def = new_class_def_order[i]; 1519 class_def->SetIndex(i); 1520 class_def->SetOffset(class_defs_offset); 1521 class_defs_offset += dex_ir::ClassDef::ItemSize(); 1522 dex_ir::ClassData* class_data = class_def->GetClassData(); 1523 if (class_data != nullptr && visited_class_data.find(class_data) == visited_class_data.end()) { 1524 class_data->SetOffset(class_data_offset); 1525 class_data_offset += class_data->GetSize(); 1526 visited_class_data.insert(class_data); 1527 new_class_data_order.push_back(class_data); 1528 } 1529 } 1530 return new_class_data_order; 1531} 1532 1533void DexLayout::LayoutStringData(const DexFile* dex_file) { 1534 const size_t num_strings = header_->GetCollections().StringIds().size(); 1535 std::vector<bool> is_shorty(num_strings, false); 1536 std::vector<bool> from_hot_method(num_strings, false); 1537 for (std::unique_ptr<dex_ir::ClassDef>& class_def : header_->GetCollections().ClassDefs()) { 1538 // A name of a profile class is probably going to get looked up by ClassTable::Lookup, mark it 1539 // as hot. 1540 const bool is_profile_class = 1541 info_->ContainsClass(*dex_file, dex::TypeIndex(class_def->ClassType()->GetIndex())); 1542 if (is_profile_class) { 1543 from_hot_method[class_def->ClassType()->GetStringId()->GetIndex()] = true; 1544 } 1545 dex_ir::ClassData* data = class_def->GetClassData(); 1546 if (data == nullptr) { 1547 continue; 1548 } 1549 for (size_t i = 0; i < 2; ++i) { 1550 for (auto& method : *(i == 0 ? data->DirectMethods() : data->VirtualMethods())) { 1551 const dex_ir::MethodId* method_id = method->GetMethodId(); 1552 dex_ir::CodeItem* code_item = method->GetCodeItem(); 1553 if (code_item == nullptr) { 1554 continue; 1555 } 1556 const bool is_clinit = is_profile_class && 1557 (method->GetAccessFlags() & kAccConstructor) != 0 && 1558 (method->GetAccessFlags() & kAccStatic) != 0; 1559 const bool method_executed = is_clinit || 1560 info_->IsStartupOrHotMethod(MethodReference(dex_file, method_id->GetIndex())); 1561 if (!method_executed) { 1562 continue; 1563 } 1564 is_shorty[method_id->Proto()->Shorty()->GetIndex()] = true; 1565 dex_ir::CodeFixups* fixups = code_item->GetCodeFixups(); 1566 if (fixups == nullptr) { 1567 continue; 1568 } 1569 if (fixups->StringIds() != nullptr) { 1570 // Add const-strings. 1571 for (dex_ir::StringId* id : *fixups->StringIds()) { 1572 from_hot_method[id->GetIndex()] = true; 1573 } 1574 } 1575 // TODO: Only visit field ids from static getters and setters. 1576 for (dex_ir::FieldId* id : *fixups->FieldIds()) { 1577 // Add the field names and types from getters and setters. 1578 from_hot_method[id->Name()->GetIndex()] = true; 1579 from_hot_method[id->Type()->GetStringId()->GetIndex()] = true; 1580 } 1581 } 1582 } 1583 } 1584 // Sort string data by specified order. 1585 std::vector<dex_ir::StringId*> string_ids; 1586 size_t min_offset = std::numeric_limits<size_t>::max(); 1587 size_t max_offset = 0; 1588 size_t hot_bytes = 0; 1589 for (auto& string_id : header_->GetCollections().StringIds()) { 1590 string_ids.push_back(string_id.get()); 1591 const size_t cur_offset = string_id->DataItem()->GetOffset(); 1592 CHECK_NE(cur_offset, 0u); 1593 min_offset = std::min(min_offset, cur_offset); 1594 dex_ir::StringData* data = string_id->DataItem(); 1595 const size_t element_size = data->GetSize() + 1; // Add one extra for null. 1596 size_t end_offset = cur_offset + element_size; 1597 if (is_shorty[string_id->GetIndex()] || from_hot_method[string_id->GetIndex()]) { 1598 hot_bytes += element_size; 1599 } 1600 max_offset = std::max(max_offset, end_offset); 1601 } 1602 VLOG(compiler) << "Hot string data bytes " << hot_bytes << "/" << max_offset - min_offset; 1603 std::sort(string_ids.begin(), 1604 string_ids.end(), 1605 [&is_shorty, &from_hot_method](const dex_ir::StringId* a, 1606 const dex_ir::StringId* b) { 1607 const bool a_is_hot = from_hot_method[a->GetIndex()]; 1608 const bool b_is_hot = from_hot_method[b->GetIndex()]; 1609 if (a_is_hot != b_is_hot) { 1610 return a_is_hot < b_is_hot; 1611 } 1612 // After hot methods are partitioned, subpartition shorties. 1613 const bool a_is_shorty = is_shorty[a->GetIndex()]; 1614 const bool b_is_shorty = is_shorty[b->GetIndex()]; 1615 if (a_is_shorty != b_is_shorty) { 1616 return a_is_shorty < b_is_shorty; 1617 } 1618 // Preserve order. 1619 return a->DataItem()->GetOffset() < b->DataItem()->GetOffset(); 1620 }); 1621 // Now we know what order we want the string data, reorder the offsets. 1622 size_t offset = min_offset; 1623 for (dex_ir::StringId* string_id : string_ids) { 1624 dex_ir::StringData* data = string_id->DataItem(); 1625 data->SetOffset(offset); 1626 offset += data->GetSize() + 1; // Add one extra for null. 1627 } 1628 if (offset > max_offset) { 1629 const uint32_t diff = offset - max_offset; 1630 // If we expanded the string data section, we need to update the offsets or else we will 1631 // corrupt the next section when writing out. 1632 FixupSections(header_->GetCollections().StringDatasOffset(), diff); 1633 // Update file size. 1634 header_->SetFileSize(header_->FileSize() + diff); 1635 } 1636} 1637 1638// Orders code items according to specified class data ordering. 1639// NOTE: If the section following the code items is byte aligned, the last code item is left in 1640// place to preserve alignment. Layout needs an overhaul to handle movement of other sections. 1641int32_t DexLayout::LayoutCodeItems(const DexFile* dex_file, 1642 std::vector<dex_ir::ClassData*> new_class_data_order) { 1643 // Do not move code items if class data section precedes code item section. 1644 // ULEB encoding is variable length, causing problems determining the offset of the code items. 1645 // TODO: We should swap the order of these sections in the future to avoid this issue. 1646 uint32_t class_data_offset = header_->GetCollections().ClassDatasOffset(); 1647 uint32_t code_item_offset = header_->GetCollections().CodeItemsOffset(); 1648 if (class_data_offset < code_item_offset) { 1649 return 0; 1650 } 1651 1652 // Find the last code item so we can leave it in place if the next section is not 4 byte aligned. 1653 dex_ir::CodeItem* last_code_item = nullptr; 1654 std::unordered_set<dex_ir::CodeItem*> visited_code_items; 1655 bool is_code_item_aligned = IsNextSectionCodeItemAligned(code_item_offset); 1656 if (!is_code_item_aligned) { 1657 for (auto& code_item_pair : header_->GetCollections().CodeItems()) { 1658 std::unique_ptr<dex_ir::CodeItem>& code_item = code_item_pair.second; 1659 if (last_code_item == nullptr 1660 || last_code_item->GetOffset() < code_item->GetOffset()) { 1661 last_code_item = code_item.get(); 1662 } 1663 } 1664 } 1665 1666 enum CodeItemKind { 1667 kMethodNotExecuted = 0, 1668 kMethodExecuted = 1, 1669 kSize = 2, 1670 }; 1671 1672 static constexpr InvokeType invoke_types[] = { 1673 kDirect, 1674 kVirtual 1675 }; 1676 1677 std::unordered_set<dex_ir::CodeItem*> code_items[CodeItemKind::kSize]; 1678 for (InvokeType invoke_type : invoke_types) { 1679 for (std::unique_ptr<dex_ir::ClassDef>& class_def : header_->GetCollections().ClassDefs()) { 1680 const bool is_profile_class = 1681 info_->ContainsClass(*dex_file, dex::TypeIndex(class_def->ClassType()->GetIndex())); 1682 1683 // Skip classes that are not defined in this dex file. 1684 dex_ir::ClassData* class_data = class_def->GetClassData(); 1685 if (class_data == nullptr) { 1686 continue; 1687 } 1688 for (auto& method : *(invoke_type == InvokeType::kDirect 1689 ? class_data->DirectMethods() 1690 : class_data->VirtualMethods())) { 1691 const dex_ir::MethodId *method_id = method->GetMethodId(); 1692 dex_ir::CodeItem *code_item = method->GetCodeItem(); 1693 if (code_item == last_code_item || code_item == nullptr) { 1694 continue; 1695 } 1696 // Separate executed methods (clinits and profiled methods) from unexecuted methods. 1697 // TODO: clinits are executed only once, consider separating them further. 1698 const bool is_clinit = is_profile_class && 1699 (method->GetAccessFlags() & kAccConstructor) != 0 && 1700 (method->GetAccessFlags() & kAccStatic) != 0; 1701 const bool is_method_executed = is_clinit || 1702 info_->IsStartupOrHotMethod(MethodReference(dex_file, method_id->GetIndex())); 1703 code_items[is_method_executed 1704 ? CodeItemKind::kMethodExecuted 1705 : CodeItemKind::kMethodNotExecuted] 1706 .insert(code_item); 1707 } 1708 } 1709 } 1710 1711 // total_diff includes diffs generated by both executed and non-executed methods. 1712 int32_t total_diff = 0; 1713 // The relative placement has no effect on correctness; it is used to ensure 1714 // the layout is deterministic 1715 for (std::unordered_set<dex_ir::CodeItem*>& code_items_set : code_items) { 1716 // diff is reset for executed and non-executed methods. 1717 int32_t diff = 0; 1718 for (dex_ir::ClassData* data : new_class_data_order) { 1719 data->SetOffset(data->GetOffset() + diff); 1720 for (InvokeType invoke_type : invoke_types) { 1721 for (auto &method : *(invoke_type == InvokeType::kDirect 1722 ? data->DirectMethods() 1723 : data->VirtualMethods())) { 1724 dex_ir::CodeItem* code_item = method->GetCodeItem(); 1725 if (code_item != nullptr && 1726 code_items_set.find(code_item) != code_items_set.end()) { 1727 diff += UnsignedLeb128Size(code_item_offset) 1728 - UnsignedLeb128Size(code_item->GetOffset()); 1729 code_item->SetOffset(code_item_offset); 1730 code_item_offset += 1731 RoundUp(code_item->GetSize(), kDexCodeItemAlignment); 1732 } 1733 } 1734 } 1735 } 1736 total_diff += diff; 1737 } 1738 // Adjust diff to be 4-byte aligned. 1739 return RoundUp(total_diff, kDexCodeItemAlignment); 1740} 1741 1742bool DexLayout::IsNextSectionCodeItemAligned(uint32_t offset) { 1743 dex_ir::Collections& collections = header_->GetCollections(); 1744 std::set<uint32_t> section_offsets; 1745 section_offsets.insert(collections.MapListOffset()); 1746 section_offsets.insert(collections.TypeListsOffset()); 1747 section_offsets.insert(collections.AnnotationSetRefListsOffset()); 1748 section_offsets.insert(collections.AnnotationSetItemsOffset()); 1749 section_offsets.insert(collections.ClassDatasOffset()); 1750 section_offsets.insert(collections.CodeItemsOffset()); 1751 section_offsets.insert(collections.StringDatasOffset()); 1752 section_offsets.insert(collections.DebugInfoItemsOffset()); 1753 section_offsets.insert(collections.AnnotationItemsOffset()); 1754 section_offsets.insert(collections.EncodedArrayItemsOffset()); 1755 section_offsets.insert(collections.AnnotationsDirectoryItemsOffset()); 1756 1757 auto found = section_offsets.find(offset); 1758 if (found != section_offsets.end()) { 1759 found++; 1760 if (found != section_offsets.end()) { 1761 return *found % kDexCodeItemAlignment == 0; 1762 } 1763 } 1764 return false; 1765} 1766 1767// Adjust offsets of every item in the specified section by diff bytes. 1768template<class T> void DexLayout::FixupSection(std::map<uint32_t, std::unique_ptr<T>>& map, 1769 uint32_t diff) { 1770 for (auto& pair : map) { 1771 std::unique_ptr<T>& item = pair.second; 1772 item->SetOffset(item->GetOffset() + diff); 1773 } 1774} 1775 1776// Adjust offsets of all sections with an address after the specified offset by diff bytes. 1777void DexLayout::FixupSections(uint32_t offset, uint32_t diff) { 1778 dex_ir::Collections& collections = header_->GetCollections(); 1779 uint32_t map_list_offset = collections.MapListOffset(); 1780 if (map_list_offset > offset) { 1781 collections.SetMapListOffset(map_list_offset + diff); 1782 } 1783 1784 uint32_t type_lists_offset = collections.TypeListsOffset(); 1785 if (type_lists_offset > offset) { 1786 collections.SetTypeListsOffset(type_lists_offset + diff); 1787 FixupSection(collections.TypeLists(), diff); 1788 } 1789 1790 uint32_t annotation_set_ref_lists_offset = collections.AnnotationSetRefListsOffset(); 1791 if (annotation_set_ref_lists_offset > offset) { 1792 collections.SetAnnotationSetRefListsOffset(annotation_set_ref_lists_offset + diff); 1793 FixupSection(collections.AnnotationSetRefLists(), diff); 1794 } 1795 1796 uint32_t annotation_set_items_offset = collections.AnnotationSetItemsOffset(); 1797 if (annotation_set_items_offset > offset) { 1798 collections.SetAnnotationSetItemsOffset(annotation_set_items_offset + diff); 1799 FixupSection(collections.AnnotationSetItems(), diff); 1800 } 1801 1802 uint32_t class_datas_offset = collections.ClassDatasOffset(); 1803 if (class_datas_offset > offset) { 1804 collections.SetClassDatasOffset(class_datas_offset + diff); 1805 FixupSection(collections.ClassDatas(), diff); 1806 } 1807 1808 uint32_t code_items_offset = collections.CodeItemsOffset(); 1809 if (code_items_offset > offset) { 1810 collections.SetCodeItemsOffset(code_items_offset + diff); 1811 FixupSection(collections.CodeItems(), diff); 1812 } 1813 1814 uint32_t string_datas_offset = collections.StringDatasOffset(); 1815 if (string_datas_offset > offset) { 1816 collections.SetStringDatasOffset(string_datas_offset + diff); 1817 FixupSection(collections.StringDatas(), diff); 1818 } 1819 1820 uint32_t debug_info_items_offset = collections.DebugInfoItemsOffset(); 1821 if (debug_info_items_offset > offset) { 1822 collections.SetDebugInfoItemsOffset(debug_info_items_offset + diff); 1823 FixupSection(collections.DebugInfoItems(), diff); 1824 } 1825 1826 uint32_t annotation_items_offset = collections.AnnotationItemsOffset(); 1827 if (annotation_items_offset > offset) { 1828 collections.SetAnnotationItemsOffset(annotation_items_offset + diff); 1829 FixupSection(collections.AnnotationItems(), diff); 1830 } 1831 1832 uint32_t encoded_array_items_offset = collections.EncodedArrayItemsOffset(); 1833 if (encoded_array_items_offset > offset) { 1834 collections.SetEncodedArrayItemsOffset(encoded_array_items_offset + diff); 1835 FixupSection(collections.EncodedArrayItems(), diff); 1836 } 1837 1838 uint32_t annotations_directory_items_offset = collections.AnnotationsDirectoryItemsOffset(); 1839 if (annotations_directory_items_offset > offset) { 1840 collections.SetAnnotationsDirectoryItemsOffset(annotations_directory_items_offset + diff); 1841 FixupSection(collections.AnnotationsDirectoryItems(), diff); 1842 } 1843} 1844 1845void DexLayout::LayoutOutputFile(const DexFile* dex_file) { 1846 LayoutStringData(dex_file); 1847 std::vector<dex_ir::ClassData*> new_class_data_order = LayoutClassDefsAndClassData(dex_file); 1848 int32_t diff = LayoutCodeItems(dex_file, new_class_data_order); 1849 // Move sections after ClassData by diff bytes. 1850 FixupSections(header_->GetCollections().ClassDatasOffset(), diff); 1851 // Update file size. 1852 header_->SetFileSize(header_->FileSize() + diff); 1853} 1854 1855void DexLayout::OutputDexFile(const DexFile* dex_file) { 1856 const std::string& dex_file_location = dex_file->GetLocation(); 1857 std::string error_msg; 1858 std::unique_ptr<File> new_file; 1859 if (!options_.output_to_memmap_) { 1860 std::string output_location(options_.output_dex_directory_); 1861 size_t last_slash = dex_file_location.rfind('/'); 1862 std::string dex_file_directory = dex_file_location.substr(0, last_slash + 1); 1863 if (output_location == dex_file_directory) { 1864 output_location = dex_file_location + ".new"; 1865 } else if (last_slash != std::string::npos) { 1866 output_location += dex_file_location.substr(last_slash); 1867 } else { 1868 output_location += "/" + dex_file_location + ".new"; 1869 } 1870 new_file.reset(OS::CreateEmptyFile(output_location.c_str())); 1871 if (new_file == nullptr) { 1872 LOG(ERROR) << "Could not create dex writer output file: " << output_location; 1873 return; 1874 } 1875 if (ftruncate(new_file->Fd(), header_->FileSize()) != 0) { 1876 LOG(ERROR) << "Could not grow dex writer output file: " << output_location;; 1877 new_file->Erase(); 1878 return; 1879 } 1880 mem_map_.reset(MemMap::MapFile(header_->FileSize(), PROT_READ | PROT_WRITE, MAP_SHARED, 1881 new_file->Fd(), 0, /*low_4gb*/ false, output_location.c_str(), &error_msg)); 1882 } else { 1883 mem_map_.reset(MemMap::MapAnonymous("layout dex", nullptr, header_->FileSize(), 1884 PROT_READ | PROT_WRITE, /* low_4gb */ false, /* reuse */ false, &error_msg)); 1885 } 1886 if (mem_map_ == nullptr) { 1887 LOG(ERROR) << "Could not create mem map for dex writer output: " << error_msg; 1888 if (new_file != nullptr) { 1889 new_file->Erase(); 1890 } 1891 return; 1892 } 1893 DexWriter::Output(header_, mem_map_.get()); 1894 if (new_file != nullptr) { 1895 UNUSED(new_file->FlushCloseOrErase()); 1896 } 1897 // Verify the output dex file's structure for debug builds. 1898 if (kIsDebugBuild) { 1899 std::string location = "memory mapped file for " + dex_file_location; 1900 std::unique_ptr<const DexFile> output_dex_file(DexFile::Open(mem_map_->Begin(), 1901 mem_map_->Size(), 1902 location, 1903 header_->Checksum(), 1904 /*oat_dex_file*/ nullptr, 1905 /*verify*/ true, 1906 /*verify_checksum*/ false, 1907 &error_msg)); 1908 DCHECK(output_dex_file != nullptr) << "Failed to re-open output file:" << error_msg; 1909 } 1910 // Do IR-level comparison between input and output. This check ignores potential differences 1911 // due to layout, so offsets are not checked. Instead, it checks the data contents of each item. 1912 if (kIsDebugBuild || options_.verify_output_) { 1913 std::unique_ptr<dex_ir::Header> orig_header(dex_ir::DexIrBuilder(*dex_file)); 1914 CHECK(VerifyOutputDexFile(orig_header.get(), header_, &error_msg)) << error_msg; 1915 } 1916} 1917 1918/* 1919 * Dumps the requested sections of the file. 1920 */ 1921void DexLayout::ProcessDexFile(const char* file_name, 1922 const DexFile* dex_file, 1923 size_t dex_file_index) { 1924 std::unique_ptr<dex_ir::Header> header(dex_ir::DexIrBuilder(*dex_file)); 1925 SetHeader(header.get()); 1926 1927 if (options_.verbose_) { 1928 fprintf(out_file_, "Opened '%s', DEX version '%.3s'\n", 1929 file_name, dex_file->GetHeader().magic_ + 4); 1930 } 1931 1932 if (options_.visualize_pattern_) { 1933 VisualizeDexLayout(header_, dex_file, dex_file_index, info_); 1934 return; 1935 } 1936 1937 if (options_.show_section_statistics_) { 1938 ShowDexSectionStatistics(header_, dex_file_index); 1939 return; 1940 } 1941 1942 // Dump dex file. 1943 if (options_.dump_) { 1944 DumpDexFile(); 1945 } 1946 1947 // Output dex file as file or memmap. 1948 if (options_.output_dex_directory_ != nullptr || options_.output_to_memmap_) { 1949 if (info_ != nullptr) { 1950 LayoutOutputFile(dex_file); 1951 } 1952 OutputDexFile(dex_file); 1953 } 1954} 1955 1956/* 1957 * Processes a single file (either direct .dex or indirect .zip/.jar/.apk). 1958 */ 1959int DexLayout::ProcessFile(const char* file_name) { 1960 if (options_.verbose_) { 1961 fprintf(out_file_, "Processing '%s'...\n", file_name); 1962 } 1963 1964 // If the file is not a .dex file, the function tries .zip/.jar/.apk files, 1965 // all of which are Zip archives with "classes.dex" inside. 1966 const bool verify_checksum = !options_.ignore_bad_checksum_; 1967 std::string error_msg; 1968 std::vector<std::unique_ptr<const DexFile>> dex_files; 1969 if (!DexFile::Open(file_name, file_name, verify_checksum, &error_msg, &dex_files)) { 1970 // Display returned error message to user. Note that this error behavior 1971 // differs from the error messages shown by the original Dalvik dexdump. 1972 fputs(error_msg.c_str(), stderr); 1973 fputc('\n', stderr); 1974 return -1; 1975 } 1976 1977 // Success. Either report checksum verification or process 1978 // all dex files found in given file. 1979 if (options_.checksum_only_) { 1980 fprintf(out_file_, "Checksum verified\n"); 1981 } else { 1982 for (size_t i = 0; i < dex_files.size(); i++) { 1983 ProcessDexFile(file_name, dex_files[i].get(), i); 1984 } 1985 } 1986 return 0; 1987} 1988 1989} // namespace art 1990