/* * Copyright (C) 2018 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_CLASS_ACCESSOR_H_ #define ART_LIBDEXFILE_DEX_CLASS_ACCESSOR_H_ #include "base/utils.h" #include "code_item_accessors.h" #include "dex_file.h" #include "invoke_type.h" #include "method_reference.h" #include "modifiers.h" namespace art { class ClassIteratorData; // Classes to access Dex data. class ClassAccessor { private: class BaseItem { public: uint32_t GetIndex() const { return index_; } uint32_t GetAccessFlags() const { return access_flags_; } bool IsFinal() const { return (GetAccessFlags() & kAccFinal) != 0; } protected: uint32_t index_ = 0u; uint32_t access_flags_ = 0u; }; public: // A decoded version of the method of a class_data_item. class Method : public BaseItem { public: uint32_t GetCodeItemOffset() const { return code_off_; } InvokeType GetInvokeType(uint32_t class_access_flags) const { return is_static_or_direct_ ? GetDirectMethodInvokeType() : GetVirtualMethodInvokeType(class_access_flags); } MethodReference GetReference() const { return MethodReference(&dex_file_, GetIndex()); } CodeItemInstructionAccessor GetInstructions() const; const DexFile::CodeItem* GetCodeItem() const; bool IsStaticOrDirect() const { return is_static_or_direct_; } private: explicit Method(const DexFile& dex_file, bool is_static_or_direct = true) : dex_file_(dex_file), is_static_or_direct_(is_static_or_direct) {} const uint8_t* Read(const uint8_t* ptr); InvokeType GetDirectMethodInvokeType() const { return (GetAccessFlags() & kAccStatic) != 0 ? kStatic : kDirect; } InvokeType GetVirtualMethodInvokeType(uint32_t class_access_flags) const { DCHECK_EQ(GetAccessFlags() & kAccStatic, 0U); if ((class_access_flags & kAccInterface) != 0) { return kInterface; } else if ((GetAccessFlags() & kAccConstructor) != 0) { return kSuper; } else { return kVirtual; } } void NextSection() { DCHECK(is_static_or_direct_) << "Already in the virtual methods section"; is_static_or_direct_ = false; index_ = 0u; } const DexFile& dex_file_; bool is_static_or_direct_ = true; uint32_t code_off_ = 0u; friend class ClassAccessor; }; // A decoded version of the field of a class_data_item. class Field : public BaseItem { public: explicit Field(const DexFile& dex_file) : dex_file_(dex_file) {} const DexFile& GetDexFile() const { return dex_file_; } private: const uint8_t* Read(const uint8_t* ptr); void NextSection() { index_ = 0u; } const DexFile& dex_file_; friend class ClassAccessor; }; template class DataIterator : public std::iterator { public: using value_type = typename std::iterator::value_type; using difference_type = typename std::iterator::difference_type; DataIterator(const DexFile& dex_file, uint32_t position, uint32_t partition_pos, uint32_t iterator_end, const uint8_t* ptr_pos) : data_(dex_file), position_(position), partition_pos_(partition_pos), iterator_end_(iterator_end), ptr_pos_(ptr_pos) { ReadData(); } bool IsValid() const { return position_ < iterator_end_; } // Value after modification. DataIterator& operator++() { ++position_; ReadData(); return *this; } const value_type& operator*() const { return data_; } const value_type* operator->() const { return &data_; } bool operator==(const DataIterator& rhs) const { DCHECK_EQ(&data_.dex_file_, &rhs.data_.dex_file_) << "Comparing different dex files."; return position_ == rhs.position_; } bool operator!=(const DataIterator& rhs) const { return !(*this == rhs); } bool operator<(const DataIterator& rhs) const { DCHECK_EQ(&data_.dex_file_, &rhs.data_.dex_file_) << "Comparing different dex files."; return position_ < rhs.position_; } bool operator>(const DataIterator& rhs) const { return rhs < *this; } bool operator<=(const DataIterator& rhs) const { return !(rhs < *this); } bool operator>=(const DataIterator& rhs) const { return !(*this < rhs); } private: // Read data at current position. void ReadData() { if (IsValid()) { // At the end of the first section, go to the next section. if (position_ == partition_pos_) { data_.NextSection(); } DCHECK(ptr_pos_ != nullptr); ptr_pos_ = data_.Read(ptr_pos_); } } DataType data_; // Iterator position. uint32_t position_; // At partition_pos_, we go to the next section. const uint32_t partition_pos_; // At iterator_end_, the iterator is no longer valid. const uint32_t iterator_end_; // Internal data pointer. const uint8_t* ptr_pos_; }; // Not explicit specifically for range-based loops. ALWAYS_INLINE ClassAccessor(const ClassIteratorData& data); ClassAccessor(const DexFile& dex_file, const DexFile::ClassDef& class_def); // Return the code item for a method. const DexFile::CodeItem* GetCodeItem(const Method& method) const; // Iterator data is not very iterator friendly, use visitors to get around this. template void VisitFieldsAndMethods(const StaticFieldVisitor& static_field_visitor, const InstanceFieldVisitor& instance_field_visitor, const DirectMethodVisitor& direct_method_visitor, const VirtualMethodVisitor& virtual_method_visitor) const; template void VisitMethods(const DirectMethodVisitor& direct_method_visitor, const VirtualMethodVisitor& virtual_method_visitor) const; template void VisitFields(const StaticFieldVisitor& static_field_visitor, const InstanceFieldVisitor& instance_field_visitor) const; // Return the iteration range for all the fields. IterationRange> GetFields() const; // Return the iteration range for all the methods. IterationRange> GetMethods() const; uint32_t NumStaticFields() const { return num_static_fields_; } uint32_t NumInstanceFields() const { return num_instance_fields_; } uint32_t NumDirectMethods() const { return num_direct_methods_; } uint32_t NumVirtualMethods() const { return num_virtual_methods_; } uint32_t NumMethods() const { return NumDirectMethods() + NumVirtualMethods(); } const char* GetDescriptor() const; dex::TypeIndex GetClassIdx() const { return descriptor_index_; } const DexFile& GetDexFile() const { return dex_file_; } protected: // Template visitor to reduce copy paste for visiting elements. // No thread safety analysis since the visitor may require capabilities. template const uint8_t* VisitMembers(size_t count, const Visitor& visitor, const uint8_t* ptr, DataType* data) const NO_THREAD_SAFETY_ANALYSIS; const DexFile& dex_file_; const dex::TypeIndex descriptor_index_ = {}; const uint8_t* ptr_pos_ = nullptr; // Pointer into stream of class_data_item. const uint32_t num_static_fields_ = 0u; const uint32_t num_instance_fields_ = 0u; const uint32_t num_direct_methods_ = 0u; const uint32_t num_virtual_methods_ = 0u; }; } // namespace art #endif // ART_LIBDEXFILE_DEX_CLASS_ACCESSOR_H_