1 /* 2 * Copyright (C) 2016 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_writer.h" 18 19 #include <stdint.h> 20 21 #include <vector> 22 23 #include "compact_dex_writer.h" 24 #include "dex/compact_dex_file.h" 25 #include "dex/dex_file_layout.h" 26 #include "dex/dex_file_types.h" 27 #include "dex/standard_dex_file.h" 28 #include "dex/utf.h" 29 #include "dexlayout.h" 30 31 namespace art { 32 33 constexpr uint32_t DexWriter::kDataSectionAlignment; 34 35 static size_t EncodeIntValue(int32_t value, uint8_t* buffer) { 36 size_t length = 0; 37 if (value >= 0) { 38 while (value > 0x7f) { 39 buffer[length++] = static_cast<uint8_t>(value); 40 value >>= 8; 41 } 42 } else { 43 while (value < -0x80) { 44 buffer[length++] = static_cast<uint8_t>(value); 45 value >>= 8; 46 } 47 } 48 buffer[length++] = static_cast<uint8_t>(value); 49 return length; 50 } 51 52 static size_t EncodeUIntValue(uint32_t value, uint8_t* buffer) { 53 size_t length = 0; 54 do { 55 buffer[length++] = static_cast<uint8_t>(value); 56 value >>= 8; 57 } while (value != 0); 58 return length; 59 } 60 61 static size_t EncodeLongValue(int64_t value, uint8_t* buffer) { 62 size_t length = 0; 63 if (value >= 0) { 64 while (value > 0x7f) { 65 buffer[length++] = static_cast<uint8_t>(value); 66 value >>= 8; 67 } 68 } else { 69 while (value < -0x80) { 70 buffer[length++] = static_cast<uint8_t>(value); 71 value >>= 8; 72 } 73 } 74 buffer[length++] = static_cast<uint8_t>(value); 75 return length; 76 } 77 78 union FloatUnion { 79 float f_; 80 uint32_t i_; 81 }; 82 83 static size_t EncodeFloatValue(float value, uint8_t* buffer) { 84 FloatUnion float_union; 85 float_union.f_ = value; 86 uint32_t int_value = float_union.i_; 87 size_t index = 3; 88 do { 89 buffer[index--] = int_value >> 24; 90 int_value <<= 8; 91 } while (int_value != 0); 92 return 3 - index; 93 } 94 95 union DoubleUnion { 96 double d_; 97 uint64_t l_; 98 }; 99 100 static size_t EncodeDoubleValue(double value, uint8_t* buffer) { 101 DoubleUnion double_union; 102 double_union.d_ = value; 103 uint64_t long_value = double_union.l_; 104 size_t index = 7; 105 do { 106 buffer[index--] = long_value >> 56; 107 long_value <<= 8; 108 } while (long_value != 0); 109 return 7 - index; 110 } 111 112 DexWriter::DexWriter(DexLayout* dex_layout, bool compute_offsets) 113 : header_(dex_layout->GetHeader()), 114 dex_layout_(dex_layout), 115 compute_offsets_(compute_offsets) {} 116 117 void DexWriter::WriteEncodedValue(Stream* stream, dex_ir::EncodedValue* encoded_value) { 118 size_t start = 0; 119 size_t length; 120 uint8_t buffer[8]; 121 int8_t type = encoded_value->Type(); 122 switch (type) { 123 case DexFile::kDexAnnotationByte: 124 length = EncodeIntValue(encoded_value->GetByte(), buffer); 125 break; 126 case DexFile::kDexAnnotationShort: 127 length = EncodeIntValue(encoded_value->GetShort(), buffer); 128 break; 129 case DexFile::kDexAnnotationChar: 130 length = EncodeUIntValue(encoded_value->GetChar(), buffer); 131 break; 132 case DexFile::kDexAnnotationInt: 133 length = EncodeIntValue(encoded_value->GetInt(), buffer); 134 break; 135 case DexFile::kDexAnnotationLong: 136 length = EncodeLongValue(encoded_value->GetLong(), buffer); 137 break; 138 case DexFile::kDexAnnotationFloat: 139 length = EncodeFloatValue(encoded_value->GetFloat(), buffer); 140 start = 4 - length; 141 break; 142 case DexFile::kDexAnnotationDouble: 143 length = EncodeDoubleValue(encoded_value->GetDouble(), buffer); 144 start = 8 - length; 145 break; 146 case DexFile::kDexAnnotationMethodType: 147 length = EncodeUIntValue(encoded_value->GetProtoId()->GetIndex(), buffer); 148 break; 149 case DexFile::kDexAnnotationMethodHandle: 150 length = EncodeUIntValue(encoded_value->GetMethodHandle()->GetIndex(), buffer); 151 break; 152 case DexFile::kDexAnnotationString: 153 length = EncodeUIntValue(encoded_value->GetStringId()->GetIndex(), buffer); 154 break; 155 case DexFile::kDexAnnotationType: 156 length = EncodeUIntValue(encoded_value->GetTypeId()->GetIndex(), buffer); 157 break; 158 case DexFile::kDexAnnotationField: 159 case DexFile::kDexAnnotationEnum: 160 length = EncodeUIntValue(encoded_value->GetFieldId()->GetIndex(), buffer); 161 break; 162 case DexFile::kDexAnnotationMethod: 163 length = EncodeUIntValue(encoded_value->GetMethodId()->GetIndex(), buffer); 164 break; 165 case DexFile::kDexAnnotationArray: 166 WriteEncodedValueHeader(stream, type, 0); 167 WriteEncodedArray(stream, encoded_value->GetEncodedArray()->GetEncodedValues()); 168 return; 169 case DexFile::kDexAnnotationAnnotation: 170 WriteEncodedValueHeader(stream, type, 0); 171 WriteEncodedAnnotation(stream, encoded_value->GetEncodedAnnotation()); 172 return; 173 case DexFile::kDexAnnotationNull: 174 WriteEncodedValueHeader(stream, type, 0); 175 return; 176 case DexFile::kDexAnnotationBoolean: 177 WriteEncodedValueHeader(stream, type, encoded_value->GetBoolean() ? 1 : 0); 178 return; 179 default: 180 return; 181 } 182 WriteEncodedValueHeader(stream, type, length - 1); 183 stream->Write(buffer + start, length); 184 } 185 186 void DexWriter::WriteEncodedValueHeader(Stream* stream, int8_t value_type, size_t value_arg) { 187 uint8_t buffer[1] = { static_cast<uint8_t>((value_arg << 5) | value_type) }; 188 stream->Write(buffer, sizeof(uint8_t)); 189 } 190 191 void DexWriter::WriteEncodedArray(Stream* stream, dex_ir::EncodedValueVector* values) { 192 stream->WriteUleb128(values->size()); 193 for (std::unique_ptr<dex_ir::EncodedValue>& value : *values) { 194 WriteEncodedValue(stream, value.get()); 195 } 196 } 197 198 void DexWriter::WriteEncodedAnnotation(Stream* stream, dex_ir::EncodedAnnotation* annotation) { 199 stream->WriteUleb128(annotation->GetType()->GetIndex()); 200 stream->WriteUleb128(annotation->GetAnnotationElements()->size()); 201 for (std::unique_ptr<dex_ir::AnnotationElement>& annotation_element : 202 *annotation->GetAnnotationElements()) { 203 stream->WriteUleb128(annotation_element->GetName()->GetIndex()); 204 WriteEncodedValue(stream, annotation_element->GetValue()); 205 } 206 } 207 208 void DexWriter::WriteEncodedFields(Stream* stream, dex_ir::FieldItemVector* fields) { 209 uint32_t prev_index = 0; 210 for (auto& field : *fields) { 211 uint32_t index = field.GetFieldId()->GetIndex(); 212 stream->WriteUleb128(index - prev_index); 213 stream->WriteUleb128(field.GetAccessFlags()); 214 prev_index = index; 215 } 216 } 217 218 void DexWriter::WriteEncodedMethods(Stream* stream, dex_ir::MethodItemVector* methods) { 219 uint32_t prev_index = 0; 220 for (auto& method : *methods) { 221 uint32_t index = method.GetMethodId()->GetIndex(); 222 uint32_t code_off = method.GetCodeItem() == nullptr ? 0 : method.GetCodeItem()->GetOffset(); 223 stream->WriteUleb128(index - prev_index); 224 stream->WriteUleb128(method.GetAccessFlags()); 225 stream->WriteUleb128(code_off); 226 prev_index = index; 227 } 228 } 229 230 // TODO: Refactor this to remove duplicated boiler plate. One way to do this is adding 231 // function that takes a CollectionVector<T> and uses overloading. 232 void DexWriter::WriteStringIds(Stream* stream, bool reserve_only) { 233 const uint32_t start = stream->Tell(); 234 for (auto& string_id : header_->StringIds()) { 235 stream->AlignTo(SectionAlignment(DexFile::kDexTypeStringIdItem)); 236 if (reserve_only) { 237 stream->Skip(string_id->GetSize()); 238 } else { 239 uint32_t string_data_off = string_id->DataItem()->GetOffset(); 240 stream->Write(&string_data_off, string_id->GetSize()); 241 } 242 } 243 if (compute_offsets_ && start != stream->Tell()) { 244 header_->StringIds().SetOffset(start); 245 } 246 } 247 248 void DexWriter::WriteStringData(Stream* stream, dex_ir::StringData* string_data) { 249 ProcessOffset(stream, string_data); 250 stream->AlignTo(SectionAlignment(DexFile::kDexTypeStringDataItem)); 251 stream->WriteUleb128(CountModifiedUtf8Chars(string_data->Data())); 252 stream->Write(string_data->Data(), strlen(string_data->Data())); 253 // Skip null terminator (already zeroed out, no need to write). 254 stream->Skip(1); 255 } 256 257 void DexWriter::WriteStringDatas(Stream* stream) { 258 const uint32_t start = stream->Tell(); 259 for (auto& string_data : header_->StringDatas()) { 260 WriteStringData(stream, string_data.get()); 261 } 262 if (compute_offsets_ && start != stream->Tell()) { 263 header_->StringDatas().SetOffset(start); 264 } 265 } 266 267 void DexWriter::WriteTypeIds(Stream* stream) { 268 uint32_t descriptor_idx[1]; 269 const uint32_t start = stream->Tell(); 270 for (auto& type_id : header_->TypeIds()) { 271 stream->AlignTo(SectionAlignment(DexFile::kDexTypeTypeIdItem)); 272 ProcessOffset(stream, type_id.get()); 273 descriptor_idx[0] = type_id->GetStringId()->GetIndex(); 274 stream->Write(descriptor_idx, type_id->GetSize()); 275 } 276 if (compute_offsets_ && start != stream->Tell()) { 277 header_->TypeIds().SetOffset(start); 278 } 279 } 280 281 void DexWriter::WriteTypeLists(Stream* stream) { 282 uint32_t size[1]; 283 uint16_t list[1]; 284 const uint32_t start = stream->Tell(); 285 for (auto& type_list : header_->TypeLists()) { 286 stream->AlignTo(SectionAlignment(DexFile::kDexTypeTypeList)); 287 size[0] = type_list->GetTypeList()->size(); 288 ProcessOffset(stream, type_list.get()); 289 stream->Write(size, sizeof(uint32_t)); 290 for (const dex_ir::TypeId* type_id : *type_list->GetTypeList()) { 291 list[0] = type_id->GetIndex(); 292 stream->Write(list, sizeof(uint16_t)); 293 } 294 } 295 if (compute_offsets_ && start != stream->Tell()) { 296 header_->TypeLists().SetOffset(start); 297 } 298 } 299 300 void DexWriter::WriteProtoIds(Stream* stream, bool reserve_only) { 301 uint32_t buffer[3]; 302 const uint32_t start = stream->Tell(); 303 for (auto& proto_id : header_->ProtoIds()) { 304 stream->AlignTo(SectionAlignment(DexFile::kDexTypeProtoIdItem)); 305 ProcessOffset(stream, proto_id.get()); 306 if (reserve_only) { 307 stream->Skip(proto_id->GetSize()); 308 } else { 309 buffer[0] = proto_id->Shorty()->GetIndex(); 310 buffer[1] = proto_id->ReturnType()->GetIndex(); 311 buffer[2] = proto_id->Parameters() == nullptr ? 0 : proto_id->Parameters()->GetOffset(); 312 stream->Write(buffer, proto_id->GetSize()); 313 } 314 } 315 if (compute_offsets_ && start != stream->Tell()) { 316 header_->ProtoIds().SetOffset(start); 317 } 318 } 319 320 void DexWriter::WriteFieldIds(Stream* stream) { 321 uint16_t buffer[4]; 322 const uint32_t start = stream->Tell(); 323 for (auto& field_id : header_->FieldIds()) { 324 stream->AlignTo(SectionAlignment(DexFile::kDexTypeFieldIdItem)); 325 ProcessOffset(stream, field_id.get()); 326 buffer[0] = field_id->Class()->GetIndex(); 327 buffer[1] = field_id->Type()->GetIndex(); 328 buffer[2] = field_id->Name()->GetIndex(); 329 buffer[3] = field_id->Name()->GetIndex() >> 16; 330 stream->Write(buffer, field_id->GetSize()); 331 } 332 if (compute_offsets_ && start != stream->Tell()) { 333 header_->FieldIds().SetOffset(start); 334 } 335 } 336 337 void DexWriter::WriteMethodIds(Stream* stream) { 338 uint16_t buffer[4]; 339 const uint32_t start = stream->Tell(); 340 for (auto& method_id : header_->MethodIds()) { 341 stream->AlignTo(SectionAlignment(DexFile::kDexTypeMethodIdItem)); 342 ProcessOffset(stream, method_id.get()); 343 buffer[0] = method_id->Class()->GetIndex(); 344 buffer[1] = method_id->Proto()->GetIndex(); 345 buffer[2] = method_id->Name()->GetIndex(); 346 buffer[3] = method_id->Name()->GetIndex() >> 16; 347 stream->Write(buffer, method_id->GetSize()); 348 } 349 if (compute_offsets_ && start != stream->Tell()) { 350 header_->MethodIds().SetOffset(start); 351 } 352 } 353 354 void DexWriter::WriteEncodedArrays(Stream* stream) { 355 const uint32_t start = stream->Tell(); 356 for (auto& encoded_array : header_->EncodedArrayItems()) { 357 stream->AlignTo(SectionAlignment(DexFile::kDexTypeEncodedArrayItem)); 358 ProcessOffset(stream, encoded_array.get()); 359 WriteEncodedArray(stream, encoded_array->GetEncodedValues()); 360 } 361 if (compute_offsets_ && start != stream->Tell()) { 362 header_->EncodedArrayItems().SetOffset(start); 363 } 364 } 365 366 void DexWriter::WriteAnnotations(Stream* stream) { 367 uint8_t visibility[1]; 368 const uint32_t start = stream->Tell(); 369 for (auto& annotation : header_->AnnotationItems()) { 370 stream->AlignTo(SectionAlignment(DexFile::kDexTypeAnnotationItem)); 371 visibility[0] = annotation->GetVisibility(); 372 ProcessOffset(stream, annotation.get()); 373 stream->Write(visibility, sizeof(uint8_t)); 374 WriteEncodedAnnotation(stream, annotation->GetAnnotation()); 375 } 376 if (compute_offsets_ && start != stream->Tell()) { 377 header_->AnnotationItems().SetOffset(start); 378 } 379 } 380 381 void DexWriter::WriteAnnotationSets(Stream* stream) { 382 uint32_t size[1]; 383 uint32_t annotation_off[1]; 384 const uint32_t start = stream->Tell(); 385 for (auto& annotation_set : header_->AnnotationSetItems()) { 386 stream->AlignTo(SectionAlignment(DexFile::kDexTypeAnnotationSetItem)); 387 size[0] = annotation_set->GetItems()->size(); 388 ProcessOffset(stream, annotation_set.get()); 389 stream->Write(size, sizeof(uint32_t)); 390 for (dex_ir::AnnotationItem* annotation : *annotation_set->GetItems()) { 391 annotation_off[0] = annotation->GetOffset(); 392 stream->Write(annotation_off, sizeof(uint32_t)); 393 } 394 } 395 if (compute_offsets_ && start != stream->Tell()) { 396 header_->AnnotationSetItems().SetOffset(start); 397 } 398 } 399 400 void DexWriter::WriteAnnotationSetRefs(Stream* stream) { 401 uint32_t size[1]; 402 uint32_t annotations_off[1]; 403 const uint32_t start = stream->Tell(); 404 for (auto& annotation_set_ref : header_->AnnotationSetRefLists()) { 405 stream->AlignTo(SectionAlignment(DexFile::kDexTypeAnnotationSetRefList)); 406 size[0] = annotation_set_ref->GetItems()->size(); 407 ProcessOffset(stream, annotation_set_ref.get()); 408 stream->Write(size, sizeof(uint32_t)); 409 for (dex_ir::AnnotationSetItem* annotation_set : *annotation_set_ref->GetItems()) { 410 annotations_off[0] = annotation_set == nullptr ? 0 : annotation_set->GetOffset(); 411 stream->Write(annotations_off, sizeof(uint32_t)); 412 } 413 } 414 if (compute_offsets_ && start != stream->Tell()) { 415 header_->AnnotationSetRefLists().SetOffset(start); 416 } 417 } 418 419 void DexWriter::WriteAnnotationsDirectories(Stream* stream) { 420 uint32_t directory_buffer[4]; 421 uint32_t annotation_buffer[2]; 422 const uint32_t start = stream->Tell(); 423 for (auto& annotations_directory : header_->AnnotationsDirectoryItems()) { 424 stream->AlignTo(SectionAlignment(DexFile::kDexTypeAnnotationsDirectoryItem)); 425 ProcessOffset(stream, annotations_directory.get()); 426 directory_buffer[0] = annotations_directory->GetClassAnnotation() == nullptr ? 0 : 427 annotations_directory->GetClassAnnotation()->GetOffset(); 428 directory_buffer[1] = annotations_directory->GetFieldAnnotations() == nullptr ? 0 : 429 annotations_directory->GetFieldAnnotations()->size(); 430 directory_buffer[2] = annotations_directory->GetMethodAnnotations() == nullptr ? 0 : 431 annotations_directory->GetMethodAnnotations()->size(); 432 directory_buffer[3] = annotations_directory->GetParameterAnnotations() == nullptr ? 0 : 433 annotations_directory->GetParameterAnnotations()->size(); 434 stream->Write(directory_buffer, 4 * sizeof(uint32_t)); 435 if (annotations_directory->GetFieldAnnotations() != nullptr) { 436 for (std::unique_ptr<dex_ir::FieldAnnotation>& field : 437 *annotations_directory->GetFieldAnnotations()) { 438 annotation_buffer[0] = field->GetFieldId()->GetIndex(); 439 annotation_buffer[1] = field->GetAnnotationSetItem()->GetOffset(); 440 stream->Write(annotation_buffer, 2 * sizeof(uint32_t)); 441 } 442 } 443 if (annotations_directory->GetMethodAnnotations() != nullptr) { 444 for (std::unique_ptr<dex_ir::MethodAnnotation>& method : 445 *annotations_directory->GetMethodAnnotations()) { 446 annotation_buffer[0] = method->GetMethodId()->GetIndex(); 447 annotation_buffer[1] = method->GetAnnotationSetItem()->GetOffset(); 448 stream->Write(annotation_buffer, 2 * sizeof(uint32_t)); 449 } 450 } 451 if (annotations_directory->GetParameterAnnotations() != nullptr) { 452 for (std::unique_ptr<dex_ir::ParameterAnnotation>& parameter : 453 *annotations_directory->GetParameterAnnotations()) { 454 annotation_buffer[0] = parameter->GetMethodId()->GetIndex(); 455 annotation_buffer[1] = parameter->GetAnnotations()->GetOffset(); 456 stream->Write(annotation_buffer, 2 * sizeof(uint32_t)); 457 } 458 } 459 } 460 if (compute_offsets_ && start != stream->Tell()) { 461 header_->AnnotationsDirectoryItems().SetOffset(start); 462 } 463 } 464 465 void DexWriter::WriteHiddenapiClassData(Stream* stream) { 466 if (header_->HiddenapiClassDatas().Empty()) { 467 return; 468 } 469 DCHECK_EQ(header_->HiddenapiClassDatas().Size(), header_->ClassDefs().Size()); 470 471 stream->AlignTo(SectionAlignment(DexFile::kDexTypeHiddenapiClassData)); 472 ProcessOffset(stream, &header_->HiddenapiClassDatas()); 473 const uint32_t start = stream->Tell(); 474 475 // Compute offsets for each class def and write the header. 476 // data_header[0]: total size of the section 477 // data_header[i + 1]: offset of class def[i] from the beginning of the section, 478 // or zero if no data 479 std::vector<uint32_t> data_header(header_->ClassDefs().Size() + 1, 0); 480 data_header[0] = sizeof(uint32_t) * (header_->ClassDefs().Size() + 1); 481 for (uint32_t i = 0; i < header_->ClassDefs().Size(); ++i) { 482 uint32_t item_size = header_->HiddenapiClassDatas()[i]->ItemSize(); 483 data_header[i + 1] = item_size == 0u ? 0 : data_header[0]; 484 data_header[0] += item_size; 485 } 486 stream->Write(data_header.data(), sizeof(uint32_t) * data_header.size()); 487 488 // Write class data streams. 489 for (uint32_t i = 0; i < header_->ClassDefs().Size(); ++i) { 490 dex_ir::ClassDef* class_def = header_->ClassDefs()[i]; 491 const auto& item = header_->HiddenapiClassDatas()[i]; 492 DCHECK(item->GetClassDef() == class_def); 493 494 if (data_header[i + 1] != 0u) { 495 dex_ir::ClassData* class_data = class_def->GetClassData(); 496 DCHECK(class_data != nullptr); 497 DCHECK_EQ(data_header[i + 1], stream->Tell() - start); 498 for (const dex_ir::FieldItem& field : *class_data->StaticFields()) { 499 stream->WriteUleb128(item->GetFlags(&field)); 500 } 501 for (const dex_ir::FieldItem& field : *class_data->InstanceFields()) { 502 stream->WriteUleb128(item->GetFlags(&field)); 503 } 504 for (const dex_ir::MethodItem& method : *class_data->DirectMethods()) { 505 stream->WriteUleb128(item->GetFlags(&method)); 506 } 507 for (const dex_ir::MethodItem& method : *class_data->VirtualMethods()) { 508 stream->WriteUleb128(item->GetFlags(&method)); 509 } 510 } 511 } 512 DCHECK_EQ(stream->Tell() - start, data_header[0]); 513 514 if (compute_offsets_ && start != stream->Tell()) { 515 header_->HiddenapiClassDatas().SetOffset(start); 516 } 517 } 518 519 void DexWriter::WriteDebugInfoItem(Stream* stream, dex_ir::DebugInfoItem* debug_info) { 520 stream->AlignTo(SectionAlignment(DexFile::kDexTypeDebugInfoItem)); 521 ProcessOffset(stream, debug_info); 522 stream->Write(debug_info->GetDebugInfo(), debug_info->GetDebugInfoSize()); 523 } 524 525 void DexWriter::WriteDebugInfoItems(Stream* stream) { 526 const uint32_t start = stream->Tell(); 527 for (auto& debug_info : header_->DebugInfoItems()) { 528 WriteDebugInfoItem(stream, debug_info.get()); 529 } 530 if (compute_offsets_ && start != stream->Tell()) { 531 header_->DebugInfoItems().SetOffset(start); 532 } 533 } 534 535 void DexWriter::WriteCodeItemPostInstructionData(Stream* stream, 536 dex_ir::CodeItem* code_item, 537 bool reserve_only) { 538 if (code_item->TriesSize() != 0) { 539 stream->AlignTo(dex::TryItem::kAlignment); 540 // Write try items. 541 for (std::unique_ptr<const dex_ir::TryItem>& try_item : *code_item->Tries()) { 542 dex::TryItem disk_try_item; 543 if (!reserve_only) { 544 disk_try_item.start_addr_ = try_item->StartAddr(); 545 disk_try_item.insn_count_ = try_item->InsnCount(); 546 disk_try_item.handler_off_ = try_item->GetHandlers()->GetListOffset(); 547 } 548 stream->Write(&disk_try_item, sizeof(disk_try_item)); 549 } 550 // Leave offset pointing to the end of the try items. 551 const size_t offset = stream->Tell(); 552 size_t max_offset = offset + stream->WriteUleb128(code_item->Handlers()->size()); 553 for (std::unique_ptr<const dex_ir::CatchHandler>& handlers : *code_item->Handlers()) { 554 stream->Seek(offset + handlers->GetListOffset()); 555 uint32_t size = handlers->HasCatchAll() ? (handlers->GetHandlers()->size() - 1) * -1 : 556 handlers->GetHandlers()->size(); 557 stream->WriteSleb128(size); 558 for (std::unique_ptr<const dex_ir::TypeAddrPair>& handler : *handlers->GetHandlers()) { 559 if (handler->GetTypeId() != nullptr) { 560 stream->WriteUleb128(handler->GetTypeId()->GetIndex()); 561 } 562 stream->WriteUleb128(handler->GetAddress()); 563 } 564 // TODO: Clean this up to write the handlers in address order. 565 max_offset = std::max(max_offset, stream->Tell()); 566 } 567 stream->Seek(max_offset); 568 } 569 } 570 571 void DexWriter::WriteCodeItem(Stream* stream, 572 dex_ir::CodeItem* code_item, 573 bool reserve_only) { 574 DCHECK(code_item != nullptr); 575 const uint32_t start_offset = stream->Tell(); 576 stream->AlignTo(SectionAlignment(DexFile::kDexTypeCodeItem)); 577 ProcessOffset(stream, code_item); 578 579 StandardDexFile::CodeItem disk_code_item; 580 if (!reserve_only) { 581 disk_code_item.registers_size_ = code_item->RegistersSize(); 582 disk_code_item.ins_size_ = code_item->InsSize(); 583 disk_code_item.outs_size_ = code_item->OutsSize(); 584 disk_code_item.tries_size_ = code_item->TriesSize(); 585 disk_code_item.debug_info_off_ = code_item->DebugInfo() == nullptr 586 ? 0 587 : code_item->DebugInfo()->GetOffset(); 588 disk_code_item.insns_size_in_code_units_ = code_item->InsnsSize(); 589 } 590 // Avoid using sizeof so that we don't write the fake instruction array at the end of the code 591 // item. 592 stream->Write(&disk_code_item, OFFSETOF_MEMBER(StandardDexFile::CodeItem, insns_)); 593 // Write the instructions. 594 stream->Write(code_item->Insns(), code_item->InsnsSize() * sizeof(uint16_t)); 595 // Write the post instruction data. 596 WriteCodeItemPostInstructionData(stream, code_item, reserve_only); 597 if (reserve_only) { 598 stream->Clear(start_offset, stream->Tell() - start_offset); 599 } 600 } 601 602 void DexWriter::WriteCodeItems(Stream* stream, bool reserve_only) { 603 DexLayoutSection* code_section = nullptr; 604 if (!reserve_only && dex_layout_ != nullptr) { 605 code_section = &dex_layout_->GetSections().sections_[static_cast<size_t>( 606 DexLayoutSections::SectionType::kSectionTypeCode)]; 607 } 608 const uint32_t start = stream->Tell(); 609 for (auto& code_item : header_->CodeItems()) { 610 uint32_t start_offset = stream->Tell(); 611 WriteCodeItem(stream, code_item.get(), reserve_only); 612 // Only add the section hotness info once. 613 if (!reserve_only && code_section != nullptr) { 614 auto it = dex_layout_->LayoutHotnessInfo().code_item_layout_.find(code_item.get()); 615 if (it != dex_layout_->LayoutHotnessInfo().code_item_layout_.end()) { 616 code_section->parts_[static_cast<size_t>(it->second)].CombineSection( 617 start_offset, 618 stream->Tell()); 619 } 620 } 621 } 622 623 if (compute_offsets_ && start != stream->Tell()) { 624 header_->CodeItems().SetOffset(start); 625 } 626 } 627 628 void DexWriter::WriteClassDefs(Stream* stream, bool reserve_only) { 629 const uint32_t start = stream->Tell(); 630 uint32_t class_def_buffer[8]; 631 for (auto& class_def : header_->ClassDefs()) { 632 stream->AlignTo(SectionAlignment(DexFile::kDexTypeClassDefItem)); 633 if (reserve_only) { 634 stream->Skip(class_def->GetSize()); 635 } else { 636 class_def_buffer[0] = class_def->ClassType()->GetIndex(); 637 class_def_buffer[1] = class_def->GetAccessFlags(); 638 class_def_buffer[2] = class_def->Superclass() == nullptr ? dex::kDexNoIndex : 639 class_def->Superclass()->GetIndex(); 640 class_def_buffer[3] = class_def->InterfacesOffset(); 641 class_def_buffer[4] = class_def->SourceFile() == nullptr ? dex::kDexNoIndex : 642 class_def->SourceFile()->GetIndex(); 643 class_def_buffer[5] = class_def->Annotations() == nullptr ? 0 : 644 class_def->Annotations()->GetOffset(); 645 class_def_buffer[6] = class_def->GetClassData() == nullptr ? 0 : 646 class_def->GetClassData()->GetOffset(); 647 class_def_buffer[7] = class_def->StaticValues() == nullptr ? 0 : 648 class_def->StaticValues()->GetOffset(); 649 stream->Write(class_def_buffer, class_def->GetSize()); 650 } 651 } 652 if (compute_offsets_ && start != stream->Tell()) { 653 header_->ClassDefs().SetOffset(start); 654 } 655 } 656 657 void DexWriter::WriteClassDatas(Stream* stream) { 658 const uint32_t start = stream->Tell(); 659 for (const std::unique_ptr<dex_ir::ClassData>& class_data : 660 header_->ClassDatas()) { 661 stream->AlignTo(SectionAlignment(DexFile::kDexTypeClassDataItem)); 662 ProcessOffset(stream, class_data.get()); 663 stream->WriteUleb128(class_data->StaticFields()->size()); 664 stream->WriteUleb128(class_data->InstanceFields()->size()); 665 stream->WriteUleb128(class_data->DirectMethods()->size()); 666 stream->WriteUleb128(class_data->VirtualMethods()->size()); 667 WriteEncodedFields(stream, class_data->StaticFields()); 668 WriteEncodedFields(stream, class_data->InstanceFields()); 669 WriteEncodedMethods(stream, class_data->DirectMethods()); 670 WriteEncodedMethods(stream, class_data->VirtualMethods()); 671 } 672 if (compute_offsets_ && start != stream->Tell()) { 673 header_->ClassDatas().SetOffset(start); 674 } 675 } 676 677 void DexWriter::WriteCallSiteIds(Stream* stream, bool reserve_only) { 678 const uint32_t start = stream->Tell(); 679 uint32_t call_site_off[1]; 680 for (auto& call_site_id : header_->CallSiteIds()) { 681 stream->AlignTo(SectionAlignment(DexFile::kDexTypeCallSiteIdItem)); 682 if (reserve_only) { 683 stream->Skip(call_site_id->GetSize()); 684 } else { 685 call_site_off[0] = call_site_id->CallSiteItem()->GetOffset(); 686 stream->Write(call_site_off, call_site_id->GetSize()); 687 } 688 } 689 if (compute_offsets_ && start != stream->Tell()) { 690 header_->CallSiteIds().SetOffset(start); 691 } 692 } 693 694 void DexWriter::WriteMethodHandles(Stream* stream) { 695 const uint32_t start = stream->Tell(); 696 uint16_t method_handle_buff[4]; 697 for (auto& method_handle : header_->MethodHandleItems()) { 698 stream->AlignTo(SectionAlignment(DexFile::kDexTypeMethodHandleItem)); 699 method_handle_buff[0] = static_cast<uint16_t>(method_handle->GetMethodHandleType()); 700 method_handle_buff[1] = 0; // unused. 701 method_handle_buff[2] = method_handle->GetFieldOrMethodId()->GetIndex(); 702 method_handle_buff[3] = 0; // unused. 703 stream->Write(method_handle_buff, method_handle->GetSize()); 704 } 705 if (compute_offsets_ && start != stream->Tell()) { 706 header_->MethodHandleItems().SetOffset(start); 707 } 708 } 709 710 void DexWriter::WriteMapItems(Stream* stream, MapItemQueue* queue) { 711 // All the sections should already have been added. 712 const uint32_t map_list_size = queue->size(); 713 stream->Write(&map_list_size, sizeof(map_list_size)); 714 while (!queue->empty()) { 715 const MapItem& item = queue->top(); 716 dex::MapItem map_item; 717 map_item.type_ = item.type_; 718 map_item.size_ = item.size_; 719 map_item.offset_ = item.offset_; 720 map_item.unused_ = 0u; 721 stream->Write(&map_item, sizeof(map_item)); 722 queue->pop(); 723 } 724 } 725 726 void DexWriter::GenerateAndWriteMapItems(Stream* stream) { 727 MapItemQueue queue; 728 729 // Header and index section. 730 queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeHeaderItem, 1, 0)); 731 queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeStringIdItem, 732 header_->StringIds().Size(), 733 header_->StringIds().GetOffset())); 734 queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeTypeIdItem, 735 header_->TypeIds().Size(), 736 header_->TypeIds().GetOffset())); 737 queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeProtoIdItem, 738 header_->ProtoIds().Size(), 739 header_->ProtoIds().GetOffset())); 740 queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeFieldIdItem, 741 header_->FieldIds().Size(), 742 header_->FieldIds().GetOffset())); 743 queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeMethodIdItem, 744 header_->MethodIds().Size(), 745 header_->MethodIds().GetOffset())); 746 queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeClassDefItem, 747 header_->ClassDefs().Size(), 748 header_->ClassDefs().GetOffset())); 749 queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeCallSiteIdItem, 750 header_->CallSiteIds().Size(), 751 header_->CallSiteIds().GetOffset())); 752 queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeMethodHandleItem, 753 header_->MethodHandleItems().Size(), 754 header_->MethodHandleItems().GetOffset())); 755 // Data section. 756 queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeMapList, 1, header_->MapListOffset())); 757 queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeTypeList, 758 header_->TypeLists().Size(), 759 header_->TypeLists().GetOffset())); 760 queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeAnnotationSetRefList, 761 header_->AnnotationSetRefLists().Size(), 762 header_->AnnotationSetRefLists().GetOffset())); 763 queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeAnnotationSetItem, 764 header_->AnnotationSetItems().Size(), 765 header_->AnnotationSetItems().GetOffset())); 766 queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeClassDataItem, 767 header_->ClassDatas().Size(), 768 header_->ClassDatas().GetOffset())); 769 queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeCodeItem, 770 header_->CodeItems().Size(), 771 header_->CodeItems().GetOffset())); 772 queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeStringDataItem, 773 header_->StringDatas().Size(), 774 header_->StringDatas().GetOffset())); 775 queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeDebugInfoItem, 776 header_->DebugInfoItems().Size(), 777 header_->DebugInfoItems().GetOffset())); 778 queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeAnnotationItem, 779 header_->AnnotationItems().Size(), 780 header_->AnnotationItems().GetOffset())); 781 queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeEncodedArrayItem, 782 header_->EncodedArrayItems().Size(), 783 header_->EncodedArrayItems().GetOffset())); 784 queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeAnnotationsDirectoryItem, 785 header_->AnnotationsDirectoryItems().Size(), 786 header_->AnnotationsDirectoryItems().GetOffset())); 787 queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeHiddenapiClassData, 788 header_->HiddenapiClassDatas().Empty() ? 0u : 1u, 789 header_->HiddenapiClassDatas().GetOffset())); 790 WriteMapItems(stream, &queue); 791 } 792 793 void DexWriter::WriteHeader(Stream* stream) { 794 StandardDexFile::Header header; 795 if (CompactDexFile::IsMagicValid(header_->Magic())) { 796 StandardDexFile::WriteMagic(header.magic_); 797 // TODO: Should we write older versions based on the feature flags? 798 StandardDexFile::WriteCurrentVersion(header.magic_); 799 } else { 800 // Standard dex -> standard dex, just reuse the same header. 801 static constexpr size_t kMagicAndVersionLen = 802 StandardDexFile::kDexMagicSize + StandardDexFile::kDexVersionLen; 803 std::copy_n(header_->Magic(), kMagicAndVersionLen, header.magic_); 804 } 805 header.checksum_ = header_->Checksum(); 806 std::copy_n(header_->Signature(), DexFile::kSha1DigestSize, header.signature_); 807 header.file_size_ = header_->FileSize(); 808 header.header_size_ = GetHeaderSize(); 809 header.endian_tag_ = header_->EndianTag(); 810 header.link_size_ = header_->LinkSize(); 811 header.link_off_ = header_->LinkOffset(); 812 header.map_off_ = header_->MapListOffset(); 813 header.string_ids_size_ = header_->StringIds().Size(); 814 header.string_ids_off_ = header_->StringIds().GetOffset(); 815 header.type_ids_size_ = header_->TypeIds().Size(); 816 header.type_ids_off_ = header_->TypeIds().GetOffset(); 817 header.proto_ids_size_ = header_->ProtoIds().Size(); 818 header.proto_ids_off_ = header_->ProtoIds().GetOffset(); 819 header.field_ids_size_ = header_->FieldIds().Size(); 820 header.field_ids_off_ = header_->FieldIds().GetOffset(); 821 header.method_ids_size_ = header_->MethodIds().Size(); 822 header.method_ids_off_ = header_->MethodIds().GetOffset(); 823 header.class_defs_size_ = header_->ClassDefs().Size(); 824 header.class_defs_off_ = header_->ClassDefs().GetOffset(); 825 header.data_size_ = header_->DataSize(); 826 header.data_off_ = header_->DataOffset(); 827 828 CHECK_EQ(sizeof(header), GetHeaderSize()); 829 static_assert(sizeof(header) == 0x70, "Size doesn't match dex spec"); 830 stream->Seek(0); 831 stream->Overwrite(reinterpret_cast<uint8_t*>(&header), sizeof(header)); 832 } 833 834 size_t DexWriter::GetHeaderSize() const { 835 return sizeof(StandardDexFile::Header); 836 } 837 838 bool DexWriter::Write(DexContainer* output, std::string* error_msg) { 839 DCHECK(error_msg != nullptr); 840 841 Stream stream_storage(output->GetMainSection()); 842 Stream* stream = &stream_storage; 843 844 // Starting offset is right after the header. 845 stream->Seek(GetHeaderSize()); 846 847 // Based on: https://source.android.com/devices/tech/dalvik/dex-format 848 // Since the offsets may not be calculated already, the writing must be done in the correct order. 849 const uint32_t string_ids_offset = stream->Tell(); 850 WriteStringIds(stream, /*reserve_only=*/ true); 851 WriteTypeIds(stream); 852 const uint32_t proto_ids_offset = stream->Tell(); 853 WriteProtoIds(stream, /*reserve_only=*/ true); 854 WriteFieldIds(stream); 855 WriteMethodIds(stream); 856 const uint32_t class_defs_offset = stream->Tell(); 857 WriteClassDefs(stream, /*reserve_only=*/ true); 858 const uint32_t call_site_ids_offset = stream->Tell(); 859 WriteCallSiteIds(stream, /*reserve_only=*/ true); 860 WriteMethodHandles(stream); 861 862 uint32_t data_offset_ = 0u; 863 if (compute_offsets_) { 864 // Data section. 865 stream->AlignTo(kDataSectionAlignment); 866 data_offset_ = stream->Tell(); 867 } 868 869 // Write code item first to minimize the space required for encoded methods. 870 // Reserve code item space since we need the debug offsets to actually write them. 871 const uint32_t code_items_offset = stream->Tell(); 872 WriteCodeItems(stream, /*reserve_only=*/ true); 873 // Write debug info section. 874 WriteDebugInfoItems(stream); 875 { 876 // Actually write code items since debug info offsets are calculated now. 877 Stream::ScopedSeek seek(stream, code_items_offset); 878 WriteCodeItems(stream, /*reserve_only=*/ false); 879 } 880 881 WriteEncodedArrays(stream); 882 WriteAnnotations(stream); 883 WriteAnnotationSets(stream); 884 WriteAnnotationSetRefs(stream); 885 WriteAnnotationsDirectories(stream); 886 WriteTypeLists(stream); 887 WriteClassDatas(stream); 888 WriteStringDatas(stream); 889 WriteHiddenapiClassData(stream); 890 891 // Write delayed id sections that depend on data sections. 892 { 893 Stream::ScopedSeek seek(stream, string_ids_offset); 894 WriteStringIds(stream, /*reserve_only=*/ false); 895 } 896 { 897 Stream::ScopedSeek seek(stream, proto_ids_offset); 898 WriteProtoIds(stream, /*reserve_only=*/ false); 899 } 900 { 901 Stream::ScopedSeek seek(stream, class_defs_offset); 902 WriteClassDefs(stream, /*reserve_only=*/ false); 903 } 904 { 905 Stream::ScopedSeek seek(stream, call_site_ids_offset); 906 WriteCallSiteIds(stream, /*reserve_only=*/ false); 907 } 908 909 // Write the map list. 910 if (compute_offsets_) { 911 stream->AlignTo(SectionAlignment(DexFile::kDexTypeMapList)); 912 header_->SetMapListOffset(stream->Tell()); 913 } else { 914 stream->Seek(header_->MapListOffset()); 915 } 916 GenerateAndWriteMapItems(stream); 917 stream->AlignTo(kDataSectionAlignment); 918 919 // Map items are included in the data section. 920 if (compute_offsets_) { 921 header_->SetDataSize(stream->Tell() - data_offset_); 922 if (header_->DataSize() != 0) { 923 // Offset must be zero when the size is zero. 924 header_->SetDataOffset(data_offset_); 925 } else { 926 header_->SetDataOffset(0u); 927 } 928 } 929 930 // Write link data if it exists. 931 const std::vector<uint8_t>& link_data = header_->LinkData(); 932 if (link_data.size() > 0) { 933 CHECK_EQ(header_->LinkSize(), static_cast<uint32_t>(link_data.size())); 934 if (compute_offsets_) { 935 header_->SetLinkOffset(stream->Tell()); 936 } else { 937 stream->Seek(header_->LinkOffset()); 938 } 939 stream->Write(&link_data[0], link_data.size()); 940 } 941 942 // Write header last. 943 if (compute_offsets_) { 944 header_->SetFileSize(stream->Tell()); 945 } 946 WriteHeader(stream); 947 948 if (dex_layout_->GetOptions().update_checksum_) { 949 header_->SetChecksum(DexFile::CalculateChecksum(stream->Begin(), header_->FileSize())); 950 // Rewrite the header with the calculated checksum. 951 WriteHeader(stream); 952 } 953 954 // Trim the map to make it sized as large as the dex file. 955 output->GetMainSection()->Resize(header_->FileSize()); 956 return true; 957 } 958 959 bool DexWriter::Output(DexLayout* dex_layout, 960 std::unique_ptr<DexContainer>* container, 961 bool compute_offsets, 962 std::string* error_msg) { 963 CHECK(dex_layout != nullptr); 964 std::unique_ptr<DexWriter> writer; 965 if (dex_layout->GetOptions().compact_dex_level_ != CompactDexLevel::kCompactDexLevelNone) { 966 CHECK(compute_offsets) << "Compact dex requires computing offsets"; 967 writer.reset(new CompactDexWriter(dex_layout)); 968 } else { 969 writer.reset(new DexWriter(dex_layout, compute_offsets)); 970 } 971 DCHECK(container != nullptr); 972 if (*container == nullptr) { 973 *container = writer->CreateDexContainer(); 974 } 975 return writer->Write(container->get(), error_msg); 976 } 977 978 void MapItemQueue::AddIfNotEmpty(const MapItem& item) { 979 if (item.size_ != 0) { 980 push(item); 981 } 982 } 983 984 void DexWriter::ProcessOffset(Stream* stream, dex_ir::Item* item) { 985 if (compute_offsets_) { 986 item->SetOffset(stream->Tell()); 987 } else { 988 // Not computing offsets, just use the one in the item. 989 stream->Seek(item->GetOffset()); 990 } 991 } 992 993 void DexWriter::ProcessOffset(Stream* stream, dex_ir::CollectionBase* item) { 994 if (compute_offsets_) { 995 item->SetOffset(stream->Tell()); 996 } else { 997 // Not computing offsets, just use the one in the item. 998 stream->Seek(item->GetOffset()); 999 } 1000 } 1001 1002 std::unique_ptr<DexContainer> DexWriter::CreateDexContainer() const { 1003 return std::unique_ptr<DexContainer>(new DexWriter::Container); 1004 } 1005 1006 } // namespace art 1007