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_CODE_ITEM_ACCESSORS_INL_H_
18 #define ART_LIBDEXFILE_DEX_CODE_ITEM_ACCESSORS_INL_H_
19 
20 #include "code_item_accessors.h"
21 
22 #include "base/iteration_range.h"
23 #include "compact_dex_file.h"
24 #include "dex_file-inl.h"
25 #include "dex_instruction_iterator.h"
26 #include "standard_dex_file.h"
27 
28 // The no ART version is used by binaries that don't include the whole runtime.
29 namespace art {
30 
Init(uint32_t insns_size_in_code_units,const uint16_t * insns)31 inline void CodeItemInstructionAccessor::Init(uint32_t insns_size_in_code_units,
32                                               const uint16_t* insns) {
33   insns_size_in_code_units_ = insns_size_in_code_units;
34   insns_ = insns;
35 }
36 
37 template <>
38 inline void CodeItemInstructionAccessor::Init<CompactDexFile::CodeItem>(
39     const CompactDexFile::CodeItem& code_item) {
40   uint32_t insns_size_in_code_units;
41   code_item.DecodeFields</*kDecodeOnlyInstructionCount*/ true>(
42       &insns_size_in_code_units,
43       /*registers_size*/ nullptr,
44       /*ins_size*/ nullptr,
45       /*outs_size*/ nullptr,
46       /*tries_size*/ nullptr);
47   Init(insns_size_in_code_units, code_item.insns_);
48 }
49 
50 template <>
51 inline void CodeItemInstructionAccessor::Init<StandardDexFile::CodeItem>(
52     const StandardDexFile::CodeItem& code_item) {
53   Init(code_item.insns_size_in_code_units_, code_item.insns_);
54 }
55 
Init(const DexFile & dex_file,const dex::CodeItem * code_item)56 inline void CodeItemInstructionAccessor::Init(const DexFile& dex_file,
57                                               const dex::CodeItem* code_item) {
58   if (code_item != nullptr) {
59     DCHECK(dex_file.IsInDataSection(code_item));
60     if (dex_file.IsCompactDexFile()) {
61       Init(down_cast<const CompactDexFile::CodeItem&>(*code_item));
62     } else {
63       DCHECK(dex_file.IsStandardDexFile());
64       Init(down_cast<const StandardDexFile::CodeItem&>(*code_item));
65     }
66   }
67 }
68 
CodeItemInstructionAccessor(const DexFile & dex_file,const dex::CodeItem * code_item)69 inline CodeItemInstructionAccessor::CodeItemInstructionAccessor(
70     const DexFile& dex_file,
71     const dex::CodeItem* code_item) {
72   Init(dex_file, code_item);
73 }
74 
begin()75 inline DexInstructionIterator CodeItemInstructionAccessor::begin() const {
76   return DexInstructionIterator(insns_, 0u);
77 }
78 
end()79 inline DexInstructionIterator CodeItemInstructionAccessor::end() const {
80   return DexInstructionIterator(insns_, insns_size_in_code_units_);
81 }
82 
InstructionsFrom(uint32_t start_dex_pc)83 inline IterationRange<DexInstructionIterator> CodeItemInstructionAccessor::InstructionsFrom(
84     uint32_t start_dex_pc) const {
85   DCHECK_LT(start_dex_pc, InsnsSizeInCodeUnits());
86   return {
87       DexInstructionIterator(insns_, start_dex_pc),
88       DexInstructionIterator(insns_, insns_size_in_code_units_) };
89 }
90 
91 template <>
92 inline void CodeItemDataAccessor::Init<CompactDexFile::CodeItem>(
93     const CompactDexFile::CodeItem& code_item) {
94   uint32_t insns_size_in_code_units;
95   code_item.DecodeFields</*kDecodeOnlyInstructionCount*/ false>(&insns_size_in_code_units,
96                                                                 &registers_size_,
97                                                                 &ins_size_,
98                                                                 &outs_size_,
99                                                                 &tries_size_);
100   CodeItemInstructionAccessor::Init(insns_size_in_code_units, code_item.insns_);
101 }
102 
103 template <>
104 inline void CodeItemDataAccessor::Init<StandardDexFile::CodeItem>(
105     const StandardDexFile::CodeItem& code_item) {
106   CodeItemInstructionAccessor::Init(code_item);
107   registers_size_ = code_item.registers_size_;
108   ins_size_ = code_item.ins_size_;
109   outs_size_ = code_item.outs_size_;
110   tries_size_ = code_item.tries_size_;
111 }
112 
Init(const DexFile & dex_file,const dex::CodeItem * code_item)113 inline void CodeItemDataAccessor::Init(const DexFile& dex_file,
114                                        const dex::CodeItem* code_item) {
115   if (code_item != nullptr) {
116     if (dex_file.IsCompactDexFile()) {
117       Init(down_cast<const CompactDexFile::CodeItem&>(*code_item));
118     } else {
119       DCHECK(dex_file.IsStandardDexFile());
120       Init(down_cast<const StandardDexFile::CodeItem&>(*code_item));
121     }
122   }
123 }
124 
CodeItemDataAccessor(const DexFile & dex_file,const dex::CodeItem * code_item)125 inline CodeItemDataAccessor::CodeItemDataAccessor(const DexFile& dex_file,
126                                                   const dex::CodeItem* code_item) {
127   Init(dex_file, code_item);
128 }
129 
TryItems()130 inline IterationRange<const dex::TryItem*> CodeItemDataAccessor::TryItems() const {
131   const dex::TryItem* try_items = DexFile::GetTryItems(end(), 0u);
132   return {
133     try_items,
134     try_items + TriesSize() };
135 }
136 
GetCatchHandlerData(size_t offset)137 inline const uint8_t* CodeItemDataAccessor::GetCatchHandlerData(size_t offset) const {
138   return DexFile::GetCatchHandlerData(end(), TriesSize(), offset);
139 }
140 
FindTryItem(uint32_t try_dex_pc)141 inline const dex::TryItem* CodeItemDataAccessor::FindTryItem(uint32_t try_dex_pc) const {
142   IterationRange<const dex::TryItem*> try_items(TryItems());
143   int32_t index = DexFile::FindTryItem(try_items.begin(),
144                                        try_items.end() - try_items.begin(),
145                                        try_dex_pc);
146   return index != -1 ? &try_items.begin()[index] : nullptr;
147 }
148 
CodeItemDataEnd()149 inline const void* CodeItemDataAccessor::CodeItemDataEnd() const {
150   const uint8_t* handler_data = GetCatchHandlerData();
151 
152   if (TriesSize() == 0 || handler_data == nullptr) {
153     return &end().Inst();
154   }
155   // Get the start of the handler data.
156   const uint32_t handlers_size = DecodeUnsignedLeb128(&handler_data);
157   // Manually read each handler.
158   for (uint32_t i = 0; i < handlers_size; ++i) {
159     int32_t uleb128_count = DecodeSignedLeb128(&handler_data) * 2;
160     if (uleb128_count <= 0) {
161       uleb128_count = -uleb128_count + 1;
162     }
163     for (int32_t j = 0; j < uleb128_count; ++j) {
164       DecodeUnsignedLeb128(&handler_data);
165     }
166   }
167   return reinterpret_cast<const void*>(handler_data);
168 }
169 
170 template <>
171 inline void CodeItemDebugInfoAccessor::Init<CompactDexFile::CodeItem>(
172     const CompactDexFile::CodeItem& code_item,
173     uint32_t dex_method_index) {
174   debug_info_offset_ = down_cast<const CompactDexFile*>(dex_file_)->GetDebugInfoOffset(
175       dex_method_index);
176   CodeItemDataAccessor::Init(code_item);
177 }
178 
179 template <>
180 inline void CodeItemDebugInfoAccessor::Init<StandardDexFile::CodeItem>(
181     const StandardDexFile::CodeItem& code_item,
182     uint32_t dex_method_index ATTRIBUTE_UNUSED) {
183   debug_info_offset_ = code_item.debug_info_off_;
184   CodeItemDataAccessor::Init(code_item);
185 }
186 
Init(const DexFile & dex_file,const dex::CodeItem * code_item,uint32_t dex_method_index)187 inline void CodeItemDebugInfoAccessor::Init(const DexFile& dex_file,
188                                             const dex::CodeItem* code_item,
189                                             uint32_t dex_method_index) {
190   if (code_item == nullptr) {
191     return;
192   }
193   dex_file_ = &dex_file;
194   if (dex_file.IsCompactDexFile()) {
195     Init(down_cast<const CompactDexFile::CodeItem&>(*code_item), dex_method_index);
196   } else {
197     DCHECK(dex_file.IsStandardDexFile());
198     Init(down_cast<const StandardDexFile::CodeItem&>(*code_item), dex_method_index);
199   }
200 }
201 
202 template<typename NewLocalVisitor>
DecodeDebugLocalInfo(bool is_static,uint32_t method_idx,const NewLocalVisitor & new_local)203 inline bool CodeItemDebugInfoAccessor::DecodeDebugLocalInfo(
204     bool is_static,
205     uint32_t method_idx,
206     const NewLocalVisitor& new_local) const {
207   return dex_file_->DecodeDebugLocalInfo(RegistersSize(),
208                                          InsSize(),
209                                          InsnsSizeInCodeUnits(),
210                                          DebugInfoOffset(),
211                                          is_static,
212                                          method_idx,
213                                          new_local);
214 }
215 
216 template <typename Visitor>
VisitParameterNames(const Visitor & visitor)217 inline uint32_t CodeItemDebugInfoAccessor::VisitParameterNames(const Visitor& visitor) const {
218   const uint8_t* stream = dex_file_->GetDebugInfoStream(DebugInfoOffset());
219   return (stream != nullptr) ? DexFile::DecodeDebugInfoParameterNames(&stream, visitor) : 0u;
220 }
221 
GetLineNumForPc(const uint32_t address,uint32_t * line_num)222 inline bool CodeItemDebugInfoAccessor::GetLineNumForPc(const uint32_t address,
223                                                        uint32_t* line_num) const {
224   return DecodeDebugPositionInfo([&](const DexFile::PositionInfo& entry) {
225     // We know that this callback will be called in ascending address order, so keep going until we
226     // find a match or we've just gone past it.
227     if (entry.address_ > address) {
228       // The line number from the previous positions callback will be the final result.
229       return true;
230     }
231     *line_num = entry.line_;
232     return entry.address_ == address;
233   });
234 }
235 
236 template <typename Visitor>
DecodeDebugPositionInfo(const Visitor & visitor)237 inline bool CodeItemDebugInfoAccessor::DecodeDebugPositionInfo(const Visitor& visitor) const {
238   return dex_file_->DecodeDebugPositionInfo(
239       dex_file_->GetDebugInfoStream(DebugInfoOffset()),
240       [this](uint32_t idx) {
241         return dex_file_->StringDataByIdx(dex::StringIndex(idx));
242       },
243       visitor);
244 }
245 
246 }  // namespace art
247 
248 #endif  // ART_LIBDEXFILE_DEX_CODE_ITEM_ACCESSORS_INL_H_
249