Home | History | Annotate | Download | only in dexlayout
      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 (std::unique_ptr<dex_ir::FieldItem>& 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 (std::unique_ptr<dex_ir::MethodItem>& 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 (std::unique_ptr<dex_ir::StringId>& string_id : header_->GetCollections().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_->GetCollections().SetStringIdsOffset(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 (std::unique_ptr<dex_ir::StringData>& string_data : header_->GetCollections().StringDatas()) {
    260     WriteStringData(stream, string_data.get());
    261   }
    262   if (compute_offsets_ && start != stream->Tell()) {
    263     header_->GetCollections().SetStringDatasOffset(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 (std::unique_ptr<dex_ir::TypeId>& type_id : header_->GetCollections().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_->GetCollections().SetTypeIdsOffset(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 (std::unique_ptr<dex_ir::TypeList>& type_list : header_->GetCollections().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_->GetCollections().SetTypeListsOffset(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 (std::unique_ptr<dex_ir::ProtoId>& proto_id : header_->GetCollections().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_->GetCollections().SetProtoIdsOffset(start);
    317   }
    318 }
    319 
    320 void DexWriter::WriteFieldIds(Stream* stream) {
    321   uint16_t buffer[4];
    322   const uint32_t start = stream->Tell();
    323   for (std::unique_ptr<dex_ir::FieldId>& field_id : header_->GetCollections().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_->GetCollections().SetFieldIdsOffset(start);
    334   }
    335 }
    336 
    337 void DexWriter::WriteMethodIds(Stream* stream) {
    338   uint16_t buffer[4];
    339   const uint32_t start = stream->Tell();
    340   for (std::unique_ptr<dex_ir::MethodId>& method_id : header_->GetCollections().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_->GetCollections().SetMethodIdsOffset(start);
    351   }
    352 }
    353 
    354 void DexWriter::WriteEncodedArrays(Stream* stream) {
    355   const uint32_t start = stream->Tell();
    356   for (std::unique_ptr<dex_ir::EncodedArrayItem>& encoded_array :
    357       header_->GetCollections().EncodedArrayItems()) {
    358     stream->AlignTo(SectionAlignment(DexFile::kDexTypeEncodedArrayItem));
    359     ProcessOffset(stream, encoded_array.get());
    360     WriteEncodedArray(stream, encoded_array->GetEncodedValues());
    361   }
    362   if (compute_offsets_ && start != stream->Tell()) {
    363     header_->GetCollections().SetEncodedArrayItemsOffset(start);
    364   }
    365 }
    366 
    367 void DexWriter::WriteAnnotations(Stream* stream) {
    368   uint8_t visibility[1];
    369   const uint32_t start = stream->Tell();
    370   for (std::unique_ptr<dex_ir::AnnotationItem>& annotation :
    371       header_->GetCollections().AnnotationItems()) {
    372     stream->AlignTo(SectionAlignment(DexFile::kDexTypeAnnotationItem));
    373     visibility[0] = annotation->GetVisibility();
    374     ProcessOffset(stream, annotation.get());
    375     stream->Write(visibility, sizeof(uint8_t));
    376     WriteEncodedAnnotation(stream, annotation->GetAnnotation());
    377   }
    378   if (compute_offsets_ && start != stream->Tell()) {
    379     header_->GetCollections().SetAnnotationItemsOffset(start);
    380   }
    381 }
    382 
    383 void DexWriter::WriteAnnotationSets(Stream* stream) {
    384   uint32_t size[1];
    385   uint32_t annotation_off[1];
    386   const uint32_t start = stream->Tell();
    387   for (std::unique_ptr<dex_ir::AnnotationSetItem>& annotation_set :
    388       header_->GetCollections().AnnotationSetItems()) {
    389     stream->AlignTo(SectionAlignment(DexFile::kDexTypeAnnotationSetItem));
    390     size[0] = annotation_set->GetItems()->size();
    391     ProcessOffset(stream, annotation_set.get());
    392     stream->Write(size, sizeof(uint32_t));
    393     for (dex_ir::AnnotationItem* annotation : *annotation_set->GetItems()) {
    394       annotation_off[0] = annotation->GetOffset();
    395       stream->Write(annotation_off, sizeof(uint32_t));
    396     }
    397   }
    398   if (compute_offsets_ && start != stream->Tell()) {
    399     header_->GetCollections().SetAnnotationSetItemsOffset(start);
    400   }
    401 }
    402 
    403 void DexWriter::WriteAnnotationSetRefs(Stream* stream) {
    404   uint32_t size[1];
    405   uint32_t annotations_off[1];
    406   const uint32_t start = stream->Tell();
    407   for (std::unique_ptr<dex_ir::AnnotationSetRefList>& annotation_set_ref :
    408       header_->GetCollections().AnnotationSetRefLists()) {
    409     stream->AlignTo(SectionAlignment(DexFile::kDexTypeAnnotationSetRefList));
    410     size[0] = annotation_set_ref->GetItems()->size();
    411     ProcessOffset(stream, annotation_set_ref.get());
    412     stream->Write(size, sizeof(uint32_t));
    413     for (dex_ir::AnnotationSetItem* annotation_set : *annotation_set_ref->GetItems()) {
    414       annotations_off[0] = annotation_set == nullptr ? 0 : annotation_set->GetOffset();
    415       stream->Write(annotations_off, sizeof(uint32_t));
    416     }
    417   }
    418   if (compute_offsets_ && start != stream->Tell()) {
    419     header_->GetCollections().SetAnnotationSetRefListsOffset(start);
    420   }
    421 }
    422 
    423 void DexWriter::WriteAnnotationsDirectories(Stream* stream) {
    424   uint32_t directory_buffer[4];
    425   uint32_t annotation_buffer[2];
    426   const uint32_t start = stream->Tell();
    427   for (std::unique_ptr<dex_ir::AnnotationsDirectoryItem>& annotations_directory :
    428       header_->GetCollections().AnnotationsDirectoryItems()) {
    429     stream->AlignTo(SectionAlignment(DexFile::kDexTypeAnnotationsDirectoryItem));
    430     ProcessOffset(stream, annotations_directory.get());
    431     directory_buffer[0] = annotations_directory->GetClassAnnotation() == nullptr ? 0 :
    432         annotations_directory->GetClassAnnotation()->GetOffset();
    433     directory_buffer[1] = annotations_directory->GetFieldAnnotations() == nullptr ? 0 :
    434         annotations_directory->GetFieldAnnotations()->size();
    435     directory_buffer[2] = annotations_directory->GetMethodAnnotations() == nullptr ? 0 :
    436         annotations_directory->GetMethodAnnotations()->size();
    437     directory_buffer[3] = annotations_directory->GetParameterAnnotations() == nullptr ? 0 :
    438         annotations_directory->GetParameterAnnotations()->size();
    439     stream->Write(directory_buffer, 4 * sizeof(uint32_t));
    440     if (annotations_directory->GetFieldAnnotations() != nullptr) {
    441       for (std::unique_ptr<dex_ir::FieldAnnotation>& field :
    442           *annotations_directory->GetFieldAnnotations()) {
    443         annotation_buffer[0] = field->GetFieldId()->GetIndex();
    444         annotation_buffer[1] = field->GetAnnotationSetItem()->GetOffset();
    445         stream->Write(annotation_buffer, 2 * sizeof(uint32_t));
    446       }
    447     }
    448     if (annotations_directory->GetMethodAnnotations() != nullptr) {
    449       for (std::unique_ptr<dex_ir::MethodAnnotation>& method :
    450           *annotations_directory->GetMethodAnnotations()) {
    451         annotation_buffer[0] = method->GetMethodId()->GetIndex();
    452         annotation_buffer[1] = method->GetAnnotationSetItem()->GetOffset();
    453         stream->Write(annotation_buffer, 2 * sizeof(uint32_t));
    454       }
    455     }
    456     if (annotations_directory->GetParameterAnnotations() != nullptr) {
    457       for (std::unique_ptr<dex_ir::ParameterAnnotation>& parameter :
    458           *annotations_directory->GetParameterAnnotations()) {
    459         annotation_buffer[0] = parameter->GetMethodId()->GetIndex();
    460         annotation_buffer[1] = parameter->GetAnnotations()->GetOffset();
    461         stream->Write(annotation_buffer, 2 * sizeof(uint32_t));
    462       }
    463     }
    464   }
    465   if (compute_offsets_ && start != stream->Tell()) {
    466     header_->GetCollections().SetAnnotationsDirectoryItemsOffset(start);
    467   }
    468 }
    469 
    470 void DexWriter::WriteDebugInfoItem(Stream* stream, dex_ir::DebugInfoItem* debug_info) {
    471   stream->AlignTo(SectionAlignment(DexFile::kDexTypeDebugInfoItem));
    472   ProcessOffset(stream, debug_info);
    473   stream->Write(debug_info->GetDebugInfo(), debug_info->GetDebugInfoSize());
    474 }
    475 
    476 void DexWriter::WriteDebugInfoItems(Stream* stream) {
    477   const uint32_t start = stream->Tell();
    478   for (std::unique_ptr<dex_ir::DebugInfoItem>& debug_info :
    479       header_->GetCollections().DebugInfoItems()) {
    480     WriteDebugInfoItem(stream, debug_info.get());
    481   }
    482   if (compute_offsets_ && start != stream->Tell()) {
    483     header_->GetCollections().SetDebugInfoItemsOffset(start);
    484   }
    485 }
    486 
    487 void DexWriter::WriteCodeItemPostInstructionData(Stream* stream,
    488                                                  dex_ir::CodeItem* code_item,
    489                                                  bool reserve_only) {
    490   if (code_item->TriesSize() != 0) {
    491     stream->AlignTo(DexFile::TryItem::kAlignment);
    492     // Write try items.
    493     for (std::unique_ptr<const dex_ir::TryItem>& try_item : *code_item->Tries()) {
    494       DexFile::TryItem disk_try_item;
    495       if (!reserve_only) {
    496         disk_try_item.start_addr_ = try_item->StartAddr();
    497         disk_try_item.insn_count_ = try_item->InsnCount();
    498         disk_try_item.handler_off_ = try_item->GetHandlers()->GetListOffset();
    499       }
    500       stream->Write(&disk_try_item, sizeof(disk_try_item));
    501     }
    502     // Leave offset pointing to the end of the try items.
    503     const size_t offset = stream->Tell();
    504     size_t max_offset = offset + stream->WriteUleb128(code_item->Handlers()->size());
    505     for (std::unique_ptr<const dex_ir::CatchHandler>& handlers : *code_item->Handlers()) {
    506       stream->Seek(offset + handlers->GetListOffset());
    507       uint32_t size = handlers->HasCatchAll() ? (handlers->GetHandlers()->size() - 1) * -1 :
    508           handlers->GetHandlers()->size();
    509       stream->WriteSleb128(size);
    510       for (std::unique_ptr<const dex_ir::TypeAddrPair>& handler : *handlers->GetHandlers()) {
    511         if (handler->GetTypeId() != nullptr) {
    512           stream->WriteUleb128(handler->GetTypeId()->GetIndex());
    513         }
    514         stream->WriteUleb128(handler->GetAddress());
    515       }
    516       // TODO: Clean this up to write the handlers in address order.
    517       max_offset = std::max(max_offset, stream->Tell());
    518     }
    519     stream->Seek(max_offset);
    520   }
    521 }
    522 
    523 void DexWriter::WriteCodeItem(Stream* stream,
    524                               dex_ir::CodeItem* code_item,
    525                               bool reserve_only) {
    526   DCHECK(code_item != nullptr);
    527   const uint32_t start_offset = stream->Tell();
    528   stream->AlignTo(SectionAlignment(DexFile::kDexTypeCodeItem));
    529   ProcessOffset(stream, code_item);
    530 
    531   StandardDexFile::CodeItem disk_code_item;
    532   if (!reserve_only) {
    533     disk_code_item.registers_size_ = code_item->RegistersSize();
    534     disk_code_item.ins_size_ = code_item->InsSize();
    535     disk_code_item.outs_size_ = code_item->OutsSize();
    536     disk_code_item.tries_size_ = code_item->TriesSize();
    537     disk_code_item.debug_info_off_ = code_item->DebugInfo() == nullptr
    538         ? 0
    539         : code_item->DebugInfo()->GetOffset();
    540     disk_code_item.insns_size_in_code_units_ = code_item->InsnsSize();
    541   }
    542   // Avoid using sizeof so that we don't write the fake instruction array at the end of the code
    543   // item.
    544   stream->Write(&disk_code_item, OFFSETOF_MEMBER(StandardDexFile::CodeItem, insns_));
    545   // Write the instructions.
    546   stream->Write(code_item->Insns(), code_item->InsnsSize() * sizeof(uint16_t));
    547   // Write the post instruction data.
    548   WriteCodeItemPostInstructionData(stream, code_item, reserve_only);
    549   if (reserve_only) {
    550     stream->Clear(start_offset, stream->Tell() - start_offset);
    551   }
    552 }
    553 
    554 void DexWriter::WriteCodeItems(Stream* stream, bool reserve_only) {
    555   DexLayoutSection* code_section = nullptr;
    556   if (!reserve_only && dex_layout_ != nullptr) {
    557     code_section = &dex_layout_->GetSections().sections_[static_cast<size_t>(
    558         DexLayoutSections::SectionType::kSectionTypeCode)];
    559   }
    560   const uint32_t start = stream->Tell();
    561   for (auto& code_item : header_->GetCollections().CodeItems()) {
    562     uint32_t start_offset = stream->Tell();
    563     WriteCodeItem(stream, code_item.get(), reserve_only);
    564     // Only add the section hotness info once.
    565     if (!reserve_only && code_section != nullptr) {
    566       auto it = dex_layout_->LayoutHotnessInfo().code_item_layout_.find(code_item.get());
    567       if (it != dex_layout_->LayoutHotnessInfo().code_item_layout_.end()) {
    568         code_section->parts_[static_cast<size_t>(it->second)].CombineSection(
    569             start_offset,
    570             stream->Tell());
    571       }
    572     }
    573   }
    574 
    575   if (compute_offsets_ && start != stream->Tell()) {
    576     header_->GetCollections().SetCodeItemsOffset(start);
    577   }
    578 }
    579 
    580 void DexWriter::WriteClassDefs(Stream* stream, bool reserve_only) {
    581   const uint32_t start = stream->Tell();
    582   uint32_t class_def_buffer[8];
    583   for (std::unique_ptr<dex_ir::ClassDef>& class_def : header_->GetCollections().ClassDefs()) {
    584     stream->AlignTo(SectionAlignment(DexFile::kDexTypeClassDefItem));
    585     if (reserve_only) {
    586       stream->Skip(class_def->GetSize());
    587     } else {
    588       class_def_buffer[0] = class_def->ClassType()->GetIndex();
    589       class_def_buffer[1] = class_def->GetAccessFlags();
    590       class_def_buffer[2] = class_def->Superclass() == nullptr ? dex::kDexNoIndex :
    591           class_def->Superclass()->GetIndex();
    592       class_def_buffer[3] = class_def->InterfacesOffset();
    593       class_def_buffer[4] = class_def->SourceFile() == nullptr ? dex::kDexNoIndex :
    594           class_def->SourceFile()->GetIndex();
    595       class_def_buffer[5] = class_def->Annotations() == nullptr ? 0 :
    596           class_def->Annotations()->GetOffset();
    597       class_def_buffer[6] = class_def->GetClassData() == nullptr ? 0 :
    598           class_def->GetClassData()->GetOffset();
    599       class_def_buffer[7] = class_def->StaticValues() == nullptr ? 0 :
    600           class_def->StaticValues()->GetOffset();
    601       stream->Write(class_def_buffer, class_def->GetSize());
    602     }
    603   }
    604   if (compute_offsets_ && start != stream->Tell()) {
    605     header_->GetCollections().SetClassDefsOffset(start);
    606   }
    607 }
    608 
    609 void DexWriter::WriteClassDatas(Stream* stream) {
    610   const uint32_t start = stream->Tell();
    611   for (const std::unique_ptr<dex_ir::ClassData>& class_data :
    612       header_->GetCollections().ClassDatas()) {
    613     stream->AlignTo(SectionAlignment(DexFile::kDexTypeClassDataItem));
    614     ProcessOffset(stream, class_data.get());
    615     stream->WriteUleb128(class_data->StaticFields()->size());
    616     stream->WriteUleb128(class_data->InstanceFields()->size());
    617     stream->WriteUleb128(class_data->DirectMethods()->size());
    618     stream->WriteUleb128(class_data->VirtualMethods()->size());
    619     WriteEncodedFields(stream, class_data->StaticFields());
    620     WriteEncodedFields(stream, class_data->InstanceFields());
    621     WriteEncodedMethods(stream, class_data->DirectMethods());
    622     WriteEncodedMethods(stream, class_data->VirtualMethods());
    623   }
    624   if (compute_offsets_ && start != stream->Tell()) {
    625     header_->GetCollections().SetClassDatasOffset(start);
    626   }
    627 }
    628 
    629 void DexWriter::WriteCallSiteIds(Stream* stream, bool reserve_only) {
    630   const uint32_t start = stream->Tell();
    631   uint32_t call_site_off[1];
    632   for (std::unique_ptr<dex_ir::CallSiteId>& call_site_id :
    633       header_->GetCollections().CallSiteIds()) {
    634     stream->AlignTo(SectionAlignment(DexFile::kDexTypeCallSiteIdItem));
    635     if (reserve_only) {
    636       stream->Skip(call_site_id->GetSize());
    637     } else {
    638       call_site_off[0] = call_site_id->CallSiteItem()->GetOffset();
    639       stream->Write(call_site_off, call_site_id->GetSize());
    640     }
    641   }
    642   if (compute_offsets_ && start != stream->Tell()) {
    643     header_->GetCollections().SetCallSiteIdsOffset(start);
    644   }
    645 }
    646 
    647 void DexWriter::WriteMethodHandles(Stream* stream) {
    648   const uint32_t start = stream->Tell();
    649   uint16_t method_handle_buff[4];
    650   for (std::unique_ptr<dex_ir::MethodHandleItem>& method_handle :
    651       header_->GetCollections().MethodHandleItems()) {
    652     stream->AlignTo(SectionAlignment(DexFile::kDexTypeMethodHandleItem));
    653     method_handle_buff[0] = static_cast<uint16_t>(method_handle->GetMethodHandleType());
    654     method_handle_buff[1] = 0;  // unused.
    655     method_handle_buff[2] = method_handle->GetFieldOrMethodId()->GetIndex();
    656     method_handle_buff[3] = 0;  // unused.
    657     stream->Write(method_handle_buff, method_handle->GetSize());
    658   }
    659   if (compute_offsets_ && start != stream->Tell()) {
    660     header_->GetCollections().SetMethodHandleItemsOffset(start);
    661   }
    662 }
    663 
    664 void DexWriter::WriteMapItems(Stream* stream, MapItemQueue* queue) {
    665   // All the sections should already have been added.
    666   const uint32_t map_list_size = queue->size();
    667   stream->Write(&map_list_size, sizeof(map_list_size));
    668   while (!queue->empty()) {
    669     const MapItem& item = queue->top();
    670     DexFile::MapItem map_item;
    671     map_item.type_ = item.type_;
    672     map_item.size_ = item.size_;
    673     map_item.offset_ = item.offset_;
    674     map_item.unused_ = 0u;
    675     stream->Write(&map_item, sizeof(map_item));
    676     queue->pop();
    677   }
    678 }
    679 
    680 void DexWriter::GenerateAndWriteMapItems(Stream* stream) {
    681   dex_ir::Collections& collection = header_->GetCollections();
    682   MapItemQueue queue;
    683 
    684   // Header and index section.
    685   queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeHeaderItem, 1, 0));
    686   queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeStringIdItem,
    687                               collection.StringIdsSize(),
    688                               collection.StringIdsOffset()));
    689   queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeTypeIdItem,
    690                               collection.TypeIdsSize(),
    691                               collection.TypeIdsOffset()));
    692   queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeProtoIdItem,
    693                               collection.ProtoIdsSize(),
    694                               collection.ProtoIdsOffset()));
    695   queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeFieldIdItem,
    696                               collection.FieldIdsSize(),
    697                               collection.FieldIdsOffset()));
    698   queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeMethodIdItem,
    699                               collection.MethodIdsSize(),
    700                               collection.MethodIdsOffset()));
    701   queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeClassDefItem,
    702                               collection.ClassDefsSize(),
    703                               collection.ClassDefsOffset()));
    704   queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeCallSiteIdItem,
    705                               collection.CallSiteIdsSize(),
    706                               collection.CallSiteIdsOffset()));
    707   queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeMethodHandleItem,
    708                               collection.MethodHandleItemsSize(),
    709                               collection.MethodHandleItemsOffset()));
    710   // Data section.
    711   queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeMapList, 1, collection.MapListOffset()));
    712   queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeTypeList,
    713                               collection.TypeListsSize(),
    714                               collection.TypeListsOffset()));
    715   queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeAnnotationSetRefList,
    716                               collection.AnnotationSetRefListsSize(),
    717                               collection.AnnotationSetRefListsOffset()));
    718   queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeAnnotationSetItem,
    719                               collection.AnnotationSetItemsSize(),
    720                               collection.AnnotationSetItemsOffset()));
    721   queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeClassDataItem,
    722                               collection.ClassDatasSize(),
    723                               collection.ClassDatasOffset()));
    724   queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeCodeItem,
    725                               collection.CodeItemsSize(),
    726                               collection.CodeItemsOffset()));
    727   queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeStringDataItem,
    728                               collection.StringDatasSize(),
    729                               collection.StringDatasOffset()));
    730   queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeDebugInfoItem,
    731                               collection.DebugInfoItemsSize(),
    732                               collection.DebugInfoItemsOffset()));
    733   queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeAnnotationItem,
    734                               collection.AnnotationItemsSize(),
    735                               collection.AnnotationItemsOffset()));
    736   queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeEncodedArrayItem,
    737                               collection.EncodedArrayItemsSize(),
    738                               collection.EncodedArrayItemsOffset()));
    739   queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeAnnotationsDirectoryItem,
    740                               collection.AnnotationsDirectoryItemsSize(),
    741                               collection.AnnotationsDirectoryItemsOffset()));
    742   WriteMapItems(stream, &queue);
    743 }
    744 
    745 void DexWriter::WriteHeader(Stream* stream) {
    746   StandardDexFile::Header header;
    747   if (CompactDexFile::IsMagicValid(header_->Magic())) {
    748     StandardDexFile::WriteMagic(header.magic_);
    749     // TODO: Should we write older versions based on the feature flags?
    750     StandardDexFile::WriteCurrentVersion(header.magic_);
    751   } else {
    752     // Standard dex -> standard dex, just reuse the same header.
    753     static constexpr size_t kMagicAndVersionLen =
    754         StandardDexFile::kDexMagicSize + StandardDexFile::kDexVersionLen;
    755     std::copy_n(header_->Magic(), kMagicAndVersionLen, header.magic_);
    756   }
    757   header.checksum_ = header_->Checksum();
    758   std::copy_n(header_->Signature(), DexFile::kSha1DigestSize, header.signature_);
    759   header.file_size_ = header_->FileSize();
    760   header.header_size_ = GetHeaderSize();
    761   header.endian_tag_ = header_->EndianTag();
    762   header.link_size_ = header_->LinkSize();
    763   header.link_off_ = header_->LinkOffset();
    764   const dex_ir::Collections& collections = header_->GetCollections();
    765   header.map_off_ = collections.MapListOffset();
    766   header.string_ids_size_ = collections.StringIdsSize();
    767   header.string_ids_off_ = collections.StringIdsOffset();
    768   header.type_ids_size_ = collections.TypeIdsSize();
    769   header.type_ids_off_ = collections.TypeIdsOffset();
    770   header.proto_ids_size_ = collections.ProtoIdsSize();
    771   header.proto_ids_off_ = collections.ProtoIdsOffset();
    772   header.field_ids_size_ = collections.FieldIdsSize();
    773   header.field_ids_off_ = collections.FieldIdsOffset();
    774   header.method_ids_size_ = collections.MethodIdsSize();
    775   header.method_ids_off_ = collections.MethodIdsOffset();
    776   header.class_defs_size_ = collections.ClassDefsSize();
    777   header.class_defs_off_ = collections.ClassDefsOffset();
    778   header.data_size_ = header_->DataSize();
    779   header.data_off_ = header_->DataOffset();
    780 
    781   CHECK_EQ(sizeof(header), GetHeaderSize());
    782   static_assert(sizeof(header) == 0x70, "Size doesn't match dex spec");
    783   stream->Seek(0);
    784   stream->Overwrite(reinterpret_cast<uint8_t*>(&header), sizeof(header));
    785 }
    786 
    787 size_t DexWriter::GetHeaderSize() const {
    788   return sizeof(StandardDexFile::Header);
    789 }
    790 
    791 bool DexWriter::Write(DexContainer* output, std::string* error_msg) {
    792   DCHECK(error_msg != nullptr);
    793 
    794   Stream stream_storage(output->GetMainSection());
    795   Stream* stream = &stream_storage;
    796 
    797   // Starting offset is right after the header.
    798   stream->Seek(GetHeaderSize());
    799 
    800   dex_ir::Collections& collection = header_->GetCollections();
    801 
    802   // Based on: https://source.android.com/devices/tech/dalvik/dex-format
    803   // Since the offsets may not be calculated already, the writing must be done in the correct order.
    804   const uint32_t string_ids_offset = stream->Tell();
    805   WriteStringIds(stream, /*reserve_only*/ true);
    806   WriteTypeIds(stream);
    807   const uint32_t proto_ids_offset = stream->Tell();
    808   WriteProtoIds(stream, /*reserve_only*/ true);
    809   WriteFieldIds(stream);
    810   WriteMethodIds(stream);
    811   const uint32_t class_defs_offset = stream->Tell();
    812   WriteClassDefs(stream, /*reserve_only*/ true);
    813   const uint32_t call_site_ids_offset = stream->Tell();
    814   WriteCallSiteIds(stream, /*reserve_only*/ true);
    815   WriteMethodHandles(stream);
    816 
    817   uint32_t data_offset_ = 0u;
    818   if (compute_offsets_) {
    819     // Data section.
    820     stream->AlignTo(kDataSectionAlignment);
    821     data_offset_ = stream->Tell();
    822   }
    823 
    824   // Write code item first to minimize the space required for encoded methods.
    825   // Reserve code item space since we need the debug offsets to actually write them.
    826   const uint32_t code_items_offset = stream->Tell();
    827   WriteCodeItems(stream, /*reserve_only*/ true);
    828   // Write debug info section.
    829   WriteDebugInfoItems(stream);
    830   {
    831     // Actually write code items since debug info offsets are calculated now.
    832     Stream::ScopedSeek seek(stream, code_items_offset);
    833     WriteCodeItems(stream, /*reserve_only*/ false);
    834   }
    835 
    836   WriteEncodedArrays(stream);
    837   WriteAnnotations(stream);
    838   WriteAnnotationSets(stream);
    839   WriteAnnotationSetRefs(stream);
    840   WriteAnnotationsDirectories(stream);
    841   WriteTypeLists(stream);
    842   WriteClassDatas(stream);
    843   WriteStringDatas(stream);
    844 
    845   // Write delayed id sections that depend on data sections.
    846   {
    847     Stream::ScopedSeek seek(stream, string_ids_offset);
    848     WriteStringIds(stream, /*reserve_only*/ false);
    849   }
    850   {
    851     Stream::ScopedSeek seek(stream, proto_ids_offset);
    852     WriteProtoIds(stream, /*reserve_only*/ false);
    853   }
    854   {
    855     Stream::ScopedSeek seek(stream, class_defs_offset);
    856     WriteClassDefs(stream, /*reserve_only*/ false);
    857   }
    858   {
    859     Stream::ScopedSeek seek(stream, call_site_ids_offset);
    860     WriteCallSiteIds(stream, /*reserve_only*/ false);
    861   }
    862 
    863   // Write the map list.
    864   if (compute_offsets_) {
    865     stream->AlignTo(SectionAlignment(DexFile::kDexTypeMapList));
    866     collection.SetMapListOffset(stream->Tell());
    867   } else {
    868     stream->Seek(collection.MapListOffset());
    869   }
    870   GenerateAndWriteMapItems(stream);
    871   stream->AlignTo(kDataSectionAlignment);
    872 
    873   // Map items are included in the data section.
    874   if (compute_offsets_) {
    875     header_->SetDataSize(stream->Tell() - data_offset_);
    876     if (header_->DataSize() != 0) {
    877       // Offset must be zero when the size is zero.
    878       header_->SetDataOffset(data_offset_);
    879     } else {
    880       header_->SetDataOffset(0u);
    881     }
    882   }
    883 
    884   // Write link data if it exists.
    885   const std::vector<uint8_t>& link_data = collection.LinkData();
    886   if (link_data.size() > 0) {
    887     CHECK_EQ(header_->LinkSize(), static_cast<uint32_t>(link_data.size()));
    888     if (compute_offsets_) {
    889       header_->SetLinkOffset(stream->Tell());
    890     } else {
    891       stream->Seek(header_->LinkOffset());
    892     }
    893     stream->Write(&link_data[0], link_data.size());
    894   }
    895 
    896   // Write header last.
    897   if (compute_offsets_) {
    898     header_->SetFileSize(stream->Tell());
    899   }
    900   WriteHeader(stream);
    901 
    902   if (dex_layout_->GetOptions().update_checksum_) {
    903     header_->SetChecksum(DexFile::CalculateChecksum(stream->Begin(), header_->FileSize()));
    904     // Rewrite the header with the calculated checksum.
    905     WriteHeader(stream);
    906   }
    907 
    908   // Trim the map to make it sized as large as the dex file.
    909   output->GetMainSection()->Resize(header_->FileSize());
    910   return true;
    911 }
    912 
    913 bool DexWriter::Output(DexLayout* dex_layout,
    914                        std::unique_ptr<DexContainer>* container,
    915                        bool compute_offsets,
    916                        std::string* error_msg) {
    917   CHECK(dex_layout != nullptr);
    918   std::unique_ptr<DexWriter> writer;
    919   if (dex_layout->GetOptions().compact_dex_level_ != CompactDexLevel::kCompactDexLevelNone) {
    920     CHECK(compute_offsets) << "Compact dex requires computing offsets";
    921     writer.reset(new CompactDexWriter(dex_layout));
    922   } else {
    923     writer.reset(new DexWriter(dex_layout, compute_offsets));
    924   }
    925   DCHECK(container != nullptr);
    926   if (*container == nullptr) {
    927     *container = writer->CreateDexContainer();
    928   }
    929   return writer->Write(container->get(), error_msg);
    930 }
    931 
    932 void MapItemQueue::AddIfNotEmpty(const MapItem& item) {
    933   if (item.size_ != 0) {
    934     push(item);
    935   }
    936 }
    937 
    938 void DexWriter::ProcessOffset(Stream* stream, dex_ir::Item* item) {
    939   if (compute_offsets_) {
    940     item->SetOffset(stream->Tell());
    941   } else {
    942     // Not computing offsets, just use the one in the item.
    943     stream->Seek(item->GetOffset());
    944   }
    945 }
    946 
    947 std::unique_ptr<DexContainer> DexWriter::CreateDexContainer() const {
    948   return std::unique_ptr<DexContainer>(new DexWriter::Container);
    949 }
    950 
    951 }  // namespace art
    952