1 /*
2  * Copyright (C) 2011 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 #include "dex_file.h"
18 
19 #include <limits.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <zlib.h>
24 
25 #include <memory>
26 #include <optional>
27 #include <ostream>
28 #include <sstream>
29 #include <type_traits>
30 
31 #include "android-base/stringprintf.h"
32 #include "base/hiddenapi_domain.h"
33 #include "base/leb128.h"
34 #include "base/pointer_size.h"
35 #include "base/stl_util.h"
36 #include "class_accessor-inl.h"
37 #include "compact_dex_file.h"
38 #include "descriptors_names.h"
39 #include "dex_file-inl.h"
40 #include "standard_dex_file.h"
41 #include "utf-inl.h"
42 
43 namespace art {
44 
45 using android::base::StringPrintf;
46 
47 using dex::CallSiteIdItem;
48 using dex::ClassDef;
49 using dex::FieldId;
50 using dex::MapList;
51 using dex::MapItem;
52 using dex::MethodHandleItem;
53 using dex::MethodId;
54 using dex::ProtoId;
55 using dex::StringId;
56 using dex::TryItem;
57 using dex::TypeId;
58 using dex::TypeList;
59 
60 static_assert(sizeof(dex::StringIndex) == sizeof(uint32_t), "StringIndex size is wrong");
61 static_assert(std::is_trivially_copyable<dex::StringIndex>::value, "StringIndex not trivial");
62 static_assert(sizeof(dex::TypeIndex) == sizeof(uint16_t), "TypeIndex size is wrong");
63 static_assert(std::is_trivially_copyable<dex::TypeIndex>::value, "TypeIndex not trivial");
64 
65 // Print the SHA1 as 20-byte hexadecimal string.
ToString() const66 std::string DexFile::Sha1::ToString() const {
67   auto data = this->data();
68   auto part = [d = data](int i) { return d[i] << 24 | d[i + 1] << 16 | d[i + 2] << 8 | d[i + 3]; };
69   return StringPrintf("%08x%08x%08x%08x%08x", part(0), part(4), part(8), part(12), part(16));
70 }
71 
CalculateChecksum() const72 uint32_t DexFile::CalculateChecksum() const {
73   return CalculateChecksum(Begin(), Size());
74 }
75 
CalculateChecksum(const uint8_t * begin,size_t size)76 uint32_t DexFile::CalculateChecksum(const uint8_t* begin, size_t size) {
77   const uint32_t non_sum_bytes = OFFSETOF_MEMBER(DexFile::Header, signature_);
78   return ChecksumMemoryRange(begin + non_sum_bytes, size - non_sum_bytes);
79 }
80 
ChecksumMemoryRange(const uint8_t * begin,size_t size)81 uint32_t DexFile::ChecksumMemoryRange(const uint8_t* begin, size_t size) {
82   return adler32(adler32(0L, Z_NULL, 0), begin, size);
83 }
84 
IsReadOnly() const85 bool DexFile::IsReadOnly() const {
86   CHECK(container_.get() != nullptr);
87   return container_->IsReadOnly();
88 }
89 
EnableWrite() const90 bool DexFile::EnableWrite() const {
91   CHECK(container_.get() != nullptr);
92   return container_->EnableWrite();
93 }
94 
DisableWrite() const95 bool DexFile::DisableWrite() const {
96   CHECK(container_.get() != nullptr);
97   return container_->DisableWrite();
98 }
99 
GetExpectedHeaderSize() const100 uint32_t DexFile::Header::GetExpectedHeaderSize() const {
101   uint32_t version = GetVersion();
102   return version == 0 ? 0 : version < 41 ? sizeof(Header) : sizeof(HeaderV41);
103 }
104 
HasDexContainer() const105 bool DexFile::Header::HasDexContainer() const {
106   if (CompactDexFile::IsMagicValid(magic_.data())) {
107     return false;
108   }
109   DCHECK_EQ(header_size_, GetExpectedHeaderSize());
110   return header_size_ >= sizeof(HeaderV41);
111 }
112 
HeaderOffset() const113 uint32_t DexFile::Header::HeaderOffset() const {
114   return HasDexContainer() ? reinterpret_cast<const HeaderV41*>(this)->header_offset_ : 0;
115 }
116 
ContainerSize() const117 uint32_t DexFile::Header::ContainerSize() const {
118   return HasDexContainer() ? reinterpret_cast<const HeaderV41*>(this)->container_size_ : file_size_;
119 }
120 
SetDexContainer(size_t header_offset,size_t container_size)121 void DexFile::Header::SetDexContainer(size_t header_offset, size_t container_size) {
122   if (HasDexContainer()) {
123     DCHECK_LE(header_offset, container_size);
124     DCHECK_LE(file_size_, container_size - header_offset);
125     data_off_ = 0;
126     data_size_ = 0;
127     auto* headerV41 = reinterpret_cast<HeaderV41*>(this);
128     DCHECK_GE(header_size_, sizeof(*headerV41));
129     headerV41->header_offset_ = header_offset;
130     headerV41->container_size_ = container_size;
131   } else {
132     DCHECK_EQ(header_offset, 0u);
133     DCHECK_EQ(container_size, file_size_);
134   }
135 }
136 
137 template <typename T>
GetSection(const uint32_t * offset,DexFileContainer * container)138 ALWAYS_INLINE const T* DexFile::GetSection(const uint32_t* offset, DexFileContainer* container) {
139   size_t size = container->End() - begin_;
140   if (size < sizeof(Header)) {
141     return nullptr;  // Invalid dex file.
142   }
143   // Compact dex is inconsistent: section offsets are relative to the
144   // header as opposed to the data section like all other its offsets.
145   if (CompactDexFile::IsMagicValid(begin_)) {
146     const uint8_t* data = reinterpret_cast<const uint8_t*>(header_);
147     return reinterpret_cast<const T*>(data + *offset);
148   }
149   return reinterpret_cast<const T*>(data_.data() + *offset);
150 }
151 
DexFile(const uint8_t * base,const std::string & location,uint32_t location_checksum,const OatDexFile * oat_dex_file,std::shared_ptr<DexFileContainer> container,bool is_compact_dex)152 DexFile::DexFile(const uint8_t* base,
153                  const std::string& location,
154                  uint32_t location_checksum,
155                  const OatDexFile* oat_dex_file,
156                  std::shared_ptr<DexFileContainer> container,
157                  bool is_compact_dex)
158     : begin_(base),
159       data_(GetDataRange(base, container.get())),
160       location_(location),
161       location_checksum_(location_checksum),
162       header_(reinterpret_cast<const Header*>(base)),
163       string_ids_(GetSection<StringId>(&header_->string_ids_off_, container.get())),
164       type_ids_(GetSection<TypeId>(&header_->type_ids_off_, container.get())),
165       field_ids_(GetSection<FieldId>(&header_->field_ids_off_, container.get())),
166       method_ids_(GetSection<MethodId>(&header_->method_ids_off_, container.get())),
167       proto_ids_(GetSection<ProtoId>(&header_->proto_ids_off_, container.get())),
168       class_defs_(GetSection<ClassDef>(&header_->class_defs_off_, container.get())),
169       method_handles_(nullptr),
170       num_method_handles_(0),
171       call_site_ids_(nullptr),
172       num_call_site_ids_(0),
173       hiddenapi_class_data_(nullptr),
174       oat_dex_file_(oat_dex_file),
175       container_(std::move(container)),
176       is_compact_dex_(is_compact_dex),
177       hiddenapi_domain_(hiddenapi::Domain::kApplication) {
178   CHECK(begin_ != nullptr) << GetLocation();
179   // Check base (=header) alignment.
180   // Must be 4-byte aligned to avoid undefined behavior when accessing
181   // any of the sections via a pointer.
182   CHECK_ALIGNED(begin_, alignof(Header));
183 
184   if (DataSize() < sizeof(Header)) {
185     // Don't go further if the data doesn't even contain a header.
186     return;
187   }
188 
189   InitializeSectionsFromMapList();
190 }
191 
~DexFile()192 DexFile::~DexFile() {
193   // We don't call DeleteGlobalRef on dex_object_ because we're only called by DestroyJavaVM, and
194   // that's only called after DetachCurrentThread, which means there's no JNIEnv. We could
195   // re-attach, but cleaning up these global references is not obviously useful. It's not as if
196   // the global reference table is otherwise empty!
197 }
198 
Init(std::string * error_msg)199 bool DexFile::Init(std::string* error_msg) {
200   CHECK_GE(container_->End(), reinterpret_cast<const uint8_t*>(header_));
201   size_t container_size = container_->End() - reinterpret_cast<const uint8_t*>(header_);
202   if (container_size < sizeof(Header)) {
203     *error_msg = StringPrintf("Unable to open '%s' : File size is too small to fit dex header",
204                               location_.c_str());
205     return false;
206   }
207   if (!CheckMagicAndVersion(error_msg)) {
208     return false;
209   }
210   if (!IsCompactDexFile()) {
211     uint32_t expected_header_size = header_->GetExpectedHeaderSize();
212     if (header_->header_size_ != expected_header_size) {
213       *error_msg = StringPrintf("Unable to open '%s' : Header size is %u but %u was expected",
214                                 location_.c_str(),
215                                 header_->header_size_,
216                                 expected_header_size);
217       return false;
218     }
219   }
220   if (container_size < header_->file_size_) {
221     *error_msg = StringPrintf("Unable to open '%s' : File size is %zu but the header expects %u",
222                               location_.c_str(),
223                               container_size,
224                               header_->file_size_);
225     return false;
226   }
227   return true;
228 }
229 
CheckMagicAndVersion(std::string * error_msg) const230 bool DexFile::CheckMagicAndVersion(std::string* error_msg) const {
231   if (!IsMagicValid()) {
232     std::ostringstream oss;
233     oss << "Unrecognized magic number in "  << GetLocation() << ":"
234             << " " << header_->magic_[0]
235             << " " << header_->magic_[1]
236             << " " << header_->magic_[2]
237             << " " << header_->magic_[3];
238     *error_msg = oss.str();
239     return false;
240   }
241   if (!IsVersionValid()) {
242     std::ostringstream oss;
243     oss << "Unrecognized version number in "  << GetLocation() << ":"
244             << " " << header_->magic_[4]
245             << " " << header_->magic_[5]
246             << " " << header_->magic_[6]
247             << " " << header_->magic_[7];
248     *error_msg = oss.str();
249     return false;
250   }
251   return true;
252 }
253 
GetDataRange(const uint8_t * data,DexFileContainer * container)254 ArrayRef<const uint8_t> DexFile::GetDataRange(const uint8_t* data, DexFileContainer* container) {
255   // NB: This function must survive random data to pass fuzzing and testing.
256   CHECK(container != nullptr);
257   CHECK_GE(data, container->Begin());
258   CHECK_LE(data, container->End());
259   size_t size = container->End() - data;
260   if (size >= sizeof(StandardDexFile::Header) && StandardDexFile::IsMagicValid(data)) {
261     auto header = reinterpret_cast<const DexFile::Header*>(data);
262     CHECK_EQ(container->Data().size(), 0u) << "Unsupported for standard dex";
263     if (size >= sizeof(HeaderV41) && header->header_size_ >= sizeof(HeaderV41)) {
264       auto headerV41 = reinterpret_cast<const DexFile::HeaderV41*>(data);
265       data -= headerV41->header_offset_;  // Allow underflow and later overflow.
266       size = headerV41->container_size_;
267     } else {
268       size = header->file_size_;
269     }
270   } else if (size >= sizeof(CompactDexFile::Header) && CompactDexFile::IsMagicValid(data)) {
271     auto header = reinterpret_cast<const CompactDexFile::Header*>(data);
272     // TODO: Remove. This is a hack. See comment of the Data method.
273     ArrayRef<const uint8_t> separate_data = container->Data();
274     if (separate_data.size() > 0) {
275       return separate_data;
276     }
277     // Shared compact dex data is located at the end after all dex files.
278     data += std::min<size_t>(header->data_off_, size);
279     size = header->data_size_;
280   }
281   // The returned range is guaranteed to be in bounds of the container memory.
282   return {data, std::min<size_t>(size, container->End() - data)};
283 }
284 
InitializeSectionsFromMapList()285 void DexFile::InitializeSectionsFromMapList() {
286   // NB: This function must survive random data to pass fuzzing and testing.
287   static_assert(sizeof(MapList) <= sizeof(Header));
288   DCHECK_GE(DataSize(), sizeof(MapList));
289   if (header_->map_off_ == 0 || header_->map_off_ > DataSize() - sizeof(MapList)) {
290     // Bad offset. The dex file verifier runs after this method and will reject the file.
291     return;
292   }
293   const uint8_t* map_list_raw = DataBegin() + header_->map_off_;
294   if (map_list_raw < Begin()) {
295     return;
296   }
297   const MapList* map_list = reinterpret_cast<const MapList*>(map_list_raw);
298   const size_t count = map_list->size_;
299 
300   size_t map_limit =
301       (DataSize() - OFFSETOF_MEMBER(MapList, list_) - header_->map_off_) / sizeof(MapItem);
302   if (count > map_limit) {
303     // Too many items. The dex file verifier runs after
304     // this method and will reject the file as it is malformed.
305     return;
306   }
307 
308   // Construct pointers to certain arrays without any checks. If they are outside the
309   // data, the dex file verification should fail and these pointers should not be used.
310   for (size_t i = 0; i < count; ++i) {
311     const MapItem& map_item = map_list->list_[i];
312     if (map_item.type_ == kDexTypeMethodHandleItem) {
313       method_handles_ = GetSection<MethodHandleItem>(&map_item.offset_, container_.get());
314       num_method_handles_ = map_item.size_;
315     } else if (map_item.type_ == kDexTypeCallSiteIdItem) {
316       call_site_ids_ = GetSection<CallSiteIdItem>(&map_item.offset_, container_.get());
317       num_call_site_ids_ = map_item.size_;
318     } else if (map_item.type_ == kDexTypeHiddenapiClassData) {
319       hiddenapi_class_data_ =
320           reinterpret_cast<const dex::HiddenapiClassData*>(DataBegin() + map_item.offset_);
321     } else {
322       // Pointers to other sections are not necessary to retain in the DexFile struct.
323       // Other items have pointers directly into their data.
324     }
325   }
326 }
327 
GetVersion() const328 uint32_t DexFile::Header::GetVersion() const {
329   const char* version = reinterpret_cast<const char*>(&magic_[kDexMagicSize]);
330   return atoi(version);
331 }
332 
FindClassDef(dex::TypeIndex type_idx) const333 const ClassDef* DexFile::FindClassDef(dex::TypeIndex type_idx) const {
334   size_t num_class_defs = NumClassDefs();
335   // Fast path for rare no class defs case.
336   if (num_class_defs == 0) {
337     return nullptr;
338   }
339   for (size_t i = 0; i < num_class_defs; ++i) {
340     const ClassDef& class_def = GetClassDef(i);
341     if (class_def.class_idx_ == type_idx) {
342       return &class_def;
343     }
344   }
345   return nullptr;
346 }
347 
GetCodeItemOffset(const ClassDef & class_def,uint32_t method_idx) const348 std::optional<uint32_t> DexFile::GetCodeItemOffset(const ClassDef &class_def,
349                                                    uint32_t method_idx) const {
350   ClassAccessor accessor(*this, class_def);
351   CHECK(accessor.HasClassData());
352   for (const ClassAccessor::Method &method : accessor.GetMethods()) {
353     if (method.GetIndex() == method_idx) {
354       return method.GetCodeItemOffset();
355     }
356   }
357   return std::nullopt;
358 }
359 
FindCodeItemOffset(const dex::ClassDef & class_def,uint32_t dex_method_idx) const360 uint32_t DexFile::FindCodeItemOffset(const dex::ClassDef &class_def,
361                                      uint32_t dex_method_idx) const {
362   std::optional<uint32_t> val = GetCodeItemOffset(class_def, dex_method_idx);
363   CHECK(val.has_value()) << "Unable to find method " << dex_method_idx;
364   return *val;
365 }
366 
FindFieldId(const TypeId & declaring_klass,const StringId & name,const TypeId & type) const367 const FieldId* DexFile::FindFieldId(const TypeId& declaring_klass,
368                                     const StringId& name,
369                                     const TypeId& type) const {
370   // Binary search MethodIds knowing that they are sorted by class_idx, name_idx then proto_idx
371   const dex::TypeIndex class_idx = GetIndexForTypeId(declaring_klass);
372   const dex::StringIndex name_idx = GetIndexForStringId(name);
373   const dex::TypeIndex type_idx = GetIndexForTypeId(type);
374   int32_t lo = 0;
375   int32_t hi = NumFieldIds() - 1;
376   while (hi >= lo) {
377     int32_t mid = (hi + lo) / 2;
378     const FieldId& field = GetFieldId(mid);
379     if (class_idx > field.class_idx_) {
380       lo = mid + 1;
381     } else if (class_idx < field.class_idx_) {
382       hi = mid - 1;
383     } else {
384       if (name_idx > field.name_idx_) {
385         lo = mid + 1;
386       } else if (name_idx < field.name_idx_) {
387         hi = mid - 1;
388       } else {
389         if (type_idx > field.type_idx_) {
390           lo = mid + 1;
391         } else if (type_idx < field.type_idx_) {
392           hi = mid - 1;
393         } else {
394           return &field;
395         }
396       }
397     }
398   }
399   return nullptr;
400 }
401 
FindMethodId(const TypeId & declaring_klass,const StringId & name,const ProtoId & signature) const402 const MethodId* DexFile::FindMethodId(const TypeId& declaring_klass,
403                                       const StringId& name,
404                                       const ProtoId& signature) const {
405   // Binary search MethodIds knowing that they are sorted by class_idx, name_idx then proto_idx
406   const dex::TypeIndex class_idx = GetIndexForTypeId(declaring_klass);
407   const dex::StringIndex name_idx = GetIndexForStringId(name);
408   const dex::ProtoIndex proto_idx = GetIndexForProtoId(signature);
409   return FindMethodIdByIndex(class_idx, name_idx, proto_idx);
410 }
411 
FindMethodIdByIndex(dex::TypeIndex class_idx,dex::StringIndex name_idx,dex::ProtoIndex proto_idx) const412 const MethodId* DexFile::FindMethodIdByIndex(dex::TypeIndex class_idx,
413                                              dex::StringIndex name_idx,
414                                              dex::ProtoIndex proto_idx) const {
415   // Binary search MethodIds knowing that they are sorted by class_idx, name_idx then proto_idx
416   int32_t lo = 0;
417   int32_t hi = NumMethodIds() - 1;
418   while (hi >= lo) {
419     int32_t mid = (hi + lo) / 2;
420     const MethodId& method = GetMethodId(mid);
421     if (class_idx > method.class_idx_) {
422       lo = mid + 1;
423     } else if (class_idx < method.class_idx_) {
424       hi = mid - 1;
425     } else {
426       if (name_idx > method.name_idx_) {
427         lo = mid + 1;
428       } else if (name_idx < method.name_idx_) {
429         hi = mid - 1;
430       } else {
431         if (proto_idx > method.proto_idx_) {
432           lo = mid + 1;
433         } else if (proto_idx < method.proto_idx_) {
434           hi = mid - 1;
435         } else {
436           DCHECK_EQ(class_idx, method.class_idx_);
437           DCHECK_EQ(proto_idx, method.proto_idx_);
438           DCHECK_EQ(name_idx, method.name_idx_);
439           return &method;
440         }
441       }
442     }
443   }
444   return nullptr;
445 }
446 
FindStringId(const char * string) const447 const StringId* DexFile::FindStringId(const char* string) const {
448   int32_t lo = 0;
449   int32_t hi = NumStringIds() - 1;
450   while (hi >= lo) {
451     int32_t mid = (hi + lo) / 2;
452     const StringId& str_id = GetStringId(dex::StringIndex(mid));
453     const char* str = GetStringData(str_id);
454     int compare = CompareModifiedUtf8ToModifiedUtf8AsUtf16CodePointValues(string, str);
455     if (compare > 0) {
456       lo = mid + 1;
457     } else if (compare < 0) {
458       hi = mid - 1;
459     } else {
460       return &str_id;
461     }
462   }
463   return nullptr;
464 }
465 
FindTypeId(std::string_view descriptor) const466 const TypeId* DexFile::FindTypeId(std::string_view descriptor) const {
467   int32_t lo = 0;
468   int32_t hi = NumTypeIds() - 1;
469   while (hi >= lo) {
470     int32_t mid = (hi + lo) / 2;
471     const TypeId& type_id = GetTypeId(dex::TypeIndex(mid));
472     std::string_view mid_descriptor = GetTypeDescriptorView(type_id);
473     int compare = CompareDescriptors(descriptor, mid_descriptor);
474     if (compare > 0) {
475       lo = mid + 1;
476     } else if (compare < 0) {
477       hi = mid - 1;
478     } else {
479       return &type_id;
480     }
481   }
482   return nullptr;
483 }
484 
FindTypeId(dex::StringIndex string_idx) const485 const TypeId* DexFile::FindTypeId(dex::StringIndex string_idx) const {
486   int32_t lo = 0;
487   int32_t hi = NumTypeIds() - 1;
488   while (hi >= lo) {
489     int32_t mid = (hi + lo) / 2;
490     const TypeId& type_id = GetTypeId(dex::TypeIndex(mid));
491     if (string_idx > type_id.descriptor_idx_) {
492       lo = mid + 1;
493     } else if (string_idx < type_id.descriptor_idx_) {
494       hi = mid - 1;
495     } else {
496       return &type_id;
497     }
498   }
499   return nullptr;
500 }
501 
FindProtoId(dex::TypeIndex return_type_idx,const dex::TypeIndex * signature_type_idxs,uint32_t signature_length) const502 const ProtoId* DexFile::FindProtoId(dex::TypeIndex return_type_idx,
503                                     const dex::TypeIndex* signature_type_idxs,
504                                     uint32_t signature_length) const {
505   int32_t lo = 0;
506   int32_t hi = NumProtoIds() - 1;
507   while (hi >= lo) {
508     int32_t mid = (hi + lo) / 2;
509     const dex::ProtoIndex proto_idx = static_cast<dex::ProtoIndex>(mid);
510     const ProtoId& proto = GetProtoId(proto_idx);
511     int compare = return_type_idx.index_ - proto.return_type_idx_.index_;
512     if (compare == 0) {
513       DexFileParameterIterator it(*this, proto);
514       size_t i = 0;
515       while (it.HasNext() && i < signature_length && compare == 0) {
516         compare = signature_type_idxs[i].index_ - it.GetTypeIdx().index_;
517         it.Next();
518         i++;
519       }
520       if (compare == 0) {
521         if (it.HasNext()) {
522           compare = -1;
523         } else if (i < signature_length) {
524           compare = 1;
525         }
526       }
527     }
528     if (compare > 0) {
529       lo = mid + 1;
530     } else if (compare < 0) {
531       hi = mid - 1;
532     } else {
533       return &proto;
534     }
535   }
536   return nullptr;
537 }
538 
539 // Given a signature place the type ids into the given vector
CreateTypeList(std::string_view signature,dex::TypeIndex * return_type_idx,std::vector<dex::TypeIndex> * param_type_idxs) const540 bool DexFile::CreateTypeList(std::string_view signature,
541                              dex::TypeIndex* return_type_idx,
542                              std::vector<dex::TypeIndex>* param_type_idxs) const {
543   if (signature[0] != '(') {
544     return false;
545   }
546   size_t offset = 1;
547   size_t end = signature.size();
548   bool process_return = false;
549   while (offset < end) {
550     size_t start_offset = offset;
551     char c = signature[offset];
552     offset++;
553     if (c == ')') {
554       process_return = true;
555       continue;
556     }
557     while (c == '[') {  // process array prefix
558       if (offset >= end) {  // expect some descriptor following [
559         return false;
560       }
561       c = signature[offset];
562       offset++;
563     }
564     if (c == 'L') {  // process type descriptors
565       do {
566         if (offset >= end) {  // unexpected early termination of descriptor
567           return false;
568         }
569         c = signature[offset];
570         offset++;
571       } while (c != ';');
572     }
573     std::string_view descriptor(signature.data() + start_offset, offset - start_offset);
574     const TypeId* type_id = FindTypeId(descriptor);
575     if (type_id == nullptr) {
576       return false;
577     }
578     dex::TypeIndex type_idx = GetIndexForTypeId(*type_id);
579     if (!process_return) {
580       param_type_idxs->push_back(type_idx);
581     } else {
582       *return_type_idx = type_idx;
583       return offset == end;  // return true if the signature had reached a sensible end
584     }
585   }
586   return false;  // failed to correctly parse return type
587 }
588 
FindTryItem(const TryItem * try_items,uint32_t tries_size,uint32_t address)589 int32_t DexFile::FindTryItem(const TryItem* try_items, uint32_t tries_size, uint32_t address) {
590   uint32_t min = 0;
591   uint32_t max = tries_size;
592   while (min < max) {
593     const uint32_t mid = (min + max) / 2;
594 
595     const TryItem& ti = try_items[mid];
596     const uint32_t start = ti.start_addr_;
597     const uint32_t end = start + ti.insn_count_;
598 
599     if (address < start) {
600       max = mid;
601     } else if (address >= end) {
602       min = mid + 1;
603     } else {  // We have a winner!
604       return mid;
605     }
606   }
607   // No match.
608   return -1;
609 }
610 
611 // Read a signed integer.  "zwidth" is the zero-based byte count.
ReadSignedInt(const uint8_t * ptr,int zwidth)612 int32_t DexFile::ReadSignedInt(const uint8_t* ptr, int zwidth) {
613   int32_t val = 0;
614   for (int i = zwidth; i >= 0; --i) {
615     val = ((uint32_t)val >> 8) | (((int32_t)*ptr++) << 24);
616   }
617   val >>= (3 - zwidth) * 8;
618   return val;
619 }
620 
621 // Read an unsigned integer.  "zwidth" is the zero-based byte count,
622 // "fill_on_right" indicates which side we want to zero-fill from.
ReadUnsignedInt(const uint8_t * ptr,int zwidth,bool fill_on_right)623 uint32_t DexFile::ReadUnsignedInt(const uint8_t* ptr, int zwidth, bool fill_on_right) {
624   uint32_t val = 0;
625   for (int i = zwidth; i >= 0; --i) {
626     val = (val >> 8) | (((uint32_t)*ptr++) << 24);
627   }
628   if (!fill_on_right) {
629     val >>= (3 - zwidth) * 8;
630   }
631   return val;
632 }
633 
634 // Read a signed long.  "zwidth" is the zero-based byte count.
ReadSignedLong(const uint8_t * ptr,int zwidth)635 int64_t DexFile::ReadSignedLong(const uint8_t* ptr, int zwidth) {
636   int64_t val = 0;
637   for (int i = zwidth; i >= 0; --i) {
638     val = ((uint64_t)val >> 8) | (((int64_t)*ptr++) << 56);
639   }
640   val >>= (7 - zwidth) * 8;
641   return val;
642 }
643 
644 // Read an unsigned long.  "zwidth" is the zero-based byte count,
645 // "fill_on_right" indicates which side we want to zero-fill from.
ReadUnsignedLong(const uint8_t * ptr,int zwidth,bool fill_on_right)646 uint64_t DexFile::ReadUnsignedLong(const uint8_t* ptr, int zwidth, bool fill_on_right) {
647   uint64_t val = 0;
648   for (int i = zwidth; i >= 0; --i) {
649     val = (val >> 8) | (((uint64_t)*ptr++) << 56);
650   }
651   if (!fill_on_right) {
652     val >>= (7 - zwidth) * 8;
653   }
654   return val;
655 }
656 
AppendPrettyMethod(uint32_t method_idx,bool with_signature,std::string * const result) const657 void DexFile::AppendPrettyMethod(uint32_t method_idx,
658                                  bool with_signature,
659                                  std::string* const result) const {
660   if (method_idx >= NumMethodIds()) {
661     android::base::StringAppendF(result, "<<invalid-method-idx-%d>>", method_idx);
662     return;
663   }
664   const MethodId& method_id = GetMethodId(method_idx);
665   const ProtoId* proto_id = with_signature ? &GetProtoId(method_id.proto_idx_) : nullptr;
666   if (with_signature) {
667     AppendPrettyDescriptor(GetTypeDescriptor(proto_id->return_type_idx_), result);
668     result->push_back(' ');
669   }
670   AppendPrettyDescriptor(GetMethodDeclaringClassDescriptor(method_id), result);
671   result->push_back('.');
672   result->append(GetMethodName(method_id));
673   if (with_signature) {
674     result->push_back('(');
675     const TypeList* params = GetProtoParameters(*proto_id);
676     if (params != nullptr) {
677       const char* separator = "";
678       for (uint32_t i = 0u, size = params->Size(); i != size; ++i) {
679         result->append(separator);
680         separator = ", ";
681         AppendPrettyDescriptor(GetTypeDescriptor(params->GetTypeItem(i).type_idx_), result);
682       }
683     }
684     result->push_back(')');
685   }
686 }
687 
PrettyField(uint32_t field_idx,bool with_type) const688 std::string DexFile::PrettyField(uint32_t field_idx, bool with_type) const {
689   if (field_idx >= NumFieldIds()) {
690     return StringPrintf("<<invalid-field-idx-%d>>", field_idx);
691   }
692   const FieldId& field_id = GetFieldId(field_idx);
693   std::string result;
694   if (with_type) {
695     result += GetFieldTypeDescriptor(field_id);
696     result += ' ';
697   }
698   AppendPrettyDescriptor(GetFieldDeclaringClassDescriptor(field_id), &result);
699   result += '.';
700   result += GetFieldName(field_id);
701   return result;
702 }
703 
PrettyType(dex::TypeIndex type_idx) const704 std::string DexFile::PrettyType(dex::TypeIndex type_idx) const {
705   if (type_idx.index_ >= NumTypeIds()) {
706     return StringPrintf("<<invalid-type-idx-%d>>", type_idx.index_);
707   }
708   const TypeId& type_id = GetTypeId(type_idx);
709   return PrettyDescriptor(GetTypeDescriptor(type_id));
710 }
711 
GetProtoIndexForCallSite(uint32_t call_site_idx) const712 dex::ProtoIndex DexFile::GetProtoIndexForCallSite(uint32_t call_site_idx) const {
713   const CallSiteIdItem& csi = GetCallSiteId(call_site_idx);
714   CallSiteArrayValueIterator it(*this, csi);
715   it.Next();
716   it.Next();
717   DCHECK_EQ(EncodedArrayValueIterator::ValueType::kMethodType, it.GetValueType());
718   return dex::ProtoIndex(it.GetJavaValue().i);
719 }
720 
721 // Checks that visibility is as expected. Includes special behavior for M and
722 // before to allow runtime and build visibility when expecting runtime.
operator <<(std::ostream & os,const DexFile & dex_file)723 std::ostream& operator<<(std::ostream& os, const DexFile& dex_file) {
724   os << StringPrintf("[DexFile: %s dex-checksum=%08x location-checksum=%08x %p-%p]",
725                      dex_file.GetLocation().c_str(),
726                      dex_file.GetHeader().checksum_, dex_file.GetLocationChecksum(),
727                      dex_file.Begin(), dex_file.Begin() + dex_file.Size());
728   return os;
729 }
730 
EncodedArrayValueIterator(const DexFile & dex_file,const uint8_t * array_data)731 EncodedArrayValueIterator::EncodedArrayValueIterator(const DexFile& dex_file,
732                                                      const uint8_t* array_data)
733     : dex_file_(dex_file),
734       array_size_(),
735       pos_(-1),
736       ptr_(array_data),
737       type_(kByte) {
738   array_size_ = (ptr_ != nullptr) ? DecodeUnsignedLeb128(&ptr_) : 0;
739   if (array_size_ > 0) {
740     bool ok [[maybe_unused]] = MaybeNext();
741   }
742 }
743 
MaybeNext()744 bool EncodedArrayValueIterator::MaybeNext() {
745   pos_++;
746   if (pos_ >= array_size_) {
747     type_ = kEndOfInput;
748     return true;
749   }
750   uint8_t value_type = *ptr_++;
751   uint8_t value_arg = value_type >> kEncodedValueArgShift;
752   size_t width = value_arg + 1;  // assume and correct later
753   type_ = static_cast<ValueType>(value_type & kEncodedValueTypeMask);
754   switch (type_) {
755   case kBoolean:
756     jval_.i = (value_arg != 0) ? 1 : 0;
757     width = 0;
758     break;
759   case kByte:
760     jval_.i = DexFile::ReadSignedInt(ptr_, value_arg);
761     CHECK(IsInt<8>(jval_.i));
762     break;
763   case kShort:
764     jval_.i = DexFile::ReadSignedInt(ptr_, value_arg);
765     CHECK(IsInt<16>(jval_.i));
766     break;
767   case kChar:
768     jval_.i = DexFile::ReadUnsignedInt(ptr_, value_arg, false);
769     CHECK(IsUint<16>(jval_.i));
770     break;
771   case kInt:
772     jval_.i = DexFile::ReadSignedInt(ptr_, value_arg);
773     break;
774   case kLong:
775     jval_.j = DexFile::ReadSignedLong(ptr_, value_arg);
776     break;
777   case kFloat:
778     jval_.i = DexFile::ReadUnsignedInt(ptr_, value_arg, true);
779     break;
780   case kDouble:
781     jval_.j = DexFile::ReadUnsignedLong(ptr_, value_arg, true);
782     break;
783   case kString:
784   case kType:
785   case kMethodType:
786   case kMethodHandle:
787     jval_.i = DexFile::ReadUnsignedInt(ptr_, value_arg, false);
788     break;
789   case kField:
790   case kMethod:
791   case kEnum:
792   case kArray:
793   case kAnnotation:
794     return false;
795   case kNull:
796     jval_.l = nullptr;
797     width = 0;
798     break;
799   default:
800     return false;
801   }
802   ptr_ += width;
803   return true;
804 }
805 
806 namespace dex {
807 
operator <<(std::ostream & os,const ProtoIndex & index)808 std::ostream& operator<<(std::ostream& os, const ProtoIndex& index) {
809   os << "ProtoIndex[" << index.index_ << "]";
810   return os;
811 }
812 
operator <<(std::ostream & os,const StringIndex & index)813 std::ostream& operator<<(std::ostream& os, const StringIndex& index) {
814   os << "StringIndex[" << index.index_ << "]";
815   return os;
816 }
817 
operator <<(std::ostream & os,const TypeIndex & index)818 std::ostream& operator<<(std::ostream& os, const TypeIndex& index) {
819   os << "TypeIndex[" << index.index_ << "]";
820   return os;
821 }
822 
823 }  // namespace dex
824 
825 }  // namespace art
826