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