/* * 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_CODE_ITEM_ACCESSORS_INL_H_ #define ART_LIBDEXFILE_DEX_CODE_ITEM_ACCESSORS_INL_H_ #include "code_item_accessors.h" #include "base/iteration_range.h" #include "compact_dex_file.h" #include "dex_file-inl.h" #include "dex_instruction_iterator.h" #include "standard_dex_file.h" // The no ART version is used by binaries that don't include the whole runtime. namespace art { inline void CodeItemInstructionAccessor::Init(uint32_t insns_size_in_code_units, const uint16_t* insns) { insns_size_in_code_units_ = insns_size_in_code_units; insns_ = insns; } template <> inline void CodeItemInstructionAccessor::Init( const CompactDexFile::CodeItem& code_item) { uint32_t insns_size_in_code_units; code_item.DecodeFields( &insns_size_in_code_units, /*registers_size*/ nullptr, /*ins_size*/ nullptr, /*outs_size*/ nullptr, /*tries_size*/ nullptr); Init(insns_size_in_code_units, code_item.insns_); } template <> inline void CodeItemInstructionAccessor::Init( const StandardDexFile::CodeItem& code_item) { Init(code_item.insns_size_in_code_units_, code_item.insns_); } inline void CodeItemInstructionAccessor::Init(const DexFile& dex_file, const dex::CodeItem* code_item) { if (code_item != nullptr) { DCHECK(dex_file.IsInDataSection(code_item)); if (dex_file.IsCompactDexFile()) { Init(down_cast(*code_item)); } else { DCHECK(dex_file.IsStandardDexFile()); Init(down_cast(*code_item)); } } } inline CodeItemInstructionAccessor::CodeItemInstructionAccessor( const DexFile& dex_file, const dex::CodeItem* code_item) { Init(dex_file, code_item); } inline DexInstructionIterator CodeItemInstructionAccessor::begin() const { return DexInstructionIterator(insns_, 0u); } inline DexInstructionIterator CodeItemInstructionAccessor::end() const { return DexInstructionIterator(insns_, insns_size_in_code_units_); } inline IterationRange CodeItemInstructionAccessor::InstructionsFrom( uint32_t start_dex_pc) const { DCHECK_LT(start_dex_pc, InsnsSizeInCodeUnits()); return { DexInstructionIterator(insns_, start_dex_pc), DexInstructionIterator(insns_, insns_size_in_code_units_) }; } template <> inline void CodeItemDataAccessor::Init( const CompactDexFile::CodeItem& code_item) { uint32_t insns_size_in_code_units; code_item.DecodeFields(&insns_size_in_code_units, ®isters_size_, &ins_size_, &outs_size_, &tries_size_); CodeItemInstructionAccessor::Init(insns_size_in_code_units, code_item.insns_); } template <> inline void CodeItemDataAccessor::Init( const StandardDexFile::CodeItem& code_item) { CodeItemInstructionAccessor::Init(code_item); registers_size_ = code_item.registers_size_; ins_size_ = code_item.ins_size_; outs_size_ = code_item.outs_size_; tries_size_ = code_item.tries_size_; } inline void CodeItemDataAccessor::Init(const DexFile& dex_file, const dex::CodeItem* code_item) { if (code_item != nullptr) { if (dex_file.IsCompactDexFile()) { Init(down_cast(*code_item)); } else { DCHECK(dex_file.IsStandardDexFile()); Init(down_cast(*code_item)); } } } inline CodeItemDataAccessor::CodeItemDataAccessor(const DexFile& dex_file, const dex::CodeItem* code_item) { Init(dex_file, code_item); } inline IterationRange CodeItemDataAccessor::TryItems() const { const dex::TryItem* try_items = DexFile::GetTryItems(end(), 0u); return { try_items, try_items + TriesSize() }; } inline const uint8_t* CodeItemDataAccessor::GetCatchHandlerData(size_t offset) const { return DexFile::GetCatchHandlerData(end(), TriesSize(), offset); } inline const dex::TryItem* CodeItemDataAccessor::FindTryItem(uint32_t try_dex_pc) const { IterationRange try_items(TryItems()); int32_t index = DexFile::FindTryItem(try_items.begin(), try_items.end() - try_items.begin(), try_dex_pc); return index != -1 ? &try_items.begin()[index] : nullptr; } inline const void* CodeItemDataAccessor::CodeItemDataEnd() const { const uint8_t* handler_data = GetCatchHandlerData(); if (TriesSize() == 0 || handler_data == nullptr) { return &end().Inst(); } // Get the start of the handler data. const uint32_t handlers_size = DecodeUnsignedLeb128(&handler_data); // Manually read each handler. for (uint32_t i = 0; i < handlers_size; ++i) { int32_t uleb128_count = DecodeSignedLeb128(&handler_data) * 2; if (uleb128_count <= 0) { uleb128_count = -uleb128_count + 1; } for (int32_t j = 0; j < uleb128_count; ++j) { DecodeUnsignedLeb128(&handler_data); } } return reinterpret_cast(handler_data); } template <> inline void CodeItemDebugInfoAccessor::Init( const CompactDexFile::CodeItem& code_item, uint32_t dex_method_index) { debug_info_offset_ = down_cast(dex_file_)->GetDebugInfoOffset( dex_method_index); CodeItemDataAccessor::Init(code_item); } template <> inline void CodeItemDebugInfoAccessor::Init( const StandardDexFile::CodeItem& code_item, uint32_t dex_method_index ATTRIBUTE_UNUSED) { debug_info_offset_ = code_item.debug_info_off_; CodeItemDataAccessor::Init(code_item); } inline void CodeItemDebugInfoAccessor::Init(const DexFile& dex_file, const dex::CodeItem* code_item, uint32_t dex_method_index) { if (code_item == nullptr) { return; } dex_file_ = &dex_file; if (dex_file.IsCompactDexFile()) { Init(down_cast(*code_item), dex_method_index); } else { DCHECK(dex_file.IsStandardDexFile()); Init(down_cast(*code_item), dex_method_index); } } template inline bool CodeItemDebugInfoAccessor::DecodeDebugLocalInfo( bool is_static, uint32_t method_idx, const NewLocalVisitor& new_local) const { return dex_file_->DecodeDebugLocalInfo(RegistersSize(), InsSize(), InsnsSizeInCodeUnits(), DebugInfoOffset(), is_static, method_idx, new_local); } template inline uint32_t CodeItemDebugInfoAccessor::VisitParameterNames(const Visitor& visitor) const { const uint8_t* stream = dex_file_->GetDebugInfoStream(DebugInfoOffset()); return (stream != nullptr) ? DexFile::DecodeDebugInfoParameterNames(&stream, visitor) : 0u; } inline bool CodeItemDebugInfoAccessor::GetLineNumForPc(const uint32_t address, uint32_t* line_num) const { return DecodeDebugPositionInfo([&](const DexFile::PositionInfo& entry) { // We know that this callback will be called in ascending address order, so keep going until we // find a match or we've just gone past it. if (entry.address_ > address) { // The line number from the previous positions callback will be the final result. return true; } *line_num = entry.line_; return entry.address_ == address; }); } template inline bool CodeItemDebugInfoAccessor::DecodeDebugPositionInfo(const Visitor& visitor) const { return dex_file_->DecodeDebugPositionInfo( dex_file_->GetDebugInfoStream(DebugInfoOffset()), [this](uint32_t idx) { return dex_file_->StringDataByIdx(dex::StringIndex(idx)); }, visitor); } } // namespace art #endif // ART_LIBDEXFILE_DEX_CODE_ITEM_ACCESSORS_INL_H_