From ea7c62983beec6a5a2a6676cc910a436b20ae92c Mon Sep 17 00:00:00 2001 From: Jeff Hao Date: Mon, 14 Nov 2016 18:10:16 -0800 Subject: [PATCH] Dexlayout cleanup and refactoring. Created option to output to a mem map in preparation of hooking dexlayout into dex2oat. Test: mm test-art-host-gtest-dexlayout_test Bug: 29921113 Change-Id: Id42ef15cb8f83cc8d05b025b7647a4338e9b96b0 --- dexlayout/Android.bp | 32 ++- dexlayout/dex_ir.cc | 79 ++++--- dexlayout/dex_ir.h | 122 +++++----- dexlayout/dex_ir_builder.cc | 2 +- dexlayout/dex_visualize.cc | 21 +- dexlayout/dex_visualize.h | 6 +- dexlayout/dex_writer.cc | 92 ++++---- dexlayout/dex_writer.h | 13 +- dexlayout/dexlayout.cc | 538 +++++++++++++++++++++++--------------------- dexlayout/dexlayout.h | 104 +++++++-- dexlayout/dexlayout_main.cc | 72 +++--- 11 files changed, 622 insertions(+), 459 deletions(-) diff --git a/dexlayout/Android.bp b/dexlayout/Android.bp index b9266f75b..9ee9ebd3d 100644 --- a/dexlayout/Android.bp +++ b/dexlayout/Android.bp @@ -12,28 +12,46 @@ // See the License for the specific language governing permissions and // limitations under the License. -art_cc_binary { - name: "dexlayout", +art_cc_defaults { + name: "libart-dexlayout-defaults", host_supported: true, srcs: [ - "dexlayout_main.cc", "dexlayout.cc", "dex_ir.cc", "dex_ir_builder.cc", "dex_visualize.cc", "dex_writer.cc", ], + export_include_dirs: ["."], + shared_libs: ["libbase"], + static_libs: ["libz"], +} + +art_cc_library { + name: "libart-dexlayout", + defaults: ["libart-dexlayout-defaults"], + shared_libs: ["libart"], +} + +art_cc_library { + name: "libartd-dexlayout", + defaults: ["libart-dexlayout-defaults"], + shared_libs: ["libartd"], +} + +art_cc_binary { + name: "dexlayout", + host_supported: true, + srcs: ["dexlayout_main.cc"], cflags: ["-Wall"], shared_libs: [ "libart", - "libbase", + "libart-dexlayout", ], } art_cc_test { name: "art_dexlayout_tests", - defaults: [ - "art_gtest_defaults", - ], + defaults: ["art_gtest_defaults"], srcs: ["dexlayout_test.cc"], } diff --git a/dexlayout/dex_ir.cc b/dexlayout/dex_ir.cc index 67f3e0956..fe2bcce84 100644 --- a/dexlayout/dex_ir.cc +++ b/dexlayout/dex_ir.cc @@ -56,6 +56,36 @@ static void GetLocalsCb(void* context, const DexFile::LocalInfo& entry) { entry.end_address_, entry.reg_))); } +static uint32_t GetCodeItemSize(const DexFile& dex_file, const DexFile::CodeItem& disk_code_item) { + uintptr_t code_item_start = reinterpret_cast(&disk_code_item); + uint32_t insns_size = disk_code_item.insns_size_in_code_units_; + uint32_t tries_size = disk_code_item.tries_size_; + if (tries_size == 0) { + uintptr_t insns_end = reinterpret_cast(&disk_code_item.insns_[insns_size]); + return insns_end - code_item_start; + } else { + uint32_t last_handler_off = 0; + for (uint32_t i = 0; i < tries_size; ++i) { + // Iterate over the try items to find the last catch handler. + const DexFile::TryItem* disk_try_item = dex_file.GetTryItems(disk_code_item, i); + uint16_t handler_off = disk_try_item->handler_off_; + if (handler_off > last_handler_off) { + last_handler_off = handler_off; + } + } + // Decode the final handler to see where it ends. + const uint8_t* handler_data = DexFile::GetCatchHandlerData(disk_code_item, last_handler_off); + int32_t uleb128_count = DecodeSignedLeb128(&handler_data) * 2; + if (uleb128_count <= 0) { + uleb128_count = -uleb128_count + 1; + } + for (int32_t i = 0; i < uleb128_count; ++i) { + DecodeUnsignedLeb128(&handler_data); + } + return reinterpret_cast(handler_data) - code_item_start; + } +} + static uint32_t GetDebugInfoStreamSize(const uint8_t* debug_info_stream) { const uint8_t* stream = debug_info_stream; DecodeUnsignedLeb128(&stream); // line_start @@ -384,11 +414,9 @@ TypeList* Collections::CreateTypeList(const DexFile::TypeList* dex_type_list, ui if (dex_type_list == nullptr) { return nullptr; } - // TODO: Create more efficient lookup for existing type lists. - for (std::unique_ptr& type_list : TypeLists()) { - if (type_list->GetOffset() == offset) { - return type_list.get(); - } + auto found_type_list = TypeLists().find(offset); + if (found_type_list != TypeLists().end()) { + return found_type_list->second.get(); } TypeIdVector* type_vector = new TypeIdVector(); uint32_t size = dex_type_list->Size(); @@ -404,10 +432,9 @@ EncodedArrayItem* Collections::CreateEncodedArrayItem(const uint8_t* static_data if (static_data == nullptr) { return nullptr; } - for (std::unique_ptr& existing_array_item : EncodedArrayItems()) { - if (existing_array_item->GetOffset() == offset) { - return existing_array_item.get(); - } + auto found_encoded_array_item = EncodedArrayItems().find(offset); + if (found_encoded_array_item != EncodedArrayItems().end()) { + return found_encoded_array_item->second.get(); } uint32_t size = DecodeUnsignedLeb128(&static_data); EncodedValueVector* values = new EncodedValueVector(); @@ -422,10 +449,9 @@ EncodedArrayItem* Collections::CreateEncodedArrayItem(const uint8_t* static_data AnnotationItem* Collections::CreateAnnotationItem(const DexFile::AnnotationItem* annotation, uint32_t offset) { - for (std::unique_ptr& existing_annotation_item : AnnotationItems()) { - if (existing_annotation_item->GetOffset() == offset) { - return existing_annotation_item.get(); - } + auto found_annotation_item = AnnotationItems().find(offset); + if (found_annotation_item != AnnotationItems().end()) { + return found_annotation_item->second.get(); } uint8_t visibility = annotation->visibility_; const uint8_t* annotation_data = annotation->annotation_; @@ -444,10 +470,9 @@ AnnotationSetItem* Collections::CreateAnnotationSetItem(const DexFile& dex_file, if (disk_annotations_item.size_ == 0 && offset == 0) { return nullptr; } - for (std::unique_ptr& existing_anno_set_item : AnnotationSetItems()) { - if (existing_anno_set_item->GetOffset() == offset) { - return existing_anno_set_item.get(); - } + auto found_anno_set_item = AnnotationSetItems().find(offset); + if (found_anno_set_item != AnnotationSetItems().end()) { + return found_anno_set_item->second.get(); } std::vector* items = new std::vector(); for (uint32_t i = 0; i < disk_annotations_item.size_; ++i) { @@ -467,10 +492,9 @@ 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& anno_dir_item : AnnotationsDirectoryItems()) { - if (anno_dir_item->GetOffset() == offset) { - return anno_dir_item.get(); - } + auto found_anno_dir_item = AnnotationsDirectoryItems().find(offset); + if (found_anno_dir_item != AnnotationsDirectoryItems().end()) { + return found_anno_dir_item->second.get(); } const DexFile::AnnotationSetItem* class_set_item = dex_file.GetClassAnnotationSet(disk_annotations_item); @@ -535,11 +559,9 @@ ParameterAnnotation* Collections::GenerateParameterAnnotation( const DexFile& dex_file, MethodId* method_id, const DexFile::AnnotationSetRefList* annotation_set_ref_list, uint32_t offset) { AnnotationSetRefList* set_ref_list = nullptr; - for (std::unique_ptr& existing_set_ref_list : AnnotationSetRefLists()) { - if (existing_set_ref_list->GetOffset() == offset) { - set_ref_list = existing_set_ref_list.get(); - break; - } + auto found_set_ref_list = AnnotationSetRefLists().find(offset); + if (found_set_ref_list != AnnotationSetRefLists().end()) { + set_ref_list = found_set_ref_list->second.get(); } if (set_ref_list == nullptr) { std::vector* annotations = new std::vector(); @@ -610,9 +632,10 @@ CodeItem* Collections::CreateCodeItem(const DexFile& dex_file, tries->push_back(std::unique_ptr(try_item)); } } - // TODO: Calculate the size of the code item. + uint32_t size = GetCodeItemSize(dex_file, disk_code_item); CodeItem* code_item = new CodeItem( registers_size, ins_size, outs_size, debug_info, insns_size, insns, tries, handler_list); + code_item->SetSize(size); code_items_.AddItem(code_item, offset); // Add "fixup" references to types, strings, methods, and fields. // This is temporary, as we will probably want more detailed parsing of the @@ -690,8 +713,8 @@ ClassData* Collections::CreateClassData( virtual_methods->push_back( std::unique_ptr(GenerateMethodItem(dex_file, cdii))); } - // TODO: Calculate the size of the class data. class_data = new ClassData(static_fields, instance_fields, direct_methods, virtual_methods); + class_data->SetSize(cdii.EndDataPointer() - encoded_data); class_datas_.AddItem(class_data, offset); } return class_data; diff --git a/dexlayout/dex_ir.h b/dexlayout/dex_ir.h index 38eb0b1b4..a2d1190d0 100644 --- a/dexlayout/dex_ir.h +++ b/dexlayout/dex_ir.h @@ -19,6 +19,7 @@ #ifndef ART_DEXLAYOUT_DEX_IR_H_ #define ART_DEXLAYOUT_DEX_IR_H_ +#include #include #include @@ -98,34 +99,52 @@ class AbstractDispatcher { }; // Collections become owners of the objects added by moving them into unique pointers. -template class CollectionWithOffset { +template class CollectionBase { public: - CollectionWithOffset() = default; - std::vector>& Collection() { return collection_; } - // Read-time support methods - void AddItem(T* object, uint32_t offset) { - object->SetOffset(offset); - collection_.push_back(std::unique_ptr(object)); - } + CollectionBase() = default; + + uint32_t GetOffset() const { return offset_; } + void SetOffset(uint32_t new_offset) { offset_ = new_offset; } + + private: + uint32_t offset_ = 0; + + DISALLOW_COPY_AND_ASSIGN(CollectionBase); +}; + +template class CollectionVector : public CollectionBase { + public: + CollectionVector() = default; + void AddIndexedItem(T* object, uint32_t offset, uint32_t index) { object->SetOffset(offset); object->SetIndex(index); collection_.push_back(std::unique_ptr(object)); } - // Ordinary object insertion into collection. - void Insert(T object ATTRIBUTE_UNUSED) { - // TODO(sehr): add ordered insertion support. - UNIMPLEMENTED(FATAL) << "Insertion not ready"; - } - uint32_t GetOffset() const { return offset_; } - void SetOffset(uint32_t new_offset) { offset_ = new_offset; } uint32_t Size() const { return collection_.size(); } + std::vector>& Collection() { return collection_; } private: std::vector> collection_; - uint32_t offset_ = 0; - DISALLOW_COPY_AND_ASSIGN(CollectionWithOffset); + DISALLOW_COPY_AND_ASSIGN(CollectionVector); +}; + +template class CollectionMap : public CollectionBase { + public: + CollectionMap() = default; + + void AddItem(T* object, uint32_t offset) { + object->SetOffset(offset); + collection_.emplace(offset, std::unique_ptr(object)); + } + uint32_t Size() const { return collection_.size(); } + std::map>& Collection() { return collection_; } + + private: + std::map> collection_; + + DISALLOW_COPY_AND_ASSIGN(CollectionMap); }; class Collections { @@ -138,22 +157,23 @@ class Collections { std::vector>& FieldIds() { return field_ids_.Collection(); } std::vector>& MethodIds() { return method_ids_.Collection(); } std::vector>& ClassDefs() { return class_defs_.Collection(); } - std::vector>& StringDatas() { return string_datas_.Collection(); } - std::vector>& TypeLists() { return type_lists_.Collection(); } - std::vector>& EncodedArrayItems() + std::map>& StringDatas() + { return string_datas_.Collection(); } + std::map>& TypeLists() { return type_lists_.Collection(); } + std::map>& EncodedArrayItems() { return encoded_array_items_.Collection(); } - std::vector>& AnnotationItems() + std::map>& AnnotationItems() { return annotation_items_.Collection(); } - std::vector>& AnnotationSetItems() + std::map>& AnnotationSetItems() { return annotation_set_items_.Collection(); } - std::vector>& AnnotationSetRefLists() + std::map>& AnnotationSetRefLists() { return annotation_set_ref_lists_.Collection(); } - std::vector>& AnnotationsDirectoryItems() + std::map>& AnnotationsDirectoryItems() { return annotations_directory_items_.Collection(); } - std::vector>& DebugInfoItems() + std::map>& DebugInfoItems() { return debug_info_items_.Collection(); } - std::vector>& CodeItems() { return code_items_.Collection(); } - std::vector>& ClassDatas() { return class_datas_.Collection(); } + std::map>& CodeItems() { return code_items_.Collection(); } + std::map>& ClassDatas() { return class_datas_.Collection(); } void CreateStringId(const DexFile& dex_file, uint32_t i); void CreateTypeId(const DexFile& dex_file, uint32_t i); @@ -204,7 +224,7 @@ class Collections { 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_; } + uint32_t MapListOffset() const { return map_list_offset_; } void SetStringIdsOffset(uint32_t new_offset) { string_ids_.SetOffset(new_offset); } void SetTypeIdsOffset(uint32_t new_offset) { type_ids_.SetOffset(new_offset); } @@ -226,7 +246,7 @@ class Collections { 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; } + void SetMapListOffset(uint32_t new_offset) { map_list_offset_ = new_offset; } uint32_t StringIdsSize() const { return string_ids_.Size(); } uint32_t TypeIdsSize() const { return type_ids_.Size(); } @@ -254,25 +274,25 @@ class Collections { const DexFile::AnnotationSetRefList* annotation_set_ref_list, uint32_t offset); MethodItem* GenerateMethodItem(const DexFile& dex_file, ClassDataItemIterator& cdii); - CollectionWithOffset string_ids_; - CollectionWithOffset type_ids_; - CollectionWithOffset proto_ids_; - CollectionWithOffset field_ids_; - CollectionWithOffset method_ids_; - CollectionWithOffset class_defs_; - - CollectionWithOffset string_datas_; - CollectionWithOffset type_lists_; - CollectionWithOffset encoded_array_items_; - CollectionWithOffset annotation_items_; - CollectionWithOffset annotation_set_items_; - CollectionWithOffset annotation_set_ref_lists_; - CollectionWithOffset annotations_directory_items_; - CollectionWithOffset debug_info_items_; - CollectionWithOffset code_items_; - CollectionWithOffset class_datas_; - - uint32_t map_item_offset_ = 0; + CollectionVector string_ids_; + CollectionVector type_ids_; + CollectionVector proto_ids_; + CollectionVector field_ids_; + CollectionVector method_ids_; + CollectionVector class_defs_; + + CollectionMap string_datas_; + CollectionMap type_lists_; + CollectionMap encoded_array_items_; + CollectionMap annotation_items_; + CollectionMap annotation_set_items_; + CollectionMap annotation_set_ref_lists_; + CollectionMap annotations_directory_items_; + CollectionMap debug_info_items_; + CollectionMap code_items_; + CollectionMap class_datas_; + + uint32_t map_list_offset_ = 0; DISALLOW_COPY_AND_ASSIGN(Collections); }; @@ -539,20 +559,20 @@ using FieldItemVector = std::vector>; class MethodItem : public Item { public: - MethodItem(uint32_t access_flags, const MethodId* method_id, const CodeItem* code) + MethodItem(uint32_t access_flags, const MethodId* method_id, CodeItem* code) : access_flags_(access_flags), method_id_(method_id), code_(code) { } ~MethodItem() OVERRIDE { } uint32_t GetAccessFlags() const { return access_flags_; } const MethodId* GetMethodId() const { return method_id_; } - const CodeItem* GetCodeItem() const { return code_; } + CodeItem* GetCodeItem() { return code_; } void Accept(AbstractDispatcher* dispatch) { dispatch->Dispatch(this); } private: uint32_t access_flags_; const MethodId* method_id_; - const CodeItem* code_; // This can be nullptr. + CodeItem* code_; // This can be nullptr. DISALLOW_COPY_AND_ASSIGN(MethodItem); }; diff --git a/dexlayout/dex_ir_builder.cc b/dexlayout/dex_ir_builder.cc index 68ff2a253..d0c5bf964 100644 --- a/dexlayout/dex_ir_builder.cc +++ b/dexlayout/dex_ir_builder.cc @@ -71,7 +71,7 @@ Header* DexIrBuilder(const DexFile& dex_file) { collections.CreateClassDef(dex_file, i); } // MapItem. - collections.SetMapItemOffset(disk_header.map_off_); + collections.SetMapListOffset(disk_header.map_off_); CheckAndSetRemainingOffsets(dex_file, &collections); diff --git a/dexlayout/dex_visualize.cc b/dexlayout/dex_visualize.cc index 05ad98fe0..02274b25a 100644 --- a/dexlayout/dex_visualize.cc +++ b/dexlayout/dex_visualize.cc @@ -263,11 +263,13 @@ class Dumper { DumpStringId(method_id->Name(), class_index); } - void DumpMethodItem(const dex_ir::MethodItem* method, const DexFile* dex_file, int class_index) { - if (profile_info_ != nullptr) { + void DumpMethodItem(dex_ir::MethodItem* method, + const DexFile* dex_file, + int class_index, + ProfileCompilationInfo* profile_info) { + if (profile_info != nullptr) { uint32_t method_idx = method->GetMethodId()->GetIndex(); - MethodReference mr(dex_file, method_idx); - if (!profile_info_->ContainsMethod(mr)) { + if (!profile_info->ContainsMethod(MethodReference(dex_file, method_idx))) { return; } } @@ -344,14 +346,17 @@ class Dumper { * Dumps a gnuplot data file showing the parts of the dex_file that belong to each class. * If profiling information is present, it dumps only those classes that are marked as hot. */ -void VisualizeDexLayout(dex_ir::Header* header, const DexFile* dex_file, size_t dex_file_index) { +void VisualizeDexLayout(dex_ir::Header* header, + const DexFile* dex_file, + size_t dex_file_index, + ProfileCompilationInfo* profile_info) { std::unique_ptr dumper(new Dumper(header->GetCollections(), dex_file_index)); const uint32_t class_defs_size = header->GetCollections().ClassDefsSize(); for (uint32_t class_index = 0; class_index < class_defs_size; class_index++) { dex_ir::ClassDef* class_def = header->GetCollections().GetClassDef(class_index); dex::TypeIndex type_idx(class_def->ClassType()->GetIndex()); - if (profile_info_ != nullptr && !profile_info_->ContainsClass(*dex_file, type_idx)) { + if (profile_info != nullptr && !profile_info->ContainsClass(*dex_file, type_idx)) { continue; } dumper->DumpAddressRange(class_def, class_index); @@ -384,12 +389,12 @@ void VisualizeDexLayout(dex_ir::Header* header, const DexFile* dex_file, size_t } if (class_data->DirectMethods()) { for (auto& method_item : *class_data->DirectMethods()) { - dumper->DumpMethodItem(method_item.get(), dex_file, class_index); + dumper->DumpMethodItem(method_item.get(), dex_file, class_index, profile_info); } } if (class_data->VirtualMethods()) { for (auto& method_item : *class_data->VirtualMethods()) { - dumper->DumpMethodItem(method_item.get(), dex_file, class_index); + dumper->DumpMethodItem(method_item.get(), dex_file, class_index, profile_info); } } } diff --git a/dexlayout/dex_visualize.h b/dexlayout/dex_visualize.h index b1d2ed79a..09f830681 100644 --- a/dexlayout/dex_visualize.h +++ b/dexlayout/dex_visualize.h @@ -28,11 +28,15 @@ namespace art { class DexFile; +class ProfileCompilationInfo; namespace dex_ir { class Header; } // namespace dex_ir -void VisualizeDexLayout(dex_ir::Header* header, const DexFile* dex_file, size_t dex_file_index); +void VisualizeDexLayout(dex_ir::Header* header, + const DexFile* dex_file, + size_t dex_file_index, + ProfileCompilationInfo* profile_info); } // namespace art diff --git a/dexlayout/dex_writer.cc b/dexlayout/dex_writer.cc index dba5da0fb..7ffa38bfd 100644 --- a/dexlayout/dex_writer.cc +++ b/dexlayout/dex_writer.cc @@ -104,7 +104,9 @@ size_t EncodeDoubleValue(double value, uint8_t* buffer) { } size_t DexWriter::Write(const void* buffer, size_t length, size_t offset) { - return dex_file_->PwriteFully(buffer, length, offset) ? length : 0; + DCHECK_LE(offset + length, mem_map_->Size()); + memcpy(mem_map_->Begin() + offset, buffer, length); + return length; } size_t DexWriter::WriteSleb128(uint32_t value, size_t offset) { @@ -236,12 +238,13 @@ size_t DexWriter::WriteEncodedMethods(dex_ir::MethodItemVector* methods, size_t void DexWriter::WriteStrings() { uint32_t string_data_off[1]; - for (std::unique_ptr& string_id : header_.GetCollections().StringIds()) { + for (std::unique_ptr& 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& string_data : header_.GetCollections().StringDatas()) { + for (auto& string_data_pair : header_->GetCollections().StringDatas()) { + std::unique_ptr& string_data = string_data_pair.second; uint32_t offset = string_data->GetOffset(); offset += WriteUleb128(CountModifiedUtf8Chars(string_data->Data()), offset); Write(string_data->Data(), strlen(string_data->Data()), offset); @@ -250,7 +253,7 @@ void DexWriter::WriteStrings() { void DexWriter::WriteTypes() { uint32_t descriptor_idx[1]; - for (std::unique_ptr& type_id : header_.GetCollections().TypeIds()) { + for (std::unique_ptr& type_id : header_->GetCollections().TypeIds()) { descriptor_idx[0] = type_id->GetStringId()->GetIndex(); Write(descriptor_idx, type_id->GetSize(), type_id->GetOffset()); } @@ -259,7 +262,8 @@ void DexWriter::WriteTypes() { void DexWriter::WriteTypeLists() { uint32_t size[1]; uint16_t list[1]; - for (std::unique_ptr& type_list : header_.GetCollections().TypeLists()) { + for (auto& type_list_pair : header_->GetCollections().TypeLists()) { + std::unique_ptr& type_list = type_list_pair.second; size[0] = type_list->GetTypeList()->size(); uint32_t offset = type_list->GetOffset(); offset += Write(size, sizeof(uint32_t), offset); @@ -272,7 +276,7 @@ void DexWriter::WriteTypeLists() { void DexWriter::WriteProtos() { uint32_t buffer[3]; - for (std::unique_ptr& proto_id : header_.GetCollections().ProtoIds()) { + for (std::unique_ptr& 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(); @@ -282,7 +286,7 @@ void DexWriter::WriteProtos() { void DexWriter::WriteFields() { uint16_t buffer[4]; - for (std::unique_ptr& field_id : header_.GetCollections().FieldIds()) { + for (std::unique_ptr& field_id : header_->GetCollections().FieldIds()) { buffer[0] = field_id->Class()->GetIndex(); buffer[1] = field_id->Type()->GetIndex(); buffer[2] = field_id->Name()->GetIndex(); @@ -293,7 +297,7 @@ void DexWriter::WriteFields() { void DexWriter::WriteMethods() { uint16_t buffer[4]; - for (std::unique_ptr& method_id : header_.GetCollections().MethodIds()) { + for (std::unique_ptr& method_id : header_->GetCollections().MethodIds()) { buffer[0] = method_id->Class()->GetIndex(); buffer[1] = method_id->Proto()->GetIndex(); buffer[2] = method_id->Name()->GetIndex(); @@ -303,16 +307,16 @@ void DexWriter::WriteMethods() { } void DexWriter::WriteEncodedArrays() { - for (std::unique_ptr& encoded_array : - header_.GetCollections().EncodedArrayItems()) { + for (auto& encoded_array_pair : header_->GetCollections().EncodedArrayItems()) { + std::unique_ptr& encoded_array = encoded_array_pair.second; WriteEncodedArray(encoded_array->GetEncodedValues(), encoded_array->GetOffset()); } } void DexWriter::WriteAnnotations() { uint8_t visibility[1]; - for (std::unique_ptr& annotation : - header_.GetCollections().AnnotationItems()) { + for (auto& annotation_pair : header_->GetCollections().AnnotationItems()) { + std::unique_ptr& annotation = annotation_pair.second; visibility[0] = annotation->GetVisibility(); size_t offset = annotation->GetOffset(); offset += Write(visibility, sizeof(uint8_t), offset); @@ -323,8 +327,8 @@ void DexWriter::WriteAnnotations() { void DexWriter::WriteAnnotationSets() { uint32_t size[1]; uint32_t annotation_off[1]; - for (std::unique_ptr& annotation_set : - header_.GetCollections().AnnotationSetItems()) { + for (auto& annotation_set_pair : header_->GetCollections().AnnotationSetItems()) { + std::unique_ptr& annotation_set = annotation_set_pair.second; size[0] = annotation_set->GetItems()->size(); size_t offset = annotation_set->GetOffset(); offset += Write(size, sizeof(uint32_t), offset); @@ -338,8 +342,8 @@ void DexWriter::WriteAnnotationSets() { void DexWriter::WriteAnnotationSetRefs() { uint32_t size[1]; uint32_t annotations_off[1]; - for (std::unique_ptr& annotation_set_ref : - header_.GetCollections().AnnotationSetRefLists()) { + for (auto& anno_set_ref_pair : header_->GetCollections().AnnotationSetRefLists()) { + std::unique_ptr& annotation_set_ref = anno_set_ref_pair.second; size[0] = annotation_set_ref->GetItems()->size(); size_t offset = annotation_set_ref->GetOffset(); offset += Write(size, sizeof(uint32_t), offset); @@ -353,8 +357,9 @@ void DexWriter::WriteAnnotationSetRefs() { void DexWriter::WriteAnnotationsDirectories() { uint32_t directory_buffer[4]; uint32_t annotation_buffer[2]; - for (std::unique_ptr& annotations_directory : - header_.GetCollections().AnnotationsDirectoryItems()) { + for (auto& annotations_directory_pair : header_->GetCollections().AnnotationsDirectoryItems()) { + std::unique_ptr& annotations_directory = + annotations_directory_pair.second; directory_buffer[0] = annotations_directory->GetClassAnnotation() == nullptr ? 0 : annotations_directory->GetClassAnnotation()->GetOffset(); directory_buffer[1] = annotations_directory->GetFieldAnnotations() == nullptr ? 0 : @@ -393,15 +398,17 @@ void DexWriter::WriteAnnotationsDirectories() { } void DexWriter::WriteDebugInfoItems() { - for (std::unique_ptr& info : header_.GetCollections().DebugInfoItems()) { - Write(info->GetDebugInfo(), info->GetDebugInfoSize(), info->GetOffset()); + for (auto& debug_info_pair : header_->GetCollections().DebugInfoItems()) { + std::unique_ptr& debug_info = debug_info_pair.second; + Write(debug_info->GetDebugInfo(), debug_info->GetDebugInfoSize(), debug_info->GetOffset()); } } void DexWriter::WriteCodeItems() { uint16_t uint16_buffer[4]; uint32_t uint32_buffer[2]; - for (std::unique_ptr& code_item : header_.GetCollections().CodeItems()) { + for (auto& code_item_pair : header_->GetCollections().CodeItems()) { + std::unique_ptr& code_item = code_item_pair.second; uint16_buffer[0] = code_item->RegistersSize(); uint16_buffer[1] = code_item->InsSize(); uint16_buffer[2] = code_item->OutsSize(); @@ -446,7 +453,7 @@ void DexWriter::WriteCodeItems() { void DexWriter::WriteClasses() { uint32_t class_def_buffer[8]; - for (std::unique_ptr& class_def : header_.GetCollections().ClassDefs()) { + for (std::unique_ptr& 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 : @@ -464,7 +471,8 @@ void DexWriter::WriteClasses() { Write(class_def_buffer, class_def->GetSize(), offset); } - for (std::unique_ptr& class_data : header_.GetCollections().ClassDatas()) { + for (auto& class_data_pair : header_->GetCollections().ClassDatas()) { + std::unique_ptr& class_data = class_data_pair.second; size_t offset = class_data->GetOffset(); offset += WriteUleb128(class_data->StaticFields()->size(), offset); offset += WriteUleb128(class_data->InstanceFields()->size(), offset); @@ -491,7 +499,7 @@ struct MapItemContainer { }; void DexWriter::WriteMapItem() { - dex_ir::Collections& collection = header_.GetCollections(); + dex_ir::Collections& collection = header_->GetCollections(); std::priority_queue queue; // Header and index section. @@ -522,7 +530,7 @@ void DexWriter::WriteMapItem() { } // Data section. - queue.push(MapItemContainer(DexFile::kDexTypeMapList, 1, collection.MapItemOffset())); + queue.push(MapItemContainer(DexFile::kDexTypeMapList, 1, collection.MapListOffset())); if (collection.TypeListsSize() != 0) { queue.push(MapItemContainer(DexFile::kDexTypeTypeList, collection.TypeListsSize(), collection.TypeListsOffset())); @@ -564,7 +572,7 @@ void DexWriter::WriteMapItem() { collection.AnnotationsDirectoryItemsSize(), collection.AnnotationsDirectoryItemsOffset())); } - uint32_t offset = collection.MapItemOffset(); + uint32_t offset = collection.MapListOffset(); uint16_t uint16_buffer[2]; uint32_t uint32_buffer[2]; uint16_buffer[1] = 0; @@ -583,19 +591,19 @@ void DexWriter::WriteMapItem() { void DexWriter::WriteHeader() { uint32_t buffer[20]; - dex_ir::Collections& collections = header_.GetCollections(); + 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(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(); + 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[1] = header_->GetSize(); + buffer[2] = header_->EndianTag(); + buffer[3] = header_->LinkSize(); + buffer[4] = header_->LinkOffset(); + buffer[5] = collections.MapListOffset(); buffer[6] = collections.StringIdsSize(); buffer[7] = collections.StringIdsOffset(); buffer[8] = collections.TypeIdsSize(); @@ -617,12 +625,7 @@ void DexWriter::WriteHeader() { 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; - } - +void DexWriter::WriteMemMap() { WriteStrings(); WriteTypes(); WriteTypeLists(); @@ -641,8 +644,9 @@ void DexWriter::WriteFile() { WriteHeader(); } -void DexWriter::OutputDexFile(dex_ir::Header& header, const char* file_name) { - (new DexWriter(header, file_name))->WriteFile(); +void DexWriter::Output(dex_ir::Header* header, MemMap* mem_map) { + DexWriter dex_writer(header, mem_map); + dex_writer.WriteMemMap(); } } // namespace art diff --git a/dexlayout/dex_writer.h b/dexlayout/dex_writer.h index 910429547..fb76e5ccf 100644 --- a/dexlayout/dex_writer.h +++ b/dexlayout/dex_writer.h @@ -21,19 +21,19 @@ #include "base/unix_file/fd_file.h" #include "dex_ir.h" +#include "mem_map.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)) { } + DexWriter(dex_ir::Header* header, MemMap* mem_map) : header_(header), mem_map_(mem_map) { } - static void OutputDexFile(dex_ir::Header& header, const char* file_name); + static void Output(dex_ir::Header* header, MemMap* mem_map); private: - void WriteFile(); + void WriteMemMap(); size_t Write(const void* buffer, size_t length, size_t offset); size_t WriteSleb128(uint32_t value, size_t offset); @@ -62,13 +62,12 @@ class DexWriter { void WriteMapItem(); void WriteHeader(); - dex_ir::Header& header_; - std::unique_ptr dex_file_; + dex_ir::Header* const header_; + MemMap* const mem_map_; DISALLOW_COPY_AND_ASSIGN(DexWriter); }; - } // namespace art #endif // ART_DEXLAYOUT_DEX_WRITER_H_ diff --git a/dexlayout/dexlayout.cc b/dexlayout/dexlayout.cc index aa806557c..634bb633c 100644 --- a/dexlayout/dexlayout.cc +++ b/dexlayout/dexlayout.cc @@ -37,27 +37,13 @@ #include "dex_visualize.h" #include "dex_writer.h" #include "jit/offline_profiling_info.h" +#include "mem_map.h" #include "os.h" #include "utils.h" namespace art { /* - * Options parsed in main driver. - */ -struct Options options_; - -/* - * Output file. Defaults to stdout. - */ -FILE* out_file_ = stdout; - -/* - * Profile information file. - */ -ProfileCompilationInfo* profile_info_ = nullptr; - -/* * Flags for use with createAccessFlagStr(). */ enum AccessFor { @@ -301,72 +287,209 @@ static void Asciify(char* out, const unsigned char* data, size_t len) { /* * Dumps a string value with some escape characters. */ -static void DumpEscapedString(const char* p) { - fputs("\"", out_file_); +static void DumpEscapedString(const char* p, FILE* out_file) { + fputs("\"", out_file); for (; *p; p++) { switch (*p) { case '\\': - fputs("\\\\", out_file_); + fputs("\\\\", out_file); break; case '\"': - fputs("\\\"", out_file_); + fputs("\\\"", out_file); break; case '\t': - fputs("\\t", out_file_); + fputs("\\t", out_file); break; case '\n': - fputs("\\n", out_file_); + fputs("\\n", out_file); break; case '\r': - fputs("\\r", out_file_); + fputs("\\r", out_file); break; default: - putc(*p, out_file_); + putc(*p, out_file); } // switch } // for - fputs("\"", out_file_); + fputs("\"", out_file); } /* * Dumps a string as an XML attribute value. */ -static void DumpXmlAttribute(const char* p) { +static void DumpXmlAttribute(const char* p, FILE* out_file) { for (; *p; p++) { switch (*p) { case '&': - fputs("&", out_file_); + fputs("&", out_file); break; case '<': - fputs("<", out_file_); + fputs("<", out_file); break; case '>': - fputs(">", out_file_); + fputs(">", out_file); break; case '"': - fputs(""", out_file_); + fputs(""", out_file); break; case '\t': - fputs(" ", out_file_); + fputs(" ", out_file); break; case '\n': - fputs(" ", out_file_); + fputs(" ", out_file); break; case '\r': - fputs(" ", out_file_); + fputs(" ", out_file); break; default: - putc(*p, out_file_); + putc(*p, out_file); } // switch } // for } -// Forward declare to resolve circular dependence. -static void DumpEncodedValue(const dex_ir::EncodedValue* data); +/* + * Helper for dumpInstruction(), which builds the string + * representation for the index in the given instruction. + * Returns a pointer to a buffer of sufficient size. + */ +static std::unique_ptr IndexString(dex_ir::Header* header, + const Instruction* dec_insn, + size_t buf_size) { + std::unique_ptr buf(new char[buf_size]); + // Determine index and width of the string. + uint32_t index = 0; + uint32_t secondary_index = DexFile::kDexNoIndex; + uint32_t width = 4; + switch (Instruction::FormatOf(dec_insn->Opcode())) { + // SOME NOT SUPPORTED: + // case Instruction::k20bc: + case Instruction::k21c: + case Instruction::k35c: + // case Instruction::k35ms: + case Instruction::k3rc: + // case Instruction::k3rms: + // case Instruction::k35mi: + // case Instruction::k3rmi: + index = dec_insn->VRegB(); + width = 4; + break; + case Instruction::k31c: + index = dec_insn->VRegB(); + width = 8; + break; + case Instruction::k22c: + // case Instruction::k22cs: + index = dec_insn->VRegC(); + width = 4; + break; + case Instruction::k45cc: + case Instruction::k4rcc: + index = dec_insn->VRegB(); + secondary_index = dec_insn->VRegH(); + width = 4; + default: + break; + } // switch + + // Determine index type. + size_t outSize = 0; + switch (Instruction::IndexTypeOf(dec_insn->Opcode())) { + case Instruction::kIndexUnknown: + // This function should never get called for this type, but do + // something sensible here, just to help with debugging. + outSize = snprintf(buf.get(), buf_size, ""); + break; + case Instruction::kIndexNone: + // This function should never get called for this type, but do + // something sensible here, just to help with debugging. + outSize = snprintf(buf.get(), buf_size, ""); + break; + case Instruction::kIndexTypeRef: + if (index < header->GetCollections().TypeIdsSize()) { + const char* tp = header->GetCollections().GetTypeId(index)->GetStringId()->Data(); + outSize = snprintf(buf.get(), buf_size, "%s // type@%0*x", tp, width, index); + } else { + outSize = snprintf(buf.get(), buf_size, " // type@%0*x", width, index); + } + break; + case Instruction::kIndexStringRef: + if (index < header->GetCollections().StringIdsSize()) { + const char* st = header->GetCollections().GetStringId(index)->Data(); + outSize = snprintf(buf.get(), buf_size, "\"%s\" // string@%0*x", st, width, index); + } else { + outSize = snprintf(buf.get(), buf_size, " // string@%0*x", width, index); + } + break; + case Instruction::kIndexMethodRef: + if (index < header->GetCollections().MethodIdsSize()) { + dex_ir::MethodId* method_id = header->GetCollections().GetMethodId(index); + const char* name = method_id->Name()->Data(); + std::string type_descriptor = GetSignatureForProtoId(method_id->Proto()); + const char* back_descriptor = method_id->Class()->GetStringId()->Data(); + outSize = snprintf(buf.get(), buf_size, "%s.%s:%s // method@%0*x", + back_descriptor, name, type_descriptor.c_str(), width, index); + } else { + outSize = snprintf(buf.get(), buf_size, " // method@%0*x", width, index); + } + break; + case Instruction::kIndexFieldRef: + if (index < header->GetCollections().FieldIdsSize()) { + dex_ir::FieldId* field_id = header->GetCollections().GetFieldId(index); + const char* name = field_id->Name()->Data(); + const char* type_descriptor = field_id->Type()->GetStringId()->Data(); + const char* back_descriptor = field_id->Class()->GetStringId()->Data(); + outSize = snprintf(buf.get(), buf_size, "%s.%s:%s // field@%0*x", + back_descriptor, name, type_descriptor, width, index); + } else { + outSize = snprintf(buf.get(), buf_size, " // field@%0*x", width, index); + } + break; + case Instruction::kIndexVtableOffset: + outSize = snprintf(buf.get(), buf_size, "[%0*x] // vtable #%0*x", + width, index, width, index); + break; + case Instruction::kIndexFieldOffset: + outSize = snprintf(buf.get(), buf_size, "[obj+%0*x]", width, index); + break; + case Instruction::kIndexMethodAndProtoRef: { + std::string method(""); + std::string proto(""); + if (index < header->GetCollections().MethodIdsSize()) { + dex_ir::MethodId* method_id = header->GetCollections().GetMethodId(index); + const char* name = method_id->Name()->Data(); + std::string type_descriptor = GetSignatureForProtoId(method_id->Proto()); + const char* back_descriptor = method_id->Class()->GetStringId()->Data(); + method = StringPrintf("%s.%s:%s", back_descriptor, name, type_descriptor.c_str()); + } + if (secondary_index < header->GetCollections().ProtoIdsSize()) { + dex_ir::ProtoId* proto_id = header->GetCollections().GetProtoId(secondary_index); + proto = GetSignatureForProtoId(proto_id); + } + outSize = snprintf(buf.get(), buf_size, "%s, %s // method@%0*x, proto@%0*x", + method.c_str(), proto.c_str(), width, index, width, secondary_index); + } + break; + // SOME NOT SUPPORTED: + // case Instruction::kIndexVaries: + // case Instruction::kIndexInlineMethod: + default: + outSize = snprintf(buf.get(), buf_size, ""); + break; + } // switch + + // Determine success of string construction. + if (outSize >= buf_size) { + // The buffer wasn't big enough; retry with computed size. Note: snprintf() + // doesn't count/ the '\0' as part of its returned size, so we add explicit + // space for it here. + return IndexString(header, dec_insn, outSize + 1); + } + return buf; +} /* * Dumps encoded annotation. */ -static void DumpEncodedAnnotation(dex_ir::EncodedAnnotation* annotation) { +void DexLayout::DumpEncodedAnnotation(dex_ir::EncodedAnnotation* annotation) { fputs(annotation->GetType()->GetStringId()->Data(), out_file_); // Display all name=value pairs. for (auto& subannotation : *annotation->GetAnnotationElements()) { @@ -379,7 +502,7 @@ static void DumpEncodedAnnotation(dex_ir::EncodedAnnotation* annotation) { /* * Dumps encoded value. */ -static void DumpEncodedValue(const dex_ir::EncodedValue* data) { +void DexLayout::DumpEncodedValue(const dex_ir::EncodedValue* data) { switch (data->Type()) { case DexFile::kDexAnnotationByte: fprintf(out_file_, "%" PRId8, data->GetByte()); @@ -407,9 +530,9 @@ static void DumpEncodedValue(const dex_ir::EncodedValue* data) { case DexFile::kDexAnnotationString: { dex_ir::StringId* string_id = data->GetStringId(); if (options_.output_format_ == kOutputPlain) { - DumpEscapedString(string_id->Data()); + DumpEscapedString(string_id->Data(), out_file_); } else { - DumpXmlAttribute(string_id->Data()); + DumpXmlAttribute(string_id->Data(), out_file_); } break; } @@ -458,22 +581,22 @@ static void DumpEncodedValue(const dex_ir::EncodedValue* data) { /* * Dumps the file header. */ -static void DumpFileHeader(dex_ir::Header* header) { +void DexLayout::DumpFileHeader() { char sanitized[8 * 2 + 1]; - dex_ir::Collections& collections = header->GetCollections(); + dex_ir::Collections& collections = header_->GetCollections(); fprintf(out_file_, "DEX file header:\n"); - Asciify(sanitized, header->Magic(), 8); + Asciify(sanitized, header_->Magic(), 8); fprintf(out_file_, "magic : '%s'\n", sanitized); - fprintf(out_file_, "checksum : %08x\n", header->Checksum()); + fprintf(out_file_, "checksum : %08x\n", header_->Checksum()); fprintf(out_file_, "signature : %02x%02x...%02x%02x\n", - header->Signature()[0], header->Signature()[1], - header->Signature()[DexFile::kSha1DigestSize - 2], - header->Signature()[DexFile::kSha1DigestSize - 1]); - fprintf(out_file_, "file_size : %d\n", header->FileSize()); - fprintf(out_file_, "header_size : %d\n", header->HeaderSize()); - fprintf(out_file_, "link_size : %d\n", header->LinkSize()); + header_->Signature()[0], header_->Signature()[1], + header_->Signature()[DexFile::kSha1DigestSize - 2], + header_->Signature()[DexFile::kSha1DigestSize - 1]); + fprintf(out_file_, "file_size : %d\n", header_->FileSize()); + fprintf(out_file_, "header_size : %d\n", header_->HeaderSize()); + fprintf(out_file_, "link_size : %d\n", header_->LinkSize()); fprintf(out_file_, "link_off : %d (0x%06x)\n", - header->LinkOffset(), header->LinkOffset()); + header_->LinkOffset(), header_->LinkOffset()); fprintf(out_file_, "string_ids_size : %d\n", collections.StringIdsSize()); fprintf(out_file_, "string_ids_off : %d (0x%06x)\n", collections.StringIdsOffset(), collections.StringIdsOffset()); @@ -492,17 +615,17 @@ static void DumpFileHeader(dex_ir::Header* header) { fprintf(out_file_, "class_defs_size : %d\n", collections.ClassDefsSize()); fprintf(out_file_, "class_defs_off : %d (0x%06x)\n", collections.ClassDefsOffset(), collections.ClassDefsOffset()); - fprintf(out_file_, "data_size : %d\n", header->DataSize()); + fprintf(out_file_, "data_size : %d\n", header_->DataSize()); fprintf(out_file_, "data_off : %d (0x%06x)\n\n", - header->DataOffset(), header->DataOffset()); + header_->DataOffset(), header_->DataOffset()); } /* * Dumps a class_def_item. */ -static void DumpClassDef(dex_ir::Header* header, int idx) { +void DexLayout::DumpClassDef(int idx) { // General class information. - dex_ir::ClassDef* class_def = header->GetCollections().GetClassDef(idx); + dex_ir::ClassDef* class_def = header_->GetCollections().GetClassDef(idx); fprintf(out_file_, "Class #%d header:\n", idx); fprintf(out_file_, "class_idx : %d\n", class_def->ClassType()->GetIndex()); fprintf(out_file_, "access_flags : %d (0x%04x)\n", @@ -558,7 +681,7 @@ static void DumpClassDef(dex_ir::Header* header, int idx) { /** * Dumps an annotation set item. */ -static void DumpAnnotationSetItem(dex_ir::AnnotationSetItem* set_item) { +void DexLayout::DumpAnnotationSetItem(dex_ir::AnnotationSetItem* set_item) { if (set_item == nullptr || set_item->GetItems()->size() == 0) { fputs(" empty-annotation-set\n", out_file_); return; @@ -582,8 +705,8 @@ static void DumpAnnotationSetItem(dex_ir::AnnotationSetItem* set_item) { /* * Dumps class annotations. */ -static void DumpClassAnnotations(dex_ir::Header* header, int idx) { - dex_ir::ClassDef* class_def = header->GetCollections().GetClassDef(idx); +void DexLayout::DumpClassAnnotations(int idx) { + dex_ir::ClassDef* class_def = header_->GetCollections().GetClassDef(idx); dex_ir::AnnotationsDirectoryItem* annotations_directory = class_def->Annotations(); if (annotations_directory == nullptr) { return; // none @@ -646,7 +769,7 @@ static void DumpClassAnnotations(dex_ir::Header* header, int idx) { /* * Dumps an interface that a class declares to implement. */ -static void DumpInterface(const dex_ir::TypeId* type_item, int i) { +void DexLayout::DumpInterface(const dex_ir::TypeId* type_item, int i) { const char* interface_name = type_item->GetStringId()->Data(); if (options_.output_format_ == kOutputPlain) { fprintf(out_file_, " #%d : '%s'\n", i, interface_name); @@ -659,7 +782,7 @@ static void DumpInterface(const dex_ir::TypeId* type_item, int i) { /* * Dumps the catches table associated with the code. */ -static void DumpCatches(const dex_ir::CodeItem* code) { +void DexLayout::DumpCatches(const dex_ir::CodeItem* code) { const uint16_t tries_size = code->TriesSize(); // No catch table. @@ -687,7 +810,7 @@ static void DumpCatches(const dex_ir::CodeItem* code) { /* * Dumps all positions table entries associated with the code. */ -static void DumpPositionInfo(const dex_ir::CodeItem* code) { +void DexLayout::DumpPositionInfo(const dex_ir::CodeItem* code) { dex_ir::DebugInfoItem* debug_info = code->DebugInfo(); if (debug_info == nullptr) { return; @@ -701,7 +824,7 @@ static void DumpPositionInfo(const dex_ir::CodeItem* code) { /* * Dumps all locals table entries associated with the code. */ -static void DumpLocalInfo(const dex_ir::CodeItem* code) { +void DexLayout::DumpLocalInfo(const dex_ir::CodeItem* code) { dex_ir::DebugInfoItem* debug_info = code->DebugInfo(); if (debug_info == nullptr) { return; @@ -716,153 +839,13 @@ static void DumpLocalInfo(const dex_ir::CodeItem* code) { } /* - * Helper for dumpInstruction(), which builds the string - * representation for the index in the given instruction. - * Returns a pointer to a buffer of sufficient size. - */ -static std::unique_ptr IndexString(dex_ir::Header* header, - const Instruction* dec_insn, - size_t buf_size) { - static const uint32_t kInvalidIndex = std::numeric_limits::max(); - std::unique_ptr buf(new char[buf_size]); - // Determine index and width of the string. - uint32_t index = 0; - uint32_t secondary_index = kInvalidIndex; - uint32_t width = 4; - switch (Instruction::FormatOf(dec_insn->Opcode())) { - // SOME NOT SUPPORTED: - // case Instruction::k20bc: - case Instruction::k21c: - case Instruction::k35c: - // case Instruction::k35ms: - case Instruction::k3rc: - // case Instruction::k3rms: - // case Instruction::k35mi: - // case Instruction::k3rmi: - index = dec_insn->VRegB(); - width = 4; - break; - case Instruction::k31c: - index = dec_insn->VRegB(); - width = 8; - break; - case Instruction::k22c: - // case Instruction::k22cs: - index = dec_insn->VRegC(); - width = 4; - break; - case Instruction::k45cc: - case Instruction::k4rcc: - index = dec_insn->VRegB(); - secondary_index = dec_insn->VRegH(); - width = 4; - break; - default: - break; - } // switch - - // Determine index type. - size_t outSize = 0; - switch (Instruction::IndexTypeOf(dec_insn->Opcode())) { - case Instruction::kIndexUnknown: - // This function should never get called for this type, but do - // something sensible here, just to help with debugging. - outSize = snprintf(buf.get(), buf_size, ""); - break; - case Instruction::kIndexNone: - // This function should never get called for this type, but do - // something sensible here, just to help with debugging. - outSize = snprintf(buf.get(), buf_size, ""); - break; - case Instruction::kIndexTypeRef: - if (index < header->GetCollections().TypeIdsSize()) { - const char* tp = header->GetCollections().GetTypeId(index)->GetStringId()->Data(); - outSize = snprintf(buf.get(), buf_size, "%s // type@%0*x", tp, width, index); - } else { - outSize = snprintf(buf.get(), buf_size, " // type@%0*x", width, index); - } - break; - case Instruction::kIndexStringRef: - if (index < header->GetCollections().StringIdsSize()) { - const char* st = header->GetCollections().GetStringId(index)->Data(); - outSize = snprintf(buf.get(), buf_size, "\"%s\" // string@%0*x", st, width, index); - } else { - outSize = snprintf(buf.get(), buf_size, " // string@%0*x", width, index); - } - break; - case Instruction::kIndexMethodRef: - if (index < header->GetCollections().MethodIdsSize()) { - dex_ir::MethodId* method_id = header->GetCollections().GetMethodId(index); - const char* name = method_id->Name()->Data(); - std::string type_descriptor = GetSignatureForProtoId(method_id->Proto()); - const char* back_descriptor = method_id->Class()->GetStringId()->Data(); - outSize = snprintf(buf.get(), buf_size, "%s.%s:%s // method@%0*x", - back_descriptor, name, type_descriptor.c_str(), width, index); - } else { - outSize = snprintf(buf.get(), buf_size, " // method@%0*x", width, index); - } - break; - case Instruction::kIndexFieldRef: - if (index < header->GetCollections().FieldIdsSize()) { - dex_ir::FieldId* field_id = header->GetCollections().GetFieldId(index); - const char* name = field_id->Name()->Data(); - const char* type_descriptor = field_id->Type()->GetStringId()->Data(); - const char* back_descriptor = field_id->Class()->GetStringId()->Data(); - outSize = snprintf(buf.get(), buf_size, "%s.%s:%s // field@%0*x", - back_descriptor, name, type_descriptor, width, index); - } else { - outSize = snprintf(buf.get(), buf_size, " // field@%0*x", width, index); - } - break; - case Instruction::kIndexVtableOffset: - outSize = snprintf(buf.get(), buf_size, "[%0*x] // vtable #%0*x", - width, index, width, index); - break; - case Instruction::kIndexFieldOffset: - outSize = snprintf(buf.get(), buf_size, "[obj+%0*x]", width, index); - break; - // SOME NOT SUPPORTED: - // case Instruction::kIndexVaries: - // case Instruction::kIndexInlineMethod: - case Instruction::kIndexMethodAndProtoRef: { - std::string method(""); - std::string proto(""); - if (index < header->GetCollections().MethodIdsSize()) { - dex_ir::MethodId* method_id = header->GetCollections().GetMethodId(index); - const char* name = method_id->Name()->Data(); - std::string type_descriptor = GetSignatureForProtoId(method_id->Proto()); - const char* back_descriptor = method_id->Class()->GetStringId()->Data(); - method = StringPrintf("%s.%s:%s", back_descriptor, name, type_descriptor.c_str()); - } - if (secondary_index < header->GetCollections().ProtoIdsSize()) { - dex_ir::ProtoId* proto_id = header->GetCollections().GetProtoId(secondary_index); - proto = GetSignatureForProtoId(proto_id); - } - outSize = snprintf(buf.get(), buf_size, "%s, %s // method@%0*x, proto@%0*x", - method.c_str(), proto.c_str(), width, index, width, secondary_index); - } - break; - default: - outSize = snprintf(buf.get(), buf_size, ""); - break; - } // switch - - // Determine success of string construction. - if (outSize >= buf_size) { - // The buffer wasn't big enough; retry with computed size. Note: snprintf() - // doesn't count/ the '\0' as part of its returned size, so we add explicit - // space for it here. - return IndexString(header, dec_insn, outSize + 1); - } - return buf; -} - -/* * Dumps a single instruction. */ -static void DumpInstruction(dex_ir::Header* header, const dex_ir::CodeItem* code, - uint32_t code_offset, uint32_t insn_idx, uint32_t insn_width, - const Instruction* dec_insn) { +void DexLayout::DumpInstruction(const dex_ir::CodeItem* code, + uint32_t code_offset, + uint32_t insn_idx, + uint32_t insn_width, + const Instruction* dec_insn) { // Address of instruction (expressed as byte offset). fprintf(out_file_, "%06x:", code_offset + 0x10 + insn_idx * 2); @@ -901,7 +884,7 @@ static void DumpInstruction(dex_ir::Header* header, const dex_ir::CodeItem* code // Set up additional argument. std::unique_ptr index_buf; if (Instruction::IndexTypeOf(dec_insn->Opcode()) != Instruction::kIndexNone) { - index_buf = IndexString(header, dec_insn, 200); + index_buf = IndexString(header_, dec_insn, 200); } // Dump the instruction. @@ -1073,9 +1056,8 @@ static void DumpInstruction(dex_ir::Header* header, const dex_ir::CodeItem* code /* * Dumps a bytecode disassembly. */ -static void DumpBytecodes(dex_ir::Header* header, uint32_t idx, - const dex_ir::CodeItem* code, uint32_t code_offset) { - dex_ir::MethodId* method_id = header->GetCollections().GetMethodId(idx); +void DexLayout::DumpBytecodes(uint32_t idx, const dex_ir::CodeItem* code, uint32_t code_offset) { + dex_ir::MethodId* method_id = header_->GetCollections().GetMethodId(idx); const char* name = method_id->Name()->Data(); std::string type_descriptor = GetSignatureForProtoId(method_id->Proto()); const char* back_descriptor = method_id->Class()->GetStringId()->Data(); @@ -1094,7 +1076,7 @@ static void DumpBytecodes(dex_ir::Header* header, uint32_t idx, fprintf(stderr, "GLITCH: zero-width instruction at idx=0x%04x\n", insn_idx); break; } - DumpInstruction(header, code, code_offset, insn_idx, insn_width, instruction); + DumpInstruction(code, code_offset, insn_idx, insn_width, instruction); insn_idx += insn_width; } // for } @@ -1102,8 +1084,7 @@ static void DumpBytecodes(dex_ir::Header* header, uint32_t idx, /* * Dumps code of a method. */ -static void DumpCode(dex_ir::Header* header, uint32_t idx, const dex_ir::CodeItem* code, - uint32_t code_offset) { +void DexLayout::DumpCode(uint32_t idx, const dex_ir::CodeItem* code, uint32_t code_offset) { fprintf(out_file_, " registers : %d\n", code->RegistersSize()); fprintf(out_file_, " ins : %d\n", code->InsSize()); fprintf(out_file_, " outs : %d\n", code->OutsSize()); @@ -1112,7 +1093,7 @@ static void DumpCode(dex_ir::Header* header, uint32_t idx, const dex_ir::CodeIte // Bytecode disassembly, if requested. if (options_.disassemble_) { - DumpBytecodes(header, idx, code, code_offset); + DumpBytecodes(idx, code, code_offset); } // Try-catch blocks. @@ -1128,14 +1109,13 @@ static void DumpCode(dex_ir::Header* header, uint32_t idx, const dex_ir::CodeIte /* * Dumps a method. */ -static void DumpMethod(dex_ir::Header* header, uint32_t idx, uint32_t flags, - const dex_ir::CodeItem* code, int i) { +void DexLayout::DumpMethod(uint32_t idx, uint32_t flags, const dex_ir::CodeItem* code, int i) { // Bail for anything private if export only requested. if (options_.exports_only_ && (flags & (kAccPublic | kAccProtected)) == 0) { return; } - dex_ir::MethodId* method_id = header->GetCollections().GetMethodId(idx); + dex_ir::MethodId* method_id = header_->GetCollections().GetMethodId(idx); const char* name = method_id->Name()->Data(); char* type_descriptor = strdup(GetSignatureForProtoId(method_id->Proto()).c_str()); const char* back_descriptor = method_id->Class()->GetStringId()->Data(); @@ -1150,7 +1130,7 @@ static void DumpMethod(dex_ir::Header* header, uint32_t idx, uint32_t flags, fprintf(out_file_, " code : (none)\n"); } else { fprintf(out_file_, " code -\n"); - DumpCode(header, idx, code, code->GetOffset()); + DumpCode(idx, code, code->GetOffset()); } if (options_.disassemble_) { fputc('\n', out_file_); @@ -1233,14 +1213,13 @@ static void DumpMethod(dex_ir::Header* header, uint32_t idx, uint32_t flags, /* * Dumps a static (class) field. */ -static void DumpSField(dex_ir::Header* header, uint32_t idx, uint32_t flags, - int i, dex_ir::EncodedValue* init) { +void DexLayout::DumpSField(uint32_t idx, uint32_t flags, int i, dex_ir::EncodedValue* init) { // Bail for anything private if export only requested. if (options_.exports_only_ && (flags & (kAccPublic | kAccProtected)) == 0) { return; } - dex_ir::FieldId* field_id = header->GetCollections().GetFieldId(idx); + dex_ir::FieldId* field_id = header_->GetCollections().GetFieldId(idx); const char* name = field_id->Name()->Data(); const char* type_descriptor = field_id->Type()->GetStringId()->Data(); const char* back_descriptor = field_id->Class()->GetStringId()->Data(); @@ -1281,8 +1260,8 @@ static void DumpSField(dex_ir::Header* header, uint32_t idx, uint32_t flags, /* * Dumps an instance field. */ -static void DumpIField(dex_ir::Header* header, uint32_t idx, uint32_t flags, int i) { - DumpSField(header, idx, flags, i, nullptr); +void DexLayout::DumpIField(uint32_t idx, uint32_t flags, int i) { + DumpSField(idx, flags, i, nullptr); } /* @@ -1293,19 +1272,19 @@ static void DumpIField(dex_ir::Header* header, uint32_t idx, uint32_t flags, int * If "*last_package" is nullptr or does not match the current class' package, * the value will be replaced with a newly-allocated string. */ -static void DumpClass(dex_ir::Header* header, int idx, char** last_package) { - dex_ir::ClassDef* class_def = header->GetCollections().GetClassDef(idx); +void DexLayout::DumpClass(int idx, char** last_package) { + dex_ir::ClassDef* class_def = header_->GetCollections().GetClassDef(idx); // Omitting non-public class. if (options_.exports_only_ && (class_def->GetAccessFlags() & kAccPublic) == 0) { return; } if (options_.show_section_headers_) { - DumpClassDef(header, idx); + DumpClassDef(idx); } if (options_.show_annotations_) { - DumpClassAnnotations(header, idx); + DumpClassAnnotations(idx); } // For the XML output, show the package name. Ideally we'd gather @@ -1313,7 +1292,7 @@ static void DumpClass(dex_ir::Header* header, int idx, char** last_package) { // package name wouldn't jump around, but that's not a great plan // for something that needs to run on the device. const char* class_descriptor = - header->GetCollections().GetClassDef(idx)->ClassType()->GetStringId()->Data(); + header_->GetCollections().GetClassDef(idx)->ClassType()->GetStringId()->Data(); if (!(class_descriptor[0] == 'L' && class_descriptor[strlen(class_descriptor)-1] == ';')) { // Arrays and primitives should not be defined explicitly. Keep going? @@ -1406,8 +1385,7 @@ static void DumpClass(dex_ir::Header* header, int idx, char** last_package) { dex_ir::FieldItemVector* static_fields = class_data->StaticFields(); if (static_fields != nullptr) { for (uint32_t i = 0; i < static_fields->size(); i++) { - DumpSField(header, - (*static_fields)[i]->GetFieldId()->GetIndex(), + DumpSField((*static_fields)[i]->GetFieldId()->GetIndex(), (*static_fields)[i]->GetAccessFlags(), i, i < encoded_values_size ? (*encoded_values)[i].get() : nullptr); @@ -1423,8 +1401,7 @@ static void DumpClass(dex_ir::Header* header, int idx, char** last_package) { dex_ir::FieldItemVector* instance_fields = class_data->InstanceFields(); if (instance_fields != nullptr) { for (uint32_t i = 0; i < instance_fields->size(); i++) { - DumpIField(header, - (*instance_fields)[i]->GetFieldId()->GetIndex(), + DumpIField((*instance_fields)[i]->GetFieldId()->GetIndex(), (*instance_fields)[i]->GetAccessFlags(), i); } // for @@ -1439,8 +1416,7 @@ static void DumpClass(dex_ir::Header* header, int idx, char** last_package) { dex_ir::MethodItemVector* direct_methods = class_data->DirectMethods(); if (direct_methods != nullptr) { for (uint32_t i = 0; i < direct_methods->size(); i++) { - DumpMethod(header, - (*direct_methods)[i]->GetMethodId()->GetIndex(), + DumpMethod((*direct_methods)[i]->GetMethodId()->GetIndex(), (*direct_methods)[i]->GetAccessFlags(), (*direct_methods)[i]->GetCodeItem(), i); @@ -1456,8 +1432,7 @@ static void DumpClass(dex_ir::Header* header, int idx, char** last_package) { dex_ir::MethodItemVector* virtual_methods = class_data->VirtualMethods(); if (virtual_methods != nullptr) { for (uint32_t i = 0; i < virtual_methods->size(); i++) { - DumpMethod(header, - (*virtual_methods)[i]->GetMethodId()->GetIndex(), + DumpMethod((*virtual_methods)[i]->GetMethodId()->GetIndex(), (*virtual_methods)[i]->GetAccessFlags(), (*virtual_methods)[i]->GetCodeItem(), i); @@ -1481,24 +1456,10 @@ static void DumpClass(dex_ir::Header* header, int idx, char** last_package) { free(access_str); } -/* - * Dumps the requested sections of the file. - */ -static void ProcessDexFile(const char* file_name, const DexFile* dex_file, size_t dex_file_index) { - if (options_.verbose_) { - fprintf(out_file_, "Opened '%s', DEX version '%.3s'\n", - file_name, dex_file->GetHeader().magic_ + 4); - } - std::unique_ptr header(dex_ir::DexIrBuilder(*dex_file)); - - if (options_.visualize_pattern_) { - VisualizeDexLayout(header.get(), dex_file, dex_file_index); - return; - } - +void DexLayout::DumpDexFile() { // Headers. if (options_.show_file_headers_) { - DumpFileHeader(header.get()); + DumpFileHeader(); } // Open XML context. @@ -1508,9 +1469,9 @@ static void ProcessDexFile(const char* file_name, const DexFile* dex_file, size_ // Iterate over all classes. char* package = nullptr; - const uint32_t class_defs_size = header->GetCollections().ClassDefsSize(); + const uint32_t class_defs_size = header_->GetCollections().ClassDefsSize(); for (uint32_t i = 0; i < class_defs_size; i++) { - DumpClass(header.get(), i, &package); + DumpClass(i, &package); } // for // Free the last package allocated. @@ -1523,20 +1484,77 @@ static void ProcessDexFile(const char* file_name, const DexFile* dex_file, size_ if (options_.output_format_ == kOutputXml) { fprintf(out_file_, "\n"); } +} - // Output dex file. - if (options_.output_dex_directory_ != nullptr) { +void DexLayout::OutputDexFile(const std::string& dex_file_location) { + std::string error_msg; + std::unique_ptr new_file; + if (!options_.output_to_memmap_) { 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()); + size_t last_slash = dex_file_location.rfind("/"); + std::string dex_file_directory = dex_file_location.substr(0, last_slash + 1); + if (output_location == dex_file_directory) { + output_location = dex_file_location + ".new"; + } else if (last_slash != std::string::npos) { + output_location += dex_file_location.substr(last_slash); + } else { + output_location += "/" + dex_file_location + ".new"; + } + new_file.reset(OS::CreateEmptyFile(output_location.c_str())); + ftruncate(new_file->Fd(), header_->FileSize()); + mem_map_.reset(MemMap::MapFile(header_->FileSize(), PROT_READ | PROT_WRITE, MAP_SHARED, + new_file->Fd(), 0, /*low_4gb*/ false, output_location.c_str(), &error_msg)); + } else { + mem_map_.reset(MemMap::MapAnonymous("layout dex", nullptr, header_->FileSize(), + PROT_READ | PROT_WRITE, /* low_4gb */ false, /* reuse */ false, &error_msg)); + } + if (mem_map_ == nullptr) { + LOG(ERROR) << "Could not create mem map for dex writer output: " << error_msg; + if (new_file.get() != nullptr) { + new_file->Erase(); + } + return; + } + DexWriter::Output(header_, mem_map_.get()); + if (new_file != nullptr) { + UNUSED(new_file->FlushCloseOrErase()); + } +} + +/* + * Dumps the requested sections of the file. + */ +void DexLayout::ProcessDexFile(const char* file_name, + const DexFile* dex_file, + size_t dex_file_index) { + std::unique_ptr header(dex_ir::DexIrBuilder(*dex_file)); + SetHeader(header.get()); + + if (options_.verbose_) { + fprintf(out_file_, "Opened '%s', DEX version '%.3s'\n", + file_name, dex_file->GetHeader().magic_ + 4); + } + + if (options_.visualize_pattern_) { + VisualizeDexLayout(header_, dex_file, dex_file_index, info_); + return; + } + + // Dump dex file. + if (options_.dump_) { + DumpDexFile(); + } + + // Output dex file as file or memmap. + if (options_.output_dex_directory_ != nullptr || options_.output_to_memmap_) { + OutputDexFile(dex_file->GetLocation()); } } /* * Processes a single file (either direct .dex or indirect .zip/.jar/.apk). */ -int ProcessFile(const char* file_name) { +int DexLayout::ProcessFile(const char* file_name) { if (options_.verbose_) { fprintf(out_file_, "Processing '%s'...\n", file_name); } diff --git a/dexlayout/dexlayout.h b/dexlayout/dexlayout.h index a5bd99284..179e90edc 100644 --- a/dexlayout/dexlayout.h +++ b/dexlayout/dexlayout.h @@ -26,8 +26,13 @@ #include #include +#include "dex_ir.h" +#include "mem_map.h" + namespace art { +class DexFile; +class Instruction; class ProfileCompilationInfo; /* Supported output formats. */ @@ -37,28 +42,87 @@ enum OutputFormat { }; /* Command-line options. */ -struct Options { - bool build_dex_ir_; - bool checksum_only_; - bool disassemble_; - bool exports_only_; - bool ignore_bad_checksum_; - bool show_annotations_; - bool show_file_headers_; - bool show_section_headers_; - bool verbose_; - bool visualize_pattern_; - OutputFormat output_format_; - const char* output_dex_directory_; - const char* output_file_name_; - const char* profile_file_name_; +class Options { + public: + Options() = default; + + bool dump_ = false; + bool build_dex_ir_ = false; + bool checksum_only_ = false; + bool disassemble_ = false; + bool exports_only_ = false; + bool ignore_bad_checksum_ = false; + bool output_to_memmap_ = false; + bool show_annotations_ = false; + bool show_file_headers_ = false; + bool show_section_headers_ = false; + bool verbose_ = false; + bool visualize_pattern_ = false; + OutputFormat output_format_ = kOutputPlain; + const char* output_dex_directory_ = nullptr; + const char* output_file_name_ = nullptr; + const char* profile_file_name_ = nullptr; }; -/* Prototypes. */ -extern struct Options options_; -extern FILE* out_file_; -extern ProfileCompilationInfo* profile_info_; -int ProcessFile(const char* file_name); +class DexLayout { + public: + DexLayout(Options& options, + ProfileCompilationInfo* info, + FILE* out_file, + dex_ir::Header* + header = nullptr) + : options_(options), info_(info), out_file_(out_file), header_(header) { } + + int ProcessFile(const char* file_name); + void ProcessDexFile(const char* file_name, const DexFile* dex_file, size_t dex_file_index); + + dex_ir::Header* GetHeader() const { return header_; } + void SetHeader(dex_ir::Header* header) { header_ = header; } + + MemMap* GetAndReleaseMemMap() { return mem_map_.release(); } + + private: + void DumpAnnotationSetItem(dex_ir::AnnotationSetItem* set_item); + void DumpBytecodes(uint32_t idx, const dex_ir::CodeItem* code, uint32_t code_offset); + void DumpCatches(const dex_ir::CodeItem* code); + void DumpClass(int idx, char** last_package); + void DumpClassAnnotations(int idx); + void DumpClassDef(int idx); + void DumpCode(uint32_t idx, const dex_ir::CodeItem* code, uint32_t code_offset); + void DumpEncodedAnnotation(dex_ir::EncodedAnnotation* annotation); + void DumpEncodedValue(const dex_ir::EncodedValue* data); + void DumpFileHeader(); + void DumpIField(uint32_t idx, uint32_t flags, int i); + void DumpInstruction(const dex_ir::CodeItem* code, + uint32_t code_offset, + uint32_t insn_idx, + uint32_t insn_width, + const Instruction* dec_insn); + void DumpInterface(const dex_ir::TypeId* type_item, int i); + void DumpLocalInfo(const dex_ir::CodeItem* code); + void DumpMethod(uint32_t idx, uint32_t flags, const dex_ir::CodeItem* code, int i); + void DumpPositionInfo(const dex_ir::CodeItem* code); + void DumpSField(uint32_t idx, uint32_t flags, int i, dex_ir::EncodedValue* init); + + void DumpDexFile(); + std::vector LayoutClassDefsAndClassData(const DexFile* dex_file); + int32_t LayoutCodeItems(std::vector new_class_def_order); + template void FixupSection(std::map>& map, uint32_t diff); + void FixupSections(uint32_t offset, uint32_t diff); + void LayoutOutputFile(const DexFile* dex_file); + void OutputDexFile(const std::string& dex_file_location); + + void DumpCFG(const DexFile* dex_file, int idx); + void DumpCFG(const DexFile* dex_file, uint32_t dex_method_idx, const DexFile::CodeItem* code); + + Options& options_; + ProfileCompilationInfo* info_; + FILE* out_file_; + dex_ir::Header* header_; + std::unique_ptr mem_map_; + + DISALLOW_COPY_AND_ASSIGN(DexLayout); +}; } // namespace art diff --git a/dexlayout/dexlayout_main.cc b/dexlayout/dexlayout_main.cc index 825dd5035..5f8a118bd 100644 --- a/dexlayout/dexlayout_main.cc +++ b/dexlayout/dexlayout_main.cc @@ -68,64 +68,67 @@ int DexlayoutDriver(int argc, char** argv) { InitLogging(argv, Runtime::Aborter); MemMap::Init(); - // Reset options. + Options options; + options.dump_ = true; + options.verbose_ = true; bool want_usage = false; - memset(&options_, 0, sizeof(options_)); - options_.verbose_ = true; // Parse all arguments. while (1) { - const int ic = getopt(argc, argv, "abcdefghil:o:p:sw:"); + const int ic = getopt(argc, argv, "abcdefghil:mo:p:sw:"); if (ic < 0) { break; // done } switch (ic) { case 'a': // display annotations - options_.show_annotations_ = true; + options.show_annotations_ = true; break; case 'b': // build dex_ir - options_.build_dex_ir_ = true; + options.build_dex_ir_ = true; break; case 'c': // verify the checksum then exit - options_.checksum_only_ = true; + options.checksum_only_ = true; break; case 'd': // disassemble Dalvik instructions - options_.disassemble_ = true; + options.disassemble_ = true; break; case 'e': // exported items only - options_.exports_only_ = true; + options.exports_only_ = true; break; case 'f': // display outer file header - options_.show_file_headers_ = true; + options.show_file_headers_ = true; break; case 'h': // display section headers, i.e. all meta-data - options_.show_section_headers_ = true; + options.show_section_headers_ = true; break; case 'i': // continue even if checksum is bad - options_.ignore_bad_checksum_ = true; + options.ignore_bad_checksum_ = true; break; case 'l': // layout if (strcmp(optarg, "plain") == 0) { - options_.output_format_ = kOutputPlain; + options.output_format_ = kOutputPlain; } else if (strcmp(optarg, "xml") == 0) { - options_.output_format_ = kOutputXml; - options_.verbose_ = false; + options.output_format_ = kOutputXml; + options.verbose_ = false; } else { want_usage = true; } break; + case 'm': // output dex files to a memmap + options.output_to_memmap_ = true; + break; case 'o': // output file - options_.output_file_name_ = optarg; + options.output_file_name_ = optarg; break; case 'p': // profile file - options_.profile_file_name_ = optarg; + options.profile_file_name_ = optarg; break; case 's': // visualize access pattern - options_.visualize_pattern_ = true; - options_.verbose_ = false; + options.visualize_pattern_ = true; + options.verbose_ = false; break; case 'w': // output dex files directory - options_.output_dex_directory_ = optarg; + options.output_dex_directory_ = optarg; break; default: want_usage = true; @@ -138,7 +141,7 @@ int DexlayoutDriver(int argc, char** argv) { fprintf(stderr, "%s: no file specified\n", kProgramName); want_usage = true; } - if (options_.checksum_only_ && options_.ignore_bad_checksum_) { + if (options.checksum_only_ && options.ignore_bad_checksum_) { fprintf(stderr, "Can't specify both -c and -i\n"); want_usage = true; } @@ -148,32 +151,37 @@ int DexlayoutDriver(int argc, char** argv) { } // Open alternative output file. - if (options_.output_file_name_) { - out_file_ = fopen(options_.output_file_name_, "w"); - if (!out_file_) { - fprintf(stderr, "Can't open %s\n", options_.output_file_name_); + FILE* out_file = stdout; + if (options.output_file_name_) { + out_file = fopen(options.output_file_name_, "w"); + if (!out_file) { + fprintf(stderr, "Can't open %s\n", options.output_file_name_); return 1; } } // Open profile file. - if (options_.profile_file_name_) { - int profile_fd = open(options_.profile_file_name_, O_RDONLY); + ProfileCompilationInfo* profile_info = nullptr; + if (options.profile_file_name_) { + int profile_fd = open(options.profile_file_name_, O_RDONLY); if (profile_fd < 0) { - fprintf(stderr, "Can't open %s\n", options_.profile_file_name_); + fprintf(stderr, "Can't open %s\n", options.profile_file_name_); return 1; } - profile_info_ = new ProfileCompilationInfo(); - if (!profile_info_->Load(profile_fd)) { - fprintf(stderr, "Can't read profile info from %s\n", options_.profile_file_name_); + profile_info = new ProfileCompilationInfo(); + if (!profile_info->Load(profile_fd)) { + fprintf(stderr, "Can't read profile info from %s\n", options.profile_file_name_); return 1; } } + // Create DexLayout instance. + DexLayout dex_layout(options, profile_info, out_file); + // Process all files supplied on command line. int result = 0; while (optind < argc) { - result |= ProcessFile(argv[optind++]); + result |= dex_layout.ProcessFile(argv[optind++]); } // while return result != 0; } -- 2.11.0