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