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