diff options
| -rw-r--r-- | dexlayout/Android.bp | 1 | ||||
| -rw-r--r-- | dexlayout/dex_ir.cc | 144 | ||||
| -rw-r--r-- | dexlayout/dex_ir.h | 143 | ||||
| -rw-r--r-- | dexlayout/dex_ir_builder.cc | 12 | ||||
| -rw-r--r-- | dexlayout/dex_visualize.cc | 28 | ||||
| -rw-r--r-- | dexlayout/dex_writer.cc | 648 | ||||
| -rw-r--r-- | dexlayout/dex_writer.h | 74 | ||||
| -rw-r--r-- | dexlayout/dexlayout.cc | 112 | ||||
| -rw-r--r-- | dexlayout/dexlayout.h | 2 | ||||
| -rw-r--r-- | dexlayout/dexlayout_main.cc | 10 | ||||
| -rw-r--r-- | dexlayout/dexlayout_test.cc | 89 |
11 files changed, 1046 insertions, 217 deletions
diff --git a/dexlayout/Android.bp b/dexlayout/Android.bp index 0987df76dc..b9266f75bf 100644 --- a/dexlayout/Android.bp +++ b/dexlayout/Android.bp @@ -21,6 +21,7 @@ art_cc_binary { "dex_ir.cc", "dex_ir_builder.cc", "dex_visualize.cc", + "dex_writer.cc", ], cflags: ["-Wall"], shared_libs: [ diff --git a/dexlayout/dex_ir.cc b/dexlayout/dex_ir.cc index aff03cd6ea..bc909c3b56 100644 --- a/dexlayout/dex_ir.cc +++ b/dexlayout/dex_ir.cc @@ -55,6 +55,54 @@ static void GetLocalsCb(void* context, const DexFile::LocalInfo& entry) { entry.end_address_, entry.reg_))); } +static uint32_t GetDebugInfoStreamSize(const uint8_t* debug_info_stream) { + const uint8_t* stream = debug_info_stream; + DecodeUnsignedLeb128(&stream); // line_start + uint32_t parameters_size = DecodeUnsignedLeb128(&stream); + for (uint32_t i = 0; i < parameters_size; ++i) { + DecodeUnsignedLeb128P1(&stream); // Parameter name. + } + + for (;;) { + uint8_t opcode = *stream++; + switch (opcode) { + case DexFile::DBG_END_SEQUENCE: + return stream - debug_info_stream; // end of stream. + case DexFile::DBG_ADVANCE_PC: + DecodeUnsignedLeb128(&stream); // addr_diff + break; + case DexFile::DBG_ADVANCE_LINE: + DecodeSignedLeb128(&stream); // line_diff + break; + case DexFile::DBG_START_LOCAL: + DecodeUnsignedLeb128(&stream); // register_num + DecodeUnsignedLeb128P1(&stream); // name_idx + DecodeUnsignedLeb128P1(&stream); // type_idx + break; + case DexFile::DBG_START_LOCAL_EXTENDED: + DecodeUnsignedLeb128(&stream); // register_num + DecodeUnsignedLeb128P1(&stream); // name_idx + DecodeUnsignedLeb128P1(&stream); // type_idx + DecodeUnsignedLeb128P1(&stream); // sig_idx + break; + case DexFile::DBG_END_LOCAL: + case DexFile::DBG_RESTART_LOCAL: + DecodeUnsignedLeb128(&stream); // register_num + break; + case DexFile::DBG_SET_PROLOGUE_END: + case DexFile::DBG_SET_EPILOGUE_BEGIN: + break; + case DexFile::DBG_SET_FILE: { + DecodeUnsignedLeb128P1(&stream); // name_idx + break; + } + default: { + break; + } + } + } +} + EncodedValue* Collections::ReadEncodedValue(const uint8_t** data) { const uint8_t encoded_value = *(*data)++; const uint8_t type = encoded_value & 0x1f; @@ -179,7 +227,7 @@ void Collections::CreateTypeId(const DexFile& dex_file, uint32_t i) { void Collections::CreateProtoId(const DexFile& dex_file, uint32_t i) { const DexFile::ProtoId& disk_proto_id = dex_file.GetProtoId(i); const DexFile::TypeList* type_list = dex_file.GetProtoParameters(disk_proto_id); - TypeList* parameter_type_list = CreateTypeList(type_list, disk_proto_id.parameters_off_, true); + TypeList* parameter_type_list = CreateTypeList(type_list, disk_proto_id.parameters_off_); ProtoId* proto_id = new ProtoId(GetStringId(disk_proto_id.shorty_idx_), GetTypeId(disk_proto_id.return_type_idx_), @@ -210,7 +258,7 @@ void Collections::CreateClassDef(const DexFile& dex_file, uint32_t i) { const TypeId* superclass = GetTypeIdOrNullPtr(disk_class_def.superclass_idx_); const DexFile::TypeList* type_list = dex_file.GetInterfacesList(disk_class_def); - TypeList* interfaces_type_list = CreateTypeList(type_list, disk_class_def.interfaces_off_, false); + TypeList* interfaces_type_list = CreateTypeList(type_list, disk_class_def.interfaces_off_); const StringId* source_file = GetStringIdOrNullPtr(disk_class_def.source_file_idx_); // Annotations. @@ -232,9 +280,8 @@ void Collections::CreateClassDef(const DexFile& dex_file, uint32_t i) { class_defs_.AddIndexedItem(class_def, ClassDefsOffset() + i * ClassDef::ItemSize(), i); } -TypeList* Collections::CreateTypeList( - const DexFile::TypeList* dex_type_list, uint32_t offset, bool allow_empty) { - if (dex_type_list == nullptr && !allow_empty) { +TypeList* Collections::CreateTypeList(const DexFile::TypeList* dex_type_list, uint32_t offset) { + if (dex_type_list == nullptr) { return nullptr; } // TODO: Create more efficient lookup for existing type lists. @@ -244,7 +291,7 @@ TypeList* Collections::CreateTypeList( } } TypeIdVector* type_vector = new TypeIdVector(); - uint32_t size = dex_type_list == nullptr ? 0 : dex_type_list->Size(); + uint32_t size = dex_type_list->Size(); for (uint32_t index = 0; index < size; ++index) { type_vector->push_back(GetTypeId(dex_type_list->GetTypeItem(index).type_idx_)); } @@ -257,6 +304,11 @@ EncodedArrayItem* Collections::CreateEncodedArrayItem(const uint8_t* static_data if (static_data == nullptr) { return nullptr; } + for (std::unique_ptr<EncodedArrayItem>& existing_array_item : EncodedArrayItems()) { + if (existing_array_item->GetOffset() == offset) { + return existing_array_item.get(); + } + } uint32_t size = DecodeUnsignedLeb128(&static_data); EncodedValueVector* values = new EncodedValueVector(); for (uint32_t i = 0; i < size; ++i) { @@ -270,6 +322,11 @@ EncodedArrayItem* Collections::CreateEncodedArrayItem(const uint8_t* static_data AnnotationItem* Collections::CreateAnnotationItem(const DexFile::AnnotationItem* annotation, uint32_t offset) { + for (std::unique_ptr<AnnotationItem>& existing_annotation_item : AnnotationItems()) { + if (existing_annotation_item->GetOffset() == offset) { + return existing_annotation_item.get(); + } + } uint8_t visibility = annotation->visibility_; const uint8_t* annotation_data = annotation->annotation_; EncodedValue* encoded_value = @@ -284,9 +341,14 @@ AnnotationItem* Collections::CreateAnnotationItem(const DexFile::AnnotationItem* AnnotationSetItem* Collections::CreateAnnotationSetItem(const DexFile& dex_file, const DexFile::AnnotationSetItem& disk_annotations_item, uint32_t offset) { - if (disk_annotations_item.size_ == 0) { + if (disk_annotations_item.size_ == 0 && offset == 0) { return nullptr; } + for (std::unique_ptr<AnnotationSetItem>& existing_anno_set_item : AnnotationSetItems()) { + if (existing_anno_set_item->GetOffset() == offset) { + return existing_anno_set_item.get(); + } + } std::vector<AnnotationItem*>* items = new std::vector<AnnotationItem*>(); for (uint32_t i = 0; i < disk_annotations_item.size_; ++i) { const DexFile::AnnotationItem* annotation = @@ -305,6 +367,11 @@ AnnotationSetItem* Collections::CreateAnnotationSetItem(const DexFile& dex_file, AnnotationsDirectoryItem* Collections::CreateAnnotationsDirectoryItem(const DexFile& dex_file, const DexFile::AnnotationsDirectoryItem* disk_annotations_item, uint32_t offset) { + for (std::unique_ptr<AnnotationsDirectoryItem>& anno_dir_item : AnnotationsDirectoryItems()) { + if (anno_dir_item->GetOffset() == offset) { + return anno_dir_item.get(); + } + } const DexFile::AnnotationSetItem* class_set_item = dex_file.GetClassAnnotationSet(disk_annotations_item); AnnotationSetItem* class_annotation = nullptr; @@ -367,16 +434,25 @@ AnnotationsDirectoryItem* Collections::CreateAnnotationsDirectoryItem(const DexF ParameterAnnotation* Collections::GenerateParameterAnnotation( const DexFile& dex_file, MethodId* method_id, const DexFile::AnnotationSetRefList* annotation_set_ref_list, uint32_t offset) { - std::vector<AnnotationSetItem*>* annotations = new std::vector<AnnotationSetItem*>(); - for (uint32_t i = 0; i < annotation_set_ref_list->size_; ++i) { - const DexFile::AnnotationSetItem* annotation_set_item = - dex_file.GetSetRefItemItem(&annotation_set_ref_list->list_[i]); - uint32_t set_offset = annotation_set_ref_list->list_[i].annotations_off_; - annotations->push_back(CreateAnnotationSetItem(dex_file, *annotation_set_item, set_offset)); + AnnotationSetRefList* set_ref_list = nullptr; + for (std::unique_ptr<AnnotationSetRefList>& existing_set_ref_list : AnnotationSetRefLists()) { + if (existing_set_ref_list->GetOffset() == offset) { + set_ref_list = existing_set_ref_list.get(); + break; + } } - AnnotationSetRefList* new_ref_list = new AnnotationSetRefList(annotations); - annotation_set_ref_lists_.AddItem(new_ref_list, offset); - return new ParameterAnnotation(method_id, new_ref_list); + if (set_ref_list == nullptr) { + std::vector<AnnotationSetItem*>* annotations = new std::vector<AnnotationSetItem*>(); + for (uint32_t i = 0; i < annotation_set_ref_list->size_; ++i) { + const DexFile::AnnotationSetItem* annotation_set_item = + dex_file.GetSetRefItemItem(&annotation_set_ref_list->list_[i]); + uint32_t set_offset = annotation_set_ref_list->list_[i].annotations_off_; + annotations->push_back(CreateAnnotationSetItem(dex_file, *annotation_set_item, set_offset)); + } + set_ref_list = new AnnotationSetRefList(annotations); + annotation_set_ref_lists_.AddItem(set_ref_list, offset); + } + return new ParameterAnnotation(method_id, set_ref_list); } CodeItem* Collections::CreateCodeItem(const DexFile& dex_file, @@ -390,7 +466,10 @@ CodeItem* Collections::CreateCodeItem(const DexFile& dex_file, const uint8_t* debug_info_stream = dex_file.GetDebugInfoStream(&disk_code_item); DebugInfoItem* debug_info = nullptr; if (debug_info_stream != nullptr) { - debug_info = new DebugInfoItem(); + uint32_t debug_info_size = GetDebugInfoStreamSize(debug_info_stream); + uint8_t* debug_info_buffer = new uint8_t[debug_info_size]; + memcpy(debug_info_buffer, debug_info_stream, debug_info_size); + debug_info = new DebugInfoItem(debug_info_size, debug_info_buffer); debug_info_items_.AddItem(debug_info, disk_code_item.debug_info_off_); } @@ -399,26 +478,41 @@ CodeItem* Collections::CreateCodeItem(const DexFile& dex_file, memcpy(insns, disk_code_item.insns_, insns_size * sizeof(uint16_t)); TryItemVector* tries = nullptr; + CatchHandlerVector* handler_list = nullptr; if (tries_size > 0) { tries = new TryItemVector(); + handler_list = new CatchHandlerVector(); for (uint32_t i = 0; i < tries_size; ++i) { const DexFile::TryItem* disk_try_item = dex_file.GetTryItems(disk_code_item, i); uint32_t start_addr = disk_try_item->start_addr_; uint16_t insn_count = disk_try_item->insn_count_; - CatchHandlerVector* handlers = new CatchHandlerVector(); - for (CatchHandlerIterator it(disk_code_item, *disk_try_item); it.HasNext(); it.Next()) { - const uint16_t type_index = it.GetHandlerTypeIndex(); - const TypeId* type_id = GetTypeIdOrNullPtr(type_index); - handlers->push_back(std::unique_ptr<const CatchHandler>( - new CatchHandler(type_id, it.GetHandlerAddress()))); + uint16_t handler_off = disk_try_item->handler_off_; + const CatchHandler* handlers = nullptr; + for (std::unique_ptr<const CatchHandler>& existing_handlers : *handler_list) { + if (handler_off == existing_handlers->GetListOffset()) { + handlers = existing_handlers.get(); + } + } + if (handlers == nullptr) { + bool catch_all = false; + TypeAddrPairVector* addr_pairs = new TypeAddrPairVector(); + for (CatchHandlerIterator it(disk_code_item, *disk_try_item); it.HasNext(); it.Next()) { + const uint16_t type_index = it.GetHandlerTypeIndex(); + const TypeId* type_id = GetTypeIdOrNullPtr(type_index); + catch_all |= type_id == nullptr; + addr_pairs->push_back(std::unique_ptr<const TypeAddrPair>( + new TypeAddrPair(type_id, it.GetHandlerAddress()))); + } + handlers = new CatchHandler(catch_all, handler_off, addr_pairs); + handler_list->push_back(std::unique_ptr<const CatchHandler>(handlers)); } TryItem* try_item = new TryItem(start_addr, insn_count, handlers); tries->push_back(std::unique_ptr<const TryItem>(try_item)); } } // TODO: Calculate the size of the code item. - CodeItem* code_item = - new CodeItem(registers_size, ins_size, outs_size, debug_info, insns_size, insns, tries); + CodeItem* code_item = new CodeItem( + registers_size, ins_size, outs_size, debug_info, insns_size, insns, tries, handler_list); code_items_.AddItem(code_item, offset); return code_item; } diff --git a/dexlayout/dex_ir.h b/dexlayout/dex_ir.h index f3d2c900e3..5e686d3c00 100644 --- a/dexlayout/dex_ir.h +++ b/dexlayout/dex_ir.h @@ -24,6 +24,7 @@ #include "dex_file-inl.h" #include "leb128.h" +#include "utf.h" namespace art { namespace dex_ir { @@ -137,10 +138,22 @@ class Collections { std::vector<std::unique_ptr<FieldId>>& FieldIds() { return field_ids_.Collection(); } std::vector<std::unique_ptr<MethodId>>& MethodIds() { return method_ids_.Collection(); } std::vector<std::unique_ptr<ClassDef>>& ClassDefs() { return class_defs_.Collection(); } - + std::vector<std::unique_ptr<StringData>>& StringDatas() { return string_datas_.Collection(); } std::vector<std::unique_ptr<TypeList>>& TypeLists() { return type_lists_.Collection(); } std::vector<std::unique_ptr<EncodedArrayItem>>& EncodedArrayItems() { return encoded_array_items_.Collection(); } + std::vector<std::unique_ptr<AnnotationItem>>& AnnotationItems() + { return annotation_items_.Collection(); } + std::vector<std::unique_ptr<AnnotationSetItem>>& AnnotationSetItems() + { return annotation_set_items_.Collection(); } + std::vector<std::unique_ptr<AnnotationSetRefList>>& AnnotationSetRefLists() + { return annotation_set_ref_lists_.Collection(); } + std::vector<std::unique_ptr<AnnotationsDirectoryItem>>& AnnotationsDirectoryItems() + { return annotations_directory_items_.Collection(); } + std::vector<std::unique_ptr<DebugInfoItem>>& DebugInfoItems() + { return debug_info_items_.Collection(); } + std::vector<std::unique_ptr<CodeItem>>& CodeItems() { return code_items_.Collection(); } + std::vector<std::unique_ptr<ClassData>>& ClassDatas() { return class_datas_.Collection(); } void CreateStringId(const DexFile& dex_file, uint32_t i); void CreateTypeId(const DexFile& dex_file, uint32_t i); @@ -149,7 +162,7 @@ class Collections { void CreateMethodId(const DexFile& dex_file, uint32_t i); void CreateClassDef(const DexFile& dex_file, uint32_t i); - TypeList* CreateTypeList(const DexFile::TypeList* type_list, uint32_t offset, bool allow_empty); + TypeList* CreateTypeList(const DexFile::TypeList* type_list, uint32_t offset); EncodedArrayItem* CreateEncodedArrayItem(const uint8_t* static_data, uint32_t offset); AnnotationItem* CreateAnnotationItem(const DexFile::AnnotationItem* annotation, uint32_t offset); AnnotationSetItem* CreateAnnotationSetItem(const DexFile& dex_file, @@ -182,14 +195,16 @@ class Collections { uint32_t ClassDefsOffset() const { return class_defs_.GetOffset(); } uint32_t StringDatasOffset() const { return string_datas_.GetOffset(); } uint32_t TypeListsOffset() const { return type_lists_.GetOffset(); } - uint32_t EncodedArrayOffset() const { return encoded_array_items_.GetOffset(); } - uint32_t AnnotationOffset() const { return annotation_items_.GetOffset(); } - uint32_t AnnotationSetOffset() const { return annotation_set_items_.GetOffset(); } + uint32_t EncodedArrayItemsOffset() const { return encoded_array_items_.GetOffset(); } + uint32_t AnnotationItemsOffset() const { return annotation_items_.GetOffset(); } + uint32_t AnnotationSetItemsOffset() const { return annotation_set_items_.GetOffset(); } uint32_t AnnotationSetRefListsOffset() const { return annotation_set_ref_lists_.GetOffset(); } - uint32_t AnnotationsDirectoryOffset() const { return annotations_directory_items_.GetOffset(); } - uint32_t DebugInfoOffset() const { return debug_info_items_.GetOffset(); } + uint32_t AnnotationsDirectoryItemsOffset() const + { return annotations_directory_items_.GetOffset(); } + uint32_t DebugInfoItemsOffset() const { return debug_info_items_.GetOffset(); } uint32_t CodeItemsOffset() const { return code_items_.GetOffset(); } uint32_t ClassDatasOffset() const { return class_datas_.GetOffset(); } + uint32_t MapItemOffset() const { return map_item_offset_; } void SetStringIdsOffset(uint32_t new_offset) { string_ids_.SetOffset(new_offset); } void SetTypeIdsOffset(uint32_t new_offset) { type_ids_.SetOffset(new_offset); } @@ -199,16 +214,19 @@ class Collections { void SetClassDefsOffset(uint32_t new_offset) { class_defs_.SetOffset(new_offset); } void SetStringDatasOffset(uint32_t new_offset) { string_datas_.SetOffset(new_offset); } void SetTypeListsOffset(uint32_t new_offset) { type_lists_.SetOffset(new_offset); } - void SetEncodedArrayOffset(uint32_t new_offset) { encoded_array_items_.SetOffset(new_offset); } - void SetAnnotationOffset(uint32_t new_offset) { annotation_items_.SetOffset(new_offset); } - void SetAnnotationSetOffset(uint32_t new_offset) { annotation_set_items_.SetOffset(new_offset); } + void SetEncodedArrayItemsOffset(uint32_t new_offset) + { encoded_array_items_.SetOffset(new_offset); } + void SetAnnotationItemsOffset(uint32_t new_offset) { annotation_items_.SetOffset(new_offset); } + void SetAnnotationSetItemsOffset(uint32_t new_offset) + { annotation_set_items_.SetOffset(new_offset); } void SetAnnotationSetRefListsOffset(uint32_t new_offset) { annotation_set_ref_lists_.SetOffset(new_offset); } - void SetAnnotationsDirectoryOffset(uint32_t new_offset) + void SetAnnotationsDirectoryItemsOffset(uint32_t new_offset) { annotations_directory_items_.SetOffset(new_offset); } - void SetDebugInfoOffset(uint32_t new_offset) { debug_info_items_.SetOffset(new_offset); } + void SetDebugInfoItemsOffset(uint32_t new_offset) { debug_info_items_.SetOffset(new_offset); } void SetCodeItemsOffset(uint32_t new_offset) { code_items_.SetOffset(new_offset); } void SetClassDatasOffset(uint32_t new_offset) { class_datas_.SetOffset(new_offset); } + void SetMapItemOffset(uint32_t new_offset) { map_item_offset_ = new_offset; } uint32_t StringIdsSize() const { return string_ids_.Size(); } uint32_t TypeIdsSize() const { return type_ids_.Size(); } @@ -216,15 +234,14 @@ class Collections { uint32_t FieldIdsSize() const { return field_ids_.Size(); } uint32_t MethodIdsSize() const { return method_ids_.Size(); } uint32_t ClassDefsSize() const { return class_defs_.Size(); } - uint32_t StringDatasSize() const { return string_datas_.Size(); } uint32_t TypeListsSize() const { return type_lists_.Size(); } - uint32_t EncodedArraySize() const { return encoded_array_items_.Size(); } - uint32_t AnnotationSize() const { return annotation_items_.Size(); } - uint32_t AnnotationSetSize() const { return annotation_set_items_.Size(); } + uint32_t EncodedArrayItemsSize() const { return encoded_array_items_.Size(); } + uint32_t AnnotationItemsSize() const { return annotation_items_.Size(); } + uint32_t AnnotationSetItemsSize() const { return annotation_set_items_.Size(); } uint32_t AnnotationSetRefListsSize() const { return annotation_set_ref_lists_.Size(); } - uint32_t AnnotationsDirectorySize() const { return annotations_directory_items_.Size(); } - uint32_t DebugInfoSize() const { return debug_info_items_.Size(); } + uint32_t AnnotationsDirectoryItemsSize() const { return annotations_directory_items_.Size(); } + uint32_t DebugInfoItemsSize() const { return debug_info_items_.Size(); } uint32_t CodeItemsSize() const { return code_items_.Size(); } uint32_t ClassDatasSize() const { return class_datas_.Size(); } @@ -255,6 +272,8 @@ class Collections { CollectionWithOffset<CodeItem> code_items_; CollectionWithOffset<ClassData> class_datas_; + uint32_t map_item_offset_ = 0; + DISALLOW_COPY_AND_ASSIGN(Collections); }; @@ -364,7 +383,7 @@ class Header : public Item { class StringData : public Item { public: explicit StringData(const char* data) : data_(strdup(data)) { - size_ = UnsignedLeb128Size(strlen(data)) + strlen(data); + size_ = UnsignedLeb128Size(CountModifiedUtf8Chars(data)) + strlen(data); } const char* Data() const { return data_.get(); } @@ -372,7 +391,7 @@ class StringData : public Item { void Accept(AbstractDispatcher* dispatch) const { dispatch->Dispatch(this); } private: - std::unique_ptr<const char> data_; + UniqueCPtr<const char> data_; DISALLOW_COPY_AND_ASSIGN(StringData); }; @@ -442,14 +461,14 @@ class ProtoId : public IndexedItem { const StringId* Shorty() const { return shorty_; } const TypeId* ReturnType() const { return return_type_; } - const TypeIdVector& Parameters() const { return *parameters_->GetTypeList(); } + const TypeList* Parameters() const { return parameters_; } void Accept(AbstractDispatcher* dispatch) const { dispatch->Dispatch(this); } private: const StringId* shorty_; const TypeId* return_type_; - TypeList* parameters_; + TypeList* parameters_; // This can be nullptr. DISALLOW_COPY_AND_ASSIGN(ProtoId); }; @@ -533,7 +552,7 @@ class MethodItem : public Item { private: uint32_t access_flags_; const MethodId* method_id_; - const CodeItem* code_; + const CodeItem* code_; // This can be nullptr. DISALLOW_COPY_AND_ASSIGN(MethodItem); }; @@ -691,8 +710,8 @@ class ClassDef : public IndexedItem { interfaces_(interfaces), source_file_(source_file), annotations_(annotations), - static_values_(static_values), - class_data_(class_data) { size_ = kClassDefItemSize; } + class_data_(class_data), + static_values_(static_values) { size_ = kClassDefItemSize; } ~ClassDef() OVERRIDE { } @@ -706,8 +725,8 @@ class ClassDef : public IndexedItem { uint32_t InterfacesOffset() { return interfaces_ == nullptr ? 0 : interfaces_->GetOffset(); } const StringId* SourceFile() const { return source_file_; } AnnotationsDirectoryItem* Annotations() const { return annotations_; } - EncodedArrayItem* StaticValues() { return static_values_; } ClassData* GetClassData() { return class_data_; } + EncodedArrayItem* StaticValues() { return static_values_; } MethodItem* GenerateMethodItem(Header& header, ClassDataItemIterator& cdii); @@ -716,19 +735,19 @@ class ClassDef : public IndexedItem { private: const TypeId* class_type_; uint32_t access_flags_; - const TypeId* superclass_; - TypeList* interfaces_; - const StringId* source_file_; - AnnotationsDirectoryItem* annotations_; - EncodedArrayItem* static_values_; - ClassData* class_data_; + const TypeId* superclass_; // This can be nullptr. + TypeList* interfaces_; // This can be nullptr. + const StringId* source_file_; // This can be nullptr. + AnnotationsDirectoryItem* annotations_; // This can be nullptr. + ClassData* class_data_; // This can be nullptr. + EncodedArrayItem* static_values_; // This can be nullptr. DISALLOW_COPY_AND_ASSIGN(ClassDef); }; -class CatchHandler { +class TypeAddrPair { public: - CatchHandler(const TypeId* type_id, uint32_t address) : type_id_(type_id), address_(address) { } + TypeAddrPair(const TypeId* type_id, uint32_t address) : type_id_(type_id), address_(address) { } const TypeId* GetTypeId() const { return type_id_; } uint32_t GetAddress() const { return address_; } @@ -737,6 +756,25 @@ class CatchHandler { const TypeId* type_id_; uint32_t address_; + DISALLOW_COPY_AND_ASSIGN(TypeAddrPair); +}; + +using TypeAddrPairVector = std::vector<std::unique_ptr<const TypeAddrPair>>; + +class CatchHandler { + public: + explicit CatchHandler(bool catch_all, uint16_t list_offset, TypeAddrPairVector* handlers) + : catch_all_(catch_all), list_offset_(list_offset), handlers_(handlers) { } + + bool HasCatchAll() const { return catch_all_; } + uint16_t GetListOffset() const { return list_offset_; } + TypeAddrPairVector* GetHandlers() const { return handlers_.get(); } + + private: + bool catch_all_; + uint16_t list_offset_; + std::unique_ptr<TypeAddrPairVector> handlers_; + DISALLOW_COPY_AND_ASSIGN(CatchHandler); }; @@ -744,20 +782,20 @@ using CatchHandlerVector = std::vector<std::unique_ptr<const CatchHandler>>; class TryItem : public Item { public: - TryItem(uint32_t start_addr, uint16_t insn_count, CatchHandlerVector* handlers) + TryItem(uint32_t start_addr, uint16_t insn_count, const CatchHandler* handlers) : start_addr_(start_addr), insn_count_(insn_count), handlers_(handlers) { } ~TryItem() OVERRIDE { } uint32_t StartAddr() const { return start_addr_; } uint16_t InsnCount() const { return insn_count_; } - const CatchHandlerVector& GetHandlers() const { return *handlers_.get(); } + const CatchHandler* GetHandlers() const { return handlers_; } void Accept(AbstractDispatcher* dispatch) { dispatch->Dispatch(this); } private: uint32_t start_addr_; uint16_t insn_count_; - std::unique_ptr<CatchHandlerVector> handlers_; + const CatchHandler* handlers_; DISALLOW_COPY_AND_ASSIGN(TryItem); }; @@ -772,14 +810,16 @@ class CodeItem : public Item { DebugInfoItem* debug_info, uint32_t insns_size, uint16_t* insns, - TryItemVector* tries) + TryItemVector* tries, + CatchHandlerVector* handlers) : registers_size_(registers_size), ins_size_(ins_size), outs_size_(outs_size), debug_info_(debug_info), insns_size_(insns_size), insns_(insns), - tries_(tries) { } + tries_(tries), + handlers_(handlers) { } ~CodeItem() OVERRIDE { } @@ -791,6 +831,7 @@ class CodeItem : public Item { uint32_t InsnsSize() const { return insns_size_; } uint16_t* Insns() const { return insns_.get(); } TryItemVector* Tries() const { return tries_.get(); } + CatchHandlerVector* Handlers() const { return handlers_.get(); } void Accept(AbstractDispatcher* dispatch) { dispatch->Dispatch(this); } @@ -798,10 +839,11 @@ class CodeItem : public Item { uint16_t registers_size_; uint16_t ins_size_; uint16_t outs_size_; - DebugInfoItem* debug_info_; + DebugInfoItem* debug_info_; // This can be nullptr. uint32_t insns_size_; std::unique_ptr<uint16_t[]> insns_; - std::unique_ptr<TryItemVector> tries_; + std::unique_ptr<TryItemVector> tries_; // This can be nullptr. + std::unique_ptr<CatchHandlerVector> handlers_; // This can be nullptr. DISALLOW_COPY_AND_ASSIGN(CodeItem); }; @@ -841,12 +883,19 @@ using LocalInfoVector = std::vector<std::unique_ptr<LocalInfo>>; class DebugInfoItem : public Item { public: - DebugInfoItem() = default; + DebugInfoItem(uint32_t debug_info_size, uint8_t* debug_info) + : debug_info_size_(debug_info_size), debug_info_(debug_info) { } + + uint32_t GetDebugInfoSize() const { return debug_info_size_; } + uint8_t* GetDebugInfo() const { return debug_info_.get(); } PositionInfoVector& GetPositionInfo() { return positions_; } LocalInfoVector& GetLocalInfo() { return locals_; } private: + uint32_t debug_info_size_; + std::unique_ptr<uint8_t[]> debug_info_; + PositionInfoVector positions_; LocalInfoVector locals_; @@ -899,7 +948,7 @@ class AnnotationSetRefList : public Item { void Accept(AbstractDispatcher* dispatch) { dispatch->Dispatch(this); } private: - std::unique_ptr<std::vector<AnnotationSetItem*>> items_; + std::unique_ptr<std::vector<AnnotationSetItem*>> items_; // Elements of vector can be nullptr. DISALLOW_COPY_AND_ASSIGN(AnnotationSetRefList); }; @@ -974,10 +1023,10 @@ class AnnotationsDirectoryItem : public Item { void Accept(AbstractDispatcher* dispatch) { dispatch->Dispatch(this); } private: - AnnotationSetItem* class_annotation_; - std::unique_ptr<FieldAnnotationVector> field_annotations_; - std::unique_ptr<MethodAnnotationVector> method_annotations_; - std::unique_ptr<ParameterAnnotationVector> parameter_annotations_; + AnnotationSetItem* class_annotation_; // This can be nullptr. + std::unique_ptr<FieldAnnotationVector> field_annotations_; // This can be nullptr. + std::unique_ptr<MethodAnnotationVector> method_annotations_; // This can be nullptr. + std::unique_ptr<ParameterAnnotationVector> parameter_annotations_; // This can be nullptr. DISALLOW_COPY_AND_ASSIGN(AnnotationsDirectoryItem); }; diff --git a/dexlayout/dex_ir_builder.cc b/dexlayout/dex_ir_builder.cc index 599f48b3b6..68ff2a253d 100644 --- a/dexlayout/dex_ir_builder.cc +++ b/dexlayout/dex_ir_builder.cc @@ -70,6 +70,8 @@ Header* DexIrBuilder(const DexFile& dex_file) { for (uint32_t i = 0; i < dex_file.NumClassDefs(); ++i) { collections.CreateClassDef(dex_file, i); } + // MapItem. + collections.SetMapItemOffset(disk_header.map_off_); CheckAndSetRemainingOffsets(dex_file, &collections); @@ -124,7 +126,7 @@ static void CheckAndSetRemainingOffsets(const DexFile& dex_file, Collections* co collections->SetAnnotationSetRefListsOffset(item->offset_); break; case DexFile::kDexTypeAnnotationSetItem: - collections->SetAnnotationSetOffset(item->offset_); + collections->SetAnnotationSetItemsOffset(item->offset_); break; case DexFile::kDexTypeClassDataItem: collections->SetClassDatasOffset(item->offset_); @@ -136,16 +138,16 @@ static void CheckAndSetRemainingOffsets(const DexFile& dex_file, Collections* co collections->SetStringDatasOffset(item->offset_); break; case DexFile::kDexTypeDebugInfoItem: - collections->SetDebugInfoOffset(item->offset_); + collections->SetDebugInfoItemsOffset(item->offset_); break; case DexFile::kDexTypeAnnotationItem: - collections->SetAnnotationOffset(item->offset_); + collections->SetAnnotationItemsOffset(item->offset_); break; case DexFile::kDexTypeEncodedArrayItem: - collections->SetEncodedArrayOffset(item->offset_); + collections->SetEncodedArrayItemsOffset(item->offset_); break; case DexFile::kDexTypeAnnotationsDirectoryItem: - collections->SetAnnotationsDirectoryOffset(item->offset_); + collections->SetAnnotationsDirectoryItemsOffset(item->offset_); break; default: LOG(ERROR) << "Unknown map list item type."; diff --git a/dexlayout/dex_visualize.cc b/dexlayout/dex_visualize.cc index be7bade8ef..46dff5f5f2 100644 --- a/dexlayout/dex_visualize.cc +++ b/dexlayout/dex_visualize.cc @@ -87,18 +87,18 @@ static const std::vector<FileSection> kFileSections = { }, { "EncArr", DexFile::kDexTypeEncodedArrayItem, - &dex_ir::Collections::EncodedArraySize, - &dex_ir::Collections::EncodedArrayOffset + &dex_ir::Collections::EncodedArrayItemsSize, + &dex_ir::Collections::EncodedArrayItemsOffset }, { "Annotation", DexFile::kDexTypeAnnotationItem, - &dex_ir::Collections::AnnotationSize, - &dex_ir::Collections::AnnotationOffset + &dex_ir::Collections::AnnotationItemsSize, + &dex_ir::Collections::AnnotationItemsOffset }, { "AnnoSet", DexFile::kDexTypeAnnotationSetItem, - &dex_ir::Collections::AnnotationSetSize, - &dex_ir::Collections::AnnotationSetOffset + &dex_ir::Collections::AnnotationSetItemsSize, + &dex_ir::Collections::AnnotationSetItemsOffset }, { "AnnoSetRL", DexFile::kDexTypeAnnotationSetRefList, @@ -107,13 +107,13 @@ static const std::vector<FileSection> kFileSections = { }, { "AnnoDir", DexFile::kDexTypeAnnotationsDirectoryItem, - &dex_ir::Collections::AnnotationsDirectorySize, - &dex_ir::Collections::AnnotationsDirectoryOffset + &dex_ir::Collections::AnnotationsDirectoryItemsSize, + &dex_ir::Collections::AnnotationsDirectoryItemsOffset }, { "DebugInfo", DexFile::kDexTypeDebugInfoItem, - &dex_ir::Collections::DebugInfoSize, - &dex_ir::Collections::DebugInfoOffset + &dex_ir::Collections::DebugInfoItemsSize, + &dex_ir::Collections::DebugInfoItemsOffset }, { "CodeItem", DexFile::kDexTypeCodeItem, @@ -244,9 +244,11 @@ class Dumper { return; } DumpStringId(proto_id->Shorty(), class_index); - const dex_ir::TypeIdVector& parameters = proto_id->Parameters(); - for (const dex_ir::TypeId* t : parameters) { - DumpTypeId(t, class_index); + const dex_ir::TypeList* type_list = proto_id->Parameters(); + if (type_list != nullptr) { + for (const dex_ir::TypeId* t : *type_list->GetTypeList()) { + DumpTypeId(t, class_index); + } } DumpTypeId(proto_id->ReturnType(), class_index); } diff --git a/dexlayout/dex_writer.cc b/dexlayout/dex_writer.cc new file mode 100644 index 0000000000..dba5da0fb1 --- /dev/null +++ b/dexlayout/dex_writer.cc @@ -0,0 +1,648 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Header file of an in-memory representation of DEX files. + */ + +#include <stdint.h> + +#include <queue> +#include <vector> + +#include "dex_writer.h" +#include "utf.h" + +namespace art { + +size_t EncodeIntValue(int32_t value, uint8_t* buffer) { + size_t length = 0; + if (value >= 0) { + while (value > 0x7f) { + buffer[length++] = static_cast<uint8_t>(value); + value >>= 8; + } + } else { + while (value < -0x80) { + buffer[length++] = static_cast<uint8_t>(value); + value >>= 8; + } + } + buffer[length++] = static_cast<uint8_t>(value); + return length; +} + +size_t EncodeUIntValue(uint32_t value, uint8_t* buffer) { + size_t length = 0; + do { + buffer[length++] = static_cast<uint8_t>(value); + value >>= 8; + } while (value != 0); + return length; +} + +size_t EncodeLongValue(int64_t value, uint8_t* buffer) { + size_t length = 0; + if (value >= 0) { + while (value > 0x7f) { + buffer[length++] = static_cast<uint8_t>(value); + value >>= 8; + } + } else { + while (value < -0x80) { + buffer[length++] = static_cast<uint8_t>(value); + value >>= 8; + } + } + buffer[length++] = static_cast<uint8_t>(value); + return length; +} + +union FloatUnion { + float f_; + uint32_t i_; +}; + +size_t EncodeFloatValue(float value, uint8_t* buffer) { + FloatUnion float_union; + float_union.f_ = value; + uint32_t int_value = float_union.i_; + size_t index = 3; + do { + buffer[index--] = int_value >> 24; + int_value <<= 8; + } while (int_value != 0); + return 3 - index; +} + +union DoubleUnion { + double d_; + uint64_t l_; +}; + +size_t EncodeDoubleValue(double value, uint8_t* buffer) { + DoubleUnion double_union; + double_union.d_ = value; + uint64_t long_value = double_union.l_; + size_t index = 7; + do { + buffer[index--] = long_value >> 56; + long_value <<= 8; + } while (long_value != 0); + return 7 - index; +} + +size_t DexWriter::Write(const void* buffer, size_t length, size_t offset) { + return dex_file_->PwriteFully(buffer, length, offset) ? length : 0; +} + +size_t DexWriter::WriteSleb128(uint32_t value, size_t offset) { + uint8_t buffer[8]; + EncodeSignedLeb128(buffer, value); + return Write(buffer, SignedLeb128Size(value), offset); +} + +size_t DexWriter::WriteUleb128(uint32_t value, size_t offset) { + uint8_t buffer[8]; + EncodeUnsignedLeb128(buffer, value); + return Write(buffer, UnsignedLeb128Size(value), offset); +} + +size_t DexWriter::WriteEncodedValue(dex_ir::EncodedValue* encoded_value, size_t offset) { + size_t original_offset = offset; + size_t start = 0; + size_t length; + uint8_t buffer[8]; + int8_t type = encoded_value->Type(); + switch (type) { + case DexFile::kDexAnnotationByte: + length = EncodeIntValue(encoded_value->GetByte(), buffer); + break; + case DexFile::kDexAnnotationShort: + length = EncodeIntValue(encoded_value->GetShort(), buffer); + break; + case DexFile::kDexAnnotationChar: + length = EncodeUIntValue(encoded_value->GetChar(), buffer); + break; + case DexFile::kDexAnnotationInt: + length = EncodeIntValue(encoded_value->GetInt(), buffer); + break; + case DexFile::kDexAnnotationLong: + length = EncodeLongValue(encoded_value->GetLong(), buffer); + break; + case DexFile::kDexAnnotationFloat: + length = EncodeFloatValue(encoded_value->GetFloat(), buffer); + start = 4 - length; + break; + case DexFile::kDexAnnotationDouble: + length = EncodeDoubleValue(encoded_value->GetDouble(), buffer); + start = 8 - length; + break; + case DexFile::kDexAnnotationString: + length = EncodeUIntValue(encoded_value->GetStringId()->GetIndex(), buffer); + break; + case DexFile::kDexAnnotationType: + length = EncodeUIntValue(encoded_value->GetTypeId()->GetIndex(), buffer); + break; + case DexFile::kDexAnnotationField: + case DexFile::kDexAnnotationEnum: + length = EncodeUIntValue(encoded_value->GetFieldId()->GetIndex(), buffer); + break; + case DexFile::kDexAnnotationMethod: + length = EncodeUIntValue(encoded_value->GetMethodId()->GetIndex(), buffer); + break; + case DexFile::kDexAnnotationArray: + offset += WriteEncodedValueHeader(type, 0, offset); + offset += WriteEncodedArray(encoded_value->GetEncodedArray()->GetEncodedValues(), offset); + return offset - original_offset; + case DexFile::kDexAnnotationAnnotation: + offset += WriteEncodedValueHeader(type, 0, offset); + offset += WriteEncodedAnnotation(encoded_value->GetEncodedAnnotation(), offset); + return offset - original_offset; + case DexFile::kDexAnnotationNull: + return WriteEncodedValueHeader(type, 0, offset); + case DexFile::kDexAnnotationBoolean: + return WriteEncodedValueHeader(type, encoded_value->GetBoolean() ? 1 : 0, offset); + default: + return 0; + } + offset += WriteEncodedValueHeader(type, length - 1, offset); + offset += Write(buffer + start, length, offset); + return offset - original_offset; +} + +size_t DexWriter::WriteEncodedValueHeader(int8_t value_type, size_t value_arg, size_t offset) { + uint8_t buffer[1] = { static_cast<uint8_t>((value_arg << 5) | value_type) }; + return Write(buffer, sizeof(uint8_t), offset); +} + +size_t DexWriter::WriteEncodedArray(dex_ir::EncodedValueVector* values, size_t offset) { + size_t original_offset = offset; + offset += WriteUleb128(values->size(), offset); + for (std::unique_ptr<dex_ir::EncodedValue>& value : *values) { + offset += WriteEncodedValue(value.get(), offset); + } + return offset - original_offset; +} + +size_t DexWriter::WriteEncodedAnnotation(dex_ir::EncodedAnnotation* annotation, size_t offset) { + size_t original_offset = offset; + offset += WriteUleb128(annotation->GetType()->GetIndex(), offset); + offset += WriteUleb128(annotation->GetAnnotationElements()->size(), offset); + for (std::unique_ptr<dex_ir::AnnotationElement>& annotation_element : + *annotation->GetAnnotationElements()) { + offset += WriteUleb128(annotation_element->GetName()->GetIndex(), offset); + offset += WriteEncodedValue(annotation_element->GetValue(), offset); + } + return offset - original_offset; +} + +size_t DexWriter::WriteEncodedFields(dex_ir::FieldItemVector* fields, size_t offset) { + size_t original_offset = offset; + uint32_t prev_index = 0; + for (std::unique_ptr<dex_ir::FieldItem>& field : *fields) { + uint32_t index = field->GetFieldId()->GetIndex(); + offset += WriteUleb128(index - prev_index, offset); + offset += WriteUleb128(field->GetAccessFlags(), offset); + prev_index = index; + } + return offset - original_offset; +} + +size_t DexWriter::WriteEncodedMethods(dex_ir::MethodItemVector* methods, size_t offset) { + size_t original_offset = offset; + uint32_t prev_index = 0; + for (std::unique_ptr<dex_ir::MethodItem>& method : *methods) { + uint32_t index = method->GetMethodId()->GetIndex(); + uint32_t code_off = method->GetCodeItem() == nullptr ? 0 : method->GetCodeItem()->GetOffset(); + offset += WriteUleb128(index - prev_index, offset); + offset += WriteUleb128(method->GetAccessFlags(), offset); + offset += WriteUleb128(code_off, offset); + prev_index = index; + } + return offset - original_offset; +} + +void DexWriter::WriteStrings() { + uint32_t string_data_off[1]; + for (std::unique_ptr<dex_ir::StringId>& string_id : header_.GetCollections().StringIds()) { + string_data_off[0] = string_id->DataItem()->GetOffset(); + Write(string_data_off, string_id->GetSize(), string_id->GetOffset()); + } + + for (std::unique_ptr<dex_ir::StringData>& string_data : header_.GetCollections().StringDatas()) { + uint32_t offset = string_data->GetOffset(); + offset += WriteUleb128(CountModifiedUtf8Chars(string_data->Data()), offset); + Write(string_data->Data(), strlen(string_data->Data()), offset); + } +} + +void DexWriter::WriteTypes() { + uint32_t descriptor_idx[1]; + for (std::unique_ptr<dex_ir::TypeId>& type_id : header_.GetCollections().TypeIds()) { + descriptor_idx[0] = type_id->GetStringId()->GetIndex(); + Write(descriptor_idx, type_id->GetSize(), type_id->GetOffset()); + } +} + +void DexWriter::WriteTypeLists() { + uint32_t size[1]; + uint16_t list[1]; + for (std::unique_ptr<dex_ir::TypeList>& type_list : header_.GetCollections().TypeLists()) { + size[0] = type_list->GetTypeList()->size(); + uint32_t offset = type_list->GetOffset(); + offset += Write(size, sizeof(uint32_t), offset); + for (const dex_ir::TypeId* type_id : *type_list->GetTypeList()) { + list[0] = type_id->GetIndex(); + offset += Write(list, sizeof(uint16_t), offset); + } + } +} + +void DexWriter::WriteProtos() { + uint32_t buffer[3]; + for (std::unique_ptr<dex_ir::ProtoId>& proto_id : header_.GetCollections().ProtoIds()) { + buffer[0] = proto_id->Shorty()->GetIndex(); + buffer[1] = proto_id->ReturnType()->GetIndex(); + buffer[2] = proto_id->Parameters() == nullptr ? 0 : proto_id->Parameters()->GetOffset(); + Write(buffer, proto_id->GetSize(), proto_id->GetOffset()); + } +} + +void DexWriter::WriteFields() { + uint16_t buffer[4]; + for (std::unique_ptr<dex_ir::FieldId>& field_id : header_.GetCollections().FieldIds()) { + buffer[0] = field_id->Class()->GetIndex(); + buffer[1] = field_id->Type()->GetIndex(); + buffer[2] = field_id->Name()->GetIndex(); + buffer[3] = field_id->Name()->GetIndex() >> 16; + Write(buffer, field_id->GetSize(), field_id->GetOffset()); + } +} + +void DexWriter::WriteMethods() { + uint16_t buffer[4]; + for (std::unique_ptr<dex_ir::MethodId>& method_id : header_.GetCollections().MethodIds()) { + buffer[0] = method_id->Class()->GetIndex(); + buffer[1] = method_id->Proto()->GetIndex(); + buffer[2] = method_id->Name()->GetIndex(); + buffer[3] = method_id->Name()->GetIndex() >> 16; + Write(buffer, method_id->GetSize(), method_id->GetOffset()); + } +} + +void DexWriter::WriteEncodedArrays() { + for (std::unique_ptr<dex_ir::EncodedArrayItem>& encoded_array : + header_.GetCollections().EncodedArrayItems()) { + WriteEncodedArray(encoded_array->GetEncodedValues(), encoded_array->GetOffset()); + } +} + +void DexWriter::WriteAnnotations() { + uint8_t visibility[1]; + for (std::unique_ptr<dex_ir::AnnotationItem>& annotation : + header_.GetCollections().AnnotationItems()) { + visibility[0] = annotation->GetVisibility(); + size_t offset = annotation->GetOffset(); + offset += Write(visibility, sizeof(uint8_t), offset); + WriteEncodedAnnotation(annotation->GetAnnotation(), offset); + } +} + +void DexWriter::WriteAnnotationSets() { + uint32_t size[1]; + uint32_t annotation_off[1]; + for (std::unique_ptr<dex_ir::AnnotationSetItem>& annotation_set : + header_.GetCollections().AnnotationSetItems()) { + size[0] = annotation_set->GetItems()->size(); + size_t offset = annotation_set->GetOffset(); + offset += Write(size, sizeof(uint32_t), offset); + for (dex_ir::AnnotationItem* annotation : *annotation_set->GetItems()) { + annotation_off[0] = annotation->GetOffset(); + offset += Write(annotation_off, sizeof(uint32_t), offset); + } + } +} + +void DexWriter::WriteAnnotationSetRefs() { + uint32_t size[1]; + uint32_t annotations_off[1]; + for (std::unique_ptr<dex_ir::AnnotationSetRefList>& annotation_set_ref : + header_.GetCollections().AnnotationSetRefLists()) { + size[0] = annotation_set_ref->GetItems()->size(); + size_t offset = annotation_set_ref->GetOffset(); + offset += Write(size, sizeof(uint32_t), offset); + for (dex_ir::AnnotationSetItem* annotation_set : *annotation_set_ref->GetItems()) { + annotations_off[0] = annotation_set == nullptr ? 0 : annotation_set->GetOffset(); + offset += Write(annotations_off, sizeof(uint32_t), offset); + } + } +} + +void DexWriter::WriteAnnotationsDirectories() { + uint32_t directory_buffer[4]; + uint32_t annotation_buffer[2]; + for (std::unique_ptr<dex_ir::AnnotationsDirectoryItem>& annotations_directory : + header_.GetCollections().AnnotationsDirectoryItems()) { + directory_buffer[0] = annotations_directory->GetClassAnnotation() == nullptr ? 0 : + annotations_directory->GetClassAnnotation()->GetOffset(); + directory_buffer[1] = annotations_directory->GetFieldAnnotations() == nullptr ? 0 : + annotations_directory->GetFieldAnnotations()->size(); + directory_buffer[2] = annotations_directory->GetMethodAnnotations() == nullptr ? 0 : + annotations_directory->GetMethodAnnotations()->size(); + directory_buffer[3] = annotations_directory->GetParameterAnnotations() == nullptr ? 0 : + annotations_directory->GetParameterAnnotations()->size(); + uint32_t offset = annotations_directory->GetOffset(); + offset += Write(directory_buffer, 4 * sizeof(uint32_t), offset); + if (annotations_directory->GetFieldAnnotations() != nullptr) { + for (std::unique_ptr<dex_ir::FieldAnnotation>& field : + *annotations_directory->GetFieldAnnotations()) { + annotation_buffer[0] = field->GetFieldId()->GetIndex(); + annotation_buffer[1] = field->GetAnnotationSetItem()->GetOffset(); + offset += Write(annotation_buffer, 2 * sizeof(uint32_t), offset); + } + } + if (annotations_directory->GetMethodAnnotations() != nullptr) { + for (std::unique_ptr<dex_ir::MethodAnnotation>& method : + *annotations_directory->GetMethodAnnotations()) { + annotation_buffer[0] = method->GetMethodId()->GetIndex(); + annotation_buffer[1] = method->GetAnnotationSetItem()->GetOffset(); + offset += Write(annotation_buffer, 2 * sizeof(uint32_t), offset); + } + } + if (annotations_directory->GetParameterAnnotations() != nullptr) { + for (std::unique_ptr<dex_ir::ParameterAnnotation>& parameter : + *annotations_directory->GetParameterAnnotations()) { + annotation_buffer[0] = parameter->GetMethodId()->GetIndex(); + annotation_buffer[1] = parameter->GetAnnotations()->GetOffset(); + offset += Write(annotation_buffer, 2 * sizeof(uint32_t), offset); + } + } + } +} + +void DexWriter::WriteDebugInfoItems() { + for (std::unique_ptr<dex_ir::DebugInfoItem>& info : header_.GetCollections().DebugInfoItems()) { + Write(info->GetDebugInfo(), info->GetDebugInfoSize(), info->GetOffset()); + } +} + +void DexWriter::WriteCodeItems() { + uint16_t uint16_buffer[4]; + uint32_t uint32_buffer[2]; + for (std::unique_ptr<dex_ir::CodeItem>& code_item : header_.GetCollections().CodeItems()) { + uint16_buffer[0] = code_item->RegistersSize(); + uint16_buffer[1] = code_item->InsSize(); + uint16_buffer[2] = code_item->OutsSize(); + uint16_buffer[3] = code_item->TriesSize(); + uint32_buffer[0] = code_item->DebugInfo() == nullptr ? 0 : code_item->DebugInfo()->GetOffset(); + uint32_buffer[1] = code_item->InsnsSize(); + size_t offset = code_item->GetOffset(); + offset += Write(uint16_buffer, 4 * sizeof(uint16_t), offset); + offset += Write(uint32_buffer, 2 * sizeof(uint32_t), offset); + offset += Write(code_item->Insns(), code_item->InsnsSize() * sizeof(uint16_t), offset); + if (code_item->TriesSize() != 0) { + if (code_item->InsnsSize() % 2 != 0) { + uint16_t padding[1] = { 0 }; + offset += Write(padding, sizeof(uint16_t), offset); + } + uint32_t start_addr[1]; + uint16_t insn_count_and_handler_off[2]; + for (std::unique_ptr<const dex_ir::TryItem>& try_item : *code_item->Tries()) { + start_addr[0] = try_item->StartAddr(); + insn_count_and_handler_off[0] = try_item->InsnCount(); + insn_count_and_handler_off[1] = try_item->GetHandlers()->GetListOffset(); + offset += Write(start_addr, sizeof(uint32_t), offset); + offset += Write(insn_count_and_handler_off, 2 * sizeof(uint16_t), offset); + } + // Leave offset pointing to the end of the try items. + WriteUleb128(code_item->Handlers()->size(), offset); + for (std::unique_ptr<const dex_ir::CatchHandler>& handlers : *code_item->Handlers()) { + size_t list_offset = offset + handlers->GetListOffset(); + uint32_t size = handlers->HasCatchAll() ? (handlers->GetHandlers()->size() - 1) * -1 : + handlers->GetHandlers()->size(); + list_offset += WriteSleb128(size, list_offset); + for (std::unique_ptr<const dex_ir::TypeAddrPair>& handler : *handlers->GetHandlers()) { + if (handler->GetTypeId() != nullptr) { + list_offset += WriteUleb128(handler->GetTypeId()->GetIndex(), list_offset); + } + list_offset += WriteUleb128(handler->GetAddress(), list_offset); + } + } + } + } +} + +void DexWriter::WriteClasses() { + uint32_t class_def_buffer[8]; + for (std::unique_ptr<dex_ir::ClassDef>& class_def : header_.GetCollections().ClassDefs()) { + class_def_buffer[0] = class_def->ClassType()->GetIndex(); + class_def_buffer[1] = class_def->GetAccessFlags(); + class_def_buffer[2] = class_def->Superclass() == nullptr ? DexFile::kDexNoIndex : + class_def->Superclass()->GetIndex(); + class_def_buffer[3] = class_def->InterfacesOffset(); + class_def_buffer[4] = class_def->SourceFile() == nullptr ? DexFile::kDexNoIndex : + class_def->SourceFile()->GetIndex(); + class_def_buffer[5] = class_def->Annotations() == nullptr ? 0 : + class_def->Annotations()->GetOffset(); + class_def_buffer[6] = class_def->GetClassData() == nullptr ? 0 : + class_def->GetClassData()->GetOffset(); + class_def_buffer[7] = class_def->StaticValues() == nullptr ? 0 : + class_def->StaticValues()->GetOffset(); + size_t offset = class_def->GetOffset(); + Write(class_def_buffer, class_def->GetSize(), offset); + } + + for (std::unique_ptr<dex_ir::ClassData>& class_data : header_.GetCollections().ClassDatas()) { + size_t offset = class_data->GetOffset(); + offset += WriteUleb128(class_data->StaticFields()->size(), offset); + offset += WriteUleb128(class_data->InstanceFields()->size(), offset); + offset += WriteUleb128(class_data->DirectMethods()->size(), offset); + offset += WriteUleb128(class_data->VirtualMethods()->size(), offset); + offset += WriteEncodedFields(class_data->StaticFields(), offset); + offset += WriteEncodedFields(class_data->InstanceFields(), offset); + offset += WriteEncodedMethods(class_data->DirectMethods(), offset); + offset += WriteEncodedMethods(class_data->VirtualMethods(), offset); + } +} + +struct MapItemContainer { + MapItemContainer(uint32_t type, uint32_t size, uint32_t offset) + : type_(type), size_(size), offset_(offset) { } + + bool operator<(const MapItemContainer& other) const { + return offset_ > other.offset_; + } + + uint32_t type_; + uint32_t size_; + uint32_t offset_; +}; + +void DexWriter::WriteMapItem() { + dex_ir::Collections& collection = header_.GetCollections(); + std::priority_queue<MapItemContainer> queue; + + // Header and index section. + queue.push(MapItemContainer(DexFile::kDexTypeHeaderItem, 1, 0)); + if (collection.StringIdsSize() != 0) { + queue.push(MapItemContainer(DexFile::kDexTypeStringIdItem, collection.StringIdsSize(), + collection.StringIdsOffset())); + } + if (collection.TypeIdsSize() != 0) { + queue.push(MapItemContainer(DexFile::kDexTypeTypeIdItem, collection.TypeIdsSize(), + collection.TypeIdsOffset())); + } + if (collection.ProtoIdsSize() != 0) { + queue.push(MapItemContainer(DexFile::kDexTypeProtoIdItem, collection.ProtoIdsSize(), + collection.ProtoIdsOffset())); + } + if (collection.FieldIdsSize() != 0) { + queue.push(MapItemContainer(DexFile::kDexTypeFieldIdItem, collection.FieldIdsSize(), + collection.FieldIdsOffset())); + } + if (collection.MethodIdsSize() != 0) { + queue.push(MapItemContainer(DexFile::kDexTypeMethodIdItem, collection.MethodIdsSize(), + collection.MethodIdsOffset())); + } + if (collection.ClassDefsSize() != 0) { + queue.push(MapItemContainer(DexFile::kDexTypeClassDefItem, collection.ClassDefsSize(), + collection.ClassDefsOffset())); + } + + // Data section. + queue.push(MapItemContainer(DexFile::kDexTypeMapList, 1, collection.MapItemOffset())); + if (collection.TypeListsSize() != 0) { + queue.push(MapItemContainer(DexFile::kDexTypeTypeList, collection.TypeListsSize(), + collection.TypeListsOffset())); + } + if (collection.AnnotationSetRefListsSize() != 0) { + queue.push(MapItemContainer(DexFile::kDexTypeAnnotationSetRefList, + collection.AnnotationSetRefListsSize(), collection.AnnotationSetRefListsOffset())); + } + if (collection.AnnotationSetItemsSize() != 0) { + queue.push(MapItemContainer(DexFile::kDexTypeAnnotationSetItem, + collection.AnnotationSetItemsSize(), collection.AnnotationSetItemsOffset())); + } + if (collection.ClassDatasSize() != 0) { + queue.push(MapItemContainer(DexFile::kDexTypeClassDataItem, collection.ClassDatasSize(), + collection.ClassDatasOffset())); + } + if (collection.CodeItemsSize() != 0) { + queue.push(MapItemContainer(DexFile::kDexTypeCodeItem, collection.CodeItemsSize(), + collection.CodeItemsOffset())); + } + if (collection.StringDatasSize() != 0) { + queue.push(MapItemContainer(DexFile::kDexTypeStringDataItem, collection.StringDatasSize(), + collection.StringDatasOffset())); + } + if (collection.DebugInfoItemsSize() != 0) { + queue.push(MapItemContainer(DexFile::kDexTypeDebugInfoItem, collection.DebugInfoItemsSize(), + collection.DebugInfoItemsOffset())); + } + if (collection.AnnotationItemsSize() != 0) { + queue.push(MapItemContainer(DexFile::kDexTypeAnnotationItem, collection.AnnotationItemsSize(), + collection.AnnotationItemsOffset())); + } + if (collection.EncodedArrayItemsSize() != 0) { + queue.push(MapItemContainer(DexFile::kDexTypeEncodedArrayItem, + collection.EncodedArrayItemsSize(), collection.EncodedArrayItemsOffset())); + } + if (collection.AnnotationsDirectoryItemsSize() != 0) { + queue.push(MapItemContainer(DexFile::kDexTypeAnnotationsDirectoryItem, + collection.AnnotationsDirectoryItemsSize(), collection.AnnotationsDirectoryItemsOffset())); + } + + uint32_t offset = collection.MapItemOffset(); + uint16_t uint16_buffer[2]; + uint32_t uint32_buffer[2]; + uint16_buffer[1] = 0; + uint32_buffer[0] = queue.size(); + offset += Write(uint32_buffer, sizeof(uint32_t), offset); + while (!queue.empty()) { + const MapItemContainer& map_item = queue.top(); + uint16_buffer[0] = map_item.type_; + uint32_buffer[0] = map_item.size_; + uint32_buffer[1] = map_item.offset_; + offset += Write(uint16_buffer, 2 * sizeof(uint16_t), offset); + offset += Write(uint32_buffer, 2 * sizeof(uint32_t), offset); + queue.pop(); + } +} + +void DexWriter::WriteHeader() { + uint32_t buffer[20]; + dex_ir::Collections& collections = header_.GetCollections(); + size_t offset = 0; + offset += Write(header_.Magic(), 8 * sizeof(uint8_t), offset); + buffer[0] = header_.Checksum(); + offset += Write(buffer, sizeof(uint32_t), offset); + offset += Write(header_.Signature(), 20 * sizeof(uint8_t), offset); + uint32_t file_size = header_.FileSize(); + buffer[0] = file_size; + buffer[1] = header_.GetSize(); + buffer[2] = header_.EndianTag(); + buffer[3] = header_.LinkSize(); + buffer[4] = header_.LinkOffset(); + buffer[5] = collections.MapItemOffset(); + buffer[6] = collections.StringIdsSize(); + buffer[7] = collections.StringIdsOffset(); + buffer[8] = collections.TypeIdsSize(); + buffer[9] = collections.TypeIdsOffset(); + buffer[10] = collections.ProtoIdsSize(); + buffer[11] = collections.ProtoIdsOffset(); + buffer[12] = collections.FieldIdsSize(); + buffer[13] = collections.FieldIdsOffset(); + buffer[14] = collections.MethodIdsSize(); + buffer[15] = collections.MethodIdsOffset(); + uint32_t class_defs_size = collections.ClassDefsSize(); + uint32_t class_defs_off = collections.ClassDefsOffset(); + buffer[16] = class_defs_size; + buffer[17] = class_defs_off; + uint32_t data_off = class_defs_off + class_defs_size * dex_ir::ClassDef::ItemSize(); + uint32_t data_size = file_size - data_off; + buffer[18] = data_size; + buffer[19] = data_off; + Write(buffer, 20 * sizeof(uint32_t), offset); +} + +void DexWriter::WriteFile() { + if (dex_file_.get() == nullptr) { + fprintf(stderr, "Can't open output dex file\n"); + return; + } + + WriteStrings(); + WriteTypes(); + WriteTypeLists(); + WriteProtos(); + WriteFields(); + WriteMethods(); + WriteEncodedArrays(); + WriteAnnotations(); + WriteAnnotationSets(); + WriteAnnotationSetRefs(); + WriteAnnotationsDirectories(); + WriteDebugInfoItems(); + WriteCodeItems(); + WriteClasses(); + WriteMapItem(); + WriteHeader(); +} + +void DexWriter::OutputDexFile(dex_ir::Header& header, const char* file_name) { + (new DexWriter(header, file_name))->WriteFile(); +} + +} // namespace art diff --git a/dexlayout/dex_writer.h b/dexlayout/dex_writer.h new file mode 100644 index 0000000000..9104295472 --- /dev/null +++ b/dexlayout/dex_writer.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Header file of an in-memory representation of DEX files. + */ + +#ifndef ART_DEXLAYOUT_DEX_WRITER_H_ +#define ART_DEXLAYOUT_DEX_WRITER_H_ + +#include "base/unix_file/fd_file.h" +#include "dex_ir.h" +#include "os.h" + +namespace art { + +class DexWriter { + public: + DexWriter(dex_ir::Header& header, const char* file_name) : header_(header), + dex_file_(OS::CreateEmptyFileWriteOnly(file_name)) { } + + static void OutputDexFile(dex_ir::Header& header, const char* file_name); + + private: + void WriteFile(); + + size_t Write(const void* buffer, size_t length, size_t offset); + size_t WriteSleb128(uint32_t value, size_t offset); + size_t WriteUleb128(uint32_t value, size_t offset); + size_t WriteEncodedValue(dex_ir::EncodedValue* encoded_value, size_t offset); + size_t WriteEncodedValueHeader(int8_t value_type, size_t value_arg, size_t offset); + size_t WriteEncodedArray(dex_ir::EncodedValueVector* values, size_t offset); + size_t WriteEncodedAnnotation(dex_ir::EncodedAnnotation* annotation, size_t offset); + size_t WriteEncodedFields(dex_ir::FieldItemVector* fields, size_t offset); + size_t WriteEncodedMethods(dex_ir::MethodItemVector* methods, size_t offset); + + void WriteStrings(); + void WriteTypes(); + void WriteTypeLists(); + void WriteProtos(); + void WriteFields(); + void WriteMethods(); + void WriteEncodedArrays(); + void WriteAnnotations(); + void WriteAnnotationSets(); + void WriteAnnotationSetRefs(); + void WriteAnnotationsDirectories(); + void WriteDebugInfoItems(); + void WriteCodeItems(); + void WriteClasses(); + void WriteMapItem(); + void WriteHeader(); + + dex_ir::Header& header_; + std::unique_ptr<File> dex_file_; + + DISALLOW_COPY_AND_ASSIGN(DexWriter); +}; + + +} // namespace art + +#endif // ART_DEXLAYOUT_DEX_WRITER_H_ diff --git a/dexlayout/dexlayout.cc b/dexlayout/dexlayout.cc index e6141372a6..a9ae55fd8b 100644 --- a/dexlayout/dexlayout.cc +++ b/dexlayout/dexlayout.cc @@ -30,11 +30,11 @@ #include <sstream> #include <vector> -#include "base/unix_file/fd_file.h" #include "dex_ir_builder.h" #include "dex_file-inl.h" #include "dex_instruction-inl.h" #include "dex_visualize.h" +#include "dex_writer.h" #include "jit/offline_profiling_info.h" #include "os.h" #include "utils.h" @@ -251,10 +251,12 @@ static std::string GetSignatureForProtoId(const dex_ir::ProtoId* proto) { return "<no signature>"; } - const std::vector<const dex_ir::TypeId*>& params = proto->Parameters(); std::string result("("); - for (uint32_t i = 0; i < params.size(); ++i) { - result += params[i]->GetStringId()->Data(); + const dex_ir::TypeList* type_list = proto->Parameters(); + if (type_list != nullptr) { + for (const dex_ir::TypeId* type_id : *type_list->GetTypeList()) { + result += type_id->GetStringId()->Data(); + } } result += ")"; result += proto->ReturnType()->GetStringId()->Data(); @@ -673,7 +675,7 @@ static void DumpCatches(const dex_ir::CodeItem* code) { const uint32_t start = try_item->StartAddr(); const uint32_t end = start + try_item->InsnCount(); fprintf(out_file_, " 0x%04x - 0x%04x\n", start, end); - for (auto& handler : try_item->GetHandlers()) { + for (auto& handler : *try_item->GetHandlers()->GetHandlers()) { const dex_ir::TypeId* type_id = handler->GetTypeId(); const char* descriptor = (type_id == nullptr) ? "<any>" : type_id->GetStringId()->Data(); fprintf(out_file_, " %s -> 0x%04x\n", descriptor, handler->GetAddress()); @@ -1502,96 +1504,6 @@ static void DumpClass(const DexFile* dex_file, } /* -static uint32_t GetDataSectionOffset(dex_ir::Header& header) { - return dex_ir::Header::ItemSize() + - header.GetCollections().StringIdsSize() * dex_ir::StringId::ItemSize() + - header.GetCollections().TypeIdsSize() * dex_ir::TypeId::ItemSize() + - header.GetCollections().ProtoIdsSize() * dex_ir::ProtoId::ItemSize() + - header.GetCollections().FieldIdsSize() * dex_ir::FieldId::ItemSize() + - header.GetCollections().MethodIdsSize() * dex_ir::MethodId::ItemSize() + - header.GetCollections().ClassDefsSize() * dex_ir::ClassDef::ItemSize(); -} - -static bool Align(File* file, uint32_t& offset) { - uint8_t zero_buffer[] = { 0, 0, 0 }; - uint32_t zeroes = (-offset) & 3; - if (zeroes > 0) { - if (!file->PwriteFully(zero_buffer, zeroes, offset)) { - return false; - } - offset += zeroes; - } - return true; -} - -static bool WriteStrings(File* dex_file, dex_ir::Header& header, - uint32_t& index_offset, uint32_t& data_offset) { - uint32_t index = 0; - uint32_t index_buffer[1]; - uint32_t string_length; - uint32_t length_length; - uint8_t length_buffer[8]; - for (std::unique_ptr<dex_ir::StringId>& string_id : header.GetCollections().StringIds()) { - string_id->SetOffset(index); - index_buffer[0] = data_offset; - string_length = strlen(string_id->Data()); - length_length = UnsignedLeb128Size(string_length); - EncodeUnsignedLeb128(length_buffer, string_length); - - if (!dex_file->PwriteFully(index_buffer, 4, index_offset) || - !dex_file->PwriteFully(length_buffer, length_length, data_offset) || - !dex_file->PwriteFully(string_id->Data(), string_length, data_offset + length_length)) { - return false; - } - - index++; - index_offset += 4; - data_offset += string_length + length_length; - } - return true; -} - -static bool WriteTypes(File* dex_file, dex_ir::Header& header, uint32_t& index_offset) { - uint32_t index = 0; - uint32_t index_buffer[1]; - for (std::unique_ptr<dex_ir::TypeId>& type_id : header.GetCollections().TypeIds()) { - type_id->SetIndex(index); - index_buffer[0] = type_id->GetStringId()->GetOffset(); - - if (!dex_file->PwriteFully(index_buffer, 4, index_offset)) { - return false; - } - - index++; - index_offset += 4; - } - return true; -} - -static bool WriteTypeLists(File* dex_file, dex_ir::Header& header, uint32_t& data_offset) { - if (!Align(dex_file, data_offset)) { - return false; - } - - return true; -} - -static void OutputDexFile(dex_ir::Header& header, const char* file_name) { - LOG(INFO) << "FILE NAME: " << file_name; - std::unique_ptr<File> dex_file(OS::CreateEmptyFileWriteOnly(file_name)); - if (dex_file == nullptr) { - fprintf(stderr, "Can't open %s\n", file_name); - return; - } - - uint32_t index_offset = dex_ir::Header::ItemSize(); - uint32_t data_offset = GetDataSectionOffset(header); - WriteStrings(dex_file.get(), header, index_offset, data_offset); - WriteTypes(dex_file.get(), header, index_offset); -} -*/ - -/* * Dumps the requested sections of the file. */ static void ProcessDexFile(const char* file_name, const DexFile* dex_file, size_t dex_file_index) { @@ -1634,13 +1546,13 @@ static void ProcessDexFile(const char* file_name, const DexFile* dex_file, size_ fprintf(out_file_, "</api>\n"); } - /* // Output dex file. - if (options_.output_dex_files_) { - std::string output_dex_filename = dex_file->GetLocation() + ".out"; - OutputDexFile(*header, output_dex_filename.c_str()); + if (options_.output_dex_directory_ != nullptr) { + std::string output_location(options_.output_dex_directory_); + size_t last_slash = dex_file->GetLocation().rfind("/"); + output_location.append(dex_file->GetLocation().substr(last_slash)); + DexWriter::OutputDexFile(*header, output_location.c_str()); } - */ } /* diff --git a/dexlayout/dexlayout.h b/dexlayout/dexlayout.h index c4892d278b..c01eb79ecf 100644 --- a/dexlayout/dexlayout.h +++ b/dexlayout/dexlayout.h @@ -43,7 +43,6 @@ struct Options { bool disassemble_; bool exports_only_; bool ignore_bad_checksum_; - bool output_dex_files_; bool show_annotations_; bool show_cfg_; bool show_file_headers_; @@ -51,6 +50,7 @@ struct Options { bool verbose_; bool visualize_pattern_; OutputFormat output_format_; + const char* output_dex_directory_; const char* output_file_name_; const char* profile_file_name_; }; diff --git a/dexlayout/dexlayout_main.cc b/dexlayout/dexlayout_main.cc index f385b09119..728e389fcf 100644 --- a/dexlayout/dexlayout_main.cc +++ b/dexlayout/dexlayout_main.cc @@ -43,7 +43,7 @@ static const char* kProgramName = "dexlayout"; static void Usage(void) { fprintf(stderr, "Copyright (C) 2016 The Android Open Source Project\n\n"); fprintf(stderr, "%s: [-a] [-c] [-d] [-e] [-f] [-h] [-i] [-l layout] [-o outfile] [-p profile]" - " [-s] [-w] dexfile...\n\n", kProgramName); + " [-s] [-w directory] dexfile...\n\n", kProgramName); fprintf(stderr, " -a : display annotations\n"); fprintf(stderr, " -b : build dex_ir\n"); fprintf(stderr, " -c : verify checksum and exit\n"); @@ -57,7 +57,7 @@ static void Usage(void) { fprintf(stderr, " -o : output file name (defaults to stdout)\n"); fprintf(stderr, " -p : profile file name (defaults to no profile)\n"); fprintf(stderr, " -s : visualize reference pattern\n"); - fprintf(stderr, " -w : output dex files\n"); + fprintf(stderr, " -w : output dex directory \n"); } /* @@ -75,7 +75,7 @@ int DexlayoutDriver(int argc, char** argv) { // Parse all arguments. while (1) { - const int ic = getopt(argc, argv, "abcdefghil:o:p:sw"); + const int ic = getopt(argc, argv, "abcdefghil:o:p:sw:"); if (ic < 0) { break; // done } @@ -127,8 +127,8 @@ int DexlayoutDriver(int argc, char** argv) { options_.visualize_pattern_ = true; options_.verbose_ = false; break; - case 'w': // output dex files - options_.output_dex_files_ = true; + case 'w': // output dex files directory + options_.output_dex_directory_ = optarg; break; default: want_usage = true; diff --git a/dexlayout/dexlayout_test.cc b/dexlayout/dexlayout_test.cc index 42b64c3888..89544d7ef4 100644 --- a/dexlayout/dexlayout_test.cc +++ b/dexlayout/dexlayout_test.cc @@ -31,43 +31,83 @@ class DexLayoutTest : public CommonRuntimeTest { protected: virtual void SetUp() { CommonRuntimeTest::SetUp(); - // TODO: Test with other dex files for improved coverage. - // Dogfood our own lib core dex file. - dex_file_ = GetLibCoreDexFileNames()[0]; } - // Runs test with given arguments. - bool Exec(std::string* error_msg) { + // Runs FullPlainOutput test. + bool FullPlainOutputExec(std::string* error_msg) { // TODO: dexdump2 -> dexdump ? ScratchFile dexdump_output; std::string dexdump_filename = dexdump_output.GetFilename(); std::string dexdump = GetTestAndroidRoot() + "/bin/dexdump2"; EXPECT_TRUE(OS::FileExists(dexdump.c_str())) << dexdump << " should be a valid file path"; - std::vector<std::string> dexdump_exec_argv = - { dexdump, "-d", "-f", "-h", "-l", "plain", "-o", dexdump_filename, dex_file_ }; ScratchFile dexlayout_output; std::string dexlayout_filename = dexlayout_output.GetFilename(); std::string dexlayout = GetTestAndroidRoot() + "/bin/dexlayout"; EXPECT_TRUE(OS::FileExists(dexlayout.c_str())) << dexlayout << " should be a valid file path"; - std::vector<std::string> dexlayout_exec_argv = - { dexlayout, "-d", "-f", "-h", "-l", "plain", "-o", dexlayout_filename, dex_file_ }; - if (!::art::Exec(dexdump_exec_argv, error_msg)) { - return false; - } - if (!::art::Exec(dexlayout_exec_argv, error_msg)) { - return false; - } - std::vector<std::string> diff_exec_argv = - { "/usr/bin/diff", dexdump_filename, dexlayout_filename }; - if (!::art::Exec(diff_exec_argv, error_msg)) { - return false; + for (const std::string &dex_file : GetLibCoreDexFileNames()) { + std::vector<std::string> dexdump_exec_argv = + { dexdump, "-d", "-f", "-h", "-l", "plain", "-o", dexdump_filename, dex_file }; + std::vector<std::string> dexlayout_exec_argv = + { dexlayout, "-d", "-f", "-h", "-l", "plain", "-o", dexlayout_filename, dex_file }; + + if (!::art::Exec(dexdump_exec_argv, error_msg)) { + return false; + } + if (!::art::Exec(dexlayout_exec_argv, error_msg)) { + return false; + } + std::vector<std::string> diff_exec_argv = + { "/usr/bin/diff", dexdump_filename, dexlayout_filename }; + if (!::art::Exec(diff_exec_argv, error_msg)) { + return false; + } } return true; } - std::string dex_file_; + // Runs DexFileOutput test. + bool DexFileOutputExec(std::string* error_msg) { + ScratchFile tmp_file; + std::string tmp_name = tmp_file.GetFilename(); + size_t tmp_last_slash = tmp_name.rfind("/"); + std::string tmp_dir = tmp_name.substr(0, tmp_last_slash + 1); + std::string dexlayout = GetTestAndroidRoot() + "/bin/dexlayout"; + EXPECT_TRUE(OS::FileExists(dexlayout.c_str())) << dexlayout << " should be a valid file path"; + + for (const std::string &dex_file : GetLibCoreDexFileNames()) { + std::vector<std::string> dexlayout_exec_argv = + { dexlayout, "-d", "-f", "-h", "-l", "plain", "-w", tmp_dir, "-o", tmp_name, dex_file }; + + if (!::art::Exec(dexlayout_exec_argv, error_msg)) { + return false; + } + + size_t dex_file_last_slash = dex_file.rfind("/"); + std::string dex_file_name = dex_file.substr(dex_file_last_slash + 1); + std::vector<std::string> unzip_exec_argv = + { "/usr/bin/unzip", dex_file, "classes.dex", "-d", tmp_dir}; + if (!::art::Exec(unzip_exec_argv, error_msg)) { + return false; + } + std::vector<std::string> diff_exec_argv = + { "/usr/bin/diff", tmp_dir + "classes.dex" , tmp_dir + dex_file_name }; + if (!::art::Exec(diff_exec_argv, error_msg)) { + return false; + } + std::vector<std::string> rm_zip_exec_argv = { "/bin/rm", tmp_dir + "classes.dex" }; + if (!::art::Exec(rm_zip_exec_argv, error_msg)) { + return false; + } + std::vector<std::string> rm_out_exec_argv = { "/bin/rm", tmp_dir + dex_file_name }; + if (!::art::Exec(rm_out_exec_argv, error_msg)) { + return false; + } + } + + return true; + } }; @@ -75,7 +115,14 @@ TEST_F(DexLayoutTest, FullPlainOutput) { // Disable test on target. TEST_DISABLED_FOR_TARGET(); std::string error_msg; - ASSERT_TRUE(Exec(&error_msg)) << error_msg; + ASSERT_TRUE(FullPlainOutputExec(&error_msg)) << error_msg; +} + +TEST_F(DexLayoutTest, DexFileOutput) { + // Disable test on target. + TEST_DISABLED_FOR_TARGET(); + std::string error_msg; + ASSERT_TRUE(DexFileOutputExec(&error_msg)) << error_msg; } } // namespace art |