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