• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
EncodeIntValue(int32_t value,uint8_t * buffer)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 
EncodeUIntValue(uint32_t value,uint8_t * buffer)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 
EncodeLongValue(int64_t value,uint8_t * buffer)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 
EncodeFloatValue(float value,uint8_t * buffer)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 
EncodeDoubleValue(double value,uint8_t * buffer)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 
DexWriter(DexLayout * dex_layout,bool compute_offsets)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 
WriteEncodedValue(Stream * stream,dex_ir::EncodedValue * encoded_value)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 
WriteEncodedValueHeader(Stream * stream,int8_t value_type,size_t value_arg)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 
WriteEncodedArray(Stream * stream,dex_ir::EncodedValueVector * values)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 
WriteEncodedAnnotation(Stream * stream,dex_ir::EncodedAnnotation * annotation)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 
WriteEncodedFields(Stream * stream,dex_ir::FieldItemVector * fields)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 
WriteEncodedMethods(Stream * stream,dex_ir::MethodItemVector * methods)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.
WriteStringIds(Stream * stream,bool reserve_only)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 
WriteStringData(Stream * stream,dex_ir::StringData * string_data)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 
WriteStringDatas(Stream * stream)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 
WriteTypeIds(Stream * stream)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 
WriteTypeLists(Stream * stream)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 
WriteProtoIds(Stream * stream,bool reserve_only)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 
WriteFieldIds(Stream * stream)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 
WriteMethodIds(Stream * stream)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 
WriteEncodedArrays(Stream * stream)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 
WriteAnnotations(Stream * stream)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 
WriteAnnotationSets(Stream * stream)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 
WriteAnnotationSetRefs(Stream * stream)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 
WriteAnnotationsDirectories(Stream * stream)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 
WriteHiddenapiClassData(Stream * stream)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 
WriteDebugInfoItem(Stream * stream,dex_ir::DebugInfoItem * debug_info)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 
WriteDebugInfoItems(Stream * stream)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 
WriteCodeItemPostInstructionData(Stream * stream,dex_ir::CodeItem * code_item,bool reserve_only)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 
WriteCodeItem(Stream * stream,dex_ir::CodeItem * code_item,bool reserve_only)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 
WriteCodeItems(Stream * stream,bool reserve_only)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 
WriteClassDefs(Stream * stream,bool reserve_only)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 
WriteClassDatas(Stream * stream)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 
WriteCallSiteIds(Stream * stream,bool reserve_only)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 
WriteMethodHandles(Stream * stream)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 
WriteMapItems(Stream * stream,MapItemQueue * queue)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 
GenerateAndWriteMapItems(Stream * stream)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 
WriteHeader(Stream * stream)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 
GetHeaderSize() const834 size_t DexWriter::GetHeaderSize() const {
835   return sizeof(StandardDexFile::Header);
836 }
837 
Write(DexContainer * output,std::string * error_msg)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 
Output(DexLayout * dex_layout,std::unique_ptr<DexContainer> * container,bool compute_offsets,std::string * error_msg)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 
AddIfNotEmpty(const MapItem & item)978 void MapItemQueue::AddIfNotEmpty(const MapItem& item) {
979   if (item.size_ != 0) {
980     push(item);
981   }
982 }
983 
ProcessOffset(Stream * stream,dex_ir::Item * item)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 
ProcessOffset(Stream * stream,dex_ir::CollectionBase * item)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 
CreateDexContainer() const1002 std::unique_ptr<DexContainer> DexWriter::CreateDexContainer() const {
1003   return std::unique_ptr<DexContainer>(new DexWriter::Container);
1004 }
1005 
1006 }  // namespace art
1007