237 lines
7.0 KiB
C++
237 lines
7.0 KiB
C++
/*
|
|
* 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_
|