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