1 /*
2 * Copyright (C) 2017 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 "slicer/writer.h"
18 #include "slicer/common.h"
19 #include "slicer/scopeguard.h"
20 #include "slicer/dex_bytecode.h"
21 #include "slicer/dex_format.h"
22 #include "slicer/dex_ir.h"
23 #include "slicer/dex_leb128.h"
24
25 #include <assert.h>
26 #include <type_traits>
27 #include <vector>
28 #include <cstdlib>
29 #include <string.h>
30 #include <algorithm>
31
32 namespace dex {
33
34 // Returns the IR node index, or kNoIndex for null IR nodes
35 template <class T>
OptIndex(const T * ir_node)36 static dex::u4 OptIndex(const T* ir_node) {
37 return ir_node != nullptr ? ir_node->index : dex::kNoIndex;
38 }
39
40 // Helper for creating the header of an encoded value
WriteEncodedValueHeader(dex::u1 type,int arg,Section & data)41 static void WriteEncodedValueHeader(dex::u1 type, int arg, Section& data) {
42 assert((type & ~dex::kEncodedValueTypeMask) == 0);
43 assert(arg >= 0 && arg < 8);
44 dex::u1 header = dex::u1(type | (arg << dex::kEncodedValueArgShift));
45 data.Push<dex::u1>(header);
46 }
47
48 // Writes an integer encoded value
49 template <class T>
WriteIntValue(dex::u1 type,T value,Section & data)50 static void WriteIntValue(dex::u1 type, T value, Section& data) {
51 dex::u1 buff[sizeof(T)] = {};
52 dex::u1* dst = buff;
53
54 if (std::is_signed<T>::value) {
55 const bool positive = (value >= 0);
56 while (positive ? value >= 0x80 : value < -0x80) {
57 *dst++ = value & 0xff;
58 value >>= 8;
59 }
60 *dst++ = value & 0xff;
61 } else {
62 do {
63 *dst++ = value & 0xff;
64 value >>= 8;
65 } while (value != 0);
66 }
67
68 size_t size = dst - buff;
69 assert(size > 0 && size <= sizeof(T));
70 WriteEncodedValueHeader(type, size - 1, data);
71 data.Push(buff, size);
72 }
73
74 // Writes a floating point encoded value
75 template <class T>
WriteFloatValue(dex::u1 type,T value,Section & data)76 static void WriteFloatValue(dex::u1 type, T value, Section& data) {
77 dex::u1 buff[sizeof(T)] = {};
78 auto src = reinterpret_cast<const dex::u1*>(&value);
79 size_t size = sizeof(T);
80
81 // skip "rightmost" zero bytes
82 while (size > 1 && *src == 0) {
83 --size;
84 ++src;
85 }
86
87 // copy the rest...
88 for (size_t i = 0; i < size; ++i) {
89 buff[i] = src[i];
90 }
91
92 assert(size > 0 && size <= sizeof(T));
93 WriteEncodedValueHeader(type, size - 1, data);
94 data.Push(buff, size);
95 }
96
97 static void WriteEncodedArray(const ir::EncodedArray* ir_array, Section& data);
98 static void WriteAnnotation(const ir::Annotation* ir_annotation, Section& data);
99
100 // "encoded_value"
WriteEncodedValue(const ir::EncodedValue * ir_value,Section & data)101 static void WriteEncodedValue(const ir::EncodedValue* ir_value, Section& data) {
102 SLICER_EXTRA(auto offset = data.size());
103
104 dex::u1 type = ir_value->type;
105 switch (type) {
106 case dex::kEncodedByte:
107 WriteIntValue(type, ir_value->u.byte_value, data);
108 break;
109
110 case dex::kEncodedShort:
111 WriteIntValue(type, ir_value->u.short_value, data);
112 break;
113
114 case dex::kEncodedChar:
115 WriteIntValue(type, ir_value->u.char_value, data);
116 break;
117
118 case dex::kEncodedInt:
119 WriteIntValue(type, ir_value->u.int_value, data);
120 break;
121
122 case dex::kEncodedLong:
123 WriteIntValue(type, ir_value->u.long_value, data);
124 break;
125
126 case dex::kEncodedFloat:
127 WriteFloatValue(type, ir_value->u.float_value, data);
128 break;
129
130 case dex::kEncodedDouble:
131 WriteFloatValue(type, ir_value->u.double_value, data);
132 break;
133
134 case dex::kEncodedString:
135 WriteIntValue<dex::u4>(type, ir_value->u.string_value->index, data);
136 break;
137
138 case dex::kEncodedType:
139 WriteIntValue<dex::u4>(type, ir_value->u.type_value->index, data);
140 break;
141
142 case dex::kEncodedField:
143 WriteIntValue<dex::u4>(type, ir_value->u.field_value->index, data);
144 break;
145
146 case dex::kEncodedMethod:
147 WriteIntValue<dex::u4>(type, ir_value->u.method_value->index, data);
148 break;
149
150 case dex::kEncodedEnum:
151 WriteIntValue<dex::u4>(type, ir_value->u.enum_value->index, data);
152 break;
153
154 case dex::kEncodedArray:
155 WriteEncodedValueHeader(type, 0, data);
156 WriteEncodedArray(ir_value->u.array_value, data);
157 break;
158
159 case dex::kEncodedAnnotation:
160 WriteEncodedValueHeader(type, 0, data);
161 WriteAnnotation(ir_value->u.annotation_value, data);
162 break;
163
164 case dex::kEncodedNull:
165 WriteEncodedValueHeader(type, 0, data);
166 break;
167
168 case dex::kEncodedBoolean: {
169 int arg = ir_value->u.bool_value ? 1 : 0;
170 WriteEncodedValueHeader(type, arg, data);
171 } break;
172
173 default:
174 SLICER_CHECK(!"unexpected value type");
175 }
176
177 // optionally check the encoding against the original one
178 // (if possible, some of the values contain relocated indexes)
179 SLICER_EXTRA({
180 switch (type) {
181 case dex::kEncodedByte:
182 case dex::kEncodedShort:
183 case dex::kEncodedChar:
184 case dex::kEncodedInt:
185 case dex::kEncodedLong:
186 case dex::kEncodedFloat:
187 case dex::kEncodedDouble:
188 case dex::kEncodedNull:
189 case dex::kEncodedBoolean:
190 auto ptr = data.ptr<const dex::u1>(offset);
191 auto size = data.size() - offset;
192 SLICER_CHECK(size == ir_value->original.size());
193 SLICER_CHECK(memcmp(ptr, ir_value->original.ptr(), size) == 0);
194 break;
195 }
196 });
197 }
198
199 // "encoded_annotation"
WriteAnnotation(const ir::Annotation * ir_annotation,Section & data)200 static void WriteAnnotation(const ir::Annotation* ir_annotation, Section& data) {
201 data.PushULeb128(ir_annotation->type->index);
202 data.PushULeb128(ir_annotation->elements.size());
203 for (auto irAnnotationElement : ir_annotation->elements) {
204 data.PushULeb128(irAnnotationElement->name->index);
205 WriteEncodedValue(irAnnotationElement->value, data);
206 }
207 }
208
209 // "encoded_array"
WriteEncodedArray(const ir::EncodedArray * ir_array,Section & data)210 static void WriteEncodedArray(const ir::EncodedArray* ir_array, Section& data) {
211 const auto& values = ir_array->values;
212 data.PushULeb128(values.size());
213 for (auto irEncodedValue : values) {
214 WriteEncodedValue(irEncodedValue, data);
215 }
216 }
217
218 // helper for concatenating .dex sections into the final image
219 template <class T>
CopySection(const T & section,dex::u1 * image,dex::u4 image_size)220 static void CopySection(const T& section, dex::u1* image, dex::u4 image_size) {
221 if (section.size() == 0) {
222 SLICER_CHECK(section.ItemsCount() == 0);
223 return;
224 }
225
226 SLICER_CHECK(section.ItemsCount() > 0);
227 dex::u4 offset = section.SectionOffset();
228 dex::u4 size = section.size();
229 SLICER_CHECK(offset >= sizeof(dex::Header));
230 SLICER_CHECK(offset + size <= image_size);
231
232 ::memcpy(image + offset, section.data(), size);
233 }
234
ReadU4(const u2 * ptr)235 static u4 ReadU4(const u2* ptr) { return ptr[0] | (u4(ptr[1]) << 16); }
236
WriteU4(u2 * ptr,u4 val)237 static void WriteU4(u2* ptr, u4 val) {
238 ptr[0] = val & 0xffff;
239 ptr[1] = val >> 16;
240 }
241
242 // This is the main interface for the .dex writer
243 // (returns nullptr on failure)
CreateImage(Allocator * allocator,size_t * new_image_size)244 dex::u1* Writer::CreateImage(Allocator* allocator, size_t* new_image_size) {
245 // create a new DexImage
246 dex_.reset(new DexImage);
247
248 SLICER_SCOPE_EXIT {
249 dex_.reset();
250 };
251
252 // TODO: revisit IR normalization
253 // (ideally we shouldn't change the IR while generating an image)
254 dex_ir_->Normalize();
255
256 // track the current offset within the .dex image
257 dex::u4 offset = 0;
258
259 // allocate the image and index sections
260 // (they will be back-filled)
261 offset += sizeof(dex::Header);
262 offset += dex_->string_ids.Init(offset, dex_ir_->strings.size());
263 offset += dex_->type_ids.Init(offset, dex_ir_->types.size());
264 offset += dex_->proto_ids.Init(offset, dex_ir_->protos.size());
265 offset += dex_->field_ids.Init(offset, dex_ir_->fields.size());
266 offset += dex_->method_ids.Init(offset, dex_ir_->methods.size());
267 offset += dex_->class_defs.Init(offset, dex_ir_->classes.size());
268
269 // the base offset for the "data" meta-section
270 SLICER_CHECK(offset % 4 == 0);
271 const dex::u4 data_offset = offset;
272
273 // we must create the sections in a very specific
274 // order due to file pointers across sections
275 offset += CreateStringDataSection(offset);
276 offset += CreateTypeListsSection(offset);
277 offset += CreateDebugInfoSection(offset);
278 offset += CreateEncodedArrayItemSection(offset);
279 offset += CreateCodeItemSection(offset);
280 offset += CreateClassDataSection(offset);
281 offset += CreateAnnItemSection(offset);
282 offset += CreateAnnSetsSection(offset);
283 offset += CreateAnnSetRefListsSection(offset);
284 offset += CreateAnnDirectoriesSection(offset);
285 offset += CreateMapSection(offset);
286
287 // back-fill the indexes
288 FillTypes();
289 FillFields();
290 FillProtos();
291 FillMethods();
292 FillClassDefs();
293
294 // allocate the final buffer for the .dex image
295 SLICER_CHECK(offset % 4 == 0);
296 const dex::u4 image_size = offset;
297 dex::u1* image = static_cast<dex::u1*>(allocator->Allocate(image_size));
298 if (image == nullptr) {
299 // memory allocation failed, bailing out...
300 return nullptr;
301 }
302 memset(image, 0, image_size);
303
304 // finally, back-fill the header
305 SLICER_CHECK(image_size > sizeof(dex::Header));
306
307 dex::Header* header = reinterpret_cast<dex::Header*>(image + 0);
308
309 // magic signature
310 memcpy(header->magic, dex_ir_->magic.ptr(), dex_ir_->magic.size());
311
312 header->file_size = image_size;
313 header->header_size = sizeof(dex::Header);
314 header->endian_tag = dex::kEndianConstant;
315
316 header->link_size = 0;
317 header->link_off = 0;
318
319 header->map_off = dex_->map_list.SectionOffset();
320 header->string_ids_size = dex_->string_ids.ItemsCount();
321 header->string_ids_off = dex_->string_ids.SectionOffset();
322 header->type_ids_size = dex_->type_ids.ItemsCount();
323 header->type_ids_off = dex_->type_ids.SectionOffset();
324 header->proto_ids_size = dex_->proto_ids.ItemsCount();
325 header->proto_ids_off = dex_->proto_ids.SectionOffset();
326 header->field_ids_size = dex_->field_ids.ItemsCount();
327 header->field_ids_off = dex_->field_ids.SectionOffset();
328 header->method_ids_size = dex_->method_ids.ItemsCount();
329 header->method_ids_off = dex_->method_ids.SectionOffset();
330 header->class_defs_size = dex_->class_defs.ItemsCount();
331 header->class_defs_off = dex_->class_defs.SectionOffset();
332 header->data_size = image_size - data_offset;
333 header->data_off = data_offset;
334
335 // copy the individual sections to the final image
336 CopySection(dex_->string_ids, image, image_size);
337 CopySection(dex_->type_ids, image, image_size);
338 CopySection(dex_->proto_ids, image, image_size);
339 CopySection(dex_->field_ids, image, image_size);
340 CopySection(dex_->method_ids, image, image_size);
341 CopySection(dex_->class_defs, image, image_size);
342 CopySection(dex_->string_data, image, image_size);
343 CopySection(dex_->type_lists, image, image_size);
344 CopySection(dex_->debug_info, image, image_size);
345 CopySection(dex_->encoded_arrays, image, image_size);
346 CopySection(dex_->code, image, image_size);
347 CopySection(dex_->class_data, image, image_size);
348 CopySection(dex_->ann_directories, image, image_size);
349 CopySection(dex_->ann_set_ref_lists, image, image_size);
350 CopySection(dex_->ann_sets, image, image_size);
351 CopySection(dex_->ann_items, image, image_size);
352 CopySection(dex_->map_list, image, image_size);
353
354 // checksum
355 header->checksum = dex::ComputeChecksum(header);
356
357 *new_image_size = image_size;
358 return image;
359 }
360
361 // "string_id_item" + string data section
CreateStringDataSection(dex::u4 section_offset)362 dex::u4 Writer::CreateStringDataSection(dex::u4 section_offset) {
363 auto& section = dex_->string_data;
364 section.SetOffset(section_offset);
365
366 const auto& strings = dex_ir_->strings;
367 for (size_t i = 0; i < strings.size(); ++i) {
368 const auto& ir_string = strings[i];
369 auto dexStringId = &dex_->string_ids[i];
370
371 dex::u4 offset = section.AddItem();
372 section.Push(ir_string->data);
373 dexStringId->string_data_off = section.AbsoluteOffset(offset);
374 }
375
376 dex::u4 size = section.Seal(4);
377 return size;
378 }
379
380 // Helper for creating the map section
381 template <class T>
AddMapItem(const T & section,std::vector<dex::MapItem> & items)382 static void AddMapItem(const T& section, std::vector<dex::MapItem>& items) {
383 if (section.ItemsCount() > 0) {
384 SLICER_CHECK(section.SectionOffset() >= sizeof(dex::Header));
385 dex::MapItem map_item = {};
386 map_item.type = section.MapEntryType();
387 map_item.size = section.ItemsCount();
388 map_item.offset = section.SectionOffset();
389 items.push_back(map_item);
390 }
391 }
392
393 // map_list section
CreateMapSection(dex::u4 section_offset)394 dex::u4 Writer::CreateMapSection(dex::u4 section_offset) {
395 auto& section = dex_->map_list;
396 section.SetOffset(section_offset);
397 section.AddItem(4);
398
399 std::vector<dex::MapItem> map_items;
400
401 dex::MapItem headerItem = {};
402 headerItem.type = dex::kHeaderItem;
403 headerItem.size = 1;
404 headerItem.offset = 0;
405 map_items.push_back(headerItem);
406
407 AddMapItem(dex_->string_ids, map_items);
408 AddMapItem(dex_->type_ids, map_items);
409 AddMapItem(dex_->proto_ids, map_items);
410 AddMapItem(dex_->field_ids, map_items);
411 AddMapItem(dex_->method_ids, map_items);
412 AddMapItem(dex_->class_defs, map_items);
413 AddMapItem(dex_->string_data, map_items);
414 AddMapItem(dex_->type_lists, map_items);
415 AddMapItem(dex_->debug_info, map_items);
416 AddMapItem(dex_->encoded_arrays, map_items);
417 AddMapItem(dex_->code, map_items);
418 AddMapItem(dex_->class_data, map_items);
419 AddMapItem(dex_->ann_directories, map_items);
420 AddMapItem(dex_->ann_set_ref_lists, map_items);
421 AddMapItem(dex_->ann_sets, map_items);
422 AddMapItem(dex_->ann_items, map_items);
423 AddMapItem(dex_->map_list, map_items);
424
425 std::sort(map_items.begin(), map_items.end(),
426 [](const dex::MapItem& a, const dex::MapItem& b) {
427 SLICER_CHECK(a.offset != b.offset);
428 return a.offset < b.offset;
429 });
430
431 section.Push<dex::u4>(map_items.size());
432 section.Push(map_items);
433 return section.Seal(4);
434 }
435
436 // annotation_item section
CreateAnnItemSection(dex::u4 section_offset)437 dex::u4 Writer::CreateAnnItemSection(dex::u4 section_offset) {
438 dex_->ann_items.SetOffset(section_offset);
439
440 for (const auto& ir_node : dex_ir_->annotations) {
441 if (ir_node->visibility != dex::kVisibilityEncoded) {
442 // TODO: factor out the node_offset_ updating
443 dex::u4& offset = node_offset_[ir_node.get()];
444 SLICER_CHECK(offset == 0);
445 offset = WriteAnnotationItem(ir_node.get());
446 }
447 }
448
449 return dex_->ann_items.Seal(4);
450 }
451
452 // annotation_set_item section
CreateAnnSetsSection(dex::u4 section_offset)453 dex::u4 Writer::CreateAnnSetsSection(dex::u4 section_offset) {
454 dex_->ann_sets.SetOffset(section_offset);
455
456 for (const auto& ir_node : dex_ir_->annotation_sets) {
457 dex::u4& offset = node_offset_[ir_node.get()];
458 SLICER_CHECK(offset == 0);
459 offset = WriteAnnotationSet(ir_node.get());
460 }
461
462 return dex_->ann_sets.Seal(4);
463 }
464
465 // annotation_set_ref_list section
CreateAnnSetRefListsSection(dex::u4 section_offset)466 dex::u4 Writer::CreateAnnSetRefListsSection(dex::u4 section_offset) {
467 dex_->ann_set_ref_lists.SetOffset(section_offset);
468
469 for (const auto& ir_node : dex_ir_->annotation_set_ref_lists) {
470 dex::u4& offset = node_offset_[ir_node.get()];
471 SLICER_CHECK(offset == 0);
472 offset = WriteAnnotationSetRefList(ir_node.get());
473 }
474
475 return dex_->ann_set_ref_lists.Seal(4);
476 }
477
478 // type_list section
CreateTypeListsSection(dex::u4 section_offset)479 dex::u4 Writer::CreateTypeListsSection(dex::u4 section_offset) {
480 dex_->type_lists.SetOffset(section_offset);
481
482 for (const auto& ir_type_list : dex_ir_->type_lists) {
483 dex::u4& offset = node_offset_[ir_type_list.get()];
484 SLICER_CHECK(offset == 0);
485 offset = WriteTypeList(ir_type_list->types);
486 }
487
488 return dex_->type_lists.Seal(4);
489 }
490
491 // code_item section
CreateCodeItemSection(dex::u4 section_offset)492 dex::u4 Writer::CreateCodeItemSection(dex::u4 section_offset) {
493 dex_->code.SetOffset(section_offset);
494
495 for (const auto& ir_node : dex_ir_->code) {
496 dex::u4& offset = node_offset_[ir_node.get()];
497 SLICER_CHECK(offset == 0);
498 offset = WriteCode(ir_node.get());
499 }
500
501 dex::u4 size = dex_->code.Seal(4);
502 return size;
503 }
504
505 // debug info section
CreateDebugInfoSection(dex::u4 section_offset)506 dex::u4 Writer::CreateDebugInfoSection(dex::u4 section_offset) {
507 dex_->debug_info.SetOffset(section_offset);
508
509 for (const auto& ir_node : dex_ir_->debug_info) {
510 dex::u4& offset = node_offset_[ir_node.get()];
511 SLICER_CHECK(offset == 0);
512 offset = WriteDebugInfo(ir_node.get());
513 }
514
515 dex::u4 size = dex_->debug_info.Seal(4);
516 return size;
517 }
518
519 // class_data_item section
CreateClassDataSection(dex::u4 section_offset)520 dex::u4 Writer::CreateClassDataSection(dex::u4 section_offset) {
521 dex_->class_data.SetOffset(section_offset);
522
523 const auto& classes = dex_ir_->classes;
524 for (size_t i = 0; i < classes.size(); ++i) {
525 auto ir_class = classes[i].get();
526 auto dex_class_def = &dex_->class_defs[i];
527 dex_class_def->class_data_off = WriteClassData(ir_class);
528 }
529
530 dex::u4 size = dex_->class_data.Seal(4);
531 return size;
532 }
533
534 // annotations_directory section
CreateAnnDirectoriesSection(dex::u4 section_offset)535 dex::u4 Writer::CreateAnnDirectoriesSection(dex::u4 section_offset) {
536 dex_->ann_directories.SetOffset(section_offset);
537
538 const auto& classes = dex_ir_->classes;
539 for (size_t i = 0; i < classes.size(); ++i) {
540 auto ir_class = classes[i].get();
541 auto dex_class_def = &dex_->class_defs[i];
542 dex_class_def->annotations_off = WriteClassAnnotations(ir_class);
543 }
544
545 return dex_->ann_directories.Seal(4);
546 }
547
548 // encoded_array_item section
CreateEncodedArrayItemSection(dex::u4 section_offset)549 dex::u4 Writer::CreateEncodedArrayItemSection(dex::u4 section_offset) {
550 dex_->encoded_arrays.SetOffset(section_offset);
551
552 const auto& classes = dex_ir_->classes;
553 for (size_t i = 0; i < classes.size(); ++i) {
554 auto ir_class = classes[i].get();
555 auto dex_class_def = &dex_->class_defs[i];
556 dex_class_def->static_values_off = WriteClassStaticValues(ir_class);
557 }
558
559 return dex_->encoded_arrays.Seal(4);
560 }
561
562 // "type_id_item"
FillTypes()563 void Writer::FillTypes() {
564 const auto& types = dex_ir_->types;
565 for (size_t i = 0; i < types.size(); ++i) {
566 const auto& ir_type = types[i];
567 auto dexTypeId = &dex_->type_ids[i];
568 // CONSIDER: an automatic index check would be nice
569 dexTypeId->descriptor_idx = ir_type->descriptor->index;
570 }
571 }
572
573 // "proto_id_item"
FillProtos()574 void Writer::FillProtos() {
575 const auto& protos = dex_ir_->protos;
576 for (size_t i = 0; i < protos.size(); ++i) {
577 const auto& irProto = protos[i];
578 auto dexProtoId = &dex_->proto_ids[i];
579 dexProtoId->shorty_idx = irProto->shorty->index;
580 dexProtoId->return_type_idx = irProto->return_type->index;
581 dexProtoId->parameters_off = FilePointer(irProto->param_types);
582 }
583 }
584
585 // "field_id_item"
FillFields()586 void Writer::FillFields() {
587 const auto& fields = dex_ir_->fields;
588 for (size_t i = 0; i < fields.size(); ++i) {
589 const auto& ir_field = fields[i];
590 auto dexFieldId = &dex_->field_ids[i];
591 dexFieldId->class_idx = ir_field->parent->index;
592 dexFieldId->type_idx = ir_field->type->index;
593 dexFieldId->name_idx = ir_field->name->index;
594 }
595 }
596
597 // "method_id_item"
FillMethods()598 void Writer::FillMethods() {
599 const auto& methods = dex_ir_->methods;
600 for (size_t i = 0; i < methods.size(); ++i) {
601 const auto& ir_method = methods[i];
602 auto dexMethodId = &dex_->method_ids[i];
603 dexMethodId->class_idx = ir_method->parent->index;
604 dexMethodId->proto_idx = ir_method->prototype->index;
605 dexMethodId->name_idx = ir_method->name->index;
606 }
607 }
608
609 // "class_def_item"
FillClassDefs()610 void Writer::FillClassDefs() {
611 const auto& classes = dex_ir_->classes;
612 for (size_t i = 0; i < classes.size(); ++i) {
613 auto ir_class = classes[i].get();
614 auto dex_class_def = &dex_->class_defs[i];
615 dex_class_def->class_idx = ir_class->type->index;
616 dex_class_def->access_flags = ir_class->access_flags;
617 dex_class_def->superclass_idx = OptIndex(ir_class->super_class);
618 dex_class_def->source_file_idx = OptIndex(ir_class->source_file);
619 dex_class_def->interfaces_off = FilePointer(ir_class->interfaces);
620
621 // NOTE: we already set some offsets when we created the
622 // corresponding .dex section:
623 //
624 // ->annotations_off
625 // ->class_data_off
626 // ->static_values_off
627 }
628 }
629
630 // "type_list"
WriteTypeList(const std::vector<ir::Type * > & types)631 dex::u4 Writer::WriteTypeList(const std::vector<ir::Type*>& types) {
632 if (types.empty()) {
633 return 0;
634 }
635
636 auto& data = dex_->type_lists;
637 dex::u4 offset = data.AddItem(4);
638 data.Push<dex::u4>(types.size());
639 for (auto ir_type : types) {
640 data.Push<dex::u2>(ir_type->index);
641 }
642 return data.AbsoluteOffset(offset);
643 }
644
645 // "annotation_item"
WriteAnnotationItem(const ir::Annotation * ir_annotation)646 dex::u4 Writer::WriteAnnotationItem(const ir::Annotation* ir_annotation) {
647 SLICER_CHECK(ir_annotation->visibility != dex::kVisibilityEncoded);
648
649 auto& data = dex_->ann_items;
650 dex::u4 offset = data.AddItem();
651 data.Push<dex::u1>(ir_annotation->visibility);
652 WriteAnnotation(ir_annotation, data);
653 return data.AbsoluteOffset(offset);
654 }
655
656 // "annotation_set_item"
WriteAnnotationSet(const ir::AnnotationSet * ir_annotation_set)657 dex::u4 Writer::WriteAnnotationSet(const ir::AnnotationSet* ir_annotation_set) {
658 SLICER_CHECK(ir_annotation_set != nullptr);
659
660 const auto& annotations = ir_annotation_set->annotations;
661
662 auto& data = dex_->ann_sets;
663 dex::u4 offset = data.AddItem(4);
664 data.Push<dex::u4>(annotations.size());
665 for (auto ir_annotation : annotations) {
666 data.Push<dex::u4>(FilePointer(ir_annotation));
667 }
668 return data.AbsoluteOffset(offset);
669 }
670
671 // "annotation_set_ref_list"
WriteAnnotationSetRefList(const ir::AnnotationSetRefList * ir_annotation_set_ref_list)672 dex::u4 Writer::WriteAnnotationSetRefList(
673 const ir::AnnotationSetRefList* ir_annotation_set_ref_list) {
674 SLICER_CHECK(ir_annotation_set_ref_list != nullptr);
675
676 const auto& annotations = ir_annotation_set_ref_list->annotations;
677
678 auto& data = dex_->ann_set_ref_lists;
679 dex::u4 offset = data.AddItem(4);
680 data.Push<dex::u4>(annotations.size());
681 for (auto ir_annotation_set : annotations) {
682 data.Push<dex::u4>(FilePointer(ir_annotation_set));
683 }
684 return data.AbsoluteOffset(offset);
685 }
686
687 // "annotations_directory_item"
WriteClassAnnotations(const ir::Class * ir_class)688 dex::u4 Writer::WriteClassAnnotations(const ir::Class* ir_class) {
689 if (ir_class->annotations == nullptr) {
690 return 0;
691 }
692
693 auto ir_annotations = ir_class->annotations;
694
695 dex::u4& offset = node_offset_[ir_annotations];
696 if (offset == 0) {
697 // in order to write a contiguous "annotations_directory_item" we do two
698 // passes :
699 // 1. write the field/method/params annotations content
700 // 2. write the directory (including the field/method/params arrays)
701 std::vector<dex::FieldAnnotationsItem> dex_field_annotations;
702 std::vector<dex::MethodAnnotationsItem> dex_method_annotations;
703 std::vector<dex::ParameterAnnotationsItem> dex_param_annotations;
704
705 for (auto irItem : ir_annotations->field_annotations) {
706 dex::FieldAnnotationsItem dex_item = {};
707 dex_item.field_idx = irItem->field_decl->index;
708 dex_item.annotations_off = FilePointer(irItem->annotations);
709 dex_field_annotations.push_back(dex_item);
710 }
711
712 for (auto irItem : ir_annotations->method_annotations) {
713 dex::MethodAnnotationsItem dex_item = {};
714 dex_item.method_idx = irItem->method_decl->index;
715 dex_item.annotations_off = FilePointer(irItem->annotations);
716 dex_method_annotations.push_back(dex_item);
717 }
718
719 for (auto irItem : ir_annotations->param_annotations) {
720 dex::ParameterAnnotationsItem dex_item = {};
721 dex_item.method_idx = irItem->method_decl->index;
722 dex_item.annotations_off = FilePointer(irItem->annotations);
723 dex_param_annotations.push_back(dex_item);
724 }
725
726 dex::u4 class_annotations_offset =
727 FilePointer(ir_annotations->class_annotation);
728
729 // now that the annotations content is written,
730 // we can write down the "annotations_directory_item"
731 dex::AnnotationsDirectoryItem dex_annotations = {};
732 dex_annotations.class_annotations_off = class_annotations_offset;
733 dex_annotations.fields_size = ir_annotations->field_annotations.size();
734 dex_annotations.methods_size = ir_annotations->method_annotations.size();
735 dex_annotations.parameters_size = ir_annotations->param_annotations.size();
736
737 auto& data = dex_->ann_directories;
738 offset = data.AddItem(4);
739 data.Push(dex_annotations);
740 data.Push(dex_field_annotations);
741 data.Push(dex_method_annotations);
742 data.Push(dex_param_annotations);
743 offset = data.AbsoluteOffset(offset);
744 }
745 return offset;
746 }
747
748 // "debug_info_item"
WriteDebugInfo(const ir::DebugInfo * ir_debug_info)749 dex::u4 Writer::WriteDebugInfo(const ir::DebugInfo* ir_debug_info) {
750 SLICER_CHECK(ir_debug_info != nullptr);
751
752 auto& data = dex_->debug_info;
753 dex::u4 offset = data.AddItem();
754
755 // debug info "header"
756 data.PushULeb128(ir_debug_info->line_start);
757 data.PushULeb128(ir_debug_info->param_names.size());
758 for (auto ir_string : ir_debug_info->param_names) {
759 data.PushULeb128(OptIndex(ir_string) + 1);
760 }
761
762 // debug info "state machine bytecodes"
763 const dex::u1* src = ir_debug_info->data.ptr<dex::u1>();
764 dex::u1 opcode = 0;
765 while ((opcode = *src++) != dex::DBG_END_SEQUENCE) {
766 data.Push<dex::u1>(opcode);
767
768 switch (opcode) {
769 case dex::DBG_ADVANCE_PC:
770 // addr_diff
771 data.PushULeb128(dex::ReadULeb128(&src));
772 break;
773
774 case dex::DBG_ADVANCE_LINE:
775 // line_diff
776 data.PushSLeb128(dex::ReadSLeb128(&src));
777 break;
778
779 case dex::DBG_START_LOCAL: {
780 // register_num
781 data.PushULeb128(dex::ReadULeb128(&src));
782
783 dex::u4 name_index = dex::ReadULeb128(&src) - 1;
784 data.PushULeb128(MapStringIndex(name_index) + 1);
785
786 dex::u4 type_index = dex::ReadULeb128(&src) - 1;
787 data.PushULeb128(MapTypeIndex(type_index) + 1);
788 } break;
789
790 case dex::DBG_START_LOCAL_EXTENDED: {
791 // register_num
792 data.PushULeb128(dex::ReadULeb128(&src));
793
794 dex::u4 name_index = dex::ReadULeb128(&src) - 1;
795 data.PushULeb128(MapStringIndex(name_index) + 1);
796
797 dex::u4 type_index = dex::ReadULeb128(&src) - 1;
798 data.PushULeb128(MapTypeIndex(type_index) + 1);
799
800 dex::u4 sig_index = dex::ReadULeb128(&src) - 1;
801 data.PushULeb128(MapStringIndex(sig_index) + 1);
802 } break;
803
804 case dex::DBG_END_LOCAL:
805 case dex::DBG_RESTART_LOCAL:
806 // register_num
807 data.PushULeb128(dex::ReadULeb128(&src));
808 break;
809
810 case dex::DBG_SET_FILE: {
811 dex::u4 name_index = dex::ReadULeb128(&src) - 1;
812 data.PushULeb128(MapStringIndex(name_index) + 1);
813 } break;
814 }
815 }
816 data.Push<dex::u1>(dex::DBG_END_SEQUENCE);
817
818 return data.AbsoluteOffset(offset);
819 }
820
821 // instruction[] array
WriteInstructions(slicer::ArrayView<const dex::u2> instructions)822 void Writer::WriteInstructions(slicer::ArrayView<const dex::u2> instructions) {
823 SLICER_CHECK(!instructions.empty());
824
825 auto offset = dex_->code.Push(instructions);
826 dex::u2* ptr = dex_->code.ptr<dex::u2>(offset);
827 dex::u2* const end = ptr + instructions.size();
828
829 // relocate the instructions
830 while (ptr < end) {
831 auto opcode = dex::OpcodeFromBytecode(*ptr);
832 dex::u2* idx = &ptr[1];
833
834 size_t idx_size = 0;
835 switch (dex::GetFormatFromOpcode(opcode)) {
836 case dex::k20bc:
837 case dex::k21c:
838 case dex::k35c:
839 case dex::k3rc:
840 case dex::k22c:
841 idx_size = 2;
842 break;
843
844 case dex::k31c:
845 idx_size = 4;
846 break;
847
848 default:
849 break;
850 }
851
852 switch (dex::GetIndexTypeFromOpcode(opcode)) {
853 case dex::kIndexStringRef:
854 if (idx_size == 4) {
855 dex::u4 new_index = MapStringIndex(ReadU4(idx));
856 SLICER_CHECK(new_index != dex::kNoIndex);
857 WriteU4(idx, new_index);
858 } else {
859 SLICER_CHECK(idx_size == 2);
860 dex::u4 new_index = MapStringIndex(*idx);
861 SLICER_CHECK(new_index != dex::kNoIndex);
862 SLICER_CHECK(dex::u2(new_index) == new_index);
863 *idx = dex::u2(new_index);
864 }
865 break;
866
867 case dex::kIndexTypeRef: {
868 SLICER_CHECK(idx_size == 2);
869 dex::u4 new_index = MapTypeIndex(*idx);
870 SLICER_CHECK(new_index != dex::kNoIndex);
871 SLICER_CHECK(dex::u2(new_index) == new_index);
872 *idx = dex::u2(new_index);
873 } break;
874
875 case dex::kIndexFieldRef: {
876 SLICER_CHECK(idx_size == 2);
877 dex::u4 new_index = MapFieldIndex(*idx);
878 SLICER_CHECK(new_index != dex::kNoIndex);
879 SLICER_CHECK(dex::u2(new_index) == new_index);
880 *idx = dex::u2(new_index);
881 } break;
882
883 case dex::kIndexMethodRef: {
884 SLICER_CHECK(idx_size == 2);
885 dex::u4 new_index = MapMethodIndex(*idx);
886 SLICER_CHECK(new_index != dex::kNoIndex);
887 SLICER_CHECK(dex::u2(new_index) == new_index);
888 *idx = dex::u2(new_index);
889 } break;
890
891 default:
892 break;
893 }
894
895 auto isize = dex::GetWidthFromBytecode(ptr);
896 SLICER_CHECK(isize > 0);
897 ptr += isize;
898 }
899 SLICER_CHECK(ptr == end);
900 }
901
902 // "try_item[] + encoded_catch_handler_list"
WriteTryBlocks(const ir::Code * irCode)903 void Writer::WriteTryBlocks(const ir::Code* irCode) {
904 SLICER_CHECK(!irCode->try_blocks.empty());
905
906 // use a temporary buffer to build the "encoded_catch_handler_list"
907 slicer::Buffer handlers_list;
908 auto original_list = irCode->catch_handlers.ptr<dex::u1>();
909 auto ptr = original_list;
910 std::map<dex::u2, dex::u2> handlers_offset_map;
911
912 dex::u4 handlers_count = dex::ReadULeb128(&ptr);
913 handlers_list.PushULeb128(handlers_count);
914
915 for (dex::u4 handler_index = 0; handler_index < handlers_count; ++handler_index) {
916 // track the oldOffset/newOffset mapping
917 handlers_offset_map[ptr - original_list] = handlers_list.size();
918
919 // parse each "encoded_catch_handler"
920 int catch_count = dex::ReadSLeb128(&ptr);
921 handlers_list.PushSLeb128(catch_count);
922
923 for (int catch_index = 0; catch_index < std::abs(catch_count); ++catch_index) {
924 // type_idx
925 dex::u4 type_index = dex::ReadULeb128(&ptr);
926 handlers_list.PushULeb128(MapTypeIndex(type_index));
927
928 // address
929 handlers_list.PushULeb128(dex::ReadULeb128(&ptr));
930 }
931
932 if (catch_count < 1) {
933 // catch_all_addr
934 handlers_list.PushULeb128(dex::ReadULeb128(&ptr));
935 }
936 }
937
938 handlers_list.Seal(1);
939
940 // now write everything (try_item[] and encoded_catch_handler_list)
941 auto& data = dex_->code;
942 dex::u4 tries_offset = data.size();
943 data.Push(irCode->try_blocks);
944 data.Push(handlers_list);
945
946 // finally relocate the offsets to handlers
947 for (dex::TryBlock& dex_try : slicer::ArrayView<dex::TryBlock>(
948 data.ptr<dex::TryBlock>(tries_offset), irCode->try_blocks.size())) {
949 dex::u2 new_Handler_offset = handlers_offset_map[dex_try.handler_off];
950 SLICER_CHECK(new_Handler_offset != 0);
951 dex_try.handler_off = new_Handler_offset;
952 }
953 }
954
955 // "code_item"
WriteCode(const ir::Code * irCode)956 dex::u4 Writer::WriteCode(const ir::Code* irCode) {
957 SLICER_CHECK(irCode != nullptr);
958
959 dex::Code dex_code = {};
960 dex_code.registers_size = irCode->registers;
961 dex_code.ins_size = irCode->ins_count;
962 dex_code.outs_size = irCode->outs_count;
963 dex_code.tries_size = irCode->try_blocks.size();
964 dex_code.debug_info_off = FilePointer(irCode->debug_info);
965 dex_code.insns_size = irCode->instructions.size();
966
967 auto& data = dex_->code;
968 dex::u4 offset = data.AddItem(4);
969 data.Push(&dex_code, offsetof(dex::Code, insns));
970 WriteInstructions(irCode->instructions);
971 if (!irCode->try_blocks.empty()) {
972 data.Align(4);
973 WriteTryBlocks(irCode);
974 }
975 return data.AbsoluteOffset(offset);
976 }
977
978 // "encoded_field"
WriteEncodedField(const ir::EncodedField * ir_encoded_field,dex::u4 * base_index)979 void Writer::WriteEncodedField(const ir::EncodedField* ir_encoded_field,
980 dex::u4* base_index) {
981 dex::u4 index_delta = ir_encoded_field->decl->index;
982 SLICER_CHECK(index_delta != dex::kNoIndex);
983 if (*base_index != dex::kNoIndex) {
984 SLICER_CHECK(index_delta > *base_index);
985 index_delta = index_delta - *base_index;
986 }
987 *base_index = ir_encoded_field->decl->index;
988
989 auto& data = dex_->class_data;
990 data.PushULeb128(index_delta);
991 data.PushULeb128(ir_encoded_field->access_flags);
992 }
993
994 // "encoded_method"
WriteEncodedMethod(const ir::EncodedMethod * ir_encoded_method,dex::u4 * base_index)995 void Writer::WriteEncodedMethod(const ir::EncodedMethod* ir_encoded_method,
996 dex::u4* base_index) {
997 dex::u4 index_delta = ir_encoded_method->decl->index;
998 SLICER_CHECK(index_delta != dex::kNoIndex);
999 if (*base_index != dex::kNoIndex) {
1000 SLICER_CHECK(index_delta > *base_index);
1001 index_delta = index_delta - *base_index;
1002 }
1003 *base_index = ir_encoded_method->decl->index;
1004
1005 dex::u4 code_offset = FilePointer(ir_encoded_method->code);
1006
1007 auto& data = dex_->class_data;
1008 data.PushULeb128(index_delta);
1009 data.PushULeb128(ir_encoded_method->access_flags);
1010 data.PushULeb128(code_offset);
1011 }
1012
1013 // "class_data_item"
WriteClassData(const ir::Class * ir_class)1014 dex::u4 Writer::WriteClassData(const ir::Class* ir_class) {
1015 if (ir_class->static_fields.empty() && ir_class->instance_fields.empty() &&
1016 ir_class->direct_methods.empty() && ir_class->virtual_methods.empty()) {
1017 return 0;
1018 }
1019
1020 auto& data = dex_->class_data;
1021 dex::u4 offset = data.AddItem();
1022
1023 data.PushULeb128(ir_class->static_fields.size());
1024 data.PushULeb128(ir_class->instance_fields.size());
1025 data.PushULeb128(ir_class->direct_methods.size());
1026 data.PushULeb128(ir_class->virtual_methods.size());
1027
1028 dex::u4 base_index = dex::kNoIndex;
1029 for (auto ir_encoded_field : ir_class->static_fields) {
1030 WriteEncodedField(ir_encoded_field, &base_index);
1031 }
1032
1033 base_index = dex::kNoIndex;
1034 for (auto ir_encoded_field : ir_class->instance_fields) {
1035 WriteEncodedField(ir_encoded_field, &base_index);
1036 }
1037
1038 base_index = dex::kNoIndex;
1039 for (auto ir_encoded_method : ir_class->direct_methods) {
1040 WriteEncodedMethod(ir_encoded_method, &base_index);
1041 }
1042
1043 base_index = dex::kNoIndex;
1044 for (auto ir_encoded_method : ir_class->virtual_methods) {
1045 WriteEncodedMethod(ir_encoded_method, &base_index);
1046 }
1047
1048 return data.AbsoluteOffset(offset);
1049 }
1050
1051 // "encoded_array_item"
WriteClassStaticValues(const ir::Class * ir_class)1052 dex::u4 Writer::WriteClassStaticValues(const ir::Class* ir_class) {
1053 if (ir_class->static_init == nullptr) {
1054 return 0;
1055 }
1056
1057 dex::u4& offset = node_offset_[ir_class->static_init];
1058 if (offset == 0) {
1059 auto& data = dex_->encoded_arrays;
1060 offset = data.AddItem();
1061 WriteEncodedArray(ir_class->static_init, data);
1062 offset = data.AbsoluteOffset(offset);
1063 }
1064 return offset;
1065 }
1066
1067 // Map an index from the original .dex to the new index
MapStringIndex(dex::u4 index) const1068 dex::u4 Writer::MapStringIndex(dex::u4 index) const {
1069 if (index != dex::kNoIndex) {
1070 index = dex_ir_->strings_map.at(index)->index;
1071 SLICER_CHECK(index != dex::kNoIndex);
1072 }
1073 return index;
1074 }
1075
1076 // Map an index from the original .dex to the new index
MapTypeIndex(dex::u4 index) const1077 dex::u4 Writer::MapTypeIndex(dex::u4 index) const {
1078 if (index != dex::kNoIndex) {
1079 index = dex_ir_->types_map.at(index)->index;
1080 SLICER_CHECK(index != dex::kNoIndex);
1081 }
1082 return index;
1083 }
1084
1085 // Map an index from the original .dex to the new index
MapFieldIndex(dex::u4 index) const1086 dex::u4 Writer::MapFieldIndex(dex::u4 index) const {
1087 if (index != dex::kNoIndex) {
1088 index = dex_ir_->fields_map.at(index)->index;
1089 SLICER_CHECK(index != dex::kNoIndex);
1090 }
1091 return index;
1092 }
1093
1094 // Map an index from the original .dex to the new index
MapMethodIndex(dex::u4 index) const1095 dex::u4 Writer::MapMethodIndex(dex::u4 index) const {
1096 if (index != dex::kNoIndex) {
1097 index = dex_ir_->methods_map.at(index)->index;
1098 SLICER_CHECK(index != dex::kNoIndex);
1099 }
1100 return index;
1101 }
1102
1103 // .dex IR node to file pointer (absolute offset)
FilePointer(const ir::Node * ir_node) const1104 dex::u4 Writer::FilePointer(const ir::Node* ir_node) const {
1105 if (ir_node == nullptr) {
1106 return 0;
1107 }
1108 auto it = node_offset_.find(ir_node);
1109 SLICER_CHECK(it != node_offset_.end());
1110 dex::u4 offset = it->second;
1111 SLICER_CHECK(offset > 0);
1112 return offset;
1113 }
1114
1115 } // namespace dex
1116