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