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