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