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