Home | History | Annotate | Download | only in dex
      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:
     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 
     39   ALWAYS_INLINE uint32_t DexPc() const {
     40     return dex_pc_;
     41   }
     42 
     43   ALWAYS_INLINE const uint16_t* Instructions() const {
     44     return instructions_;
     45   }
     46 
     47  protected:
     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;
     67   explicit DexInstructionIteratorBase(const Instruction* inst, uint32_t dex_pc)
     68       : data_(reinterpret_cast<const uint16_t*>(inst), dex_pc) {}
     69 
     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.
     75   ALWAYS_INLINE uint32_t DexPc() const {
     76     return data_.DexPc();
     77   }
     78 
     79   // Instructions from the start of the code item.
     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 
    125   explicit DexInstructionIterator(const uint16_t* inst, uint32_t dex_pc)
    126       : DexInstructionIteratorBase(Instruction::At(inst), dex_pc) {}
    127 
    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.
    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:
    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.
    207   ALWAYS_INLINE const Instruction& Inst() const {
    208     return data_.Inst();
    209   }
    210 
    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.
    217   bool IsErrorState() const {
    218     return error_state_;
    219   }
    220 
    221  private:
    222   ALWAYS_INLINE void AssertValid() const {
    223     DCHECK(!IsErrorState());
    224     DCHECK_LT(DexPc(), NumCodeUnits());
    225   }
    226 
    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