diff options
Diffstat (limited to 'runtime/dex_file.h')
-rw-r--r-- | runtime/dex_file.h | 1223 |
1 files changed, 1223 insertions, 0 deletions
diff --git a/runtime/dex_file.h b/runtime/dex_file.h new file mode 100644 index 0000000..e09270e --- /dev/null +++ b/runtime/dex_file.h @@ -0,0 +1,1223 @@ +/* + * 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_SRC_DEX_FILE_H_ +#define ART_SRC_DEX_FILE_H_ + +#include <string> +#include <vector> + +#include "base/logging.h" +#include "base/mutex.h" +#include "base/stringpiece.h" +#include "globals.h" +#include "invoke_type.h" +#include "jni.h" +#include "mem_map.h" +#include "modifiers.h" +#include "safe_map.h" +#include "UniquePtr.h" + +namespace art { + +namespace mirror { +class AbstractMethod; +class ClassLoader; +class DexCache; +class Field; +} // namespace mirror +class ClassLinker; +class ZipArchive; + +// TODO: move all of the macro functionality into the DexCache class. +class DexFile { + public: + static const byte kDexMagic[]; + static const byte kDexMagicVersion[]; + static const size_t kSha1DigestSize = 20; + static const uint32_t kDexEndianConstant = 0x12345678; + + // name of the DexFile entry within a zip archive + static const char* kClassesDex; + + // The value of an invalid index. + static const uint32_t kDexNoIndex = 0xFFFFFFFF; + + // The value of an invalid index. + static const uint16_t kDexNoIndex16 = 0xFFFF; + + // Raw header_item. + struct Header { + uint8_t magic_[8]; + uint32_t checksum_; // See also location_checksum_ + uint8_t signature_[kSha1DigestSize]; + uint32_t file_size_; // size of entire file + uint32_t header_size_; // offset to start of next section + uint32_t endian_tag_; + uint32_t link_size_; // unused + uint32_t link_off_; // unused + uint32_t map_off_; // unused + uint32_t string_ids_size_; // number of StringIds + uint32_t string_ids_off_; // file offset of StringIds array + uint32_t type_ids_size_; // number of TypeIds, we don't support more than 65535 + uint32_t type_ids_off_; // file offset of TypeIds array + uint32_t proto_ids_size_; // number of ProtoIds, we don't support more than 65535 + uint32_t proto_ids_off_; // file offset of ProtoIds array + uint32_t field_ids_size_; // number of FieldIds + uint32_t field_ids_off_; // file offset of FieldIds array + uint32_t method_ids_size_; // number of MethodIds + uint32_t method_ids_off_; // file offset of MethodIds array + uint32_t class_defs_size_; // number of ClassDefs + uint32_t class_defs_off_; // file offset of ClassDef array + uint32_t data_size_; // unused + uint32_t data_off_; // unused + + private: + DISALLOW_COPY_AND_ASSIGN(Header); + }; + + // Map item type codes. + enum { + kDexTypeHeaderItem = 0x0000, + kDexTypeStringIdItem = 0x0001, + kDexTypeTypeIdItem = 0x0002, + kDexTypeProtoIdItem = 0x0003, + kDexTypeFieldIdItem = 0x0004, + kDexTypeMethodIdItem = 0x0005, + kDexTypeClassDefItem = 0x0006, + kDexTypeMapList = 0x1000, + kDexTypeTypeList = 0x1001, + kDexTypeAnnotationSetRefList = 0x1002, + kDexTypeAnnotationSetItem = 0x1003, + kDexTypeClassDataItem = 0x2000, + kDexTypeCodeItem = 0x2001, + kDexTypeStringDataItem = 0x2002, + kDexTypeDebugInfoItem = 0x2003, + kDexTypeAnnotationItem = 0x2004, + kDexTypeEncodedArrayItem = 0x2005, + kDexTypeAnnotationsDirectoryItem = 0x2006, + }; + + struct MapItem { + uint16_t type_; + uint16_t unused_; + uint32_t size_; + uint32_t offset_; + + private: + DISALLOW_COPY_AND_ASSIGN(MapItem); + }; + + struct MapList { + uint32_t size_; + MapItem list_[1]; + + private: + DISALLOW_COPY_AND_ASSIGN(MapList); + }; + + // Raw string_id_item. + struct StringId { + uint32_t string_data_off_; // offset in bytes from the base address + + private: + DISALLOW_COPY_AND_ASSIGN(StringId); + }; + + // Raw type_id_item. + struct TypeId { + uint32_t descriptor_idx_; // index into string_ids + + private: + DISALLOW_COPY_AND_ASSIGN(TypeId); + }; + + // Raw field_id_item. + struct FieldId { + uint16_t class_idx_; // index into type_ids_ array for defining class + uint16_t type_idx_; // index into type_ids_ array for field type + uint32_t name_idx_; // index into string_ids_ array for field name + + private: + DISALLOW_COPY_AND_ASSIGN(FieldId); + }; + + // Raw method_id_item. + struct MethodId { + uint16_t class_idx_; // index into type_ids_ array for defining class + uint16_t proto_idx_; // index into proto_ids_ array for method prototype + uint32_t name_idx_; // index into string_ids_ array for method name + + private: + DISALLOW_COPY_AND_ASSIGN(MethodId); + }; + + // Raw proto_id_item. + struct ProtoId { + uint32_t shorty_idx_; // index into string_ids array for shorty descriptor + uint16_t return_type_idx_; // index into type_ids array for return type + uint16_t pad_; // padding = 0 + uint32_t parameters_off_; // file offset to type_list for parameter types + + private: + DISALLOW_COPY_AND_ASSIGN(ProtoId); + }; + + // Raw class_def_item. + struct ClassDef { + uint16_t class_idx_; // index into type_ids_ array for this class + uint16_t pad1_; // padding = 0 + uint32_t access_flags_; + uint16_t superclass_idx_; // index into type_ids_ array for superclass + uint16_t pad2_; // padding = 0 + uint32_t interfaces_off_; // file offset to TypeList + uint32_t source_file_idx_; // index into string_ids_ for source file name + uint32_t annotations_off_; // file offset to annotations_directory_item + uint32_t class_data_off_; // file offset to class_data_item + uint32_t static_values_off_; // file offset to EncodedArray + + private: + DISALLOW_COPY_AND_ASSIGN(ClassDef); + }; + + // Raw type_item. + struct TypeItem { + uint16_t type_idx_; // index into type_ids section + + private: + DISALLOW_COPY_AND_ASSIGN(TypeItem); + }; + + // Raw type_list. + class TypeList { + public: + uint32_t Size() const { + return size_; + } + + const TypeItem& GetTypeItem(uint32_t idx) const { + CHECK_LT(idx, this->size_); + return this->list_[idx]; + } + + private: + uint32_t size_; // size of the list, in entries + TypeItem list_[1]; // elements of the list + DISALLOW_COPY_AND_ASSIGN(TypeList); + }; + + // Raw code_item. + struct CodeItem { + uint16_t registers_size_; + uint16_t ins_size_; + uint16_t outs_size_; + uint16_t tries_size_; + uint32_t debug_info_off_; // file offset to debug info stream + uint32_t insns_size_in_code_units_; // size of the insns array, in 2 byte code units + uint16_t insns_[1]; + + private: + DISALLOW_COPY_AND_ASSIGN(CodeItem); + }; + + // Raw try_item. + struct TryItem { + uint32_t start_addr_; + uint16_t insn_count_; + uint16_t handler_off_; + + private: + DISALLOW_COPY_AND_ASSIGN(TryItem); + }; + + // 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, + 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, + }; + + struct AnnotationsDirectoryItem { + uint32_t class_annotations_off_; + uint32_t fields_size_; + uint32_t methods_size_; + uint32_t parameters_size_; + + private: + DISALLOW_COPY_AND_ASSIGN(AnnotationsDirectoryItem); + }; + + struct FieldAnnotationsItem { + uint32_t field_idx_; + uint32_t annotations_off_; + + private: + DISALLOW_COPY_AND_ASSIGN(FieldAnnotationsItem); + }; + + struct MethodAnnotationsItem { + uint32_t method_idx_; + uint32_t annotations_off_; + + private: + DISALLOW_COPY_AND_ASSIGN(MethodAnnotationsItem); + }; + + struct ParameterAnnotationsItem { + uint32_t method_idx_; + uint32_t annotations_off_; + + private: + DISALLOW_COPY_AND_ASSIGN(ParameterAnnotationsItem); + }; + + struct AnnotationSetRefItem { + uint32_t annotations_off_; + + private: + DISALLOW_COPY_AND_ASSIGN(AnnotationSetRefItem); + }; + + struct AnnotationSetRefList { + uint32_t size_; + AnnotationSetRefItem list_[1]; + + private: + DISALLOW_COPY_AND_ASSIGN(AnnotationSetRefList); + }; + + struct AnnotationSetItem { + uint32_t size_; + uint32_t entries_[1]; + + private: + DISALLOW_COPY_AND_ASSIGN(AnnotationSetItem); + }; + + struct AnnotationItem { + uint8_t visibility_; + uint8_t annotation_[1]; + + private: + DISALLOW_COPY_AND_ASSIGN(AnnotationItem); + }; + + typedef std::pair<const DexFile*, const DexFile::ClassDef*> ClassPathEntry; + typedef std::vector<const DexFile*> ClassPath; + + // Search a collection of DexFiles for a descriptor + static ClassPathEntry FindInClassPath(const StringPiece& descriptor, + const ClassPath& class_path); + + // Returns the checksum of a file for comparison with GetLocationChecksum(). + // For .dex files, this is the header checksum. + // For zip files, this is the classes.dex zip entry CRC32 checksum. + // Return true if the checksum could be found, false otherwise. + static bool GetChecksum(const std::string& filename, uint32_t& checksum) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + + // Opens .dex file, guessing the container format based on file extension + static const DexFile* Open(const std::string& filename, + const std::string& location); + + // Opens .dex file, backed by existing memory + static const DexFile* Open(const uint8_t* base, size_t size, + const std::string& location, + uint32_t location_checksum) { + return OpenMemory(base, size, location, location_checksum, NULL); + } + + // Opens .dex file from the classes.dex in a zip archive + static const DexFile* Open(const ZipArchive& zip_archive, const std::string& location); + + // 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_; + } + + // Returns a com.android.dex.Dex object corresponding to the mapped-in dex file. + // Used by managed code to implement annotations. + jobject GetDexObject(JNIEnv* env) const; + + const Header& GetHeader() const { + DCHECK(header_ != NULL) << GetLocation(); + return *header_; + } + + Mutex& GetModificationLock() { + return modification_lock; + } + + // Decode the dex magic version + uint32_t GetVersion() const; + + // Returns true if the byte string points to the magic value. + static bool IsMagicValid(const byte* magic); + + // Returns true if the byte string after the magic is the correct value. + static bool IsVersionValid(const byte* magic); + + // Returns the number of string identifiers in the .dex file. + size_t NumStringIds() const { + DCHECK(header_ != NULL) << GetLocation(); + return header_->string_ids_size_; + } + + // Returns the StringId at the specified index. + const StringId& GetStringId(uint32_t idx) const { + DCHECK_LT(idx, NumStringIds()) << GetLocation(); + return string_ids_[idx]; + } + + uint32_t GetIndexForStringId(const StringId& string_id) const { + CHECK_GE(&string_id, string_ids_) << GetLocation(); + CHECK_LT(&string_id, string_ids_ + header_->string_ids_size_) << GetLocation(); + return &string_id - string_ids_; + } + + int32_t GetStringLength(const StringId& string_id) const; + + // Returns a pointer to the UTF-8 string data referred to by the given string_id. + const char* GetStringDataAndLength(const StringId& string_id, uint32_t* length) const; + + const char* GetStringData(const StringId& string_id) const { + uint32_t length; + return GetStringDataAndLength(string_id, &length); + } + + // return the UTF-8 encoded string with the specified string_id index + const char* StringDataAndLengthByIdx(uint32_t idx, uint32_t* unicode_length) const { + if (idx == kDexNoIndex) { + *unicode_length = 0; + return NULL; + } + const StringId& string_id = GetStringId(idx); + return GetStringDataAndLength(string_id, unicode_length); + } + + const char* StringDataByIdx(uint32_t idx) const { + uint32_t unicode_length; + return StringDataAndLengthByIdx(idx, &unicode_length); + } + + // Looks up a string id for a given modified utf8 string. + const StringId* FindStringId(const char* string) const; + + // Looks up a string id for a given utf16 string. + const StringId* FindStringId(const uint16_t* string) const; + + // Returns the number of type identifiers in the .dex file. + size_t NumTypeIds() const { + DCHECK(header_ != NULL) << GetLocation(); + return header_->type_ids_size_; + } + + // Returns the TypeId at the specified index. + const TypeId& GetTypeId(uint32_t idx) const { + DCHECK_LT(idx, NumTypeIds()) << GetLocation(); + return type_ids_[idx]; + } + + uint16_t GetIndexForTypeId(const 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 static_cast<uint16_t>(result); + } + + // Get the descriptor string associated with a given type index. + const char* StringByTypeIdx(uint32_t idx, uint32_t* unicode_length) const { + const TypeId& type_id = GetTypeId(idx); + return StringDataAndLengthByIdx(type_id.descriptor_idx_, unicode_length); + } + + const char* StringByTypeIdx(uint32_t idx) const { + const TypeId& type_id = GetTypeId(idx); + return StringDataByIdx(type_id.descriptor_idx_); + } + + // Returns the type descriptor string of a type id. + const char* GetTypeDescriptor(const TypeId& type_id) const { + return StringDataByIdx(type_id.descriptor_idx_); + } + + // Looks up a type for the given string index + const TypeId* FindTypeId(uint32_t string_idx) const; + + // Returns the number of field identifiers in the .dex file. + size_t NumFieldIds() const { + DCHECK(header_ != NULL) << GetLocation(); + return header_->field_ids_size_; + } + + // Returns the FieldId at the specified index. + const FieldId& GetFieldId(uint32_t idx) const { + CHECK_LT(idx, NumFieldIds()) << GetLocation(); + return field_ids_[idx]; + } + + uint32_t GetIndexForFieldId(const 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 FieldId* FindFieldId(const DexFile::TypeId& declaring_klass, + const DexFile::StringId& name, + const DexFile::TypeId& type) const; + + // Returns the declaring class descriptor string of a field id. + const char* GetFieldDeclaringClassDescriptor(const FieldId& field_id) const { + const DexFile::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 FieldId& field_id) const { + const DexFile::TypeId& type_id = GetTypeId(field_id.type_idx_); + return GetTypeDescriptor(type_id); + } + + // Returns the name of a field id. + const char* GetFieldName(const FieldId& field_id) const { + return StringDataByIdx(field_id.name_idx_); + } + + // Returns the number of method identifiers in the .dex file. + size_t NumMethodIds() const { + DCHECK(header_ != NULL) << GetLocation(); + return header_->method_ids_size_; + } + + // Returns the MethodId at the specified index. + const MethodId& GetMethodId(uint32_t idx) const { + DCHECK_LT(idx, NumMethodIds()) << GetLocation(); + return method_ids_[idx]; + } + + uint32_t GetIndexForMethodId(const 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 MethodId* FindMethodId(const DexFile::TypeId& declaring_klass, + const DexFile::StringId& name, + const DexFile::ProtoId& signature) const; + + // Returns the declaring class descriptor string of a method id. + const char* GetMethodDeclaringClassDescriptor(const MethodId& method_id) const { + const DexFile::TypeId& type_id = GetTypeId(method_id.class_idx_); + return GetTypeDescriptor(type_id); + } + + // Returns the prototype of a method id. + const ProtoId& GetMethodPrototype(const MethodId& method_id) const { + return GetProtoId(method_id.proto_idx_); + } + + // Returns the signature of a method id. + const std::string GetMethodSignature(const MethodId& method_id) const { + return CreateMethodSignature(method_id.proto_idx_, NULL); + } + + // Returns the name of a method id. + const char* GetMethodName(const MethodId& method_id) const { + return StringDataByIdx(method_id.name_idx_); + } + + // Returns the shorty of a method id. + const char* GetMethodShorty(const MethodId& method_id) const { + return StringDataByIdx(GetProtoId(method_id.proto_idx_).shorty_idx_); + } + const char* GetMethodShorty(const MethodId& method_id, uint32_t* length) const { + return StringDataAndLengthByIdx(GetProtoId(method_id.proto_idx_).shorty_idx_, length); + } + // Returns the number of class definitions in the .dex file. + size_t NumClassDefs() const { + DCHECK(header_ != NULL) << GetLocation(); + return header_->class_defs_size_; + } + + // Returns the ClassDef at the specified index. + const ClassDef& GetClassDef(uint32_t idx) const { + CHECK_LT(idx, NumClassDefs()) << GetLocation(); + return class_defs_[idx]; + } + + uint32_t GetIndexForClassDef(const 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 ClassDef& class_def) const { + return StringByTypeIdx(class_def.class_idx_); + } + + // Looks up a class definition by its class descriptor. + const ClassDef* FindClassDef(const StringPiece& descriptor) const; + + // Looks up a class definition index by its class descriptor. + bool FindClassDefIndex(const StringPiece& descriptor, uint32_t& idx) const; + + const TypeList* GetInterfacesList(const ClassDef& class_def) const { + if (class_def.interfaces_off_ == 0) { + return NULL; + } else { + const byte* addr = begin_ + class_def.interfaces_off_; + return reinterpret_cast<const TypeList*>(addr); + } + } + + // Returns a pointer to the raw memory mapped class_data_item + const byte* GetClassData(const ClassDef& class_def) const { + if (class_def.class_data_off_ == 0) { + return NULL; + } else { + return begin_ + class_def.class_data_off_; + } + } + + // + const CodeItem* GetCodeItem(const uint32_t code_off) const { + if (code_off == 0) { + return NULL; // native or abstract method + } else { + const byte* addr = begin_ + code_off; + return reinterpret_cast<const CodeItem*>(addr); + } + } + + const char* GetReturnTypeDescriptor(const ProtoId& proto_id) const { + return StringByTypeIdx(proto_id.return_type_idx_); + } + + // Returns the number of prototype identifiers in the .dex file. + size_t NumProtoIds() const { + DCHECK(header_ != NULL) << GetLocation(); + return header_->proto_ids_size_; + } + + // Returns the ProtoId at the specified index. + const ProtoId& GetProtoId(uint32_t idx) const { + DCHECK_LT(idx, NumProtoIds()) << GetLocation(); + return proto_ids_[idx]; + } + + uint16_t GetIndexForProtoId(const ProtoId& proto_id) const { + CHECK_GE(&proto_id, proto_ids_) << GetLocation(); + CHECK_LT(&proto_id, proto_ids_ + header_->proto_ids_size_) << GetLocation(); + return &proto_id - proto_ids_; + } + + // Looks up a proto id for a given return type and signature type list + const ProtoId* FindProtoId(uint16_t return_type_id, + const std::vector<uint16_t>& signature_type_idxs_) const; + + // Given a signature place the type ids into the given vector, returns true on success + bool CreateTypeList(uint16_t* return_type_idx, std::vector<uint16_t>* param_type_idxs, + const std::string& signature) const; + + // Given a proto_idx decode the type list and return type into a method signature + std::string CreateMethodSignature(uint32_t proto_idx, int32_t* unicode_length) const; + + // Returns the short form method descriptor for the given prototype. + const char* GetShorty(uint32_t proto_idx) const { + const ProtoId& proto_id = GetProtoId(proto_idx); + return StringDataByIdx(proto_id.shorty_idx_); + } + + const TypeList* GetProtoParameters(const ProtoId& proto_id) const { + if (proto_id.parameters_off_ == 0) { + return NULL; + } else { + const byte* addr = begin_ + proto_id.parameters_off_; + return reinterpret_cast<const TypeList*>(addr); + } + } + + const byte* GetEncodedStaticFieldValuesArray(const ClassDef& class_def) const { + if (class_def.static_values_off_ == 0) { + return 0; + } else { + return begin_ + class_def.static_values_off_; + } + } + + static const TryItem* GetTryItems(const CodeItem& code_item, uint32_t offset); + + // Get the base of the encoded data for the given DexCode. + static const byte* GetCatchHandlerData(const CodeItem& code_item, uint32_t offset) { + const byte* handler_data = + reinterpret_cast<const byte*>(GetTryItems(code_item, code_item.tries_size_)); + return handler_data + offset; + } + + // Find which try region is associated with the given address (ie dex pc). Returns -1 if none. + static int32_t FindTryItem(const CodeItem &code_item, uint32_t address); + + // Find the handler offset associated with the given address (ie dex pc). Returns -1 if none. + static int32_t FindCatchHandlerOffset(const CodeItem &code_item, uint32_t address); + + // Get the pointer to the start of the debugging data + const byte* GetDebugInfoStream(const CodeItem* code_item) const { + if (code_item->debug_info_off_ == 0) { + return NULL; + } else { + return begin_ + code_item->debug_info_off_; + } + } + + // Callback for "new position table entry". + // Returning true causes the decoder to stop early. + typedef bool (*DexDebugNewPositionCb)(void* context, uint32_t address, uint32_t line_num); + + // Callback for "new locals table entry". "signature" is an empty string + // if no signature is available for an entry. + typedef void (*DexDebugNewLocalCb)(void* context, uint16_t reg, + uint32_t start_address, + uint32_t end_address, + const char* name, + const char* descriptor, + const char* signature); + + static bool LineNumForPcCb(void* context, uint32_t address, uint32_t line_num); + + // 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, + }; + + struct LocalInfo { + LocalInfo() + : name_(NULL), descriptor_(NULL), signature_(NULL), start_address_(0), is_live_(false) {} + + const char* name_; // E.g., list + const char* descriptor_; // E.g., Ljava/util/LinkedList; + const char* signature_; // E.g., java.util.LinkedList<java.lang.Integer> + uint16_t start_address_; // PC location where the local is first defined. + bool is_live_; // Is the local defined and live. + + private: + DISALLOW_COPY_AND_ASSIGN(LocalInfo); + }; + + struct LineNumFromPcContext { + LineNumFromPcContext(uint32_t address, uint32_t line_num) + : address_(address), line_num_(line_num) {} + uint32_t address_; + uint32_t line_num_; + private: + DISALLOW_COPY_AND_ASSIGN(LineNumFromPcContext); + }; + + void InvokeLocalCbIfLive(void* context, int reg, uint32_t end_address, + LocalInfo* local_in_reg, DexDebugNewLocalCb local_cb) const { + if (local_cb != NULL && local_in_reg[reg].is_live_) { + local_cb(context, reg, local_in_reg[reg].start_address_, end_address, + local_in_reg[reg].name_, local_in_reg[reg].descriptor_, + local_in_reg[reg].signature_ != NULL ? local_in_reg[reg].signature_ : ""); + } + } + + // Determine the source file line number based on the program counter. + // "pc" is an offset, in 16-bit units, from the start of the method's code. + // + // Returns -1 if no match was found (possibly because the source files were + // compiled without "-g", so no line number information is present). + // Returns -2 for native methods (as expected in exception traces). + // + // This is used by runtime; therefore use art::Method not art::DexFile::Method. + int32_t GetLineNumFromPC(const mirror::AbstractMethod* method, uint32_t rel_pc) const + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + + void DecodeDebugInfo(const CodeItem* code_item, bool is_static, uint32_t method_idx, + DexDebugNewPositionCb position_cb, DexDebugNewLocalCb local_cb, + void* context) const; + + const char* GetSourceFile(const ClassDef& class_def) const { + if (class_def.source_file_idx_ == 0xffffffff) { + return NULL; + } else { + return StringDataByIdx(class_def.source_file_idx_); + } + } + + int GetPermissions() const; + + bool IsReadOnly() const; + + bool EnableWrite(uint8_t* addr, size_t size) const; + + bool DisableWrite(uint8_t* addr, size_t size) const; + + private: + // Opens a .dex file + static const DexFile* OpenFile(const std::string& filename, + const std::string& location, + bool verify); + + // Opens a dex file from within a .jar, .zip, or .apk file + static const DexFile* OpenZip(const std::string& filename, + const std::string& location); + + // Opens a .dex file at the given address backed by a MemMap + static const DexFile* OpenMemory(const std::string& location, + uint32_t location_checksum, + MemMap* mem_map); + + // Opens a .dex file at the given address, optionally backed by a MemMap + static const DexFile* OpenMemory(const byte* dex_file, + size_t size, + const std::string& location, + uint32_t location_checksum, + MemMap* mem_map); + + DexFile(const byte* base, size_t size, + const std::string& location, + uint32_t location_checksum, + MemMap* mem_map) + : begin_(base), + size_(size), + location_(location), + location_checksum_(location_checksum), + mem_map_(mem_map), + dex_object_(NULL), + modification_lock("DEX modification lock"), + header_(0), + string_ids_(0), + type_ids_(0), + field_ids_(0), + method_ids_(0), + proto_ids_(0), + class_defs_(0) { + CHECK(begin_ != NULL) << GetLocation(); + CHECK_GT(size_, 0U) << GetLocation(); + } + + const byte* Begin() const { + return begin_; + } + + size_t Size() const { + return size_; + } + + // Top-level initializer that calls other Init methods. + bool Init(); + + // Caches pointers into to the various file sections. + void InitMembers(); + + // Builds the index of descriptors to class definitions. + void InitIndex(); + + // Returns true if the header magic and version numbers are of the expected values. + bool CheckMagicAndVersion() const; + + void DecodeDebugInfo0(const CodeItem* code_item, bool is_static, uint32_t method_idx, + DexDebugNewPositionCb position_cb, DexDebugNewLocalCb local_cb, + void* context, const byte* stream, LocalInfo* local_in_reg) const; + + // The index of descriptors to class definition indexes (as opposed to type id indexes) + typedef SafeMap<const StringPiece, uint32_t> Index; + Index index_; + + // The base address of the memory mapping. + const byte* const begin_; + + // The size of the underlying memory allocation in bytes. + const size_t 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_; + + // Manages the underlying memory allocation. + UniquePtr<MemMap> mem_map_; + + // A cached com.android.dex.Dex instance, possibly NULL. Use GetDexObject. + // TODO: this is mutable as it shouldn't be here. We should move it to the dex cache or similar. + mutable jobject dex_object_; + + // The DEX-to-DEX compiler uses this lock to ensure thread safety when + // enabling write access to a read-only DEX file. + // TODO: move to Locks::dex_file_modification_lock. + Mutex modification_lock; + + // Points to the header section. + const Header* header_; + + // Points to the base of the string identifier list. + const StringId* string_ids_; + + // Points to the base of the type identifier list. + const TypeId* type_ids_; + + // Points to the base of the field identifier list. + const FieldId* field_ids_; + + // Points to the base of the method identifier list. + const MethodId* method_ids_; + + // Points to the base of the prototype identifier list. + const ProtoId* proto_ids_; + + // Points to the base of the class definition list. + const ClassDef* class_defs_; +}; + +// Iterate over a dex file's ProtoId's paramters +class DexFileParameterIterator { + public: + DexFileParameterIterator(const DexFile& dex_file, const DexFile::ProtoId& proto_id) + : dex_file_(dex_file), size_(0), pos_(0) { + type_list_ = dex_file_.GetProtoParameters(proto_id); + if (type_list_ != NULL) { + size_ = type_list_->Size(); + } + } + bool HasNext() const { return pos_ < size_; } + void Next() { ++pos_; } + uint16_t GetTypeIdx() { + return type_list_->GetTypeItem(pos_).type_idx_; + } + const char* GetDescriptor() { + return dex_file_.StringByTypeIdx(GetTypeIdx()); + } + private: + const DexFile& dex_file_; + const DexFile::TypeList* type_list_; + uint32_t size_; + uint32_t pos_; + DISALLOW_IMPLICIT_CONSTRUCTORS(DexFileParameterIterator); +}; + +// Iterate and decode class_data_item +class ClassDataItemIterator { + public: + ClassDataItemIterator(const DexFile& dex_file, const byte* raw_class_data_item) + : dex_file_(dex_file), pos_(0), ptr_pos_(raw_class_data_item), last_idx_(0) { + ReadClassDataHeader(); + if (EndOfInstanceFieldsPos() > 0) { + ReadClassDataField(); + } else if (EndOfVirtualMethodsPos() > 0) { + ReadClassDataMethod(); + } + } + uint32_t NumStaticFields() const { + return header_.static_fields_size_; + } + uint32_t NumInstanceFields() const { + return header_.instance_fields_size_; + } + uint32_t NumDirectMethods() const { + return header_.direct_methods_size_; + } + uint32_t NumVirtualMethods() const { + return header_.virtual_methods_size_; + } + bool HasNextStaticField() const { + return pos_ < EndOfStaticFieldsPos(); + } + bool HasNextInstanceField() const { + return pos_ >= EndOfStaticFieldsPos() && pos_ < EndOfInstanceFieldsPos(); + } + bool HasNextDirectMethod() const { + return pos_ >= EndOfInstanceFieldsPos() && pos_ < EndOfDirectMethodsPos(); + } + bool HasNextVirtualMethod() const { + return pos_ >= EndOfDirectMethodsPos() && pos_ < EndOfVirtualMethodsPos(); + } + bool HasNext() const { + return pos_ < EndOfVirtualMethodsPos(); + } + inline void Next() { + pos_++; + if (pos_ < EndOfStaticFieldsPos()) { + last_idx_ = GetMemberIndex(); + ReadClassDataField(); + } else if (pos_ == EndOfStaticFieldsPos() && NumInstanceFields() > 0) { + last_idx_ = 0; // transition to next array, reset last index + ReadClassDataField(); + } else if (pos_ < EndOfInstanceFieldsPos()) { + last_idx_ = GetMemberIndex(); + ReadClassDataField(); + } else if (pos_ == EndOfInstanceFieldsPos() && NumDirectMethods() > 0) { + last_idx_ = 0; // transition to next array, reset last index + ReadClassDataMethod(); + } else if (pos_ < EndOfDirectMethodsPos()) { + last_idx_ = GetMemberIndex(); + ReadClassDataMethod(); + } else if (pos_ == EndOfDirectMethodsPos() && NumVirtualMethods() > 0) { + last_idx_ = 0; // transition to next array, reset last index + ReadClassDataMethod(); + } else if (pos_ < EndOfVirtualMethodsPos()) { + last_idx_ = GetMemberIndex(); + ReadClassDataMethod(); + } else { + DCHECK(!HasNext()); + } + } + uint32_t GetMemberIndex() const { + if (pos_ < EndOfInstanceFieldsPos()) { + return last_idx_ + field_.field_idx_delta_; + } else { + CHECK_LT(pos_, EndOfVirtualMethodsPos()); + return last_idx_ + method_.method_idx_delta_; + } + } + uint32_t GetMemberAccessFlags() const { + if (pos_ < EndOfInstanceFieldsPos()) { + return field_.access_flags_; + } else { + CHECK_LT(pos_, EndOfVirtualMethodsPos()); + return method_.access_flags_; + } + } + InvokeType GetMethodInvokeType(const DexFile::ClassDef& class_def) const { + if (HasNextDirectMethod()) { + if ((GetMemberAccessFlags() & kAccStatic) != 0 ) { + return kStatic; + } else { + return kDirect; + } + } else { + CHECK_EQ(GetMemberAccessFlags() & kAccStatic, 0U); + if ((class_def.access_flags_ & kAccInterface) != 0) { + return kInterface; + } else if ((GetMemberAccessFlags() & kAccConstructor) != 0) { + return kSuper; + } else { + return kVirtual; + } + } + } + const DexFile::CodeItem* GetMethodCodeItem() const { + return dex_file_.GetCodeItem(method_.code_off_); + } + uint32_t GetMethodCodeItemOffset() const { + return method_.code_off_; + } + const byte* EndDataPointer() const { + CHECK(!HasNext()); + return ptr_pos_; + } + + private: + // A dex file's class_data_item is leb128 encoded, this structure holds a decoded form of the + // header for a class_data_item + struct ClassDataHeader { + uint32_t static_fields_size_; // the number of static fields + uint32_t instance_fields_size_; // the number of instance fields + uint32_t direct_methods_size_; // the number of direct methods + uint32_t virtual_methods_size_; // the number of virtual methods + } header_; + + // Read and decode header from a class_data_item stream into header + void ReadClassDataHeader(); + + uint32_t EndOfStaticFieldsPos() const { + return header_.static_fields_size_; + } + uint32_t EndOfInstanceFieldsPos() const { + return EndOfStaticFieldsPos() + header_.instance_fields_size_; + } + uint32_t EndOfDirectMethodsPos() const { + return EndOfInstanceFieldsPos() + header_.direct_methods_size_; + } + uint32_t EndOfVirtualMethodsPos() const { + return EndOfDirectMethodsPos() + header_.virtual_methods_size_; + } + + // A decoded version of the field of a class_data_item + struct ClassDataField { + uint32_t field_idx_delta_; // delta of index into the field_ids array for FieldId + uint32_t access_flags_; // access flags for the field + ClassDataField() : field_idx_delta_(0), access_flags_(0) {} + + private: + DISALLOW_COPY_AND_ASSIGN(ClassDataField); + }; + ClassDataField field_; + + // Read and decode a field from a class_data_item stream into field + void ReadClassDataField(); + + // A decoded version of the method of a class_data_item + struct ClassDataMethod { + uint32_t method_idx_delta_; // delta of index into the method_ids array for MethodId + uint32_t access_flags_; + uint32_t code_off_; + ClassDataMethod() : method_idx_delta_(0), access_flags_(0), code_off_(0) {} + + private: + DISALLOW_COPY_AND_ASSIGN(ClassDataMethod); + }; + ClassDataMethod method_; + + // Read and decode a method from a class_data_item stream into method + void ReadClassDataMethod(); + + const DexFile& dex_file_; + size_t pos_; // integral number of items passed + const byte* ptr_pos_; // pointer into stream of class_data_item + uint32_t last_idx_; // last read field or method index to apply delta to + DISALLOW_IMPLICIT_CONSTRUCTORS(ClassDataItemIterator); +}; + +class EncodedStaticFieldValueIterator { + public: + EncodedStaticFieldValueIterator(const DexFile& dex_file, mirror::DexCache* dex_cache, + mirror::ClassLoader* class_loader, + ClassLinker* linker, const DexFile::ClassDef& class_def) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + + void ReadValueToField(mirror::Field* field) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + + bool HasNext() { return pos_ < array_size_; } + + void Next(); + + enum ValueType { + kByte = 0x00, + kShort = 0x02, + kChar = 0x03, + kInt = 0x04, + kLong = 0x06, + kFloat = 0x10, + kDouble = 0x11, + kString = 0x17, + kType = 0x18, + kField = 0x19, + kMethod = 0x1a, + kEnum = 0x1b, + kArray = 0x1c, + kAnnotation = 0x1d, + kNull = 0x1e, + kBoolean = 0x1f + }; + + private: + static const byte kEncodedValueTypeMask = 0x1f; // 0b11111 + static const byte kEncodedValueArgShift = 5; + + const DexFile& dex_file_; + mirror::DexCache* dex_cache_; // Dex cache to resolve literal objects. + mirror::ClassLoader* class_loader_; // ClassLoader to resolve types. + ClassLinker* linker_; // Linker to resolve literal objects. + size_t array_size_; // Size of array. + size_t pos_; // Current position. + const byte* ptr_; // Pointer into encoded data array. + ValueType type_; // Type of current encoded value. + jvalue jval_; // Value of current encoded value. + DISALLOW_IMPLICIT_CONSTRUCTORS(EncodedStaticFieldValueIterator); +}; +std::ostream& operator<<(std::ostream& os, const EncodedStaticFieldValueIterator::ValueType& code); + +class CatchHandlerIterator { + public: + CatchHandlerIterator(const DexFile::CodeItem& code_item, uint32_t address); + + CatchHandlerIterator(const DexFile::CodeItem& code_item, + const DexFile::TryItem& try_item); + + explicit CatchHandlerIterator(const byte* handler_data) { + Init(handler_data); + } + + uint16_t GetHandlerTypeIndex() const { + return handler_.type_idx_; + } + uint32_t GetHandlerAddress() const { + return handler_.address_; + } + void Next(); + bool HasNext() const { + return remaining_count_ != -1 || catch_all_; + } + // End of this set of catch blocks, convenience method to locate next set of catch blocks + const byte* EndDataPointer() const { + CHECK(!HasNext()); + return current_data_; + } + + private: + void Init(const DexFile::CodeItem& code_item, int32_t offset); + void Init(const byte* handler_data); + + struct CatchHandlerItem { + uint16_t type_idx_; // type index of the caught exception type + uint32_t address_; // handler address + } handler_; + const byte *current_data_; // the current handler in dex file. + int32_t remaining_count_; // number of handlers not read. + bool catch_all_; // is there a handler that will catch all exceptions in case + // that all typed handler does not match. +}; + +} // namespace art + +#endif // ART_SRC_DEX_FILE_H_ |