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