1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef ART_LIBDEXFILE_DEX_CLASS_ACCESSOR_H_
18 #define ART_LIBDEXFILE_DEX_CLASS_ACCESSOR_H_
19 
20 #include "code_item_accessors.h"
21 #include "dex_file_types.h"
22 #include "invoke_type.h"
23 #include "modifiers.h"
24 
25 namespace art {
26 
27 namespace dex {
28 struct ClassDef;
29 struct CodeItem;
30 class DexFileVerifier;
31 }  // namespace dex
32 
33 class ClassIteratorData;
34 class DexFile;
35 template <typename Iter> class IterationRange;
36 class MethodReference;
37 
38 // Classes to access Dex data.
39 class ClassAccessor {
40  public:
41   class BaseItem {
42    public:
BaseItem(const DexFile & dex_file,const uint8_t * ptr_pos,const uint8_t * hiddenapi_ptr_pos)43     explicit BaseItem(const DexFile& dex_file,
44                       const uint8_t* ptr_pos,
45                       const uint8_t* hiddenapi_ptr_pos)
46         : dex_file_(dex_file), ptr_pos_(ptr_pos), hiddenapi_ptr_pos_(hiddenapi_ptr_pos) {}
47 
GetIndex()48     uint32_t GetIndex() const {
49       return index_;
50     }
51 
GetAccessFlags()52     uint32_t GetAccessFlags() const {
53       return access_flags_;
54     }
55 
GetHiddenapiFlags()56     uint32_t GetHiddenapiFlags() const {
57       return hiddenapi_flags_;
58     }
59 
IsFinal()60     bool IsFinal() const {
61       return (GetAccessFlags() & kAccFinal) != 0;
62     }
63 
GetDexFile()64     const DexFile& GetDexFile() const {
65       return dex_file_;
66     }
67 
GetDataPointer()68     const uint8_t* GetDataPointer() const {
69       return ptr_pos_;
70     }
71 
MemberIsNative()72     bool MemberIsNative() const {
73       return GetAccessFlags() & kAccNative;
74     }
75 
MemberIsFinal()76     bool MemberIsFinal() const {
77       return GetAccessFlags() & kAccFinal;
78     }
79 
80    protected:
81     // Internal data pointer for reading.
82     const DexFile& dex_file_;
83     const uint8_t* ptr_pos_ = nullptr;
84     const uint8_t* hiddenapi_ptr_pos_ = nullptr;
85     uint32_t index_ = 0u;
86     uint32_t access_flags_ = 0u;
87     uint32_t hiddenapi_flags_ = 0u;
88   };
89 
90   // A decoded version of the method of a class_data_item.
91   class Method : public BaseItem {
92    public:
GetCodeItemOffset()93     uint32_t GetCodeItemOffset() const {
94       return code_off_;
95     }
96 
GetInvokeType(uint32_t class_access_flags)97     InvokeType GetInvokeType(uint32_t class_access_flags) const {
98       return is_static_or_direct_
99           ? GetDirectMethodInvokeType()
100           : GetVirtualMethodInvokeType(class_access_flags);
101     }
102 
103     MethodReference GetReference() const;
104 
105     CodeItemInstructionAccessor GetInstructions() const;
106     CodeItemDataAccessor GetInstructionsAndData() const;
107 
108     const dex::CodeItem* GetCodeItem() const;
109 
IsStaticOrDirect()110     bool IsStaticOrDirect() const {
111       return is_static_or_direct_;
112     }
113 
114    private:
115     Method(const DexFile& dex_file,
116            const uint8_t* ptr_pos,
117            const uint8_t* hiddenapi_ptr_pos = nullptr,
118            bool is_static_or_direct = true)
BaseItem(dex_file,ptr_pos,hiddenapi_ptr_pos)119         : BaseItem(dex_file, ptr_pos, hiddenapi_ptr_pos),
120           is_static_or_direct_(is_static_or_direct) {}
121 
122     void Read();
123 
GetDirectMethodInvokeType()124     InvokeType GetDirectMethodInvokeType() const {
125       return (GetAccessFlags() & kAccStatic) != 0 ? kStatic : kDirect;
126     }
127 
GetVirtualMethodInvokeType(uint32_t class_access_flags)128     InvokeType GetVirtualMethodInvokeType(uint32_t class_access_flags) const {
129       DCHECK_EQ(GetAccessFlags() & kAccStatic, 0U);
130       if ((class_access_flags & kAccInterface) != 0) {
131         return kInterface;
132       } else if ((GetAccessFlags() & kAccConstructor) != 0) {
133         return kSuper;
134       } else {
135         return kVirtual;
136       }
137     }
138 
139     // Move to virtual method section.
NextSection()140     void NextSection() {
141       DCHECK(is_static_or_direct_) << "Already in the virtual methods section";
142       is_static_or_direct_ = false;
143       index_ = 0u;
144     }
145 
146     bool is_static_or_direct_ = true;
147     uint32_t code_off_ = 0u;
148 
149     friend class ClassAccessor;
150     friend class dex::DexFileVerifier;
151   };
152 
153   // A decoded version of the field of a class_data_item.
154   class Field : public BaseItem {
155    public:
156     Field(const DexFile& dex_file,
157           const uint8_t* ptr_pos,
158           const uint8_t* hiddenapi_ptr_pos = nullptr)
BaseItem(dex_file,ptr_pos,hiddenapi_ptr_pos)159         : BaseItem(dex_file, ptr_pos, hiddenapi_ptr_pos) {}
160 
IsStatic()161     bool IsStatic() const {
162      return is_static_;
163     }
164 
165    private:
166     void Read();
167 
168     // Move to instance fields section.
NextSection()169     void NextSection() {
170       index_ = 0u;
171       is_static_ = false;
172     }
173 
174     bool is_static_ = true;
175     friend class ClassAccessor;
176     friend class dex::DexFileVerifier;
177   };
178 
179   template <typename DataType>
180   class DataIterator : public std::iterator<std::forward_iterator_tag, DataType> {
181    public:
182     using value_type = typename std::iterator<std::forward_iterator_tag, DataType>::value_type;
183     using difference_type =
184         typename std::iterator<std::forward_iterator_tag, value_type>::difference_type;
185 
DataIterator(const DexFile & dex_file,uint32_t position,uint32_t partition_pos,uint32_t iterator_end,const uint8_t * ptr_pos,const uint8_t * hiddenapi_ptr_pos)186     DataIterator(const DexFile& dex_file,
187                  uint32_t position,
188                  uint32_t partition_pos,
189                  uint32_t iterator_end,
190                  const uint8_t* ptr_pos,
191                  const uint8_t* hiddenapi_ptr_pos)
192         : data_(dex_file, ptr_pos, hiddenapi_ptr_pos),
193           position_(position),
194           partition_pos_(partition_pos),
195           iterator_end_(iterator_end) {
196       ReadData();
197     }
198 
IsValid()199     bool IsValid() const {
200       return position_ < iterator_end_;
201     }
202 
203     // Value after modification.
204     DataIterator& operator++() {
205       ++position_;
206       ReadData();
207       return *this;
208     }
209 
210     const value_type& operator*() const {
211       return data_;
212     }
213 
214     const value_type* operator->() const {
215       return &data_;
216     }
217 
218     bool operator==(const DataIterator& rhs) const {
219       DCHECK_EQ(&data_.dex_file_, &rhs.data_.dex_file_) << "Comparing different dex files.";
220       return position_ == rhs.position_;
221     }
222 
223     bool operator!=(const DataIterator& rhs) const {
224       return !(*this == rhs);
225     }
226 
227     bool operator<(const DataIterator& rhs) const {
228       DCHECK_EQ(&data_.dex_file_, &rhs.data_.dex_file_) << "Comparing different dex files.";
229       return position_ < rhs.position_;
230     }
231 
232     bool operator>(const DataIterator& rhs) const {
233       return rhs < *this;
234     }
235 
236     bool operator<=(const DataIterator& rhs) const {
237       return !(rhs < *this);
238     }
239 
240     bool operator>=(const DataIterator& rhs) const {
241       return !(*this < rhs);
242     }
243 
GetDataPointer()244     const uint8_t* GetDataPointer() const {
245       return data_.ptr_pos_;
246     }
247 
248    private:
249     // Read data at current position.
ReadData()250     void ReadData() {
251       if (IsValid()) {
252         // At the end of the first section, go to the next section.
253         if (position_ == partition_pos_) {
254           data_.NextSection();
255         }
256         data_.Read();
257       }
258     }
259 
260     DataType data_;
261     // Iterator position.
262     uint32_t position_;
263     // At partition_pos_, we go to the next section.
264     const uint32_t partition_pos_;
265     // At iterator_end_, the iterator is no longer valid.
266     const uint32_t iterator_end_;
267 
268     friend class dex::DexFileVerifier;
269   };
270 
271   // Not explicit specifically for range-based loops.
272   ALWAYS_INLINE ClassAccessor(const ClassIteratorData& data);  // NOLINT [runtime/explicit] [5]
273 
274   ALWAYS_INLINE ClassAccessor(const DexFile& dex_file,
275                               const dex::ClassDef& class_def,
276                               bool parse_hiddenapi_class_data = false);
277 
278   ALWAYS_INLINE ClassAccessor(const DexFile& dex_file, uint32_t class_def_index);
279 
280   ClassAccessor(const DexFile& dex_file,
281                 const uint8_t* class_data,
282                 uint32_t class_def_index = dex::kDexNoIndex,
283                 bool parse_hiddenapi_class_data = false);
284 
285   // Return the code item for a method.
286   const dex::CodeItem* GetCodeItem(const Method& method) const;
287 
288   // Iterator data is not very iterator friendly, use visitors to get around this.
289   template <typename StaticFieldVisitor,
290             typename InstanceFieldVisitor,
291             typename DirectMethodVisitor,
292             typename VirtualMethodVisitor>
293   void VisitFieldsAndMethods(const StaticFieldVisitor& static_field_visitor,
294                              const InstanceFieldVisitor& instance_field_visitor,
295                              const DirectMethodVisitor& direct_method_visitor,
296                              const VirtualMethodVisitor& virtual_method_visitor) const;
297 
298   template <typename DirectMethodVisitor,
299             typename VirtualMethodVisitor>
300   void VisitMethods(const DirectMethodVisitor& direct_method_visitor,
301                     const VirtualMethodVisitor& virtual_method_visitor) const;
302 
303   template <typename StaticFieldVisitor,
304             typename InstanceFieldVisitor>
305   void VisitFields(const StaticFieldVisitor& static_field_visitor,
306                    const InstanceFieldVisitor& instance_field_visitor) const;
307 
308   // Return the iteration range for all the fields.
309   IterationRange<DataIterator<Field>> GetFields() const;
310 
311   // Return the iteration range for all the static fields.
312   IterationRange<DataIterator<Field>> GetStaticFields() const;
313 
314   // Return the iteration range for all the instance fields.
315   IterationRange<DataIterator<Field>> GetInstanceFields() const;
316 
317   // Return the iteration range for all the methods.
318   IterationRange<DataIterator<Method>> GetMethods() const;
319 
320   // Return the iteration range for the direct methods.
321   IterationRange<DataIterator<Method>> GetDirectMethods() const;
322 
323   // Return the iteration range for the virtual methods.
324   IterationRange<DataIterator<Method>> GetVirtualMethods() const;
325 
NumStaticFields()326   uint32_t NumStaticFields() const {
327     return num_static_fields_;
328   }
329 
NumInstanceFields()330   uint32_t NumInstanceFields() const {
331     return num_instance_fields_;
332   }
333 
NumFields()334   uint32_t NumFields() const {
335     return NumStaticFields() + NumInstanceFields();
336   }
337 
NumDirectMethods()338   uint32_t NumDirectMethods() const {
339     return num_direct_methods_;
340   }
341 
NumVirtualMethods()342   uint32_t NumVirtualMethods() const {
343     return num_virtual_methods_;
344   }
345 
NumMethods()346   uint32_t NumMethods() const {
347     return NumDirectMethods() + NumVirtualMethods();
348   }
349 
350   const char* GetDescriptor() const;
351 
352   dex::TypeIndex GetClassIdx() const;
353 
GetDexFile()354   const DexFile& GetDexFile() const {
355     return dex_file_;
356   }
357 
HasClassData()358   bool HasClassData() const {
359     return ptr_pos_ != nullptr;
360   }
361 
HasHiddenapiClassData()362   bool HasHiddenapiClassData() const {
363     return hiddenapi_ptr_pos_ != nullptr;
364   }
365 
GetClassDefIndex()366   uint32_t GetClassDefIndex() const {
367     return class_def_index_;
368   }
369 
370   const dex::ClassDef& GetClassDef() const;
371 
372  protected:
373   // Template visitor to reduce copy paste for visiting elements.
374   // No thread safety analysis since the visitor may require capabilities.
375   template <typename DataType, typename Visitor>
376   void VisitMembers(size_t count, const Visitor& visitor, DataType* data) const
377       NO_THREAD_SAFETY_ANALYSIS;
378 
379   // Return an iteration range for the first <count> fields.
380   IterationRange<DataIterator<Field>> GetFieldsInternal(size_t count) const;
381 
382   // Return an iteration range for the first <count> methods.
383   IterationRange<DataIterator<Method>> GetMethodsInternal(size_t count) const;
384 
385   const DexFile& dex_file_;
386   const uint32_t class_def_index_;
387   const uint8_t* ptr_pos_ = nullptr;  // Pointer into stream of class_data_item.
388   const uint8_t* hiddenapi_ptr_pos_ = nullptr;  // Pointer into stream of hiddenapi_metadata.
389   const uint32_t num_static_fields_ = 0u;
390   const uint32_t num_instance_fields_ = 0u;
391   const uint32_t num_direct_methods_ = 0u;
392   const uint32_t num_virtual_methods_ = 0u;
393 
394   friend class dex::DexFileVerifier;
395 };
396 
397 }  // namespace art
398 
399 #endif  // ART_LIBDEXFILE_DEX_CLASS_ACCESSOR_H_
400