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