xref: /aosp_15_r20/art/libdexfile/dex/dex_instruction_iterator.h (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker  * Copyright (C) 2017 The Android Open Source Project
3*795d594fSAndroid Build Coastguard Worker  *
4*795d594fSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*795d594fSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*795d594fSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*795d594fSAndroid Build Coastguard Worker  *
8*795d594fSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*795d594fSAndroid Build Coastguard Worker  *
10*795d594fSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*795d594fSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*795d594fSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*795d594fSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*795d594fSAndroid Build Coastguard Worker  * limitations under the License.
15*795d594fSAndroid Build Coastguard Worker  */
16*795d594fSAndroid Build Coastguard Worker 
17*795d594fSAndroid Build Coastguard Worker #ifndef ART_LIBDEXFILE_DEX_DEX_INSTRUCTION_ITERATOR_H_
18*795d594fSAndroid Build Coastguard Worker #define ART_LIBDEXFILE_DEX_DEX_INSTRUCTION_ITERATOR_H_
19*795d594fSAndroid Build Coastguard Worker 
20*795d594fSAndroid Build Coastguard Worker #include <iterator>
21*795d594fSAndroid Build Coastguard Worker 
22*795d594fSAndroid Build Coastguard Worker #include <android-base/logging.h>
23*795d594fSAndroid Build Coastguard Worker 
24*795d594fSAndroid Build Coastguard Worker #include "base/macros.h"
25*795d594fSAndroid Build Coastguard Worker #include "dex_instruction.h"
26*795d594fSAndroid Build Coastguard Worker 
27*795d594fSAndroid Build Coastguard Worker namespace art {
28*795d594fSAndroid Build Coastguard Worker 
29*795d594fSAndroid Build Coastguard Worker class DexInstructionPcPair {
30*795d594fSAndroid Build Coastguard Worker  public:
Inst()31*795d594fSAndroid Build Coastguard Worker   ALWAYS_INLINE const Instruction& Inst() const {
32*795d594fSAndroid Build Coastguard Worker     return *Instruction::At(instructions_ + DexPc());
33*795d594fSAndroid Build Coastguard Worker   }
34*795d594fSAndroid Build Coastguard Worker 
35*795d594fSAndroid Build Coastguard Worker   ALWAYS_INLINE const Instruction* operator->() const {
36*795d594fSAndroid Build Coastguard Worker     return &Inst();
37*795d594fSAndroid Build Coastguard Worker   }
38*795d594fSAndroid Build Coastguard Worker 
DexPc()39*795d594fSAndroid Build Coastguard Worker   ALWAYS_INLINE uint32_t DexPc() const {
40*795d594fSAndroid Build Coastguard Worker     return dex_pc_;
41*795d594fSAndroid Build Coastguard Worker   }
42*795d594fSAndroid Build Coastguard Worker 
Instructions()43*795d594fSAndroid Build Coastguard Worker   ALWAYS_INLINE const uint16_t* Instructions() const {
44*795d594fSAndroid Build Coastguard Worker     return instructions_;
45*795d594fSAndroid Build Coastguard Worker   }
46*795d594fSAndroid Build Coastguard Worker 
47*795d594fSAndroid Build Coastguard Worker  protected:
DexInstructionPcPair(const uint16_t * instructions,uint32_t dex_pc)48*795d594fSAndroid Build Coastguard Worker   explicit DexInstructionPcPair(const uint16_t* instructions, uint32_t dex_pc)
49*795d594fSAndroid Build Coastguard Worker       : instructions_(instructions), dex_pc_(dex_pc) {}
50*795d594fSAndroid Build Coastguard Worker 
51*795d594fSAndroid Build Coastguard Worker   const uint16_t* instructions_ = nullptr;
52*795d594fSAndroid Build Coastguard Worker   uint32_t dex_pc_ = 0;
53*795d594fSAndroid Build Coastguard Worker 
54*795d594fSAndroid Build Coastguard Worker   friend class DexInstructionIteratorBase;
55*795d594fSAndroid Build Coastguard Worker   friend class DexInstructionIterator;
56*795d594fSAndroid Build Coastguard Worker   friend class SafeDexInstructionIterator;
57*795d594fSAndroid Build Coastguard Worker };
58*795d594fSAndroid Build Coastguard Worker 
59*795d594fSAndroid Build Coastguard Worker // Base helper class to prevent duplicated comparators.
60*795d594fSAndroid Build Coastguard Worker class DexInstructionIteratorBase {
61*795d594fSAndroid Build Coastguard Worker  public:
62*795d594fSAndroid Build Coastguard Worker   using iterator_category = std::forward_iterator_tag;
63*795d594fSAndroid Build Coastguard Worker   using value_type = DexInstructionPcPair;
64*795d594fSAndroid Build Coastguard Worker   using difference_type = ptrdiff_t;
65*795d594fSAndroid Build Coastguard Worker   using pointer = void;
66*795d594fSAndroid Build Coastguard Worker   using reference = void;
67*795d594fSAndroid Build Coastguard Worker 
DexInstructionIteratorBase(const Instruction * inst,uint32_t dex_pc)68*795d594fSAndroid Build Coastguard Worker   explicit DexInstructionIteratorBase(const Instruction* inst, uint32_t dex_pc)
69*795d594fSAndroid Build Coastguard Worker       : data_(reinterpret_cast<const uint16_t*>(inst), dex_pc) {}
70*795d594fSAndroid Build Coastguard Worker 
Inst()71*795d594fSAndroid Build Coastguard Worker   const Instruction& Inst() const {
72*795d594fSAndroid Build Coastguard Worker     return data_.Inst();
73*795d594fSAndroid Build Coastguard Worker   }
74*795d594fSAndroid Build Coastguard Worker 
75*795d594fSAndroid Build Coastguard Worker   // Return the dex pc for an iterator compared to the code item begin.
DexPc()76*795d594fSAndroid Build Coastguard Worker   ALWAYS_INLINE uint32_t DexPc() const {
77*795d594fSAndroid Build Coastguard Worker     return data_.DexPc();
78*795d594fSAndroid Build Coastguard Worker   }
79*795d594fSAndroid Build Coastguard Worker 
80*795d594fSAndroid Build Coastguard Worker   // Instructions from the start of the code item.
Instructions()81*795d594fSAndroid Build Coastguard Worker   ALWAYS_INLINE const uint16_t* Instructions() const {
82*795d594fSAndroid Build Coastguard Worker     return data_.Instructions();
83*795d594fSAndroid Build Coastguard Worker   }
84*795d594fSAndroid Build Coastguard Worker 
85*795d594fSAndroid Build Coastguard Worker  protected:
86*795d594fSAndroid Build Coastguard Worker   DexInstructionPcPair data_;
87*795d594fSAndroid Build Coastguard Worker };
88*795d594fSAndroid Build Coastguard Worker 
89*795d594fSAndroid Build Coastguard Worker static ALWAYS_INLINE inline bool operator==(const DexInstructionIteratorBase& lhs,
90*795d594fSAndroid Build Coastguard Worker                                             const DexInstructionIteratorBase& rhs) {
91*795d594fSAndroid Build Coastguard Worker   DCHECK_EQ(lhs.Instructions(), rhs.Instructions()) << "Comparing different code items.";
92*795d594fSAndroid Build Coastguard Worker   return lhs.DexPc() == rhs.DexPc();
93*795d594fSAndroid Build Coastguard Worker }
94*795d594fSAndroid Build Coastguard Worker 
95*795d594fSAndroid Build Coastguard Worker static inline bool operator!=(const DexInstructionIteratorBase& lhs,
96*795d594fSAndroid Build Coastguard Worker                               const DexInstructionIteratorBase& rhs) {
97*795d594fSAndroid Build Coastguard Worker   return !(lhs == rhs);
98*795d594fSAndroid Build Coastguard Worker }
99*795d594fSAndroid Build Coastguard Worker 
100*795d594fSAndroid Build Coastguard Worker static inline bool operator<(const DexInstructionIteratorBase& lhs,
101*795d594fSAndroid Build Coastguard Worker                              const DexInstructionIteratorBase& rhs) {
102*795d594fSAndroid Build Coastguard Worker   DCHECK_EQ(lhs.Instructions(), rhs.Instructions()) << "Comparing different code items.";
103*795d594fSAndroid Build Coastguard Worker   return lhs.DexPc() < rhs.DexPc();
104*795d594fSAndroid Build Coastguard Worker }
105*795d594fSAndroid Build Coastguard Worker 
106*795d594fSAndroid Build Coastguard Worker static inline bool operator>(const DexInstructionIteratorBase& lhs,
107*795d594fSAndroid Build Coastguard Worker                              const DexInstructionIteratorBase& rhs) {
108*795d594fSAndroid Build Coastguard Worker   return rhs < lhs;
109*795d594fSAndroid Build Coastguard Worker }
110*795d594fSAndroid Build Coastguard Worker 
111*795d594fSAndroid Build Coastguard Worker static inline bool operator<=(const DexInstructionIteratorBase& lhs,
112*795d594fSAndroid Build Coastguard Worker                               const DexInstructionIteratorBase& rhs) {
113*795d594fSAndroid Build Coastguard Worker   return !(rhs < lhs);
114*795d594fSAndroid Build Coastguard Worker }
115*795d594fSAndroid Build Coastguard Worker 
116*795d594fSAndroid Build Coastguard Worker static inline bool operator>=(const DexInstructionIteratorBase& lhs,
117*795d594fSAndroid Build Coastguard Worker                               const DexInstructionIteratorBase& rhs) {
118*795d594fSAndroid Build Coastguard Worker   return !(lhs < rhs);
119*795d594fSAndroid Build Coastguard Worker }
120*795d594fSAndroid Build Coastguard Worker 
121*795d594fSAndroid Build Coastguard Worker // A helper class for a code_item's instructions using range based for loop syntax.
122*795d594fSAndroid Build Coastguard Worker class DexInstructionIterator : public DexInstructionIteratorBase {
123*795d594fSAndroid Build Coastguard Worker  public:
124*795d594fSAndroid Build Coastguard Worker   using DexInstructionIteratorBase::DexInstructionIteratorBase;
125*795d594fSAndroid Build Coastguard Worker 
DexInstructionIterator(const uint16_t * inst,uint32_t dex_pc)126*795d594fSAndroid Build Coastguard Worker   explicit DexInstructionIterator(const uint16_t* inst, uint32_t dex_pc)
127*795d594fSAndroid Build Coastguard Worker       : DexInstructionIteratorBase(inst != nullptr ? Instruction::At(inst) : nullptr, dex_pc) {}
128*795d594fSAndroid Build Coastguard Worker 
DexInstructionIterator(const DexInstructionPcPair & pair)129*795d594fSAndroid Build Coastguard Worker   explicit DexInstructionIterator(const DexInstructionPcPair& pair)
130*795d594fSAndroid Build Coastguard Worker       : DexInstructionIterator(pair.Instructions(), pair.DexPc()) {}
131*795d594fSAndroid Build Coastguard Worker 
132*795d594fSAndroid Build Coastguard Worker   // Value after modification.
133*795d594fSAndroid Build Coastguard Worker   DexInstructionIterator& operator++() {
134*795d594fSAndroid Build Coastguard Worker     data_.dex_pc_ += Inst().SizeInCodeUnits();
135*795d594fSAndroid Build Coastguard Worker     return *this;
136*795d594fSAndroid Build Coastguard Worker   }
137*795d594fSAndroid Build Coastguard Worker 
138*795d594fSAndroid Build Coastguard Worker   // Value before modification.
139*795d594fSAndroid Build Coastguard Worker   DexInstructionIterator operator++(int) {
140*795d594fSAndroid Build Coastguard Worker     DexInstructionIterator temp = *this;
141*795d594fSAndroid Build Coastguard Worker     ++*this;
142*795d594fSAndroid Build Coastguard Worker     return temp;
143*795d594fSAndroid Build Coastguard Worker   }
144*795d594fSAndroid Build Coastguard Worker 
145*795d594fSAndroid Build Coastguard Worker   const value_type& operator*() const {
146*795d594fSAndroid Build Coastguard Worker     return data_;
147*795d594fSAndroid Build Coastguard Worker   }
148*795d594fSAndroid Build Coastguard Worker 
149*795d594fSAndroid Build Coastguard Worker   const Instruction* operator->() const {
150*795d594fSAndroid Build Coastguard Worker     return &data_.Inst();
151*795d594fSAndroid Build Coastguard Worker   }
152*795d594fSAndroid Build Coastguard Worker 
153*795d594fSAndroid Build Coastguard Worker   // Return the dex pc for the iterator.
DexPc()154*795d594fSAndroid Build Coastguard Worker   ALWAYS_INLINE uint32_t DexPc() const {
155*795d594fSAndroid Build Coastguard Worker     return data_.DexPc();
156*795d594fSAndroid Build Coastguard Worker   }
157*795d594fSAndroid Build Coastguard Worker };
158*795d594fSAndroid Build Coastguard Worker 
159*795d594fSAndroid Build Coastguard Worker // A safe version of DexInstructionIterator that is guaranteed to not go past the end of the code
160*795d594fSAndroid Build Coastguard Worker // item.
161*795d594fSAndroid Build Coastguard Worker class SafeDexInstructionIterator : public DexInstructionIteratorBase {
162*795d594fSAndroid Build Coastguard Worker  public:
SafeDexInstructionIterator(const DexInstructionIteratorBase & start,const DexInstructionIteratorBase & end)163*795d594fSAndroid Build Coastguard Worker   explicit SafeDexInstructionIterator(const DexInstructionIteratorBase& start,
164*795d594fSAndroid Build Coastguard Worker                                       const DexInstructionIteratorBase& end)
165*795d594fSAndroid Build Coastguard Worker       : DexInstructionIteratorBase(&start.Inst(), start.DexPc())
166*795d594fSAndroid Build Coastguard Worker       , num_code_units_(end.DexPc()) {
167*795d594fSAndroid Build Coastguard Worker     DCHECK_EQ(start.Instructions(), end.Instructions())
168*795d594fSAndroid Build Coastguard Worker         << "start and end must be in the same code item.";
169*795d594fSAndroid Build Coastguard Worker   }
170*795d594fSAndroid Build Coastguard Worker 
171*795d594fSAndroid Build Coastguard Worker   // Value after modification, does not read past the end of the allowed region. May increment past
172*795d594fSAndroid Build Coastguard Worker   // the end of the code item though.
173*795d594fSAndroid Build Coastguard Worker   SafeDexInstructionIterator& operator++() {
174*795d594fSAndroid Build Coastguard Worker     AssertValid();
175*795d594fSAndroid Build Coastguard Worker     const size_t size_code_units = Inst().CodeUnitsRequiredForSizeComputation();
176*795d594fSAndroid Build Coastguard Worker     const size_t available = NumCodeUnits() - DexPc();
177*795d594fSAndroid Build Coastguard Worker     if (UNLIKELY(size_code_units > available)) {
178*795d594fSAndroid Build Coastguard Worker       error_state_ = true;
179*795d594fSAndroid Build Coastguard Worker       return *this;
180*795d594fSAndroid Build Coastguard Worker     }
181*795d594fSAndroid Build Coastguard Worker     const size_t instruction_code_units = Inst().SizeInCodeUnits();
182*795d594fSAndroid Build Coastguard Worker     if (UNLIKELY(instruction_code_units > available)) {
183*795d594fSAndroid Build Coastguard Worker       error_state_ = true;
184*795d594fSAndroid Build Coastguard Worker       return *this;
185*795d594fSAndroid Build Coastguard Worker     }
186*795d594fSAndroid Build Coastguard Worker     data_.dex_pc_ += instruction_code_units;
187*795d594fSAndroid Build Coastguard Worker     return *this;
188*795d594fSAndroid Build Coastguard Worker   }
189*795d594fSAndroid Build Coastguard Worker 
190*795d594fSAndroid Build Coastguard Worker   // Value before modification.
191*795d594fSAndroid Build Coastguard Worker   SafeDexInstructionIterator operator++(int) {
192*795d594fSAndroid Build Coastguard Worker     SafeDexInstructionIterator temp = *this;
193*795d594fSAndroid Build Coastguard Worker     ++*this;
194*795d594fSAndroid Build Coastguard Worker     return temp;
195*795d594fSAndroid Build Coastguard Worker   }
196*795d594fSAndroid Build Coastguard Worker 
197*795d594fSAndroid Build Coastguard Worker   const value_type& operator*() const {
198*795d594fSAndroid Build Coastguard Worker     AssertValid();
199*795d594fSAndroid Build Coastguard Worker     return data_;
200*795d594fSAndroid Build Coastguard Worker   }
201*795d594fSAndroid Build Coastguard Worker 
202*795d594fSAndroid Build Coastguard Worker   const Instruction* operator->() const {
203*795d594fSAndroid Build Coastguard Worker     AssertValid();
204*795d594fSAndroid Build Coastguard Worker     return &data_.Inst();
205*795d594fSAndroid Build Coastguard Worker   }
206*795d594fSAndroid Build Coastguard Worker 
207*795d594fSAndroid Build Coastguard Worker   // Return the current instruction of the iterator.
Inst()208*795d594fSAndroid Build Coastguard Worker   ALWAYS_INLINE const Instruction& Inst() const {
209*795d594fSAndroid Build Coastguard Worker     return data_.Inst();
210*795d594fSAndroid Build Coastguard Worker   }
211*795d594fSAndroid Build Coastguard Worker 
Instructions()212*795d594fSAndroid Build Coastguard Worker   const uint16_t* Instructions() const {
213*795d594fSAndroid Build Coastguard Worker     return data_.Instructions();
214*795d594fSAndroid Build Coastguard Worker   }
215*795d594fSAndroid Build Coastguard Worker 
216*795d594fSAndroid Build Coastguard Worker   // Returns true if the iterator is in an error state. This occurs when an instruction couldn't
217*795d594fSAndroid Build Coastguard Worker   // have its size computed without reading past the end iterator.
IsErrorState()218*795d594fSAndroid Build Coastguard Worker   bool IsErrorState() const {
219*795d594fSAndroid Build Coastguard Worker     return error_state_;
220*795d594fSAndroid Build Coastguard Worker   }
221*795d594fSAndroid Build Coastguard Worker 
222*795d594fSAndroid Build Coastguard Worker  private:
AssertValid()223*795d594fSAndroid Build Coastguard Worker   ALWAYS_INLINE void AssertValid() const {
224*795d594fSAndroid Build Coastguard Worker     DCHECK(!IsErrorState());
225*795d594fSAndroid Build Coastguard Worker     DCHECK_LT(DexPc(), NumCodeUnits());
226*795d594fSAndroid Build Coastguard Worker   }
227*795d594fSAndroid Build Coastguard Worker 
NumCodeUnits()228*795d594fSAndroid Build Coastguard Worker   ALWAYS_INLINE uint32_t NumCodeUnits() const {
229*795d594fSAndroid Build Coastguard Worker     return num_code_units_;
230*795d594fSAndroid Build Coastguard Worker   }
231*795d594fSAndroid Build Coastguard Worker 
232*795d594fSAndroid Build Coastguard Worker   const uint32_t num_code_units_ = 0;
233*795d594fSAndroid Build Coastguard Worker   bool error_state_ = false;
234*795d594fSAndroid Build Coastguard Worker };
235*795d594fSAndroid Build Coastguard Worker 
236*795d594fSAndroid Build Coastguard Worker }  // namespace art
237*795d594fSAndroid Build Coastguard Worker 
238*795d594fSAndroid Build Coastguard Worker #endif  // ART_LIBDEXFILE_DEX_DEX_INSTRUCTION_ITERATOR_H_
239