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