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