• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
235 // This is the main interface for the .dex writer
236 // (returns nullptr on failure)
CreateImage(Allocator * allocator,size_t * new_image_size)237 dex::u1* Writer::CreateImage(Allocator* allocator, size_t* new_image_size) {
238   // create a new DexImage
239   dex_.reset(new DexImage);
240 
241   SLICER_SCOPE_EXIT {
242       dex_.reset();
243   };
244 
245   // TODO: revisit IR normalization
246   // (ideally we shouldn't change the IR while generating an image)
247   dex_ir_->Normalize();
248 
249   // track the current offset within the .dex image
250   dex::u4 offset = 0;
251 
252   // allocate the image and index sections
253   // (they will be back-filled)
254   offset += sizeof(dex::Header);
255   offset += dex_->string_ids.Init(offset, dex_ir_->strings.size());
256   offset += dex_->type_ids.Init(offset, dex_ir_->types.size());
257   offset += dex_->proto_ids.Init(offset, dex_ir_->protos.size());
258   offset += dex_->field_ids.Init(offset, dex_ir_->fields.size());
259   offset += dex_->method_ids.Init(offset, dex_ir_->methods.size());
260   offset += dex_->class_defs.Init(offset, dex_ir_->classes.size());
261 
262   // the base offset for the "data" meta-section
263   SLICER_CHECK(offset % 4 == 0);
264   const dex::u4 data_offset = offset;
265 
266   // we must create the sections in a very specific
267   // order due to file pointers across sections
268   offset += CreateStringDataSection(offset);
269   offset += CreateTypeListsSection(offset);
270   offset += CreateDebugInfoSection(offset);
271   offset += CreateEncodedArrayItemSection(offset);
272   offset += CreateCodeItemSection(offset);
273   offset += CreateClassDataSection(offset);
274   offset += CreateAnnItemSection(offset);
275   offset += CreateAnnSetsSection(offset);
276   offset += CreateAnnSetRefListsSection(offset);
277   offset += CreateAnnDirectoriesSection(offset);
278   offset += CreateMapSection(offset);
279 
280   // back-fill the indexes
281   FillTypes();
282   FillFields();
283   FillProtos();
284   FillMethods();
285   FillClassDefs();
286 
287   // allocate the final buffer for the .dex image
288   SLICER_CHECK(offset % 4 == 0);
289   const dex::u4 image_size = offset;
290   dex::u1* image = static_cast<dex::u1*>(allocator->Allocate(image_size));
291   if (image == nullptr) {
292     // memory allocation failed, bailing out...
293     return nullptr;
294   }
295   memset(image, 0, image_size);
296 
297   // finally, back-fill the header
298   SLICER_CHECK(image_size > sizeof(dex::Header));
299 
300   dex::Header* header = reinterpret_cast<dex::Header*>(image + 0);
301 
302   // magic signature
303   memcpy(header->magic, dex_ir_->magic.ptr(), dex_ir_->magic.size());
304 
305   header->file_size = image_size;
306   header->header_size = sizeof(dex::Header);
307   header->endian_tag = dex::kEndianConstant;
308 
309   header->link_size = 0;
310   header->link_off = 0;
311 
312   header->map_off = dex_->map_list.SectionOffset();
313   header->string_ids_size = dex_->string_ids.ItemsCount();
314   header->string_ids_off = dex_->string_ids.SectionOffset();
315   header->type_ids_size = dex_->type_ids.ItemsCount();
316   header->type_ids_off = dex_->type_ids.SectionOffset();
317   header->proto_ids_size = dex_->proto_ids.ItemsCount();
318   header->proto_ids_off = dex_->proto_ids.SectionOffset();
319   header->field_ids_size = dex_->field_ids.ItemsCount();
320   header->field_ids_off = dex_->field_ids.SectionOffset();
321   header->method_ids_size = dex_->method_ids.ItemsCount();
322   header->method_ids_off = dex_->method_ids.SectionOffset();
323   header->class_defs_size = dex_->class_defs.ItemsCount();
324   header->class_defs_off = dex_->class_defs.SectionOffset();
325   header->data_size = image_size - data_offset;
326   header->data_off = data_offset;
327 
328   // copy the individual sections to the final image
329   CopySection(dex_->string_ids, image, image_size);
330   CopySection(dex_->type_ids, image, image_size);
331   CopySection(dex_->proto_ids, image, image_size);
332   CopySection(dex_->field_ids, image, image_size);
333   CopySection(dex_->method_ids, image, image_size);
334   CopySection(dex_->class_defs, image, image_size);
335   CopySection(dex_->string_data, image, image_size);
336   CopySection(dex_->type_lists, image, image_size);
337   CopySection(dex_->debug_info, image, image_size);
338   CopySection(dex_->encoded_arrays, image, image_size);
339   CopySection(dex_->code, image, image_size);
340   CopySection(dex_->class_data, image, image_size);
341   CopySection(dex_->ann_directories, image, image_size);
342   CopySection(dex_->ann_set_ref_lists, image, image_size);
343   CopySection(dex_->ann_sets, image, image_size);
344   CopySection(dex_->ann_items, image, image_size);
345   CopySection(dex_->map_list, image, image_size);
346 
347   // checksum
348   header->checksum = dex::ComputeChecksum(header);
349 
350   *new_image_size = image_size;
351   return image;
352 }
353 
354 // "string_id_item" + string data section
CreateStringDataSection(dex::u4 section_offset)355 dex::u4 Writer::CreateStringDataSection(dex::u4 section_offset) {
356   auto& section = dex_->string_data;
357   section.SetOffset(section_offset);
358 
359   const auto& strings = dex_ir_->strings;
360   for (size_t i = 0; i < strings.size(); ++i) {
361     const auto& ir_string = strings[i];
362     auto dexStringId = &dex_->string_ids[i];
363 
364     dex::u4 offset = section.AddItem();
365     section.Push(ir_string->data);
366     dexStringId->string_data_off = section.AbsoluteOffset(offset);
367   }
368 
369   dex::u4 size = section.Seal(4);
370   return size;
371 }
372 
373 // Helper for creating the map section
374 template <class T>
AddMapItem(const T & section,std::vector<dex::MapItem> & items)375 static void AddMapItem(const T& section, std::vector<dex::MapItem>& items) {
376   if (section.ItemsCount() > 0) {
377     SLICER_CHECK(section.SectionOffset() >= sizeof(dex::Header));
378     dex::MapItem map_item = {};
379     map_item.type = section.MapEntryType();
380     map_item.size = section.ItemsCount();
381     map_item.offset = section.SectionOffset();
382     items.push_back(map_item);
383   }
384 }
385 
386 // map_list section
CreateMapSection(dex::u4 section_offset)387 dex::u4 Writer::CreateMapSection(dex::u4 section_offset) {
388   auto& section = dex_->map_list;
389   section.SetOffset(section_offset);
390   section.AddItem(4);
391 
392   std::vector<dex::MapItem> map_items;
393 
394   dex::MapItem headerItem = {};
395   headerItem.type = dex::kHeaderItem;
396   headerItem.size = 1;
397   headerItem.offset = 0;
398   map_items.push_back(headerItem);
399 
400   AddMapItem(dex_->string_ids, map_items);
401   AddMapItem(dex_->type_ids, map_items);
402   AddMapItem(dex_->proto_ids, map_items);
403   AddMapItem(dex_->field_ids, map_items);
404   AddMapItem(dex_->method_ids, map_items);
405   AddMapItem(dex_->class_defs, map_items);
406   AddMapItem(dex_->string_data, map_items);
407   AddMapItem(dex_->type_lists, map_items);
408   AddMapItem(dex_->debug_info, map_items);
409   AddMapItem(dex_->encoded_arrays, map_items);
410   AddMapItem(dex_->code, map_items);
411   AddMapItem(dex_->class_data, map_items);
412   AddMapItem(dex_->ann_directories, map_items);
413   AddMapItem(dex_->ann_set_ref_lists, map_items);
414   AddMapItem(dex_->ann_sets, map_items);
415   AddMapItem(dex_->ann_items, map_items);
416   AddMapItem(dex_->map_list, map_items);
417 
418   std::sort(map_items.begin(), map_items.end(),
419             [](const dex::MapItem& a, const dex::MapItem& b) {
420               SLICER_CHECK(a.offset != b.offset);
421               return a.offset < b.offset;
422             });
423 
424   section.Push<dex::u4>(map_items.size());
425   section.Push(map_items);
426   return section.Seal(4);
427 }
428 
429 // annotation_item section
CreateAnnItemSection(dex::u4 section_offset)430 dex::u4 Writer::CreateAnnItemSection(dex::u4 section_offset) {
431   dex_->ann_items.SetOffset(section_offset);
432 
433   for (const auto& ir_node : dex_ir_->annotations) {
434     if (ir_node->visibility != dex::kVisibilityEncoded) {
435       // TODO: factor out the node_offset_ updating
436       dex::u4& offset = node_offset_[ir_node.get()];
437       SLICER_CHECK(offset == 0);
438       offset = WriteAnnotationItem(ir_node.get());
439     }
440   }
441 
442   return dex_->ann_items.Seal(4);
443 }
444 
445 // annotation_set_item section
CreateAnnSetsSection(dex::u4 section_offset)446 dex::u4 Writer::CreateAnnSetsSection(dex::u4 section_offset) {
447   dex_->ann_sets.SetOffset(section_offset);
448 
449   for (const auto& ir_node : dex_ir_->annotation_sets) {
450     dex::u4& offset = node_offset_[ir_node.get()];
451     SLICER_CHECK(offset == 0);
452     offset = WriteAnnotationSet(ir_node.get());
453   }
454 
455   return dex_->ann_sets.Seal(4);
456 }
457 
458 // annotation_set_ref_list section
CreateAnnSetRefListsSection(dex::u4 section_offset)459 dex::u4 Writer::CreateAnnSetRefListsSection(dex::u4 section_offset) {
460   dex_->ann_set_ref_lists.SetOffset(section_offset);
461 
462   for (const auto& ir_node : dex_ir_->annotation_set_ref_lists) {
463     dex::u4& offset = node_offset_[ir_node.get()];
464     SLICER_CHECK(offset == 0);
465     offset = WriteAnnotationSetRefList(ir_node.get());
466   }
467 
468   return dex_->ann_set_ref_lists.Seal(4);
469 }
470 
471 // type_list section
CreateTypeListsSection(dex::u4 section_offset)472 dex::u4 Writer::CreateTypeListsSection(dex::u4 section_offset) {
473   dex_->type_lists.SetOffset(section_offset);
474 
475   for (const auto& ir_type_list : dex_ir_->type_lists) {
476     dex::u4& offset = node_offset_[ir_type_list.get()];
477     SLICER_CHECK(offset == 0);
478     offset = WriteTypeList(ir_type_list->types);
479   }
480 
481   return dex_->type_lists.Seal(4);
482 }
483 
484 // code_item section
CreateCodeItemSection(dex::u4 section_offset)485 dex::u4 Writer::CreateCodeItemSection(dex::u4 section_offset) {
486   dex_->code.SetOffset(section_offset);
487 
488   for (const auto& ir_node : dex_ir_->code) {
489     dex::u4& offset = node_offset_[ir_node.get()];
490     SLICER_CHECK(offset == 0);
491     offset = WriteCode(ir_node.get());
492   }
493 
494   dex::u4 size = dex_->code.Seal(4);
495   return size;
496 }
497 
498 // debug info section
CreateDebugInfoSection(dex::u4 section_offset)499 dex::u4 Writer::CreateDebugInfoSection(dex::u4 section_offset) {
500   dex_->debug_info.SetOffset(section_offset);
501 
502   for (const auto& ir_node : dex_ir_->debug_info) {
503     dex::u4& offset = node_offset_[ir_node.get()];
504     SLICER_CHECK(offset == 0);
505     offset = WriteDebugInfo(ir_node.get());
506   }
507 
508   dex::u4 size = dex_->debug_info.Seal(4);
509   return size;
510 }
511 
512 // class_data_item section
CreateClassDataSection(dex::u4 section_offset)513 dex::u4 Writer::CreateClassDataSection(dex::u4 section_offset) {
514   dex_->class_data.SetOffset(section_offset);
515 
516   const auto& classes = dex_ir_->classes;
517   for (size_t i = 0; i < classes.size(); ++i) {
518     auto ir_class = classes[i].get();
519     auto dex_class_def = &dex_->class_defs[i];
520     dex_class_def->class_data_off = WriteClassData(ir_class);
521   }
522 
523   dex::u4 size = dex_->class_data.Seal(4);
524   return size;
525 }
526 
527 // annotations_directory section
CreateAnnDirectoriesSection(dex::u4 section_offset)528 dex::u4 Writer::CreateAnnDirectoriesSection(dex::u4 section_offset) {
529   dex_->ann_directories.SetOffset(section_offset);
530 
531   const auto& classes = dex_ir_->classes;
532   for (size_t i = 0; i < classes.size(); ++i) {
533     auto ir_class = classes[i].get();
534     auto dex_class_def = &dex_->class_defs[i];
535     dex_class_def->annotations_off = WriteClassAnnotations(ir_class);
536   }
537 
538   return dex_->ann_directories.Seal(4);
539 }
540 
541 // encoded_array_item section
CreateEncodedArrayItemSection(dex::u4 section_offset)542 dex::u4 Writer::CreateEncodedArrayItemSection(dex::u4 section_offset) {
543   dex_->encoded_arrays.SetOffset(section_offset);
544 
545   const auto& classes = dex_ir_->classes;
546   for (size_t i = 0; i < classes.size(); ++i) {
547     auto ir_class = classes[i].get();
548     auto dex_class_def = &dex_->class_defs[i];
549     dex_class_def->static_values_off = WriteClassStaticValues(ir_class);
550   }
551 
552   return dex_->encoded_arrays.Seal(4);
553 }
554 
555 // "type_id_item"
FillTypes()556 void Writer::FillTypes() {
557   const auto& types = dex_ir_->types;
558   for (size_t i = 0; i < types.size(); ++i) {
559     const auto& ir_type = types[i];
560     auto dexTypeId = &dex_->type_ids[i];
561     // CONSIDER: an automatic index check would be nice
562     dexTypeId->descriptor_idx = ir_type->descriptor->index;
563   }
564 }
565 
566 // "proto_id_item"
FillProtos()567 void Writer::FillProtos() {
568   const auto& protos = dex_ir_->protos;
569   for (size_t i = 0; i < protos.size(); ++i) {
570     const auto& irProto = protos[i];
571     auto dexProtoId = &dex_->proto_ids[i];
572     dexProtoId->shorty_idx = irProto->shorty->index;
573     dexProtoId->return_type_idx = irProto->return_type->index;
574     dexProtoId->parameters_off = FilePointer(irProto->param_types);
575   }
576 }
577 
578 // "field_id_item"
FillFields()579 void Writer::FillFields() {
580   const auto& fields = dex_ir_->fields;
581   for (size_t i = 0; i < fields.size(); ++i) {
582     const auto& ir_field = fields[i];
583     auto dexFieldId = &dex_->field_ids[i];
584     dexFieldId->class_idx = ir_field->parent->index;
585     dexFieldId->type_idx = ir_field->type->index;
586     dexFieldId->name_idx = ir_field->name->index;
587   }
588 }
589 
590 // "method_id_item"
FillMethods()591 void Writer::FillMethods() {
592   const auto& methods = dex_ir_->methods;
593   for (size_t i = 0; i < methods.size(); ++i) {
594     const auto& ir_method = methods[i];
595     auto dexMethodId = &dex_->method_ids[i];
596     dexMethodId->class_idx = ir_method->parent->index;
597     dexMethodId->proto_idx = ir_method->prototype->index;
598     dexMethodId->name_idx = ir_method->name->index;
599   }
600 }
601 
602 // "class_def_item"
FillClassDefs()603 void Writer::FillClassDefs() {
604   const auto& classes = dex_ir_->classes;
605   for (size_t i = 0; i < classes.size(); ++i) {
606     auto ir_class = classes[i].get();
607     auto dex_class_def = &dex_->class_defs[i];
608     dex_class_def->class_idx = ir_class->type->index;
609     dex_class_def->access_flags = ir_class->access_flags;
610     dex_class_def->superclass_idx = OptIndex(ir_class->super_class);
611     dex_class_def->source_file_idx = OptIndex(ir_class->source_file);
612     dex_class_def->interfaces_off = FilePointer(ir_class->interfaces);
613 
614     // NOTE: we already set some offsets when we created the
615     //  corresponding .dex section:
616     //
617     //  ->annotations_off
618     //  ->class_data_off
619     //  ->static_values_off
620   }
621 }
622 
623 // "type_list"
WriteTypeList(const std::vector<ir::Type * > & types)624 dex::u4 Writer::WriteTypeList(const std::vector<ir::Type*>& types) {
625   if (types.empty()) {
626     return 0;
627   }
628 
629   auto& data = dex_->type_lists;
630   dex::u4 offset = data.AddItem(4);
631   data.Push<dex::u4>(types.size());
632   for (auto ir_type : types) {
633     data.Push<dex::u2>(ir_type->index);
634   }
635   return data.AbsoluteOffset(offset);
636 }
637 
638 // "annotation_item"
WriteAnnotationItem(const ir::Annotation * ir_annotation)639 dex::u4 Writer::WriteAnnotationItem(const ir::Annotation* ir_annotation) {
640   SLICER_CHECK(ir_annotation->visibility != dex::kVisibilityEncoded);
641 
642   auto& data = dex_->ann_items;
643   dex::u4 offset = data.AddItem();
644   data.Push<dex::u1>(ir_annotation->visibility);
645   WriteAnnotation(ir_annotation, data);
646   return data.AbsoluteOffset(offset);
647 }
648 
649 // "annotation_set_item"
WriteAnnotationSet(const ir::AnnotationSet * ir_annotation_set)650 dex::u4 Writer::WriteAnnotationSet(const ir::AnnotationSet* ir_annotation_set) {
651   SLICER_CHECK(ir_annotation_set != nullptr);
652 
653   const auto& annotations = ir_annotation_set->annotations;
654 
655   auto& data = dex_->ann_sets;
656   dex::u4 offset = data.AddItem(4);
657   data.Push<dex::u4>(annotations.size());
658   for (auto ir_annotation : annotations) {
659     data.Push<dex::u4>(FilePointer(ir_annotation));
660   }
661   return data.AbsoluteOffset(offset);
662 }
663 
664 // "annotation_set_ref_list"
WriteAnnotationSetRefList(const ir::AnnotationSetRefList * ir_annotation_set_ref_list)665 dex::u4 Writer::WriteAnnotationSetRefList(
666     const ir::AnnotationSetRefList* ir_annotation_set_ref_list) {
667   SLICER_CHECK(ir_annotation_set_ref_list != nullptr);
668 
669   const auto& annotations = ir_annotation_set_ref_list->annotations;
670 
671   auto& data = dex_->ann_set_ref_lists;
672   dex::u4 offset = data.AddItem(4);
673   data.Push<dex::u4>(annotations.size());
674   for (auto ir_annotation_set : annotations) {
675     data.Push<dex::u4>(FilePointer(ir_annotation_set));
676   }
677   return data.AbsoluteOffset(offset);
678 }
679 
680 // "annotations_directory_item"
WriteClassAnnotations(const ir::Class * ir_class)681 dex::u4 Writer::WriteClassAnnotations(const ir::Class* ir_class) {
682   if (ir_class->annotations == nullptr) {
683     return 0;
684   }
685 
686   auto ir_annotations = ir_class->annotations;
687 
688   dex::u4& offset = node_offset_[ir_annotations];
689   if (offset == 0) {
690     // in order to write a contiguous "annotations_directory_item" we do two
691     // passes :
692     // 1. write the field/method/params annotations content
693     // 2. write the directory (including the field/method/params arrays)
694     std::vector<dex::FieldAnnotationsItem> dex_field_annotations;
695     std::vector<dex::MethodAnnotationsItem> dex_method_annotations;
696     std::vector<dex::ParameterAnnotationsItem> dex_param_annotations;
697 
698     for (auto irItem : ir_annotations->field_annotations) {
699       dex::FieldAnnotationsItem dex_item = {};
700       dex_item.field_idx = irItem->field_decl->index;
701       dex_item.annotations_off = FilePointer(irItem->annotations);
702       dex_field_annotations.push_back(dex_item);
703     }
704 
705     for (auto irItem : ir_annotations->method_annotations) {
706       dex::MethodAnnotationsItem dex_item = {};
707       dex_item.method_idx = irItem->method_decl->index;
708       dex_item.annotations_off = FilePointer(irItem->annotations);
709       dex_method_annotations.push_back(dex_item);
710     }
711 
712     for (auto irItem : ir_annotations->param_annotations) {
713       dex::ParameterAnnotationsItem dex_item = {};
714       dex_item.method_idx = irItem->method_decl->index;
715       dex_item.annotations_off = FilePointer(irItem->annotations);
716       dex_param_annotations.push_back(dex_item);
717     }
718 
719     dex::u4 class_annotations_offset =
720         FilePointer(ir_annotations->class_annotation);
721 
722     // now that the annotations content is written,
723     // we can write down the "annotations_directory_item"
724     dex::AnnotationsDirectoryItem dex_annotations = {};
725     dex_annotations.class_annotations_off = class_annotations_offset;
726     dex_annotations.fields_size = ir_annotations->field_annotations.size();
727     dex_annotations.methods_size = ir_annotations->method_annotations.size();
728     dex_annotations.parameters_size = ir_annotations->param_annotations.size();
729 
730     auto& data = dex_->ann_directories;
731     offset = data.AddItem(4);
732     data.Push(dex_annotations);
733     data.Push(dex_field_annotations);
734     data.Push(dex_method_annotations);
735     data.Push(dex_param_annotations);
736     offset = data.AbsoluteOffset(offset);
737   }
738   return offset;
739 }
740 
741 // "debug_info_item"
WriteDebugInfo(const ir::DebugInfo * ir_debug_info)742 dex::u4 Writer::WriteDebugInfo(const ir::DebugInfo* ir_debug_info) {
743   SLICER_CHECK(ir_debug_info != nullptr);
744 
745   auto& data = dex_->debug_info;
746   dex::u4 offset = data.AddItem();
747 
748   // debug info "header"
749   data.PushULeb128(ir_debug_info->line_start);
750   data.PushULeb128(ir_debug_info->param_names.size());
751   for (auto ir_string : ir_debug_info->param_names) {
752     data.PushULeb128(OptIndex(ir_string) + 1);
753   }
754 
755   // debug info "state machine bytecodes"
756   const dex::u1* src = ir_debug_info->data.ptr<dex::u1>();
757   dex::u1 opcode = 0;
758   while ((opcode = *src++) != dex::DBG_END_SEQUENCE) {
759     data.Push<dex::u1>(opcode);
760 
761     switch (opcode) {
762       case dex::DBG_ADVANCE_PC:
763         // addr_diff
764         data.PushULeb128(dex::ReadULeb128(&src));
765         break;
766 
767       case dex::DBG_ADVANCE_LINE:
768         // line_diff
769         data.PushSLeb128(dex::ReadSLeb128(&src));
770         break;
771 
772       case dex::DBG_START_LOCAL: {
773         // register_num
774         data.PushULeb128(dex::ReadULeb128(&src));
775 
776         dex::u4 name_index = dex::ReadULeb128(&src) - 1;
777         data.PushULeb128(MapStringIndex(name_index) + 1);
778 
779         dex::u4 type_index = dex::ReadULeb128(&src) - 1;
780         data.PushULeb128(MapTypeIndex(type_index) + 1);
781       } break;
782 
783       case dex::DBG_START_LOCAL_EXTENDED: {
784         // register_num
785         data.PushULeb128(dex::ReadULeb128(&src));
786 
787         dex::u4 name_index = dex::ReadULeb128(&src) - 1;
788         data.PushULeb128(MapStringIndex(name_index) + 1);
789 
790         dex::u4 type_index = dex::ReadULeb128(&src) - 1;
791         data.PushULeb128(MapTypeIndex(type_index) + 1);
792 
793         dex::u4 sig_index = dex::ReadULeb128(&src) - 1;
794         data.PushULeb128(MapStringIndex(sig_index) + 1);
795       } break;
796 
797       case dex::DBG_END_LOCAL:
798       case dex::DBG_RESTART_LOCAL:
799         // register_num
800         data.PushULeb128(dex::ReadULeb128(&src));
801         break;
802 
803       case dex::DBG_SET_FILE: {
804         dex::u4 name_index = dex::ReadULeb128(&src) - 1;
805         data.PushULeb128(MapStringIndex(name_index) + 1);
806       } break;
807     }
808   }
809   data.Push<dex::u1>(dex::DBG_END_SEQUENCE);
810 
811   return data.AbsoluteOffset(offset);
812 }
813 
814 // instruction[] array
WriteInstructions(slicer::ArrayView<const dex::u2> instructions)815 void Writer::WriteInstructions(slicer::ArrayView<const dex::u2> instructions) {
816   SLICER_CHECK(!instructions.empty());
817 
818   auto offset = dex_->code.Push(instructions);
819   dex::u2* ptr = dex_->code.ptr<dex::u2>(offset);
820   dex::u2* const end = ptr + instructions.size();
821 
822   // relocate the instructions
823   while (ptr < end) {
824     auto opcode = dex::OpcodeFromBytecode(*ptr);
825 
826     dex::u2* index16 = nullptr;
827     dex::u4* index32 = nullptr;
828 
829     switch (dex::GetFormatFromOpcode(opcode)) {
830       case dex::k20bc:
831       case dex::k21c:
832       case dex::k35c:
833       case dex::k3rc:
834       case dex::k22c:
835         index16 = &ptr[1];
836         break;
837 
838       case dex::k31c:
839         index32 = reinterpret_cast<dex::u4*>(&ptr[1]);
840         break;
841 
842       default:
843         break;
844     }
845 
846     switch (dex::GetIndexTypeFromOpcode(opcode)) {
847       case dex::kIndexStringRef:
848         if (index32 != nullptr) {
849           SLICER_CHECK(index16 == nullptr);
850           dex::u4 new_index = MapStringIndex(*index32);
851           SLICER_CHECK(new_index != dex::kNoIndex);
852           *index32 = new_index;
853         } else {
854           dex::u4 new_index = MapStringIndex(*index16);
855           SLICER_CHECK(new_index != dex::kNoIndex);
856           SLICER_CHECK(dex::u2(new_index) == new_index);
857           *index16 = dex::u2(new_index);
858         }
859         break;
860 
861       case dex::kIndexTypeRef: {
862         SLICER_CHECK(index32 == nullptr);
863         dex::u4 new_index = MapTypeIndex(*index16);
864         SLICER_CHECK(new_index != dex::kNoIndex);
865         SLICER_CHECK(dex::u2(new_index) == new_index);
866         *index16 = dex::u2(new_index);
867       } break;
868 
869       case dex::kIndexFieldRef: {
870         SLICER_CHECK(index32 == nullptr);
871         dex::u4 new_index = MapFieldIndex(*index16);
872         SLICER_CHECK(new_index != dex::kNoIndex);
873         SLICER_CHECK(dex::u2(new_index) == new_index);
874         *index16 = dex::u2(new_index);
875       } break;
876 
877       case dex::kIndexMethodRef: {
878         SLICER_CHECK(index32 == nullptr);
879         dex::u4 new_index = MapMethodIndex(*index16);
880         SLICER_CHECK(new_index != dex::kNoIndex);
881         SLICER_CHECK(dex::u2(new_index) == new_index);
882         *index16 = dex::u2(new_index);
883       } break;
884 
885       default:
886         break;
887     }
888 
889     auto isize = dex::GetWidthFromBytecode(ptr);
890     SLICER_CHECK(isize > 0);
891     ptr += isize;
892   }
893   SLICER_CHECK(ptr == end);
894 }
895 
896 // "try_item[] + encoded_catch_handler_list"
WriteTryBlocks(const ir::Code * irCode)897 void Writer::WriteTryBlocks(const ir::Code* irCode) {
898   SLICER_CHECK(!irCode->try_blocks.empty());
899 
900   // use a temporary buffer to build the "encoded_catch_handler_list"
901   slicer::Buffer handlers_list;
902   auto original_list = irCode->catch_handlers.ptr<dex::u1>();
903   auto ptr = original_list;
904   std::map<dex::u2, dex::u2> handlers_offset_map;
905 
906   dex::u4 handlers_count = dex::ReadULeb128(&ptr);
907   handlers_list.PushULeb128(handlers_count);
908 
909   for (dex::u4 handler_index = 0; handler_index < handlers_count; ++handler_index) {
910     // track the oldOffset/newOffset mapping
911     handlers_offset_map[ptr - original_list] = handlers_list.size();
912 
913     // parse each "encoded_catch_handler"
914     int catch_count = dex::ReadSLeb128(&ptr);
915     handlers_list.PushSLeb128(catch_count);
916 
917     for (int catch_index = 0; catch_index < std::abs(catch_count); ++catch_index) {
918       // type_idx
919       dex::u4 type_index = dex::ReadULeb128(&ptr);
920       handlers_list.PushULeb128(MapTypeIndex(type_index));
921 
922       // address
923       handlers_list.PushULeb128(dex::ReadULeb128(&ptr));
924     }
925 
926     if (catch_count < 1) {
927       // catch_all_addr
928       handlers_list.PushULeb128(dex::ReadULeb128(&ptr));
929     }
930   }
931 
932   handlers_list.Seal(1);
933 
934   // now write everything (try_item[] and encoded_catch_handler_list)
935   auto& data = dex_->code;
936   dex::u4 tries_offset = data.size();
937   data.Push(irCode->try_blocks);
938   data.Push(handlers_list);
939 
940   // finally relocate the offsets to handlers
941   for (dex::TryBlock& dex_try : slicer::ArrayView<dex::TryBlock>(
942            data.ptr<dex::TryBlock>(tries_offset), irCode->try_blocks.size())) {
943     dex::u2 new_Handler_offset = handlers_offset_map[dex_try.handler_off];
944     SLICER_CHECK(new_Handler_offset != 0);
945     dex_try.handler_off = new_Handler_offset;
946   }
947 }
948 
949 // "code_item"
WriteCode(const ir::Code * irCode)950 dex::u4 Writer::WriteCode(const ir::Code* irCode) {
951   SLICER_CHECK(irCode != nullptr);
952 
953   dex::Code dex_code = {};
954   dex_code.registers_size = irCode->registers;
955   dex_code.ins_size = irCode->ins_count;
956   dex_code.outs_size = irCode->outs_count;
957   dex_code.tries_size = irCode->try_blocks.size();
958   dex_code.debug_info_off = FilePointer(irCode->debug_info);
959   dex_code.insns_size = irCode->instructions.size();
960 
961   auto& data = dex_->code;
962   dex::u4 offset = data.AddItem(4);
963   data.Push(&dex_code, offsetof(dex::Code, insns));
964   WriteInstructions(irCode->instructions);
965   if (!irCode->try_blocks.empty()) {
966     data.Align(4);
967     WriteTryBlocks(irCode);
968   }
969   return data.AbsoluteOffset(offset);
970 }
971 
972 // "encoded_field"
WriteEncodedField(const ir::EncodedField * ir_encoded_field,dex::u4 * base_index)973 void Writer::WriteEncodedField(const ir::EncodedField* ir_encoded_field,
974                        dex::u4* base_index) {
975   dex::u4 index_delta = ir_encoded_field->decl->index;
976   SLICER_CHECK(index_delta != dex::kNoIndex);
977   if (*base_index != dex::kNoIndex) {
978     SLICER_CHECK(index_delta > *base_index);
979     index_delta = index_delta - *base_index;
980   }
981   *base_index = ir_encoded_field->decl->index;
982 
983   auto& data = dex_->class_data;
984   data.PushULeb128(index_delta);
985   data.PushULeb128(ir_encoded_field->access_flags);
986 }
987 
988 // "encoded_method"
WriteEncodedMethod(const ir::EncodedMethod * ir_encoded_method,dex::u4 * base_index)989 void Writer::WriteEncodedMethod(const ir::EncodedMethod* ir_encoded_method,
990                         dex::u4* base_index) {
991   dex::u4 index_delta = ir_encoded_method->decl->index;
992   SLICER_CHECK(index_delta != dex::kNoIndex);
993   if (*base_index != dex::kNoIndex) {
994     SLICER_CHECK(index_delta > *base_index);
995     index_delta = index_delta - *base_index;
996   }
997   *base_index = ir_encoded_method->decl->index;
998 
999   dex::u4 code_offset = FilePointer(ir_encoded_method->code);
1000 
1001   auto& data = dex_->class_data;
1002   data.PushULeb128(index_delta);
1003   data.PushULeb128(ir_encoded_method->access_flags);
1004   data.PushULeb128(code_offset);
1005 }
1006 
1007 // "class_data_item"
WriteClassData(const ir::Class * ir_class)1008 dex::u4 Writer::WriteClassData(const ir::Class* ir_class) {
1009   if (ir_class->static_fields.empty() && ir_class->instance_fields.empty() &&
1010       ir_class->direct_methods.empty() && ir_class->virtual_methods.empty()) {
1011     return 0;
1012   }
1013 
1014   auto& data = dex_->class_data;
1015   dex::u4 offset = data.AddItem();
1016 
1017   data.PushULeb128(ir_class->static_fields.size());
1018   data.PushULeb128(ir_class->instance_fields.size());
1019   data.PushULeb128(ir_class->direct_methods.size());
1020   data.PushULeb128(ir_class->virtual_methods.size());
1021 
1022   dex::u4 base_index = dex::kNoIndex;
1023   for (auto ir_encoded_field : ir_class->static_fields) {
1024     WriteEncodedField(ir_encoded_field, &base_index);
1025   }
1026 
1027   base_index = dex::kNoIndex;
1028   for (auto ir_encoded_field : ir_class->instance_fields) {
1029     WriteEncodedField(ir_encoded_field, &base_index);
1030   }
1031 
1032   base_index = dex::kNoIndex;
1033   for (auto ir_encoded_method : ir_class->direct_methods) {
1034     WriteEncodedMethod(ir_encoded_method, &base_index);
1035   }
1036 
1037   base_index = dex::kNoIndex;
1038   for (auto ir_encoded_method : ir_class->virtual_methods) {
1039     WriteEncodedMethod(ir_encoded_method, &base_index);
1040   }
1041 
1042   return data.AbsoluteOffset(offset);
1043 }
1044 
1045 // "encoded_array_item"
WriteClassStaticValues(const ir::Class * ir_class)1046 dex::u4 Writer::WriteClassStaticValues(const ir::Class* ir_class) {
1047   if (ir_class->static_init == nullptr) {
1048     return 0;
1049   }
1050 
1051   dex::u4& offset = node_offset_[ir_class->static_init];
1052   if (offset == 0) {
1053     auto& data = dex_->encoded_arrays;
1054     offset = data.AddItem();
1055     WriteEncodedArray(ir_class->static_init, data);
1056     offset = data.AbsoluteOffset(offset);
1057   }
1058   return offset;
1059 }
1060 
1061 // Map an index from the original .dex to the new index
MapStringIndex(dex::u4 index) const1062 dex::u4 Writer::MapStringIndex(dex::u4 index) const {
1063   if (index != dex::kNoIndex) {
1064     index = dex_ir_->strings_map.at(index)->index;
1065     SLICER_CHECK(index != dex::kNoIndex);
1066   }
1067   return index;
1068 }
1069 
1070 // Map an index from the original .dex to the new index
MapTypeIndex(dex::u4 index) const1071 dex::u4 Writer::MapTypeIndex(dex::u4 index) const {
1072   if (index != dex::kNoIndex) {
1073     index = dex_ir_->types_map.at(index)->index;
1074     SLICER_CHECK(index != dex::kNoIndex);
1075   }
1076   return index;
1077 }
1078 
1079 // Map an index from the original .dex to the new index
MapFieldIndex(dex::u4 index) const1080 dex::u4 Writer::MapFieldIndex(dex::u4 index) const {
1081   if (index != dex::kNoIndex) {
1082     index = dex_ir_->fields_map.at(index)->index;
1083     SLICER_CHECK(index != dex::kNoIndex);
1084   }
1085   return index;
1086 }
1087 
1088 // Map an index from the original .dex to the new index
MapMethodIndex(dex::u4 index) const1089 dex::u4 Writer::MapMethodIndex(dex::u4 index) const {
1090   if (index != dex::kNoIndex) {
1091     index = dex_ir_->methods_map.at(index)->index;
1092     SLICER_CHECK(index != dex::kNoIndex);
1093   }
1094   return index;
1095 }
1096 
1097 // .dex IR node to file pointer (absolute offset)
FilePointer(const ir::Node * ir_node) const1098 dex::u4 Writer::FilePointer(const ir::Node* ir_node) const {
1099   if (ir_node == nullptr) {
1100     return 0;
1101   }
1102   auto it = node_offset_.find(ir_node);
1103   SLICER_CHECK(it != node_offset_.end());
1104   dex::u4 offset = it->second;
1105   SLICER_CHECK(offset > 0);
1106   return offset;
1107 }
1108 
1109 }  // namespace dex
1110