#include"base/array_ref.h" #include"base/globals.h" #include"base/macros.h" #include"base/mman.h"// For the PROT_* and MAP_* constants. #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 DexInstructionIterator; enum InvokeType : uint32_t; template <typename Iter> class IterationRange; class MemMap; class OatDexFile; class Signature; class StandardDexFile; class ZipArchive;
// Owns the physical storage that backs one or more DexFiles (that is, it can be shared). // It frees the storage (e.g. closes file) when all DexFiles that use it are all closed. // // The memory range must include all data used by the DexFiles including any shared data. // // It might also include surrounding non-dex data (e.g. it might represent vdex file). class DexFileContainer { public:
DexFileContainer() { } virtual ~DexFileContainer() {}
virtualbool IsReadOnly() const = 0;
// Make the underlying writeable. Return true on success (memory can be written). virtualbool EnableWrite() = 0; // Make the underlying read-only. Return true on success (memory is read-only now). virtualbool DisableWrite() = 0;
// Dex file is the API that exposes native dex files (ordinary dex files). // The dex file format used by ART is mostly the same as APKs, but this // abstraction is present to allow ART internal dex files. class DexFile { public: // Number of bytes in the dex file magic. static constexpr size_t kDexMagicSize = 4; static constexpr size_t kDexVersionLen = 4;
// Raw header_item. struct Header {
Magic magic_ = {};
uint32_t checksum_ = 0; // See also location_checksum_
Sha1 signature_ = {};
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;
// Get the header_size that is expected for this version.
uint32_t GetExpectedHeaderSize() const;
// Returns true for standard DEX version 41 or newer. bool HasDexContainer() const;
// Returns offset of this header within the container. // Returns 0 for older dex versions without container.
uint32_t HeaderOffset() const;
// Returns size of the whole container. // Returns file_size_ for older dex versions without container.
uint32_t ContainerSize() const;
// Set the DEX container fields to the given values. // Must be [0, file_size_) for older dex versions. void SetDexContainer(size_t header_offset, size_t container_size);
};
struct HeaderV41 : public Header {
uint32_t container_size_ = 0; // total size of all dex files in the container.
uint32_t header_offset_ = 0; // offset of this dex's header in the container.
};
// MethodHandle Types enumclass 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
};
// 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_;
}
// Decode the dex magic version
uint32_t GetDexVersion() const { return GetHeader().GetVersion();
}
// Returns true if this is DEX V41 or later (i.e. supports container). // Returns true even if the container contains just a single DEX file. bool HasDexContainer() const { return GetHeader().HasDexContainer(); }
// Returns the whole memory range of the DEX V41 container. // Returns just the range of the DEX file for V40 or older.
ArrayRef<const uint8_t> GetDexContainerRange() const { return {Begin() - header_->HeaderOffset(), header_->ContainerSize()};
}
// Returns true if the byte string points to the magic value. virtualbool IsMagicValid() const = 0;
// Returns true if the byte string after the magic is the correct value. virtualbool IsVersionValid() const = 0;
// Returns true if the dex file supports default methods. virtualbool 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_];
}
// 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. constchar* GetStringDataAndUtf16Length(const dex::StringId& string_id,
uint32_t* utf16_length) const; constchar* GetStringDataAndUtf16Length(dex::StringIndex string_idx,
uint32_t* utf16_length) const;
// Looks up a string id for a given modified utf8 string. const dex::StringId* FindStringId(constchar* 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_;
}
// 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];
}
// 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;
// Return the code-item offset associated with the class and method or nullopt // if the method does not exist or has no code.
std::optional<uint32_t> GetCodeItemOffset(const dex::ClassDef& class_def,
uint32_t dex_method_idx) const;
// Return the code-item offset associated with the class and method or // LOG(FATAL) if the method does not exist or has no code.
uint32_t FindCodeItemOffset(const dex::ClassDef& class_def,
uint32_t dex_method_idx) const;
// Returns the declaring class descriptor string of a field id. constchar* GetFieldDeclaringClassDescriptor(const dex::FieldId& field_id) const; constchar* GetFieldDeclaringClassDescriptor(uint32_t field_idx) const;
std::string_view GetFieldDeclaringClassDescriptorView(const dex::FieldId& field_id) const;
std::string_view GetFieldDeclaringClassDescriptorView(uint32_t field_idx) const;
// Returns the class descriptor string of a field id. constchar* GetFieldTypeDescriptor(const dex::FieldId& field_id) const; constchar* GetFieldTypeDescriptor(uint32_t field_idx) const;
std::string_view GetFieldTypeDescriptorView(const dex::FieldId& field_id) const;
std::string_view GetFieldTypeDescriptorView(uint32_t field_idx) const;
// Returns the name of a field id. constchar* GetFieldName(const dex::FieldId& field_id) const; constchar* GetFieldName(uint32_t field_idx) const;
std::string_view GetFieldNameView(const dex::FieldId& field_id) const;
std::string_view GetFieldNameView(uint32_t field_idx) 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];
}
// 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. constchar* GetMethodDeclaringClassDescriptor(const dex::MethodId& method_id) const; constchar* GetMethodDeclaringClassDescriptor(uint32_t method_idx) const;
std::string_view GetMethodDeclaringClassDescriptorView(const dex::MethodId& method_id) const;
std::string_view GetMethodDeclaringClassDescriptorView(uint32_t method_idx) 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. constchar* GetMethodName(const dex::MethodId& method_id) const; constchar* GetMethodName(const dex::MethodId& method_id, uint32_t* utf_length) const; constchar* GetMethodName(uint32_t method_idx) const; constchar* GetMethodName(uint32_t method_idx, uint32_t* utf_length) const;
std::string_view GetMethodNameView(const dex::MethodId& method_id) const;
std::string_view GetMethodNameView(uint32_t method_idx) const;
// Returns the shorty of a method by its index. constchar* GetMethodShorty(uint32_t idx) const;
std::string_view GetMethodShortyView(uint32_t idx) const;
// Returns the shorty of a method id. constchar* GetMethodShorty(const dex::MethodId& method_id) const; constchar* GetMethodShorty(const dex::MethodId& method_id, uint32_t* length) const;
std::string_view GetMethodShortyView(const dex::MethodId& method_id) 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];
}
// 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);
}
// 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_];
}
// 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.data(), 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. constchar* GetShorty(dex::ProtoIndex proto_idx) const;
std::string_view GetShortyView(dex::ProtoIndex proto_idx) const;
std::string_view GetShortyView(const dex::ProtoId& proto_id) const;
// Get the base of the encoded data for the given DexCode. staticconst 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 >= DataSize()) ? 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. constchar* source_file_ = nullptr; // nullptr if the file from ClassDef still applies. bool prologue_end_ = false; bool epilogue_begin_ = false;
};
struct LocalInfo {
LocalInfo() = default;
constchar* name_ = nullptr; // E.g., list. It can be nullptr if unknown. constchar* descriptor_ = nullptr; // E.g., Ljava/util/LinkedList; constchar* 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". using DexDebugNewLocalCb = void (*)(void* context, const LocalInfo& entry);
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); returnreinterpret_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); returnreinterpret_cast<const dex::ParameterAnnotationsItem*>(addr);
}
const dex::AnnotationSetItem* GetFieldAnnotationSetItem( const dex::FieldAnnotationsItem& anno_item) const { // `DexFileVerifier` checks that the offset is not zero. return NonNullDataPointer<dex::AnnotationSetItem>(anno_item.annotations_off_);
}
const dex::AnnotationSetItem* GetMethodAnnotationSetItem( const dex::MethodAnnotationsItem& anno_item) const { // `DexFileVerifier` checks that the offset is not zero. return NonNullDataPointer<dex::AnnotationSetItem>(anno_item.annotations_off_);
}
// Returns false if there is no debugging information or if it cannot be decoded. template<typename NewLocalCallback, typename IndexToStringData, typename TypeIndexToStringData> staticbool DecodeDebugLocalInfo(const uint8_t* stream, const std::string& location, constchar* declaring_class_descriptor, const std::vector<constchar*>& 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> staticbool DecodeDebugPositionInfo(const uint8_t* stream,
IndexToStringData&& index_to_string_data,
DexDebugNewPosition&& position_functor);
// 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_);
// Appends a human-readable form of the method at an index. void AppendPrettyMethod(uint32_t method_idx, bool with_signature, std::string* result) 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;
protected: // First Dex format version supporting default methods. static constexpr uint32_t kDefaultMethodsVersion = 37;
DexFile(const uint8_t* base, const std::string& location,
uint32_t location_checksum, const OatDexFile* oat_dex_file, // Shared since several dex files may be stored in the same logical container.
std::shared_ptr<DexFileContainer> container);
// 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_;
size_t unused_size_ = 0; // Preserve layout for DRM (b/305203031).
// Data memory range: Most dex offsets are relative to this memory range. // Standard dex: same as (begin_, size_). // Dex container: all dex files (starting from the first header). // Compact: shared data which is located after all non-shared data. // // This is different to the "data section" in the standard dex header.
ArrayRef<const uint8_t> const data_;
// The full absolute path to the dex file, if it was loaded from disk. // // Can also be a path to a multidex container (typically apk), followed by // DexFileLoader.kMultiDexSeparator (i.e. '!') and the file inside the // container. // // When dex2oat runs this may be a canonical location where the file is // supposed to be (coming from -Xbootclasspath-locations), rather than where // it actually is. In such cases they won't incorporate a prefix from // ANDROID_ROOT and other path environment variables. // // On host this may not be an absolute path. // // On device libnativeloader uses this to determine the location of the java // package or shared library, which decides where to load native libraries // from. // // 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. mutableconst OatDexFile* oat_dex_file_;
// Manages the underlying memory allocation.
std::shared_ptr<DexFileContainer> container_;
// 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_;
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.
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.