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