1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998
|
/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ART_LIBDEXFILE_DEX_DEX_FILE_H_
#define ART_LIBDEXFILE_DEX_DEX_FILE_H_
#include <memory>
#include <string>
#include <string_view>
#include <vector>
#include <android-base/logging.h>
#include "base/globals.h"
#include "base/macros.h"
#include "base/value_object.h"
#include "dex_file_structs.h"
#include "dex_file_types.h"
#include "jni.h"
#include "modifiers.h"
namespace art {
class ClassDataItemIterator;
class ClassIterator;
class CompactDexFile;
class DexInstructionIterator;
enum InvokeType : uint32_t;
template <typename Iter> class IterationRange;
class MemMap;
class OatDexFile;
class Signature;
class StandardDexFile;
class ZipArchive;
namespace hiddenapi {
enum class Domain : char;
} // namespace hiddenapi
// Some instances of DexFile own the storage referred to by DexFile. Clients who create
// such management do so by subclassing Container.
class DexFileContainer {
public:
DexFileContainer() { }
virtual ~DexFileContainer() { }
virtual int GetPermissions() = 0;
virtual bool IsReadOnly() = 0;
virtual bool EnableWrite() = 0;
virtual bool DisableWrite() = 0;
private:
DISALLOW_COPY_AND_ASSIGN(DexFileContainer);
};
// Dex file is the API that exposes native dex files (ordinary dex files) and CompactDex.
// Originally, the dex file format used by ART was mostly the same as APKs. The only change was
// quickened opcodes and layout optimizations.
// Since ART needs to support both native dex files and CompactDex files, the DexFile interface
// provides an abstraction to facilitate this.
class DexFile {
public:
// Number of bytes in the dex file magic.
static constexpr size_t kDexMagicSize = 4;
static constexpr size_t kDexVersionLen = 4;
// First Dex format version enforcing class definition ordering rules.
static const uint32_t kClassDefinitionOrderEnforcedVersion = 37;
static constexpr size_t kSha1DigestSize = 20;
static constexpr uint32_t kDexEndianConstant = 0x12345678;
// The value of an invalid index.
static const uint16_t kDexNoIndex16 = 0xFFFF;
static const uint32_t kDexNoIndex32 = 0xFFFFFFFF;
// Raw header_item.
struct Header {
uint8_t magic_[8] = {};
uint32_t checksum_ = 0; // See also location_checksum_
uint8_t signature_[kSha1DigestSize] = {};
uint32_t file_size_ = 0; // size of entire file
uint32_t header_size_ = 0; // offset to start of next section
uint32_t endian_tag_ = 0;
uint32_t link_size_ = 0; // unused
uint32_t link_off_ = 0; // unused
uint32_t map_off_ = 0; // map list offset from data_off_
uint32_t string_ids_size_ = 0; // number of StringIds
uint32_t string_ids_off_ = 0; // file offset of StringIds array
uint32_t type_ids_size_ = 0; // number of TypeIds, we don't support more than 65535
uint32_t type_ids_off_ = 0; // file offset of TypeIds array
uint32_t proto_ids_size_ = 0; // number of ProtoIds, we don't support more than 65535
uint32_t proto_ids_off_ = 0; // file offset of ProtoIds array
uint32_t field_ids_size_ = 0; // number of FieldIds
uint32_t field_ids_off_ = 0; // file offset of FieldIds array
uint32_t method_ids_size_ = 0; // number of MethodIds
uint32_t method_ids_off_ = 0; // file offset of MethodIds array
uint32_t class_defs_size_ = 0; // number of ClassDefs
uint32_t class_defs_off_ = 0; // file offset of ClassDef array
uint32_t data_size_ = 0; // size of data section
uint32_t data_off_ = 0; // file offset of data section
// Decode the dex magic version
uint32_t GetVersion() const;
};
// Map item type codes.
enum MapItemType : uint16_t { // private
kDexTypeHeaderItem = 0x0000,
kDexTypeStringIdItem = 0x0001,
kDexTypeTypeIdItem = 0x0002,
kDexTypeProtoIdItem = 0x0003,
kDexTypeFieldIdItem = 0x0004,
kDexTypeMethodIdItem = 0x0005,
kDexTypeClassDefItem = 0x0006,
kDexTypeCallSiteIdItem = 0x0007,
kDexTypeMethodHandleItem = 0x0008,
kDexTypeMapList = 0x1000,
kDexTypeTypeList = 0x1001,
kDexTypeAnnotationSetRefList = 0x1002,
kDexTypeAnnotationSetItem = 0x1003,
kDexTypeClassDataItem = 0x2000,
kDexTypeCodeItem = 0x2001,
kDexTypeStringDataItem = 0x2002,
kDexTypeDebugInfoItem = 0x2003,
kDexTypeAnnotationItem = 0x2004,
kDexTypeEncodedArrayItem = 0x2005,
kDexTypeAnnotationsDirectoryItem = 0x2006,
kDexTypeHiddenapiClassData = 0xF000,
};
// MethodHandle Types
enum class MethodHandleType : uint16_t { // private
kStaticPut = 0x0000, // a setter for a given static field.
kStaticGet = 0x0001, // a getter for a given static field.
kInstancePut = 0x0002, // a setter for a given instance field.
kInstanceGet = 0x0003, // a getter for a given instance field.
kInvokeStatic = 0x0004, // an invoker for a given static method.
kInvokeInstance = 0x0005, // invoke_instance : an invoker for a given instance method. This
// can be any non-static method on any class (or interface) except
// for “<init>”.
kInvokeConstructor = 0x0006, // an invoker for a given constructor.
kInvokeDirect = 0x0007, // an invoker for a direct (special) method.
kInvokeInterface = 0x0008, // an invoker for an interface method.
kLast = kInvokeInterface
};
// Annotation constants.
enum {
kDexVisibilityBuild = 0x00, /* annotation visibility */
kDexVisibilityRuntime = 0x01,
kDexVisibilitySystem = 0x02,
kDexAnnotationByte = 0x00,
kDexAnnotationShort = 0x02,
kDexAnnotationChar = 0x03,
kDexAnnotationInt = 0x04,
kDexAnnotationLong = 0x06,
kDexAnnotationFloat = 0x10,
kDexAnnotationDouble = 0x11,
kDexAnnotationMethodType = 0x15,
kDexAnnotationMethodHandle = 0x16,
kDexAnnotationString = 0x17,
kDexAnnotationType = 0x18,
kDexAnnotationField = 0x19,
kDexAnnotationMethod = 0x1a,
kDexAnnotationEnum = 0x1b,
kDexAnnotationArray = 0x1c,
kDexAnnotationAnnotation = 0x1d,
kDexAnnotationNull = 0x1e,
kDexAnnotationBoolean = 0x1f,
kDexAnnotationValueTypeMask = 0x1f, /* low 5 bits */
kDexAnnotationValueArgShift = 5,
};
enum AnnotationResultStyle { // private
kAllObjects,
kPrimitivesOrObjects,
kAllRaw
};
struct AnnotationValue;
// Closes a .dex file.
virtual ~DexFile();
const std::string& GetLocation() const {
return location_;
}
// For DexFiles directly from .dex files, this is the checksum from the DexFile::Header.
// For DexFiles opened from a zip files, this will be the ZipEntry CRC32 of classes.dex.
uint32_t GetLocationChecksum() const {
return location_checksum_;
}
const Header& GetHeader() const {
DCHECK(header_ != nullptr) << GetLocation();
return *header_;
}
// Decode the dex magic version
uint32_t GetDexVersion() const {
return GetHeader().GetVersion();
}
// Returns true if the byte string points to the magic value.
virtual bool IsMagicValid() const = 0;
// Returns true if the byte string after the magic is the correct value.
virtual bool IsVersionValid() const = 0;
// Returns true if the dex file supports default methods.
virtual bool SupportsDefaultMethods() const = 0;
// Returns the maximum size in bytes needed to store an equivalent dex file strictly conforming to
// the dex file specification. That is the size if we wanted to get rid of all the
// quickening/compact-dexing/etc.
//
// TODO This should really be an exact size! b/72402467
virtual size_t GetDequickenedSize() const = 0;
// Returns the number of string identifiers in the .dex file.
size_t NumStringIds() const {
DCHECK(header_ != nullptr) << GetLocation();
return header_->string_ids_size_;
}
// Returns the StringId at the specified index.
const dex::StringId& GetStringId(dex::StringIndex idx) const {
DCHECK_LT(idx.index_, NumStringIds()) << GetLocation();
return string_ids_[idx.index_];
}
dex::StringIndex GetIndexForStringId(const dex::StringId& string_id) const {
CHECK_GE(&string_id, string_ids_) << GetLocation();
CHECK_LT(&string_id, string_ids_ + header_->string_ids_size_) << GetLocation();
return dex::StringIndex(&string_id - string_ids_);
}
int32_t GetStringLength(const dex::StringId& string_id) const;
// Returns a pointer to the UTF-8 string data referred to by the given string_id as well as the
// length of the string when decoded as a UTF-16 string. Note the UTF-16 length is not the same
// as the string length of the string data.
const char* GetStringDataAndUtf16Length(const dex::StringId& string_id,
uint32_t* utf16_length) const;
const char* GetStringData(const dex::StringId& string_id) const;
// Index version of GetStringDataAndUtf16Length.
const char* StringDataAndUtf16LengthByIdx(dex::StringIndex idx, uint32_t* utf16_length) const;
const char* StringDataByIdx(dex::StringIndex idx) const;
std::string_view StringViewByIdx(dex::StringIndex idx) const;
// Looks up a string id for a given modified utf8 string.
const dex::StringId* FindStringId(const char* string) const;
const dex::TypeId* FindTypeId(const char* string) const;
// Returns the number of type identifiers in the .dex file.
uint32_t NumTypeIds() const {
DCHECK(header_ != nullptr) << GetLocation();
return header_->type_ids_size_;
}
bool IsTypeIndexValid(dex::TypeIndex idx) const {
return idx.IsValid() && idx.index_ < NumTypeIds();
}
// Returns the TypeId at the specified index.
const dex::TypeId& GetTypeId(dex::TypeIndex idx) const {
DCHECK_LT(idx.index_, NumTypeIds()) << GetLocation();
return type_ids_[idx.index_];
}
dex::TypeIndex GetIndexForTypeId(const dex::TypeId& type_id) const {
CHECK_GE(&type_id, type_ids_) << GetLocation();
CHECK_LT(&type_id, type_ids_ + header_->type_ids_size_) << GetLocation();
size_t result = &type_id - type_ids_;
DCHECK_LT(result, 65536U) << GetLocation();
return dex::TypeIndex(static_cast<uint16_t>(result));
}
// Get the descriptor string associated with a given type index.
const char* StringByTypeIdx(dex::TypeIndex idx, uint32_t* unicode_length) const;
const char* StringByTypeIdx(dex::TypeIndex idx) const;
// Returns the type descriptor string of a type id.
const char* GetTypeDescriptor(const dex::TypeId& type_id) const;
// Looks up a type for the given string index
const dex::TypeId* FindTypeId(dex::StringIndex string_idx) const;
// Returns the number of field identifiers in the .dex file.
size_t NumFieldIds() const {
DCHECK(header_ != nullptr) << GetLocation();
return header_->field_ids_size_;
}
// Returns the FieldId at the specified index.
const dex::FieldId& GetFieldId(uint32_t idx) const {
DCHECK_LT(idx, NumFieldIds()) << GetLocation();
return field_ids_[idx];
}
uint32_t GetIndexForFieldId(const dex::FieldId& field_id) const {
CHECK_GE(&field_id, field_ids_) << GetLocation();
CHECK_LT(&field_id, field_ids_ + header_->field_ids_size_) << GetLocation();
return &field_id - field_ids_;
}
// Looks up a field by its declaring class, name and type
const dex::FieldId* FindFieldId(const dex::TypeId& declaring_klass,
const dex::StringId& name,
const dex::TypeId& type) const;
uint32_t FindCodeItemOffset(const dex::ClassDef& class_def,
uint32_t dex_method_idx) const;
virtual uint32_t GetCodeItemSize(const dex::CodeItem& disk_code_item) const = 0;
// Returns the declaring class descriptor string of a field id.
const char* GetFieldDeclaringClassDescriptor(const dex::FieldId& field_id) const {
const dex::TypeId& type_id = GetTypeId(field_id.class_idx_);
return GetTypeDescriptor(type_id);
}
// Returns the class descriptor string of a field id.
const char* GetFieldTypeDescriptor(const dex::FieldId& field_id) const;
// Returns the name of a field id.
const char* GetFieldName(const dex::FieldId& field_id) const;
// Returns the number of method identifiers in the .dex file.
size_t NumMethodIds() const {
DCHECK(header_ != nullptr) << GetLocation();
return header_->method_ids_size_;
}
// Returns the MethodId at the specified index.
const dex::MethodId& GetMethodId(uint32_t idx) const {
DCHECK_LT(idx, NumMethodIds()) << GetLocation();
return method_ids_[idx];
}
uint32_t GetIndexForMethodId(const dex::MethodId& method_id) const {
CHECK_GE(&method_id, method_ids_) << GetLocation();
CHECK_LT(&method_id, method_ids_ + header_->method_ids_size_) << GetLocation();
return &method_id - method_ids_;
}
// Looks up a method by its declaring class, name and proto_id
const dex::MethodId* FindMethodId(const dex::TypeId& declaring_klass,
const dex::StringId& name,
const dex::ProtoId& signature) const;
// Returns the declaring class descriptor string of a method id.
const char* GetMethodDeclaringClassDescriptor(const dex::MethodId& method_id) const;
// Returns the prototype of a method id.
const dex::ProtoId& GetMethodPrototype(const dex::MethodId& method_id) const {
return GetProtoId(method_id.proto_idx_);
}
// Returns a representation of the signature of a method id.
const Signature GetMethodSignature(const dex::MethodId& method_id) const;
// Returns a representation of the signature of a proto id.
const Signature GetProtoSignature(const dex::ProtoId& proto_id) const;
// Returns the name of a method id.
const char* GetMethodName(const dex::MethodId& method_id) const;
const char* GetMethodName(const dex::MethodId& method_id, uint32_t* utf_length) const;
const char* GetMethodName(uint32_t idx, uint32_t* utf_length) const;
// Returns the shorty of a method by its index.
const char* GetMethodShorty(uint32_t idx) const;
// Returns the shorty of a method id.
const char* GetMethodShorty(const dex::MethodId& method_id) const;
const char* GetMethodShorty(const dex::MethodId& method_id, uint32_t* length) const;
// Returns the number of class definitions in the .dex file.
uint32_t NumClassDefs() const {
DCHECK(header_ != nullptr) << GetLocation();
return header_->class_defs_size_;
}
// Returns the ClassDef at the specified index.
const dex::ClassDef& GetClassDef(uint16_t idx) const {
DCHECK_LT(idx, NumClassDefs()) << GetLocation();
return class_defs_[idx];
}
uint16_t GetIndexForClassDef(const dex::ClassDef& class_def) const {
CHECK_GE(&class_def, class_defs_) << GetLocation();
CHECK_LT(&class_def, class_defs_ + header_->class_defs_size_) << GetLocation();
return &class_def - class_defs_;
}
// Returns the class descriptor string of a class definition.
const char* GetClassDescriptor(const dex::ClassDef& class_def) const;
// Looks up a class definition by its type index.
const dex::ClassDef* FindClassDef(dex::TypeIndex type_idx) const;
const dex::TypeList* GetInterfacesList(const dex::ClassDef& class_def) const {
return DataPointer<dex::TypeList>(class_def.interfaces_off_);
}
uint32_t NumMethodHandles() const {
return num_method_handles_;
}
const dex::MethodHandleItem& GetMethodHandle(uint32_t idx) const {
CHECK_LT(idx, NumMethodHandles());
return method_handles_[idx];
}
uint32_t NumCallSiteIds() const {
return num_call_site_ids_;
}
const dex::CallSiteIdItem& GetCallSiteId(uint32_t idx) const {
CHECK_LT(idx, NumCallSiteIds());
return call_site_ids_[idx];
}
// Returns a pointer to the raw memory mapped class_data_item
const uint8_t* GetClassData(const dex::ClassDef& class_def) const {
return DataPointer<uint8_t>(class_def.class_data_off_);
}
// Return the code item for a provided offset.
const dex::CodeItem* GetCodeItem(const uint32_t code_off) const {
// May be null for native or abstract methods.
return DataPointer<dex::CodeItem>(code_off);
}
const char* GetReturnTypeDescriptor(const dex::ProtoId& proto_id) const;
// Returns the number of prototype identifiers in the .dex file.
size_t NumProtoIds() const {
DCHECK(header_ != nullptr) << GetLocation();
return header_->proto_ids_size_;
}
// Returns the ProtoId at the specified index.
const dex::ProtoId& GetProtoId(dex::ProtoIndex idx) const {
DCHECK_LT(idx.index_, NumProtoIds()) << GetLocation();
return proto_ids_[idx.index_];
}
dex::ProtoIndex GetIndexForProtoId(const dex::ProtoId& proto_id) const {
CHECK_GE(&proto_id, proto_ids_) << GetLocation();
CHECK_LT(&proto_id, proto_ids_ + header_->proto_ids_size_) << GetLocation();
return dex::ProtoIndex(&proto_id - proto_ids_);
}
// Looks up a proto id for a given return type and signature type list
const dex::ProtoId* FindProtoId(dex::TypeIndex return_type_idx,
const dex::TypeIndex* signature_type_idxs,
uint32_t signature_length) const;
const dex::ProtoId* FindProtoId(dex::TypeIndex return_type_idx,
const std::vector<dex::TypeIndex>& signature_type_idxs) const {
return FindProtoId(return_type_idx, &signature_type_idxs[0], signature_type_idxs.size());
}
// Given a signature place the type ids into the given vector, returns true on success
bool CreateTypeList(std::string_view signature,
dex::TypeIndex* return_type_idx,
std::vector<dex::TypeIndex>* param_type_idxs) const;
// Returns the short form method descriptor for the given prototype.
const char* GetShorty(dex::ProtoIndex proto_idx) const;
const dex::TypeList* GetProtoParameters(const dex::ProtoId& proto_id) const {
return DataPointer<dex::TypeList>(proto_id.parameters_off_);
}
const uint8_t* GetEncodedStaticFieldValuesArray(const dex::ClassDef& class_def) const {
return DataPointer<uint8_t>(class_def.static_values_off_);
}
const uint8_t* GetCallSiteEncodedValuesArray(const dex::CallSiteIdItem& call_site_id) const {
return DataBegin() + call_site_id.data_off_;
}
dex::ProtoIndex GetProtoIndexForCallSite(uint32_t call_site_idx) const;
static const dex::TryItem* GetTryItems(const DexInstructionIterator& code_item_end,
uint32_t offset);
// Get the base of the encoded data for the given DexCode.
static const uint8_t* GetCatchHandlerData(const DexInstructionIterator& code_item_end,
uint32_t tries_size,
uint32_t offset);
// Find which try region is associated with the given address (ie dex pc). Returns -1 if none.
static int32_t FindTryItem(const dex::TryItem* try_items, uint32_t tries_size, uint32_t address);
// Get the pointer to the start of the debugging data
const uint8_t* GetDebugInfoStream(uint32_t debug_info_off) const {
// Check that the offset is in bounds.
// Note that although the specification says that 0 should be used if there
// is no debug information, some applications incorrectly use 0xFFFFFFFF.
return (debug_info_off == 0 || debug_info_off >= data_size_)
? nullptr
: DataBegin() + debug_info_off;
}
struct PositionInfo {
PositionInfo() = default;
uint32_t address_ = 0; // In 16-bit code units.
uint32_t line_ = 0; // Source code line number starting at 1.
const char* source_file_ = nullptr; // nullptr if the file from ClassDef still applies.
bool prologue_end_ = false;
bool epilogue_begin_ = false;
};
struct LocalInfo {
LocalInfo() = default;
const char* name_ = nullptr; // E.g., list. It can be nullptr if unknown.
const char* descriptor_ = nullptr; // E.g., Ljava/util/LinkedList;
const char* signature_ = nullptr; // E.g., java.util.LinkedList<java.lang.Integer>
uint32_t start_address_ = 0; // PC location where the local is first defined.
uint32_t end_address_ = 0; // PC location where the local is no longer defined.
uint16_t reg_ = 0; // Dex register which stores the values.
bool is_live_ = false; // Is the local defined and live.
};
// Callback for "new locals table entry".
typedef void (*DexDebugNewLocalCb)(void* context, const LocalInfo& entry);
const dex::AnnotationsDirectoryItem* GetAnnotationsDirectory(const dex::ClassDef& class_def)
const {
return DataPointer<dex::AnnotationsDirectoryItem>(class_def.annotations_off_);
}
const dex::AnnotationSetItem* GetClassAnnotationSet(const dex::AnnotationsDirectoryItem* anno_dir)
const {
return DataPointer<dex::AnnotationSetItem>(anno_dir->class_annotations_off_);
}
const dex::FieldAnnotationsItem* GetFieldAnnotations(
const dex::AnnotationsDirectoryItem* anno_dir) const {
return (anno_dir->fields_size_ == 0)
? nullptr
: reinterpret_cast<const dex::FieldAnnotationsItem*>(&anno_dir[1]);
}
const dex::MethodAnnotationsItem* GetMethodAnnotations(
const dex::AnnotationsDirectoryItem* anno_dir) const {
if (anno_dir->methods_size_ == 0) {
return nullptr;
}
// Skip past the header and field annotations.
const uint8_t* addr = reinterpret_cast<const uint8_t*>(&anno_dir[1]);
addr += anno_dir->fields_size_ * sizeof(dex::FieldAnnotationsItem);
return reinterpret_cast<const dex::MethodAnnotationsItem*>(addr);
}
const dex::ParameterAnnotationsItem* GetParameterAnnotations(
const dex::AnnotationsDirectoryItem* anno_dir) const {
if (anno_dir->parameters_size_ == 0) {
return nullptr;
}
// Skip past the header, field annotations, and method annotations.
const uint8_t* addr = reinterpret_cast<const uint8_t*>(&anno_dir[1]);
addr += anno_dir->fields_size_ * sizeof(dex::FieldAnnotationsItem);
addr += anno_dir->methods_size_ * sizeof(dex::MethodAnnotationsItem);
return reinterpret_cast<const dex::ParameterAnnotationsItem*>(addr);
}
const dex::AnnotationSetItem* GetFieldAnnotationSetItem(
const dex::FieldAnnotationsItem& anno_item) const {
return DataPointer<dex::AnnotationSetItem>(anno_item.annotations_off_);
}
const dex::AnnotationSetItem* GetMethodAnnotationSetItem(
const dex::MethodAnnotationsItem& anno_item) const {
return DataPointer<dex::AnnotationSetItem>(anno_item.annotations_off_);
}
const dex::AnnotationSetRefList* GetParameterAnnotationSetRefList(
const dex::ParameterAnnotationsItem* anno_item) const {
return DataPointer<dex::AnnotationSetRefList>(anno_item->annotations_off_);
}
ALWAYS_INLINE const dex::AnnotationItem* GetAnnotationItemAtOffset(uint32_t offset) const {
return DataPointer<dex::AnnotationItem>(offset);
}
ALWAYS_INLINE const dex::HiddenapiClassData* GetHiddenapiClassDataAtOffset(uint32_t offset)
const {
return DataPointer<dex::HiddenapiClassData>(offset);
}
ALWAYS_INLINE const dex::HiddenapiClassData* GetHiddenapiClassData() const {
return hiddenapi_class_data_;
}
ALWAYS_INLINE bool HasHiddenapiClassData() const {
return hiddenapi_class_data_ != nullptr;
}
const dex::AnnotationItem* GetAnnotationItem(const dex::AnnotationSetItem* set_item,
uint32_t index) const {
DCHECK_LE(index, set_item->size_);
return GetAnnotationItemAtOffset(set_item->entries_[index]);
}
const dex::AnnotationSetItem* GetSetRefItemItem(const dex::AnnotationSetRefItem* anno_item)
const {
return DataPointer<dex::AnnotationSetItem>(anno_item->annotations_off_);
}
// Debug info opcodes and constants
enum {
DBG_END_SEQUENCE = 0x00,
DBG_ADVANCE_PC = 0x01,
DBG_ADVANCE_LINE = 0x02,
DBG_START_LOCAL = 0x03,
DBG_START_LOCAL_EXTENDED = 0x04,
DBG_END_LOCAL = 0x05,
DBG_RESTART_LOCAL = 0x06,
DBG_SET_PROLOGUE_END = 0x07,
DBG_SET_EPILOGUE_BEGIN = 0x08,
DBG_SET_FILE = 0x09,
DBG_FIRST_SPECIAL = 0x0a,
DBG_LINE_BASE = -4,
DBG_LINE_RANGE = 15,
};
// Returns false if there is no debugging information or if it cannot be decoded.
template<typename NewLocalCallback, typename IndexToStringData, typename TypeIndexToStringData>
static bool DecodeDebugLocalInfo(const uint8_t* stream,
const std::string& location,
const char* declaring_class_descriptor,
const std::vector<const char*>& arg_descriptors,
const std::string& method_name,
bool is_static,
uint16_t registers_size,
uint16_t ins_size,
uint16_t insns_size_in_code_units,
const IndexToStringData& index_to_string_data,
const TypeIndexToStringData& type_index_to_string_data,
const NewLocalCallback& new_local) NO_THREAD_SAFETY_ANALYSIS;
template<typename NewLocalCallback>
bool DecodeDebugLocalInfo(uint32_t registers_size,
uint32_t ins_size,
uint32_t insns_size_in_code_units,
uint32_t debug_info_offset,
bool is_static,
uint32_t method_idx,
const NewLocalCallback& new_local) const;
// Returns false if there is no debugging information or if it cannot be decoded.
template<typename DexDebugNewPosition, typename IndexToStringData>
static bool DecodeDebugPositionInfo(const uint8_t* stream,
const IndexToStringData& index_to_string_data,
const DexDebugNewPosition& position_functor);
const char* GetSourceFile(const dex::ClassDef& class_def) const {
if (!class_def.source_file_idx_.IsValid()) {
return nullptr;
} else {
return StringDataByIdx(class_def.source_file_idx_);
}
}
int GetPermissions() const;
bool IsReadOnly() const;
bool EnableWrite() const;
bool DisableWrite() const;
const uint8_t* Begin() const {
return begin_;
}
size_t Size() const {
return size_;
}
const uint8_t* DataBegin() const {
return data_begin_;
}
size_t DataSize() const {
return data_size_;
}
template <typename T>
const T* DataPointer(size_t offset) const {
DCHECK_LT(offset, DataSize()) << "Offset past end of data section";
return (offset != 0u) ? reinterpret_cast<const T*>(DataBegin() + offset) : nullptr;
}
const OatDexFile* GetOatDexFile() const {
return oat_dex_file_;
}
// Used by oat writer.
void SetOatDexFile(OatDexFile* oat_dex_file) const {
oat_dex_file_ = oat_dex_file;
}
// Read MapItems and validate/set remaining offsets.
const dex::MapList* GetMapList() const {
return reinterpret_cast<const dex::MapList*>(DataBegin() + header_->map_off_);
}
// Utility methods for reading integral values from a buffer.
static int32_t ReadSignedInt(const uint8_t* ptr, int zwidth);
static uint32_t ReadUnsignedInt(const uint8_t* ptr, int zwidth, bool fill_on_right);
static int64_t ReadSignedLong(const uint8_t* ptr, int zwidth);
static uint64_t ReadUnsignedLong(const uint8_t* ptr, int zwidth, bool fill_on_right);
// Recalculates the checksum of the dex file. Does not use the current value in the header.
virtual uint32_t CalculateChecksum() const;
static uint32_t CalculateChecksum(const uint8_t* begin, size_t size);
static uint32_t ChecksumMemoryRange(const uint8_t* begin, size_t size);
// Number of bytes at the beginning of the dex file header which are skipped
// when computing the adler32 checksum of the entire file.
static constexpr uint32_t kNumNonChecksumBytes = OFFSETOF_MEMBER(DexFile::Header, signature_);
// Returns a human-readable form of the method at an index.
std::string PrettyMethod(uint32_t method_idx, bool with_signature = true) const;
// Returns a human-readable form of the field at an index.
std::string PrettyField(uint32_t field_idx, bool with_type = true) const;
// Returns a human-readable form of the type at an index.
std::string PrettyType(dex::TypeIndex type_idx) const;
// Not virtual for performance reasons.
ALWAYS_INLINE bool IsCompactDexFile() const {
return is_compact_dex_;
}
ALWAYS_INLINE bool IsStandardDexFile() const {
return !is_compact_dex_;
}
ALWAYS_INLINE const StandardDexFile* AsStandardDexFile() const;
ALWAYS_INLINE const CompactDexFile* AsCompactDexFile() const;
hiddenapi::Domain GetHiddenapiDomain() const { return hiddenapi_domain_; }
void SetHiddenapiDomain(hiddenapi::Domain value) const { hiddenapi_domain_ = value; }
bool IsInMainSection(const void* addr) const {
return Begin() <= addr && addr < Begin() + Size();
}
bool IsInDataSection(const void* addr) const {
return DataBegin() <= addr && addr < DataBegin() + DataSize();
}
DexFileContainer* GetContainer() const {
return container_.get();
}
IterationRange<ClassIterator> GetClasses() const;
template <typename Visitor>
static uint32_t DecodeDebugInfoParameterNames(const uint8_t** debug_info,
const Visitor& visitor);
static inline bool StringEquals(const DexFile* df1, dex::StringIndex sidx1,
const DexFile* df2, dex::StringIndex sidx2);
protected:
// First Dex format version supporting default methods.
static const uint32_t kDefaultMethodsVersion = 37;
DexFile(const uint8_t* base,
size_t size,
const uint8_t* data_begin,
size_t data_size,
const std::string& location,
uint32_t location_checksum,
const OatDexFile* oat_dex_file,
std::unique_ptr<DexFileContainer> container,
bool is_compact_dex);
// Top-level initializer that calls other Init methods.
bool Init(std::string* error_msg);
// Returns true if the header magic and version numbers are of the expected values.
bool CheckMagicAndVersion(std::string* error_msg) const;
// Initialize section info for sections only found in map. Returns true on success.
void InitializeSectionsFromMapList();
// The base address of the memory mapping.
const uint8_t* const begin_;
// The size of the underlying memory allocation in bytes.
const size_t size_;
// The base address of the data section (same as Begin() for standard dex).
const uint8_t* const data_begin_;
// The size of the data section.
const size_t data_size_;
// Typically the dex file name when available, alternatively some identifying string.
//
// The ClassLinker will use this to match DexFiles the boot class
// path to DexCache::GetLocation when loading from an image.
const std::string location_;
const uint32_t location_checksum_;
// Points to the header section.
const Header* const header_;
// Points to the base of the string identifier list.
const dex::StringId* const string_ids_;
// Points to the base of the type identifier list.
const dex::TypeId* const type_ids_;
// Points to the base of the field identifier list.
const dex::FieldId* const field_ids_;
// Points to the base of the method identifier list.
const dex::MethodId* const method_ids_;
// Points to the base of the prototype identifier list.
const dex::ProtoId* const proto_ids_;
// Points to the base of the class definition list.
const dex::ClassDef* const class_defs_;
// Points to the base of the method handles list.
const dex::MethodHandleItem* method_handles_;
// Number of elements in the method handles list.
size_t num_method_handles_;
// Points to the base of the call sites id list.
const dex::CallSiteIdItem* call_site_ids_;
// Number of elements in the call sites list.
size_t num_call_site_ids_;
// Points to the base of the hiddenapi class data item_, or nullptr if the dex
// file does not have one.
const dex::HiddenapiClassData* hiddenapi_class_data_;
// If this dex file was loaded from an oat file, oat_dex_file_ contains a
// pointer to the OatDexFile it was loaded from. Otherwise oat_dex_file_ is
// null.
mutable const OatDexFile* oat_dex_file_;
// Manages the underlying memory allocation.
std::unique_ptr<DexFileContainer> container_;
// If the dex file is a compact dex file. If false then the dex file is a standard dex file.
const bool is_compact_dex_;
// The domain this dex file belongs to for hidden API access checks.
// It is decleared `mutable` because the domain is assigned after the DexFile
// has been created and can be changed later by the runtime.
mutable hiddenapi::Domain hiddenapi_domain_;
friend class DexFileLoader;
friend class DexFileVerifierTest;
friend class OatWriter;
};
std::ostream& operator<<(std::ostream& os, const DexFile& dex_file);
// Iterate over a dex file's ProtoId's paramters
class DexFileParameterIterator {
public:
DexFileParameterIterator(const DexFile& dex_file, const dex::ProtoId& proto_id)
: dex_file_(dex_file) {
type_list_ = dex_file_.GetProtoParameters(proto_id);
if (type_list_ != nullptr) {
size_ = type_list_->Size();
}
}
bool HasNext() const { return pos_ < size_; }
size_t Size() const { return size_; }
void Next() { ++pos_; }
dex::TypeIndex GetTypeIdx() {
return type_list_->GetTypeItem(pos_).type_idx_;
}
const char* GetDescriptor() {
return dex_file_.StringByTypeIdx(dex::TypeIndex(GetTypeIdx()));
}
private:
const DexFile& dex_file_;
const dex::TypeList* type_list_ = nullptr;
uint32_t size_ = 0;
uint32_t pos_ = 0;
DISALLOW_IMPLICIT_CONSTRUCTORS(DexFileParameterIterator);
};
class EncodedArrayValueIterator {
public:
EncodedArrayValueIterator(const DexFile& dex_file, const uint8_t* array_data);
bool HasNext() const { return pos_ < array_size_; }
void Next();
enum ValueType {
kByte = 0x00,
kShort = 0x02,
kChar = 0x03,
kInt = 0x04,
kLong = 0x06,
kFloat = 0x10,
kDouble = 0x11,
kMethodType = 0x15,
kMethodHandle = 0x16,
kString = 0x17,
kType = 0x18,
kField = 0x19,
kMethod = 0x1a,
kEnum = 0x1b,
kArray = 0x1c,
kAnnotation = 0x1d,
kNull = 0x1e,
kBoolean = 0x1f,
};
ValueType GetValueType() const { return type_; }
const jvalue& GetJavaValue() const { return jval_; }
protected:
static constexpr uint8_t kEncodedValueTypeMask = 0x1f; // 0b11111
static constexpr uint8_t kEncodedValueArgShift = 5;
const DexFile& dex_file_;
size_t array_size_; // Size of array.
size_t pos_; // Current position.
const uint8_t* ptr_; // Pointer into encoded data array.
ValueType type_; // Type of current encoded value.
jvalue jval_; // Value of current encoded value.
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(EncodedArrayValueIterator);
};
std::ostream& operator<<(std::ostream& os, const EncodedArrayValueIterator::ValueType& code);
class EncodedStaticFieldValueIterator : public EncodedArrayValueIterator {
public:
EncodedStaticFieldValueIterator(const DexFile& dex_file,
const dex::ClassDef& class_def)
: EncodedArrayValueIterator(dex_file,
dex_file.GetEncodedStaticFieldValuesArray(class_def))
{}
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(EncodedStaticFieldValueIterator);
};
std::ostream& operator<<(std::ostream& os, const EncodedStaticFieldValueIterator::ValueType& code);
class CallSiteArrayValueIterator : public EncodedArrayValueIterator {
public:
CallSiteArrayValueIterator(const DexFile& dex_file,
const dex::CallSiteIdItem& call_site_id)
: EncodedArrayValueIterator(dex_file,
dex_file.GetCallSiteEncodedValuesArray(call_site_id))
{}
uint32_t Size() const { return array_size_; }
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(CallSiteArrayValueIterator);
};
std::ostream& operator<<(std::ostream& os, const CallSiteArrayValueIterator::ValueType& code);
} // namespace art
#endif // ART_LIBDEXFILE_DEX_DEX_FILE_H_
|