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