• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 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_DEX_INSTRUCTION_ITERATOR_H_
18 #define ART_LIBDEXFILE_DEX_DEX_INSTRUCTION_ITERATOR_H_
19 
20 #include <iterator>
21 
22 #include <android-base/logging.h>
23 
24 #include "base/macros.h"
25 #include "dex_instruction.h"
26 
27 namespace art {
28 
29 class DexInstructionPcPair {
30  public:
Inst()31   ALWAYS_INLINE const Instruction& Inst() const {
32     return *Instruction::At(instructions_ + DexPc());
33   }
34 
35   ALWAYS_INLINE const Instruction* operator->() const {
36     return &Inst();
37   }
38 
DexPc()39   ALWAYS_INLINE uint32_t DexPc() const {
40     return dex_pc_;
41   }
42 
Instructions()43   ALWAYS_INLINE const uint16_t* Instructions() const {
44     return instructions_;
45   }
46 
47  protected:
DexInstructionPcPair(const uint16_t * instructions,uint32_t dex_pc)48   explicit DexInstructionPcPair(const uint16_t* instructions, uint32_t dex_pc)
49       : instructions_(instructions), dex_pc_(dex_pc) {}
50 
51   const uint16_t* instructions_ = nullptr;
52   uint32_t dex_pc_ = 0;
53 
54   friend class DexInstructionIteratorBase;
55   friend class DexInstructionIterator;
56   friend class SafeDexInstructionIterator;
57 };
58 
59 // Base helper class to prevent duplicated comparators.
60 class DexInstructionIteratorBase : public
61         std::iterator<std::forward_iterator_tag, DexInstructionPcPair> {
62  public:
63   using value_type = std::iterator<std::forward_iterator_tag, DexInstructionPcPair>::value_type;
64   using difference_type = std::iterator<std::forward_iterator_tag, value_type>::difference_type;
65 
66   DexInstructionIteratorBase() = default;
DexInstructionIteratorBase(const Instruction * inst,uint32_t dex_pc)67   explicit DexInstructionIteratorBase(const Instruction* inst, uint32_t dex_pc)
68       : data_(reinterpret_cast<const uint16_t*>(inst), dex_pc) {}
69 
Inst()70   const Instruction& Inst() const {
71     return data_.Inst();
72   }
73 
74   // Return the dex pc for an iterator compared to the code item begin.
DexPc()75   ALWAYS_INLINE uint32_t DexPc() const {
76     return data_.DexPc();
77   }
78 
79   // Instructions from the start of the code item.
Instructions()80   ALWAYS_INLINE const uint16_t* Instructions() const {
81     return data_.Instructions();
82   }
83 
84  protected:
85   DexInstructionPcPair data_;
86 };
87 
88 static ALWAYS_INLINE inline bool operator==(const DexInstructionIteratorBase& lhs,
89                                             const DexInstructionIteratorBase& rhs) {
90   DCHECK_EQ(lhs.Instructions(), rhs.Instructions()) << "Comparing different code items.";
91   return lhs.DexPc() == rhs.DexPc();
92 }
93 
94 static inline bool operator!=(const DexInstructionIteratorBase& lhs,
95                               const DexInstructionIteratorBase& rhs) {
96   return !(lhs == rhs);
97 }
98 
99 static inline bool operator<(const DexInstructionIteratorBase& lhs,
100                              const DexInstructionIteratorBase& rhs) {
101   DCHECK_EQ(lhs.Instructions(), rhs.Instructions()) << "Comparing different code items.";
102   return lhs.DexPc() < rhs.DexPc();
103 }
104 
105 static inline bool operator>(const DexInstructionIteratorBase& lhs,
106                              const DexInstructionIteratorBase& rhs) {
107   return rhs < lhs;
108 }
109 
110 static inline bool operator<=(const DexInstructionIteratorBase& lhs,
111                               const DexInstructionIteratorBase& rhs) {
112   return !(rhs < lhs);
113 }
114 
115 static inline bool operator>=(const DexInstructionIteratorBase& lhs,
116                               const DexInstructionIteratorBase& rhs) {
117   return !(lhs < rhs);
118 }
119 
120 // A helper class for a code_item's instructions using range based for loop syntax.
121 class DexInstructionIterator : public DexInstructionIteratorBase {
122  public:
123   using DexInstructionIteratorBase::DexInstructionIteratorBase;
124 
DexInstructionIterator(const uint16_t * inst,uint32_t dex_pc)125   explicit DexInstructionIterator(const uint16_t* inst, uint32_t dex_pc)
126       : DexInstructionIteratorBase(Instruction::At(inst), dex_pc) {}
127 
DexInstructionIterator(const DexInstructionPcPair & pair)128   explicit DexInstructionIterator(const DexInstructionPcPair& pair)
129       : DexInstructionIterator(pair.Instructions(), pair.DexPc()) {}
130 
131   // Value after modification.
132   DexInstructionIterator& operator++() {
133     data_.dex_pc_ += Inst().SizeInCodeUnits();
134     return *this;
135   }
136 
137   // Value before modification.
138   DexInstructionIterator operator++(int) {
139     DexInstructionIterator temp = *this;
140     ++*this;
141     return temp;
142   }
143 
144   const value_type& operator*() const {
145     return data_;
146   }
147 
148   const Instruction* operator->() const {
149     return &data_.Inst();
150   }
151 
152   // Return the dex pc for the iterator.
DexPc()153   ALWAYS_INLINE uint32_t DexPc() const {
154     return data_.DexPc();
155   }
156 };
157 
158 // A safe version of DexInstructionIterator that is guaranteed to not go past the end of the code
159 // item.
160 class SafeDexInstructionIterator : public DexInstructionIteratorBase {
161  public:
SafeDexInstructionIterator(const DexInstructionIteratorBase & start,const DexInstructionIteratorBase & end)162   explicit SafeDexInstructionIterator(const DexInstructionIteratorBase& start,
163                                       const DexInstructionIteratorBase& end)
164       : DexInstructionIteratorBase(&start.Inst(), start.DexPc())
165       , num_code_units_(end.DexPc()) {
166     DCHECK_EQ(start.Instructions(), end.Instructions())
167         << "start and end must be in the same code item.";
168   }
169 
170   // Value after modification, does not read past the end of the allowed region. May increment past
171   // the end of the code item though.
172   SafeDexInstructionIterator& operator++() {
173     AssertValid();
174     const size_t size_code_units = Inst().CodeUnitsRequiredForSizeComputation();
175     const size_t available = NumCodeUnits() - DexPc();
176     if (UNLIKELY(size_code_units > available)) {
177       error_state_ = true;
178       return *this;
179     }
180     const size_t instruction_code_units = Inst().SizeInCodeUnits();
181     if (UNLIKELY(instruction_code_units > available)) {
182       error_state_ = true;
183       return *this;
184     }
185     data_.dex_pc_ += instruction_code_units;
186     return *this;
187   }
188 
189   // Value before modification.
190   SafeDexInstructionIterator operator++(int) {
191     SafeDexInstructionIterator temp = *this;
192     ++*this;
193     return temp;
194   }
195 
196   const value_type& operator*() const {
197     AssertValid();
198     return data_;
199   }
200 
201   const Instruction* operator->() const {
202     AssertValid();
203     return &data_.Inst();
204   }
205 
206   // Return the current instruction of the iterator.
Inst()207   ALWAYS_INLINE const Instruction& Inst() const {
208     return data_.Inst();
209   }
210 
Instructions()211   const uint16_t* Instructions() const {
212     return data_.Instructions();
213   }
214 
215   // Returns true if the iterator is in an error state. This occurs when an instruction couldn't
216   // have its size computed without reading past the end iterator.
IsErrorState()217   bool IsErrorState() const {
218     return error_state_;
219   }
220 
221  private:
AssertValid()222   ALWAYS_INLINE void AssertValid() const {
223     DCHECK(!IsErrorState());
224     DCHECK_LT(DexPc(), NumCodeUnits());
225   }
226 
NumCodeUnits()227   ALWAYS_INLINE uint32_t NumCodeUnits() const {
228     return num_code_units_;
229   }
230 
231   const uint32_t num_code_units_ = 0;
232   bool error_state_ = false;
233 };
234 
235 }  // namespace art
236 
237 #endif  // ART_LIBDEXFILE_DEX_DEX_INSTRUCTION_ITERATOR_H_
238