| /* |
| * 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<CompactDexFile::CodeItem>( |
| const CompactDexFile::CodeItem& code_item) { |
| uint32_t insns_size_in_code_units; |
| code_item.DecodeFields</*kDecodeOnlyInstructionCount*/ true>( |
| &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<StandardDexFile::CodeItem>( |
| 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<const CompactDexFile::CodeItem&>(*code_item)); |
| } else { |
| DCHECK(dex_file.IsStandardDexFile()); |
| Init(down_cast<const StandardDexFile::CodeItem&>(*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<DexInstructionIterator> 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<CompactDexFile::CodeItem>( |
| const CompactDexFile::CodeItem& code_item) { |
| uint32_t insns_size_in_code_units; |
| code_item.DecodeFields</*kDecodeOnlyInstructionCount*/ false>(&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<StandardDexFile::CodeItem>( |
| 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<const CompactDexFile::CodeItem&>(*code_item)); |
| } else { |
| DCHECK(dex_file.IsStandardDexFile()); |
| Init(down_cast<const StandardDexFile::CodeItem&>(*code_item)); |
| } |
| } |
| } |
| |
| inline CodeItemDataAccessor::CodeItemDataAccessor(const DexFile& dex_file, |
| const dex::CodeItem* code_item) { |
| Init(dex_file, code_item); |
| } |
| |
| inline IterationRange<const dex::TryItem*> 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<const dex::TryItem*> 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<const void*>(handler_data); |
| } |
| |
| template <> |
| inline void CodeItemDebugInfoAccessor::Init<CompactDexFile::CodeItem>( |
| const CompactDexFile::CodeItem& code_item, |
| uint32_t dex_method_index) { |
| debug_info_offset_ = down_cast<const CompactDexFile*>(dex_file_)->GetDebugInfoOffset( |
| dex_method_index); |
| CodeItemDataAccessor::Init(code_item); |
| } |
| |
| template <> |
| inline void CodeItemDebugInfoAccessor::Init<StandardDexFile::CodeItem>( |
| const StandardDexFile::CodeItem& code_item, [[maybe_unused]] uint32_t dex_method_index) { |
| 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) { |
| dex_file_ = &dex_file; |
| if (code_item == nullptr) { |
| return; |
| } |
| if (dex_file.IsCompactDexFile()) { |
| Init(down_cast<const CompactDexFile::CodeItem&>(*code_item), dex_method_index); |
| } else { |
| DCHECK(dex_file.IsStandardDexFile()); |
| Init(down_cast<const StandardDexFile::CodeItem&>(*code_item), dex_method_index); |
| } |
| } |
| |
| template<typename NewLocalVisitor> |
| inline bool CodeItemDebugInfoAccessor::DecodeDebugLocalInfo( |
| bool is_static, |
| uint32_t method_idx, |
| NewLocalVisitor&& new_local) const { |
| return dex_file_->DecodeDebugLocalInfo(RegistersSize(), |
| InsSize(), |
| InsnsSizeInCodeUnits(), |
| DebugInfoOffset(), |
| is_static, |
| method_idx, |
| std::forward<NewLocalVisitor>(new_local)); |
| } |
| |
| template <typename Visitor> |
| inline uint32_t CodeItemDebugInfoAccessor::VisitParameterNames(Visitor&& visitor) const { |
| const uint8_t* stream = dex_file_->GetDebugInfoStream(DebugInfoOffset()); |
| return (stream != nullptr) ? |
| DexFile::DecodeDebugInfoParameterNames(&stream, std::forward<Visitor>(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 <typename Visitor> |
| inline bool CodeItemDebugInfoAccessor::DecodeDebugPositionInfo(Visitor&& visitor) const { |
| return dex_file_->DecodeDebugPositionInfo( |
| dex_file_->GetDebugInfoStream(DebugInfoOffset()), |
| [this](uint32_t idx) { |
| return dex_file_->StringDataByIdx(dex::StringIndex(idx)); |
| }, |
| std::forward<Visitor>(visitor)); |
| } |
| |
| } // namespace art |
| |
| #endif // ART_LIBDEXFILE_DEX_CODE_ITEM_ACCESSORS_INL_H_ |