Home | History | Annotate | Download | only in slicer
      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>
     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
     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>
     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>
     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"
    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"
    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"
    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>
    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)
    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
    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>
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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"
    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"
    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"
    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"
    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"
    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"
    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"
    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"
    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"
    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"
    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"
    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
    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::kFmt20bc:
    831       case dex::kFmt21c:
    832       case dex::kFmt35c:
    833       case dex::kFmt3rc:
    834       case dex::kFmt22c:
    835         index16 = &ptr[1];
    836         break;
    837 
    838       case dex::kFmt31c:
    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"
    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"
    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"
    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"
    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"
   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"
   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
   1062 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
   1071 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
   1080 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
   1089 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)
   1098 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