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