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