diff options
author | 2024-06-07 18:37:36 +0100 | |
---|---|---|
committer | 2024-06-11 17:04:48 +0000 | |
commit | e472bb5932be0104f43a027db60e64dd8635cd0a (patch) | |
tree | 786790b1ec3971606ae1ab4bb9f03a9bca885ef9 | |
parent | d61b2041348830473064d3f934cdf18d49a6170f (diff) |
Remove dexlayout.
dex2oat hasn't supported --compact-dex-level=fast since
https://r.android.com/2736873.
Test: art/tools/buildbot-build.sh
Bug: 6527146
Bug: 325430813
Change-Id: If517dbc2fabb71d79468d74ea219ccb89b037e6c
-rw-r--r-- | dexlayout/Android.bp | 299 | ||||
-rw-r--r-- | dexlayout/compact_dex_writer.cc | 528 | ||||
-rw-r--r-- | dexlayout/compact_dex_writer.h | 179 | ||||
-rw-r--r-- | dexlayout/dex_container.h | 96 | ||||
-rw-r--r-- | dexlayout/dex_ir.cc | 174 | ||||
-rw-r--r-- | dexlayout/dex_ir.h | 1369 | ||||
-rw-r--r-- | dexlayout/dex_ir_builder.cc | 1263 | ||||
-rw-r--r-- | dexlayout/dex_ir_builder.h | 39 | ||||
-rw-r--r-- | dexlayout/dex_verify.cc | 1048 | ||||
-rw-r--r-- | dexlayout/dex_verify.h | 117 | ||||
-rw-r--r-- | dexlayout/dex_visualize.cc | 348 | ||||
-rw-r--r-- | dexlayout/dex_visualize.h | 45 | ||||
-rw-r--r-- | dexlayout/dex_writer.cc | 1007 | ||||
-rw-r--r-- | dexlayout/dex_writer.h | 286 | ||||
-rw-r--r-- | dexlayout/dexdiag.cc | 540 | ||||
-rw-r--r-- | dexlayout/dexdiag_test.cc | 143 | ||||
-rw-r--r-- | dexlayout/dexlayout.cc | 2332 | ||||
-rw-r--r-- | dexlayout/dexlayout.h | 222 | ||||
-rw-r--r-- | dexlayout/dexlayout_main.cc | 235 | ||||
-rw-r--r-- | dexlayout/dexlayout_test.cc | 834 |
20 files changed, 0 insertions, 11104 deletions
diff --git a/dexlayout/Android.bp b/dexlayout/Android.bp deleted file mode 100644 index 09ec0fc79f..0000000000 --- a/dexlayout/Android.bp +++ /dev/null @@ -1,299 +0,0 @@ -// 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. - -package { - // See: http://go/android-license-faq - // A large-scale-change added 'default_applicable_licenses' to import - // all of the 'license_kinds' from "art_license" - // to get the below license kinds: - // SPDX-license-identifier-Apache-2.0 - default_applicable_licenses: ["art_license"], - default_team: "trendy_team_art_performance", -} - -art_cc_defaults { - name: "libart-dexlayout-defaults", - defaults: ["art_defaults"], - host_supported: true, - srcs: [ - "compact_dex_writer.cc", - "dexlayout.cc", - "dex_ir.cc", - "dex_ir_builder.cc", - "dex_verify.cc", - "dex_visualize.cc", - "dex_writer.cc", - ], - export_include_dirs: ["."], - target: { - android: { - shared_libs: [ - "libartpalette", - "libbase", - ], - }, - not_windows: { - shared_libs: [ - "libartpalette", - "libbase", - ], - }, - windows: { - cflags: ["-Wno-thread-safety"], - static_libs: [ - "libartpalette", - "libbase", - ], - }, - }, - shared_libs: ["libz"], -} - -cc_defaults { - name: "libart-dexlayout_static_base_defaults", - whole_static_libs: [ - "libbase", - "libz", - ], -} - -art_cc_library { - name: "libart-dexlayout", - defaults: [ - "libart-dexlayout-defaults", - ], - target: { - android: { - lto: { - thin: true, - }, - shared_libs: [ - "libartbase", - "libdexfile", - "libprofile", - ], - }, - not_windows: { - shared_libs: [ - "libartbase", - "libdexfile", - "libprofile", - ], - }, - windows: { - enabled: true, - shared: { - enabled: false, - }, - static_libs: [ - "libartbase", - "libdexfile", - "libprofile", - ], - }, - }, - apex_available: [ - "com.android.art", - "com.android.art.debug", - "test_broken_com.android.art", - ], -} - -cc_defaults { - name: "libart-dexlayout_static_defaults", - defaults: [ - "libart-dexlayout_static_base_defaults", - "libartbase_static_defaults", - "libdexfile_static_defaults", - "libprofile_static_defaults", - ], - whole_static_libs: ["libart-dexlayout"], -} - -art_cc_library { - name: "libartd-dexlayout", - defaults: [ - "libart-dexlayout-defaults", - "art_debug_defaults", - ], - target: { - android: { - shared_libs: [ - "libartbased", - "libdexfiled", - "libprofiled", - ], - }, - not_windows: { - shared_libs: [ - "libartbased", - "libdexfiled", - "libprofiled", - ], - }, - windows: { - static_libs: [ - "libartbased", - "libdexfiled", - "libprofiled", - ], - }, - }, - apex_available: [ - "com.android.art.debug", - // TODO(b/183882457): This lib doesn't go into com.android.art, but - // apex_available lists need to be the same for internal libs to avoid - // stubs, and this depends on libdexfiled. - "com.android.art", - ], -} - -cc_defaults { - name: "libartd-dexlayout_static_defaults", - defaults: [ - "libart-dexlayout_static_base_defaults", - "libartbased_static_defaults", - "libdexfiled_static_defaults", - "libprofiled_static_defaults", - ], - whole_static_libs: ["libartd-dexlayout"], -} - -cc_defaults { - name: "dexlayout-defaults", - defaults: ["art_defaults"], - host_supported: true, - shared_libs: [ - "libbase", - ], -} - -art_cc_binary { - name: "dexlayout", - defaults: ["dexlayout-defaults"], - srcs: ["dexlayout_main.cc"], - shared_libs: [ - "libdexfile", - "libprofile", - "libartbase", - "libart-dexlayout", - ], - apex_available: [ - "com.android.art", - "com.android.art.debug", - "test_broken_com.android.art", - ], -} - -art_cc_binary { - name: "dexlayouts", - defaults: [ - "dexlayout-defaults", - "libart-dexlayout_static_defaults", - "libprofile_static_defaults", - "libdexfile_static_defaults", - "libartbase_static_defaults", - ], - srcs: ["dexlayout_main.cc"], - host_supported: true, - device_supported: false, - target: { - darwin: { - enabled: false, - }, - windows: { - enabled: true, - cflags: ["-Wno-thread-safety"], - }, - }, -} - -art_cc_binary { - name: "dexlayoutd", - defaults: [ - "art_debug_defaults", - "dexlayout-defaults", - ], - srcs: ["dexlayout_main.cc"], - shared_libs: [ - "libdexfiled", - "libprofiled", - "libartbased", - "libartd-dexlayout", - ], - apex_available: [ - "com.android.art.debug", - ], -} - -art_cc_test { - name: "art_dexlayout_tests", - defaults: ["art_gtest_defaults"], - shared_libs: [ - "libprofiled", - "libartd-dexlayout", - ], - data: [ - ":art-gtest-jars-ManyMethods", - ], - srcs: ["dexlayout_test.cc"], - target: { - host: { - required: [ - "dexdump", - "dexlayoutd", - ], - }, - }, -} - -art_cc_binary { - name: "dexdiag", - defaults: ["art_defaults"], - host_supported: true, - srcs: ["dexdiag.cc"], - cflags: ["-Wall"], - shared_libs: [ - "libart", - "libdexfile", - "libartbase", - "libart-dexlayout", - "libbase", - ], - target: { - android: { - shared_libs: [ - "libmeminfo", - ], - }, - }, - apex_available: [ - "com.android.art", - "com.android.art.debug", - ], -} - -art_cc_test { - name: "art_dexdiag_tests", - host_supported: true, - defaults: [ - "art_gtest_defaults", - ], - srcs: ["dexdiag_test.cc"], - target: { - host: { - required: ["dexdiag"], - }, - }, -} diff --git a/dexlayout/compact_dex_writer.cc b/dexlayout/compact_dex_writer.cc deleted file mode 100644 index b07a956ce4..0000000000 --- a/dexlayout/compact_dex_writer.cc +++ /dev/null @@ -1,528 +0,0 @@ -/* - * Copyright (C) 2017 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. - */ - -#include "compact_dex_writer.h" - -#include "android-base/stringprintf.h" -#include "base/logging.h" -#include "base/time_utils.h" -#include "dex/compact_dex_file.h" -#include "dex/compact_offset_table.h" -#include "dexlayout.h" - -namespace art { - -CompactDexWriter::CompactDexWriter(DexLayout* dex_layout) - : DexWriter(dex_layout, /*compute_offsets=*/ true) { - CHECK(GetCompactDexLevel() != CompactDexLevel::kCompactDexLevelNone); -} - -CompactDexLevel CompactDexWriter::GetCompactDexLevel() const { - return dex_layout_->GetOptions().compact_dex_level_; -} - -CompactDexWriter::Container::Container() - : data_item_dedupe_(&data_section_) {} - -uint32_t CompactDexWriter::WriteDebugInfoOffsetTable(Stream* stream) { - const uint32_t start_offset = stream->Tell(); - // Debug offsets for method indexes. 0 means no debug info. - std::vector<uint32_t> debug_info_offsets(header_->MethodIds().Size(), 0u); - - static constexpr InvokeType invoke_types[] = { - kDirect, - kVirtual - }; - - for (InvokeType invoke_type : invoke_types) { - for (auto& class_def : header_->ClassDefs()) { - // Skip classes that are not defined in this dex file. - dex_ir::ClassData* class_data = class_def->GetClassData(); - if (class_data == nullptr) { - continue; - } - for (auto& method : *(invoke_type == InvokeType::kDirect - ? class_data->DirectMethods() - : class_data->VirtualMethods())) { - const dex_ir::MethodId* method_id = method.GetMethodId(); - dex_ir::CodeItem* code_item = method.GetCodeItem(); - if (code_item != nullptr && code_item->DebugInfo() != nullptr) { - const uint32_t debug_info_offset = code_item->DebugInfo()->GetOffset(); - const uint32_t method_idx = method_id->GetIndex(); - if (debug_info_offsets[method_idx] != 0u) { - CHECK_EQ(debug_info_offset, debug_info_offsets[method_idx]); - } - debug_info_offsets[method_idx] = debug_info_offset; - } - } - } - } - - std::vector<uint8_t> data; - debug_info_base_ = 0u; - debug_info_offsets_table_offset_ = 0u; - CompactOffsetTable::Build(debug_info_offsets, - &data, - &debug_info_base_, - &debug_info_offsets_table_offset_); - // Align the table and write it out. - stream->AlignTo(CompactOffsetTable::kAlignment); - debug_info_offsets_pos_ = stream->Tell(); - stream->Write(data.data(), data.size()); - - // Verify that the whole table decodes as expected and measure average performance. - const bool kMeasureAndTestOutput = dex_layout_->GetOptions().verify_output_; - if (kMeasureAndTestOutput && !debug_info_offsets.empty()) { - uint64_t start_time = NanoTime(); - stream->Begin(); - CompactOffsetTable::Accessor accessor(stream->Begin() + debug_info_offsets_pos_, - debug_info_base_, - debug_info_offsets_table_offset_); - - for (size_t i = 0; i < debug_info_offsets.size(); ++i) { - CHECK_EQ(accessor.GetOffset(i), debug_info_offsets[i]); - } - uint64_t end_time = NanoTime(); - VLOG(dex) << "Average lookup time (ns) for debug info offsets: " - << (end_time - start_time) / debug_info_offsets.size(); - } - - return stream->Tell() - start_offset; -} - -CompactDexWriter::ScopedDataSectionItem::ScopedDataSectionItem(Stream* stream, - dex_ir::Item* item, - size_t alignment, - Deduper* deduper) - : stream_(stream), - item_(item), - alignment_(alignment), - deduper_(deduper), - start_offset_(stream->Tell()) { - stream_->AlignTo(alignment_); -} - -CompactDexWriter::ScopedDataSectionItem::~ScopedDataSectionItem() { - if (deduper_ == nullptr) { - return; - } - // After having written, maybe dedupe the whole section (excluding padding). - const uint32_t deduped_offset = deduper_->Dedupe(start_offset_, - stream_->Tell(), - item_->GetOffset()); - // If we deduped, only use the deduped offset if the alignment matches the required alignment. - // Otherwise, return without deduping. - if (deduped_offset != Deduper::kDidNotDedupe && IsAlignedParam(deduped_offset, alignment_)) { - // Update the IR offset to the offset of the deduped item. - item_->SetOffset(deduped_offset); - // Clear the written data for the item so that the stream write doesn't abort in the future. - stream_->Clear(start_offset_, stream_->Tell() - start_offset_); - // Since we deduped, restore the offset to the original position. - stream_->Seek(start_offset_); - } -} - -size_t CompactDexWriter::ScopedDataSectionItem::Written() const { - return stream_->Tell() - start_offset_; -} - -void CompactDexWriter::WriteCodeItem(Stream* stream, - dex_ir::CodeItem* code_item, - bool reserve_only) { - DCHECK(code_item != nullptr); - DCHECK(!reserve_only) << "Not supported because of deduping."; - ScopedDataSectionItem data_item(stream, - code_item, - CompactDexFile::CodeItem::kAlignment, - /* deduper= */ nullptr); - - CompactDexFile::CodeItem disk_code_item; - - uint16_t preheader_storage[CompactDexFile::CodeItem::kMaxPreHeaderSize] = {}; - uint16_t* preheader_end = preheader_storage + CompactDexFile::CodeItem::kMaxPreHeaderSize; - const uint16_t* preheader = disk_code_item.Create( - code_item->RegistersSize(), - code_item->InsSize(), - code_item->OutsSize(), - code_item->TriesSize(), - code_item->InsnsSize(), - preheader_end); - const size_t preheader_bytes = (preheader_end - preheader) * sizeof(preheader[0]); - - static constexpr size_t kPayloadInstructionRequiredAlignment = 4; - const uint32_t current_code_item_start = stream->Tell() + preheader_bytes; - if (!IsAlignedParam(current_code_item_start, kPayloadInstructionRequiredAlignment) || - kIsDebugBuild) { - // If the preheader is going to make the code unaligned, consider adding 2 bytes of padding - // before if required. - IterationRange<DexInstructionIterator> instructions = code_item->Instructions(); - SafeDexInstructionIterator it(instructions.begin(), instructions.end()); - for (; !it.IsErrorState() && it < instructions.end(); ++it) { - // In case the instruction goes past the end of the code item, make sure to not process it. - if (std::next(it).IsErrorState()) { - break; - } - const Instruction::Code opcode = it->Opcode(); - // Payload instructions possibly require special alignment for their data. - if (opcode == Instruction::FILL_ARRAY_DATA || - opcode == Instruction::PACKED_SWITCH || - opcode == Instruction::SPARSE_SWITCH) { - stream->Skip( - RoundUp(current_code_item_start, kPayloadInstructionRequiredAlignment) - - current_code_item_start); - break; - } - } - } - - // Write preheader first. - stream->Write(reinterpret_cast<const uint8_t*>(preheader), preheader_bytes); - // Registered offset is after the preheader. - ProcessOffset(stream, code_item); - // Avoid using sizeof so that we don't write the fake instruction array at the end of the code - // item. - stream->Write(&disk_code_item, OFFSETOF_MEMBER(CompactDexFile::CodeItem, insns_)); - // Write the instructions. - stream->Write(code_item->Insns(), code_item->InsnsSize() * sizeof(uint16_t)); - // Write the post instruction data. - WriteCodeItemPostInstructionData(stream, code_item, reserve_only); -} - -void CompactDexWriter::WriteDebugInfoItem(Stream* stream, dex_ir::DebugInfoItem* debug_info) { - ScopedDataSectionItem data_item(stream, - debug_info, - SectionAlignment(DexFile::kDexTypeDebugInfoItem), - data_item_dedupe_); - ProcessOffset(stream, debug_info); - stream->Write(debug_info->GetDebugInfo(), debug_info->GetDebugInfoSize()); -} - - -CompactDexWriter::Deduper::Deduper(DexContainer::Section* section) - : dedupe_map_(/*__n=*/ 32, - HashedMemoryRange::HashEqual(section), - HashedMemoryRange::HashEqual(section)) {} - -uint32_t CompactDexWriter::Deduper::Dedupe(uint32_t data_start, - uint32_t data_end, - uint32_t item_offset) { - HashedMemoryRange range {data_start, data_end - data_start}; - auto existing = dedupe_map_.emplace(range, item_offset); - if (!existing.second) { - // Failed to insert means we deduped, return the existing item offset. - return existing.first->second; - } - return kDidNotDedupe; -} - -void CompactDexWriter::SortDebugInfosByMethodIndex() { - static constexpr InvokeType invoke_types[] = { - kDirect, - kVirtual - }; - std::map<const dex_ir::DebugInfoItem*, uint32_t> method_idx_map; - for (InvokeType invoke_type : invoke_types) { - for (auto& class_def : header_->ClassDefs()) { - // Skip classes that are not defined in this dex file. - dex_ir::ClassData* class_data = class_def->GetClassData(); - if (class_data == nullptr) { - continue; - } - for (auto& method : *(invoke_type == InvokeType::kDirect - ? class_data->DirectMethods() - : class_data->VirtualMethods())) { - const dex_ir::MethodId* method_id = method.GetMethodId(); - dex_ir::CodeItem* code_item = method.GetCodeItem(); - if (code_item != nullptr && code_item->DebugInfo() != nullptr) { - const dex_ir::DebugInfoItem* debug_item = code_item->DebugInfo(); - method_idx_map.insert(std::make_pair(debug_item, method_id->GetIndex())); - } - } - } - } - std::sort(header_->DebugInfoItems().begin(), - header_->DebugInfoItems().end(), - [&](const std::unique_ptr<dex_ir::DebugInfoItem>& a, - const std::unique_ptr<dex_ir::DebugInfoItem>& b) { - auto it_a = method_idx_map.find(a.get()); - auto it_b = method_idx_map.find(b.get()); - uint32_t idx_a = it_a != method_idx_map.end() ? it_a->second : 0u; - uint32_t idx_b = it_b != method_idx_map.end() ? it_b->second : 0u; - return idx_a < idx_b; - }); -} - -void CompactDexWriter::WriteHeader(Stream* stream) { - CompactDexFile::Header header; - CompactDexFile::WriteMagic(&header.magic_[0]); - CompactDexFile::WriteCurrentVersion(&header.magic_[0]); - header.checksum_ = header_->Checksum(); - header.signature_ = header_->Signature(); - header.file_size_ = header_->FileSize(); - // Since we are not necessarily outputting the same format as the input, avoid using the stored - // header size. - header.header_size_ = GetHeaderSize(); - header.endian_tag_ = header_->EndianTag(); - header.link_size_ = header_->LinkSize(); - header.link_off_ = header_->LinkOffset(); - header.map_off_ = header_->MapListOffset(); - header.string_ids_size_ = header_->StringIds().Size(); - header.string_ids_off_ = header_->StringIds().GetOffset(); - header.type_ids_size_ = header_->TypeIds().Size(); - header.type_ids_off_ = header_->TypeIds().GetOffset(); - header.proto_ids_size_ = header_->ProtoIds().Size(); - header.proto_ids_off_ = header_->ProtoIds().GetOffset(); - header.field_ids_size_ = header_->FieldIds().Size(); - header.field_ids_off_ = header_->FieldIds().GetOffset(); - header.method_ids_size_ = header_->MethodIds().Size(); - header.method_ids_off_ = header_->MethodIds().GetOffset(); - header.class_defs_size_ = header_->ClassDefs().Size(); - header.class_defs_off_ = header_->ClassDefs().GetOffset(); - header.data_size_ = header_->DataSize(); - header.data_off_ = header_->DataOffset(); - header.owned_data_begin_ = owned_data_begin_; - header.owned_data_end_ = owned_data_end_; - - // Compact dex specific flags. - header.debug_info_offsets_pos_ = debug_info_offsets_pos_; - header.debug_info_offsets_table_offset_ = debug_info_offsets_table_offset_; - header.debug_info_base_ = debug_info_base_; - header.feature_flags_ = 0u; - // In cases where apps are converted to cdex during install, maintain feature flags so that - // the verifier correctly verifies apps that aren't targetting default methods. - if (header_->SupportDefaultMethods()) { - header.feature_flags_ |= static_cast<uint32_t>(CompactDexFile::FeatureFlags::kDefaultMethods); - } - stream->Seek(0); - stream->Overwrite(reinterpret_cast<uint8_t*>(&header), sizeof(header)); -} - -size_t CompactDexWriter::GetHeaderSize() const { - return sizeof(CompactDexFile::Header); -} - -void CompactDexWriter::WriteStringData(Stream* stream, dex_ir::StringData* string_data) { - ScopedDataSectionItem data_item(stream, - string_data, - SectionAlignment(DexFile::kDexTypeStringDataItem), - data_item_dedupe_); - ProcessOffset(stream, string_data); - stream->WriteUleb128(CountModifiedUtf8Chars(string_data->Data())); - stream->Write(string_data->Data(), strlen(string_data->Data())); - // Skip null terminator (already zeroed out, no need to write). - stream->Skip(1); -} - -bool CompactDexWriter::CanGenerateCompactDex(std::string* error_msg) { - static constexpr InvokeType invoke_types[] = { - kDirect, - kVirtual - }; - std::vector<bool> saw_method_id(header_->MethodIds().Size(), false); - std::vector<dex_ir::CodeItem*> method_id_code_item(header_->MethodIds().Size(), nullptr); - std::vector<dex_ir::DebugInfoItem*> method_id_debug_info(header_->MethodIds().Size(), nullptr); - for (InvokeType invoke_type : invoke_types) { - for (auto& class_def : header_->ClassDefs()) { - // Skip classes that are not defined in this dex file. - dex_ir::ClassData* class_data = class_def->GetClassData(); - if (class_data == nullptr) { - continue; - } - for (auto& method : *(invoke_type == InvokeType::kDirect - ? class_data->DirectMethods() - : class_data->VirtualMethods())) { - const uint32_t idx = method.GetMethodId()->GetIndex(); - dex_ir::CodeItem* code_item = method.GetCodeItem(); - dex_ir:: DebugInfoItem* debug_info_item = nullptr; - if (code_item != nullptr) { - debug_info_item = code_item->DebugInfo(); - } - if (saw_method_id[idx]) { - if (method_id_code_item[idx] != code_item) { - *error_msg = android::base::StringPrintf("Conflicting code item for method id %u", - idx); - // Conflicting info, abort generation. - return false; - } - if (method_id_debug_info[idx] != debug_info_item) { - *error_msg = android::base::StringPrintf("Conflicting debug info for method id %u", - idx); - // Conflicting info, abort generation. - return false; - } - } - method_id_code_item[idx] = code_item; - method_id_debug_info[idx] = debug_info_item; - saw_method_id[idx] = true; - } - } - } - return true; -} - -bool CompactDexWriter::Write(DexContainer* output, std::string* error_msg) { - DCHECK(error_msg != nullptr); - CHECK(compute_offsets_); - CHECK(output->IsCompactDexContainer()); - - if (!CanGenerateCompactDex(error_msg)) { - return false; - } - - Container* const container = down_cast<Container*>(output); - // For now, use the same stream for both data and metadata. - Stream temp_main_stream(output->GetMainSection()); - CHECK_EQ(output->GetMainSection()->Size(), 0u); - Stream temp_data_stream(output->GetDataSection()); - Stream* main_stream = &temp_main_stream; - Stream* data_stream = &temp_data_stream; - - // We want offset 0 to be reserved for null, seek to the data section alignment or the end of the - // section. - data_stream->Seek(std::max( - static_cast<uint32_t>(output->GetDataSection()->Size()), - kDataSectionAlignment)); - data_item_dedupe_ = &container->data_item_dedupe_; - - // Starting offset is right after the header. - main_stream->Seek(GetHeaderSize()); - - // Based on: https://source.android.com/devices/tech/dalvik/dex-format - // Since the offsets may not be calculated already, the writing must be done in the correct order. - const uint32_t string_ids_offset = main_stream->Tell(); - WriteStringIds(main_stream, /*reserve_only=*/ true); - WriteTypeIds(main_stream); - const uint32_t proto_ids_offset = main_stream->Tell(); - WriteProtoIds(main_stream, /*reserve_only=*/ true); - WriteFieldIds(main_stream); - WriteMethodIds(main_stream); - const uint32_t class_defs_offset = main_stream->Tell(); - WriteClassDefs(main_stream, /*reserve_only=*/ true); - const uint32_t call_site_ids_offset = main_stream->Tell(); - WriteCallSiteIds(main_stream, /*reserve_only=*/ true); - WriteMethodHandles(main_stream); - - if (compute_offsets_) { - // Data section. - data_stream->AlignTo(kDataSectionAlignment); - } - owned_data_begin_ = data_stream->Tell(); - - // Write code item first to minimize the space required for encoded methods. - // For cdex, the code items don't depend on the debug info. - WriteCodeItems(data_stream, /*reserve_only=*/ false); - - // Sort the debug infos by method index order, this reduces size by ~0.1% by reducing the size of - // the debug info offset table. - SortDebugInfosByMethodIndex(); - WriteDebugInfoItems(data_stream); - - WriteEncodedArrays(data_stream); - WriteAnnotations(data_stream); - WriteAnnotationSets(data_stream); - WriteAnnotationSetRefs(data_stream); - WriteAnnotationsDirectories(data_stream); - WriteTypeLists(data_stream); - WriteClassDatas(data_stream); - WriteStringDatas(data_stream); - WriteHiddenapiClassData(data_stream); - - // Write delayed id sections that depend on data sections. - { - Stream::ScopedSeek seek(main_stream, string_ids_offset); - WriteStringIds(main_stream, /*reserve_only=*/ false); - } - { - Stream::ScopedSeek seek(main_stream, proto_ids_offset); - WriteProtoIds(main_stream, /*reserve_only=*/ false); - } - { - Stream::ScopedSeek seek(main_stream, class_defs_offset); - WriteClassDefs(main_stream, /*reserve_only=*/ false); - } - { - Stream::ScopedSeek seek(main_stream, call_site_ids_offset); - WriteCallSiteIds(main_stream, /*reserve_only=*/ false); - } - - // Write the map list. - if (compute_offsets_) { - data_stream->AlignTo(SectionAlignment(DexFile::kDexTypeMapList)); - header_->SetMapListOffset(data_stream->Tell()); - } else { - data_stream->Seek(header_->MapListOffset()); - } - - // Map items are included in the data section. - GenerateAndWriteMapItems(data_stream); - - // Write link data if it exists. - const std::vector<uint8_t>& link_data = header_->LinkData(); - if (link_data.size() > 0) { - CHECK_EQ(header_->LinkSize(), static_cast<uint32_t>(link_data.size())); - if (compute_offsets_) { - header_->SetLinkOffset(data_stream->Tell()); - } else { - data_stream->Seek(header_->LinkOffset()); - } - data_stream->Write(&link_data[0], link_data.size()); - } - - // Write debug info offset table last to make dex file verifier happy. - WriteDebugInfoOffsetTable(data_stream); - - data_stream->AlignTo(kDataSectionAlignment); - owned_data_end_ = data_stream->Tell(); - if (compute_offsets_) { - header_->SetDataSize(data_stream->Tell()); - if (header_->DataSize() != 0) { - // Offset must be zero when the size is zero. - main_stream->AlignTo(kDataSectionAlignment); - // For now, default to saying the data is right after the main stream. - header_->SetDataOffset(main_stream->Tell()); - } else { - header_->SetDataOffset(0u); - } - } - - // Write header last. - if (compute_offsets_) { - header_->SetFileSize(main_stream->Tell()); - } - WriteHeader(main_stream); - - // Trim sections to make sure they are sized properly. - output->GetMainSection()->Resize(header_->FileSize()); - output->GetDataSection()->Resize(data_stream->Tell()); - - if (dex_layout_->GetOptions().update_checksum_) { - // Compute the cdex section (also covers the used part of the data section). - header_->SetChecksum(CompactDexFile::CalculateChecksum(output->GetMainSection()->Begin(), - output->GetMainSection()->Size(), - output->GetDataSection()->Begin(), - output->GetDataSection()->Size())); - // Rewrite the header with the calculated checksum. - WriteHeader(main_stream); - } - - return true; -} - -std::unique_ptr<DexContainer> CompactDexWriter::CreateDexContainer() const { - return std::unique_ptr<DexContainer>(new CompactDexWriter::Container()); -} - -} // namespace art diff --git a/dexlayout/compact_dex_writer.h b/dexlayout/compact_dex_writer.h deleted file mode 100644 index d7a3f8411b..0000000000 --- a/dexlayout/compact_dex_writer.h +++ /dev/null @@ -1,179 +0,0 @@ -/* - * Copyright (C) 2017 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_COMPACT_DEX_WRITER_H_ -#define ART_DEXLAYOUT_COMPACT_DEX_WRITER_H_ - -#include <memory> // For unique_ptr -#include <unordered_map> - -#include "base/data_hash.h" -#include "dex_writer.h" - -namespace art { - -// Compact dex writer for a single dex. -class CompactDexWriter : public DexWriter { - public: - explicit CompactDexWriter(DexLayout* dex_layout); - - protected: - class Deduper { - public: - static const uint32_t kDidNotDedupe = 0; - - explicit Deduper(DexContainer::Section* section); - - // Deduplicate a blob of data that has been written to mem_map. - // Returns the offset of the deduplicated data or kDidNotDedupe did deduplication did not occur. - uint32_t Dedupe(uint32_t data_start, uint32_t data_end, uint32_t item_offset); - - // Clear dedupe state to prevent deduplication against existing items in the future. - void Clear() { - dedupe_map_.clear(); - } - - private: - class HashedMemoryRange { - public: - uint32_t offset_; - uint32_t length_; - - class HashEqual { - public: - explicit HashEqual(DexContainer::Section* section) : section_(section) {} - - // Equal function. - bool operator()(const HashedMemoryRange& a, const HashedMemoryRange& b) const { - if (a.length_ != b.length_) { - return false; - } - const uint8_t* data = Data(); - DCHECK_LE(a.offset_ + a.length_, section_->Size()); - DCHECK_LE(b.offset_ + b.length_, section_->Size()); - return std::equal(data + a.offset_, data + a.offset_ + a.length_, data + b.offset_); - } - - // Hash function. - size_t operator()(const HashedMemoryRange& range) const { - DCHECK_LE(range.offset_ + range.length_, section_->Size()); - return DataHash::HashBytes(Data() + range.offset_, range.length_); - } - - ALWAYS_INLINE uint8_t* Data() const { - return section_->Begin(); - } - - private: - DexContainer::Section* const section_; - }; - }; - - // Dedupe map. - std::unordered_map<HashedMemoryRange, - uint32_t, - HashedMemoryRange::HashEqual, - HashedMemoryRange::HashEqual> dedupe_map_; - }; - - // Handles alignment and deduping of a data section item. - class ScopedDataSectionItem { - public: - ScopedDataSectionItem(Stream* stream, dex_ir::Item* item, size_t alignment, Deduper* deduper); - ~ScopedDataSectionItem(); - size_t Written() const; - - private: - Stream* const stream_; - dex_ir::Item* const item_; - const size_t alignment_; - Deduper* deduper_; - const uint32_t start_offset_; - }; - - public: - class Container : public DexContainer { - public: - Section* GetMainSection() override { - return &main_section_; - } - - Section* GetDataSection() override { - return &data_section_; - } - - bool IsCompactDexContainer() const override { - return true; - } - - private: - Container(); - - VectorSection main_section_; - VectorSection data_section_; - Deduper data_item_dedupe_; - - friend class CompactDexWriter; - }; - - protected: - // Return true if we can generate compact dex for the IR. - bool CanGenerateCompactDex(std::string* error_msg); - - bool Write(DexContainer* output, std::string* error_msg) override; - - std::unique_ptr<DexContainer> CreateDexContainer() const override; - - void WriteHeader(Stream* stream) override; - - size_t GetHeaderSize() const override; - - uint32_t WriteDebugInfoOffsetTable(Stream* stream); - - void WriteCodeItem(Stream* stream, dex_ir::CodeItem* code_item, bool reserve_only) override; - - void WriteStringData(Stream* stream, dex_ir::StringData* string_data) override; - - void WriteDebugInfoItem(Stream* stream, dex_ir::DebugInfoItem* debug_info) override; - - void SortDebugInfosByMethodIndex(); - - CompactDexLevel GetCompactDexLevel() const; - - private: - // Position in the compact dex file for the debug info table data starts. - uint32_t debug_info_offsets_pos_ = 0u; - - // Offset into the debug info table data where the lookup table is. - uint32_t debug_info_offsets_table_offset_ = 0u; - - // Base offset of where debug info starts in the dex file. - uint32_t debug_info_base_ = 0u; - - // Part of the shared data section owned by this file. - uint32_t owned_data_begin_ = 0u; - uint32_t owned_data_end_ = 0u; - - Deduper* data_item_dedupe_ = nullptr; - - DISALLOW_COPY_AND_ASSIGN(CompactDexWriter); -}; - -} // namespace art - -#endif // ART_DEXLAYOUT_COMPACT_DEX_WRITER_H_ diff --git a/dexlayout/dex_container.h b/dexlayout/dex_container.h deleted file mode 100644 index 713de1b89b..0000000000 --- a/dexlayout/dex_container.h +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (C) 2018 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_CONTAINER_H_ -#define ART_DEXLAYOUT_DEX_CONTAINER_H_ - -#include <vector> - -namespace art { - -// Dex container holds the artifacts produced by dexlayout and contains up to two sections: a main -// section and a data section. -// This container may also hold metadata used for multi dex deduplication in the future. -class DexContainer { - public: - virtual ~DexContainer() {} - - class Section { - public: - virtual ~Section() {} - - // Returns the start of the memory region. - virtual uint8_t* Begin() = 0; - - // Size in bytes. - virtual size_t Size() const = 0; - - // Resize the backing storage. - virtual void Resize(size_t size) = 0; - - // Clear the container. - virtual void Clear() = 0; - - // Release the data, clearing the container contents. - virtual std::vector<uint8_t> ReleaseData() = 0; - - // Returns the end of the memory region. - uint8_t* End() { - return Begin() + Size(); - } - }; - - // Vector backed section. - class VectorSection : public Section { - public: - virtual ~VectorSection() {} - - uint8_t* Begin() override { - return &data_[0]; - } - - size_t Size() const override { - return data_.size(); - } - - void Resize(size_t size) override { - data_.resize(size, 0u); - } - - void Clear() override { - data_.clear(); - } - - std::vector<uint8_t> ReleaseData() override { - std::vector<uint8_t> temp; - temp.swap(data_); - return temp; - } - - private: - std::vector<uint8_t> data_; - }; - - virtual Section* GetMainSection() = 0; - virtual Section* GetDataSection() = 0; - virtual bool IsCompactDexContainer() const = 0; -}; - -} // namespace art - -#endif // ART_DEXLAYOUT_DEX_CONTAINER_H_ diff --git a/dexlayout/dex_ir.cc b/dexlayout/dex_ir.cc deleted file mode 100644 index 82c03890fa..0000000000 --- a/dexlayout/dex_ir.cc +++ /dev/null @@ -1,174 +0,0 @@ -/* - * 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. - * - * Implementation file of the dexlayout utility. - * - * This is a tool to read dex files into an internal representation, - * reorganize the representation, and emit dex files with a better - * file layout. - */ - -#include "dex_ir.h" - -#include "dex/code_item_accessors-inl.h" -#include "dex/dex_file_exception_helpers.h" -#include "dex/dex_instruction-inl.h" -#include "dex_ir_builder.h" - -namespace art { -namespace dex_ir { - -static uint32_t HeaderOffset([[maybe_unused]] const dex_ir::Header* header) { return 0; } - -static uint32_t HeaderSize([[maybe_unused]] const dex_ir::Header* header) { - // Size is in elements, so there is only one header. - return 1; -} - -// The description of each dex file section type. -struct FileSectionDescriptor { - public: - std::string name; - uint16_t type; - // A function that when applied to a collection object, gives the size of the section. - std::function<uint32_t(dex_ir::Header*)> size_fn; - // A function that when applied to a collection object, gives the offset of the section. - std::function<uint32_t(dex_ir::Header*)> offset_fn; -}; - -static const FileSectionDescriptor kFileSectionDescriptors[] = { - { - "Header", - DexFile::kDexTypeHeaderItem, - &HeaderSize, - &HeaderOffset, - }, { - "StringId", - DexFile::kDexTypeStringIdItem, - [](const dex_ir::Header* h) { return h->StringIds().Size(); }, - [](const dex_ir::Header* h) { return h->StringIds().GetOffset(); } - }, { - "TypeId", - DexFile::kDexTypeTypeIdItem, - [](const dex_ir::Header* h) { return h->TypeIds().Size(); }, - [](const dex_ir::Header* h) { return h->TypeIds().GetOffset(); } - }, { - "ProtoId", - DexFile::kDexTypeProtoIdItem, - [](const dex_ir::Header* h) { return h->ProtoIds().Size(); }, - [](const dex_ir::Header* h) { return h->ProtoIds().GetOffset(); } - }, { - "FieldId", - DexFile::kDexTypeFieldIdItem, - [](const dex_ir::Header* h) { return h->FieldIds().Size(); }, - [](const dex_ir::Header* h) { return h->FieldIds().GetOffset(); } - }, { - "MethodId", - DexFile::kDexTypeMethodIdItem, - [](const dex_ir::Header* h) { return h->MethodIds().Size(); }, - [](const dex_ir::Header* h) { return h->MethodIds().GetOffset(); } - }, { - "ClassDef", - DexFile::kDexTypeClassDefItem, - [](const dex_ir::Header* h) { return h->ClassDefs().Size(); }, - [](const dex_ir::Header* h) { return h->ClassDefs().GetOffset(); } - }, { - "CallSiteId", - DexFile::kDexTypeCallSiteIdItem, - [](const dex_ir::Header* h) { return h->CallSiteIds().Size(); }, - [](const dex_ir::Header* h) { return h->CallSiteIds().GetOffset(); } - }, { - "MethodHandle", - DexFile::kDexTypeMethodHandleItem, - [](const dex_ir::Header* h) { return h->MethodHandleItems().Size(); }, - [](const dex_ir::Header* h) { return h->MethodHandleItems().GetOffset(); } - }, { - "StringData", - DexFile::kDexTypeStringDataItem, - [](const dex_ir::Header* h) { return h->StringDatas().Size(); }, - [](const dex_ir::Header* h) { return h->StringDatas().GetOffset(); } - }, { - "TypeList", - DexFile::kDexTypeTypeList, - [](const dex_ir::Header* h) { return h->TypeLists().Size(); }, - [](const dex_ir::Header* h) { return h->TypeLists().GetOffset(); } - }, { - "EncArr", - DexFile::kDexTypeEncodedArrayItem, - [](const dex_ir::Header* h) { return h->EncodedArrayItems().Size(); }, - [](const dex_ir::Header* h) { return h->EncodedArrayItems().GetOffset(); } - }, { - "Annotation", - DexFile::kDexTypeAnnotationItem, - [](const dex_ir::Header* h) { return h->AnnotationItems().Size(); }, - [](const dex_ir::Header* h) { return h->AnnotationItems().GetOffset(); } - }, { - "AnnoSet", - DexFile::kDexTypeAnnotationSetItem, - [](const dex_ir::Header* h) { return h->AnnotationSetItems().Size(); }, - [](const dex_ir::Header* h) { return h->AnnotationSetItems().GetOffset(); } - }, { - "AnnoSetRL", - DexFile::kDexTypeAnnotationSetRefList, - [](const dex_ir::Header* h) { return h->AnnotationSetRefLists().Size(); }, - [](const dex_ir::Header* h) { return h->AnnotationSetRefLists().GetOffset(); } - }, { - "AnnoDir", - DexFile::kDexTypeAnnotationsDirectoryItem, - [](const dex_ir::Header* h) { return h->AnnotationsDirectoryItems().Size(); }, - [](const dex_ir::Header* h) { return h->AnnotationsDirectoryItems().GetOffset(); } - }, { - "DebugInfo", - DexFile::kDexTypeDebugInfoItem, - [](const dex_ir::Header* h) { return h->DebugInfoItems().Size(); }, - [](const dex_ir::Header* h) { return h->DebugInfoItems().GetOffset(); } - }, { - "CodeItem", - DexFile::kDexTypeCodeItem, - [](const dex_ir::Header* h) { return h->CodeItems().Size(); }, - [](const dex_ir::Header* h) { return h->CodeItems().GetOffset(); } - }, { - "ClassData", - DexFile::kDexTypeClassDataItem, - [](const dex_ir::Header* h) { return h->ClassDatas().Size(); }, - [](const dex_ir::Header* h) { return h->ClassDatas().GetOffset(); } - } -}; - -std::vector<dex_ir::DexFileSection> GetSortedDexFileSections(dex_ir::Header* header, - dex_ir::SortDirection direction) { - std::vector<dex_ir::DexFileSection> sorted_sections; - // Build the table that will map from offset to color - for (const FileSectionDescriptor& s : kFileSectionDescriptors) { - sorted_sections.push_back(dex_ir::DexFileSection(s.name, - s.type, - s.size_fn(header), - s.offset_fn(header))); - } - // Sort by offset. - std::sort(sorted_sections.begin(), - sorted_sections.end(), - [=](dex_ir::DexFileSection& a, dex_ir::DexFileSection& b) { - if (direction == SortDirection::kSortDescending) { - return a.offset > b.offset; - } else { - return a.offset < b.offset; - } - }); - return sorted_sections; -} - -} // namespace dex_ir -} // namespace art diff --git a/dexlayout/dex_ir.h b/dexlayout/dex_ir.h deleted file mode 100644 index 229e948c12..0000000000 --- a/dexlayout/dex_ir.h +++ /dev/null @@ -1,1369 +0,0 @@ -/* - * 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_IR_H_ -#define ART_DEXLAYOUT_DEX_IR_H_ - -#include <stdint.h> -#include <unordered_map> -#include <vector> - -#include "base/iteration_range.h" -#include "base/leb128.h" -#include "base/safe_map.h" -#include "base/stl_util.h" -#include "dex/dex_file-inl.h" -#include "dex/dex_file_types.h" -#include "dex/utf.h" - -namespace art { -namespace dex_ir { - -// Forward declarations for classes used in containers or pointed to. -class AnnotationItem; -class AnnotationsDirectoryItem; -class AnnotationSetItem; -class AnnotationSetRefList; -class CallSiteId; -class ClassData; -class ClassDef; -class CodeItem; -class DebugInfoItem; -class EncodedAnnotation; -class EncodedArrayItem; -class EncodedValue; -class FieldId; -class FieldItem; -class Header; -class HiddenapiClassData; -class MapList; -class MapItem; -class MethodHandleItem; -class MethodId; -class MethodItem; -class ParameterAnnotation; -class ProtoId; -class StringData; -class StringId; -class TryItem; -class TypeId; -class TypeList; - -// Item size constants. -static constexpr size_t kHeaderItemSize = 112; -static constexpr size_t kStringIdItemSize = 4; -static constexpr size_t kTypeIdItemSize = 4; -static constexpr size_t kProtoIdItemSize = 12; -static constexpr size_t kFieldIdItemSize = 8; -static constexpr size_t kMethodIdItemSize = 8; -static constexpr size_t kClassDefItemSize = 32; -static constexpr size_t kCallSiteIdItemSize = 4; -static constexpr size_t kMethodHandleItemSize = 8; - -// Visitor support -class AbstractDispatcher { - public: - AbstractDispatcher() = default; - virtual ~AbstractDispatcher() { } - - virtual void Dispatch(Header* header) = 0; - virtual void Dispatch(const StringData* string_data) = 0; - virtual void Dispatch(const StringId* string_id) = 0; - virtual void Dispatch(const TypeId* type_id) = 0; - virtual void Dispatch(const ProtoId* proto_id) = 0; - virtual void Dispatch(const FieldId* field_id) = 0; - virtual void Dispatch(const MethodId* method_id) = 0; - virtual void Dispatch(const CallSiteId* call_site_id) = 0; - virtual void Dispatch(const MethodHandleItem* method_handle_item) = 0; - virtual void Dispatch(ClassData* class_data) = 0; - virtual void Dispatch(ClassDef* class_def) = 0; - virtual void Dispatch(FieldItem* field_item) = 0; - virtual void Dispatch(MethodItem* method_item) = 0; - virtual void Dispatch(EncodedArrayItem* array_item) = 0; - virtual void Dispatch(CodeItem* code_item) = 0; - virtual void Dispatch(TryItem* try_item) = 0; - virtual void Dispatch(DebugInfoItem* debug_info_item) = 0; - virtual void Dispatch(AnnotationItem* annotation_item) = 0; - virtual void Dispatch(AnnotationSetItem* annotation_set_item) = 0; - virtual void Dispatch(AnnotationSetRefList* annotation_set_ref_list) = 0; - virtual void Dispatch(AnnotationsDirectoryItem* annotations_directory_item) = 0; - virtual void Dispatch(HiddenapiClassData* hiddenapi_class_data) = 0; - virtual void Dispatch(MapList* map_list) = 0; - virtual void Dispatch(MapItem* map_item) = 0; - - private: - DISALLOW_COPY_AND_ASSIGN(AbstractDispatcher); -}; - -template <class T> -class Iterator { - public: - using iterator_category = std::random_access_iterator_tag; - using value_type = T; - using difference_type = ptrdiff_t; - using pointer = value_type*; - using reference = value_type&; - - Iterator(const Iterator&) = default; - Iterator(Iterator&&) noexcept = default; - Iterator& operator=(const Iterator&) = default; - Iterator& operator=(Iterator&&) noexcept = default; - - Iterator(const std::vector<T>& vector, - uint32_t position, - uint32_t iterator_end) - : vector_(&vector), - position_(position), - iterator_end_(iterator_end) { } - Iterator() : vector_(nullptr), position_(0U), iterator_end_(0U) { } - - bool IsValid() const { return position_ < iterator_end_; } - - bool operator==(const Iterator& rhs) const { return position_ == rhs.position_; } - bool operator!=(const Iterator& rhs) const { return !(*this == rhs); } - bool operator<(const Iterator& rhs) const { return position_ < rhs.position_; } - bool operator>(const Iterator& rhs) const { return rhs < *this; } - bool operator<=(const Iterator& rhs) const { return !(rhs < *this); } - bool operator>=(const Iterator& rhs) const { return !(*this < rhs); } - - Iterator& operator++() { // Value after modification. - ++position_; - return *this; - } - - Iterator operator++(int) { - Iterator temp = *this; - ++position_; - return temp; - } - - Iterator& operator+=(difference_type delta) { - position_ += delta; - return *this; - } - - Iterator operator+(difference_type delta) const { - Iterator temp = *this; - temp += delta; - return temp; - } - - Iterator& operator--() { // Value after modification. - --position_; - return *this; - } - - Iterator operator--(int) { - Iterator temp = *this; - --position_; - return temp; - } - - Iterator& operator-=(difference_type delta) { - position_ -= delta; - return *this; - } - - Iterator operator-(difference_type delta) const { - Iterator temp = *this; - temp -= delta; - return temp; - } - - difference_type operator-(const Iterator& rhs) { - return position_ - rhs.position_; - } - - reference operator*() const { - return const_cast<reference>((*vector_)[position_]); - } - - pointer operator->() const { - return const_cast<pointer>(&((*vector_)[position_])); - } - - reference operator[](difference_type n) const { - return (*vector_)[position_ + n]; - } - - private: - const std::vector<T>* vector_; - uint32_t position_; - uint32_t iterator_end_; - - template <typename U> - friend bool operator<(const Iterator<U>& lhs, const Iterator<U>& rhs); -}; - -// Collections become owners of the objects added by moving them into unique pointers. -class CollectionBase { - public: - CollectionBase() = default; - virtual ~CollectionBase() { } - - uint32_t GetOffset() const { return offset_; } - void SetOffset(uint32_t new_offset) { offset_ = new_offset; } - virtual uint32_t Size() const = 0; - bool Empty() const { return Size() == 0u; } - - private: - // Start out unassigned. - uint32_t offset_ = 0u; - - DISALLOW_COPY_AND_ASSIGN(CollectionBase); -}; - -template<class T> class CollectionVector : public CollectionBase { - public: - using ElementType = std::unique_ptr<T>; - - CollectionVector() { } - explicit CollectionVector(size_t size) { - // Preallocate so that assignment does not invalidate pointers into the vector. - collection_.reserve(size); - } - ~CollectionVector() override { } - - template<class... Args> - T* CreateAndAddItem(Args&&... args) { - T* object = new T(std::forward<Args>(args)...); - collection_.push_back(std::unique_ptr<T>(object)); - return object; - } - - uint32_t Size() const override { return collection_.size(); } - - Iterator<ElementType> begin() const { return Iterator<ElementType>(collection_, 0U, Size()); } - Iterator<ElementType> end() const { return Iterator<ElementType>(collection_, Size(), Size()); } - - const ElementType& operator[](size_t index) const { - DCHECK_LT(index, Size()); - return collection_[index]; - } - ElementType& operator[](size_t index) { - DCHECK_LT(index, Size()); - return collection_[index]; - } - - // Sort the vector by copying pointers over. - template <typename MapType> - void SortByMapOrder(const MapType& map) { - CHECK_EQ(map.size(), Size()); - - // Move all pointers to a temporary map owning the pointers. - std::unordered_map<T*, ElementType> pointers_map; - pointers_map.reserve(Size()); - for (std::unique_ptr<T>& element : collection_) { - pointers_map[element.get()] = std::move(element); - } - - // Move back the pointers to the original vector according to the map order. - auto it = map.begin(); - for (size_t i = 0; i < Size(); ++i) { - auto element_it = pointers_map.find(it->second); - DCHECK(element_it != pointers_map.end()); - collection_[i] = std::move(element_it->second); - ++it; - } - } - - protected: - std::vector<ElementType> collection_; - - private: - DISALLOW_COPY_AND_ASSIGN(CollectionVector); -}; - -template<class T> class IndexedCollectionVector : public CollectionVector<T> { - public: - using Vector = std::vector<std::unique_ptr<T>>; - IndexedCollectionVector() = default; - explicit IndexedCollectionVector(size_t size) : CollectionVector<T>(size) { } - - template <class... Args> - T* CreateAndAddIndexedItem(uint32_t index, Args&&... args) { - T* object = CollectionVector<T>::CreateAndAddItem(std::forward<Args>(args)...); - object->SetIndex(index); - return object; - } - - T* operator[](size_t index) const { - DCHECK_NE(CollectionVector<T>::collection_[index].get(), static_cast<T*>(nullptr)); - return CollectionVector<T>::collection_[index].get(); - } - - private: - DISALLOW_COPY_AND_ASSIGN(IndexedCollectionVector); -}; - -class Item { - public: - Item() { } - virtual ~Item() { } - - Item(Item&&) = default; - - // Return the assigned offset. - uint32_t GetOffset() const WARN_UNUSED { - CHECK(OffsetAssigned()); - return offset_; - } - uint32_t GetSize() const WARN_UNUSED { return size_; } - void SetOffset(uint32_t offset) { offset_ = offset; } - void SetSize(uint32_t size) { size_ = size; } - bool OffsetAssigned() const { - return offset_ != kOffsetUnassigned; - } - - protected: - Item(uint32_t offset, uint32_t size) : offset_(offset), size_(size) { } - - // 0 is the dex file header and shouldn't be a valid offset for any part of the dex file. - static constexpr uint32_t kOffsetUnassigned = 0u; - - // Start out unassigned. - uint32_t offset_ = kOffsetUnassigned; - uint32_t size_ = 0; -}; - -class IndexedItem : public Item { - public: - IndexedItem() { } - virtual ~IndexedItem() { } - - uint32_t GetIndex() const { return index_; } - void SetIndex(uint32_t index) { index_ = index; } - - protected: - IndexedItem(uint32_t offset, uint32_t size, uint32_t index) - : Item(offset, size), index_(index) { } - - uint32_t index_ = 0; -}; - -class Header : public Item { - public: - Header(DexFile::Magic magic, - uint32_t checksum, - DexFile::Sha1 signature, - uint32_t endian_tag, - uint32_t file_size, - uint32_t header_size, - uint32_t link_size, - uint32_t link_offset, - uint32_t data_size, - uint32_t data_offset, - bool support_default_methods) - : Item(0, kHeaderItemSize), support_default_methods_(support_default_methods) { - ConstructorHelper(magic, - checksum, - signature, - endian_tag, - file_size, - header_size, - link_size, - link_offset, - data_size, - data_offset); - } - - Header(DexFile::Magic magic, - uint32_t checksum, - DexFile::Sha1 signature, - uint32_t endian_tag, - uint32_t file_size, - uint32_t header_size, - uint32_t link_size, - uint32_t link_offset, - uint32_t data_size, - uint32_t data_offset, - bool support_default_methods, - uint32_t num_string_ids, - uint32_t num_type_ids, - uint32_t num_proto_ids, - uint32_t num_field_ids, - uint32_t num_method_ids, - uint32_t num_class_defs) - : Item(0, kHeaderItemSize), - support_default_methods_(support_default_methods), - string_ids_(num_string_ids), - type_ids_(num_type_ids), - proto_ids_(num_proto_ids), - field_ids_(num_field_ids), - method_ids_(num_method_ids), - class_defs_(num_class_defs) { - ConstructorHelper(magic, - checksum, - signature, - endian_tag, - file_size, - header_size, - link_size, - link_offset, - data_size, - data_offset); - } - ~Header() override { } - - static size_t ItemSize() { return kHeaderItemSize; } - - DexFile::Magic Magic() const { return magic_; } - uint32_t Checksum() const { return checksum_; } - DexFile::Sha1 Signature() const { return signature_; } - uint32_t EndianTag() const { return endian_tag_; } - uint32_t FileSize() const { return file_size_; } - uint32_t HeaderSize() const { return header_size_; } - uint32_t LinkSize() const { return link_size_; } - uint32_t LinkOffset() const { return link_offset_; } - uint32_t DataSize() const { return data_size_; } - uint32_t DataOffset() const { return data_offset_; } - - void SetChecksum(uint32_t new_checksum) { checksum_ = new_checksum; } - void SetSignature(DexFile::Sha1 new_signature) { signature_ = new_signature; } - void SetFileSize(uint32_t new_file_size) { file_size_ = new_file_size; } - void SetHeaderSize(uint32_t new_header_size) { header_size_ = new_header_size; } - void SetLinkSize(uint32_t new_link_size) { link_size_ = new_link_size; } - void SetLinkOffset(uint32_t new_link_offset) { link_offset_ = new_link_offset; } - void SetDataSize(uint32_t new_data_size) { data_size_ = new_data_size; } - void SetDataOffset(uint32_t new_data_offset) { data_offset_ = new_data_offset; } - - IndexedCollectionVector<StringId>& StringIds() { return string_ids_; } - const IndexedCollectionVector<StringId>& StringIds() const { return string_ids_; } - IndexedCollectionVector<TypeId>& TypeIds() { return type_ids_; } - const IndexedCollectionVector<TypeId>& TypeIds() const { return type_ids_; } - IndexedCollectionVector<ProtoId>& ProtoIds() { return proto_ids_; } - const IndexedCollectionVector<ProtoId>& ProtoIds() const { return proto_ids_; } - IndexedCollectionVector<FieldId>& FieldIds() { return field_ids_; } - const IndexedCollectionVector<FieldId>& FieldIds() const { return field_ids_; } - IndexedCollectionVector<MethodId>& MethodIds() { return method_ids_; } - const IndexedCollectionVector<MethodId>& MethodIds() const { return method_ids_; } - IndexedCollectionVector<ClassDef>& ClassDefs() { return class_defs_; } - const IndexedCollectionVector<ClassDef>& ClassDefs() const { return class_defs_; } - IndexedCollectionVector<CallSiteId>& CallSiteIds() { return call_site_ids_; } - const IndexedCollectionVector<CallSiteId>& CallSiteIds() const { return call_site_ids_; } - IndexedCollectionVector<MethodHandleItem>& MethodHandleItems() { return method_handle_items_; } - const IndexedCollectionVector<MethodHandleItem>& MethodHandleItems() const { - return method_handle_items_; - } - CollectionVector<StringData>& StringDatas() { return string_datas_; } - const CollectionVector<StringData>& StringDatas() const { return string_datas_; } - CollectionVector<TypeList>& TypeLists() { return type_lists_; } - const CollectionVector<TypeList>& TypeLists() const { return type_lists_; } - CollectionVector<EncodedArrayItem>& EncodedArrayItems() { return encoded_array_items_; } - const CollectionVector<EncodedArrayItem>& EncodedArrayItems() const { - return encoded_array_items_; - } - CollectionVector<AnnotationItem>& AnnotationItems() { return annotation_items_; } - const CollectionVector<AnnotationItem>& AnnotationItems() const { return annotation_items_; } - CollectionVector<AnnotationSetItem>& AnnotationSetItems() { return annotation_set_items_; } - const CollectionVector<AnnotationSetItem>& AnnotationSetItems() const { - return annotation_set_items_; - } - CollectionVector<AnnotationSetRefList>& AnnotationSetRefLists() { - return annotation_set_ref_lists_; - } - const CollectionVector<AnnotationSetRefList>& AnnotationSetRefLists() const { - return annotation_set_ref_lists_; - } - CollectionVector<AnnotationsDirectoryItem>& AnnotationsDirectoryItems() { - return annotations_directory_items_; - } - const CollectionVector<AnnotationsDirectoryItem>& AnnotationsDirectoryItems() const { - return annotations_directory_items_; - } - IndexedCollectionVector<HiddenapiClassData>& HiddenapiClassDatas() { - return hiddenapi_class_datas_; - } - const IndexedCollectionVector<HiddenapiClassData>& HiddenapiClassDatas() const { - return hiddenapi_class_datas_; - } - CollectionVector<DebugInfoItem>& DebugInfoItems() { return debug_info_items_; } - const CollectionVector<DebugInfoItem>& DebugInfoItems() const { return debug_info_items_; } - CollectionVector<CodeItem>& CodeItems() { return code_items_; } - const CollectionVector<CodeItem>& CodeItems() const { return code_items_; } - CollectionVector<ClassData>& ClassDatas() { return class_datas_; } - const CollectionVector<ClassData>& ClassDatas() const { return class_datas_; } - - StringId* GetStringIdOrNullPtr(uint32_t index) { - return index == dex::kDexNoIndex ? nullptr : StringIds()[index]; - } - TypeId* GetTypeIdOrNullPtr(uint16_t index) { - return index == DexFile::kDexNoIndex16 ? nullptr : TypeIds()[index]; - } - - uint32_t MapListOffset() const { return map_list_offset_; } - void SetMapListOffset(uint32_t new_offset) { map_list_offset_ = new_offset; } - - const std::vector<uint8_t>& LinkData() const { return link_data_; } - void SetLinkData(std::vector<uint8_t>&& link_data) { link_data_ = std::move(link_data); } - - void Accept(AbstractDispatcher* dispatch) { dispatch->Dispatch(this); } - - bool SupportDefaultMethods() const { - return support_default_methods_; - } - - private: - DexFile::Magic magic_; - uint32_t checksum_; - DexFile::Sha1 signature_; - uint32_t endian_tag_; - uint32_t file_size_; - uint32_t header_size_; - uint32_t link_size_; - uint32_t link_offset_; - uint32_t data_size_; - uint32_t data_offset_; - const bool support_default_methods_; - - void ConstructorHelper(DexFile::Magic magic, - uint32_t checksum, - DexFile::Sha1 signature, - uint32_t endian_tag, - uint32_t file_size, - uint32_t header_size, - uint32_t link_size, - uint32_t link_offset, - uint32_t data_size, - uint32_t data_offset) { - checksum_ = checksum; - endian_tag_ = endian_tag; - file_size_ = file_size; - header_size_ = header_size; - link_size_ = link_size; - link_offset_ = link_offset; - data_size_ = data_size; - data_offset_ = data_offset; - magic_ = magic; - signature_ = signature; - } - - // Collection vectors own the IR data. - IndexedCollectionVector<StringId> string_ids_; - IndexedCollectionVector<TypeId> type_ids_; - IndexedCollectionVector<ProtoId> proto_ids_; - IndexedCollectionVector<FieldId> field_ids_; - IndexedCollectionVector<MethodId> method_ids_; - IndexedCollectionVector<ClassDef> class_defs_; - IndexedCollectionVector<CallSiteId> call_site_ids_; - IndexedCollectionVector<MethodHandleItem> method_handle_items_; - IndexedCollectionVector<StringData> string_datas_; - IndexedCollectionVector<TypeList> type_lists_; - IndexedCollectionVector<EncodedArrayItem> encoded_array_items_; - IndexedCollectionVector<AnnotationItem> annotation_items_; - IndexedCollectionVector<AnnotationSetItem> annotation_set_items_; - IndexedCollectionVector<AnnotationSetRefList> annotation_set_ref_lists_; - IndexedCollectionVector<AnnotationsDirectoryItem> annotations_directory_items_; - IndexedCollectionVector<HiddenapiClassData> hiddenapi_class_datas_; - // The order of the vectors controls the layout of the output file by index order, to change the - // layout just sort the vector. Note that you may only change the order of the non indexed vectors - // below. Indexed vectors are accessed by indices in other places, changing the sorting order will - // invalidate the existing indices and is not currently supported. - CollectionVector<DebugInfoItem> debug_info_items_; - CollectionVector<CodeItem> code_items_; - CollectionVector<ClassData> class_datas_; - - uint32_t map_list_offset_ = 0; - - // Link data. - std::vector<uint8_t> link_data_; - - DISALLOW_COPY_AND_ASSIGN(Header); -}; - -class StringData : public Item { - public: - explicit StringData(const char* data) : data_(strdup(data)) { - size_ = UnsignedLeb128Size(CountModifiedUtf8Chars(data)) + strlen(data); - } - - const char* Data() const { return data_.get(); } - - void Accept(AbstractDispatcher* dispatch) const { dispatch->Dispatch(this); } - - private: - UniqueCPtr<const char> data_; - - DISALLOW_COPY_AND_ASSIGN(StringData); -}; - -class StringId : public IndexedItem { - public: - explicit StringId(StringData* string_data) : string_data_(string_data) { - size_ = kStringIdItemSize; - } - ~StringId() override { } - - static size_t ItemSize() { return kStringIdItemSize; } - - const char* Data() const { return string_data_->Data(); } - StringData* DataItem() const { return string_data_; } - - void Accept(AbstractDispatcher* dispatch) const { dispatch->Dispatch(this); } - - private: - StringData* string_data_; - - DISALLOW_COPY_AND_ASSIGN(StringId); -}; - -class TypeId : public IndexedItem { - public: - explicit TypeId(StringId* string_id) : string_id_(string_id) { size_ = kTypeIdItemSize; } - ~TypeId() override { } - - static size_t ItemSize() { return kTypeIdItemSize; } - - StringId* GetStringId() const { return string_id_; } - - void Accept(AbstractDispatcher* dispatch) const { dispatch->Dispatch(this); } - - private: - StringId* string_id_; - - DISALLOW_COPY_AND_ASSIGN(TypeId); -}; - -using TypeIdVector = std::vector<const TypeId*>; - -class TypeList : public Item { - public: - explicit TypeList(TypeIdVector* type_list) : type_list_(type_list) { - size_ = sizeof(uint32_t) + (type_list->size() * sizeof(uint16_t)); - } - ~TypeList() override { } - - const TypeIdVector* GetTypeList() const { return type_list_.get(); } - - private: - std::unique_ptr<TypeIdVector> type_list_; - - DISALLOW_COPY_AND_ASSIGN(TypeList); -}; - -class ProtoId : public IndexedItem { - public: - ProtoId(const StringId* shorty, const TypeId* return_type, TypeList* parameters) - : shorty_(shorty), return_type_(return_type), parameters_(parameters) - { size_ = kProtoIdItemSize; } - ~ProtoId() override { } - - static size_t ItemSize() { return kProtoIdItemSize; } - - const StringId* Shorty() const { return shorty_; } - const TypeId* ReturnType() const { return return_type_; } - const TypeList* Parameters() const { return parameters_; } - - void Accept(AbstractDispatcher* dispatch) const { dispatch->Dispatch(this); } - - private: - const StringId* shorty_; - const TypeId* return_type_; - TypeList* parameters_; // This can be nullptr. - - DISALLOW_COPY_AND_ASSIGN(ProtoId); -}; - -class FieldId : public IndexedItem { - public: - FieldId(const TypeId* klass, const TypeId* type, const StringId* name) - : class_(klass), type_(type), name_(name) { size_ = kFieldIdItemSize; } - ~FieldId() override { } - - static size_t ItemSize() { return kFieldIdItemSize; } - - const TypeId* Class() const { return class_; } - const TypeId* Type() const { return type_; } - const StringId* Name() const { return name_; } - - void Accept(AbstractDispatcher* dispatch) const { dispatch->Dispatch(this); } - - private: - const TypeId* class_; - const TypeId* type_; - const StringId* name_; - - DISALLOW_COPY_AND_ASSIGN(FieldId); -}; - -class MethodId : public IndexedItem { - public: - MethodId(const TypeId* klass, const ProtoId* proto, const StringId* name) - : class_(klass), proto_(proto), name_(name) { size_ = kMethodIdItemSize; } - ~MethodId() override { } - - static size_t ItemSize() { return kMethodIdItemSize; } - - const TypeId* Class() const { return class_; } - const ProtoId* Proto() const { return proto_; } - const StringId* Name() const { return name_; } - - void Accept(AbstractDispatcher* dispatch) const { dispatch->Dispatch(this); } - - private: - const TypeId* class_; - const ProtoId* proto_; - const StringId* name_; - - DISALLOW_COPY_AND_ASSIGN(MethodId); -}; - -class FieldItem : public Item { - public: - FieldItem(uint32_t access_flags, const FieldId* field_id) - : access_flags_(access_flags), field_id_(field_id) { } - ~FieldItem() override { } - - FieldItem(FieldItem&&) = default; - - uint32_t GetAccessFlags() const { return access_flags_; } - const FieldId* GetFieldId() const { return field_id_; } - - void Accept(AbstractDispatcher* dispatch) { dispatch->Dispatch(this); } - - private: - uint32_t access_flags_; - const FieldId* field_id_; - - DISALLOW_COPY_AND_ASSIGN(FieldItem); -}; - -using FieldItemVector = std::vector<FieldItem>; - -class MethodItem : public Item { - public: - MethodItem(uint32_t access_flags, const MethodId* method_id, CodeItem* code) - : access_flags_(access_flags), method_id_(method_id), code_(code) { } - ~MethodItem() override { } - - MethodItem(MethodItem&&) = default; - - uint32_t GetAccessFlags() const { return access_flags_; } - const MethodId* GetMethodId() const { return method_id_; } - CodeItem* GetCodeItem() { return code_; } - - void Accept(AbstractDispatcher* dispatch) { dispatch->Dispatch(this); } - - private: - uint32_t access_flags_; - const MethodId* method_id_; - CodeItem* code_; // This can be nullptr. - - DISALLOW_COPY_AND_ASSIGN(MethodItem); -}; - -using MethodItemVector = std::vector<MethodItem>; - -class EncodedValue { - public: - explicit EncodedValue(uint8_t type) : type_(type) { } - - int8_t Type() const { return type_; } - - void SetBoolean(bool z) { u_.bool_val_ = z; } - void SetByte(int8_t b) { u_.byte_val_ = b; } - void SetShort(int16_t s) { u_.short_val_ = s; } - void SetChar(uint16_t c) { u_.char_val_ = c; } - void SetInt(int32_t i) { u_.int_val_ = i; } - void SetLong(int64_t l) { u_.long_val_ = l; } - void SetFloat(float f) { u_.float_val_ = f; } - void SetDouble(double d) { u_.double_val_ = d; } - void SetStringId(StringId* string_id) { u_.string_val_ = string_id; } - void SetTypeId(TypeId* type_id) { u_.type_val_ = type_id; } - void SetProtoId(ProtoId* proto_id) { u_.proto_val_ = proto_id; } - void SetFieldId(FieldId* field_id) { u_.field_val_ = field_id; } - void SetMethodId(MethodId* method_id) { u_.method_val_ = method_id; } - void SetMethodHandle(MethodHandleItem* method_handle) { u_.method_handle_val_ = method_handle; } - void SetEncodedArray(EncodedArrayItem* encoded_array) { encoded_array_.reset(encoded_array); } - void SetEncodedAnnotation(EncodedAnnotation* encoded_annotation) - { encoded_annotation_.reset(encoded_annotation); } - - bool GetBoolean() const { return u_.bool_val_; } - int8_t GetByte() const { return u_.byte_val_; } - int16_t GetShort() const { return u_.short_val_; } - uint16_t GetChar() const { return u_.char_val_; } - int32_t GetInt() const { return u_.int_val_; } - int64_t GetLong() const { return u_.long_val_; } - float GetFloat() const { return u_.float_val_; } - double GetDouble() const { return u_.double_val_; } - StringId* GetStringId() const { return u_.string_val_; } - TypeId* GetTypeId() const { return u_.type_val_; } - ProtoId* GetProtoId() const { return u_.proto_val_; } - FieldId* GetFieldId() const { return u_.field_val_; } - MethodId* GetMethodId() const { return u_.method_val_; } - MethodHandleItem* GetMethodHandle() const { return u_.method_handle_val_; } - EncodedArrayItem* GetEncodedArray() const { return encoded_array_.get(); } - EncodedAnnotation* GetEncodedAnnotation() const { return encoded_annotation_.get(); } - - EncodedAnnotation* ReleaseEncodedAnnotation() { return encoded_annotation_.release(); } - - private: - uint8_t type_; - union { - bool bool_val_; - int8_t byte_val_; - int16_t short_val_; - uint16_t char_val_; - int32_t int_val_; - int64_t long_val_; - float float_val_; - double double_val_; - StringId* string_val_; - TypeId* type_val_; - ProtoId* proto_val_; - FieldId* field_val_; - MethodId* method_val_; - MethodHandleItem* method_handle_val_; - } u_; - std::unique_ptr<EncodedArrayItem> encoded_array_; - std::unique_ptr<EncodedAnnotation> encoded_annotation_; - - DISALLOW_COPY_AND_ASSIGN(EncodedValue); -}; - -using EncodedValueVector = std::vector<std::unique_ptr<EncodedValue>>; - -class AnnotationElement { - public: - AnnotationElement(StringId* name, EncodedValue* value) : name_(name), value_(value) { } - - StringId* GetName() const { return name_; } - EncodedValue* GetValue() const { return value_.get(); } - - private: - StringId* name_; - std::unique_ptr<EncodedValue> value_; - - DISALLOW_COPY_AND_ASSIGN(AnnotationElement); -}; - -using AnnotationElementVector = std::vector<std::unique_ptr<AnnotationElement>>; - -class EncodedAnnotation { - public: - EncodedAnnotation(TypeId* type, AnnotationElementVector* elements) - : type_(type), elements_(elements) { } - - TypeId* GetType() const { return type_; } - AnnotationElementVector* GetAnnotationElements() const { return elements_.get(); } - - private: - TypeId* type_; - std::unique_ptr<AnnotationElementVector> elements_; - - DISALLOW_COPY_AND_ASSIGN(EncodedAnnotation); -}; - -class EncodedArrayItem : public Item { - public: - explicit EncodedArrayItem(EncodedValueVector* encoded_values) - : encoded_values_(encoded_values) { } - - EncodedValueVector* GetEncodedValues() const { return encoded_values_.get(); } - - private: - std::unique_ptr<EncodedValueVector> encoded_values_; - - DISALLOW_COPY_AND_ASSIGN(EncodedArrayItem); -}; - -class ClassData : public Item { - public: - ClassData(FieldItemVector* static_fields, - FieldItemVector* instance_fields, - MethodItemVector* direct_methods, - MethodItemVector* virtual_methods) - : static_fields_(static_fields), - instance_fields_(instance_fields), - direct_methods_(direct_methods), - virtual_methods_(virtual_methods) { } - - ~ClassData() override = default; - FieldItemVector* StaticFields() { return static_fields_.get(); } - FieldItemVector* InstanceFields() { return instance_fields_.get(); } - MethodItemVector* DirectMethods() { return direct_methods_.get(); } - MethodItemVector* VirtualMethods() { return virtual_methods_.get(); } - - void Accept(AbstractDispatcher* dispatch) { dispatch->Dispatch(this); } - - private: - std::unique_ptr<FieldItemVector> static_fields_; - std::unique_ptr<FieldItemVector> instance_fields_; - std::unique_ptr<MethodItemVector> direct_methods_; - std::unique_ptr<MethodItemVector> virtual_methods_; - - DISALLOW_COPY_AND_ASSIGN(ClassData); -}; - -class ClassDef : public IndexedItem { - public: - ClassDef(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) - : class_type_(class_type), - access_flags_(access_flags), - superclass_(superclass), - interfaces_(interfaces), - source_file_(source_file), - annotations_(annotations), - class_data_(class_data), - static_values_(static_values) { size_ = kClassDefItemSize; } - - ~ClassDef() override { } - - static size_t ItemSize() { return kClassDefItemSize; } - - const TypeId* ClassType() const { return class_type_; } - uint32_t GetAccessFlags() const { return access_flags_; } - const TypeId* Superclass() const { return superclass_; } - const TypeList* Interfaces() { return interfaces_; } - uint32_t InterfacesOffset() { return interfaces_ == nullptr ? 0 : interfaces_->GetOffset(); } - const StringId* SourceFile() const { return source_file_; } - AnnotationsDirectoryItem* Annotations() const { return annotations_; } - ClassData* GetClassData() { return class_data_; } - EncodedArrayItem* StaticValues() { return static_values_; } - - void Accept(AbstractDispatcher* dispatch) { dispatch->Dispatch(this); } - - private: - const TypeId* class_type_; - uint32_t access_flags_; - 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 TypeAddrPair { - public: - 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_; } - - private: - const TypeId* type_id_; // This can be nullptr. - 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); -}; - -using CatchHandlerVector = std::vector<std::unique_ptr<const CatchHandler>>; - -class TryItem : public Item { - public: - 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 CatchHandler* GetHandlers() const { return handlers_; } - - void Accept(AbstractDispatcher* dispatch) { dispatch->Dispatch(this); } - - private: - uint32_t start_addr_; - uint16_t insn_count_; - const CatchHandler* handlers_; - - DISALLOW_COPY_AND_ASSIGN(TryItem); -}; - -using TryItemVector = std::vector<std::unique_ptr<const TryItem>>; - -class CodeFixups { - public: - CodeFixups(std::vector<TypeId*> type_ids, - std::vector<StringId*> string_ids, - std::vector<MethodId*> method_ids, - std::vector<FieldId*> field_ids) - : type_ids_(std::move(type_ids)), - string_ids_(std::move(string_ids)), - method_ids_(std::move(method_ids)), - field_ids_(std::move(field_ids)) { } - - const std::vector<TypeId*>& TypeIds() const { return type_ids_; } - const std::vector<StringId*>& StringIds() const { return string_ids_; } - const std::vector<MethodId*>& MethodIds() const { return method_ids_; } - const std::vector<FieldId*>& FieldIds() const { return field_ids_; } - - private: - std::vector<TypeId*> type_ids_; - std::vector<StringId*> string_ids_; - std::vector<MethodId*> method_ids_; - std::vector<FieldId*> field_ids_; - - DISALLOW_COPY_AND_ASSIGN(CodeFixups); -}; - -class CodeItem : public Item { - public: - CodeItem(uint16_t registers_size, - uint16_t ins_size, - uint16_t outs_size, - DebugInfoItem* debug_info, - uint32_t insns_size, - uint16_t* insns, - 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), - handlers_(handlers) { } - - ~CodeItem() override { } - - uint16_t RegistersSize() const { return registers_size_; } - uint16_t InsSize() const { return ins_size_; } - uint16_t OutsSize() const { return outs_size_; } - uint16_t TriesSize() const { return tries_ == nullptr ? 0 : tries_->size(); } - DebugInfoItem* DebugInfo() const { return debug_info_; } - 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 SetCodeFixups(CodeFixups* fixups) { fixups_.reset(fixups); } - CodeFixups* GetCodeFixups() const { return fixups_.get(); } - - void Accept(AbstractDispatcher* dispatch) { dispatch->Dispatch(this); } - - IterationRange<DexInstructionIterator> Instructions() const { - return MakeIterationRange(DexInstructionIterator(Insns(), 0u), - DexInstructionIterator(Insns(), InsnsSize())); - } - - private: - uint16_t registers_size_; - uint16_t ins_size_; - uint16_t outs_size_; - DebugInfoItem* debug_info_; // This can be nullptr. - uint32_t insns_size_; - std::unique_ptr<uint16_t[]> insns_; - std::unique_ptr<TryItemVector> tries_; // This can be nullptr. - std::unique_ptr<CatchHandlerVector> handlers_; // This can be nullptr. - std::unique_ptr<CodeFixups> fixups_; // This can be nullptr. - - DISALLOW_COPY_AND_ASSIGN(CodeItem); -}; - -class DebugInfoItem : public Item { - public: - 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(); } - - private: - uint32_t debug_info_size_; - std::unique_ptr<uint8_t[]> debug_info_; - - DISALLOW_COPY_AND_ASSIGN(DebugInfoItem); -}; - -class AnnotationItem : public Item { - public: - AnnotationItem(uint8_t visibility, EncodedAnnotation* annotation) - : visibility_(visibility), annotation_(annotation) { } - - uint8_t GetVisibility() const { return visibility_; } - EncodedAnnotation* GetAnnotation() const { return annotation_.get(); } - - void Accept(AbstractDispatcher* dispatch) { dispatch->Dispatch(this); } - - private: - uint8_t visibility_; - std::unique_ptr<EncodedAnnotation> annotation_; - - DISALLOW_COPY_AND_ASSIGN(AnnotationItem); -}; - -class AnnotationSetItem : public Item { - public: - explicit AnnotationSetItem(std::vector<AnnotationItem*>* items) : items_(items) { - size_ = sizeof(uint32_t) + items->size() * sizeof(uint32_t); - } - ~AnnotationSetItem() override { } - - std::vector<AnnotationItem*>* GetItems() { return items_.get(); } - - void Accept(AbstractDispatcher* dispatch) { dispatch->Dispatch(this); } - - private: - std::unique_ptr<std::vector<AnnotationItem*>> items_; - - DISALLOW_COPY_AND_ASSIGN(AnnotationSetItem); -}; - -class AnnotationSetRefList : public Item { - public: - explicit AnnotationSetRefList(std::vector<AnnotationSetItem*>* items) : items_(items) { - size_ = sizeof(uint32_t) + items->size() * sizeof(uint32_t); - } - ~AnnotationSetRefList() override { } - - std::vector<AnnotationSetItem*>* GetItems() { return items_.get(); } - - void Accept(AbstractDispatcher* dispatch) { dispatch->Dispatch(this); } - - private: - std::unique_ptr<std::vector<AnnotationSetItem*>> items_; // Elements of vector can be nullptr. - - DISALLOW_COPY_AND_ASSIGN(AnnotationSetRefList); -}; - -class FieldAnnotation { - public: - FieldAnnotation(FieldId* field_id, AnnotationSetItem* annotation_set_item) - : field_id_(field_id), annotation_set_item_(annotation_set_item) { } - - FieldId* GetFieldId() const { return field_id_; } - AnnotationSetItem* GetAnnotationSetItem() const { return annotation_set_item_; } - - private: - FieldId* field_id_; - AnnotationSetItem* annotation_set_item_; - - DISALLOW_COPY_AND_ASSIGN(FieldAnnotation); -}; - -using FieldAnnotationVector = std::vector<std::unique_ptr<FieldAnnotation>>; - -class MethodAnnotation { - public: - MethodAnnotation(MethodId* method_id, AnnotationSetItem* annotation_set_item) - : method_id_(method_id), annotation_set_item_(annotation_set_item) { } - - MethodId* GetMethodId() const { return method_id_; } - AnnotationSetItem* GetAnnotationSetItem() const { return annotation_set_item_; } - - private: - MethodId* method_id_; - AnnotationSetItem* annotation_set_item_; - - DISALLOW_COPY_AND_ASSIGN(MethodAnnotation); -}; - -using MethodAnnotationVector = std::vector<std::unique_ptr<MethodAnnotation>>; - -class ParameterAnnotation { - public: - ParameterAnnotation(MethodId* method_id, AnnotationSetRefList* annotations) - : method_id_(method_id), annotations_(annotations) { } - - MethodId* GetMethodId() const { return method_id_; } - AnnotationSetRefList* GetAnnotations() { return annotations_; } - - private: - MethodId* method_id_; - AnnotationSetRefList* annotations_; - - DISALLOW_COPY_AND_ASSIGN(ParameterAnnotation); -}; - -using ParameterAnnotationVector = std::vector<std::unique_ptr<ParameterAnnotation>>; - -class AnnotationsDirectoryItem : public Item { - public: - AnnotationsDirectoryItem(AnnotationSetItem* class_annotation, - FieldAnnotationVector* field_annotations, - MethodAnnotationVector* method_annotations, - ParameterAnnotationVector* parameter_annotations) - : class_annotation_(class_annotation), - field_annotations_(field_annotations), - method_annotations_(method_annotations), - parameter_annotations_(parameter_annotations) { } - - AnnotationSetItem* GetClassAnnotation() const { return class_annotation_; } - FieldAnnotationVector* GetFieldAnnotations() { return field_annotations_.get(); } - MethodAnnotationVector* GetMethodAnnotations() { return method_annotations_.get(); } - ParameterAnnotationVector* GetParameterAnnotations() { return parameter_annotations_.get(); } - - void Accept(AbstractDispatcher* dispatch) { dispatch->Dispatch(this); } - - private: - 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); -}; - -class CallSiteId : public IndexedItem { - public: - explicit CallSiteId(EncodedArrayItem* call_site_item) : call_site_item_(call_site_item) { - size_ = kCallSiteIdItemSize; - } - ~CallSiteId() override { } - - static size_t ItemSize() { return kCallSiteIdItemSize; } - - EncodedArrayItem* CallSiteItem() const { return call_site_item_; } - - void Accept(AbstractDispatcher* dispatch) const { dispatch->Dispatch(this); } - - private: - EncodedArrayItem* call_site_item_; - - DISALLOW_COPY_AND_ASSIGN(CallSiteId); -}; - -class MethodHandleItem : public IndexedItem { - public: - MethodHandleItem(DexFile::MethodHandleType method_handle_type, IndexedItem* field_or_method_id) - : method_handle_type_(method_handle_type), - field_or_method_id_(field_or_method_id) { - size_ = kMethodHandleItemSize; - } - ~MethodHandleItem() override { } - - static size_t ItemSize() { return kMethodHandleItemSize; } - - DexFile::MethodHandleType GetMethodHandleType() const { return method_handle_type_; } - IndexedItem* GetFieldOrMethodId() const { return field_or_method_id_; } - - void Accept(AbstractDispatcher* dispatch) const { dispatch->Dispatch(this); } - - private: - DexFile::MethodHandleType method_handle_type_; - IndexedItem* field_or_method_id_; - - DISALLOW_COPY_AND_ASSIGN(MethodHandleItem); -}; - -using HiddenapiFlagsMap = SafeMap<const Item*, uint32_t>; - -class HiddenapiClassData : public IndexedItem { - public: - HiddenapiClassData(const ClassDef* class_def, std::unique_ptr<HiddenapiFlagsMap> flags) - : class_def_(class_def), flags_(std::move(flags)) { } - ~HiddenapiClassData() override { } - - const ClassDef* GetClassDef() const { return class_def_; } - - uint32_t GetFlags(const Item* field_or_method_item) const { - return (flags_ == nullptr) ? 0u : flags_->Get(field_or_method_item); - } - - static uint32_t GetFlags(Header* header, ClassDef* class_def, const Item* field_or_method_item) { - DCHECK(header != nullptr); - DCHECK(class_def != nullptr); - return (header->HiddenapiClassDatas().Empty()) - ? 0u - : header->HiddenapiClassDatas()[class_def->GetIndex()]->GetFlags(field_or_method_item); - } - - uint32_t ItemSize() const { - uint32_t size = 0u; - bool has_non_zero_entries = false; - if (flags_ != nullptr) { - for (const auto& entry : *flags_) { - size += UnsignedLeb128Size(entry.second); - has_non_zero_entries |= (entry.second != 0u); - } - } - return has_non_zero_entries ? size : 0u; - } - - void Accept(AbstractDispatcher* dispatch) { dispatch->Dispatch(this); } - - private: - const ClassDef* class_def_; - std::unique_ptr<HiddenapiFlagsMap> flags_; - - DISALLOW_COPY_AND_ASSIGN(HiddenapiClassData); -}; - -// TODO(sehr): implement MapList. -class MapList : public Item { - public: - void Accept(AbstractDispatcher* dispatch) { dispatch->Dispatch(this); } - - private: - DISALLOW_COPY_AND_ASSIGN(MapList); -}; - -class MapItem : public Item { - public: - void Accept(AbstractDispatcher* dispatch) { dispatch->Dispatch(this); } - - private: - DISALLOW_COPY_AND_ASSIGN(MapItem); -}; - -// Interface for building a vector of file sections for use by other clients. -struct DexFileSection { - public: - DexFileSection(const std::string& name, uint16_t type, uint32_t size, uint32_t offset) - : name(name), type(type), size(size), offset(offset) { } - std::string name; - // The type (DexFile::MapItemType). - uint16_t type; - // The size (in elements, not bytes). - uint32_t size; - // The byte offset from the start of the file. - uint32_t offset; -}; - -enum class SortDirection { - kSortAscending, - kSortDescending -}; - -std::vector<DexFileSection> GetSortedDexFileSections(dex_ir::Header* header, - SortDirection direction); - -} // namespace dex_ir -} // namespace art - -#endif // ART_DEXLAYOUT_DEX_IR_H_ diff --git a/dexlayout/dex_ir_builder.cc b/dexlayout/dex_ir_builder.cc deleted file mode 100644 index 5636e2c1f5..0000000000 --- a/dexlayout/dex_ir_builder.cc +++ /dev/null @@ -1,1263 +0,0 @@ -/* - * 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 <memory> -#include <vector> - -#include "dex_ir_builder.h" - -#include "dex/class_accessor-inl.h" -#include "dex/code_item_accessors-inl.h" -#include "dex/dex_file_exception_helpers.h" -#include "dex/dex_instruction-inl.h" -#include "dexlayout.h" - -namespace art { -namespace dex_ir { - -static uint64_t ReadVarWidth(const uint8_t** data, uint8_t length, bool sign_extend) { - uint64_t value = 0; - for (uint32_t i = 0; i <= length; i++) { - value |= static_cast<uint64_t>(*(*data)++) << (i * 8); - } - if (sign_extend) { - int shift = (7 - length) * 8; - return (static_cast<int64_t>(value) << shift) >> shift; - } - return value; -} - -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; - } - } - } -} - -template<class T> class CollectionMap : public CollectionBase { - public: - CollectionMap() = default; - ~CollectionMap() override { } - - template <class... Args> - T* CreateAndAddItem(CollectionVector<T>& vector, - bool eagerly_assign_offsets, - uint32_t offset, - Args&&... args) { - T* item = vector.CreateAndAddItem(std::forward<Args>(args)...); - DCHECK(!GetExistingObject(offset)); - DCHECK(!item->OffsetAssigned()); - if (eagerly_assign_offsets) { - item->SetOffset(offset); - } - AddItem(item, offset); - return item; - } - - // Returns the existing item if it is already inserted, null otherwise. - T* GetExistingObject(uint32_t offset) { - auto it = collection_.find(offset); - return it != collection_.end() ? it->second : nullptr; - } - - uint32_t Size() const override { return size(); } - - // Lower case for template interop with std::map. - uint32_t size() const { return collection_.size(); } - std::map<uint32_t, T*>& Collection() { return collection_; } - - private: - std::map<uint32_t, T*> collection_; - - // CollectionMaps do not own the objects they contain, therefore AddItem is supported - // rather than CreateAndAddItem. - void AddItem(T* object, uint32_t offset) { - auto it = collection_.emplace(offset, object); - CHECK(it.second) << "CollectionMap already has an object with offset " << offset << " " - << " and address " << it.first->second; - } - - DISALLOW_COPY_AND_ASSIGN(CollectionMap); -}; - -class BuilderMaps { - public: - BuilderMaps(Header* header, bool eagerly_assign_offsets) - : header_(header), eagerly_assign_offsets_(eagerly_assign_offsets) { } - - void CreateStringId(const DexFile& dex_file, uint32_t i); - void CreateTypeId(const DexFile& dex_file, uint32_t i); - void CreateProtoId(const DexFile& dex_file, uint32_t i); - void CreateFieldId(const DexFile& dex_file, uint32_t i); - void CreateMethodId(const DexFile& dex_file, uint32_t i); - void CreateClassDef(const DexFile& dex_file, uint32_t i); - void CreateCallSiteId(const DexFile& dex_file, uint32_t i); - void CreateMethodHandleItem(const DexFile& dex_file, uint32_t i); - - void CreateCallSitesAndMethodHandles(const DexFile& dex_file); - - TypeList* CreateTypeList(const dex::TypeList* type_list, uint32_t offset); - EncodedArrayItem* CreateEncodedArrayItem(const DexFile& dex_file, - const uint8_t* static_data, - uint32_t offset); - AnnotationItem* CreateAnnotationItem(const DexFile& dex_file, - const dex::AnnotationItem* annotation); - AnnotationSetItem* CreateAnnotationSetItem(const DexFile& dex_file, - const dex::AnnotationSetItem* disk_annotations_item, uint32_t offset); - AnnotationsDirectoryItem* CreateAnnotationsDirectoryItem(const DexFile& dex_file, - const dex::AnnotationsDirectoryItem* disk_annotations_item, uint32_t offset); - CodeItem* DedupeOrCreateCodeItem(const DexFile& dex_file, - const dex::CodeItem* disk_code_item, - uint32_t offset, - uint32_t dex_method_index); - ClassData* CreateClassData(const DexFile& dex_file, const dex::ClassDef& class_def); - - void AddAnnotationsFromMapListSection(const DexFile& dex_file, - uint32_t start_offset, - uint32_t count); - void AddHiddenapiClassDataFromMapListSection(const DexFile& dex_file, uint32_t offset); - - void CheckAndSetRemainingOffsets(const DexFile& dex_file, const Options& options); - - // Sort the vectors buy map order (same order that was used in the input file). - void SortVectorsByMapOrder(); - - private: - bool GetIdsFromByteCode(const CodeItem* code, - std::vector<TypeId*>* type_ids, - std::vector<StringId*>* string_ids, - std::vector<MethodId*>* method_ids, - std::vector<FieldId*>* field_ids); - - bool GetIdFromInstruction(const Instruction* dec_insn, - std::vector<TypeId*>* type_ids, - std::vector<StringId*>* string_ids, - std::vector<MethodId*>* method_ids, - std::vector<FieldId*>* field_ids); - - EncodedValue* ReadEncodedValue(const DexFile& dex_file, const uint8_t** data); - EncodedValue* ReadEncodedValue(const DexFile& dex_file, - const uint8_t** data, - uint8_t type, - uint8_t length); - void ReadEncodedValue(const DexFile& dex_file, - const uint8_t** data, - uint8_t type, - uint8_t length, - EncodedValue* item); - - MethodItem GenerateMethodItem(const DexFile& dex_file, const ClassAccessor::Method& method); - - ParameterAnnotation* GenerateParameterAnnotation( - const DexFile& dex_file, - MethodId* method_id, - const dex::AnnotationSetRefList* annotation_set_ref_list, - uint32_t offset); - - template <typename Type, class... Args> - Type* CreateAndAddIndexedItem(IndexedCollectionVector<Type>& vector, - uint32_t offset, - uint32_t index, - Args&&... args) { - Type* item = vector.CreateAndAddIndexedItem(index, std::forward<Args>(args)...); - DCHECK(!item->OffsetAssigned()); - if (eagerly_assign_offsets_) { - item->SetOffset(offset); - } - return item; - } - - Header* header_; - // If we eagerly assign offsets during IR building or later after layout. Must be false if - // changing the layout is enabled. - bool eagerly_assign_offsets_; - - // Note: maps do not have ownership. - CollectionMap<StringData> string_datas_map_; - CollectionMap<TypeList> type_lists_map_; - CollectionMap<EncodedArrayItem> encoded_array_items_map_; - CollectionMap<AnnotationItem> annotation_items_map_; - CollectionMap<AnnotationSetItem> annotation_set_items_map_; - CollectionMap<AnnotationSetRefList> annotation_set_ref_lists_map_; - CollectionMap<AnnotationsDirectoryItem> annotations_directory_items_map_; - CollectionMap<DebugInfoItem> debug_info_items_map_; - // Code item maps need to check both the debug info offset and debug info offset, do not use - // CollectionMap. - // First offset is the code item offset, second is the debug info offset. - std::map<std::pair<uint32_t, uint32_t>, CodeItem*> code_items_map_; - CollectionMap<ClassData> class_datas_map_; - - DISALLOW_COPY_AND_ASSIGN(BuilderMaps); -}; - -Header* DexIrBuilder(const DexFile& dex_file, - bool eagerly_assign_offsets, - const Options& options) { - const DexFile::Header& disk_header = dex_file.GetHeader(); - Header* header = new Header(disk_header.magic_, - disk_header.checksum_, - disk_header.signature_, - disk_header.endian_tag_, - disk_header.file_size_, - disk_header.header_size_, - disk_header.link_size_, - disk_header.link_off_, - disk_header.data_size_, - disk_header.data_off_, - dex_file.SupportsDefaultMethods(), - dex_file.NumStringIds(), - dex_file.NumTypeIds(), - dex_file.NumProtoIds(), - dex_file.NumFieldIds(), - dex_file.NumMethodIds(), - dex_file.NumClassDefs()); - BuilderMaps builder_maps(header, eagerly_assign_offsets); - // Walk the rest of the header fields. - // StringId table. - header->StringIds().SetOffset(disk_header.string_ids_off_); - for (uint32_t i = 0; i < dex_file.NumStringIds(); ++i) { - builder_maps.CreateStringId(dex_file, i); - } - // TypeId table. - header->TypeIds().SetOffset(disk_header.type_ids_off_); - for (uint32_t i = 0; i < dex_file.NumTypeIds(); ++i) { - builder_maps.CreateTypeId(dex_file, i); - } - // ProtoId table. - header->ProtoIds().SetOffset(disk_header.proto_ids_off_); - for (uint32_t i = 0; i < dex_file.NumProtoIds(); ++i) { - builder_maps.CreateProtoId(dex_file, i); - } - // FieldId table. - header->FieldIds().SetOffset(disk_header.field_ids_off_); - for (uint32_t i = 0; i < dex_file.NumFieldIds(); ++i) { - builder_maps.CreateFieldId(dex_file, i); - } - // MethodId table. - header->MethodIds().SetOffset(disk_header.method_ids_off_); - for (uint32_t i = 0; i < dex_file.NumMethodIds(); ++i) { - builder_maps.CreateMethodId(dex_file, i); - } - // ClassDef table. - header->ClassDefs().SetOffset(disk_header.class_defs_off_); - for (uint32_t i = 0; i < dex_file.NumClassDefs(); ++i) { - if (!options.class_filter_.empty()) { - // If the filter is enabled (not empty), filter out classes that don't have a matching - // descriptor. - const dex::ClassDef& class_def = dex_file.GetClassDef(i); - const char* descriptor = dex_file.GetClassDescriptor(class_def); - if (options.class_filter_.find(descriptor) == options.class_filter_.end()) { - continue; - } - } - builder_maps.CreateClassDef(dex_file, i); - } - // MapItem. - header->SetMapListOffset(disk_header.map_off_); - // CallSiteIds and MethodHandleItems. - builder_maps.CreateCallSitesAndMethodHandles(dex_file); - builder_maps.CheckAndSetRemainingOffsets(dex_file, options); - - // Sort the vectors by the map order (same order as the file). - builder_maps.SortVectorsByMapOrder(); - - // Load the link data if it exists. - header->SetLinkData(std::vector<uint8_t>( - dex_file.DataBegin() + dex_file.GetHeader().link_off_, - dex_file.DataBegin() + dex_file.GetHeader().link_off_ + dex_file.GetHeader().link_size_)); - - return header; -} - -/* - * Get all the types, strings, methods, and fields referred to from bytecode. - */ -void BuilderMaps::CheckAndSetRemainingOffsets(const DexFile& dex_file, const Options& options) { - const DexFile::Header& disk_header = dex_file.GetHeader(); - // Read MapItems and validate/set remaining offsets. - const dex::MapList* map = dex_file.GetMapList(); - const uint32_t count = map->size_; - for (uint32_t i = 0; i < count; ++i) { - const dex::MapItem* item = map->list_ + i; - switch (item->type_) { - case DexFile::kDexTypeHeaderItem: - CHECK_EQ(item->size_, 1u); - CHECK_EQ(item->offset_, 0u); - break; - case DexFile::kDexTypeStringIdItem: - CHECK_EQ(item->size_, header_->StringIds().Size()); - CHECK_EQ(item->offset_, header_->StringIds().GetOffset()); - break; - case DexFile::kDexTypeTypeIdItem: - CHECK_EQ(item->size_, header_->TypeIds().Size()); - CHECK_EQ(item->offset_, header_->TypeIds().GetOffset()); - break; - case DexFile::kDexTypeProtoIdItem: - CHECK_EQ(item->size_, header_->ProtoIds().Size()); - CHECK_EQ(item->offset_, header_->ProtoIds().GetOffset()); - break; - case DexFile::kDexTypeFieldIdItem: - CHECK_EQ(item->size_, header_->FieldIds().Size()); - CHECK_EQ(item->offset_, header_->FieldIds().GetOffset()); - break; - case DexFile::kDexTypeMethodIdItem: - CHECK_EQ(item->size_, header_->MethodIds().Size()); - CHECK_EQ(item->offset_, header_->MethodIds().GetOffset()); - break; - case DexFile::kDexTypeClassDefItem: - if (options.class_filter_.empty()) { - // The filter may have removed some classes, this will get fixed up during writing. - CHECK_EQ(item->size_, header_->ClassDefs().Size()); - } - CHECK_EQ(item->offset_, header_->ClassDefs().GetOffset()); - break; - case DexFile::kDexTypeCallSiteIdItem: - CHECK_EQ(item->size_, header_->CallSiteIds().Size()); - CHECK_EQ(item->offset_, header_->CallSiteIds().GetOffset()); - break; - case DexFile::kDexTypeMethodHandleItem: - CHECK_EQ(item->size_, header_->MethodHandleItems().Size()); - CHECK_EQ(item->offset_, header_->MethodHandleItems().GetOffset()); - break; - case DexFile::kDexTypeMapList: - CHECK_EQ(item->size_, 1u); - CHECK_EQ(item->offset_, disk_header.map_off_); - break; - case DexFile::kDexTypeTypeList: - header_->TypeLists().SetOffset(item->offset_); - break; - case DexFile::kDexTypeAnnotationSetRefList: - header_->AnnotationSetRefLists().SetOffset(item->offset_); - break; - case DexFile::kDexTypeAnnotationSetItem: - header_->AnnotationSetItems().SetOffset(item->offset_); - break; - case DexFile::kDexTypeClassDataItem: - header_->ClassDatas().SetOffset(item->offset_); - break; - case DexFile::kDexTypeCodeItem: - header_->CodeItems().SetOffset(item->offset_); - break; - case DexFile::kDexTypeStringDataItem: - header_->StringDatas().SetOffset(item->offset_); - break; - case DexFile::kDexTypeDebugInfoItem: - header_->DebugInfoItems().SetOffset(item->offset_); - break; - case DexFile::kDexTypeAnnotationItem: - header_->AnnotationItems().SetOffset(item->offset_); - AddAnnotationsFromMapListSection(dex_file, item->offset_, item->size_); - break; - case DexFile::kDexTypeEncodedArrayItem: - header_->EncodedArrayItems().SetOffset(item->offset_); - break; - case DexFile::kDexTypeAnnotationsDirectoryItem: - header_->AnnotationsDirectoryItems().SetOffset(item->offset_); - break; - case DexFile::kDexTypeHiddenapiClassData: - header_->HiddenapiClassDatas().SetOffset(item->offset_); - AddHiddenapiClassDataFromMapListSection(dex_file, item->offset_); - break; - default: - LOG(ERROR) << "Unknown map list item type."; - } - } -} - -void BuilderMaps::CreateStringId(const DexFile& dex_file, uint32_t i) { - const dex::StringId& disk_string_id = dex_file.GetStringId(dex::StringIndex(i)); - StringData* string_data = - string_datas_map_.CreateAndAddItem(header_->StringDatas(), - eagerly_assign_offsets_, - disk_string_id.string_data_off_, - dex_file.GetStringData(disk_string_id)); - CreateAndAddIndexedItem(header_->StringIds(), - header_->StringIds().GetOffset() + i * StringId::ItemSize(), - i, - string_data); -} - -void BuilderMaps::CreateTypeId(const DexFile& dex_file, uint32_t i) { - const dex::TypeId& disk_type_id = dex_file.GetTypeId(dex::TypeIndex(i)); - CreateAndAddIndexedItem(header_->TypeIds(), - header_->TypeIds().GetOffset() + i * TypeId::ItemSize(), - i, - header_->StringIds()[disk_type_id.descriptor_idx_.index_]); -} - -void BuilderMaps::CreateProtoId(const DexFile& dex_file, uint32_t i) { - const dex::ProtoId& disk_proto_id = dex_file.GetProtoId(dex::ProtoIndex(i)); - const dex::TypeList* type_list = dex_file.GetProtoParameters(disk_proto_id); - TypeList* parameter_type_list = CreateTypeList(type_list, disk_proto_id.parameters_off_); - - CreateAndAddIndexedItem(header_->ProtoIds(), - header_->ProtoIds().GetOffset() + i * ProtoId::ItemSize(), - i, - header_->StringIds()[disk_proto_id.shorty_idx_.index_], - header_->TypeIds()[disk_proto_id.return_type_idx_.index_], - parameter_type_list); -} - -void BuilderMaps::CreateFieldId(const DexFile& dex_file, uint32_t i) { - const dex::FieldId& disk_field_id = dex_file.GetFieldId(i); - CreateAndAddIndexedItem(header_->FieldIds(), - header_->FieldIds().GetOffset() + i * FieldId::ItemSize(), - i, - header_->TypeIds()[disk_field_id.class_idx_.index_], - header_->TypeIds()[disk_field_id.type_idx_.index_], - header_->StringIds()[disk_field_id.name_idx_.index_]); -} - -void BuilderMaps::CreateMethodId(const DexFile& dex_file, uint32_t i) { - const dex::MethodId& disk_method_id = dex_file.GetMethodId(i); - CreateAndAddIndexedItem(header_->MethodIds(), - header_->MethodIds().GetOffset() + i * MethodId::ItemSize(), - i, - header_->TypeIds()[disk_method_id.class_idx_.index_], - header_->ProtoIds()[disk_method_id.proto_idx_.index_], - header_->StringIds()[disk_method_id.name_idx_.index_]); -} - -void BuilderMaps::CreateClassDef(const DexFile& dex_file, uint32_t i) { - const dex::ClassDef& disk_class_def = dex_file.GetClassDef(i); - const TypeId* class_type = header_->TypeIds()[disk_class_def.class_idx_.index_]; - uint32_t access_flags = disk_class_def.access_flags_; - const TypeId* superclass = header_->GetTypeIdOrNullPtr(disk_class_def.superclass_idx_.index_); - - const dex::TypeList* type_list = dex_file.GetInterfacesList(disk_class_def); - TypeList* interfaces_type_list = CreateTypeList(type_list, disk_class_def.interfaces_off_); - - const StringId* source_file = - header_->GetStringIdOrNullPtr(disk_class_def.source_file_idx_.index_); - // Annotations. - AnnotationsDirectoryItem* annotations = nullptr; - const dex::AnnotationsDirectoryItem* disk_annotations_directory_item = - dex_file.GetAnnotationsDirectory(disk_class_def); - if (disk_annotations_directory_item != nullptr) { - annotations = CreateAnnotationsDirectoryItem( - dex_file, disk_annotations_directory_item, disk_class_def.annotations_off_); - } - // Static field initializers. - const uint8_t* static_data = dex_file.GetEncodedStaticFieldValuesArray(disk_class_def); - EncodedArrayItem* static_values = - CreateEncodedArrayItem(dex_file, static_data, disk_class_def.static_values_off_); - ClassData* class_data = CreateClassData(dex_file, disk_class_def); - CreateAndAddIndexedItem(header_->ClassDefs(), - header_->ClassDefs().GetOffset() + i * ClassDef::ItemSize(), - i, - class_type, - access_flags, - superclass, - interfaces_type_list, - source_file, - annotations, - static_values, - class_data); -} - -void BuilderMaps::CreateCallSiteId(const DexFile& dex_file, uint32_t i) { - const dex::CallSiteIdItem& disk_call_site_id = dex_file.GetCallSiteId(i); - const uint8_t* disk_call_item_ptr = dex_file.DataBegin() + disk_call_site_id.data_off_; - EncodedArrayItem* call_site_item = - CreateEncodedArrayItem(dex_file, disk_call_item_ptr, disk_call_site_id.data_off_); - - CreateAndAddIndexedItem(header_->CallSiteIds(), - header_->CallSiteIds().GetOffset() + i * CallSiteId::ItemSize(), - i, - call_site_item); -} - -void BuilderMaps::CreateMethodHandleItem(const DexFile& dex_file, uint32_t i) { - const dex::MethodHandleItem& disk_method_handle = dex_file.GetMethodHandle(i); - uint16_t index = disk_method_handle.field_or_method_idx_; - DexFile::MethodHandleType type = - static_cast<DexFile::MethodHandleType>(disk_method_handle.method_handle_type_); - bool is_invoke = type == DexFile::MethodHandleType::kInvokeStatic || - type == DexFile::MethodHandleType::kInvokeInstance || - type == DexFile::MethodHandleType::kInvokeConstructor || - type == DexFile::MethodHandleType::kInvokeDirect || - type == DexFile::MethodHandleType::kInvokeInterface; - static_assert(DexFile::MethodHandleType::kLast == DexFile::MethodHandleType::kInvokeInterface, - "Unexpected method handle types."); - IndexedItem* field_or_method_id; - if (is_invoke) { - field_or_method_id = header_->MethodIds()[index]; - } else { - field_or_method_id = header_->FieldIds()[index]; - } - CreateAndAddIndexedItem(header_->MethodHandleItems(), - header_->MethodHandleItems().GetOffset() + - i * MethodHandleItem::ItemSize(), - i, - type, - field_or_method_id); -} - -void BuilderMaps::CreateCallSitesAndMethodHandles(const DexFile& dex_file) { - // Iterate through the map list and set the offset of the CallSiteIds and MethodHandleItems. - const dex::MapList* map = dex_file.GetMapList(); - for (uint32_t i = 0; i < map->size_; ++i) { - const dex::MapItem* item = map->list_ + i; - switch (item->type_) { - case DexFile::kDexTypeCallSiteIdItem: - header_->CallSiteIds().SetOffset(item->offset_); - break; - case DexFile::kDexTypeMethodHandleItem: - header_->MethodHandleItems().SetOffset(item->offset_); - break; - default: - break; - } - } - // Populate MethodHandleItems first (CallSiteIds may depend on them). - for (uint32_t i = 0; i < dex_file.NumMethodHandles(); i++) { - CreateMethodHandleItem(dex_file, i); - } - // Populate CallSiteIds. - for (uint32_t i = 0; i < dex_file.NumCallSiteIds(); i++) { - CreateCallSiteId(dex_file, i); - } -} - -TypeList* BuilderMaps::CreateTypeList(const dex::TypeList* dex_type_list, uint32_t offset) { - if (dex_type_list == nullptr) { - return nullptr; - } - TypeList* type_list = type_lists_map_.GetExistingObject(offset); - if (type_list == nullptr) { - TypeIdVector* type_vector = new TypeIdVector(); - uint32_t size = dex_type_list->Size(); - for (uint32_t index = 0; index < size; ++index) { - type_vector->push_back(header_->TypeIds()[ - dex_type_list->GetTypeItem(index).type_idx_.index_]); - } - type_list = type_lists_map_.CreateAndAddItem(header_->TypeLists(), - eagerly_assign_offsets_, - offset, - type_vector); - } - return type_list; -} - -EncodedArrayItem* BuilderMaps::CreateEncodedArrayItem(const DexFile& dex_file, - const uint8_t* static_data, - uint32_t offset) { - if (static_data == nullptr) { - return nullptr; - } - EncodedArrayItem* encoded_array_item = encoded_array_items_map_.GetExistingObject(offset); - if (encoded_array_item == nullptr) { - uint32_t size = DecodeUnsignedLeb128(&static_data); - EncodedValueVector* values = new EncodedValueVector(); - for (uint32_t i = 0; i < size; ++i) { - values->push_back(std::unique_ptr<EncodedValue>(ReadEncodedValue(dex_file, &static_data))); - } - // TODO: Calculate the size of the encoded array. - encoded_array_item = encoded_array_items_map_.CreateAndAddItem(header_->EncodedArrayItems(), - eagerly_assign_offsets_, - offset, - values); - } - return encoded_array_item; -} - -void BuilderMaps::AddAnnotationsFromMapListSection(const DexFile& dex_file, - uint32_t start_offset, - uint32_t count) { - uint32_t current_offset = start_offset; - for (size_t i = 0; i < count; ++i) { - // Annotation that we didn't process already, add it to the set. - const dex::AnnotationItem* annotation = dex_file.GetAnnotationItemAtOffset(current_offset); - AnnotationItem* annotation_item = CreateAnnotationItem(dex_file, annotation); - DCHECK(annotation_item != nullptr); - current_offset += annotation_item->GetSize(); - } -} - -void BuilderMaps::AddHiddenapiClassDataFromMapListSection(const DexFile& dex_file, - uint32_t offset) { - const dex::HiddenapiClassData* hiddenapi_class_data = - dex_file.GetHiddenapiClassDataAtOffset(offset); - DCHECK(hiddenapi_class_data == dex_file.GetHiddenapiClassData()); - - for (auto& class_def : header_->ClassDefs()) { - uint32_t index = class_def->GetIndex(); - ClassData* class_data = class_def->GetClassData(); - const uint8_t* ptr = hiddenapi_class_data->GetFlagsPointer(index); - - std::unique_ptr<HiddenapiFlagsMap> flags = nullptr; - if (ptr != nullptr) { - DCHECK(class_data != nullptr); - flags = std::make_unique<HiddenapiFlagsMap>(); - for (const dex_ir::FieldItem& field : *class_data->StaticFields()) { - flags->emplace(&field, DecodeUnsignedLeb128(&ptr)); - } - for (const dex_ir::FieldItem& field : *class_data->InstanceFields()) { - flags->emplace(&field, DecodeUnsignedLeb128(&ptr)); - } - for (const dex_ir::MethodItem& method : *class_data->DirectMethods()) { - flags->emplace(&method, DecodeUnsignedLeb128(&ptr)); - } - for (const dex_ir::MethodItem& method : *class_data->VirtualMethods()) { - flags->emplace(&method, DecodeUnsignedLeb128(&ptr)); - } - } - - CreateAndAddIndexedItem(header_->HiddenapiClassDatas(), - header_->HiddenapiClassDatas().GetOffset() + - hiddenapi_class_data->flags_offset_[index], - index, - class_def.get(), - std::move(flags)); - } -} - -AnnotationItem* BuilderMaps::CreateAnnotationItem(const DexFile& dex_file, - const dex::AnnotationItem* annotation) { - const uint8_t* const start_data = reinterpret_cast<const uint8_t*>(annotation); - const uint32_t offset = start_data - dex_file.DataBegin(); - AnnotationItem* annotation_item = annotation_items_map_.GetExistingObject(offset); - if (annotation_item == nullptr) { - uint8_t visibility = annotation->visibility_; - const uint8_t* annotation_data = annotation->annotation_; - std::unique_ptr<EncodedValue> encoded_value( - ReadEncodedValue(dex_file, &annotation_data, DexFile::kDexAnnotationAnnotation, 0)); - annotation_item = - annotation_items_map_.CreateAndAddItem(header_->AnnotationItems(), - eagerly_assign_offsets_, - offset, - visibility, - encoded_value->ReleaseEncodedAnnotation()); - annotation_item->SetSize(annotation_data - start_data); - } - return annotation_item; -} - - -AnnotationSetItem* BuilderMaps::CreateAnnotationSetItem(const DexFile& dex_file, - const dex::AnnotationSetItem* disk_annotations_item, uint32_t offset) { - if (disk_annotations_item == nullptr || (disk_annotations_item->size_ == 0 && offset == 0)) { - return nullptr; - } - AnnotationSetItem* annotation_set_item = annotation_set_items_map_.GetExistingObject(offset); - if (annotation_set_item == nullptr) { - std::vector<AnnotationItem*>* items = new std::vector<AnnotationItem*>(); - for (uint32_t i = 0; i < disk_annotations_item->size_; ++i) { - const dex::AnnotationItem* annotation = - dex_file.GetAnnotationItem(disk_annotations_item, i); - if (annotation == nullptr) { - continue; - } - AnnotationItem* annotation_item = CreateAnnotationItem(dex_file, annotation); - items->push_back(annotation_item); - } - annotation_set_item = - annotation_set_items_map_.CreateAndAddItem(header_->AnnotationSetItems(), - eagerly_assign_offsets_, - offset, - items); - } - return annotation_set_item; -} - -AnnotationsDirectoryItem* BuilderMaps::CreateAnnotationsDirectoryItem(const DexFile& dex_file, - const dex::AnnotationsDirectoryItem* disk_annotations_item, uint32_t offset) { - AnnotationsDirectoryItem* annotations_directory_item = - annotations_directory_items_map_.GetExistingObject(offset); - if (annotations_directory_item != nullptr) { - return annotations_directory_item; - } - const dex::AnnotationSetItem* class_set_item = - dex_file.GetClassAnnotationSet(disk_annotations_item); - AnnotationSetItem* class_annotation = nullptr; - if (class_set_item != nullptr) { - uint32_t item_offset = disk_annotations_item->class_annotations_off_; - class_annotation = CreateAnnotationSetItem(dex_file, class_set_item, item_offset); - } - const dex::FieldAnnotationsItem* fields = - dex_file.GetFieldAnnotations(disk_annotations_item); - FieldAnnotationVector* field_annotations = nullptr; - if (fields != nullptr) { - field_annotations = new FieldAnnotationVector(); - for (uint32_t i = 0; i < disk_annotations_item->fields_size_; ++i) { - FieldId* field_id = header_->FieldIds()[fields[i].field_idx_]; - const dex::AnnotationSetItem* field_set_item = - dex_file.GetFieldAnnotationSetItem(fields[i]); - uint32_t annotation_set_offset = fields[i].annotations_off_; - AnnotationSetItem* annotation_set_item = - CreateAnnotationSetItem(dex_file, field_set_item, annotation_set_offset); - field_annotations->push_back(std::make_unique<FieldAnnotation>( - field_id, annotation_set_item)); - } - } - const dex::MethodAnnotationsItem* methods = - dex_file.GetMethodAnnotations(disk_annotations_item); - MethodAnnotationVector* method_annotations = nullptr; - if (methods != nullptr) { - method_annotations = new MethodAnnotationVector(); - for (uint32_t i = 0; i < disk_annotations_item->methods_size_; ++i) { - MethodId* method_id = header_->MethodIds()[methods[i].method_idx_]; - const dex::AnnotationSetItem* method_set_item = - dex_file.GetMethodAnnotationSetItem(methods[i]); - uint32_t annotation_set_offset = methods[i].annotations_off_; - AnnotationSetItem* annotation_set_item = - CreateAnnotationSetItem(dex_file, method_set_item, annotation_set_offset); - method_annotations->push_back(std::make_unique<MethodAnnotation>( - method_id, annotation_set_item)); - } - } - const dex::ParameterAnnotationsItem* parameters = - dex_file.GetParameterAnnotations(disk_annotations_item); - ParameterAnnotationVector* parameter_annotations = nullptr; - if (parameters != nullptr) { - parameter_annotations = new ParameterAnnotationVector(); - for (uint32_t i = 0; i < disk_annotations_item->parameters_size_; ++i) { - MethodId* method_id = header_->MethodIds()[parameters[i].method_idx_]; - const dex::AnnotationSetRefList* list = - dex_file.GetParameterAnnotationSetRefList(¶meters[i]); - parameter_annotations->push_back(std::unique_ptr<ParameterAnnotation>( - GenerateParameterAnnotation(dex_file, method_id, list, parameters[i].annotations_off_))); - } - } - // TODO: Calculate the size of the annotations directory. - return annotations_directory_items_map_.CreateAndAddItem(header_->AnnotationsDirectoryItems(), - eagerly_assign_offsets_, - offset, - class_annotation, - field_annotations, - method_annotations, - parameter_annotations); -} - -CodeItem* BuilderMaps::DedupeOrCreateCodeItem(const DexFile& dex_file, - const dex::CodeItem* disk_code_item, - uint32_t offset, - uint32_t dex_method_index) { - if (disk_code_item == nullptr) { - return nullptr; - } - CodeItemDebugInfoAccessor accessor(dex_file, disk_code_item, dex_method_index); - const uint32_t debug_info_offset = accessor.DebugInfoOffset(); - - // Create the offsets pair and dedupe based on it. - std::pair<uint32_t, uint32_t> offsets_pair(offset, debug_info_offset); - auto existing = code_items_map_.find(offsets_pair); - if (existing != code_items_map_.end()) { - return existing->second; - } - - const uint8_t* debug_info_stream = dex_file.GetDebugInfoStream(debug_info_offset); - DebugInfoItem* debug_info = nullptr; - if (debug_info_stream != nullptr) { - debug_info = debug_info_items_map_.GetExistingObject(debug_info_offset); - if (debug_info == nullptr) { - 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 = debug_info_items_map_.CreateAndAddItem(header_->DebugInfoItems(), - eagerly_assign_offsets_, - debug_info_offset, - debug_info_size, - debug_info_buffer); - } - } - - uint32_t insns_size = accessor.InsnsSizeInCodeUnits(); - uint16_t* insns = new uint16_t[insns_size]; - memcpy(insns, accessor.Insns(), insns_size * sizeof(uint16_t)); - - TryItemVector* tries = nullptr; - CatchHandlerVector* handler_list = nullptr; - if (accessor.TriesSize() > 0) { - tries = new TryItemVector(); - handler_list = new CatchHandlerVector(); - for (const dex::TryItem& disk_try_item : accessor.TryItems()) { - uint32_t start_addr = disk_try_item.start_addr_; - uint16_t insn_count = disk_try_item.insn_count_; - 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(); - break; - } - } - if (handlers == nullptr) { - bool catch_all = false; - TypeAddrPairVector* addr_pairs = new TypeAddrPairVector(); - for (CatchHandlerIterator it(accessor, disk_try_item); it.HasNext(); it.Next()) { - const dex::TypeIndex type_index = it.GetHandlerTypeIndex(); - const TypeId* type_id = header_->GetTypeIdOrNullPtr(type_index.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)); - } - // Manually walk catch handlers list and add any missing handlers unreferenced by try items. - const uint8_t* handlers_base = accessor.GetCatchHandlerData(); - const uint8_t* handlers_data = handlers_base; - uint32_t handlers_size = DecodeUnsignedLeb128(&handlers_data); - while (handlers_size > handler_list->size()) { - bool already_added = false; - uint16_t handler_off = handlers_data - handlers_base; - for (std::unique_ptr<const CatchHandler>& existing_handlers : *handler_list) { - if (handler_off == existing_handlers->GetListOffset()) { - already_added = true; - break; - } - } - int32_t size = DecodeSignedLeb128(&handlers_data); - bool has_catch_all = size <= 0; - if (has_catch_all) { - size = -size; - } - if (already_added) { - for (int32_t i = 0; i < size; i++) { - DecodeUnsignedLeb128(&handlers_data); - DecodeUnsignedLeb128(&handlers_data); - } - if (has_catch_all) { - DecodeUnsignedLeb128(&handlers_data); - } - continue; - } - TypeAddrPairVector* addr_pairs = new TypeAddrPairVector(); - for (int32_t i = 0; i < size; i++) { - const TypeId* type_id = - header_->GetTypeIdOrNullPtr(DecodeUnsignedLeb128(&handlers_data)); - uint32_t addr = DecodeUnsignedLeb128(&handlers_data); - addr_pairs->push_back( - std::unique_ptr<const TypeAddrPair>(new TypeAddrPair(type_id, addr))); - } - if (has_catch_all) { - uint32_t addr = DecodeUnsignedLeb128(&handlers_data); - addr_pairs->push_back( - std::unique_ptr<const TypeAddrPair>(new TypeAddrPair(nullptr, addr))); - } - const CatchHandler* handler = new CatchHandler(has_catch_all, handler_off, addr_pairs); - handler_list->push_back(std::unique_ptr<const CatchHandler>(handler)); - } - } - - uint32_t size = dex_file.GetCodeItemSize(*disk_code_item); - CodeItem* code_item = header_->CodeItems().CreateAndAddItem(accessor.RegistersSize(), - accessor.InsSize(), - accessor.OutsSize(), - debug_info, - insns_size, - insns, - tries, - handler_list); - code_item->SetSize(size); - - // Add the code item to the map. - DCHECK(!code_item->OffsetAssigned()); - if (eagerly_assign_offsets_) { - code_item->SetOffset(offset); - } - code_items_map_.emplace(offsets_pair, code_item); - - // Add "fixup" references to types, strings, methods, and fields. - // This is temporary, as we will probably want more detailed parsing of the - // instructions here. - std::vector<TypeId*> type_ids; - std::vector<StringId*> string_ids; - std::vector<MethodId*> method_ids; - std::vector<FieldId*> field_ids; - if (GetIdsFromByteCode(code_item, - /*out*/ &type_ids, - /*out*/ &string_ids, - /*out*/ &method_ids, - /*out*/ &field_ids)) { - CodeFixups* fixups = new CodeFixups(std::move(type_ids), - std::move(string_ids), - std::move(method_ids), - std::move(field_ids)); - code_item->SetCodeFixups(fixups); - } - - return code_item; -} - -ClassData* BuilderMaps::CreateClassData(const DexFile& dex_file, - const dex::ClassDef& class_def) { - // Read the fields and methods defined by the class, resolving the circular reference from those - // to classes by setting class at the same time. - const uint32_t offset = class_def.class_data_off_; - ClassData* class_data = class_datas_map_.GetExistingObject(offset); - if (class_data == nullptr && offset != 0u) { - ClassAccessor accessor(dex_file, class_def); - // Static fields. - FieldItemVector* static_fields = new FieldItemVector(); - for (const ClassAccessor::Field& field : accessor.GetStaticFields()) { - FieldId* field_item = header_->FieldIds()[field.GetIndex()]; - uint32_t access_flags = field.GetAccessFlags(); - static_fields->emplace_back(access_flags, field_item); - } - FieldItemVector* instance_fields = new FieldItemVector(); - for (const ClassAccessor::Field& field : accessor.GetInstanceFields()) { - FieldId* field_item = header_->FieldIds()[field.GetIndex()]; - uint32_t access_flags = field.GetAccessFlags(); - instance_fields->emplace_back(access_flags, field_item); - } - // Direct methods. - MethodItemVector* direct_methods = new MethodItemVector(); - auto direct_methods_it = accessor.GetDirectMethods(); - for (auto it = direct_methods_it.begin(); it != direct_methods_it.end(); ++it) { - direct_methods->push_back(GenerateMethodItem(dex_file, *it)); - } - // Virtual methods. - MethodItemVector* virtual_methods = new MethodItemVector(); - auto virtual_methods_it = accessor.GetVirtualMethods(); - const uint8_t* last_data_ptr; - for (auto it = virtual_methods_it.begin(); ; ++it) { - if (it == virtual_methods_it.end()) { - last_data_ptr = it->GetDataPointer(); - break; - } - virtual_methods->push_back(GenerateMethodItem(dex_file, *it)); - } - class_data = class_datas_map_.CreateAndAddItem(header_->ClassDatas(), - eagerly_assign_offsets_, - offset, - static_fields, - instance_fields, - direct_methods, - virtual_methods); - class_data->SetSize(last_data_ptr - dex_file.GetClassData(class_def)); - } - return class_data; -} - -void BuilderMaps::SortVectorsByMapOrder() { - header_->StringDatas().SortByMapOrder(string_datas_map_.Collection()); - header_->TypeLists().SortByMapOrder(type_lists_map_.Collection()); - header_->EncodedArrayItems().SortByMapOrder(encoded_array_items_map_.Collection()); - header_->AnnotationItems().SortByMapOrder(annotation_items_map_.Collection()); - header_->AnnotationSetItems().SortByMapOrder(annotation_set_items_map_.Collection()); - header_->AnnotationSetRefLists().SortByMapOrder(annotation_set_ref_lists_map_.Collection()); - header_->AnnotationsDirectoryItems().SortByMapOrder( - annotations_directory_items_map_.Collection()); - header_->DebugInfoItems().SortByMapOrder(debug_info_items_map_.Collection()); - header_->CodeItems().SortByMapOrder(code_items_map_); - header_->ClassDatas().SortByMapOrder(class_datas_map_.Collection()); -} - -bool BuilderMaps::GetIdsFromByteCode(const CodeItem* code, - std::vector<TypeId*>* type_ids, - std::vector<StringId*>* string_ids, - std::vector<MethodId*>* method_ids, - std::vector<FieldId*>* field_ids) { - bool has_id = false; - IterationRange<DexInstructionIterator> instructions = code->Instructions(); - SafeDexInstructionIterator it(instructions.begin(), instructions.end()); - for (; !it.IsErrorState() && it < instructions.end(); ++it) { - // In case the instruction goes past the end of the code item, make sure to not process it. - SafeDexInstructionIterator next = it; - ++next; - if (next.IsErrorState()) { - break; - } - has_id |= GetIdFromInstruction(&it.Inst(), type_ids, string_ids, method_ids, field_ids); - } // for - return has_id; -} - -bool BuilderMaps::GetIdFromInstruction(const Instruction* dec_insn, - std::vector<TypeId*>* type_ids, - std::vector<StringId*>* string_ids, - std::vector<MethodId*>* method_ids, - std::vector<FieldId*>* field_ids) { - // Determine index and width of the string. - uint32_t index = 0; - 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: - case Instruction::k45cc: - case Instruction::k4rcc: - index = dec_insn->VRegB(); - break; - case Instruction::k31c: - index = dec_insn->VRegB(); - break; - case Instruction::k22c: - // case Instruction::k22cs: - index = dec_insn->VRegC(); - break; - default: - break; - } // switch - - // Determine index type, and add reference to the appropriate collection. - switch (Instruction::IndexTypeOf(dec_insn->Opcode())) { - case Instruction::kIndexTypeRef: - if (index < header_->TypeIds().Size()) { - type_ids->push_back(header_->TypeIds()[index]); - return true; - } - break; - case Instruction::kIndexStringRef: - if (index < header_->StringIds().Size()) { - string_ids->push_back(header_->StringIds()[index]); - return true; - } - break; - case Instruction::kIndexMethodRef: - case Instruction::kIndexMethodAndProtoRef: - if (index < header_->MethodIds().Size()) { - method_ids->push_back(header_->MethodIds()[index]); - return true; - } - break; - case Instruction::kIndexFieldRef: - if (index < header_->FieldIds().Size()) { - field_ids->push_back(header_->FieldIds()[index]); - return true; - } - break; - case Instruction::kIndexUnknown: - case Instruction::kIndexNone: - case Instruction::kIndexVtableOffset: - case Instruction::kIndexFieldOffset: - default: - break; - } // switch - return false; -} - -EncodedValue* BuilderMaps::ReadEncodedValue(const DexFile& dex_file, const uint8_t** data) { - const uint8_t encoded_value = *(*data)++; - const uint8_t type = encoded_value & 0x1f; - EncodedValue* item = new EncodedValue(type); - ReadEncodedValue(dex_file, data, type, encoded_value >> 5, item); - return item; -} - -EncodedValue* BuilderMaps::ReadEncodedValue(const DexFile& dex_file, - const uint8_t** data, - uint8_t type, - uint8_t length) { - EncodedValue* item = new EncodedValue(type); - ReadEncodedValue(dex_file, data, type, length, item); - return item; -} - -void BuilderMaps::ReadEncodedValue(const DexFile& dex_file, - const uint8_t** data, - uint8_t type, - uint8_t length, - EncodedValue* item) { - switch (type) { - case DexFile::kDexAnnotationByte: - item->SetByte(static_cast<int8_t>(ReadVarWidth(data, length, false))); - break; - case DexFile::kDexAnnotationShort: - item->SetShort(static_cast<int16_t>(ReadVarWidth(data, length, true))); - break; - case DexFile::kDexAnnotationChar: - item->SetChar(static_cast<uint16_t>(ReadVarWidth(data, length, false))); - break; - case DexFile::kDexAnnotationInt: - item->SetInt(static_cast<int32_t>(ReadVarWidth(data, length, true))); - break; - case DexFile::kDexAnnotationLong: - item->SetLong(static_cast<int64_t>(ReadVarWidth(data, length, true))); - break; - case DexFile::kDexAnnotationFloat: { - // Fill on right. - union { - float f; - uint32_t data; - } conv; - conv.data = static_cast<uint32_t>(ReadVarWidth(data, length, false)) << (3 - length) * 8; - item->SetFloat(conv.f); - break; - } - case DexFile::kDexAnnotationDouble: { - // Fill on right. - union { - double d; - uint64_t data; - } conv; - conv.data = ReadVarWidth(data, length, false) << (7 - length) * 8; - item->SetDouble(conv.d); - break; - } - case DexFile::kDexAnnotationMethodType: { - const uint32_t proto_index = static_cast<uint32_t>(ReadVarWidth(data, length, false)); - item->SetProtoId(header_->ProtoIds()[proto_index]); - break; - } - case DexFile::kDexAnnotationMethodHandle: { - const uint32_t method_handle_index = static_cast<uint32_t>(ReadVarWidth(data, length, false)); - item->SetMethodHandle(header_->MethodHandleItems()[method_handle_index]); - break; - } - case DexFile::kDexAnnotationString: { - const uint32_t string_index = static_cast<uint32_t>(ReadVarWidth(data, length, false)); - item->SetStringId(header_->StringIds()[string_index]); - break; - } - case DexFile::kDexAnnotationType: { - const uint32_t string_index = static_cast<uint32_t>(ReadVarWidth(data, length, false)); - item->SetTypeId(header_->TypeIds()[string_index]); - break; - } - case DexFile::kDexAnnotationField: - case DexFile::kDexAnnotationEnum: { - const uint32_t field_index = static_cast<uint32_t>(ReadVarWidth(data, length, false)); - item->SetFieldId(header_->FieldIds()[field_index]); - break; - } - case DexFile::kDexAnnotationMethod: { - const uint32_t method_index = static_cast<uint32_t>(ReadVarWidth(data, length, false)); - item->SetMethodId(header_->MethodIds()[method_index]); - break; - } - case DexFile::kDexAnnotationArray: { - EncodedValueVector* values = new EncodedValueVector(); - const uint32_t offset = *data - dex_file.DataBegin(); - const uint32_t size = DecodeUnsignedLeb128(data); - // Decode all elements. - for (uint32_t i = 0; i < size; i++) { - values->push_back(std::unique_ptr<EncodedValue>(ReadEncodedValue(dex_file, data))); - } - EncodedArrayItem* array_item = new EncodedArrayItem(values); - if (eagerly_assign_offsets_) { - array_item->SetOffset(offset); - } - item->SetEncodedArray(array_item); - break; - } - case DexFile::kDexAnnotationAnnotation: { - AnnotationElementVector* elements = new AnnotationElementVector(); - const uint32_t type_idx = DecodeUnsignedLeb128(data); - const uint32_t size = DecodeUnsignedLeb128(data); - // Decode all name=value pairs. - for (uint32_t i = 0; i < size; i++) { - const uint32_t name_index = DecodeUnsignedLeb128(data); - elements->push_back(std::make_unique<AnnotationElement>( - header_->StringIds()[name_index], - ReadEncodedValue(dex_file, data))); - } - item->SetEncodedAnnotation(new EncodedAnnotation(header_->TypeIds()[type_idx], elements)); - break; - } - case DexFile::kDexAnnotationNull: - break; - case DexFile::kDexAnnotationBoolean: - item->SetBoolean(length != 0); - break; - default: - break; - } -} - -MethodItem BuilderMaps::GenerateMethodItem(const DexFile& dex_file, - const ClassAccessor::Method& method) { - MethodId* method_id = header_->MethodIds()[method.GetIndex()]; - uint32_t access_flags = method.GetAccessFlags(); - const dex::CodeItem* disk_code_item = method.GetCodeItem(); - // Temporary hack to prevent incorrectly deduping code items if they have the same offset since - // they may have different debug info streams. - CodeItem* code_item = DedupeOrCreateCodeItem(dex_file, - disk_code_item, - method.GetCodeItemOffset(), - method.GetIndex()); - return MethodItem(access_flags, method_id, code_item); -} - -ParameterAnnotation* BuilderMaps::GenerateParameterAnnotation( - const DexFile& dex_file, - MethodId* method_id, - const dex::AnnotationSetRefList* annotation_set_ref_list, - uint32_t offset) { - AnnotationSetRefList* set_ref_list = annotation_set_ref_lists_map_.GetExistingObject(offset); - 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 dex::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 = - annotation_set_ref_lists_map_.CreateAndAddItem(header_->AnnotationSetRefLists(), - eagerly_assign_offsets_, - offset, - annotations); - } - return new ParameterAnnotation(method_id, set_ref_list); -} - -} // namespace dex_ir -} // namespace art diff --git a/dexlayout/dex_ir_builder.h b/dexlayout/dex_ir_builder.h deleted file mode 100644 index 9f5377fe56..0000000000 --- a/dexlayout/dex_ir_builder.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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_IR_BUILDER_H_ -#define ART_DEXLAYOUT_DEX_IR_BUILDER_H_ - -#include "dex_ir.h" - -namespace art { - -class Options; - -namespace dex_ir { - -// Eagerly assign offsets based on the original offsets in the input dex file. If this is not done, -// dex_ir::Item::GetOffset will abort when reading uninitialized offsets. -dex_ir::Header* DexIrBuilder(const DexFile& dex_file, - bool eagerly_assign_offsets, - const Options& options); - -} // namespace dex_ir -} // namespace art - -#endif // ART_DEXLAYOUT_DEX_IR_BUILDER_H_ diff --git a/dexlayout/dex_verify.cc b/dexlayout/dex_verify.cc deleted file mode 100644 index 83a7c69d7d..0000000000 --- a/dexlayout/dex_verify.cc +++ /dev/null @@ -1,1048 +0,0 @@ -/* - * Copyright (C) 2017 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. - * - * Implementation file of dex ir verifier. - * - * Compares two dex files at the IR level, allowing differences in layout, but not in data. - */ - -#include "dex_verify.h" - -#include <inttypes.h> - -#include <set> - -#include "android-base/stringprintf.h" - -namespace art { - -using android::base::StringPrintf; - -bool VerifyOutputDexFile(dex_ir::Header* orig_header, - dex_ir::Header* output_header, - std::string* error_msg) { - // Compare all id sections. They have a defined order that can't be changed by dexlayout. - if (!VerifyIds(orig_header->StringIds(), output_header->StringIds(), "string ids", error_msg) || - !VerifyIds(orig_header->TypeIds(), output_header->TypeIds(), "type ids", error_msg) || - !VerifyIds(orig_header->ProtoIds(), output_header->ProtoIds(), "proto ids", error_msg) || - !VerifyIds(orig_header->FieldIds(), output_header->FieldIds(), "field ids", error_msg) || - !VerifyIds(orig_header->MethodIds(), output_header->MethodIds(), "method ids", error_msg)) { - return false; - } - // Compare class defs. The order may have been changed by dexlayout. - if (!VerifyClassDefs(orig_header->ClassDefs(), output_header->ClassDefs(), error_msg)) { - return false; - } - return true; -} - -template<class T> bool VerifyIds(dex_ir::CollectionVector<T>& orig, - dex_ir::CollectionVector<T>& output, - const char* section_name, - std::string* error_msg) { - auto orig_iter = orig.begin(); - auto output_iter = output.begin(); - for (; orig_iter != orig.end() && output_iter != output.end(); ++orig_iter, ++output_iter) { - if (!VerifyId(orig_iter->get(), output_iter->get(), error_msg)) { - return false; - } - } - if (orig_iter != orig.end() || output_iter != output.end()) { - const char* longer; - if (orig_iter == orig.end()) { - longer = "output"; - } else { - longer = "original"; - } - *error_msg = StringPrintf("Mismatch for %s section: %s is longer.", section_name, longer); - return false; - } - return true; -} - -bool VerifyId(dex_ir::StringId* orig, dex_ir::StringId* output, std::string* error_msg) { - if (strcmp(orig->Data(), output->Data()) != 0) { - *error_msg = StringPrintf("Mismatched string data for string id %u at offset %x: %s vs %s.", - orig->GetIndex(), - orig->GetOffset(), - orig->Data(), - output->Data()); - return false; - } - return true; -} - -bool VerifyId(dex_ir::TypeId* orig, dex_ir::TypeId* output, std::string* error_msg) { - if (orig->GetStringId()->GetIndex() != output->GetStringId()->GetIndex()) { - *error_msg = StringPrintf("Mismatched string index for type id %u at offset %x: %u vs %u.", - orig->GetIndex(), - orig->GetOffset(), - orig->GetStringId()->GetIndex(), - output->GetStringId()->GetIndex()); - return false; - } - return true; -} - -bool VerifyId(dex_ir::ProtoId* orig, dex_ir::ProtoId* output, std::string* error_msg) { - if (orig->Shorty()->GetIndex() != output->Shorty()->GetIndex()) { - *error_msg = StringPrintf("Mismatched string index for proto id %u at offset %x: %u vs %u.", - orig->GetIndex(), - orig->GetOffset(), - orig->Shorty()->GetIndex(), - output->Shorty()->GetIndex()); - return false; - } - if (orig->ReturnType()->GetIndex() != output->ReturnType()->GetIndex()) { - *error_msg = StringPrintf("Mismatched type index for proto id %u at offset %x: %u vs %u.", - orig->GetIndex(), - orig->GetOffset(), - orig->ReturnType()->GetIndex(), - output->ReturnType()->GetIndex()); - return false; - } - if (!VerifyTypeList(orig->Parameters(), output->Parameters())) { - *error_msg = StringPrintf("Mismatched type list for proto id %u at offset %x.", - orig->GetIndex(), - orig->GetOffset()); - } - return true; -} - -bool VerifyId(dex_ir::FieldId* orig, dex_ir::FieldId* output, std::string* error_msg) { - if (orig->Class()->GetIndex() != output->Class()->GetIndex()) { - *error_msg = - StringPrintf("Mismatched class type index for field id %u at offset %x: %u vs %u.", - orig->GetIndex(), - orig->GetOffset(), - orig->Class()->GetIndex(), - output->Class()->GetIndex()); - return false; - } - if (orig->Type()->GetIndex() != output->Type()->GetIndex()) { - *error_msg = StringPrintf("Mismatched type index for field id %u at offset %x: %u vs %u.", - orig->GetIndex(), - orig->GetOffset(), - orig->Class()->GetIndex(), - output->Class()->GetIndex()); - return false; - } - if (orig->Name()->GetIndex() != output->Name()->GetIndex()) { - *error_msg = StringPrintf("Mismatched string index for field id %u at offset %x: %u vs %u.", - orig->GetIndex(), - orig->GetOffset(), - orig->Name()->GetIndex(), - output->Name()->GetIndex()); - return false; - } - return true; -} - -bool VerifyId(dex_ir::MethodId* orig, dex_ir::MethodId* output, std::string* error_msg) { - if (orig->Class()->GetIndex() != output->Class()->GetIndex()) { - *error_msg = StringPrintf("Mismatched type index for method id %u at offset %x: %u vs %u.", - orig->GetIndex(), - orig->GetOffset(), - orig->Class()->GetIndex(), - output->Class()->GetIndex()); - return false; - } - if (orig->Proto()->GetIndex() != output->Proto()->GetIndex()) { - *error_msg = StringPrintf("Mismatched proto index for method id %u at offset %x: %u vs %u.", - orig->GetIndex(), - orig->GetOffset(), - orig->Class()->GetIndex(), - output->Class()->GetIndex()); - return false; - } - if (orig->Name()->GetIndex() != output->Name()->GetIndex()) { - *error_msg = - StringPrintf("Mismatched string index for method id %u at offset %x: %u vs %u.", - orig->GetIndex(), - orig->GetOffset(), - orig->Name()->GetIndex(), - output->Name()->GetIndex()); - return false; - } - return true; -} - -struct ClassDefCompare { - bool operator()(dex_ir::ClassDef* lhs, dex_ir::ClassDef* rhs) const { - return lhs->ClassType()->GetIndex() < rhs->ClassType()->GetIndex(); - } -}; - -// The class defs may have a new order due to dexlayout. Use the class's class_idx to uniquely -// identify them and sort them for comparison. -bool VerifyClassDefs(dex_ir::CollectionVector<dex_ir::ClassDef>& orig, - dex_ir::CollectionVector<dex_ir::ClassDef>& output, - std::string* error_msg) { - // Store the class defs into sets sorted by the class's type index. - std::set<dex_ir::ClassDef*, ClassDefCompare> orig_set; - std::set<dex_ir::ClassDef*, ClassDefCompare> output_set; - auto orig_iter = orig.begin(); - auto output_iter = output.begin(); - for (; orig_iter != orig.end() && output_iter != output.end(); ++orig_iter, ++output_iter) { - orig_set.insert(orig_iter->get()); - output_set.insert(output_iter->get()); - } - if (orig_iter != orig.end() || output_iter != output.end()) { - const char* longer; - if (orig_iter == orig.end()) { - longer = "output"; - } else { - longer = "original"; - } - *error_msg = StringPrintf("Mismatch for class defs section: %s is longer.", longer); - return false; - } - auto orig_set_iter = orig_set.begin(); - auto output_set_iter = output_set.begin(); - while (orig_set_iter != orig_set.end() && output_set_iter != output_set.end()) { - if (!VerifyClassDef(*orig_set_iter, *output_set_iter, error_msg)) { - return false; - } - orig_set_iter++; - output_set_iter++; - } - return true; -} - -bool VerifyClassDef(dex_ir::ClassDef* orig, dex_ir::ClassDef* output, std::string* error_msg) { - if (orig->ClassType()->GetIndex() != output->ClassType()->GetIndex()) { - *error_msg = - StringPrintf("Mismatched class type index for class def %u at offset %x: %u vs %u.", - orig->GetIndex(), - orig->GetOffset(), - orig->ClassType()->GetIndex(), - output->ClassType()->GetIndex()); - return false; - } - if (orig->GetAccessFlags() != output->GetAccessFlags()) { - *error_msg = - StringPrintf("Mismatched access flags for class def %u at offset %x: %x vs %x.", - orig->GetIndex(), - orig->GetOffset(), - orig->GetAccessFlags(), - output->GetAccessFlags()); - return false; - } - uint32_t orig_super = orig->Superclass() == nullptr ? 0 : orig->Superclass()->GetIndex(); - uint32_t output_super = output->Superclass() == nullptr ? 0 : output->Superclass()->GetIndex(); - if (orig_super != output_super) { - *error_msg = - StringPrintf("Mismatched super class for class def %u at offset %x: %u vs %u.", - orig->GetIndex(), - orig->GetOffset(), - orig_super, - output_super); - return false; - } - if (!VerifyTypeList(orig->Interfaces(), output->Interfaces())) { - *error_msg = StringPrintf("Mismatched type list for class def %u at offset %x.", - orig->GetIndex(), - orig->GetOffset()); - return false; - } - const char* orig_source = orig->SourceFile() == nullptr ? "" : orig->SourceFile()->Data(); - const char* output_source = output->SourceFile() == nullptr ? "" : output->SourceFile()->Data(); - if (strcmp(orig_source, output_source) != 0) { - *error_msg = StringPrintf("Mismatched source file for class def %u at offset %x: %s vs %s.", - orig->GetIndex(), - orig->GetOffset(), - orig_source, - output_source); - return false; - } - if (!VerifyAnnotationsDirectory(orig->Annotations(), output->Annotations(), error_msg)) { - return false; - } - if (!VerifyClassData(orig->GetClassData(), output->GetClassData(), error_msg)) { - return false; - } - return VerifyEncodedArray(orig->StaticValues(), output->StaticValues(), error_msg); -} - -bool VerifyTypeList(const dex_ir::TypeList* orig, const dex_ir::TypeList* output) { - if (orig == nullptr || output == nullptr) { - return orig == output; - } - const dex_ir::TypeIdVector* orig_list = orig->GetTypeList(); - const dex_ir::TypeIdVector* output_list = output->GetTypeList(); - if (orig_list->size() != output_list->size()) { - return false; - } - for (size_t i = 0; i < orig_list->size(); ++i) { - if ((*orig_list)[i]->GetIndex() != (*output_list)[i]->GetIndex()) { - return false; - } - } - return true; -} - -bool VerifyAnnotationsDirectory(dex_ir::AnnotationsDirectoryItem* orig, - dex_ir::AnnotationsDirectoryItem* output, - std::string* error_msg) { - if (orig == nullptr || output == nullptr) { - if (orig != output) { - *error_msg = "Found unexpected empty annotations directory."; - return false; - } - return true; - } - if (!VerifyAnnotationSet(orig->GetClassAnnotation(), output->GetClassAnnotation(), error_msg)) { - return false; - } - if (!VerifyFieldAnnotations(orig->GetFieldAnnotations(), - output->GetFieldAnnotations(), - orig->GetOffset(), - error_msg)) { - return false; - } - if (!VerifyMethodAnnotations(orig->GetMethodAnnotations(), - output->GetMethodAnnotations(), - orig->GetOffset(), - error_msg)) { - return false; - } - return VerifyParameterAnnotations(orig->GetParameterAnnotations(), - output->GetParameterAnnotations(), - orig->GetOffset(), - error_msg); -} - -bool VerifyFieldAnnotations(dex_ir::FieldAnnotationVector* orig, - dex_ir::FieldAnnotationVector* output, - uint32_t orig_offset, - std::string* error_msg) { - if (orig == nullptr || output == nullptr) { - if (orig != output) { - *error_msg = StringPrintf( - "Found unexpected empty field annotations for annotations directory at offset %x.", - orig_offset); - return false; - } - return true; - } - if (orig->size() != output->size()) { - *error_msg = StringPrintf( - "Mismatched field annotations size for annotations directory at offset %x: %zu vs %zu.", - orig_offset, - orig->size(), - output->size()); - return false; - } - for (size_t i = 0; i < orig->size(); ++i) { - dex_ir::FieldAnnotation* orig_field = (*orig)[i].get(); - dex_ir::FieldAnnotation* output_field = (*output)[i].get(); - if (orig_field->GetFieldId()->GetIndex() != output_field->GetFieldId()->GetIndex()) { - *error_msg = StringPrintf( - "Mismatched field annotation index for annotations directory at offset %x: %u vs %u.", - orig_offset, - orig_field->GetFieldId()->GetIndex(), - output_field->GetFieldId()->GetIndex()); - return false; - } - if (!VerifyAnnotationSet(orig_field->GetAnnotationSetItem(), - output_field->GetAnnotationSetItem(), - error_msg)) { - return false; - } - } - return true; -} - -bool VerifyMethodAnnotations(dex_ir::MethodAnnotationVector* orig, - dex_ir::MethodAnnotationVector* output, - uint32_t orig_offset, - std::string* error_msg) { - if (orig == nullptr || output == nullptr) { - if (orig != output) { - *error_msg = StringPrintf( - "Found unexpected empty method annotations for annotations directory at offset %x.", - orig_offset); - return false; - } - return true; - } - if (orig->size() != output->size()) { - *error_msg = StringPrintf( - "Mismatched method annotations size for annotations directory at offset %x: %zu vs %zu.", - orig_offset, - orig->size(), - output->size()); - return false; - } - for (size_t i = 0; i < orig->size(); ++i) { - dex_ir::MethodAnnotation* orig_method = (*orig)[i].get(); - dex_ir::MethodAnnotation* output_method = (*output)[i].get(); - if (orig_method->GetMethodId()->GetIndex() != output_method->GetMethodId()->GetIndex()) { - *error_msg = StringPrintf( - "Mismatched method annotation index for annotations directory at offset %x: %u vs %u.", - orig_offset, - orig_method->GetMethodId()->GetIndex(), - output_method->GetMethodId()->GetIndex()); - return false; - } - if (!VerifyAnnotationSet(orig_method->GetAnnotationSetItem(), - output_method->GetAnnotationSetItem(), - error_msg)) { - return false; - } - } - return true; -} - -bool VerifyParameterAnnotations(dex_ir::ParameterAnnotationVector* orig, - dex_ir::ParameterAnnotationVector* output, - uint32_t orig_offset, - std::string* error_msg) { - if (orig == nullptr || output == nullptr) { - if (orig != output) { - *error_msg = StringPrintf( - "Found unexpected empty parameter annotations for annotations directory at offset %x.", - orig_offset); - return false; - } - return true; - } - if (orig->size() != output->size()) { - *error_msg = StringPrintf( - "Mismatched parameter annotations size for annotations directory at offset %x: %zu vs %zu.", - orig_offset, - orig->size(), - output->size()); - return false; - } - for (size_t i = 0; i < orig->size(); ++i) { - dex_ir::ParameterAnnotation* orig_param = (*orig)[i].get(); - dex_ir::ParameterAnnotation* output_param = (*output)[i].get(); - if (orig_param->GetMethodId()->GetIndex() != output_param->GetMethodId()->GetIndex()) { - *error_msg = StringPrintf( - "Mismatched parameter annotation index for annotations directory at offset %x: %u vs %u.", - orig_offset, - orig_param->GetMethodId()->GetIndex(), - output_param->GetMethodId()->GetIndex()); - return false; - } - if (!VerifyAnnotationSetRefList(orig_param->GetAnnotations(), - output_param->GetAnnotations(), - error_msg)) { - return false; - } - } - return true; -} - -bool VerifyAnnotationSetRefList(dex_ir::AnnotationSetRefList* orig, - dex_ir::AnnotationSetRefList* output, - std::string* error_msg) { - std::vector<dex_ir::AnnotationSetItem*>* orig_items = orig->GetItems(); - std::vector<dex_ir::AnnotationSetItem*>* output_items = output->GetItems(); - if (orig_items->size() != output_items->size()) { - *error_msg = StringPrintf( - "Mismatched annotation set ref list size at offset %x: %zu vs %zu.", - orig->GetOffset(), - orig_items->size(), - output_items->size()); - return false; - } - for (size_t i = 0; i < orig_items->size(); ++i) { - if (!VerifyAnnotationSet((*orig_items)[i], (*output_items)[i], error_msg)) { - return false; - } - } - return true; -} - -bool VerifyAnnotationSet(dex_ir::AnnotationSetItem* orig, - dex_ir::AnnotationSetItem* output, - std::string* error_msg) { - if (orig == nullptr || output == nullptr) { - if (orig != output) { - *error_msg = "Found unexpected empty annotation set."; - return false; - } - return true; - } - std::vector<dex_ir::AnnotationItem*>* orig_items = orig->GetItems(); - std::vector<dex_ir::AnnotationItem*>* output_items = output->GetItems(); - if (orig_items->size() != output_items->size()) { - *error_msg = StringPrintf("Mismatched size for annotation set at offset %x: %zu vs %zu.", - orig->GetOffset(), - orig_items->size(), - output_items->size()); - return false; - } - for (size_t i = 0; i < orig_items->size(); ++i) { - if (!VerifyAnnotation((*orig_items)[i], (*output_items)[i], error_msg)) { - return false; - } - } - return true; -} - -bool VerifyAnnotation(dex_ir::AnnotationItem* orig, - dex_ir::AnnotationItem* output, - std::string* error_msg) { - if (orig->GetVisibility() != output->GetVisibility()) { - *error_msg = StringPrintf("Mismatched visibility for annotation at offset %x: %u vs %u.", - orig->GetOffset(), - orig->GetVisibility(), - output->GetVisibility()); - return false; - } - return VerifyEncodedAnnotation(orig->GetAnnotation(), - output->GetAnnotation(), - orig->GetOffset(), - error_msg); -} - -bool VerifyEncodedAnnotation(dex_ir::EncodedAnnotation* orig, - dex_ir::EncodedAnnotation* output, - uint32_t orig_offset, - std::string* error_msg) { - if (orig->GetType()->GetIndex() != output->GetType()->GetIndex()) { - *error_msg = StringPrintf( - "Mismatched encoded annotation type for annotation at offset %x: %u vs %u.", - orig_offset, - orig->GetType()->GetIndex(), - output->GetType()->GetIndex()); - return false; - } - dex_ir::AnnotationElementVector* orig_elements = orig->GetAnnotationElements(); - dex_ir::AnnotationElementVector* output_elements = output->GetAnnotationElements(); - if (orig_elements->size() != output_elements->size()) { - *error_msg = StringPrintf( - "Mismatched encoded annotation size for annotation at offset %x: %zu vs %zu.", - orig_offset, - orig_elements->size(), - output_elements->size()); - return false; - } - for (size_t i = 0; i < orig_elements->size(); ++i) { - if (!VerifyAnnotationElement((*orig_elements)[i].get(), - (*output_elements)[i].get(), - orig_offset, - error_msg)) { - return false; - } - } - return true; -} - -bool VerifyAnnotationElement(dex_ir::AnnotationElement* orig, - dex_ir::AnnotationElement* output, - uint32_t orig_offset, - std::string* error_msg) { - if (orig->GetName()->GetIndex() != output->GetName()->GetIndex()) { - *error_msg = StringPrintf( - "Mismatched annotation element name for annotation at offset %x: %u vs %u.", - orig_offset, - orig->GetName()->GetIndex(), - output->GetName()->GetIndex()); - return false; - } - return VerifyEncodedValue(orig->GetValue(), output->GetValue(), orig_offset, error_msg); -} - -bool VerifyEncodedValue(dex_ir::EncodedValue* orig, - dex_ir::EncodedValue* output, - uint32_t orig_offset, - std::string* error_msg) { - if (orig->Type() != output->Type()) { - *error_msg = StringPrintf( - "Mismatched encoded value type for annotation or encoded array at offset %x: %d vs %d.", - orig_offset, - orig->Type(), - output->Type()); - return false; - } - switch (orig->Type()) { - case DexFile::kDexAnnotationByte: - if (orig->GetByte() != output->GetByte()) { - *error_msg = StringPrintf("Mismatched encoded byte for annotation at offset %x: %d vs %d.", - orig_offset, - orig->GetByte(), - output->GetByte()); - return false; - } - break; - case DexFile::kDexAnnotationShort: - if (orig->GetShort() != output->GetShort()) { - *error_msg = StringPrintf("Mismatched encoded short for annotation at offset %x: %d vs %d.", - orig_offset, - orig->GetShort(), - output->GetShort()); - return false; - } - break; - case DexFile::kDexAnnotationChar: - if (orig->GetChar() != output->GetChar()) { - *error_msg = StringPrintf("Mismatched encoded char for annotation at offset %x: %c vs %c.", - orig_offset, - orig->GetChar(), - output->GetChar()); - return false; - } - break; - case DexFile::kDexAnnotationInt: - if (orig->GetInt() != output->GetInt()) { - *error_msg = StringPrintf("Mismatched encoded int for annotation at offset %x: %d vs %d.", - orig_offset, - orig->GetInt(), - output->GetInt()); - return false; - } - break; - case DexFile::kDexAnnotationLong: - if (orig->GetLong() != output->GetLong()) { - *error_msg = StringPrintf( - "Mismatched encoded long for annotation at offset %x: %" PRId64 " vs %" PRId64 ".", - orig_offset, - orig->GetLong(), - output->GetLong()); - return false; - } - break; - case DexFile::kDexAnnotationFloat: - // The float value is encoded, so compare as if it's an int. - if (orig->GetInt() != output->GetInt()) { - *error_msg = StringPrintf( - "Mismatched encoded float for annotation at offset %x: %x (encoded) vs %x (encoded).", - orig_offset, - orig->GetInt(), - output->GetInt()); - return false; - } - break; - case DexFile::kDexAnnotationDouble: - // The double value is encoded, so compare as if it's a long. - if (orig->GetLong() != output->GetLong()) { - *error_msg = StringPrintf( - "Mismatched encoded double for annotation at offset %x: %" PRIx64 - " (encoded) vs %" PRIx64 " (encoded).", - orig_offset, - orig->GetLong(), - output->GetLong()); - return false; - } - break; - case DexFile::kDexAnnotationString: - if (orig->GetStringId()->GetIndex() != output->GetStringId()->GetIndex()) { - *error_msg = StringPrintf( - "Mismatched encoded string for annotation at offset %x: %s vs %s.", - orig_offset, - orig->GetStringId()->Data(), - output->GetStringId()->Data()); - return false; - } - break; - case DexFile::kDexAnnotationType: - if (orig->GetTypeId()->GetIndex() != output->GetTypeId()->GetIndex()) { - *error_msg = StringPrintf("Mismatched encoded type for annotation at offset %x: %u vs %u.", - orig_offset, - orig->GetTypeId()->GetIndex(), - output->GetTypeId()->GetIndex()); - return false; - } - break; - case DexFile::kDexAnnotationField: - case DexFile::kDexAnnotationEnum: - if (orig->GetFieldId()->GetIndex() != output->GetFieldId()->GetIndex()) { - *error_msg = StringPrintf("Mismatched encoded field for annotation at offset %x: %u vs %u.", - orig_offset, - orig->GetFieldId()->GetIndex(), - output->GetFieldId()->GetIndex()); - return false; - } - break; - case DexFile::kDexAnnotationMethod: - if (orig->GetMethodId()->GetIndex() != output->GetMethodId()->GetIndex()) { - *error_msg = StringPrintf( - "Mismatched encoded method for annotation at offset %x: %u vs %u.", - orig_offset, - orig->GetMethodId()->GetIndex(), - output->GetMethodId()->GetIndex()); - return false; - } - break; - case DexFile::kDexAnnotationArray: - if (!VerifyEncodedArray(orig->GetEncodedArray(), output->GetEncodedArray(), error_msg)) { - return false; - } - break; - case DexFile::kDexAnnotationAnnotation: - if (!VerifyEncodedAnnotation(orig->GetEncodedAnnotation(), - output->GetEncodedAnnotation(), - orig_offset, - error_msg)) { - return false; - } - break; - case DexFile::kDexAnnotationNull: - break; - case DexFile::kDexAnnotationBoolean: - if (orig->GetBoolean() != output->GetBoolean()) { - *error_msg = StringPrintf( - "Mismatched encoded boolean for annotation at offset %x: %d vs %d.", - orig_offset, - orig->GetBoolean(), - output->GetBoolean()); - return false; - } - break; - default: - break; - } - return true; -} - -bool VerifyEncodedArray(dex_ir::EncodedArrayItem* orig, - dex_ir::EncodedArrayItem* output, - std::string* error_msg) { - if (orig == nullptr || output == nullptr) { - if (orig != output) { - *error_msg = "Found unexpected empty encoded array."; - return false; - } - return true; - } - dex_ir::EncodedValueVector* orig_vector = orig->GetEncodedValues(); - dex_ir::EncodedValueVector* output_vector = output->GetEncodedValues(); - if (orig_vector->size() != output_vector->size()) { - *error_msg = StringPrintf("Mismatched size for encoded array at offset %x: %zu vs %zu.", - orig->GetOffset(), - orig_vector->size(), - output_vector->size()); - return false; - } - for (size_t i = 0; i < orig_vector->size(); ++i) { - if (!VerifyEncodedValue((*orig_vector)[i].get(), - (*output_vector)[i].get(), - orig->GetOffset(), - error_msg)) { - return false; - } - } - return true; -} - -bool VerifyClassData(dex_ir::ClassData* orig, dex_ir::ClassData* output, std::string* error_msg) { - if (orig == nullptr || output == nullptr) { - if (orig != output) { - *error_msg = "Found unexpected empty class data."; - return false; - } - return true; - } - if (!VerifyFields(orig->StaticFields(), output->StaticFields(), orig->GetOffset(), error_msg)) { - return false; - } - if (!VerifyFields(orig->InstanceFields(), - output->InstanceFields(), - orig->GetOffset(), - error_msg)) { - return false; - } - if (!VerifyMethods(orig->DirectMethods(), - output->DirectMethods(), - orig->GetOffset(), - error_msg)) { - return false; - } - return VerifyMethods(orig->VirtualMethods(), - output->VirtualMethods(), - orig->GetOffset(), - error_msg); -} - -bool VerifyFields(dex_ir::FieldItemVector* orig, - dex_ir::FieldItemVector* output, - uint32_t orig_offset, - std::string* error_msg) { - if (orig->size() != output->size()) { - *error_msg = StringPrintf("Mismatched fields size for class data at offset %x: %zu vs %zu.", - orig_offset, - orig->size(), - output->size()); - return false; - } - for (size_t i = 0; i < orig->size(); ++i) { - dex_ir::FieldItem* orig_field = &(*orig)[i]; - dex_ir::FieldItem* output_field = &(*output)[i]; - if (orig_field->GetFieldId()->GetIndex() != output_field->GetFieldId()->GetIndex()) { - *error_msg = StringPrintf("Mismatched field index for class data at offset %x: %u vs %u.", - orig_offset, - orig_field->GetFieldId()->GetIndex(), - output_field->GetFieldId()->GetIndex()); - return false; - } - if (orig_field->GetAccessFlags() != output_field->GetAccessFlags()) { - *error_msg = StringPrintf( - "Mismatched field access flags for class data at offset %x: %u vs %u.", - orig_offset, - orig_field->GetAccessFlags(), - output_field->GetAccessFlags()); - return false; - } - } - return true; -} - -bool VerifyMethods(dex_ir::MethodItemVector* orig, - dex_ir::MethodItemVector* output, - uint32_t orig_offset, - std::string* error_msg) { - if (orig->size() != output->size()) { - *error_msg = StringPrintf("Mismatched methods size for class data at offset %x: %zu vs %zu.", - orig_offset, - orig->size(), - output->size()); - return false; - } - for (size_t i = 0; i < orig->size(); ++i) { - dex_ir::MethodItem* orig_method = &(*orig)[i]; - dex_ir::MethodItem* output_method = &(*output)[i]; - if (orig_method->GetMethodId()->GetIndex() != output_method->GetMethodId()->GetIndex()) { - *error_msg = StringPrintf("Mismatched method index for class data at offset %x: %u vs %u.", - orig_offset, - orig_method->GetMethodId()->GetIndex(), - output_method->GetMethodId()->GetIndex()); - return false; - } - if (orig_method->GetAccessFlags() != output_method->GetAccessFlags()) { - *error_msg = StringPrintf( - "Mismatched method access flags for class data at offset %x: %u vs %u.", - orig_offset, - orig_method->GetAccessFlags(), - output_method->GetAccessFlags()); - return false; - } - if (!VerifyCode(orig_method->GetCodeItem(), output_method->GetCodeItem(), error_msg)) { - return false; - } - } - return true; -} - -bool VerifyCode(dex_ir::CodeItem* orig, dex_ir::CodeItem* output, std::string* error_msg) { - if (orig == nullptr || output == nullptr) { - if (orig != output) { - *error_msg = "Found unexpected empty code item."; - return false; - } - return true; - } - if (orig->RegistersSize() != output->RegistersSize()) { - *error_msg = StringPrintf("Mismatched registers size for code item at offset %x: %u vs %u.", - orig->GetOffset(), - orig->RegistersSize(), - output->RegistersSize()); - return false; - } - if (orig->InsSize() != output->InsSize()) { - *error_msg = StringPrintf("Mismatched ins size for code item at offset %x: %u vs %u.", - orig->GetOffset(), - orig->InsSize(), - output->InsSize()); - return false; - } - if (orig->OutsSize() != output->OutsSize()) { - *error_msg = StringPrintf("Mismatched outs size for code item at offset %x: %u vs %u.", - orig->GetOffset(), - orig->OutsSize(), - output->OutsSize()); - return false; - } - if (orig->TriesSize() != output->TriesSize()) { - *error_msg = StringPrintf("Mismatched tries size for code item at offset %x: %u vs %u.", - orig->GetOffset(), - orig->TriesSize(), - output->TriesSize()); - return false; - } - if (!VerifyDebugInfo(orig->DebugInfo(), output->DebugInfo(), error_msg)) { - return false; - } - if (orig->InsnsSize() != output->InsnsSize()) { - *error_msg = StringPrintf("Mismatched insns size for code item at offset %x: %u vs %u.", - orig->GetOffset(), - orig->InsnsSize(), - output->InsnsSize()); - return false; - } - if (memcmp(orig->Insns(), output->Insns(), orig->InsnsSize()) != 0) { - *error_msg = StringPrintf("Mismatched insns for code item at offset %x.", - orig->GetOffset()); - return false; - } - if (!VerifyTries(orig->Tries(), output->Tries(), orig->GetOffset(), error_msg)) { - return false; - } - return VerifyHandlers(orig->Handlers(), output->Handlers(), orig->GetOffset(), error_msg); -} - -bool VerifyDebugInfo(dex_ir::DebugInfoItem* orig, - dex_ir::DebugInfoItem* output, - std::string* error_msg) { - if (orig == nullptr || output == nullptr) { - if (orig != output) { - *error_msg = "Found unexpected empty debug info."; - return false; - } - return true; - } - // TODO: Test for debug equivalence rather than byte array equality. - uint32_t orig_size = orig->GetDebugInfoSize(); - uint32_t output_size = output->GetDebugInfoSize(); - if (orig_size != output_size) { - *error_msg = "DebugInfoSize disagreed."; - return false; - } - uint8_t* orig_data = orig->GetDebugInfo(); - uint8_t* output_data = output->GetDebugInfo(); - if ((orig_data == nullptr && output_data != nullptr) || - (orig_data != nullptr && output_data == nullptr)) { - *error_msg = "DebugInfo null/non-null mismatch."; - return false; - } - if (orig_data != nullptr && memcmp(orig_data, output_data, orig_size) != 0) { - *error_msg = "DebugInfo bytes mismatch."; - return false; - } - return true; -} - -bool VerifyTries(dex_ir::TryItemVector* orig, - dex_ir::TryItemVector* output, - uint32_t orig_offset, - std::string* error_msg) { - if (orig == nullptr || output == nullptr) { - if (orig != output) { - *error_msg = "Found unexpected empty try items."; - return false; - } - return true; - } - if (orig->size() != output->size()) { - *error_msg = StringPrintf("Mismatched tries size for code item at offset %x: %zu vs %zu.", - orig_offset, - orig->size(), - output->size()); - return false; - } - for (size_t i = 0; i < orig->size(); ++i) { - const dex_ir::TryItem* orig_try = (*orig)[i].get(); - const dex_ir::TryItem* output_try = (*output)[i].get(); - if (orig_try->StartAddr() != output_try->StartAddr()) { - *error_msg = StringPrintf( - "Mismatched try item start addr for code item at offset %x: %u vs %u.", - orig_offset, - orig_try->StartAddr(), - output_try->StartAddr()); - return false; - } - if (orig_try->InsnCount() != output_try->InsnCount()) { - *error_msg = StringPrintf( - "Mismatched try item insn count for code item at offset %x: %u vs %u.", - orig_offset, - orig_try->InsnCount(), - output_try->InsnCount()); - return false; - } - if (!VerifyHandler(orig_try->GetHandlers(), - output_try->GetHandlers(), - orig_offset, - error_msg)) { - return false; - } - } - return true; -} - -bool VerifyHandlers(dex_ir::CatchHandlerVector* orig, - dex_ir::CatchHandlerVector* output, - uint32_t orig_offset, - std::string* error_msg) { - if (orig == nullptr || output == nullptr) { - if (orig != output) { - *error_msg = "Found unexpected empty catch handlers."; - return false; - } - return true; - } - if (orig->size() != output->size()) { - *error_msg = StringPrintf( - "Mismatched catch handlers size for code item at offset %x: %zu vs %zu.", - orig_offset, - orig->size(), - output->size()); - return false; - } - for (size_t i = 0; i < orig->size(); ++i) { - if (!VerifyHandler((*orig)[i].get(), (*output)[i].get(), orig_offset, error_msg)) { - return false; - } - } - return true; -} - -bool VerifyHandler(const dex_ir::CatchHandler* orig, - const dex_ir::CatchHandler* output, - uint32_t orig_offset, - std::string* error_msg) { - dex_ir::TypeAddrPairVector* orig_handlers = orig->GetHandlers(); - dex_ir::TypeAddrPairVector* output_handlers = output->GetHandlers(); - if (orig_handlers->size() != output_handlers->size()) { - *error_msg = StringPrintf( - "Mismatched number of catch handlers for code item at offset %x: %zu vs %zu.", - orig_offset, - orig_handlers->size(), - output_handlers->size()); - return false; - } - for (size_t i = 0; i < orig_handlers->size(); ++i) { - const dex_ir::TypeAddrPair* orig_handler = (*orig_handlers)[i].get(); - const dex_ir::TypeAddrPair* output_handler = (*output_handlers)[i].get(); - if (orig_handler->GetTypeId() == nullptr || output_handler->GetTypeId() == nullptr) { - if (orig_handler->GetTypeId() != output_handler->GetTypeId()) { - *error_msg = StringPrintf( - "Found unexpected catch all catch handler for code item at offset %x.", - orig_offset); - return false; - } - } else if (orig_handler->GetTypeId()->GetIndex() != output_handler->GetTypeId()->GetIndex()) { - *error_msg = StringPrintf( - "Mismatched catch handler type for code item at offset %x: %u vs %u.", - orig_offset, - orig_handler->GetTypeId()->GetIndex(), - output_handler->GetTypeId()->GetIndex()); - return false; - } - if (orig_handler->GetAddress() != output_handler->GetAddress()) { - *error_msg = StringPrintf( - "Mismatched catch handler address for code item at offset %x: %u vs %u.", - orig_offset, - orig_handler->GetAddress(), - output_handler->GetAddress()); - return false; - } - } - return true; -} - -} // namespace art diff --git a/dexlayout/dex_verify.h b/dexlayout/dex_verify.h deleted file mode 100644 index 4943defe16..0000000000 --- a/dexlayout/dex_verify.h +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright (C) 2017 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 dex ir verifier. - * - * Compares two dex files at the IR level, allowing differences in layout, but not in data. - */ - -#ifndef ART_DEXLAYOUT_DEX_VERIFY_H_ -#define ART_DEXLAYOUT_DEX_VERIFY_H_ - -#include "dex_ir.h" - -namespace art { -// Check that the output dex file contains the same data as the original. -// Compares the dex IR of both dex files. Allows the dex files to have different layouts. -bool VerifyOutputDexFile(dex_ir::Header* orig_header, - dex_ir::Header* output_header, - std::string* error_msg); - -template<class T> bool VerifyIds(dex_ir::CollectionVector<T>& orig, - dex_ir::CollectionVector<T>& output, - const char* section_name, - std::string* error_msg); -bool VerifyId(dex_ir::StringId* orig, dex_ir::StringId* output, std::string* error_msg); -bool VerifyId(dex_ir::TypeId* orig, dex_ir::TypeId* output, std::string* error_msg); -bool VerifyId(dex_ir::ProtoId* orig, dex_ir::ProtoId* output, std::string* error_msg); -bool VerifyId(dex_ir::FieldId* orig, dex_ir::FieldId* output, std::string* error_msg); -bool VerifyId(dex_ir::MethodId* orig, dex_ir::MethodId* output, std::string* error_msg); - -bool VerifyClassDefs(dex_ir::CollectionVector<dex_ir::ClassDef>& orig, - dex_ir::CollectionVector<dex_ir::ClassDef>& output, - std::string* error_msg); -bool VerifyClassDef(dex_ir::ClassDef* orig, dex_ir::ClassDef* output, std::string* error_msg); - -bool VerifyTypeList(const dex_ir::TypeList* orig, const dex_ir::TypeList* output); - -bool VerifyAnnotationsDirectory(dex_ir::AnnotationsDirectoryItem* orig, - dex_ir::AnnotationsDirectoryItem* output, - std::string* error_msg); -bool VerifyFieldAnnotations(dex_ir::FieldAnnotationVector* orig, - dex_ir::FieldAnnotationVector* output, - uint32_t orig_offset, - std::string* error_msg); -bool VerifyMethodAnnotations(dex_ir::MethodAnnotationVector* orig, - dex_ir::MethodAnnotationVector* output, - uint32_t orig_offset, - std::string* error_msg); -bool VerifyParameterAnnotations(dex_ir::ParameterAnnotationVector* orig, - dex_ir::ParameterAnnotationVector* output, - uint32_t orig_offset, - std::string* error_msg); -bool VerifyAnnotationSetRefList(dex_ir::AnnotationSetRefList* orig, - dex_ir::AnnotationSetRefList* output, - std::string* error_msg); -bool VerifyAnnotationSet(dex_ir::AnnotationSetItem* orig, - dex_ir::AnnotationSetItem* output, - std::string* error_msg); -bool VerifyAnnotation(dex_ir::AnnotationItem* orig, - dex_ir::AnnotationItem* output, - std::string* error_msg); -bool VerifyEncodedAnnotation(dex_ir::EncodedAnnotation* orig, - dex_ir::EncodedAnnotation* output, - uint32_t orig_offset, - std::string* error_msg); -bool VerifyAnnotationElement(dex_ir::AnnotationElement* orig, - dex_ir::AnnotationElement* output, - uint32_t orig_offset, - std::string* error_msg); -bool VerifyEncodedValue(dex_ir::EncodedValue* orig, - dex_ir::EncodedValue* output, - uint32_t orig_offset, - std::string* error_msg); -bool VerifyEncodedArray(dex_ir::EncodedArrayItem* orig, - dex_ir::EncodedArrayItem* output, - std::string* error_msg); - -bool VerifyClassData(dex_ir::ClassData* orig, dex_ir::ClassData* output, std::string* error_msg); -bool VerifyFields(dex_ir::FieldItemVector* orig, - dex_ir::FieldItemVector* output, - uint32_t orig_offset, - std::string* error_msg); -bool VerifyMethods(dex_ir::MethodItemVector* orig, - dex_ir::MethodItemVector* output, - uint32_t orig_offset, - std::string* error_msg); -bool VerifyCode(dex_ir::CodeItem* orig, dex_ir::CodeItem* output, std::string* error_msg); -bool VerifyDebugInfo(dex_ir::DebugInfoItem* orig, - dex_ir::DebugInfoItem* output, - std::string* error_msg); -bool VerifyTries(dex_ir::TryItemVector* orig, - dex_ir::TryItemVector* output, - uint32_t orig_offset, - std::string* error_msg); -bool VerifyHandlers(dex_ir::CatchHandlerVector* orig, - dex_ir::CatchHandlerVector* output, - uint32_t orig_offset, - std::string* error_msg); -bool VerifyHandler(const dex_ir::CatchHandler* orig, - const dex_ir::CatchHandler* output, - uint32_t orig_offset, - std::string* error_msg); -} // namespace art - -#endif // ART_DEXLAYOUT_DEX_VERIFY_H_ diff --git a/dexlayout/dex_visualize.cc b/dexlayout/dex_visualize.cc deleted file mode 100644 index 9b11ec7f39..0000000000 --- a/dexlayout/dex_visualize.cc +++ /dev/null @@ -1,348 +0,0 @@ -/* - * 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. - * - * Implementation file of the dex layout visualization. - * - * This is a tool to read dex files into an internal representation, - * reorganize the representation, and emit dex files with a better - * file layout. - */ - -#include "dex_visualize.h" - -#include <inttypes.h> -#include <stdio.h> - -#include <functional> -#include <memory> -#include <vector> - -#include <android-base/logging.h> - -#include "base/mem_map.h" -#include "dex_ir.h" -#include "dexlayout.h" -#include "profile/profile_compilation_info.h" - -namespace art { - -static std::string MultidexName(const std::string& prefix, - size_t dex_file_index, - const std::string& suffix) { - return prefix + ((dex_file_index > 0) ? std::to_string(dex_file_index + 1) : "") + suffix; -} - -class Dumper { - public: - // Colors are based on the type of the section in MapList. - explicit Dumper(dex_ir::Header* header) - : out_file_(nullptr), - sorted_sections_( - dex_ir::GetSortedDexFileSections(header, dex_ir::SortDirection::kSortDescending)), - page_size_(MemMap::GetPageSize()) {} - - bool OpenAndPrintHeader(size_t dex_index) { - // Open the file and emit the gnuplot prologue. - out_file_ = fopen(MultidexName("layout", dex_index, ".gnuplot").c_str(), "we"); - if (out_file_ == nullptr) { - return false; - } - fprintf(out_file_, "set terminal png size 1920,1080\n"); - fprintf(out_file_, "set output \"%s\"\n", MultidexName("layout", dex_index, ".png").c_str()); - fprintf(out_file_, "set title \"%s\"\n", MultidexName("classes", dex_index, ".dex").c_str()); - fprintf(out_file_, "set xlabel \"Page offset into dex\"\n"); - fprintf(out_file_, "set ylabel \"ClassDef index\"\n"); - fprintf(out_file_, "set xtics rotate out ("); - bool printed_one = false; - - for (const dex_ir::DexFileSection& s : sorted_sections_) { - if (s.size > 0) { - if (printed_one) { - fprintf(out_file_, ", "); - } - fprintf(out_file_, "\"%s\" %" PRIuPTR, s.name.c_str(), s.offset / page_size_); - printed_one = true; - } - } - fprintf(out_file_, ")\n"); - fprintf(out_file_, - "plot \"-\" using 1:2:3:4:5 with vector nohead linewidth 1 lc variable notitle\n"); - return true; - } - - int GetColor(uint32_t offset) const { - // The dread linear search to find the right section for the reference. - uint16_t section = 0; - for (const dex_ir::DexFileSection& file_section : sorted_sections_) { - if (file_section.offset < offset) { - section = file_section.type; - break; - } - } - // And a lookup table from type to color. - ColorMapType::const_iterator iter = kColorMap.find(section); - if (iter != kColorMap.end()) { - return iter->second; - } - return 0; - } - - void DumpAddressRange(uint32_t from, uint32_t size, int class_index) { - const uint32_t low_page = from / page_size_; - const uint32_t high_page = (size > 0) ? (from + size - 1) / page_size_ : low_page; - const uint32_t size_delta = high_page - low_page; - fprintf(out_file_, "%d %d %d 0 %d\n", low_page, class_index, size_delta, GetColor(from)); - } - - void DumpAddressRange(const dex_ir::Item* item, int class_index) { - if (item != nullptr) { - DumpAddressRange(item->GetOffset(), item->GetSize(), class_index); - } - } - - void DumpStringData(const dex_ir::StringData* string_data, int class_index) { - DumpAddressRange(string_data, class_index); - } - - void DumpStringId(const dex_ir::StringId* string_id, int class_index) { - DumpAddressRange(string_id, class_index); - if (string_id == nullptr) { - return; - } - DumpStringData(string_id->DataItem(), class_index); - } - - void DumpTypeId(const dex_ir::TypeId* type_id, int class_index) { - DumpAddressRange(type_id, class_index); - DumpStringId(type_id->GetStringId(), class_index); - } - - void DumpFieldId(const dex_ir::FieldId* field_id, int class_index) { - DumpAddressRange(field_id, class_index); - if (field_id == nullptr) { - return; - } - DumpTypeId(field_id->Class(), class_index); - DumpTypeId(field_id->Type(), class_index); - DumpStringId(field_id->Name(), class_index); - } - - void DumpFieldItem(const dex_ir::FieldItem* field, int class_index) { - DumpAddressRange(field, class_index); - if (field == nullptr) { - return; - } - DumpFieldId(field->GetFieldId(), class_index); - } - - void DumpProtoId(const dex_ir::ProtoId* proto_id, int class_index) { - DumpAddressRange(proto_id, class_index); - if (proto_id == nullptr) { - return; - } - DumpStringId(proto_id->Shorty(), 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); - } - - void DumpMethodId(const dex_ir::MethodId* method_id, int class_index) { - DumpAddressRange(method_id, class_index); - if (method_id == nullptr) { - return; - } - DumpTypeId(method_id->Class(), class_index); - DumpProtoId(method_id->Proto(), class_index); - DumpStringId(method_id->Name(), class_index); - } - - 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(); - if (!profile_info->GetMethodHotness(MethodReference(dex_file, method_idx)).IsHot()) { - return; - } - } - DumpAddressRange(method, class_index); - if (method == nullptr) { - return; - } - DumpMethodId(method->GetMethodId(), class_index); - const dex_ir::CodeItem* code_item = method->GetCodeItem(); - if (code_item != nullptr) { - DumpAddressRange(code_item, class_index); - const dex_ir::CodeFixups* fixups = code_item->GetCodeFixups(); - if (fixups != nullptr) { - for (dex_ir::TypeId* type_id : fixups->TypeIds()) { - DumpTypeId(type_id, class_index); - } - for (dex_ir::StringId* string_id : fixups->StringIds()) { - DumpStringId(string_id, class_index); - } - for (dex_ir::MethodId* method_id : fixups->MethodIds()) { - DumpMethodId(method_id, class_index); - } - for (dex_ir::FieldId* field_id : fixups->FieldIds()) { - DumpFieldId(field_id, class_index); - } - } - } - } - - ~Dumper() { - fclose(out_file_); - } - - private: - using ColorMapType = std::map<uint16_t, int>; - const ColorMapType kColorMap = { - { DexFile::kDexTypeHeaderItem, 1 }, - { DexFile::kDexTypeStringIdItem, 2 }, - { DexFile::kDexTypeTypeIdItem, 3 }, - { DexFile::kDexTypeProtoIdItem, 4 }, - { DexFile::kDexTypeFieldIdItem, 5 }, - { DexFile::kDexTypeMethodIdItem, 6 }, - { DexFile::kDexTypeClassDefItem, 7 }, - { DexFile::kDexTypeTypeList, 8 }, - { DexFile::kDexTypeAnnotationSetRefList, 9 }, - { DexFile::kDexTypeAnnotationSetItem, 10 }, - { DexFile::kDexTypeClassDataItem, 11 }, - { DexFile::kDexTypeCodeItem, 12 }, - { DexFile::kDexTypeStringDataItem, 13 }, - { DexFile::kDexTypeDebugInfoItem, 14 }, - { DexFile::kDexTypeAnnotationItem, 15 }, - { DexFile::kDexTypeEncodedArrayItem, 16 }, - { DexFile::kDexTypeAnnotationsDirectoryItem, 16 } - }; - - FILE* out_file_; - std::vector<dex_ir::DexFileSection> sorted_sections_; - const size_t page_size_; - - DISALLOW_COPY_AND_ASSIGN(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, - ProfileCompilationInfo* profile_info) { - std::unique_ptr<Dumper> dumper(new Dumper(header)); - if (!dumper->OpenAndPrintHeader(dex_file_index)) { - LOG(ERROR) << "Could not open output file."; - return; - } - - const uint32_t class_defs_size = header->ClassDefs().Size(); - for (uint32_t class_index = 0; class_index < class_defs_size; class_index++) { - dex_ir::ClassDef* class_def = header->ClassDefs()[class_index]; - dex::TypeIndex type_idx(class_def->ClassType()->GetIndex()); - if (profile_info != nullptr && !profile_info->ContainsClass(*dex_file, type_idx)) { - continue; - } - dumper->DumpAddressRange(class_def, class_index); - // Type id. - dumper->DumpTypeId(class_def->ClassType(), class_index); - // Superclass type id. - dumper->DumpTypeId(class_def->Superclass(), class_index); - // Interfaces. - // TODO(jeffhao): get TypeList from class_def to use Item interface. - static constexpr uint32_t kInterfaceSizeKludge = 8; - dumper->DumpAddressRange(class_def->InterfacesOffset(), kInterfaceSizeKludge, class_index); - // Source file info. - dumper->DumpStringId(class_def->SourceFile(), class_index); - // Annotations. - dumper->DumpAddressRange(class_def->Annotations(), class_index); - // TODO(sehr): walk the annotations and dump them. - // Class data. - dex_ir::ClassData* class_data = class_def->GetClassData(); - if (class_data != nullptr) { - dumper->DumpAddressRange(class_data, class_index); - if (class_data->StaticFields()) { - for (auto& field_item : *class_data->StaticFields()) { - dumper->DumpFieldItem(&field_item, class_index); - } - } - if (class_data->InstanceFields()) { - for (auto& field_item : *class_data->InstanceFields()) { - dumper->DumpFieldItem(&field_item, class_index); - } - } - if (class_data->DirectMethods()) { - for (auto& method_item : *class_data->DirectMethods()) { - dumper->DumpMethodItem(&method_item, dex_file, class_index, profile_info); - } - } - if (class_data->VirtualMethods()) { - for (auto& method_item : *class_data->VirtualMethods()) { - dumper->DumpMethodItem(&method_item, dex_file, class_index, profile_info); - } - } - } - } // for -} - -static uint32_t FindNextByteAfterSection(dex_ir::Header* header, - const std::vector<dex_ir::DexFileSection>& sorted_sections, - size_t section_index) { - for (size_t i = section_index + 1; i < sorted_sections.size(); ++i) { - const dex_ir::DexFileSection& section = sorted_sections[i]; - if (section.size != 0) { - return section.offset; - } - } - return header->FileSize(); -} - -/* - * Dumps the offset and size of sections within the file. - */ -void ShowDexSectionStatistics(dex_ir::Header* header, size_t dex_file_index, size_t page_size) { - // Compute the (multidex) class file name). - fprintf(stdout, "%s (%d bytes)\n", - MultidexName("classes", dex_file_index, ".dex").c_str(), - header->FileSize()); - fprintf(stdout, "section offset items bytes pages pct\n"); - std::vector<dex_ir::DexFileSection> sorted_sections = - GetSortedDexFileSections(header, dex_ir::SortDirection::kSortAscending); - for (size_t i = 0; i < sorted_sections.size(); ++i) { - const dex_ir::DexFileSection& file_section = sorted_sections[i]; - uint32_t bytes = 0; - if (file_section.size > 0) { - bytes = FindNextByteAfterSection(header, sorted_sections, i) - file_section.offset; - } - fprintf(stdout, - "%-10s %8d %8d %8d %8" PRIuPTR " %%%02d\n", - file_section.name.c_str(), - file_section.offset, - file_section.size, - bytes, - RoundUp(bytes, page_size) / page_size, - 100 * bytes / header->FileSize()); - } - fprintf(stdout, "\n"); -} - -} // namespace art diff --git a/dexlayout/dex_visualize.h b/dexlayout/dex_visualize.h deleted file mode 100644 index 8406412858..0000000000 --- a/dexlayout/dex_visualize.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * 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 the dexlayout utility. - * - * This is a tool to read dex files into an internal representation, - * reorganize the representation, and emit dex files with a better - * file layout. - */ - -#ifndef ART_DEXLAYOUT_DEX_VISUALIZE_H_ -#define ART_DEXLAYOUT_DEX_VISUALIZE_H_ - -#include <stddef.h> - -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, - ProfileCompilationInfo* profile_info); - -void ShowDexSectionStatistics(dex_ir::Header* header, size_t dex_file_index, size_t page_size); - -} // namespace art - -#endif // ART_DEXLAYOUT_DEX_VISUALIZE_H_ diff --git a/dexlayout/dex_writer.cc b/dexlayout/dex_writer.cc deleted file mode 100644 index c1cf6cdfb6..0000000000 --- a/dexlayout/dex_writer.cc +++ /dev/null @@ -1,1007 +0,0 @@ -/* - * 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. - */ - -#include "dex_writer.h" - -#include <stdint.h> - -#include <vector> - -#include "compact_dex_writer.h" -#include "dex/compact_dex_file.h" -#include "dex/dex_file_layout.h" -#include "dex/dex_file_types.h" -#include "dex/standard_dex_file.h" -#include "dex/utf.h" -#include "dexlayout.h" - -namespace art { - -static 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; -} - -static 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; -} - -static 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_; -}; - -static 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_; -}; - -static 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; -} - -DexWriter::DexWriter(DexLayout* dex_layout, bool compute_offsets) - : header_(dex_layout->GetHeader()), - dex_layout_(dex_layout), - compute_offsets_(compute_offsets) {} - -void DexWriter::WriteEncodedValue(Stream* stream, dex_ir::EncodedValue* encoded_value) { - 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::kDexAnnotationMethodType: - length = EncodeUIntValue(encoded_value->GetProtoId()->GetIndex(), buffer); - break; - case DexFile::kDexAnnotationMethodHandle: - length = EncodeUIntValue(encoded_value->GetMethodHandle()->GetIndex(), buffer); - 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: - WriteEncodedValueHeader(stream, type, 0); - WriteEncodedArray(stream, encoded_value->GetEncodedArray()->GetEncodedValues()); - return; - case DexFile::kDexAnnotationAnnotation: - WriteEncodedValueHeader(stream, type, 0); - WriteEncodedAnnotation(stream, encoded_value->GetEncodedAnnotation()); - return; - case DexFile::kDexAnnotationNull: - WriteEncodedValueHeader(stream, type, 0); - return; - case DexFile::kDexAnnotationBoolean: - WriteEncodedValueHeader(stream, type, encoded_value->GetBoolean() ? 1 : 0); - return; - default: - return; - } - WriteEncodedValueHeader(stream, type, length - 1); - stream->Write(buffer + start, length); -} - -void DexWriter::WriteEncodedValueHeader(Stream* stream, int8_t value_type, size_t value_arg) { - uint8_t buffer[1] = { static_cast<uint8_t>((value_arg << 5) | value_type) }; - stream->Write(buffer, sizeof(uint8_t)); -} - -void DexWriter::WriteEncodedArray(Stream* stream, dex_ir::EncodedValueVector* values) { - stream->WriteUleb128(values->size()); - for (std::unique_ptr<dex_ir::EncodedValue>& value : *values) { - WriteEncodedValue(stream, value.get()); - } -} - -void DexWriter::WriteEncodedAnnotation(Stream* stream, dex_ir::EncodedAnnotation* annotation) { - stream->WriteUleb128(annotation->GetType()->GetIndex()); - stream->WriteUleb128(annotation->GetAnnotationElements()->size()); - for (std::unique_ptr<dex_ir::AnnotationElement>& annotation_element : - *annotation->GetAnnotationElements()) { - stream->WriteUleb128(annotation_element->GetName()->GetIndex()); - WriteEncodedValue(stream, annotation_element->GetValue()); - } -} - -void DexWriter::WriteEncodedFields(Stream* stream, dex_ir::FieldItemVector* fields) { - uint32_t prev_index = 0; - for (auto& field : *fields) { - uint32_t index = field.GetFieldId()->GetIndex(); - stream->WriteUleb128(index - prev_index); - stream->WriteUleb128(field.GetAccessFlags()); - prev_index = index; - } -} - -void DexWriter::WriteEncodedMethods(Stream* stream, dex_ir::MethodItemVector* methods) { - uint32_t prev_index = 0; - for (auto& method : *methods) { - uint32_t index = method.GetMethodId()->GetIndex(); - uint32_t code_off = method.GetCodeItem() == nullptr ? 0 : method.GetCodeItem()->GetOffset(); - stream->WriteUleb128(index - prev_index); - stream->WriteUleb128(method.GetAccessFlags()); - stream->WriteUleb128(code_off); - prev_index = index; - } -} - -// TODO: Refactor this to remove duplicated boiler plate. One way to do this is adding -// function that takes a CollectionVector<T> and uses overloading. -void DexWriter::WriteStringIds(Stream* stream, bool reserve_only) { - const uint32_t start = stream->Tell(); - for (auto& string_id : header_->StringIds()) { - stream->AlignTo(SectionAlignment(DexFile::kDexTypeStringIdItem)); - if (reserve_only) { - stream->Skip(string_id->GetSize()); - } else { - uint32_t string_data_off = string_id->DataItem()->GetOffset(); - stream->Write(&string_data_off, string_id->GetSize()); - } - } - if (compute_offsets_ && start != stream->Tell()) { - header_->StringIds().SetOffset(start); - } -} - -void DexWriter::WriteStringData(Stream* stream, dex_ir::StringData* string_data) { - ProcessOffset(stream, string_data); - stream->AlignTo(SectionAlignment(DexFile::kDexTypeStringDataItem)); - stream->WriteUleb128(CountModifiedUtf8Chars(string_data->Data())); - stream->Write(string_data->Data(), strlen(string_data->Data())); - // Skip null terminator (already zeroed out, no need to write). - stream->Skip(1); -} - -void DexWriter::WriteStringDatas(Stream* stream) { - const uint32_t start = stream->Tell(); - for (auto& string_data : header_->StringDatas()) { - WriteStringData(stream, string_data.get()); - } - if (compute_offsets_ && start != stream->Tell()) { - header_->StringDatas().SetOffset(start); - } -} - -void DexWriter::WriteTypeIds(Stream* stream) { - uint32_t descriptor_idx[1]; - const uint32_t start = stream->Tell(); - for (auto& type_id : header_->TypeIds()) { - stream->AlignTo(SectionAlignment(DexFile::kDexTypeTypeIdItem)); - ProcessOffset(stream, type_id.get()); - descriptor_idx[0] = type_id->GetStringId()->GetIndex(); - stream->Write(descriptor_idx, type_id->GetSize()); - } - if (compute_offsets_ && start != stream->Tell()) { - header_->TypeIds().SetOffset(start); - } -} - -void DexWriter::WriteTypeLists(Stream* stream) { - uint32_t size[1]; - uint16_t list[1]; - const uint32_t start = stream->Tell(); - for (auto& type_list : header_->TypeLists()) { - stream->AlignTo(SectionAlignment(DexFile::kDexTypeTypeList)); - size[0] = type_list->GetTypeList()->size(); - ProcessOffset(stream, type_list.get()); - stream->Write(size, sizeof(uint32_t)); - for (const dex_ir::TypeId* type_id : *type_list->GetTypeList()) { - list[0] = type_id->GetIndex(); - stream->Write(list, sizeof(uint16_t)); - } - } - if (compute_offsets_ && start != stream->Tell()) { - header_->TypeLists().SetOffset(start); - } -} - -void DexWriter::WriteProtoIds(Stream* stream, bool reserve_only) { - uint32_t buffer[3]; - const uint32_t start = stream->Tell(); - for (auto& proto_id : header_->ProtoIds()) { - stream->AlignTo(SectionAlignment(DexFile::kDexTypeProtoIdItem)); - ProcessOffset(stream, proto_id.get()); - if (reserve_only) { - stream->Skip(proto_id->GetSize()); - } else { - buffer[0] = proto_id->Shorty()->GetIndex(); - buffer[1] = proto_id->ReturnType()->GetIndex(); - buffer[2] = proto_id->Parameters() == nullptr ? 0 : proto_id->Parameters()->GetOffset(); - stream->Write(buffer, proto_id->GetSize()); - } - } - if (compute_offsets_ && start != stream->Tell()) { - header_->ProtoIds().SetOffset(start); - } -} - -void DexWriter::WriteFieldIds(Stream* stream) { - uint16_t buffer[4]; - const uint32_t start = stream->Tell(); - for (auto& field_id : header_->FieldIds()) { - stream->AlignTo(SectionAlignment(DexFile::kDexTypeFieldIdItem)); - ProcessOffset(stream, field_id.get()); - 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; - stream->Write(buffer, field_id->GetSize()); - } - if (compute_offsets_ && start != stream->Tell()) { - header_->FieldIds().SetOffset(start); - } -} - -void DexWriter::WriteMethodIds(Stream* stream) { - uint16_t buffer[4]; - const uint32_t start = stream->Tell(); - for (auto& method_id : header_->MethodIds()) { - stream->AlignTo(SectionAlignment(DexFile::kDexTypeMethodIdItem)); - ProcessOffset(stream, method_id.get()); - 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; - stream->Write(buffer, method_id->GetSize()); - } - if (compute_offsets_ && start != stream->Tell()) { - header_->MethodIds().SetOffset(start); - } -} - -void DexWriter::WriteEncodedArrays(Stream* stream) { - const uint32_t start = stream->Tell(); - for (auto& encoded_array : header_->EncodedArrayItems()) { - stream->AlignTo(SectionAlignment(DexFile::kDexTypeEncodedArrayItem)); - ProcessOffset(stream, encoded_array.get()); - WriteEncodedArray(stream, encoded_array->GetEncodedValues()); - } - if (compute_offsets_ && start != stream->Tell()) { - header_->EncodedArrayItems().SetOffset(start); - } -} - -void DexWriter::WriteAnnotations(Stream* stream) { - uint8_t visibility[1]; - const uint32_t start = stream->Tell(); - for (auto& annotation : header_->AnnotationItems()) { - stream->AlignTo(SectionAlignment(DexFile::kDexTypeAnnotationItem)); - visibility[0] = annotation->GetVisibility(); - ProcessOffset(stream, annotation.get()); - stream->Write(visibility, sizeof(uint8_t)); - WriteEncodedAnnotation(stream, annotation->GetAnnotation()); - } - if (compute_offsets_ && start != stream->Tell()) { - header_->AnnotationItems().SetOffset(start); - } -} - -void DexWriter::WriteAnnotationSets(Stream* stream) { - uint32_t size[1]; - uint32_t annotation_off[1]; - const uint32_t start = stream->Tell(); - for (auto& annotation_set : header_->AnnotationSetItems()) { - stream->AlignTo(SectionAlignment(DexFile::kDexTypeAnnotationSetItem)); - size[0] = annotation_set->GetItems()->size(); - ProcessOffset(stream, annotation_set.get()); - stream->Write(size, sizeof(uint32_t)); - for (dex_ir::AnnotationItem* annotation : *annotation_set->GetItems()) { - annotation_off[0] = annotation->GetOffset(); - stream->Write(annotation_off, sizeof(uint32_t)); - } - } - if (compute_offsets_ && start != stream->Tell()) { - header_->AnnotationSetItems().SetOffset(start); - } -} - -void DexWriter::WriteAnnotationSetRefs(Stream* stream) { - uint32_t size[1]; - uint32_t annotations_off[1]; - const uint32_t start = stream->Tell(); - for (auto& annotation_set_ref : header_->AnnotationSetRefLists()) { - stream->AlignTo(SectionAlignment(DexFile::kDexTypeAnnotationSetRefList)); - size[0] = annotation_set_ref->GetItems()->size(); - ProcessOffset(stream, annotation_set_ref.get()); - stream->Write(size, sizeof(uint32_t)); - for (dex_ir::AnnotationSetItem* annotation_set : *annotation_set_ref->GetItems()) { - annotations_off[0] = annotation_set == nullptr ? 0 : annotation_set->GetOffset(); - stream->Write(annotations_off, sizeof(uint32_t)); - } - } - if (compute_offsets_ && start != stream->Tell()) { - header_->AnnotationSetRefLists().SetOffset(start); - } -} - -void DexWriter::WriteAnnotationsDirectories(Stream* stream) { - uint32_t directory_buffer[4]; - uint32_t annotation_buffer[2]; - const uint32_t start = stream->Tell(); - for (auto& annotations_directory : header_->AnnotationsDirectoryItems()) { - stream->AlignTo(SectionAlignment(DexFile::kDexTypeAnnotationsDirectoryItem)); - ProcessOffset(stream, annotations_directory.get()); - 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(); - stream->Write(directory_buffer, 4 * sizeof(uint32_t)); - 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(); - stream->Write(annotation_buffer, 2 * sizeof(uint32_t)); - } - } - 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(); - stream->Write(annotation_buffer, 2 * sizeof(uint32_t)); - } - } - 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(); - stream->Write(annotation_buffer, 2 * sizeof(uint32_t)); - } - } - } - if (compute_offsets_ && start != stream->Tell()) { - header_->AnnotationsDirectoryItems().SetOffset(start); - } -} - -void DexWriter::WriteHiddenapiClassData(Stream* stream) { - if (header_->HiddenapiClassDatas().Empty()) { - return; - } - DCHECK_EQ(header_->HiddenapiClassDatas().Size(), header_->ClassDefs().Size()); - - stream->AlignTo(SectionAlignment(DexFile::kDexTypeHiddenapiClassData)); - ProcessOffset(stream, &header_->HiddenapiClassDatas()); - const uint32_t start = stream->Tell(); - - // Compute offsets for each class def and write the header. - // data_header[0]: total size of the section - // data_header[i + 1]: offset of class def[i] from the beginning of the section, - // or zero if no data - std::vector<uint32_t> data_header(header_->ClassDefs().Size() + 1, 0); - data_header[0] = sizeof(uint32_t) * (header_->ClassDefs().Size() + 1); - for (uint32_t i = 0; i < header_->ClassDefs().Size(); ++i) { - uint32_t item_size = header_->HiddenapiClassDatas()[i]->ItemSize(); - data_header[i + 1] = item_size == 0u ? 0 : data_header[0]; - data_header[0] += item_size; - } - stream->Write(data_header.data(), sizeof(uint32_t) * data_header.size()); - - // Write class data streams. - for (uint32_t i = 0; i < header_->ClassDefs().Size(); ++i) { - dex_ir::ClassDef* class_def = header_->ClassDefs()[i]; - const auto& item = header_->HiddenapiClassDatas()[i]; - DCHECK(item->GetClassDef() == class_def); - - if (data_header[i + 1] != 0u) { - dex_ir::ClassData* class_data = class_def->GetClassData(); - DCHECK(class_data != nullptr); - DCHECK_EQ(data_header[i + 1], stream->Tell() - start); - for (const dex_ir::FieldItem& field : *class_data->StaticFields()) { - stream->WriteUleb128(item->GetFlags(&field)); - } - for (const dex_ir::FieldItem& field : *class_data->InstanceFields()) { - stream->WriteUleb128(item->GetFlags(&field)); - } - for (const dex_ir::MethodItem& method : *class_data->DirectMethods()) { - stream->WriteUleb128(item->GetFlags(&method)); - } - for (const dex_ir::MethodItem& method : *class_data->VirtualMethods()) { - stream->WriteUleb128(item->GetFlags(&method)); - } - } - } - DCHECK_EQ(stream->Tell() - start, data_header[0]); - - if (compute_offsets_ && start != stream->Tell()) { - header_->HiddenapiClassDatas().SetOffset(start); - } -} - -void DexWriter::WriteDebugInfoItem(Stream* stream, dex_ir::DebugInfoItem* debug_info) { - stream->AlignTo(SectionAlignment(DexFile::kDexTypeDebugInfoItem)); - ProcessOffset(stream, debug_info); - stream->Write(debug_info->GetDebugInfo(), debug_info->GetDebugInfoSize()); -} - -void DexWriter::WriteDebugInfoItems(Stream* stream) { - const uint32_t start = stream->Tell(); - for (auto& debug_info : header_->DebugInfoItems()) { - WriteDebugInfoItem(stream, debug_info.get()); - } - if (compute_offsets_ && start != stream->Tell()) { - header_->DebugInfoItems().SetOffset(start); - } -} - -void DexWriter::WriteCodeItemPostInstructionData(Stream* stream, - dex_ir::CodeItem* code_item, - bool reserve_only) { - if (code_item->TriesSize() != 0) { - stream->AlignTo(dex::TryItem::kAlignment); - // Write try items. - for (std::unique_ptr<const dex_ir::TryItem>& try_item : *code_item->Tries()) { - dex::TryItem disk_try_item; - if (!reserve_only) { - disk_try_item.start_addr_ = try_item->StartAddr(); - disk_try_item.insn_count_ = try_item->InsnCount(); - disk_try_item.handler_off_ = try_item->GetHandlers()->GetListOffset(); - } - stream->Write(&disk_try_item, sizeof(disk_try_item)); - } - // Leave offset pointing to the end of the try items. - const size_t offset = stream->Tell(); - size_t max_offset = offset + stream->WriteUleb128(code_item->Handlers()->size()); - for (std::unique_ptr<const dex_ir::CatchHandler>& handlers : *code_item->Handlers()) { - stream->Seek(offset + handlers->GetListOffset()); - uint32_t size = handlers->HasCatchAll() ? (handlers->GetHandlers()->size() - 1) * -1 : - handlers->GetHandlers()->size(); - stream->WriteSleb128(size); - for (std::unique_ptr<const dex_ir::TypeAddrPair>& handler : *handlers->GetHandlers()) { - if (handler->GetTypeId() != nullptr) { - stream->WriteUleb128(handler->GetTypeId()->GetIndex()); - } - stream->WriteUleb128(handler->GetAddress()); - } - // TODO: Clean this up to write the handlers in address order. - max_offset = std::max(max_offset, stream->Tell()); - } - stream->Seek(max_offset); - } -} - -void DexWriter::WriteCodeItem(Stream* stream, - dex_ir::CodeItem* code_item, - bool reserve_only) { - DCHECK(code_item != nullptr); - const uint32_t start_offset = stream->Tell(); - stream->AlignTo(SectionAlignment(DexFile::kDexTypeCodeItem)); - ProcessOffset(stream, code_item); - - StandardDexFile::CodeItem disk_code_item; - if (!reserve_only) { - disk_code_item.registers_size_ = code_item->RegistersSize(); - disk_code_item.ins_size_ = code_item->InsSize(); - disk_code_item.outs_size_ = code_item->OutsSize(); - disk_code_item.tries_size_ = code_item->TriesSize(); - disk_code_item.debug_info_off_ = code_item->DebugInfo() == nullptr - ? 0 - : code_item->DebugInfo()->GetOffset(); - disk_code_item.insns_size_in_code_units_ = code_item->InsnsSize(); - } - // Avoid using sizeof so that we don't write the fake instruction array at the end of the code - // item. - stream->Write(&disk_code_item, OFFSETOF_MEMBER(StandardDexFile::CodeItem, insns_)); - // Write the instructions. - stream->Write(code_item->Insns(), code_item->InsnsSize() * sizeof(uint16_t)); - // Write the post instruction data. - WriteCodeItemPostInstructionData(stream, code_item, reserve_only); - if (reserve_only) { - stream->Clear(start_offset, stream->Tell() - start_offset); - } -} - -void DexWriter::WriteCodeItems(Stream* stream, bool reserve_only) { - DexLayoutSection* code_section = nullptr; - if (!reserve_only && dex_layout_ != nullptr) { - code_section = &dex_layout_->GetSections().sections_[static_cast<size_t>( - DexLayoutSections::SectionType::kSectionTypeCode)]; - } - const uint32_t start = stream->Tell(); - for (auto& code_item : header_->CodeItems()) { - uint32_t start_offset = stream->Tell(); - WriteCodeItem(stream, code_item.get(), reserve_only); - // Only add the section hotness info once. - if (!reserve_only && code_section != nullptr) { - auto it = dex_layout_->LayoutHotnessInfo().code_item_layout_.find(code_item.get()); - if (it != dex_layout_->LayoutHotnessInfo().code_item_layout_.end()) { - code_section->parts_[static_cast<size_t>(it->second)].CombineSection( - start_offset, - stream->Tell()); - } - } - } - - if (compute_offsets_ && start != stream->Tell()) { - header_->CodeItems().SetOffset(start); - } -} - -void DexWriter::WriteClassDefs(Stream* stream, bool reserve_only) { - const uint32_t start = stream->Tell(); - uint32_t class_def_buffer[8]; - for (auto& class_def : header_->ClassDefs()) { - stream->AlignTo(SectionAlignment(DexFile::kDexTypeClassDefItem)); - if (reserve_only) { - stream->Skip(class_def->GetSize()); - } else { - class_def_buffer[0] = class_def->ClassType()->GetIndex(); - class_def_buffer[1] = class_def->GetAccessFlags(); - class_def_buffer[2] = class_def->Superclass() == nullptr ? dex::kDexNoIndex : - class_def->Superclass()->GetIndex(); - class_def_buffer[3] = class_def->InterfacesOffset(); - class_def_buffer[4] = class_def->SourceFile() == nullptr ? dex::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(); - stream->Write(class_def_buffer, class_def->GetSize()); - } - } - if (compute_offsets_ && start != stream->Tell()) { - header_->ClassDefs().SetOffset(start); - } -} - -void DexWriter::WriteClassDatas(Stream* stream) { - const uint32_t start = stream->Tell(); - for (const std::unique_ptr<dex_ir::ClassData>& class_data : - header_->ClassDatas()) { - stream->AlignTo(SectionAlignment(DexFile::kDexTypeClassDataItem)); - ProcessOffset(stream, class_data.get()); - stream->WriteUleb128(class_data->StaticFields()->size()); - stream->WriteUleb128(class_data->InstanceFields()->size()); - stream->WriteUleb128(class_data->DirectMethods()->size()); - stream->WriteUleb128(class_data->VirtualMethods()->size()); - WriteEncodedFields(stream, class_data->StaticFields()); - WriteEncodedFields(stream, class_data->InstanceFields()); - WriteEncodedMethods(stream, class_data->DirectMethods()); - WriteEncodedMethods(stream, class_data->VirtualMethods()); - } - if (compute_offsets_ && start != stream->Tell()) { - header_->ClassDatas().SetOffset(start); - } -} - -void DexWriter::WriteCallSiteIds(Stream* stream, bool reserve_only) { - const uint32_t start = stream->Tell(); - uint32_t call_site_off[1]; - for (auto& call_site_id : header_->CallSiteIds()) { - stream->AlignTo(SectionAlignment(DexFile::kDexTypeCallSiteIdItem)); - if (reserve_only) { - stream->Skip(call_site_id->GetSize()); - } else { - call_site_off[0] = call_site_id->CallSiteItem()->GetOffset(); - stream->Write(call_site_off, call_site_id->GetSize()); - } - } - if (compute_offsets_ && start != stream->Tell()) { - header_->CallSiteIds().SetOffset(start); - } -} - -void DexWriter::WriteMethodHandles(Stream* stream) { - const uint32_t start = stream->Tell(); - uint16_t method_handle_buff[4]; - for (auto& method_handle : header_->MethodHandleItems()) { - stream->AlignTo(SectionAlignment(DexFile::kDexTypeMethodHandleItem)); - method_handle_buff[0] = static_cast<uint16_t>(method_handle->GetMethodHandleType()); - method_handle_buff[1] = 0; // unused. - method_handle_buff[2] = method_handle->GetFieldOrMethodId()->GetIndex(); - method_handle_buff[3] = 0; // unused. - stream->Write(method_handle_buff, method_handle->GetSize()); - } - if (compute_offsets_ && start != stream->Tell()) { - header_->MethodHandleItems().SetOffset(start); - } -} - -void DexWriter::WriteMapItems(Stream* stream, MapItemQueue* queue) { - // All the sections should already have been added. - const uint32_t map_list_size = queue->size(); - stream->Write(&map_list_size, sizeof(map_list_size)); - while (!queue->empty()) { - const MapItem& item = queue->top(); - dex::MapItem map_item; - map_item.type_ = item.type_; - map_item.size_ = item.size_; - map_item.offset_ = item.offset_; - map_item.unused_ = 0u; - stream->Write(&map_item, sizeof(map_item)); - queue->pop(); - } -} - -void DexWriter::GenerateAndWriteMapItems(Stream* stream) { - MapItemQueue queue; - - // Header and index section. - queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeHeaderItem, 1, 0)); - queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeStringIdItem, - header_->StringIds().Size(), - header_->StringIds().GetOffset())); - queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeTypeIdItem, - header_->TypeIds().Size(), - header_->TypeIds().GetOffset())); - queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeProtoIdItem, - header_->ProtoIds().Size(), - header_->ProtoIds().GetOffset())); - queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeFieldIdItem, - header_->FieldIds().Size(), - header_->FieldIds().GetOffset())); - queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeMethodIdItem, - header_->MethodIds().Size(), - header_->MethodIds().GetOffset())); - queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeClassDefItem, - header_->ClassDefs().Size(), - header_->ClassDefs().GetOffset())); - queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeCallSiteIdItem, - header_->CallSiteIds().Size(), - header_->CallSiteIds().GetOffset())); - queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeMethodHandleItem, - header_->MethodHandleItems().Size(), - header_->MethodHandleItems().GetOffset())); - // Data section. - queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeMapList, 1, header_->MapListOffset())); - queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeTypeList, - header_->TypeLists().Size(), - header_->TypeLists().GetOffset())); - queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeAnnotationSetRefList, - header_->AnnotationSetRefLists().Size(), - header_->AnnotationSetRefLists().GetOffset())); - queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeAnnotationSetItem, - header_->AnnotationSetItems().Size(), - header_->AnnotationSetItems().GetOffset())); - queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeClassDataItem, - header_->ClassDatas().Size(), - header_->ClassDatas().GetOffset())); - queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeCodeItem, - header_->CodeItems().Size(), - header_->CodeItems().GetOffset())); - queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeStringDataItem, - header_->StringDatas().Size(), - header_->StringDatas().GetOffset())); - queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeDebugInfoItem, - header_->DebugInfoItems().Size(), - header_->DebugInfoItems().GetOffset())); - queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeAnnotationItem, - header_->AnnotationItems().Size(), - header_->AnnotationItems().GetOffset())); - queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeEncodedArrayItem, - header_->EncodedArrayItems().Size(), - header_->EncodedArrayItems().GetOffset())); - queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeAnnotationsDirectoryItem, - header_->AnnotationsDirectoryItems().Size(), - header_->AnnotationsDirectoryItems().GetOffset())); - queue.AddIfNotEmpty(MapItem(DexFile::kDexTypeHiddenapiClassData, - header_->HiddenapiClassDatas().Empty() ? 0u : 1u, - header_->HiddenapiClassDatas().GetOffset())); - WriteMapItems(stream, &queue); -} - -void DexWriter::WriteHeader(Stream* stream) { - StandardDexFile::HeaderV41 header{}; - if (CompactDexFile::IsMagicValid(header_->Magic())) { - StandardDexFile::WriteMagic(header.magic_.data()); - if (header_->SupportDefaultMethods()) { - StandardDexFile::WriteCurrentVersion(header.magic_.data()); - } else { - StandardDexFile::WriteVersionBeforeDefaultMethods(header.magic_.data()); - } - } else { - // Standard dex -> standard dex, just reuse the same header. - header.magic_ = header_->Magic(); - } - header.checksum_ = header_->Checksum(); - header.signature_ = header_->Signature(); - header.file_size_ = header_->FileSize(); - header.header_size_ = GetHeaderSize(); - header.endian_tag_ = header_->EndianTag(); - header.link_size_ = header_->LinkSize(); - header.link_off_ = header_->LinkOffset(); - header.map_off_ = header_->MapListOffset(); - header.string_ids_size_ = header_->StringIds().Size(); - header.string_ids_off_ = header_->StringIds().GetOffset(); - header.type_ids_size_ = header_->TypeIds().Size(); - header.type_ids_off_ = header_->TypeIds().GetOffset(); - header.proto_ids_size_ = header_->ProtoIds().Size(); - header.proto_ids_off_ = header_->ProtoIds().GetOffset(); - header.field_ids_size_ = header_->FieldIds().Size(); - header.field_ids_off_ = header_->FieldIds().GetOffset(); - header.method_ids_size_ = header_->MethodIds().Size(); - header.method_ids_off_ = header_->MethodIds().GetOffset(); - header.class_defs_size_ = header_->ClassDefs().Size(); - header.class_defs_off_ = header_->ClassDefs().GetOffset(); - header.data_size_ = header_->DataSize(); - header.data_off_ = header_->DataOffset(); - header.SetDexContainer(0, header_->FileSize()); - - static_assert(sizeof(header) == 0x78, "Size doesn't match dex spec"); - stream->Seek(0); - stream->Overwrite(reinterpret_cast<uint8_t*>(&header), GetHeaderSize()); -} - -size_t DexWriter::GetHeaderSize() const { - return header_->Magic() == DexFile::Magic{'d', 'e', 'x', '\n', '0', '4', '1', '\0'} ? - sizeof(StandardDexFile::HeaderV41) : - sizeof(StandardDexFile::Header); -} - -bool DexWriter::Write(DexContainer* output, std::string* error_msg) { - DCHECK(error_msg != nullptr); - - Stream stream_storage(output->GetMainSection()); - Stream* stream = &stream_storage; - - // Starting offset is right after the header. - stream->Seek(GetHeaderSize()); - - // Based on: https://source.android.com/devices/tech/dalvik/dex-format - // Since the offsets may not be calculated already, the writing must be done in the correct order. - const uint32_t string_ids_offset = stream->Tell(); - WriteStringIds(stream, /*reserve_only=*/ true); - WriteTypeIds(stream); - const uint32_t proto_ids_offset = stream->Tell(); - WriteProtoIds(stream, /*reserve_only=*/ true); - WriteFieldIds(stream); - WriteMethodIds(stream); - const uint32_t class_defs_offset = stream->Tell(); - WriteClassDefs(stream, /*reserve_only=*/ true); - const uint32_t call_site_ids_offset = stream->Tell(); - WriteCallSiteIds(stream, /*reserve_only=*/ true); - WriteMethodHandles(stream); - - uint32_t data_offset_ = 0u; - if (compute_offsets_) { - // Data section. - stream->AlignTo(kDataSectionAlignment); - data_offset_ = stream->Tell(); - } - - // Write code item first to minimize the space required for encoded methods. - // Reserve code item space since we need the debug offsets to actually write them. - const uint32_t code_items_offset = stream->Tell(); - WriteCodeItems(stream, /*reserve_only=*/ true); - // Write debug info section. - WriteDebugInfoItems(stream); - { - // Actually write code items since debug info offsets are calculated now. - Stream::ScopedSeek seek(stream, code_items_offset); - WriteCodeItems(stream, /*reserve_only=*/ false); - } - - WriteEncodedArrays(stream); - WriteAnnotations(stream); - WriteAnnotationSets(stream); - WriteAnnotationSetRefs(stream); - WriteAnnotationsDirectories(stream); - WriteTypeLists(stream); - WriteClassDatas(stream); - WriteStringDatas(stream); - WriteHiddenapiClassData(stream); - - // Write delayed id sections that depend on data sections. - { - Stream::ScopedSeek seek(stream, string_ids_offset); - WriteStringIds(stream, /*reserve_only=*/ false); - } - { - Stream::ScopedSeek seek(stream, proto_ids_offset); - WriteProtoIds(stream, /*reserve_only=*/ false); - } - { - Stream::ScopedSeek seek(stream, class_defs_offset); - WriteClassDefs(stream, /*reserve_only=*/ false); - } - { - Stream::ScopedSeek seek(stream, call_site_ids_offset); - WriteCallSiteIds(stream, /*reserve_only=*/ false); - } - - // Write the map list. - if (compute_offsets_) { - stream->AlignTo(SectionAlignment(DexFile::kDexTypeMapList)); - header_->SetMapListOffset(stream->Tell()); - } else { - stream->Seek(header_->MapListOffset()); - } - GenerateAndWriteMapItems(stream); - stream->AlignTo(kDataSectionAlignment); - - // Map items are included in the data section. - if (compute_offsets_) { - header_->SetDataSize(stream->Tell() - data_offset_); - if (header_->DataSize() != 0) { - // Offset must be zero when the size is zero. - header_->SetDataOffset(data_offset_); - } else { - header_->SetDataOffset(0u); - } - } - - // Write link data if it exists. - const std::vector<uint8_t>& link_data = header_->LinkData(); - if (link_data.size() > 0) { - CHECK_EQ(header_->LinkSize(), static_cast<uint32_t>(link_data.size())); - if (compute_offsets_) { - header_->SetLinkOffset(stream->Tell()); - } else { - stream->Seek(header_->LinkOffset()); - } - stream->Write(&link_data[0], link_data.size()); - } - - // Write header last. - if (compute_offsets_) { - header_->SetFileSize(stream->Tell()); - } - WriteHeader(stream); - - if (dex_layout_->GetOptions().update_checksum_) { - header_->SetChecksum(DexFile::CalculateChecksum(stream->Begin(), header_->FileSize())); - // Rewrite the header with the calculated checksum. - WriteHeader(stream); - } - - // Trim the map to make it sized as large as the dex file. - output->GetMainSection()->Resize(header_->FileSize()); - return true; -} - -bool DexWriter::Output(DexLayout* dex_layout, - std::unique_ptr<DexContainer>* container, - bool compute_offsets, - std::string* error_msg) { - CHECK(dex_layout != nullptr); - std::unique_ptr<DexWriter> writer; - if (dex_layout->GetOptions().compact_dex_level_ != CompactDexLevel::kCompactDexLevelNone) { - CHECK(compute_offsets) << "Compact dex requires computing offsets"; - writer.reset(new CompactDexWriter(dex_layout)); - } else { - writer.reset(new DexWriter(dex_layout, compute_offsets)); - } - DCHECK(container != nullptr); - if (*container == nullptr) { - *container = writer->CreateDexContainer(); - } - return writer->Write(container->get(), error_msg); -} - -void MapItemQueue::AddIfNotEmpty(const MapItem& item) { - if (item.size_ != 0) { - push(item); - } -} - -void DexWriter::ProcessOffset(Stream* stream, dex_ir::Item* item) { - if (compute_offsets_) { - item->SetOffset(stream->Tell()); - } else { - // Not computing offsets, just use the one in the item. - stream->Seek(item->GetOffset()); - } -} - -void DexWriter::ProcessOffset(Stream* stream, dex_ir::CollectionBase* item) { - if (compute_offsets_) { - item->SetOffset(stream->Tell()); - } else { - // Not computing offsets, just use the one in the item. - stream->Seek(item->GetOffset()); - } -} - -std::unique_ptr<DexContainer> DexWriter::CreateDexContainer() const { - return std::unique_ptr<DexContainer>(new DexWriter::Container); -} - -} // namespace art diff --git a/dexlayout/dex_writer.h b/dexlayout/dex_writer.h deleted file mode 100644 index 62247ec9e2..0000000000 --- a/dexlayout/dex_writer.h +++ /dev/null @@ -1,286 +0,0 @@ -/* - * 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 <functional> -#include <memory> // For unique_ptr - -#include "base/os.h" -#include "base/unix_file/fd_file.h" -#include "dex/compact_dex_level.h" -#include "dex_container.h" -#include "dex/dex_file.h" -#include "dex_ir.h" - -#include <queue> - -namespace art { - -class DexLayout; -class DexLayoutHotnessInfo; - -struct MapItem { - // Not using DexFile::MapItemType since compact dex and standard dex file may have different - // sections. - MapItem() = default; - MapItem(uint32_t type, uint32_t size, size_t offset) - : type_(type), size_(size), offset_(offset) { } - - // Sort by decreasing order since the priority_queue puts largest elements first. - bool operator>(const MapItem& other) const { - return offset_ > other.offset_; - } - - uint32_t type_ = 0u; - uint32_t size_ = 0u; - uint32_t offset_ = 0u; -}; - -class MapItemQueue : public - std::priority_queue<MapItem, std::vector<MapItem>, std::greater<MapItem>> { - public: - void AddIfNotEmpty(const MapItem& item); -}; - -class DexWriter { - public: - static constexpr uint32_t kDataSectionAlignment = sizeof(uint32_t) * 2; - static constexpr uint32_t kDexSectionWordAlignment = 4; - - // Stream that writes into a dex container section. Do not have two streams pointing to the same - // backing storage as there may be invalidation of backing storage to resize the section. - // Random access stream (consider refactoring). - class Stream { - public: - explicit Stream(DexContainer::Section* section) : section_(section) { - SyncWithSection(); - } - - const uint8_t* Begin() const { - return data_; - } - - // Functions are not virtual (yet) for speed. - size_t Tell() const { - return position_; - } - - void Seek(size_t position) { - position_ = position; - EnsureStorage(0u); - } - - // Does not allow overwriting for bug prevention purposes. - ALWAYS_INLINE size_t Write(const void* buffer, size_t length) { - EnsureStorage(length); - for (size_t i = 0; i < length; ++i) { - DCHECK_EQ(data_[position_ + i], 0u); - } - memcpy(&data_[position_], buffer, length); - position_ += length; - return length; - } - - ALWAYS_INLINE size_t Overwrite(const void* buffer, size_t length) { - EnsureStorage(length); - memcpy(&data_[position_], buffer, length); - position_ += length; - return length; - } - - ALWAYS_INLINE size_t Clear(size_t position, size_t length) { - EnsureStorage(length); - memset(&data_[position], 0, length); - return length; - } - - ALWAYS_INLINE size_t WriteSleb128(int32_t value) { - EnsureStorage(8); - uint8_t* ptr = &data_[position_]; - const size_t len = EncodeSignedLeb128(ptr, value) - ptr; - position_ += len; - return len; - } - - ALWAYS_INLINE size_t WriteUleb128(uint32_t value) { - EnsureStorage(8); - uint8_t* ptr = &data_[position_]; - const size_t len = EncodeUnsignedLeb128(ptr, value) - ptr; - position_ += len; - return len; - } - - ALWAYS_INLINE void AlignTo(const size_t alignment) { - position_ = RoundUp(position_, alignment); - EnsureStorage(0u); - } - - ALWAYS_INLINE void Skip(const size_t count) { - position_ += count; - EnsureStorage(0u); - } - - class ScopedSeek { - public: - ScopedSeek(Stream* stream, uint32_t offset) : stream_(stream), offset_(stream->Tell()) { - stream->Seek(offset); - } - - ~ScopedSeek() { - stream_->Seek(offset_); - } - - private: - Stream* const stream_; - const uint32_t offset_; - }; - - private: - ALWAYS_INLINE void EnsureStorage(size_t length) { - size_t end = position_ + length; - while (UNLIKELY(end > data_size_)) { - section_->Resize(data_size_ * 3 / 2 + 1); - SyncWithSection(); - } - } - - void SyncWithSection() { - data_ = section_->Begin(); - data_size_ = section_->Size(); - } - - // Current position of the stream. - size_t position_ = 0u; - DexContainer::Section* const section_ = nullptr; - // Cached Begin() from the container to provide faster accesses. - uint8_t* data_ = nullptr; - // Cached Size from the container to provide faster accesses. - size_t data_size_ = 0u; - }; - - static inline constexpr uint32_t SectionAlignment(DexFile::MapItemType type) { - switch (type) { - case DexFile::kDexTypeClassDataItem: - case DexFile::kDexTypeStringDataItem: - case DexFile::kDexTypeDebugInfoItem: - case DexFile::kDexTypeAnnotationItem: - case DexFile::kDexTypeEncodedArrayItem: - return alignof(uint8_t); - - default: - // All other sections are kDexAlignedSection. - return DexWriter::kDexSectionWordAlignment; - } - } - - class Container : public DexContainer { - public: - Section* GetMainSection() override { - return &main_section_; - } - - Section* GetDataSection() override { - return &data_section_; - } - - bool IsCompactDexContainer() const override { - return false; - } - - private: - VectorSection main_section_; - VectorSection data_section_; - - friend class CompactDexWriter; - }; - - DexWriter(DexLayout* dex_layout, bool compute_offsets); - - static bool Output(DexLayout* dex_layout, - std::unique_ptr<DexContainer>* container, - bool compute_offsets, - std::string* error_msg) WARN_UNUSED; - - virtual ~DexWriter() {} - - protected: - virtual bool Write(DexContainer* output, std::string* error_msg); - virtual std::unique_ptr<DexContainer> CreateDexContainer() const; - - void WriteEncodedValue(Stream* stream, dex_ir::EncodedValue* encoded_value); - void WriteEncodedValueHeader(Stream* stream, int8_t value_type, size_t value_arg); - void WriteEncodedArray(Stream* stream, dex_ir::EncodedValueVector* values); - void WriteEncodedAnnotation(Stream* stream, dex_ir::EncodedAnnotation* annotation); - void WriteEncodedFields(Stream* stream, dex_ir::FieldItemVector* fields); - void WriteEncodedMethods(Stream* stream, dex_ir::MethodItemVector* methods); - - // Header and id section - virtual void WriteHeader(Stream* stream); - virtual size_t GetHeaderSize() const; - // reserve_only means don't write, only reserve space. This is required since the string data - // offsets must be assigned. - void WriteStringIds(Stream* stream, bool reserve_only); - void WriteTypeIds(Stream* stream); - void WriteProtoIds(Stream* stream, bool reserve_only); - void WriteFieldIds(Stream* stream); - void WriteMethodIds(Stream* stream); - void WriteClassDefs(Stream* stream, bool reserve_only); - void WriteCallSiteIds(Stream* stream, bool reserve_only); - - void WriteEncodedArrays(Stream* stream); - void WriteAnnotations(Stream* stream); - void WriteAnnotationSets(Stream* stream); - void WriteAnnotationSetRefs(Stream* stream); - void WriteAnnotationsDirectories(Stream* stream); - - // Data section. - void WriteDebugInfoItems(Stream* stream); - void WriteCodeItems(Stream* stream, bool reserve_only); - void WriteTypeLists(Stream* stream); - void WriteStringDatas(Stream* stream); - void WriteClassDatas(Stream* stream); - void WriteMethodHandles(Stream* stream); - void WriteHiddenapiClassData(Stream* stream); - void WriteMapItems(Stream* stream, MapItemQueue* queue); - void GenerateAndWriteMapItems(Stream* stream); - - virtual void WriteCodeItemPostInstructionData(Stream* stream, - dex_ir::CodeItem* item, - bool reserve_only); - virtual void WriteCodeItem(Stream* stream, dex_ir::CodeItem* item, bool reserve_only); - virtual void WriteDebugInfoItem(Stream* stream, dex_ir::DebugInfoItem* debug_info); - virtual void WriteStringData(Stream* stream, dex_ir::StringData* string_data); - - // Process an offset, if compute_offset is set, write into the dex ir item, otherwise read the - // existing offset and use that for writing. - void ProcessOffset(Stream* stream, dex_ir::Item* item); - void ProcessOffset(Stream* stream, dex_ir::CollectionBase* item); - - dex_ir::Header* const header_; - DexLayout* const dex_layout_; - bool compute_offsets_; - - private: - DISALLOW_COPY_AND_ASSIGN(DexWriter); -}; - -} // namespace art - -#endif // ART_DEXLAYOUT_DEX_WRITER_H_ diff --git a/dexlayout/dexdiag.cc b/dexlayout/dexdiag.cc deleted file mode 100644 index 2821374ef4..0000000000 --- a/dexlayout/dexdiag.cc +++ /dev/null @@ -1,540 +0,0 @@ -/* - * Copyright (C) 2017 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. - */ - -#include <errno.h> -#include <inttypes.h> -#include <stdint.h> -#include <stdlib.h> -#include <string.h> - -#include <iostream> -#include <memory> -#include <string> -#include <string_view> -#include <vector> - -#include "android-base/stringprintf.h" - -#include "base/logging.h" // For InitLogging. -#include "base/string_view_cpp20.h" - -#include "dexlayout.h" -#include "dex/dex_file.h" -#include "dex_ir.h" -#include "dex_ir_builder.h" -#ifdef ART_TARGET_ANDROID -#include <meminfo/pageacct.h> -#include <meminfo/procmeminfo.h> -#endif -#include "vdex_file.h" - -namespace art { - -using android::base::StringPrintf; -#ifdef ART_TARGET_ANDROID -using android::meminfo::ProcMemInfo; -using android::meminfo::Vma; -#endif - -static bool g_verbose = false; - -// The width needed to print a file page offset (32-bit). -static constexpr int kPageCountWidth = - static_cast<int>(std::numeric_limits<uint32_t>::digits10); -// Display the sections. -static constexpr char kSectionHeader[] = "Section name"; - -struct DexSectionInfo { - public: - std::string name; - char letter; -}; - -static const std::map<uint16_t, DexSectionInfo> kDexSectionInfoMap = { - { DexFile::kDexTypeHeaderItem, { "Header", 'H' } }, - { DexFile::kDexTypeStringIdItem, { "StringId", 'S' } }, - { DexFile::kDexTypeTypeIdItem, { "TypeId", 'T' } }, - { DexFile::kDexTypeProtoIdItem, { "ProtoId", 'P' } }, - { DexFile::kDexTypeFieldIdItem, { "FieldId", 'F' } }, - { DexFile::kDexTypeMethodIdItem, { "MethodId", 'M' } }, - { DexFile::kDexTypeClassDefItem, { "ClassDef", 'C' } }, - { DexFile::kDexTypeCallSiteIdItem, { "CallSiteId", 'z' } }, - { DexFile::kDexTypeMethodHandleItem, { "MethodHandle", 'Z' } }, - { DexFile::kDexTypeMapList, { "TypeMap", 'L' } }, - { DexFile::kDexTypeTypeList, { "TypeList", 't' } }, - { DexFile::kDexTypeAnnotationSetRefList, { "AnnotationSetReferenceItem", '1' } }, - { DexFile::kDexTypeAnnotationSetItem, { "AnnotationSetItem", '2' } }, - { DexFile::kDexTypeClassDataItem, { "ClassData", 'c' } }, - { DexFile::kDexTypeCodeItem, { "CodeItem", 'X' } }, - { DexFile::kDexTypeStringDataItem, { "StringData", 's' } }, - { DexFile::kDexTypeDebugInfoItem, { "DebugInfo", 'D' } }, - { DexFile::kDexTypeAnnotationItem, { "AnnotationItem", '3' } }, - { DexFile::kDexTypeEncodedArrayItem, { "EncodedArrayItem", 'E' } }, - { DexFile::kDexTypeAnnotationsDirectoryItem, { "AnnotationsDirectoryItem", '4' } } -}; - -class PageCount { - public: - PageCount() { - for (auto it = kDexSectionInfoMap.begin(); it != kDexSectionInfoMap.end(); ++it) { - map_[it->first] = 0; - } - } - void Increment(uint16_t type) { - map_[type]++; - } - size_t Get(uint16_t type) const { - auto it = map_.find(type); - DCHECK(it != map_.end()); - return it->second; - } - private: - std::map<uint16_t, size_t> map_; - DISALLOW_COPY_AND_ASSIGN(PageCount); -}; - -class Printer { - public: - Printer() : section_header_width_(ComputeHeaderWidth()) { - } - - void PrintHeader() const { - std::cout << StringPrintf("%-*s %*s %*s %% of %% of", - section_header_width_, - kSectionHeader, - kPageCountWidth, - "resident", - kPageCountWidth, - "total" - ) - << std::endl; - std::cout << StringPrintf("%-*s %*s %*s sect. total", - section_header_width_, - "", - kPageCountWidth, - "pages", - kPageCountWidth, - "pages") - << std::endl; - } - - void PrintOne(const char* name, - size_t resident, - size_t mapped, - double percent_of_section, - double percent_of_total) const { - // 6.2 is sufficient to print 0-100% with two decimal places of accuracy. - std::cout << StringPrintf("%-*s %*zd %*zd %6.2f %6.2f", - section_header_width_, - name, - kPageCountWidth, - resident, - kPageCountWidth, - mapped, - percent_of_section, - percent_of_total) - << std::endl; - } - - void PrintSkipLine() const { std::cout << std::endl; } - - // Computes the width of the section header column in the table (for fixed formatting). - static int ComputeHeaderWidth() { - int header_width = 0; - for (const auto& pair : kDexSectionInfoMap) { - const DexSectionInfo& section_info = pair.second; - header_width = std::max(header_width, static_cast<int>(section_info.name.length())); - } - return header_width; - } - - private: - const int section_header_width_; -}; - -static void PrintLetterKey() { - std::cout << "L pagetype" << std::endl; - for (const auto& pair : kDexSectionInfoMap) { - const DexSectionInfo& section_info = pair.second; - std::cout << section_info.letter << " " << section_info.name.c_str() << std::endl; - } - std::cout << "* (Executable page resident)" << std::endl; - std::cout << ". (Mapped page not resident)" << std::endl; -} - -#ifdef ART_TARGET_ANDROID -static char PageTypeChar(uint16_t type) { - if (kDexSectionInfoMap.find(type) == kDexSectionInfoMap.end()) { - return '-'; - } - return kDexSectionInfoMap.find(type)->second.letter; -} - -static uint16_t FindSectionTypeForPage(size_t page, - const std::vector<dex_ir::DexFileSection>& sections) { - for (const auto& section : sections) { - size_t first_page_of_section = section.offset / MemMap::GetPageSize(); - // Only consider non-empty sections. - if (section.size == 0) { - continue; - } - // Attribute the page to the highest-offset section that starts before the page. - if (first_page_of_section <= page) { - return section.type; - } - } - // If there's no non-zero sized section with an offset below offset we're looking for, it - // must be the header. - return DexFile::kDexTypeHeaderItem; -} - -static void ProcessPageMap(const std::vector<uint64_t>& pagemap, - size_t start, - size_t end, - const std::vector<dex_ir::DexFileSection>& sections, - PageCount* page_counts) { - static constexpr size_t kLineLength = 32; - for (size_t page = start; page < end; ++page) { - char type_char = '.'; - if (::android::meminfo::page_present(pagemap[page])) { - const size_t dex_page_offset = page - start; - uint16_t type = FindSectionTypeForPage(dex_page_offset, sections); - page_counts->Increment(type); - type_char = PageTypeChar(type); - } - if (g_verbose) { - std::cout << type_char; - if ((page - start) % kLineLength == kLineLength - 1) { - std::cout << std::endl; - } - } - } - if (g_verbose) { - if ((end - start) % kLineLength != 0) { - std::cout << std::endl; - } - } -} - -static void DisplayDexStatistics(size_t start, - size_t end, - const PageCount& resident_pages, - const std::vector<dex_ir::DexFileSection>& sections, - Printer* printer) { - // Compute the total possible sizes for sections. - PageCount mapped_pages; - DCHECK_GE(end, start); - size_t total_mapped_pages = end - start; - if (total_mapped_pages == 0) { - return; - } - for (size_t page = start; page < end; ++page) { - const size_t dex_page_offset = page - start; - mapped_pages.Increment(FindSectionTypeForPage(dex_page_offset, sections)); - } - size_t total_resident_pages = 0; - printer->PrintHeader(); - for (size_t i = sections.size(); i > 0; --i) { - const dex_ir::DexFileSection& section = sections[i - 1]; - const uint16_t type = section.type; - const DexSectionInfo& section_info = kDexSectionInfoMap.find(type)->second; - size_t pages_resident = resident_pages.Get(type); - double percent_resident = 0; - if (mapped_pages.Get(type) > 0) { - percent_resident = 100.0 * pages_resident / mapped_pages.Get(type); - } - printer->PrintOne(section_info.name.c_str(), - pages_resident, - mapped_pages.Get(type), - percent_resident, - 100.0 * pages_resident / total_mapped_pages); - total_resident_pages += pages_resident; - } - double percent_of_total = 100.0 * total_resident_pages / total_mapped_pages; - printer->PrintOne("GRAND TOTAL", - total_resident_pages, - total_mapped_pages, - percent_of_total, - percent_of_total); - printer->PrintSkipLine(); -} - -static void ProcessOneDexMapping(const std::vector<uint64_t>& pagemap, - uint64_t map_start, - const DexFile* dex_file, - uint64_t vdex_start, - Printer* printer) { - uint64_t dex_file_start = reinterpret_cast<uint64_t>(dex_file->Begin()); - size_t dex_file_size = dex_file->Size(); - if (dex_file_start < vdex_start) { - std::cerr << "Dex file start offset for " - << dex_file->GetLocation().c_str() - << " is incorrect: map start " - << StringPrintf("%" PRIx64 " > dex start %" PRIx64 "\n", map_start, dex_file_start) - << std::endl; - return; - } - uint64_t start_page = (dex_file_start - vdex_start) / MemMap::GetPageSize(); - uint64_t start_address = start_page * MemMap::GetPageSize(); - uint64_t end_page = RoundUp(start_address + dex_file_size, - MemMap::GetPageSize()) / MemMap::GetPageSize(); - std::cout << "DEX " - << dex_file->GetLocation().c_str() - << StringPrintf(": %" PRIx64 "-%" PRIx64, - map_start + start_page * MemMap::GetPageSize(), - map_start + end_page * MemMap::GetPageSize()) - << std::endl; - // Build a list of the dex file section types, sorted from highest offset to lowest. - std::vector<dex_ir::DexFileSection> sections; - { - Options options; - std::unique_ptr<dex_ir::Header> header(dex_ir::DexIrBuilder(*dex_file, - /*eagerly_assign_offsets=*/ true, - options)); - sections = dex_ir::GetSortedDexFileSections(header.get(), - dex_ir::SortDirection::kSortDescending); - } - PageCount section_resident_pages; - ProcessPageMap(pagemap, start_page, end_page, sections, §ion_resident_pages); - DisplayDexStatistics(start_page, end_page, section_resident_pages, sections, printer); -} - -static bool IsVdexFileMapping(const std::string& mapped_name) { - // Confirm that the map is from a vdex file. - static const char* suffixes[] = { ".vdex" }; - for (const char* suffix : suffixes) { - size_t match_loc = mapped_name.find(suffix); - if (match_loc != std::string::npos && mapped_name.length() == match_loc + strlen(suffix)) { - return true; - } - } - return false; -} - -static bool DisplayMappingIfFromVdexFile(ProcMemInfo& proc, const Vma& vma, Printer* printer) { - std::string vdex_name = vma.name; - // Extract all the dex files from the vdex file. - std::string error_msg; - std::unique_ptr<VdexFile> vdex(VdexFile::Open(vdex_name, - /*writable=*/ false, - /*low_4gb=*/ false, - &error_msg /*out*/)); - if (vdex == nullptr) { - std::cerr << "Could not open vdex file " - << vdex_name - << ": error " - << error_msg - << std::endl; - return false; - } - - std::vector<std::unique_ptr<const DexFile>> dex_files; - if (!vdex->OpenAllDexFiles(&dex_files, &error_msg)) { - std::cerr << "Dex files could not be opened for " - << vdex_name - << ": error " - << error_msg - << std::endl; - return false; - } - // Open the page mapping (one uint64_t per page) for the entire vdex mapping. - std::vector<uint64_t> pagemap; - if (!proc.PageMap(vma, &pagemap)) { - std::cerr << "Error creating pagemap." << std::endl; - return false; - } - // Process the dex files. - std::cout << "MAPPING " - << vma.name - << StringPrintf(": %" PRIx64 "-%" PRIx64, vma.start, vma.end) - << std::endl; - for (const auto& dex_file : dex_files) { - ProcessOneDexMapping(pagemap, - vma.start, - dex_file.get(), - reinterpret_cast<uint64_t>(vdex->Begin()), - printer); - } - return true; -} - -static void ProcessOneOatMapping(const std::vector<uint64_t>& pagemap, - Printer* printer) { - static constexpr size_t kLineLength = 32; - size_t resident_page_count = 0; - for (size_t page = 0; page < pagemap.size(); ++page) { - char type_char = '.'; - if (::android::meminfo::page_present(pagemap[page])) { - ++resident_page_count; - type_char = '*'; - } - if (g_verbose) { - std::cout << type_char; - if (page % kLineLength == kLineLength - 1) { - std::cout << std::endl; - } - } - } - if (g_verbose) { - if (pagemap.size() % kLineLength != 0) { - std::cout << std::endl; - } - } - double percent_of_total = 100.0 * resident_page_count / pagemap.size(); - printer->PrintHeader(); - printer->PrintOne("EXECUTABLE", resident_page_count, pagemap.size(), percent_of_total, percent_of_total); - printer->PrintSkipLine(); -} - -static bool IsOatFileMapping(const std::string& mapped_name) { - // Confirm that the map is from an oat file. - static const char* suffixes[] = { ".odex", ".oat" }; - for (const char* suffix : suffixes) { - size_t match_loc = mapped_name.find(suffix); - if (match_loc != std::string::npos && mapped_name.length() == match_loc + strlen(suffix)) { - return true; - } - } - return false; -} - -static bool DisplayMappingIfFromOatFile(ProcMemInfo& proc, const Vma& vma, Printer* printer) { - // Open the page mapping (one uint64_t per page) for the entire vdex mapping. - std::vector<uint64_t> pagemap; - if (!proc.PageMap(vma, &pagemap) != 0) { - std::cerr << "Error creating pagemap." << std::endl; - return false; - } - // Process the dex files. - std::cout << "MAPPING " - << vma.name - << StringPrintf(": %" PRIx64 "-%" PRIx64, vma.start, vma.end) - << std::endl; - ProcessOneOatMapping(pagemap, printer); - return true; -} - -static bool FilterByNameContains(const std::string& mapped_file_name, - const std::vector<std::string>& name_filters) { - // If no filters were set, everything matches. - if (name_filters.empty()) { - return true; - } - for (const auto& name_contains : name_filters) { - if (mapped_file_name.find(name_contains) != std::string::npos) { - return true; - } - } - return false; -} -#endif - -static void Usage(const char* cmd) { - std::cout << "Usage: " << cmd << " [options] pid" << std::endl - << " --contains=<string>: Display sections containing string." << std::endl - << " --help: Shows this message." << std::endl - << " --verbose: Makes displays verbose." << std::endl; - PrintLetterKey(); -} - -NO_RETURN static void Abort(const char* msg) { - std::cerr << msg; - exit(1); -} - -static int DexDiagMain(int argc, char* argv[]) { - if (argc < 2) { - Usage(argv[0]); - return EXIT_FAILURE; - } - - std::vector<std::string> name_filters; - // TODO: add option to track usage by class name, etc. - for (int i = 1; i < argc - 1; ++i) { - const std::string_view option(argv[i]); - if (option == "--help") { - Usage(argv[0]); - return EXIT_SUCCESS; - } else if (option == "--verbose") { - g_verbose = true; - } else if (StartsWith(option, "--contains=")) { - std::string contains(option.substr(strlen("--contains="))); - name_filters.push_back(contains); - } else { - Usage(argv[0]); - return EXIT_FAILURE; - } - } - - // Art specific set up. - InitLogging(argv, Abort); - MemMap::Init(); - -#ifdef ART_TARGET_ANDROID - pid_t pid; - char* endptr; - pid = (pid_t)strtol(argv[argc - 1], &endptr, 10); - if (*endptr != '\0' || kill(pid, 0) != 0) { - std::cerr << StringPrintf("Invalid PID \"%s\".\n", argv[argc - 1]) << std::endl; - return EXIT_FAILURE; - } - - // get libmeminfo process information. - ProcMemInfo proc(pid); - // Get the set of mappings by the specified process. - // Do not get the map usage stats, they are never used and it can take - // a long time to get this data. - const std::vector<Vma>& maps = proc.MapsWithoutUsageStats(); - if (maps.empty()) { - std::cerr << "Error listing maps." << std::endl; - return EXIT_FAILURE; - } - - bool match_found = false; - // Process the mappings that are due to vdex or oat files. - Printer printer; - for (auto& vma : maps) { - std::string mapped_file_name = vma.name; - // Filter by name contains options (if any). - if (!FilterByNameContains(mapped_file_name, name_filters)) { - continue; - } - if (IsVdexFileMapping(mapped_file_name)) { - if (!DisplayMappingIfFromVdexFile(proc, vma, &printer)) { - return EXIT_FAILURE; - } - match_found = true; - } else if (IsOatFileMapping(mapped_file_name)) { - if (!DisplayMappingIfFromOatFile(proc, vma, &printer)) { - return EXIT_FAILURE; - } - match_found = true; - } - } - if (!match_found) { - std::cerr << "No relevant memory maps were found." << std::endl; - return EXIT_FAILURE; - } -#endif - - return EXIT_SUCCESS; -} - -} // namespace art - -int main(int argc, char* argv[]) { - return art::DexDiagMain(argc, argv); -} diff --git a/dexlayout/dexdiag_test.cc b/dexlayout/dexdiag_test.cc deleted file mode 100644 index cdea3bc827..0000000000 --- a/dexlayout/dexdiag_test.cc +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright (C) 2017 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. - */ - -#include <string> -#include <vector> - -#include "base/common_art_test.h" -#include "base/file_utils.h" -#include "base/os.h" -#include "exec_utils.h" -#include "oat/oat_file.h" - -namespace art { - -static const char* kDexDiagContains = "--contains=boot.vdex"; -static const char* kDexDiagContainsFails = "--contains=anything_other_than_core.vdex"; -static const char* kDexDiagHelp = "--help"; -static const char* kDexDiagVerbose = "--verbose"; -static const char* kDexDiagBinaryName = "dexdiag"; - -class DexDiagTest : public CommonArtTest { - protected: - void SetUp() override { CommonArtTest::SetUp(); } - - // Path to the dexdiag(d?)[32|64] binary. - std::string GetDexDiagFilePath() { - std::string path = GetArtBinDir() + '/' + kDexDiagBinaryName; - std::string path32 = path + "32"; - // If we have both a 32-bit and a 64-bit build, the 32-bit file will have a 32 suffix. - if (OS::FileExists(path32.c_str()) && !Is64BitInstructionSet(kRuntimeISA)) { - return path32; - } else { - // This is a 64-bit build or only a single build exists. - return path; - } - } - - std::unique_ptr<OatFile> OpenOatAndVdexFiles() { - // Open the core.oat file. - // This is a little convoluted because we have to - // get the location of the default core image (.../framework/core.oat), - // find it in the right architecture subdirectory (.../framework/arm/core.oat), - // Then, opening the oat file has the side-effect of opening the corresponding - // vdex file (.../framework/arm/core.vdex). - const std::string default_location = GetCoreOatLocation(); - EXPECT_TRUE(!default_location.empty()); - std::string oat_location = GetSystemImageFilename(default_location.c_str(), kRuntimeISA); - EXPECT_TRUE(!oat_location.empty()); - std::cout << "==" << oat_location << std::endl; - std::string error_msg; - std::unique_ptr<OatFile> oat(OatFile::Open(/*zip_fd=*/-1, - oat_location, - oat_location, - /*executable=*/false, - /*low_4gb=*/false, - &error_msg)); - EXPECT_TRUE(oat != nullptr) << error_msg; - return oat; - } - - // Run dexdiag with a custom boot image location. - bool Exec(pid_t this_pid, const std::vector<std::string>& args, std::string* error_msg) { - // Invoke 'dexdiag' against the current process. - // This should succeed because we have a runtime and so it should - // be able to map in the boot.art and do a diff for it. - std::vector<std::string> exec_argv; - - // Build the command line "dexdiag <args> this_pid". - std::string executable_path = GetDexDiagFilePath(); - EXPECT_TRUE(OS::FileExists(executable_path.c_str())) - << executable_path << " should be a valid file path"; - exec_argv.push_back(executable_path); - for (const auto& arg : args) { - exec_argv.push_back(arg); - } - exec_argv.push_back(std::to_string(this_pid)); - - return ::art::Exec(exec_argv, error_msg); - } -}; - -// We can't run these tests on the host, as they will fail when trying to open -// /proc/pid/pagemap. -// On the target, we invoke 'dexdiag' against the current process. -// This should succeed because we have a runtime and so dexdiag should -// be able to find the map for, e.g., boot.vdex and friends. -TEST_F(DexDiagTest, DexDiagHelpTest) { - // TODO: test the resulting output. - std::string error_msg; - ASSERT_TRUE(Exec(getpid(), {kDexDiagHelp}, &error_msg)) - << "Failed to execute -- because: " << error_msg; -} - -#if defined(ART_TARGET) -TEST_F(DexDiagTest, DexDiagContainsTest) { -#else -TEST_F(DexDiagTest, DISABLED_DexDiagContainsTest) { -#endif - std::unique_ptr<OatFile> oat = OpenOatAndVdexFiles(); - // TODO: test the resulting output. - std::string error_msg; - ASSERT_TRUE(Exec(getpid(), {kDexDiagContains}, &error_msg)) - << "Failed to execute -- because: " << error_msg; -} - -#if defined(ART_TARGET) -TEST_F(DexDiagTest, DexDiagContainsFailsTest) { -#else -TEST_F(DexDiagTest, DISABLED_DexDiagContainsFailsTest) { -#endif - std::unique_ptr<OatFile> oat = OpenOatAndVdexFiles(); - // TODO: test the resulting output. - std::string error_msg; - ASSERT_FALSE(Exec(getpid(), {kDexDiagContainsFails}, &error_msg)) - << "Failed to execute -- because: " << error_msg; -} - -#if defined(ART_TARGET) -TEST_F(DexDiagTest, DexDiagVerboseTest) { -#else -TEST_F(DexDiagTest, DISABLED_DexDiagVerboseTest) { -#endif - // TODO: test the resulting output. - std::unique_ptr<OatFile> oat = OpenOatAndVdexFiles(); - std::string error_msg; - ASSERT_TRUE(Exec(getpid(), {kDexDiagVerbose}, &error_msg)) - << "Failed to execute -- because: " << error_msg; -} - -} // namespace art diff --git a/dexlayout/dexlayout.cc b/dexlayout/dexlayout.cc deleted file mode 100644 index f43ded0251..0000000000 --- a/dexlayout/dexlayout.cc +++ /dev/null @@ -1,2332 +0,0 @@ -/* - * 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. - * - * Implementation file of the dexlayout utility. - * - * This is a tool to read dex files into an internal representation, - * reorganize the representation, and emit dex files with a better - * file layout. - */ - -#include "dexlayout.h" - -#include <inttypes.h> -#include <stdio.h> - -#include <cstdint> -#include <iostream> -#include <iterator> -#include <memory> -#include <sstream> -#include <unordered_set> -#include <vector> - -#include "android-base/stringprintf.h" -#include "base/hiddenapi_flags.h" -#include "base/logging.h" // For VLOG_IS_ON. -#include "base/mem_map.h" -#include "base/mman.h" // For the PROT_* and MAP_* constants. -#include "base/os.h" -#include "base/utils.h" -#include "dex/art_dex_file_loader.h" -#include "dex/descriptors_names.h" -#include "dex/dex_file-inl.h" -#include "dex/dex_file_layout.h" -#include "dex/dex_file_loader.h" -#include "dex/dex_file_types.h" -#include "dex/dex_file_verifier.h" -#include "dex/dex_instruction-inl.h" -#include "dex_ir.h" -#include "dex_ir_builder.h" -#include "dex_verify.h" -#include "dex_visualize.h" -#include "dex_writer.h" -#include "profile/profile_compilation_info.h" - -namespace art { - -using android::base::StringPrintf; - -/* - * Flags for use with createAccessFlagStr(). - */ -enum AccessFor { - kAccessForClass = 0, kAccessForMethod = 1, kAccessForField = 2, kAccessForMAX -}; -const int kNumFlags = 18; - -/* - * Gets 2 little-endian bytes. - */ -static inline uint16_t Get2LE(unsigned char const* src) { - return src[0] | (src[1] << 8); -} - -/* - * Converts the class name portion of a type descriptor to human-readable - * "dotted" form. For example, "Ljava/lang/String;" becomes "String". - */ -static std::string DescriptorClassToName(const char* str) { - std::string descriptor(str); - // Reduce to just the class name prefix. - size_t last_slash = descriptor.rfind('/'); - if (last_slash == std::string::npos) { - last_slash = 0; - } - // Start past the '/' or 'L'. - last_slash++; - - // Copy class name over, trimming trailing ';'. - size_t size = descriptor.size() - 1 - last_slash; - std::string result(descriptor.substr(last_slash, size)); - - return result; -} - -/* - * Returns string representing the boolean value. - */ -static const char* StrBool(bool val) { - return val ? "true" : "false"; -} - -/* - * Returns a quoted string representing the boolean value. - */ -static const char* QuotedBool(bool val) { - return val ? "\"true\"" : "\"false\""; -} - -/* - * Returns a quoted string representing the access flags. - */ -static const char* QuotedVisibility(uint32_t access_flags) { - if (access_flags & kAccPublic) { - return "\"public\""; - } else if (access_flags & kAccProtected) { - return "\"protected\""; - } else if (access_flags & kAccPrivate) { - return "\"private\""; - } else { - return "\"package\""; - } -} - -/* - * Counts the number of '1' bits in a word. - */ -static int CountOnes(uint32_t val) { - val = val - ((val >> 1) & 0x55555555); - val = (val & 0x33333333) + ((val >> 2) & 0x33333333); - return (((val + (val >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24; -} - -/* - * Creates a new string with human-readable access flags. - * - * In the base language the access_flags fields are type uint16_t; in Dalvik they're uint32_t. - */ -static char* CreateAccessFlagStr(uint32_t flags, AccessFor for_what) { - static const char* kAccessStrings[kAccessForMAX][kNumFlags] = { - { - "PUBLIC", /* 0x00001 */ - "PRIVATE", /* 0x00002 */ - "PROTECTED", /* 0x00004 */ - "STATIC", /* 0x00008 */ - "FINAL", /* 0x00010 */ - "?", /* 0x00020 */ - "?", /* 0x00040 */ - "?", /* 0x00080 */ - "?", /* 0x00100 */ - "INTERFACE", /* 0x00200 */ - "ABSTRACT", /* 0x00400 */ - "?", /* 0x00800 */ - "SYNTHETIC", /* 0x01000 */ - "ANNOTATION", /* 0x02000 */ - "ENUM", /* 0x04000 */ - "?", /* 0x08000 */ - "VERIFIED", /* 0x10000 */ - "OPTIMIZED", /* 0x20000 */ - }, { - "PUBLIC", /* 0x00001 */ - "PRIVATE", /* 0x00002 */ - "PROTECTED", /* 0x00004 */ - "STATIC", /* 0x00008 */ - "FINAL", /* 0x00010 */ - "SYNCHRONIZED", /* 0x00020 */ - "BRIDGE", /* 0x00040 */ - "VARARGS", /* 0x00080 */ - "NATIVE", /* 0x00100 */ - "?", /* 0x00200 */ - "ABSTRACT", /* 0x00400 */ - "STRICT", /* 0x00800 */ - "SYNTHETIC", /* 0x01000 */ - "?", /* 0x02000 */ - "?", /* 0x04000 */ - "MIRANDA", /* 0x08000 */ - "CONSTRUCTOR", /* 0x10000 */ - "DECLARED_SYNCHRONIZED", /* 0x20000 */ - }, { - "PUBLIC", /* 0x00001 */ - "PRIVATE", /* 0x00002 */ - "PROTECTED", /* 0x00004 */ - "STATIC", /* 0x00008 */ - "FINAL", /* 0x00010 */ - "?", /* 0x00020 */ - "VOLATILE", /* 0x00040 */ - "TRANSIENT", /* 0x00080 */ - "?", /* 0x00100 */ - "?", /* 0x00200 */ - "?", /* 0x00400 */ - "?", /* 0x00800 */ - "SYNTHETIC", /* 0x01000 */ - "?", /* 0x02000 */ - "ENUM", /* 0x04000 */ - "?", /* 0x08000 */ - "?", /* 0x10000 */ - "?", /* 0x20000 */ - }, - }; - - // Allocate enough storage to hold the expected number of strings, - // plus a space between each. We over-allocate, using the longest - // string above as the base metric. - const int kLongest = 21; // The strlen of longest string above. - const int count = CountOnes(flags); - char* str; - char* cp; - cp = str = reinterpret_cast<char*>(malloc(count * (kLongest + 1) + 1)); - - for (int i = 0; i < kNumFlags; i++) { - if (flags & 0x01) { - const char* accessStr = kAccessStrings[for_what][i]; - const int len = strlen(accessStr); - if (cp != str) { - *cp++ = ' '; - } - memcpy(cp, accessStr, len); - cp += len; - } - flags >>= 1; - } // for - - *cp = '\0'; - return str; -} - -static std::string GetHiddenapiFlagStr(uint32_t hiddenapi_flags) { - std::stringstream ss; - hiddenapi::ApiList(hiddenapi_flags).Dump(ss); - std::string api_list = ss.str(); - std::transform(api_list.begin(), api_list.end(), api_list.begin(), ::toupper); - return api_list; -} - -static std::string GetSignatureForProtoId(const dex_ir::ProtoId* proto) { - if (proto == nullptr) { - return "<no signature>"; - } - - std::string result("("); - 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(); - return result; -} - -/* - * Copies character data from "data" to "out", converting non-ASCII values - * to fprintf format chars or an ASCII filler ('.' or '?'). - * - * The output buffer must be able to hold (2*len)+1 bytes. The result is - * NULL-terminated. - */ -static void Asciify(char* out, const unsigned char* data, size_t len) { - for (; len != 0u; --len) { - if (*data < 0x20) { - // Could do more here, but we don't need them yet. - switch (*data) { - case '\0': - *out++ = '\\'; - *out++ = '0'; - break; - case '\n': - *out++ = '\\'; - *out++ = 'n'; - break; - default: - *out++ = '.'; - break; - } // switch - } else if (*data >= 0x80) { - *out++ = '?'; - } else { - *out++ = *data; - } - data++; - } // while - *out = '\0'; -} -/* clang-format off */ -constexpr char kEscapedLength[256] = { - 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 4, 2, 2, 4, 4, // \a, \b, \t, \n, \r - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // ", - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // '0'..'9' - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 'A'..'O' - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, // 'P'..'Z', '\' - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 'a'..'o' - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4, // 'p'..'z', DEL - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // Unicode range, keep - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -}; -/* clang-format on */ - -/* - * Check if a UTF8 string contains characters we should quote. - */ -static bool needsEscape(std::string_view s) { - for (unsigned char c : s) { - if (kEscapedLength[c] != 1) { - return true; - } - } - return false; -} - -std::string escapeString(std::string_view s) { - std::ostringstream oss; - for (unsigned char c : s) { - switch (kEscapedLength[c]) { - case 1: - oss << static_cast<char>(c); - break; - case 2: - switch (c) { - case '\b': - oss << '\\' << 'b'; - break; - case '\f': - oss << '\\' << 'f'; - break; - case '\n': - oss << '\\' << 'n'; - break; - case '\r': - oss << '\\' << 'r'; - break; - case '\t': - oss << '\\' << 't'; - break; - case '\"': - oss << '\\' << '"'; - break; - case '\\': - oss << '\\' << '\\'; - break; - } - break; - case 4: - oss << '\\' << '0' + (c / 64) << '0' + ((c % 64) / 8) << '0' + (c % 8); - break; - } - } - return oss.str(); -} - -/* - * Dumps a string value with some escape characters. - */ -static void DumpEscapedString(std::string_view s, FILE* out_file) { - fputs("\"", out_file); - if (needsEscape(s)) { - std::string e = escapeString(s); - fputs(e.c_str(), out_file); - } else { - for (char c : s) { - fputc(c, out_file); - } - } - fputs("\"", out_file); -} - -/* - * Dumps a string as an XML attribute value. - */ -static void DumpXmlAttribute(const char* p, FILE* out_file) { - for (; *p; p++) { - switch (*p) { - case '&': - fputs("&", out_file); - break; - case '<': - fputs("<", out_file); - break; - case '>': - fputs(">", out_file); - break; - case '"': - fputs(""", out_file); - break; - case '\t': - fputs("	", out_file); - break; - case '\n': - fputs("
", out_file); - break; - case '\r': - fputs("
", out_file); - break; - default: - putc(*p, out_file); - } // switch - } // for -} - -/* - * 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<char[]> IndexString(dex_ir::Header* header, - const Instruction* dec_insn, - size_t buf_size) { - std::unique_ptr<char[]> buf(new char[buf_size]); - // Determine index and width of the string. - uint32_t index = 0; - uint32_t secondary_index = dex::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; - 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, "<unknown-index>"); - 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, "<no-index>"); - break; - case Instruction::kIndexTypeRef: - if (index < header->TypeIds().Size()) { - const char* tp = header->TypeIds()[index]->GetStringId()->Data(); - outSize = snprintf(buf.get(), buf_size, "%s // type@%0*x", tp, width, index); - } else { - outSize = snprintf(buf.get(), buf_size, "<type?> // type@%0*x", width, index); - } - break; - case Instruction::kIndexStringRef: - if (index < header->StringIds().Size()) { - const char* st = header->StringIds()[index]->Data(); - if (needsEscape(std::string_view(st))) { - std::string escaped = escapeString(st); - outSize = - snprintf(buf.get(), buf_size, "\"%s\" // string@%0*x", escaped.c_str(), width, index); - } else { - outSize = snprintf(buf.get(), buf_size, "\"%s\" // string@%0*x", st, width, index); - } - } else { - outSize = snprintf(buf.get(), buf_size, "<string?> // string@%0*x", width, index); - } - break; - case Instruction::kIndexMethodRef: - if (index < header->MethodIds().Size()) { - dex_ir::MethodId* method_id = header->MethodIds()[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?> // method@%0*x", width, index); - } - break; - case Instruction::kIndexFieldRef: - if (index < header->FieldIds().Size()) { - dex_ir::FieldId* field_id = header->FieldIds()[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?> // 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("<method?>"); - std::string proto("<proto?>"); - if (index < header->MethodIds().Size()) { - dex_ir::MethodId* method_id = header->MethodIds()[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->ProtoIds().Size()) { - dex_ir::ProtoId* proto_id = header->ProtoIds()[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; - case Instruction::kIndexCallSiteRef: - outSize = snprintf(buf.get(), buf_size, "call_site@%0*x", width, 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. - */ -void DexLayout::DumpEncodedAnnotation(dex_ir::EncodedAnnotation* annotation) { - fputs(annotation->GetType()->GetStringId()->Data(), out_file_); - // Display all name=value pairs. - for (auto& subannotation : *annotation->GetAnnotationElements()) { - fputc(' ', out_file_); - fputs(subannotation->GetName()->Data(), out_file_); - fputc('=', out_file_); - DumpEncodedValue(subannotation->GetValue()); - } -} -/* - * Dumps encoded value. - */ -void DexLayout::DumpEncodedValue(const dex_ir::EncodedValue* data) { - switch (data->Type()) { - case DexFile::kDexAnnotationByte: - fprintf(out_file_, "%" PRId8, data->GetByte()); - break; - case DexFile::kDexAnnotationShort: - fprintf(out_file_, "%" PRId16, data->GetShort()); - break; - case DexFile::kDexAnnotationChar: - fprintf(out_file_, "%" PRIu16, data->GetChar()); - break; - case DexFile::kDexAnnotationInt: - fprintf(out_file_, "%" PRId32, data->GetInt()); - break; - case DexFile::kDexAnnotationLong: - fprintf(out_file_, "%" PRId64, data->GetLong()); - break; - case DexFile::kDexAnnotationFloat: { - fprintf(out_file_, "%g", data->GetFloat()); - break; - } - case DexFile::kDexAnnotationDouble: { - fprintf(out_file_, "%g", data->GetDouble()); - break; - } - case DexFile::kDexAnnotationString: { - dex_ir::StringId* string_id = data->GetStringId(); - if (options_.output_format_ == kOutputPlain) { - DumpEscapedString(string_id->Data(), out_file_); - } else { - DumpXmlAttribute(string_id->Data(), out_file_); - } - break; - } - case DexFile::kDexAnnotationType: { - dex_ir::TypeId* type_id = data->GetTypeId(); - fputs(type_id->GetStringId()->Data(), out_file_); - break; - } - case DexFile::kDexAnnotationField: - case DexFile::kDexAnnotationEnum: { - dex_ir::FieldId* field_id = data->GetFieldId(); - fputs(field_id->Name()->Data(), out_file_); - break; - } - case DexFile::kDexAnnotationMethod: { - dex_ir::MethodId* method_id = data->GetMethodId(); - fputs(method_id->Name()->Data(), out_file_); - break; - } - case DexFile::kDexAnnotationArray: { - fputc('{', out_file_); - // Display all elements. - for (auto& value : *data->GetEncodedArray()->GetEncodedValues()) { - fputc(' ', out_file_); - DumpEncodedValue(value.get()); - } - fputs(" }", out_file_); - break; - } - case DexFile::kDexAnnotationAnnotation: { - DumpEncodedAnnotation(data->GetEncodedAnnotation()); - break; - } - case DexFile::kDexAnnotationNull: - fputs("null", out_file_); - break; - case DexFile::kDexAnnotationBoolean: - fputs(StrBool(data->GetBoolean()), out_file_); - break; - default: - fputs("????", out_file_); - break; - } // switch -} - -/* - * Dumps the file header. - */ -void DexLayout::DumpFileHeader() { - char sanitized[8 * 2 + 1]; - fprintf(out_file_, "DEX file header:\n"); - Asciify(sanitized, header_->Magic().data(), header_->Magic().size()); - fprintf(out_file_, "magic : '%s'\n", sanitized); - 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()); - fprintf(out_file_, "link_off : %d (0x%06x)\n", - header_->LinkOffset(), header_->LinkOffset()); - fprintf(out_file_, "string_ids_size : %d\n", header_->StringIds().Size()); - fprintf(out_file_, "string_ids_off : %d (0x%06x)\n", - header_->StringIds().GetOffset(), header_->StringIds().GetOffset()); - fprintf(out_file_, "type_ids_size : %d\n", header_->TypeIds().Size()); - fprintf(out_file_, "type_ids_off : %d (0x%06x)\n", - header_->TypeIds().GetOffset(), header_->TypeIds().GetOffset()); - fprintf(out_file_, "proto_ids_size : %d\n", header_->ProtoIds().Size()); - fprintf(out_file_, "proto_ids_off : %d (0x%06x)\n", - header_->ProtoIds().GetOffset(), header_->ProtoIds().GetOffset()); - fprintf(out_file_, "field_ids_size : %d\n", header_->FieldIds().Size()); - fprintf(out_file_, "field_ids_off : %d (0x%06x)\n", - header_->FieldIds().GetOffset(), header_->FieldIds().GetOffset()); - fprintf(out_file_, "method_ids_size : %d\n", header_->MethodIds().Size()); - fprintf(out_file_, "method_ids_off : %d (0x%06x)\n", - header_->MethodIds().GetOffset(), header_->MethodIds().GetOffset()); - fprintf(out_file_, "class_defs_size : %d\n", header_->ClassDefs().Size()); - fprintf(out_file_, "class_defs_off : %d (0x%06x)\n", - header_->ClassDefs().GetOffset(), header_->ClassDefs().GetOffset()); - fprintf(out_file_, "data_size : %d\n", header_->DataSize()); - fprintf(out_file_, "data_off : %d (0x%06x)\n\n", - header_->DataOffset(), header_->DataOffset()); -} - -/* - * Dumps a class_def_item. - */ -void DexLayout::DumpClassDef(int idx) { - // General class information. - dex_ir::ClassDef* class_def = header_->ClassDefs()[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", - class_def->GetAccessFlags(), class_def->GetAccessFlags()); - uint32_t superclass_idx = class_def->Superclass() == nullptr ? - DexFile::kDexNoIndex16 : class_def->Superclass()->GetIndex(); - fprintf(out_file_, "superclass_idx : %d\n", superclass_idx); - fprintf(out_file_, "interfaces_off : %d (0x%06x)\n", - class_def->InterfacesOffset(), class_def->InterfacesOffset()); - uint32_t source_file_offset = 0xffffffffU; - if (class_def->SourceFile() != nullptr) { - source_file_offset = class_def->SourceFile()->GetIndex(); - } - fprintf(out_file_, "source_file_idx : %d\n", source_file_offset); - uint32_t annotations_offset = 0; - if (class_def->Annotations() != nullptr) { - annotations_offset = class_def->Annotations()->GetOffset(); - } - fprintf(out_file_, "annotations_off : %d (0x%06x)\n", - annotations_offset, annotations_offset); - if (class_def->GetClassData() == nullptr) { - fprintf(out_file_, "class_data_off : %d (0x%06x)\n", 0, 0); - } else { - fprintf(out_file_, "class_data_off : %d (0x%06x)\n", - class_def->GetClassData()->GetOffset(), class_def->GetClassData()->GetOffset()); - } - - // Fields and methods. - dex_ir::ClassData* class_data = class_def->GetClassData(); - if (class_data != nullptr && class_data->StaticFields() != nullptr) { - fprintf(out_file_, "static_fields_size : %zu\n", class_data->StaticFields()->size()); - } else { - fprintf(out_file_, "static_fields_size : 0\n"); - } - if (class_data != nullptr && class_data->InstanceFields() != nullptr) { - fprintf(out_file_, "instance_fields_size: %zu\n", class_data->InstanceFields()->size()); - } else { - fprintf(out_file_, "instance_fields_size: 0\n"); - } - if (class_data != nullptr && class_data->DirectMethods() != nullptr) { - fprintf(out_file_, "direct_methods_size : %zu\n", class_data->DirectMethods()->size()); - } else { - fprintf(out_file_, "direct_methods_size : 0\n"); - } - if (class_data != nullptr && class_data->VirtualMethods() != nullptr) { - fprintf(out_file_, "virtual_methods_size: %zu\n", class_data->VirtualMethods()->size()); - } else { - fprintf(out_file_, "virtual_methods_size: 0\n"); - } - fprintf(out_file_, "\n"); -} - -/** - * Dumps an annotation 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; - } - for (dex_ir::AnnotationItem* annotation : *set_item->GetItems()) { - if (annotation == nullptr) { - continue; - } - fputs(" ", out_file_); - switch (annotation->GetVisibility()) { - case DexFile::kDexVisibilityBuild: fputs("VISIBILITY_BUILD ", out_file_); break; - case DexFile::kDexVisibilityRuntime: fputs("VISIBILITY_RUNTIME ", out_file_); break; - case DexFile::kDexVisibilitySystem: fputs("VISIBILITY_SYSTEM ", out_file_); break; - default: fputs("VISIBILITY_UNKNOWN ", out_file_); break; - } // switch - DumpEncodedAnnotation(annotation->GetAnnotation()); - fputc('\n', out_file_); - } -} - -/* - * Dumps class annotations. - */ -void DexLayout::DumpClassAnnotations(int idx) { - dex_ir::ClassDef* class_def = header_->ClassDefs()[idx]; - dex_ir::AnnotationsDirectoryItem* annotations_directory = class_def->Annotations(); - if (annotations_directory == nullptr) { - return; // none - } - - fprintf(out_file_, "Class #%d annotations:\n", idx); - - dex_ir::AnnotationSetItem* class_set_item = annotations_directory->GetClassAnnotation(); - dex_ir::FieldAnnotationVector* fields = annotations_directory->GetFieldAnnotations(); - dex_ir::MethodAnnotationVector* methods = annotations_directory->GetMethodAnnotations(); - dex_ir::ParameterAnnotationVector* parameters = annotations_directory->GetParameterAnnotations(); - - // Annotations on the class itself. - if (class_set_item != nullptr) { - fprintf(out_file_, "Annotations on class\n"); - DumpAnnotationSetItem(class_set_item); - } - - // Annotations on fields. - if (fields != nullptr) { - for (auto& field : *fields) { - const dex_ir::FieldId* field_id = field->GetFieldId(); - const uint32_t field_idx = field_id->GetIndex(); - const char* field_name = field_id->Name()->Data(); - fprintf(out_file_, "Annotations on field #%u '%s'\n", field_idx, field_name); - DumpAnnotationSetItem(field->GetAnnotationSetItem()); - } - } - - // Annotations on methods. - if (methods != nullptr) { - for (auto& method : *methods) { - const dex_ir::MethodId* method_id = method->GetMethodId(); - const uint32_t method_idx = method_id->GetIndex(); - const char* method_name = method_id->Name()->Data(); - fprintf(out_file_, "Annotations on method #%u '%s'\n", method_idx, method_name); - DumpAnnotationSetItem(method->GetAnnotationSetItem()); - } - } - - // Annotations on method parameters. - if (parameters != nullptr) { - for (auto& parameter : *parameters) { - const dex_ir::MethodId* method_id = parameter->GetMethodId(); - const uint32_t method_idx = method_id->GetIndex(); - const char* method_name = method_id->Name()->Data(); - fprintf(out_file_, "Annotations on method #%u '%s' parameters\n", method_idx, method_name); - uint32_t j = 0; - for (dex_ir::AnnotationSetItem* annotation : *parameter->GetAnnotations()->GetItems()) { - fprintf(out_file_, "#%u\n", j); - DumpAnnotationSetItem(annotation); - ++j; - } - } - } - - fputc('\n', out_file_); -} - -/* - * Dumps an interface that a class declares to implement. - */ -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); - } else { - std::string dot(DescriptorToDot(interface_name)); - fprintf(out_file_, "<implements name=\"%s\">\n</implements>\n", dot.c_str()); - } -} - -/* - * Dumps the catches table associated with the code. - */ -void DexLayout::DumpCatches(const dex_ir::CodeItem* code) { - const uint16_t tries_size = code->TriesSize(); - - // No catch table. - if (tries_size == 0) { - fprintf(out_file_, " catches : (none)\n"); - return; - } - - // Dump all table entries. - fprintf(out_file_, " catches : %d\n", tries_size); - std::vector<std::unique_ptr<const dex_ir::TryItem>>* tries = code->Tries(); - for (uint32_t i = 0; i < tries_size; i++) { - const dex_ir::TryItem* try_item = (*tries)[i].get(); - 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()->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()); - } // for - } // for -} - -/* - * Dumps a single instruction. - */ -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); - - // Dump (part of) raw bytes. - const uint16_t* insns = code->Insns(); - for (uint32_t i = 0; i < 8; i++) { - if (i < insn_width) { - if (i == 7) { - fprintf(out_file_, " ... "); - } else { - // Print 16-bit value in little-endian order. - const uint8_t* bytePtr = (const uint8_t*) &insns[insn_idx + i]; - fprintf(out_file_, " %02x%02x", bytePtr[0], bytePtr[1]); - } - } else { - fputs(" ", out_file_); - } - } // for - - // Dump pseudo-instruction or opcode. - if (dec_insn->Opcode() == Instruction::NOP) { - const uint16_t instr = Get2LE((const uint8_t*) &insns[insn_idx]); - if (instr == Instruction::kPackedSwitchSignature) { - fprintf(out_file_, "|%04x: packed-switch-data (%d units)", insn_idx, insn_width); - } else if (instr == Instruction::kSparseSwitchSignature) { - fprintf(out_file_, "|%04x: sparse-switch-data (%d units)", insn_idx, insn_width); - } else if (instr == Instruction::kArrayDataSignature) { - fprintf(out_file_, "|%04x: array-data (%d units)", insn_idx, insn_width); - } else { - fprintf(out_file_, "|%04x: nop // spacer", insn_idx); - } - } else { - fprintf(out_file_, "|%04x: %s", insn_idx, dec_insn->Name()); - } - - // Set up additional argument. - std::unique_ptr<char[]> index_buf; - if (Instruction::IndexTypeOf(dec_insn->Opcode()) != Instruction::kIndexNone) { - index_buf = IndexString(header_, dec_insn, 200); - } - - // Dump the instruction. - // - // NOTE: pDecInsn->DumpString(pDexFile) differs too much from original. - // - switch (Instruction::FormatOf(dec_insn->Opcode())) { - case Instruction::k10x: // op - break; - case Instruction::k12x: // op vA, vB - fprintf(out_file_, " v%d, v%d", dec_insn->VRegA(), dec_insn->VRegB()); - break; - case Instruction::k11n: // op vA, #+B - fprintf(out_file_, " v%d, #int %d // #%x", - dec_insn->VRegA(), (int32_t) dec_insn->VRegB(), (uint8_t)dec_insn->VRegB()); - break; - case Instruction::k11x: // op vAA - fprintf(out_file_, " v%d", dec_insn->VRegA()); - break; - case Instruction::k10t: // op +AA - case Instruction::k20t: { // op +AAAA - const int32_t targ = (int32_t) dec_insn->VRegA(); - fprintf(out_file_, " %04x // %c%04x", - insn_idx + targ, - (targ < 0) ? '-' : '+', - (targ < 0) ? -targ : targ); - break; - } - case Instruction::k22x: // op vAA, vBBBB - fprintf(out_file_, " v%d, v%d", dec_insn->VRegA(), dec_insn->VRegB()); - break; - case Instruction::k21t: { // op vAA, +BBBB - const int32_t targ = (int32_t) dec_insn->VRegB(); - fprintf(out_file_, " v%d, %04x // %c%04x", dec_insn->VRegA(), - insn_idx + targ, - (targ < 0) ? '-' : '+', - (targ < 0) ? -targ : targ); - break; - } - case Instruction::k21s: // op vAA, #+BBBB - fprintf(out_file_, " v%d, #int %d // #%x", - dec_insn->VRegA(), (int32_t) dec_insn->VRegB(), (uint16_t)dec_insn->VRegB()); - break; - case Instruction::k21h: // op vAA, #+BBBB0000[00000000] - // The printed format varies a bit based on the actual opcode. - if (dec_insn->Opcode() == Instruction::CONST_HIGH16) { - const int32_t value = dec_insn->VRegB() << 16; - fprintf(out_file_, " v%d, #int %d // #%x", - dec_insn->VRegA(), value, (uint16_t) dec_insn->VRegB()); - } else { - const int64_t value = ((int64_t) dec_insn->VRegB()) << 48; - fprintf(out_file_, " v%d, #long %" PRId64 " // #%x", - dec_insn->VRegA(), value, (uint16_t) dec_insn->VRegB()); - } - break; - case Instruction::k21c: // op vAA, thing@BBBB - case Instruction::k31c: // op vAA, thing@BBBBBBBB - fprintf(out_file_, " v%d, %s", dec_insn->VRegA(), index_buf.get()); - break; - case Instruction::k23x: // op vAA, vBB, vCC - fprintf(out_file_, " v%d, v%d, v%d", - dec_insn->VRegA(), dec_insn->VRegB(), dec_insn->VRegC()); - break; - case Instruction::k22b: // op vAA, vBB, #+CC - fprintf(out_file_, " v%d, v%d, #int %d // #%02x", - dec_insn->VRegA(), dec_insn->VRegB(), - (int32_t) dec_insn->VRegC(), (uint8_t) dec_insn->VRegC()); - break; - case Instruction::k22t: { // op vA, vB, +CCCC - const int32_t targ = (int32_t) dec_insn->VRegC(); - fprintf(out_file_, " v%d, v%d, %04x // %c%04x", - dec_insn->VRegA(), dec_insn->VRegB(), - insn_idx + targ, - (targ < 0) ? '-' : '+', - (targ < 0) ? -targ : targ); - break; - } - case Instruction::k22s: // op vA, vB, #+CCCC - fprintf(out_file_, " v%d, v%d, #int %d // #%04x", - dec_insn->VRegA(), dec_insn->VRegB(), - (int32_t) dec_insn->VRegC(), (uint16_t) dec_insn->VRegC()); - break; - case Instruction::k22c: // op vA, vB, thing@CCCC - // NOT SUPPORTED: - // case Instruction::k22cs: // [opt] op vA, vB, field offset CCCC - fprintf(out_file_, " v%d, v%d, %s", - dec_insn->VRegA(), dec_insn->VRegB(), index_buf.get()); - break; - case Instruction::k30t: - fprintf(out_file_, " #%08x", dec_insn->VRegA()); - break; - case Instruction::k31i: { // op vAA, #+BBBBBBBB - // This is often, but not always, a float. - union { - float f; - uint32_t i; - } conv; - conv.i = dec_insn->VRegB(); - fprintf(out_file_, " v%d, #float %g // #%08x", - dec_insn->VRegA(), conv.f, dec_insn->VRegB()); - break; - } - case Instruction::k31t: // op vAA, offset +BBBBBBBB - fprintf(out_file_, " v%d, %08x // +%08x", - dec_insn->VRegA(), insn_idx + dec_insn->VRegB(), dec_insn->VRegB()); - break; - case Instruction::k32x: // op vAAAA, vBBBB - fprintf(out_file_, " v%d, v%d", dec_insn->VRegA(), dec_insn->VRegB()); - break; - case Instruction::k35c: // op {vC, vD, vE, vF, vG}, thing@BBBB - case Instruction::k45cc: { // op {vC, vD, vE, vF, vG}, meth@BBBB, proto@HHHH - // NOT SUPPORTED: - // case Instruction::k35ms: // [opt] invoke-virtual+super - // case Instruction::k35mi: // [opt] inline invoke - uint32_t arg[Instruction::kMaxVarArgRegs]; - dec_insn->GetVarArgs(arg); - fputs(" {", out_file_); - for (int i = 0, n = dec_insn->VRegA(); i < n; i++) { - if (i == 0) { - fprintf(out_file_, "v%d", arg[i]); - } else { - fprintf(out_file_, ", v%d", arg[i]); - } - } // for - fprintf(out_file_, "}, %s", index_buf.get()); - break; - } - case Instruction::k3rc: // op {vCCCC .. v(CCCC+AA-1)}, thing@BBBB - case Instruction::k4rcc: // op {vCCCC .. v(CCCC+AA-1)}, meth@BBBB, proto@HHHH - // NOT SUPPORTED: - // case Instruction::k3rms: // [opt] invoke-virtual+super/range - // case Instruction::k3rmi: // [opt] execute-inline/range - { - // This doesn't match the "dx" output when some of the args are - // 64-bit values -- dx only shows the first register. - fputs(" {", out_file_); - for (int i = 0, n = dec_insn->VRegA(); i < n; i++) { - if (i == 0) { - fprintf(out_file_, "v%d", dec_insn->VRegC() + i); - } else { - fprintf(out_file_, ", v%d", dec_insn->VRegC() + i); - } - } // for - fprintf(out_file_, "}, %s", index_buf.get()); - } - break; - case Instruction::k51l: { // op vAA, #+BBBBBBBBBBBBBBBB - // This is often, but not always, a double. - union { - double d; - uint64_t j; - } conv; - conv.j = dec_insn->WideVRegB(); - fprintf(out_file_, " v%d, #double %g // #%016" PRIx64, - dec_insn->VRegA(), conv.d, dec_insn->WideVRegB()); - break; - } - // NOT SUPPORTED: - // case Instruction::k00x: // unknown op or breakpoint - // break; - default: - fprintf(out_file_, " ???"); - break; - } // switch - - fputc('\n', out_file_); -} - -/* - * Dumps a bytecode disassembly. - */ -void DexLayout::DumpBytecodes(uint32_t idx, const dex_ir::CodeItem* code, uint32_t code_offset) { - dex_ir::MethodId* method_id = header_->MethodIds()[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(); - - // Generate header. - std::string dot(DescriptorToDot(back_descriptor)); - fprintf(out_file_, "%06x: |[%06x] %s.%s:%s\n", - code_offset, code_offset, dot.c_str(), name, type_descriptor.c_str()); - - // Iterate over all instructions. - for (const DexInstructionPcPair& inst : code->Instructions()) { - const uint32_t insn_width = inst->SizeInCodeUnits(); - if (insn_width == 0) { - LOG(WARNING) << "GLITCH: zero-width instruction at idx=0x" << std::hex << inst.DexPc(); - break; - } - DumpInstruction(code, code_offset, inst.DexPc(), insn_width, &inst.Inst()); - } // for -} - -/* - * Lookup functions. - */ -static const char* GetStringData(uint32_t idx, dex_ir::Header* header) { - dex_ir::StringId* string_id = header->GetStringIdOrNullPtr(idx); - if (string_id == nullptr) { - return nullptr; - } - return string_id->Data(); -} - -static const char* StringDataByTypeIdx(uint16_t idx, dex_ir::Header* header) { - dex_ir::TypeId* type_id = header->GetTypeIdOrNullPtr(idx); - if (type_id == nullptr) { - return nullptr; - } - dex_ir::StringId* string_id = type_id->GetStringId(); - if (string_id == nullptr) { - return nullptr; - } - return string_id->Data(); -} - - -/* - * Dumps code of a method. - */ -void DexLayout::DumpCode(uint32_t idx, - const dex_ir::CodeItem* code, - uint32_t code_offset, - const char* declaring_class_descriptor, - const char* method_name, - bool is_static, - const dex_ir::ProtoId* proto) { - fprintf(out_file_, " registers : %d\n", code->RegistersSize()); - fprintf(out_file_, " ins : %d\n", code->InsSize()); - fprintf(out_file_, " outs : %d\n", code->OutsSize()); - fprintf(out_file_, " insns size : %d 16-bit code units\n", - code->InsnsSize()); - - // Bytecode disassembly, if requested. - if (options_.disassemble_) { - DumpBytecodes(idx, code, code_offset); - } - - // Try-catch blocks. - DumpCatches(code); - - // Positions and locals table in the debug info. - dex_ir::DebugInfoItem* debug_info = code->DebugInfo(); - fprintf(out_file_, " positions :\n"); - if (debug_info != nullptr) { - DexFile::DecodeDebugPositionInfo(debug_info->GetDebugInfo(), - [this](uint32_t idx) { - return GetStringData(idx, this->header_); - }, - [&](const DexFile::PositionInfo& entry) { - fprintf(out_file_, - " 0x%04x line=%d\n", - entry.address_, - entry.line_); - return false; - }); - } - fprintf(out_file_, " locals :\n"); - if (debug_info != nullptr) { - std::vector<const char*> arg_descriptors; - const dex_ir::TypeList* parameters = proto->Parameters(); - if (parameters != nullptr) { - const dex_ir::TypeIdVector* parameter_type_vector = parameters->GetTypeList(); - if (parameter_type_vector != nullptr) { - for (const dex_ir::TypeId* type_id : *parameter_type_vector) { - arg_descriptors.push_back(type_id->GetStringId()->Data()); - } - } - } - DexFile::DecodeDebugLocalInfo(debug_info->GetDebugInfo(), - "DexLayout in-memory", - declaring_class_descriptor, - arg_descriptors, - method_name, - is_static, - code->RegistersSize(), - code->InsSize(), - code->InsnsSize(), - [this](uint32_t idx) { - return GetStringData(idx, this->header_); - }, - [this](uint32_t idx) { - return - StringDataByTypeIdx(dchecked_integral_cast<uint16_t>(idx), - this->header_); - }, - [&](const DexFile::LocalInfo& entry) { - fprintf(out_file_, - " 0x%04x - 0x%04x reg=%d %s %s", - entry.start_address_, - entry.end_address_, - entry.reg_, - entry.name_, - entry.descriptor_); - if (entry.signature_) { - fputc(' ', out_file_); - fputs(entry.signature_, out_file_); - } - fputc('\n', out_file_); - }); - } -} - -/* - * Dumps a method. - */ -void DexLayout::DumpMethod(uint32_t idx, - uint32_t flags, - uint32_t hiddenapi_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_->MethodIds()[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(); - char* access_str = CreateAccessFlagStr(flags, kAccessForMethod); - - if (options_.output_format_ == kOutputPlain) { - fprintf(out_file_, " #%d : (in %s)\n", i, back_descriptor); - fprintf(out_file_, " name : '%s'\n", name); - fprintf(out_file_, " type : '%s'\n", type_descriptor); - fprintf(out_file_, " access : 0x%04x (%s)\n", flags, access_str); - if (options_.show_section_headers_) { - fprintf(out_file_, " method_idx : %d\n", method_id->GetIndex()); - } - if (hiddenapi_flags != 0u) { - fprintf(out_file_, - " hiddenapi : 0x%04x (%s)\n", - hiddenapi_flags, - GetHiddenapiFlagStr(hiddenapi_flags).c_str()); - } - if (code == nullptr) { - fprintf(out_file_, " code : (none)\n"); - } else { - fprintf(out_file_, " code -\n"); - DumpCode(idx, - code, - code->GetOffset(), - back_descriptor, - name, - (flags & kAccStatic) != 0, - method_id->Proto()); - } - if (options_.disassemble_) { - fputc('\n', out_file_); - } - } else if (options_.output_format_ == kOutputXml) { - const bool constructor = (name[0] == '<'); - - // Method name and prototype. - if (constructor) { - std::string dot(DescriptorClassToName(back_descriptor)); - fprintf(out_file_, "<constructor name=\"%s\"\n", dot.c_str()); - dot = DescriptorToDot(back_descriptor); - fprintf(out_file_, " type=\"%s\"\n", dot.c_str()); - } else { - fprintf(out_file_, "<method name=\"%s\"\n", name); - const char* return_type = strrchr(type_descriptor, ')'); - if (return_type == nullptr) { - LOG(ERROR) << "bad method type descriptor '" << type_descriptor << "'"; - goto bail; - } - std::string dot(DescriptorToDot(return_type + 1)); - fprintf(out_file_, " return=\"%s\"\n", dot.c_str()); - fprintf(out_file_, " abstract=%s\n", QuotedBool((flags & kAccAbstract) != 0)); - fprintf(out_file_, " native=%s\n", QuotedBool((flags & kAccNative) != 0)); - fprintf(out_file_, " synchronized=%s\n", QuotedBool( - (flags & (kAccSynchronized | kAccDeclaredSynchronized)) != 0)); - } - - // Additional method flags. - fprintf(out_file_, " static=%s\n", QuotedBool((flags & kAccStatic) != 0)); - fprintf(out_file_, " final=%s\n", QuotedBool((flags & kAccFinal) != 0)); - // The "deprecated=" not knowable w/o parsing annotations. - fprintf(out_file_, " visibility=%s\n>\n", QuotedVisibility(flags)); - - // Parameters. - if (type_descriptor[0] != '(') { - LOG(ERROR) << "ERROR: bad descriptor '" << type_descriptor << "'"; - goto bail; - } - char* tmp_buf = reinterpret_cast<char*>(malloc(strlen(type_descriptor) + 1)); - const char* base = type_descriptor + 1; - int arg_num = 0; - while (*base != ')') { - char* cp = tmp_buf; - while (*base == '[') { - *cp++ = *base++; - } - if (*base == 'L') { - // Copy through ';'. - do { - *cp = *base++; - } while (*cp++ != ';'); - } else { - // Primitive char, copy it. - if (strchr("ZBCSIFJD", *base) == nullptr) { - LOG(ERROR) << "ERROR: bad method signature '" << base << "'"; - break; // while - } - *cp++ = *base++; - } - // Null terminate and display. - *cp++ = '\0'; - std::string dot(DescriptorToDot(tmp_buf)); - fprintf(out_file_, "<parameter name=\"arg%d\" type=\"%s\">\n" - "</parameter>\n", arg_num++, dot.c_str()); - } // while - free(tmp_buf); - if (constructor) { - fprintf(out_file_, "</constructor>\n"); - } else { - fprintf(out_file_, "</method>\n"); - } - } - -bail: - free(type_descriptor); - free(access_str); -} - -/* - * Dumps a static (class) field. - */ -void DexLayout::DumpSField(uint32_t idx, - uint32_t flags, - uint32_t hiddenapi_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_->FieldIds()[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(); - char* access_str = CreateAccessFlagStr(flags, kAccessForField); - - if (options_.output_format_ == kOutputPlain) { - fprintf(out_file_, " #%d : (in %s)\n", i, back_descriptor); - fprintf(out_file_, " name : '%s'\n", name); - fprintf(out_file_, " type : '%s'\n", type_descriptor); - fprintf(out_file_, " access : 0x%04x (%s)\n", flags, access_str); - if (hiddenapi_flags != 0u) { - fprintf(out_file_, - " hiddenapi : 0x%04x (%s)\n", - hiddenapi_flags, - GetHiddenapiFlagStr(hiddenapi_flags).c_str()); - } - if (init != nullptr) { - fputs(" value : ", out_file_); - DumpEncodedValue(init); - fputs("\n", out_file_); - } - } else if (options_.output_format_ == kOutputXml) { - fprintf(out_file_, "<field name=\"%s\"\n", name); - std::string dot(DescriptorToDot(type_descriptor)); - fprintf(out_file_, " type=\"%s\"\n", dot.c_str()); - fprintf(out_file_, " transient=%s\n", QuotedBool((flags & kAccTransient) != 0)); - fprintf(out_file_, " volatile=%s\n", QuotedBool((flags & kAccVolatile) != 0)); - // The "value=" is not knowable w/o parsing annotations. - fprintf(out_file_, " static=%s\n", QuotedBool((flags & kAccStatic) != 0)); - fprintf(out_file_, " final=%s\n", QuotedBool((flags & kAccFinal) != 0)); - // The "deprecated=" is not knowable w/o parsing annotations. - fprintf(out_file_, " visibility=%s\n", QuotedVisibility(flags)); - if (init != nullptr) { - fputs(" value=\"", out_file_); - DumpEncodedValue(init); - fputs("\"\n", out_file_); - } - fputs(">\n</field>\n", out_file_); - } - - free(access_str); -} - -/* - * Dumps an instance field. - */ -void DexLayout::DumpIField(uint32_t idx, - uint32_t flags, - uint32_t hiddenapi_flags, - int i) { - DumpSField(idx, flags, hiddenapi_flags, i, nullptr); -} - -/* - * Dumps the class. - * - * Note "idx" is a DexClassDef index, not a DexTypeId index. - * - * If "*last_package" is nullptr or does not match the current class' package, - * the value will be replaced with a newly-allocated string. - */ -void DexLayout::DumpClass(int idx, char** last_package) { - dex_ir::ClassDef* class_def = header_->ClassDefs()[idx]; - // Omitting non-public class. - if (options_.exports_only_ && (class_def->GetAccessFlags() & kAccPublic) == 0) { - return; - } - - if (options_.show_section_headers_) { - DumpClassDef(idx); - } - - if (options_.show_annotations_) { - DumpClassAnnotations(idx); - } - - // For the XML output, show the package name. Ideally we'd gather - // up the classes, sort them, and dump them alphabetically so the - // 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_->ClassDefs()[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? - LOG(ERROR) << "Malformed class name '" << class_descriptor << "'"; - } else if (options_.output_format_ == kOutputXml) { - char* mangle = strdup(class_descriptor + 1); - mangle[strlen(mangle)-1] = '\0'; - - // Reduce to just the package name. - char* last_slash = strrchr(mangle, '/'); - if (last_slash != nullptr) { - *last_slash = '\0'; - } else { - *mangle = '\0'; - } - - for (char* cp = mangle; *cp != '\0'; cp++) { - if (*cp == '/') { - *cp = '.'; - } - } // for - - if (*last_package == nullptr || strcmp(mangle, *last_package) != 0) { - // Start of a new package. - if (*last_package != nullptr) { - fprintf(out_file_, "</package>\n"); - } - fprintf(out_file_, "<package name=\"%s\"\n>\n", mangle); - free(*last_package); - *last_package = mangle; - } else { - free(mangle); - } - } - - // General class information. - char* access_str = CreateAccessFlagStr(class_def->GetAccessFlags(), kAccessForClass); - const char* superclass_descriptor = nullptr; - if (class_def->Superclass() != nullptr) { - superclass_descriptor = class_def->Superclass()->GetStringId()->Data(); - } - if (options_.output_format_ == kOutputPlain) { - fprintf(out_file_, "Class #%d -\n", idx); - fprintf(out_file_, " Class descriptor : '%s'\n", class_descriptor); - fprintf(out_file_, " Access flags : 0x%04x (%s)\n", - class_def->GetAccessFlags(), access_str); - if (superclass_descriptor != nullptr) { - fprintf(out_file_, " Superclass : '%s'\n", superclass_descriptor); - } - fprintf(out_file_, " Interfaces -\n"); - } else { - std::string dot(DescriptorClassToName(class_descriptor)); - fprintf(out_file_, "<class name=\"%s\"\n", dot.c_str()); - if (superclass_descriptor != nullptr) { - dot = DescriptorToDot(superclass_descriptor); - fprintf(out_file_, " extends=\"%s\"\n", dot.c_str()); - } - fprintf(out_file_, " interface=%s\n", - QuotedBool((class_def->GetAccessFlags() & kAccInterface) != 0)); - fprintf(out_file_, " abstract=%s\n", - QuotedBool((class_def->GetAccessFlags() & kAccAbstract) != 0)); - fprintf(out_file_, " static=%s\n", QuotedBool((class_def->GetAccessFlags() & kAccStatic) != 0)); - fprintf(out_file_, " final=%s\n", QuotedBool((class_def->GetAccessFlags() & kAccFinal) != 0)); - // The "deprecated=" not knowable w/o parsing annotations. - fprintf(out_file_, " visibility=%s\n", QuotedVisibility(class_def->GetAccessFlags())); - fprintf(out_file_, ">\n"); - } - - // Interfaces. - const dex_ir::TypeList* interfaces = class_def->Interfaces(); - if (interfaces != nullptr) { - const dex_ir::TypeIdVector* interfaces_vector = interfaces->GetTypeList(); - for (uint32_t i = 0; i < interfaces_vector->size(); i++) { - DumpInterface((*interfaces_vector)[i], i); - } // for - } - - // Fields and methods. - dex_ir::ClassData* class_data = class_def->GetClassData(); - // Prepare data for static fields. - dex_ir::EncodedArrayItem* static_values = class_def->StaticValues(); - dex_ir::EncodedValueVector* encoded_values = - static_values == nullptr ? nullptr : static_values->GetEncodedValues(); - const uint32_t encoded_values_size = (encoded_values == nullptr) ? 0 : encoded_values->size(); - - // Static fields. - if (options_.output_format_ == kOutputPlain) { - fprintf(out_file_, " Static fields -\n"); - } - if (class_data != nullptr) { - dex_ir::FieldItemVector* static_fields = class_data->StaticFields(); - if (static_fields != nullptr) { - for (uint32_t i = 0; i < static_fields->size(); i++) { - DumpSField((*static_fields)[i].GetFieldId()->GetIndex(), - (*static_fields)[i].GetAccessFlags(), - dex_ir::HiddenapiClassData::GetFlags(header_, class_def, &(*static_fields)[i]), - i, - i < encoded_values_size ? (*encoded_values)[i].get() : nullptr); - } // for - } - } - - // Instance fields. - if (options_.output_format_ == kOutputPlain) { - fprintf(out_file_, " Instance fields -\n"); - } - if (class_data != nullptr) { - dex_ir::FieldItemVector* instance_fields = class_data->InstanceFields(); - if (instance_fields != nullptr) { - for (uint32_t i = 0; i < instance_fields->size(); i++) { - DumpIField((*instance_fields)[i].GetFieldId()->GetIndex(), - (*instance_fields)[i].GetAccessFlags(), - dex_ir::HiddenapiClassData::GetFlags(header_, class_def, &(*instance_fields)[i]), - i); - } // for - } - } - - // Direct methods. - if (options_.output_format_ == kOutputPlain) { - fprintf(out_file_, " Direct methods -\n"); - } - if (class_data != nullptr) { - dex_ir::MethodItemVector* direct_methods = class_data->DirectMethods(); - if (direct_methods != nullptr) { - for (uint32_t i = 0; i < direct_methods->size(); i++) { - DumpMethod((*direct_methods)[i].GetMethodId()->GetIndex(), - (*direct_methods)[i].GetAccessFlags(), - dex_ir::HiddenapiClassData::GetFlags(header_, class_def, &(*direct_methods)[i]), - (*direct_methods)[i].GetCodeItem(), - i); - } // for - } - } - - // Virtual methods. - if (options_.output_format_ == kOutputPlain) { - fprintf(out_file_, " Virtual methods -\n"); - } - if (class_data != nullptr) { - dex_ir::MethodItemVector* virtual_methods = class_data->VirtualMethods(); - if (virtual_methods != nullptr) { - for (uint32_t i = 0; i < virtual_methods->size(); i++) { - DumpMethod((*virtual_methods)[i].GetMethodId()->GetIndex(), - (*virtual_methods)[i].GetAccessFlags(), - dex_ir::HiddenapiClassData::GetFlags(header_, class_def, &(*virtual_methods)[i]), - (*virtual_methods)[i].GetCodeItem(), - i); - } // for - } - } - - // End of class. - if (options_.output_format_ == kOutputPlain) { - const char* file_name = "unknown"; - if (class_def->SourceFile() != nullptr) { - file_name = class_def->SourceFile()->Data(); - } - const dex_ir::StringId* source_file = class_def->SourceFile(); - fprintf(out_file_, " source_file_idx : %d (%s)\n\n", - source_file == nullptr ? 0xffffffffU : source_file->GetIndex(), file_name); - } else if (options_.output_format_ == kOutputXml) { - fprintf(out_file_, "</class>\n"); - } - - free(access_str); -} - -void DexLayout::DumpMethodHandle(int idx) { - const dex_ir::MethodHandleItem* mh = header_->MethodHandleItems()[idx]; - const char* type = nullptr; - bool is_instance = false; - bool is_invoke = false; - - switch (mh->GetMethodHandleType()) { - case DexFile::MethodHandleType::kStaticPut: - type = "put-static"; - is_instance = false; - is_invoke = false; - break; - case DexFile::MethodHandleType::kStaticGet: - type = "get-static"; - is_instance = false; - is_invoke = false; - break; - case DexFile::MethodHandleType::kInstancePut: - type = "put-instance"; - is_instance = true; - is_invoke = false; - break; - case DexFile::MethodHandleType::kInstanceGet: - type = "get-instance"; - is_instance = true; - is_invoke = false; - break; - case DexFile::MethodHandleType::kInvokeStatic: - type = "invoke-static"; - is_instance = false; - is_invoke = true; - break; - case DexFile::MethodHandleType::kInvokeInstance: - type = "invoke-instance"; - is_instance = true; - is_invoke = true; - break; - case DexFile::MethodHandleType::kInvokeConstructor: - type = "invoke-constructor"; - is_instance = true; - is_invoke = true; - break; - case DexFile::MethodHandleType::kInvokeDirect: - type = "invoke-direct"; - is_instance = true; - is_invoke = true; - break; - case DexFile::MethodHandleType::kInvokeInterface: - type = "invoke-interface"; - is_instance = true; - is_invoke = true; - break; - default: - type = "????"; - break; - } // switch - - const char* declaring_class; - const char* member; - std::string member_type; - if (type != nullptr) { - if (is_invoke) { - auto method_id = static_cast<dex_ir::MethodId*>(mh->GetFieldOrMethodId()); - declaring_class = method_id->Class()->GetStringId()->Data(); - member = method_id->Name()->Data(); - auto proto_id = method_id->Proto(); - member_type = GetSignatureForProtoId(proto_id); - } else { - auto field_id = static_cast<dex_ir::FieldId*>(mh->GetFieldOrMethodId()); - declaring_class = field_id->Class()->GetStringId()->Data(); - member = field_id->Name()->Data(); - member_type = field_id->Type()->GetStringId()->Data(); - } - if (is_instance) { - member_type = android::base::StringPrintf("(%s%s", declaring_class, member_type.c_str() + 1); - } - } else { - type = "?"; - declaring_class = "?"; - member = "?"; - member_type = "?"; - } - - if (options_.output_format_ == kOutputPlain) { - fprintf(out_file_, "Method handle #%u:\n", idx); - fprintf(out_file_, " type : %s\n", type); - fprintf(out_file_, " target : %s %s\n", declaring_class, member); - fprintf(out_file_, " target_type : %s\n", member_type.c_str()); - } -} - -void DexLayout::DumpCallSite(int idx) { - const dex_ir::CallSiteId* call_site_id = header_->CallSiteIds()[idx]; - auto call_site_items = call_site_id->CallSiteItem()->GetEncodedValues(); - if (call_site_items->size() < 3) { - LOG(ERROR) << "ERROR: Call site " << idx << " has too few values."; - return; - } - uint32_t offset = call_site_id->CallSiteItem()->GetOffset(); - - auto it = call_site_items->begin(); - if ((*it)->Type() != EncodedArrayValueIterator::ValueType::kMethodHandle) { - LOG(ERROR) << "ERROR: Call site " << idx << " needs to have a MethodHandle as its first item." - << " Found " << (*it)->Type(); - return; - } - auto method_handle = (*it)->GetMethodHandle(); - uint32_t method_handle_idx = method_handle->GetIndex(); - - it++; - if ((*it)->Type() != EncodedArrayValueIterator::ValueType::kString) { - LOG(ERROR) << "ERROR: Call site " << idx << " needs to have a String for method name " - << "as its second item." - << " Found " << (*it)->Type(); - return; - } - const char* method_name = (*it)->GetStringId()->Data(); - - it++; - if ((*it)->Type() != EncodedArrayValueIterator::ValueType::kMethodType) { - LOG(ERROR) << "ERROR: Call site " << idx << " needs to have a Prototype as its third item." - << " Found " << (*it)->Type(); - return; - } - auto proto_id = (*it)->GetProtoId(); - std::string method_type = GetSignatureForProtoId(proto_id); - - it++; - if (options_.output_format_ == kOutputPlain) { - fprintf(out_file_, "Call site #%u: // offset %u\n", idx, offset); - fprintf(out_file_, " link_argument[0] : %u (MethodHandle)\n", method_handle_idx); - fprintf(out_file_, " link_argument[1] : %s (String)\n", method_name); - fprintf(out_file_, " link_argument[2] : %s (MethodType)\n", method_type.c_str()); - } - - size_t argument = 3; - - while (it != call_site_items->end()) { - const char* type; - std::string value; - switch ((*it)->Type()) { - case EncodedArrayValueIterator::ValueType::kByte: - type = "byte"; - value = android::base::StringPrintf("%u", (*it)->GetByte()); - break; - case EncodedArrayValueIterator::ValueType::kShort: - type = "short"; - value = android::base::StringPrintf("%d", (*it)->GetShort()); - break; - case EncodedArrayValueIterator::ValueType::kChar: - type = "char"; - value = android::base::StringPrintf("%u", (*it)->GetChar()); - break; - case EncodedArrayValueIterator::ValueType::kInt: - type = "int"; - value = android::base::StringPrintf("%d", (*it)->GetInt()); - break; - case EncodedArrayValueIterator::ValueType::kLong: - type = "long"; - value = android::base::StringPrintf("%" PRId64, (*it)->GetLong()); - break; - case EncodedArrayValueIterator::ValueType::kFloat: - type = "float"; - value = android::base::StringPrintf("%g", (*it)->GetFloat()); - break; - case EncodedArrayValueIterator::ValueType::kDouble: - type = "double"; - value = android::base::StringPrintf("%g", (*it)->GetDouble()); - break; - case EncodedArrayValueIterator::ValueType::kMethodType: { - type = "MethodType"; - auto proto_id_item = (*it)->GetProtoId(); - value = GetSignatureForProtoId(proto_id_item); - break; - } - case EncodedArrayValueIterator::ValueType::kMethodHandle: { - type = "MethodHandle"; - auto method_handle_item = (*it)->GetMethodHandle(); - value = android::base::StringPrintf("%d", method_handle_item->GetIndex()); - break; - } - case EncodedArrayValueIterator::ValueType::kString: { - type = "String"; - auto string_id = (*it)->GetStringId(); - value = string_id->Data(); - break; - } - case EncodedArrayValueIterator::ValueType::kType: { - type = "Class"; - auto type_id = (*it)->GetTypeId(); - value = type_id->GetStringId()->Data(); - break; - } - case EncodedArrayValueIterator::ValueType::kField: - case EncodedArrayValueIterator::ValueType::kMethod: - case EncodedArrayValueIterator::ValueType::kEnum: - case EncodedArrayValueIterator::ValueType::kArray: - case EncodedArrayValueIterator::ValueType::kAnnotation: - // Unreachable based on current EncodedArrayValueIterator::Next(). - UNIMPLEMENTED(FATAL) << " type " << (*it)->Type(); - UNREACHABLE(); - case EncodedArrayValueIterator::ValueType::kNull: - type = "Null"; - value = "null"; - break; - case EncodedArrayValueIterator::ValueType::kBoolean: - type = "boolean"; - value = (*it)->GetBoolean() ? "true" : "false"; - break; - } - - if (options_.output_format_ == kOutputPlain) { - fprintf(out_file_, " link_argument[%zu] : %s (%s)\n", argument, value.c_str(), type); - } - - it++; - argument++; - } -} - -void DexLayout::DumpDexFile() { - // Headers. - if (options_.show_file_headers_) { - DumpFileHeader(); - } - - // Open XML context. - if (options_.output_format_ == kOutputXml) { - fprintf(out_file_, "<api>\n"); - } - - // Iterate over all classes. - char* package = nullptr; - const uint32_t class_defs_size = header_->ClassDefs().Size(); - for (uint32_t i = 0; i < class_defs_size; i++) { - DumpClass(i, &package); - } // for - - const uint32_t mh_items_size = header_->MethodHandleItems().Size(); - for (uint32_t i = 0; i < mh_items_size; i++) { - DumpMethodHandle(i); - } - - const uint32_t call_sites_size = header_->CallSiteIds().Size(); - for (uint32_t i = 0; i < call_sites_size; i++) { - DumpCallSite(i); - } - - // Free the last package allocated. - if (package != nullptr) { - fprintf(out_file_, "</package>\n"); - free(package); - } - - // Close XML context. - if (options_.output_format_ == kOutputXml) { - fprintf(out_file_, "</api>\n"); - } -} - -void DexLayout::LayoutClassDefsAndClassData(const DexFile* dex_file) { - std::vector<dex_ir::ClassDef*> new_class_def_order; - for (auto& class_def : header_->ClassDefs()) { - dex::TypeIndex type_idx(class_def->ClassType()->GetIndex()); - if (info_->ContainsClass(*dex_file, type_idx)) { - new_class_def_order.push_back(class_def.get()); - } - } - for (auto& class_def : header_->ClassDefs()) { - dex::TypeIndex type_idx(class_def->ClassType()->GetIndex()); - if (!info_->ContainsClass(*dex_file, type_idx)) { - new_class_def_order.push_back(class_def.get()); - } - } - std::unordered_set<dex_ir::ClassData*> visited_class_data; - size_t class_data_index = 0; - auto& class_datas = header_->ClassDatas(); - for (dex_ir::ClassDef* class_def : new_class_def_order) { - dex_ir::ClassData* class_data = class_def->GetClassData(); - if (class_data != nullptr && visited_class_data.find(class_data) == visited_class_data.end()) { - visited_class_data.insert(class_data); - // Overwrite the existing vector with the new ordering, note that the sets of objects are - // equivalent, but the order changes. This is why this is not a memory leak. - // TODO: Consider cleaning this up with a shared_ptr. - class_datas[class_data_index].release(); // NOLINT b/117926937 - class_datas[class_data_index].reset(class_data); - ++class_data_index; - } - } - CHECK_EQ(class_data_index, class_datas.Size()); - - if (DexLayout::kChangeClassDefOrder) { - // This currently produces dex files that violate the spec since the super class class_def is - // supposed to occur before any subclasses. - dex_ir::CollectionVector<dex_ir::ClassDef>& class_defs = header_->ClassDefs(); - CHECK_EQ(new_class_def_order.size(), class_defs.Size()); - for (size_t i = 0; i < class_defs.Size(); ++i) { - // Overwrite the existing vector with the new ordering, note that the sets of objects are - // equivalent, but the order changes. This is why this is not a memory leak. - // TODO: Consider cleaning this up with a shared_ptr. - class_defs[i].release(); // NOLINT b/117926937 - class_defs[i].reset(new_class_def_order[i]); - } - } -} - -void DexLayout::LayoutStringData(const DexFile* dex_file) { - const size_t num_strings = header_->StringIds().Size(); - std::vector<bool> is_shorty(num_strings, false); - std::vector<bool> from_hot_method(num_strings, false); - for (auto& class_def : header_->ClassDefs()) { - // A name of a profile class is probably going to get looked up by ClassTable::Lookup, mark it - // as hot. Add its super class and interfaces as well, which can be used during initialization. - const bool is_profile_class = - info_->ContainsClass(*dex_file, dex::TypeIndex(class_def->ClassType()->GetIndex())); - if (is_profile_class) { - from_hot_method[class_def->ClassType()->GetStringId()->GetIndex()] = true; - const dex_ir::TypeId* superclass = class_def->Superclass(); - if (superclass != nullptr) { - from_hot_method[superclass->GetStringId()->GetIndex()] = true; - } - const dex_ir::TypeList* interfaces = class_def->Interfaces(); - if (interfaces != nullptr) { - for (const dex_ir::TypeId* interface_type : *interfaces->GetTypeList()) { - from_hot_method[interface_type->GetStringId()->GetIndex()] = true; - } - } - } - dex_ir::ClassData* data = class_def->GetClassData(); - if (data == nullptr) { - continue; - } - for (size_t i = 0; i < 2; ++i) { - for (auto& method : *(i == 0 ? data->DirectMethods() : data->VirtualMethods())) { - const dex_ir::MethodId* method_id = method.GetMethodId(); - dex_ir::CodeItem* code_item = method.GetCodeItem(); - if (code_item == nullptr) { - continue; - } - const bool is_clinit = is_profile_class && - (method.GetAccessFlags() & kAccConstructor) != 0 && - (method.GetAccessFlags() & kAccStatic) != 0; - const bool method_executed = is_clinit || - info_->GetMethodHotness(MethodReference(dex_file, method_id->GetIndex())).IsInProfile(); - if (!method_executed) { - continue; - } - is_shorty[method_id->Proto()->Shorty()->GetIndex()] = true; - dex_ir::CodeFixups* fixups = code_item->GetCodeFixups(); - if (fixups == nullptr) { - continue; - } - // Add const-strings. - for (dex_ir::StringId* id : fixups->StringIds()) { - from_hot_method[id->GetIndex()] = true; - } - // Add field classes, names, and types. - for (dex_ir::FieldId* id : fixups->FieldIds()) { - // TODO: Only visit field ids from static getters and setters. - from_hot_method[id->Class()->GetStringId()->GetIndex()] = true; - from_hot_method[id->Name()->GetIndex()] = true; - from_hot_method[id->Type()->GetStringId()->GetIndex()] = true; - } - // For clinits, add referenced method classes, names, and protos. - if (is_clinit) { - for (dex_ir::MethodId* id : fixups->MethodIds()) { - from_hot_method[id->Class()->GetStringId()->GetIndex()] = true; - from_hot_method[id->Name()->GetIndex()] = true; - is_shorty[id->Proto()->Shorty()->GetIndex()] = true; - } - } - } - } - } - // Sort string data by specified order. - std::vector<dex_ir::StringId*> string_ids; - for (auto& string_id : header_->StringIds()) { - string_ids.push_back(string_id.get()); - } - std::sort(string_ids.begin(), - string_ids.end(), - [&is_shorty, &from_hot_method](const dex_ir::StringId* a, - const dex_ir::StringId* b) { - const bool a_is_hot = from_hot_method[a->GetIndex()]; - const bool b_is_hot = from_hot_method[b->GetIndex()]; - if (a_is_hot != b_is_hot) { - return a_is_hot < b_is_hot; - } - // After hot methods are partitioned, subpartition shorties. - const bool a_is_shorty = is_shorty[a->GetIndex()]; - const bool b_is_shorty = is_shorty[b->GetIndex()]; - if (a_is_shorty != b_is_shorty) { - return a_is_shorty < b_is_shorty; - } - // Order by index by default. - return a->GetIndex() < b->GetIndex(); - }); - auto& string_datas = header_->StringDatas(); - // Now we know what order we want the string data, reorder them. - size_t data_index = 0; - for (dex_ir::StringId* string_id : string_ids) { - string_datas[data_index].release(); // NOLINT b/117926937 - string_datas[data_index].reset(string_id->DataItem()); - ++data_index; - } - if (kIsDebugBuild) { - std::unordered_set<dex_ir::StringData*> visited; - for (const std::unique_ptr<dex_ir::StringData>& data : string_datas) { - visited.insert(data.get()); - } - for (auto& string_id : header_->StringIds()) { - CHECK(visited.find(string_id->DataItem()) != visited.end()); - } - } - CHECK_EQ(data_index, string_datas.Size()); -} - -// Orders code items according to specified class data ordering. -void DexLayout::LayoutCodeItems(const DexFile* dex_file) { - static constexpr InvokeType invoke_types[] = { - kDirect, - kVirtual - }; - - std::unordered_map<dex_ir::CodeItem*, LayoutType>& code_item_layout = - layout_hotness_info_.code_item_layout_; - - // Assign hotness flags to all code items. - for (InvokeType invoke_type : invoke_types) { - for (auto& class_def : header_->ClassDefs()) { - const bool is_profile_class = - info_->ContainsClass(*dex_file, dex::TypeIndex(class_def->ClassType()->GetIndex())); - - // Skip classes that are not defined in this dex file. - dex_ir::ClassData* class_data = class_def->GetClassData(); - if (class_data == nullptr) { - continue; - } - for (auto& method : *(invoke_type == InvokeType::kDirect - ? class_data->DirectMethods() - : class_data->VirtualMethods())) { - const dex_ir::MethodId *method_id = method.GetMethodId(); - dex_ir::CodeItem *code_item = method.GetCodeItem(); - if (code_item == nullptr) { - continue; - } - // Separate executed methods (clinits and profiled methods) from unexecuted methods. - const bool is_clinit = (method.GetAccessFlags() & kAccConstructor) != 0 && - (method.GetAccessFlags() & kAccStatic) != 0; - const bool is_startup_clinit = is_profile_class && is_clinit; - using Hotness = ProfileCompilationInfo::MethodHotness; - Hotness hotness = info_->GetMethodHotness(MethodReference(dex_file, method_id->GetIndex())); - LayoutType state = LayoutType::kLayoutTypeUnused; - if (hotness.IsHot()) { - // Hot code is compiled, maybe one day it won't be accessed. So lay it out together for - // now. - state = LayoutType::kLayoutTypeHot; - } else if (is_startup_clinit || hotness.GetFlags() == Hotness::kFlagStartup) { - // Startup clinit or a method that only has the startup flag. - state = LayoutType::kLayoutTypeStartupOnly; - } else if (is_clinit) { - state = LayoutType::kLayoutTypeUsedOnce; - } else if (hotness.IsInProfile()) { - state = LayoutType::kLayoutTypeSometimesUsed; - } - auto it = code_item_layout.emplace(code_item, state); - if (!it.second) { - LayoutType& layout_type = it.first->second; - // Already exists, merge the hotness. - layout_type = MergeLayoutType(layout_type, state); - } - } - } - } - - const auto& code_items = header_->CodeItems(); - if (VLOG_IS_ON(dex)) { - size_t layout_count[static_cast<size_t>(LayoutType::kLayoutTypeCount)] = {}; - for (const std::unique_ptr<dex_ir::CodeItem>& code_item : code_items) { - auto it = code_item_layout.find(code_item.get()); - DCHECK(it != code_item_layout.end()); - ++layout_count[static_cast<size_t>(it->second)]; - } - for (size_t i = 0; i < static_cast<size_t>(LayoutType::kLayoutTypeCount); ++i) { - LOG(INFO) << "Code items in category " << i << " count=" << layout_count[i]; - } - } - - // Sort the code items vector by new layout. The writing process will take care of calculating - // all the offsets. Stable sort to preserve any existing locality that might be there. - std::stable_sort(code_items.begin(), - code_items.end(), - [&](const std::unique_ptr<dex_ir::CodeItem>& a, - const std::unique_ptr<dex_ir::CodeItem>& b) { - auto it_a = code_item_layout.find(a.get()); - auto it_b = code_item_layout.find(b.get()); - DCHECK(it_a != code_item_layout.end()); - DCHECK(it_b != code_item_layout.end()); - const LayoutType layout_type_a = it_a->second; - const LayoutType layout_type_b = it_b->second; - return layout_type_a < layout_type_b; - }); -} - -void DexLayout::LayoutOutputFile(const DexFile* dex_file) { - LayoutStringData(dex_file); - LayoutClassDefsAndClassData(dex_file); - LayoutCodeItems(dex_file); -} - -bool DexLayout::OutputDexFile(const DexFile* input_dex_file, - bool compute_offsets, - std::unique_ptr<DexContainer>* dex_container, - std::string* error_msg) { - const std::string& dex_file_location = input_dex_file->GetLocation(); - std::unique_ptr<File> new_file; - // If options_.output_dex_directory_ is non null, we are outputting to a file. - if (options_.output_dex_directory_ != nullptr) { - std::string output_location(options_.output_dex_directory_); - const 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 (!output_location.empty() && output_location.back() != '/') { - output_location += "/"; - } - const size_t separator = dex_file_location.rfind('!'); - if (separator != std::string::npos) { - output_location += dex_file_location.substr(separator + 1); - } else { - output_location += "classes.dex"; - } - } - new_file.reset(OS::CreateEmptyFile(output_location.c_str())); - if (new_file == nullptr) { - LOG(ERROR) << "Could not create dex writer output file: " << output_location; - return false; - } - } - if (!DexWriter::Output(this, dex_container, compute_offsets, error_msg)) { - return false; - } - if (new_file != nullptr) { - DexContainer* const container = dex_container->get(); - DexContainer::Section* const main_section = container->GetMainSection(); - if (!new_file->WriteFully(main_section->Begin(), main_section->Size())) { - LOG(ERROR) << "Failed to write main section for dex file " << dex_file_location; - new_file->Erase(); - return false; - } - DexContainer::Section* const data_section = container->GetDataSection(); - if (!new_file->WriteFully(data_section->Begin(), data_section->Size())) { - LOG(ERROR) << "Failed to write data section for dex file " << dex_file_location; - new_file->Erase(); - return false; - } - UNUSED(new_file->FlushCloseOrErase()); - } - return true; -} - -/* - * Dumps the requested sections of the file. - */ -bool DexLayout::ProcessDexFile(const char* file_name, - const DexFile* dex_file, - size_t dex_file_index, - std::unique_ptr<DexContainer>* dex_container, - std::string* error_msg) { - const bool has_output_container = dex_container != nullptr; - const bool output = options_.output_dex_directory_ != nullptr || has_output_container; - - // Try to avoid eagerly assigning offsets to find bugs since Offset will abort if the offset - // is unassigned. - bool eagerly_assign_offsets = false; - if (options_.visualize_pattern_ || options_.show_section_statistics_ || options_.dump_) { - // These options required the offsets for dumping purposes. - eagerly_assign_offsets = true; - } - std::unique_ptr<dex_ir::Header> header(dex_ir::DexIrBuilder(*dex_file, - eagerly_assign_offsets, - GetOptions())); - SetHeader(header.get()); - - // Dexlayout does not support containers, but allow it if it has just single dex file. - const DexFile::Header& hdr = dex_file->GetHeader(); - if (hdr.HeaderOffset() != 0u || hdr.ContainerSize() != hdr.file_size_) { - *error_msg = "DEX containers are not supported in dexlayout"; - DCHECK(false) << *error_msg; - return false; - } - - if (options_.verbose_) { - fprintf(out_file_, - "Opened '%s', DEX version '%.3s'\n", - file_name, - dex_file->GetHeader().magic_.data() + 4); - } - - if (options_.visualize_pattern_) { - VisualizeDexLayout(header_, dex_file, dex_file_index, info_); - return true; - } - - if (options_.show_section_statistics_) { - ShowDexSectionStatistics(header_, dex_file_index, page_size_); - return true; - } - - // Dump dex file. - if (options_.dump_) { - DumpDexFile(); - } - - // In case we are outputting to a file, keep it open so we can verify. - if (output) { - // Layout information about what strings and code items are hot. Used by the writing process - // to generate the sections that are stored in the oat file. - bool do_layout = info_ != nullptr && !info_->IsEmpty(); - if (do_layout) { - LayoutOutputFile(dex_file); - } - // The output needs a dex container, use a temporary one. - std::unique_ptr<DexContainer> temp_container; - if (dex_container == nullptr) { - dex_container = &temp_container; - } - // If we didn't set the offsets eagerly, we definitely need to compute them here. - if (!OutputDexFile(dex_file, do_layout || !eagerly_assign_offsets, dex_container, error_msg)) { - return false; - } - - // Clear header before verifying to reduce peak RAM usage. - const size_t file_size = header_->FileSize(); - header.reset(); - - // Verify the output dex file's structure, only enabled by default for debug builds. - if (options_.verify_output_ && has_output_container) { - std::string location = "memory mapped file for " + std::string(file_name); - // Dex file verifier cannot handle compact dex. - bool verify = options_.compact_dex_level_ == CompactDexLevel::kCompactDexLevelNone; - DexContainer::Section* const main_section = (*dex_container)->GetMainSection(); - DexContainer::Section* const data_section = (*dex_container)->GetDataSection(); - DCHECK_EQ(file_size, main_section->Size()) - << main_section->Size() << " " << data_section->Size(); - auto container = std::make_unique<DexLoaderContainer>( - main_section->Begin(), main_section->End(), data_section->Begin(), data_section->End()); - ArtDexFileLoader dex_file_loader(std::move(container), location); - std::unique_ptr<const DexFile> output_dex_file( - dex_file_loader.Open(/* location_checksum= */ 0, - /*oat_dex_file=*/nullptr, - verify, - /*verify_checksum=*/false, - error_msg)); - CHECK(output_dex_file != nullptr) << "Failed to re-open output file:" << *error_msg; - - // Do IR-level comparison between input and output. This check ignores potential differences - // due to layout, so offsets are not checked. Instead, it checks the data contents of each - // item. - // - // Regenerate output IR to catch any bugs that might happen during writing. - std::unique_ptr<dex_ir::Header> output_header( - dex_ir::DexIrBuilder(*output_dex_file, - /*eagerly_assign_offsets=*/ true, - GetOptions())); - std::unique_ptr<dex_ir::Header> orig_header( - dex_ir::DexIrBuilder(*dex_file, - /*eagerly_assign_offsets=*/ true, - GetOptions())); - CHECK(VerifyOutputDexFile(output_header.get(), orig_header.get(), error_msg)) << *error_msg; - } - } - return true; -} - -/* - * Processes a single file (either direct .dex or indirect .zip/.jar/.apk). - */ -int DexLayout::ProcessFile(const char* file_name) { - if (options_.verbose_) { - fprintf(out_file_, "Processing '%s'...\n", file_name); - } - - // If the file is not a .dex file, the function tries .zip/.jar/.apk files, - // all of which are Zip archives with "classes.dex" inside. - const bool verify_checksum = !options_.ignore_bad_checksum_; - std::string error_msg; - ArtDexFileLoader dex_file_loader(file_name); - std::vector<std::unique_ptr<const DexFile>> dex_files; - if (!dex_file_loader.Open( - /* verify= */ true, verify_checksum, &error_msg, &dex_files)) { - // Display returned error message to user. Note that this error behavior - // differs from the error messages shown by the original Dalvik dexdump. - LOG(ERROR) << error_msg; - return -1; - } - - // Success. Either report checksum verification or process - // all dex files found in given file. - if (options_.checksum_only_) { - fprintf(out_file_, "Checksum verified\n"); - } else { - for (size_t i = 0; i < dex_files.size(); i++) { - // Pass in a null container to avoid output by default. - if (!ProcessDexFile(file_name, - dex_files[i].get(), - i, - /*dex_container=*/ nullptr, - &error_msg)) { - LOG(WARNING) << "Failed to run dex file " << i << " in " << file_name << " : " << error_msg; - } - } - } - return 0; -} - -} // namespace art diff --git a/dexlayout/dexlayout.h b/dexlayout/dexlayout.h deleted file mode 100644 index 42383070f5..0000000000 --- a/dexlayout/dexlayout.h +++ /dev/null @@ -1,222 +0,0 @@ -/* - * 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 the dexlayout utility. - * - * This is a tool to read dex files into an internal representation, - * reorganize the representation, and emit dex files with a better - * file layout. - */ - -#ifndef ART_DEXLAYOUT_DEXLAYOUT_H_ -#define ART_DEXLAYOUT_DEXLAYOUT_H_ - -#include <stdint.h> -#include <stdio.h> - -#include <set> -#include <unordered_map> - -#include "base/mem_map.h" -#include "dex/compact_dex_level.h" -#include "dex_container.h" -#include "dex/dex_file_layout.h" -#include "dex_ir.h" - -namespace art { - -class DexFile; -class Instruction; -class ProfileCompilationInfo; - -/* Supported output formats. */ -enum OutputFormat { - kOutputPlain = 0, // default - kOutputXml, // XML-style -}; - -/* Command-line options. */ -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_container_ = false; - bool show_annotations_ = false; - bool show_file_headers_ = false; - bool show_section_headers_ = false; - bool show_section_statistics_ = false; - bool verbose_ = false; - bool verify_output_ = kIsDebugBuild; - bool visualize_pattern_ = false; - bool update_checksum_ = false; - CompactDexLevel compact_dex_level_ = CompactDexLevel::kCompactDexLevelNone; - OutputFormat output_format_ = kOutputPlain; - const char* output_dex_directory_ = nullptr; - const char* output_file_name_ = nullptr; - const char* profile_file_name_ = nullptr; - // Filter that removes classes that don't have a matching descriptor (during IR creation). - // This speeds up cases when the output only requires a single class. - std::set<std::string> class_filter_; -}; - -// Hotness info -class DexLayoutHotnessInfo { - public: - // Store layout information so that the offset calculation can specify the section sizes. - std::unordered_map<dex_ir::CodeItem*, LayoutType> code_item_layout_; -}; - -class DexLayout { - public: - class VectorOutputContainer { - public: - // Begin is not necessarily aligned (for now). - uint8_t* Begin() { - return &data_[0]; - } - - private: - std::vector<uint8_t> data_; - }; - - - // Setting this to false disables class def layout entirely, which is stronger than strictly - // necessary to ensure the partial order w.r.t. class derivation. TODO: Re-enable (b/68317550). - // This should never be set for a device build, as changing class defs ids - // conflict with profiles and verification passed by Play. - static constexpr bool kChangeClassDefOrder = false; - static_assert(!(kIsTargetBuild && kChangeClassDefOrder), "Never set class reordering on target"); - - DexLayout(Options& options, - ProfileCompilationInfo* info, - FILE* out_file, - dex_ir::Header* header) - : options_(options), - info_(info), - out_file_(out_file), - header_(header), - page_size_(MemMap::GetPageSize()) { } - - int ProcessFile(const char* file_name); - bool ProcessDexFile(const char* file_name, - const DexFile* dex_file, - size_t dex_file_index, - std::unique_ptr<DexContainer>* dex_container, - std::string* error_msg); - - dex_ir::Header* GetHeader() const { return header_; } - void SetHeader(dex_ir::Header* header) { header_ = header; } - - DexLayoutSections& GetSections() { - return dex_sections_; - } - - const DexLayoutHotnessInfo& LayoutHotnessInfo() const { - return layout_hotness_info_; - } - - const Options& GetOptions() const { - return options_; - } - - 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 DumpMethodHandle(int idx); - void DumpCallSite(int idx); - void DumpClassAnnotations(int idx); - void DumpClassDef(int idx); - void DumpCode(uint32_t idx, - const dex_ir::CodeItem* code, - uint32_t code_offset, - const char* declaring_class_descriptor, - const char* method_name, - bool is_static, - const dex_ir::ProtoId* proto); - void DumpEncodedAnnotation(dex_ir::EncodedAnnotation* annotation); - void DumpEncodedValue(const dex_ir::EncodedValue* data); - void DumpFileHeader(); - void DumpIField(uint32_t idx, uint32_t flags, uint32_t hiddenapi_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, - uint32_t hiddenapi_flags, - const dex_ir::CodeItem* code, - int i); - void DumpPositionInfo(const dex_ir::CodeItem* code); - void DumpSField(uint32_t idx, - uint32_t flags, - uint32_t hiddenapi_flags, - int i, - dex_ir::EncodedValue* init); - void DumpDexFile(); - - void LayoutClassDefsAndClassData(const DexFile* dex_file); - void LayoutCodeItems(const DexFile* dex_file); - void LayoutStringData(const DexFile* dex_file); - - // Creates a new layout for the dex file based on profile info. - // Currently reorders ClassDefs, ClassDataItems, and CodeItems. - void LayoutOutputFile(const DexFile* dex_file); - bool OutputDexFile(const DexFile* input_dex_file, - bool compute_offsets, - std::unique_ptr<DexContainer>* dex_container, - std::string* error_msg); - - void DumpCFG(const DexFile* dex_file, int idx); - void DumpCFG(const DexFile* dex_file, uint32_t dex_method_idx, const dex::CodeItem* code); - - Options& options_; - ProfileCompilationInfo* info_; - FILE* out_file_; - dex_ir::Header* header_; - const size_t page_size_; - DexLayoutSections dex_sections_; - // Layout hotness information is only calculated when dexlayout is enabled. - DexLayoutHotnessInfo layout_hotness_info_; - - DISALLOW_COPY_AND_ASSIGN(DexLayout); -}; - -class DexLoaderContainer : public MemoryDexFileContainer { - public: - DexLoaderContainer(const uint8_t* begin, - const uint8_t* end, - const uint8_t* data_begin, - const uint8_t* data_end) - : MemoryDexFileContainer(begin, end), data_(data_begin, data_end - data_begin) {} - ArrayRef<const uint8_t> Data() const override { return data_; } - - private: - ArrayRef<const uint8_t> data_; -}; - -} // namespace art - -#endif // ART_DEXLAYOUT_DEXLAYOUT_H_ diff --git a/dexlayout/dexlayout_main.cc b/dexlayout/dexlayout_main.cc deleted file mode 100644 index 6c37b1d91f..0000000000 --- a/dexlayout/dexlayout_main.cc +++ /dev/null @@ -1,235 +0,0 @@ - /* - * 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. - * - * Main driver of the dexlayout utility. - * - * This is a tool to read dex files into an internal representation, - * reorganize the representation, and emit dex files with a better - * file layout. - */ - -#include "dexlayout.h" - -#include <fcntl.h> -#include <stdio.h> -#include <string.h> -#include <sys/stat.h> -#include <sys/types.h> -#include <unistd.h> - -#include <android-base/logging.h> - -#include "base/logging.h" // For InitLogging. -#include "base/mem_map.h" -#include "profile/profile_compilation_info.h" - -namespace art { - -static const char* kProgramName = "dexlayout"; - -/* - * Shows usage. - */ -static void Usage() { - LOG(ERROR) << "Copyright (C) 2016 The Android Open Source Project\n"; - LOG(ERROR) << kProgramName - << ": [-a] [-c] [-d] [-e] [-f] [-h] [-i] [-l layout] [-o outfile] [-p profile]" - " [-s] [-t] [-u] [-v] [-w directory] dexfile...\n"; - LOG(ERROR) << " -a : display annotations"; - LOG(ERROR) << " -b : build dex_ir"; - LOG(ERROR) << " -c : verify checksum and exit"; - LOG(ERROR) << " -d : disassemble code sections"; - LOG(ERROR) << " -e : display exported items only"; - LOG(ERROR) << " -f : display summary information from file header"; - LOG(ERROR) << " -h : display file header details"; - LOG(ERROR) << " -i : ignore checksum failures"; - LOG(ERROR) << " -l : output layout, either 'plain' or 'xml'"; - LOG(ERROR) << " -o : output file name (defaults to stdout)"; - LOG(ERROR) << " -p : profile file name (defaults to no profile)"; - LOG(ERROR) << " -s : visualize reference pattern"; - LOG(ERROR) << " -t : display file section sizes"; - LOG(ERROR) << " -u : update dex checksums"; - LOG(ERROR) << " -v : verify output file is canonical to input (IR level comparison)"; - LOG(ERROR) << " -w : output dex directory"; - LOG(ERROR) << " -x : compact dex generation level, either 'none' or 'fast'"; -} - -NO_RETURN static void Abort(const char* msg) { - LOG(ERROR) << msg; - exit(1); -} - -/* - * Main driver of the dexlayout utility. - */ -int DexlayoutDriver(int argc, char** argv) { - // Art specific set up. - InitLogging(argv, Abort); - MemMap::Init(); - - Options options; - options.dump_ = true; - options.verbose_ = true; - bool want_usage = false; - - // Parse all arguments. - while (true) { - const int ic = getopt(argc, argv, "abcdefghil:o:p:stuvw:x:"); - if (ic < 0) { - break; // done - } - switch (ic) { - case 'a': // display annotations - options.show_annotations_ = true; - break; - case 'b': // build dex_ir - options.build_dex_ir_ = true; - break; - case 'c': // verify the checksum then exit - options.checksum_only_ = true; - break; - case 'd': // disassemble Dalvik instructions - options.disassemble_ = true; - break; - case 'e': // exported items only - options.exports_only_ = true; - break; - case 'f': // display outer file header - options.show_file_headers_ = true; - break; - case 'h': // display section headers, i.e. all meta-data - options.show_section_headers_ = true; - break; - case 'i': // continue even if checksum is bad - options.ignore_bad_checksum_ = true; - break; - case 'l': // layout - if (strcmp(optarg, "plain") == 0) { - options.output_format_ = kOutputPlain; - } else if (strcmp(optarg, "xml") == 0) { - options.output_format_ = kOutputXml; - options.verbose_ = false; - } else { - want_usage = true; - } - break; - case 'o': // output file - options.output_file_name_ = optarg; - break; - case 'p': // profile file - options.profile_file_name_ = optarg; - break; - case 's': // visualize access pattern - options.visualize_pattern_ = true; - options.verbose_ = false; - break; - case 't': // display section statistics - options.show_section_statistics_ = true; - options.verbose_ = false; - break; - case 'u': // update checksum - options.update_checksum_ = true; - break; - case 'v': // verify output - options.verify_output_ = true; - break; - case 'w': // output dex files directory - options.output_dex_directory_ = optarg; - break; - case 'x': // compact dex level - if (strcmp(optarg, "none") == 0) { - options.compact_dex_level_ = CompactDexLevel::kCompactDexLevelNone; - } else if (strcmp(optarg, "fast") == 0) { - options.compact_dex_level_ = CompactDexLevel::kCompactDexLevelFast; - } else { - want_usage = true; - } - break; - default: - want_usage = true; - break; - } // switch - } // while - - // Detect early problems. - if (optind == argc) { - LOG(ERROR) << "no file specified"; - want_usage = true; - } - if (options.checksum_only_ && options.ignore_bad_checksum_) { - LOG(ERROR) << "Can't specify both -c and -i"; - want_usage = true; - } - if (want_usage) { - Usage(); - return 2; - } - - // Open alternative output file. - FILE* out_file = stdout; - if (options.output_file_name_) { - out_file = fopen(options.output_file_name_, "we"); - if (!out_file) { - PLOG(ERROR) << "Can't open " << options.output_file_name_; - return 1; - } - } - - // Open profile file. - std::unique_ptr<ProfileCompilationInfo> profile_info; - if (options.profile_file_name_) { -#ifdef _WIN32 - int flags = O_RDONLY; -#else - int flags = O_RDONLY | O_CLOEXEC; -#endif - int profile_fd = open(options.profile_file_name_, flags); - if (profile_fd < 0) { - PLOG(ERROR) << "Can't open " << options.profile_file_name_; - return 1; - } - profile_info.reset(new ProfileCompilationInfo()); - if (!profile_info->Load(profile_fd)) { - LOG(ERROR) << "Can't read profile info from " << options.profile_file_name_; - return 1; - } - } - PLOG(INFO) << "After opening profile file"; - - // Create DexLayout instance. - DexLayout dex_layout(options, profile_info.get(), out_file, /*header=*/ nullptr); - - // Process all files supplied on command line. - int result = 0; - while (optind < argc) { - result |= dex_layout.ProcessFile(argv[optind++]); - } // while - - if (options.output_file_name_) { - CHECK(out_file != nullptr && out_file != stdout); - fclose(out_file); - } - - return result != 0 ? 1 : 0; -} - -} // namespace art - -int main(int argc, char** argv) { - // Output all logging to stderr. - android::base::SetLogger(android::base::StderrLogger); - - return art::DexlayoutDriver(argc, argv); -} diff --git a/dexlayout/dexlayout_test.cc b/dexlayout/dexlayout_test.cc deleted file mode 100644 index 97c19ee147..0000000000 --- a/dexlayout/dexlayout_test.cc +++ /dev/null @@ -1,834 +0,0 @@ -/* - * 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. - */ - -#include "dexlayout.h" - -#include <sys/types.h> -#include <unistd.h> - -#include <memory> -#include <sstream> -#include <string> -#include <vector> - -#include "base/common_art_test.h" -#include "base/unix_file/fd_file.h" -#include "base/utils.h" -#include "dex/art_dex_file_loader.h" -#include "dex/base64_test_util.h" -#include "dex/class_accessor-inl.h" -#include "dex/code_item_accessors-inl.h" -#include "dex/dex_file-inl.h" -#include "dex/dex_file_loader.h" -#include "exec_utils.h" -#include "profile/profile_compilation_info.h" - -namespace art { - -static const char kDexFileLayoutInputDex[] = - "ZGV4CjAzNQD1KW3+B8NAB0f2A/ZVIBJ0aHrGIqcpVTAUAgAAcAAAAHhWNBIAAAAAAAAAAIwBAAAH" - "AAAAcAAAAAQAAACMAAAAAQAAAJwAAAAAAAAAAAAAAAMAAACoAAAAAgAAAMAAAAAUAQAAAAEAADAB" - "AAA4AQAAQAEAAEgBAABNAQAAUgEAAGYBAAADAAAABAAAAAUAAAAGAAAABgAAAAMAAAAAAAAAAAAA" - "AAAAAAABAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAEAAAAAAAAAdQEAAAAAAAABAAAA" - "AAAAAAIAAAAAAAAAAgAAAAAAAAB/AQAAAAAAAAEAAQABAAAAaQEAAAQAAABwEAIAAAAOAAEAAQAB" - "AAAAbwEAAAQAAABwEAIAAAAOAAY8aW5pdD4ABkEuamF2YQAGQi5qYXZhAANMQTsAA0xCOwASTGph" - "dmEvbGFuZy9PYmplY3Q7AAFWAAQABw48AAQABw48AAAAAQAAgIAEgAIAAAEAAYCABJgCAAAACwAA" - "AAAAAAABAAAAAAAAAAEAAAAHAAAAcAAAAAIAAAAEAAAAjAAAAAMAAAABAAAAnAAAAAUAAAADAAAA" - "qAAAAAYAAAACAAAAwAAAAAEgAAACAAAAAAEAAAIgAAAHAAAAMAEAAAMgAAACAAAAaQEAAAAgAAAC" - "AAAAdQEAAAAQAAABAAAAjAEAAA=="; - -// Dex file with catch handler unreferenced by try blocks. -// Constructed by building a dex file with try/catch blocks and hex editing. -static const char kUnreferencedCatchHandlerInputDex[] = - "ZGV4CjAzNQD+exd52Y0f9nY5x5GmInXq5nXrO6Kl2RV4AwAAcAAAAHhWNBIAAAAAAAAAANgCAAAS" - "AAAAcAAAAAgAAAC4AAAAAwAAANgAAAABAAAA/AAAAAQAAAAEAQAAAQAAACQBAAA0AgAARAEAANYB" - "AADeAQAA5gEAAO4BAAAAAgAADwIAACYCAAA9AgAAUQIAAGUCAAB5AgAAfwIAAIUCAACIAgAAjAIA" - "AKECAACnAgAArAIAAAQAAAAFAAAABgAAAAcAAAAIAAAACQAAAAwAAAAOAAAADAAAAAYAAAAAAAAA" - "DQAAAAYAAADIAQAADQAAAAYAAADQAQAABQABABAAAAAAAAAAAAAAAAAAAgAPAAAAAQABABEAAAAD" - "AAAAAAAAAAAAAAABAAAAAwAAAAAAAAADAAAAAAAAAMgCAAAAAAAAAQABAAEAAAC1AgAABAAAAHAQ" - "AwAAAA4AAwABAAIAAgC6AgAAIQAAAGIAAAAaAQoAbiACABAAYgAAABoBCwBuIAIAEAAOAA0AYgAA" - "ABoBAQBuIAIAEAAo8A0AYgAAABoBAgBuIAIAEAAo7gAAAAAAAAcAAQAHAAAABwABAAIBAg8BAhgA" - "AQAAAAQAAAABAAAABwAGPGluaXQ+AAZDYXRjaDEABkNhdGNoMgAQSGFuZGxlclRlc3QuamF2YQAN" - "TEhhbmRsZXJUZXN0OwAVTGphdmEvaW8vUHJpbnRTdHJlYW07ABVMamF2YS9sYW5nL0V4Y2VwdGlv" - "bjsAEkxqYXZhL2xhbmcvT2JqZWN0OwASTGphdmEvbGFuZy9TdHJpbmc7ABJMamF2YS9sYW5nL1N5" - "c3RlbTsABFRyeTEABFRyeTIAAVYAAlZMABNbTGphdmEvbGFuZy9TdHJpbmc7AARtYWluAANvdXQA" - "B3ByaW50bG4AAQAHDgAEAQAHDn17AncdHoseAAAAAgAAgYAExAIBCdwCAAANAAAAAAAAAAEAAAAA" - "AAAAAQAAABIAAABwAAAAAgAAAAgAAAC4AAAAAwAAAAMAAADYAAAABAAAAAEAAAD8AAAABQAAAAQA" - "AAAEAQAABgAAAAEAAAAkAQAAASAAAAIAAABEAQAAARAAAAIAAADIAQAAAiAAABIAAADWAQAAAyAA" - "AAIAAAC1AgAAACAAAAEAAADIAgAAABAAAAEAAADYAgAA"; - -// Dex file with 0-size (catch all only) catch handler unreferenced by try blocks. -// Constructed by building a dex file with try/catch blocks and hex editing. -static const char kUnreferenced0SizeCatchHandlerInputDex[] = - "ZGV4CjAzNQCEbEEvMstSNpQpjPdfMEfUBS48cis2QRJoAwAAcAAAAHhWNBIAAAAAAAAAAMgCAAAR" - "AAAAcAAAAAcAAAC0AAAAAwAAANAAAAABAAAA9AAAAAQAAAD8AAAAAQAAABwBAAAsAgAAPAEAAOoB" - "AADyAQAABAIAABMCAAAqAgAAPgIAAFICAABmAgAAaQIAAG0CAACCAgAAhgIAAIoCAACQAgAAlQIA" - "AJ4CAACiAgAAAgAAAAMAAAAEAAAABQAAAAYAAAAHAAAACQAAAAcAAAAFAAAAAAAAAAgAAAAFAAAA" - "3AEAAAgAAAAFAAAA5AEAAAQAAQANAAAAAAAAAAAAAAAAAAIADAAAAAEAAQAOAAAAAgAAAAAAAAAA" - "AAAAAQAAAAIAAAAAAAAAAQAAAAAAAAC5AgAAAAAAAAEAAQABAAAApgIAAAQAAABwEAMAAAAOAAQA" - "AQACAAIAqwIAAC8AAABiAAAAGgEPAG4gAgAQAGIAAAAaAQoAbiACABAAYgAAABoBEABuIAIAEABi" - "AAAAGgELAG4gAgAQAA4ADQBiAQAAGgIKAG4gAgAhACcADQBiAQAAGgILAG4gAgAhACcAAAAAAAAA" - "BwABAA4AAAAHAAEAAgAdACYAAAABAAAAAwAAAAEAAAAGAAY8aW5pdD4AEEhhbmRsZXJUZXN0Lmph" - "dmEADUxIYW5kbGVyVGVzdDsAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwASTGphdmEvbGFuZy9PYmpl" - "Y3Q7ABJMamF2YS9sYW5nL1N0cmluZzsAEkxqYXZhL2xhbmcvU3lzdGVtOwABVgACVkwAE1tMamF2" - "YS9sYW5nL1N0cmluZzsAAmYxAAJmMgAEbWFpbgADb3V0AAdwcmludGxuAAJ0MQACdDIAAQAHDgAE" - "AQAHDnl7eXkCeB2bAAAAAgAAgYAEvAIBCdQCAA0AAAAAAAAAAQAAAAAAAAABAAAAEQAAAHAAAAAC" - "AAAABwAAALQAAAADAAAAAwAAANAAAAAEAAAAAQAAAPQAAAAFAAAABAAAAPwAAAAGAAAAAQAAABwB" - "AAABIAAAAgAAADwBAAABEAAAAgAAANwBAAACIAAAEQAAAOoBAAADIAAAAgAAAKYCAAAAIAAAAQAA" - "ALkCAAAAEAAAAQAAAMgCAAA="; - -// Dex file with an unreferenced catch handler at end of code item. -// Constructed by building a dex file with try/catch blocks and hex editing. -static const char kUnreferencedEndingCatchHandlerInputDex[] = - "ZGV4CjAzNQCEflufI6xGTDDRmLpbfYi6ujPrDLIwvYcEBAAAcAAAAHhWNBIAAAAAAAAAAGQDAAAT" - "AAAAcAAAAAgAAAC8AAAAAwAAANwAAAABAAAAAAEAAAUAAAAIAQAAAQAAADABAAC0AgAAUAEAAE4C" - "AABWAgAAXgIAAGYCAAB4AgAAhwIAAJ4CAAC1AgAAyQIAAN0CAADxAgAA9wIAAP0CAAAAAwAABAMA" - "ABkDAAAcAwAAIgMAACcDAAAEAAAABQAAAAYAAAAHAAAACAAAAAkAAAAMAAAADgAAAAwAAAAGAAAA" - "AAAAAA0AAAAGAAAAQAIAAA0AAAAGAAAASAIAAAUAAQARAAAAAAAAAAAAAAAAAAAADwAAAAAAAgAQ" - "AAAAAQABABIAAAADAAAAAAAAAAAAAAABAAAAAwAAAAAAAAADAAAAAAAAAFADAAAAAAAAAQABAAEA" - "AAAwAwAABAAAAHAQBAAAAA4AAgAAAAIAAgA1AwAAIQAAAGIAAAAaAQoAbiADABAAYgAAABoBCwBu" - "IAMAEAAOAA0AYgAAABoBAQBuIAMAEAAo8A0AYgAAABoBAgBuIAMAEAAo7gAAAAAAAAcAAQAHAAAA" - "BwABAAIBAg8BAhgAAwABAAIAAgBCAwAAIQAAAGIAAAAaAQoAbiADABAAYgAAABoBCwBuIAMAEAAO" - "AA0AYgAAABoBAQBuIAMAEAAo8A0AYgAAABoBAgBuIAMAEAAo7gAAAAAAAAcAAQAHAAAABwABAAIB" - "Ag8BAhgAAQAAAAQAAAABAAAABwAGPGluaXQ+AAZDYXRjaDEABkNhdGNoMgAQSGFuZGxlclRlc3Qu" - "amF2YQANTEhhbmRsZXJUZXN0OwAVTGphdmEvaW8vUHJpbnRTdHJlYW07ABVMamF2YS9sYW5nL0V4" - "Y2VwdGlvbjsAEkxqYXZhL2xhbmcvT2JqZWN0OwASTGphdmEvbGFuZy9TdHJpbmc7ABJMamF2YS9s" - "YW5nL1N5c3RlbTsABFRyeTEABFRyeTIAAVYAAlZMABNbTGphdmEvbGFuZy9TdHJpbmc7AAFhAARt" - "YWluAANvdXQAB3ByaW50bG4AAQAHDgAEAAcOfHsCeB0eih4AEQEABw59ewJ3HR6LHgAAAAMAAIGA" - "BNACAQnoAgEJ1AMAAA0AAAAAAAAAAQAAAAAAAAABAAAAEwAAAHAAAAACAAAACAAAALwAAAADAAAA" - "AwAAANwAAAAEAAAAAQAAAAABAAAFAAAABQAAAAgBAAAGAAAAAQAAADABAAABIAAAAwAAAFABAAAB" - "EAAAAgAAAEACAAACIAAAEwAAAE4CAAADIAAAAwAAADADAAAAIAAAAQAAAFADAAAAEAAAAQAAAGQD" - "AAA="; - -// Dex file with multiple code items that have the same debug_info_off_. Constructed by a modified -// dexlayout on XandY. -static const char kDexFileDuplicateOffset[] = - "ZGV4CjAzNwAQfXfPCB8qCxo7MqdFhmHZQwCv8+udHD8MBAAAcAAAAHhWNBIAAAAAAAAAAFQDAAAT" - "AAAAcAAAAAgAAAC8AAAAAQAAANwAAAABAAAA6AAAAAUAAADwAAAAAwAAABgBAACUAgAAeAEAABQC" - "AAAeAgAAJgIAACsCAAAyAgAANwIAAFsCAAB7AgAAngIAALICAAC1AgAAvQIAAMUCAADIAgAA1QIA" - "AOkCAADvAgAA9QIAAPwCAAACAAAAAwAAAAQAAAAFAAAABgAAAAcAAAAIAAAACQAAAAkAAAAHAAAA" - "AAAAAAIAAQASAAAAAAAAAAEAAAABAAAAAQAAAAIAAAAAAAAAAgAAAAEAAAAGAAAAAQAAAAAAAAAA" - "AAAABgAAAAAAAAAKAAAAAAAAACsDAAAAAAAAAQAAAAAAAAAGAAAAAAAAAAsAAAD0AQAANQMAAAAA" - "AAACAAAAAAAAAAAAAAAAAAAACwAAAAQCAAA/AwAAAAAAAAIAAAAUAwAAGgMAAAEAAAAjAwAAAQAB" - "AAEAAAAFAAAABAAAAHAQBAAAAA4AAQABAAEAAAAFAAAABAAAAHAQBAAAAA4AAQAAAAEAAAAFAAAA" - "CAAAACIAAQBwEAEAAABpAAAADgABAAEAAQAAAAUAAAAEAAAAcBAAAAAADgB4AQAAAAAAAAAAAAAA" - "AAAAhAEAAAAAAAAAAAAAAAAAAAg8Y2xpbml0PgAGPGluaXQ+AANMWDsABUxZJFo7AANMWTsAIkxk" - "YWx2aWsvYW5ub3RhdGlvbi9FbmNsb3NpbmdDbGFzczsAHkxkYWx2aWsvYW5ub3RhdGlvbi9Jbm5l" - "ckNsYXNzOwAhTGRhbHZpay9hbm5vdGF0aW9uL01lbWJlckNsYXNzZXM7ABJMamF2YS9sYW5nL09i" - "amVjdDsAAVYABlguamF2YQAGWS5qYXZhAAFaAAthY2Nlc3NGbGFncwASZW1pdHRlcjogamFjay00" - "LjI1AARuYW1lAAR0aGlzAAV2YWx1ZQABegARAAcOABMABw4AEgAHDnYAEQAHDgACAwERGAICBAIN" - "BAgPFwwCBQERHAEYAQAAAQAAgIAEjAMAAAEAAYCABKQDAQACAAAIAoiABLwDAYCABNwDAAAADwAA" - "AAAAAAABAAAAAAAAAAEAAAATAAAAcAAAAAIAAAAIAAAAvAAAAAMAAAABAAAA3AAAAAQAAAABAAAA" - "6AAAAAUAAAAFAAAA8AAAAAYAAAADAAAAGAEAAAMQAAACAAAAeAEAAAEgAAAEAAAAjAEAAAYgAAAC" - "AAAA9AEAAAIgAAATAAAAFAIAAAMgAAAEAAAA/wIAAAQgAAADAAAAFAMAAAAgAAADAAAAKwMAAAAQ" - "AAABAAAAVAMAAA=="; - -// Dex file with null value for annotations_off in the annotation_set_ref_list. -// Constructed by building a dex file with annotations and hex editing. -static const char kNullSetRefListElementInputDex[] = - "ZGV4CjAzNQB1iA+7ZwgkF+7E6ZesYFc2lRAR3qnRAanwAwAAcAAAAHhWNBIAAAAAAAAAACADAAAS" - "AAAAcAAAAAgAAAC4AAAAAwAAANgAAAABAAAA/AAAAAQAAAAEAQAAAgAAACQBAACMAgAAZAEAAOgB" - "AADwAQAAAAIAAAMCAAAQAgAAIAIAADQCAABIAgAAawIAAI0CAAC1AgAAyAIAANECAADUAgAA2QIA" - "ANwCAADjAgAA6QIAAAMAAAAEAAAABQAAAAYAAAAHAAAACAAAAAkAAAAMAAAAAgAAAAMAAAAAAAAA" - "DAAAAAcAAAAAAAAADQAAAAcAAADgAQAABgAGAAsAAAAAAAEAAAAAAAAAAgAOAAAAAQAAABAAAAAC" - "AAEAAAAAAAAAAAAAAAAAAgAAAAAAAAABAAAAsAEAAAgDAAAAAAAAAQAAAAEmAAACAAAA2AEAAAoA" - "AADIAQAAFgMAAAAAAAACAAAAAAAAAHwBAAABAAAA/AIAAAAAAAABAAAAAgMAAAEAAQABAAAA8AIA" - "AAQAAABwEAMAAAAOAAIAAgAAAAAA9QIAAAEAAAAOAAAAAAAAAAAAAAAAAAAAAQAAAAEAAABkAQAA" - "cAEAAAAAAAAAAAAAAAAAAAEAAAAEAAAAAgAAAAMAAwAGPGluaXQ+AA5Bbm5vQ2xhc3MuamF2YQAB" - "TAALTEFubm9DbGFzczsADkxNeUFubm90YXRpb247ABJMamF2YS9sYW5nL09iamVjdDsAEkxqYXZh" - "L2xhbmcvU3RyaW5nOwAhTGphdmEvbGFuZy9hbm5vdGF0aW9uL0Fubm90YXRpb247ACBMamF2YS9s" - "YW5nL2Fubm90YXRpb24vUmV0ZW50aW9uOwAmTGphdmEvbGFuZy9hbm5vdGF0aW9uL1JldGVudGlv" - "blBvbGljeTsAEU15QW5ub3RhdGlvbi5qYXZhAAdSVU5USU1FAAFWAANWTEwAAWEABWFOYW1lAARu" - "YW1lAAV2YWx1ZQABAAcOAAICAAAHDgABBQERGwABAQEQFw8AAAIAAICABIQDAQmcAwAAAAECgQgA" - "AAARAAAAAAAAAAEAAAAAAAAAAQAAABIAAABwAAAAAgAAAAgAAAC4AAAAAwAAAAMAAADYAAAABAAA" - "AAEAAAD8AAAABQAAAAQAAAAEAQAABgAAAAIAAAAkAQAAAhAAAAEAAABkAQAAAxAAAAMAAABwAQAA" - "ASAAAAIAAACEAQAABiAAAAIAAACwAQAAARAAAAIAAADYAQAAAiAAABIAAADoAQAAAyAAAAIAAADw" - "AgAABCAAAAIAAAD8AgAAACAAAAIAAAAIAwAAABAAAAEAAAAgAwAA"; - -// Dex file with shared empty class data item for multiple class defs. -// Constructing by building a dex file with multiple classes and hex editing. -static const char kMultiClassDataInputDex[] = - "ZGV4CjAzNQALJgF9TtnLq748xVe/+wyxETrT9lTEiW6YAQAAcAAAAHhWNBIAAAAAAAAAADQBAAAI" - "AAAAcAAAAAQAAACQAAAAAAAAAAAAAAACAAAAoAAAAAAAAAAAAAAAAgAAALAAAACoAAAA8AAAAPAA" - "AAD4AAAAAAEAAAMBAAAIAQAADQEAACEBAAAkAQAAAgAAAAMAAAAEAAAABQAAAAEAAAAGAAAAAgAA" - "AAcAAAABAAAAAQYAAAMAAAAAAAAAAAAAAAAAAAAnAQAAAAAAAAIAAAABBgAAAwAAAAAAAAABAAAA" - "AAAAACcBAAAAAAAABkEuamF2YQAGQi5qYXZhAAFJAANMQTsAA0xCOwASTGphdmEvbGFuZy9PYmpl" - "Y3Q7AAFhAAFiAAAAAAABAAAAARkAAAAIAAAAAAAAAAEAAAAAAAAAAQAAAAgAAABwAAAAAgAAAAQA" - "AACQAAAABAAAAAIAAACgAAAABgAAAAIAAACwAAAAAiAAAAgAAADwAAAAACAAAAIAAAAnAQAAABAA" - "AAEAAAA0AQAA"; - -// Dex file with code info followed by non 4-byte aligned section. -// Constructed a dex file with code info followed by string data and hex edited. -static const char kUnalignedCodeInfoInputDex[] = - "ZGV4CjAzNQDXJzXNb4iWn2SLhmLydW/8h1K9moERIw7UAQAAcAAAAHhWNBIAAAAAAAAAAEwBAAAG" - "AAAAcAAAAAMAAACIAAAAAQAAAJQAAAAAAAAAAAAAAAMAAACgAAAAAQAAALgAAAD8AAAA2AAAAAIB" - "AAAKAQAAEgEAABcBAAArAQAALgEAAAIAAAADAAAABAAAAAQAAAACAAAAAAAAAAAAAAAAAAAAAAAA" - "AAUAAAABAAAAAAAAAAAAAAABAAAAAQAAAAAAAAABAAAAAAAAADsBAAAAAAAAAQABAAEAAAAxAQAA" - "BAAAAHAQAgAAAA4AAQABAAAAAAA2AQAAAQAAAA4ABjxpbml0PgAGQS5qYXZhAANMQTsAEkxqYXZh" - "L2xhbmcvT2JqZWN0OwABVgABYQABAAcOAAMABw4AAAABAQCBgATYAQEB8AEAAAALAAAAAAAAAAEA" - "AAAAAAAAAQAAAAYAAABwAAAAAgAAAAMAAACIAAAAAwAAAAEAAACUAAAABQAAAAMAAACgAAAABgAA" - "AAEAAAC4AAAAASAAAAIAAADYAAAAAiAAAAYAAAACAQAAAyAAAAIAAAAxAQAAACAAAAEAAAA7AQAA" - "ABAAAAEAAABMAQAA"; - -// Dex file with class data section preceding code items. -// Constructed by passing dex file through dexmerger tool and hex editing. -static const char kClassDataBeforeCodeInputDex[] = - "ZGV4CjAzNQCZKmCu3XXn4zvxCh5VH0gZNNobEAcsc49EAgAAcAAAAHhWNBIAAAAAAAAAAAQBAAAJ" - "AAAAcAAAAAQAAACUAAAAAgAAAKQAAAAAAAAAAAAAAAUAAAC8AAAAAQAAAOQAAABAAQAABAEAAPgB" - "AAAAAgAACAIAAAsCAAAQAgAAJAIAACcCAAAqAgAALQIAAAIAAAADAAAABAAAAAUAAAACAAAAAAAA" - "AAAAAAAFAAAAAwAAAAAAAAABAAEAAAAAAAEAAAAGAAAAAQAAAAcAAAABAAAACAAAAAIAAQAAAAAA" - "AQAAAAEAAAACAAAAAAAAAAEAAAAAAAAAjAEAAAAAAAALAAAAAAAAAAEAAAAAAAAAAQAAAAkAAABw" - "AAAAAgAAAAQAAACUAAAAAwAAAAIAAACkAAAABQAAAAUAAAC8AAAABgAAAAEAAADkAAAAABAAAAEA" - "AAAEAQAAACAAAAEAAACMAQAAASAAAAQAAACkAQAAAiAAAAkAAAD4AQAAAyAAAAQAAAAwAgAAAAAB" - "AwCBgASkAwEBvAMBAdADAQHkAwAAAQABAAEAAAAwAgAABAAAAHAQBAAAAA4AAgABAAAAAAA1AgAA" - "AgAAABIQDwACAAEAAAAAADoCAAACAAAAEiAPAAIAAQAAAAAAPwIAAAIAAAASMA8ABjxpbml0PgAG" - "QS5qYXZhAAFJAANMQTsAEkxqYXZhL2xhbmcvT2JqZWN0OwABVgABYQABYgABYwABAAcOAAMABw4A" - "BgAHDgAJAAcOAA=="; - -// Dex file with local info containing a null type descriptor. -// Constructed a dex file with debug info sequence containing DBG_RESTART_LOCAL without any -// DBG_START_LOCAL to give it a declared type. -static const char kUnknownTypeDebugInfoInputDex[] = - "ZGV4CjAzNQBtKqZfzjHLNSNwW2A6Bz9FuCEX0sL+FF38AQAAcAAAAHhWNBIAAAAAAAAAAHQBAAAI" - "AAAAcAAAAAQAAACQAAAAAgAAAKAAAAAAAAAAAAAAAAMAAAC4AAAAAQAAANAAAAAMAQAA8AAAABwB" - "AAAkAQAALAEAAC8BAAA0AQAASAEAAEsBAABOAQAAAgAAAAMAAAAEAAAABQAAAAIAAAAAAAAAAAAA" - "AAUAAAADAAAAAAAAAAEAAQAAAAAAAQAAAAYAAAACAAEAAAAAAAEAAAABAAAAAgAAAAAAAAABAAAA" - "AAAAAGMBAAAAAAAAAQABAAEAAABUAQAABAAAAHAQAgAAAA4AAgABAAAAAABZAQAAAgAAABIQDwAG" - "PGluaXQ+AAZBLmphdmEAAUkAA0xBOwASTGphdmEvbGFuZy9PYmplY3Q7AAFWAAFhAAR0aGlzAAEA" - "Bw4AAwAHDh4GAAYAAAAAAQEAgYAE8AEBAYgCAAAACwAAAAAAAAABAAAAAAAAAAEAAAAIAAAAcAAA" - "AAIAAAAEAAAAkAAAAAMAAAACAAAAoAAAAAUAAAADAAAAuAAAAAYAAAABAAAA0AAAAAEgAAACAAAA" - "8AAAAAIgAAAIAAAAHAEAAAMgAAACAAAAVAEAAAAgAAABAAAAYwEAAAAQAAABAAAAdAEAAA=="; - -// Dex file with multiple class data items pointing to the same code item. -// Constructed by hex editing. -static const char kDuplicateCodeItemInputDex[] = - "ZGV4CjAzNQCwKtVglQOmLWuHwldN5jkBOInC7mTMhJMAAgAAcAAAAHhWNBIAAAAAAAAAAHgBAAAH" - "AAAAcAAAAAMAAACMAAAAAQAAAJgAAAAAAAAAAAAAAAQAAACkAAAAAQAAAMQAAAAcAQAA5AAAACQB" - "AAAsAQAANAEAADkBAABNAQAAUAEAAFMBAAACAAAAAwAAAAQAAAAEAAAAAgAAAAAAAAAAAAAAAAAA" - "AAAAAAAFAAAAAAAAAAYAAAABAAAAAAAAAAAAAAABAAAAAQAAAAAAAAABAAAAAAAAAGUBAAAAAAAA" - "AQABAAEAAABWAQAABAAAAHAQAwAAAA4AAQABAAAAAABbAQAAAQAAAA4AAAABAAEAAAAAAGABAAAB" - "AAAADgAAAAY8aW5pdD4ABkEuamF2YQADTEE7ABJMamF2YS9sYW5nL09iamVjdDsAAVYAAWEAAWIA" - "AQAHDgADAAcOAAUABw4AAAABAgCBgATkAQEA/AEBAPwBAAsAAAAAAAAAAQAAAAAAAAABAAAABwAA" - "AHAAAAACAAAAAwAAAIwAAAADAAAAAQAAAJgAAAAFAAAABAAAAKQAAAAGAAAAAQAAAMQAAAABIAAA" - "AwAAAOQAAAACIAAABwAAACQBAAADIAAAAwAAAFYBAAAAIAAAAQAAAGUBAAAAEAAAAQAAAHgBAAA="; - -// Returns the default compact dex option for dexlayout. -static std::vector<std::string> DefaultCompactDexOption() { return {"-x", "none"}; } - -static void WriteBase64ToFile(const char* base64, File* file) { - // Decode base64. - CHECK(base64 != nullptr); - size_t length; - std::unique_ptr<uint8_t[]> bytes(DecodeBase64(base64, &length)); - CHECK(bytes != nullptr); - if (!file->WriteFully(bytes.get(), length)) { - PLOG(FATAL) << "Failed to write base64 as file"; - } -} - -static void WriteFileBase64(const char* base64, const char* location) { - // Write to provided file. - std::unique_ptr<File> file(OS::CreateEmptyFile(location)); - CHECK(file != nullptr); - WriteBase64ToFile(base64, file.get()); - if (file->FlushCloseOrErase() != 0) { - PLOG(FATAL) << "Could not flush and close test file."; - } -} - -class DexLayoutTest : public CommonArtTest { - protected: - std::string GetDexLayoutPath() { - return GetArtBinDir() + "/dexlayoutd"; - } - - // Runs FullPlainOutput test. - bool FullPlainOutputExec(std::string* error_msg) { - ScratchFile dexdump_output; - const std::string& dexdump_filename = dexdump_output.GetFilename(); - std::string dexdump = GetArtBinDir() + "/dexdump"; - EXPECT_TRUE(OS::FileExists(dexdump.c_str())) << dexdump << " should be a valid file path"; - - ScratchFile dexlayout_output; - const std::string& dexlayout_filename = dexlayout_output.GetFilename(); - - 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_args = - { "-d", "-f", "-h", "-l", "plain", "-o", dexlayout_filename, dex_file }; - if (!::art::Exec(dexdump_exec_argv, error_msg)) { - return false; - } - if (!DexLayoutExec(dexlayout_args, 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; - } - - // Runs DexFileOutput test. - bool DexFileOutputExec(std::string* error_msg) { - ScratchFile tmp_file; - const 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 unzip_dir = tmp_dir + "unzip/"; - - for (const std::string& dex_file : GetLibCoreDexFileNames()) { - std::vector<std::string> dexlayout_args = - { "-w", tmp_dir, "-o", tmp_name, dex_file }; - if (!DexLayoutExec(dexlayout_args, error_msg, /*pass_default_cdex_option=*/ false)) { - return false; - } - std::string dex_file_name = "classes.dex"; - std::vector<std::string> unzip_exec_argv = - { "/usr/bin/unzip", dex_file, "classes.dex", "-d", unzip_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" , unzip_dir + dex_file_name }; - if (!::art::Exec(diff_exec_argv, error_msg)) { - return false; - } - if (!UnlinkFile(unzip_dir + "classes.dex")) { - return false; - } - if (!UnlinkFile(tmp_dir + dex_file_name)) { - return false; - } - // Remove the unzip temp directory so that unlinking android_data doesn't fail. - EXPECT_EQ(rmdir(unzip_dir.c_str()), 0); - } - return true; - } - - // Create a profile with some subset of methods and classes. - void CreateProfile(const std::string& input_dex, - const std::string& out_profile) { - std::vector<std::unique_ptr<const DexFile>> dex_files; - std::string error_msg; - ArtDexFileLoader dex_file_loader(input_dex); - bool result = dex_file_loader.Open(/*verify=*/true, - /*verify_checksum=*/false, - &error_msg, - &dex_files); - - ASSERT_TRUE(result) << error_msg; - ASSERT_GE(dex_files.size(), 1u); - - size_t profile_methods = 0; - size_t profile_classes = 0; - ProfileCompilationInfo pfi; - for (const std::unique_ptr<const DexFile>& dex_file : dex_files) { - for (uint32_t i = 0; i < dex_file->NumMethodIds(); i += 2) { - uint8_t flags = 0u; - - if ((i & 3) != 0) { - flags |= ProfileCompilationInfo::MethodHotness::kFlagHot; - ++profile_methods; - } else if ((i & 2) != 0) { - flags |= ProfileCompilationInfo::MethodHotness::kFlagStartup; - ++profile_methods; - } - pfi.AddMethod(ProfileMethodInfo(MethodReference(dex_file.get(), /*index=*/ i)), - static_cast<ProfileCompilationInfo::MethodHotness::Flag>(flags)); - } - // Add every even class too. - std::set<dex::TypeIndex> classes; - for (uint32_t i = 0; i < dex_file->NumClassDefs(); i += 1) { - if ((i & 2) == 0) { - classes.insert(dex::TypeIndex(dex_file->GetClassDef(i).class_idx_)); - ++profile_classes; - } - } - if (!classes.empty()) { - pfi.AddClassesForDex(dex_file.get(), classes.begin(), classes.end()); - } - } - // Write to provided file. - std::unique_ptr<File> file(OS::CreateEmptyFile(out_profile.c_str())); - ASSERT_TRUE(file != nullptr); - pfi.Save(file->Fd()); - if (file->FlushCloseOrErase() != 0) { - PLOG(FATAL) << "Could not flush and close test file."; - } - EXPECT_GE(profile_methods, 0u); - EXPECT_GE(profile_classes, 0u); - } - - // Runs DexFileLayout test. - bool DexFileLayoutExec(std::string* error_msg) { - ScratchFile tmp_file; - const 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); - - // Write inputs and expected outputs. - std::string dex_file = tmp_dir + "classes.dex"; - WriteFileBase64(kDexFileLayoutInputDex, dex_file.c_str()); - std::string profile_file = tmp_dir + "primary.prof"; - CreateProfile(dex_file, profile_file); - // WriteFileBase64(kDexFileLayoutInputProfile, profile_file.c_str()); - std::string output_dex = tmp_dir + "classes.dex.new"; - - std::vector<std::string> dexlayout_args = - { "-v", "-w", tmp_dir, "-o", tmp_name, "-p", profile_file, dex_file }; - if (!DexLayoutExec(dexlayout_args, error_msg)) { - return false; - } - - // -v makes sure that the layout did not corrupt the dex file. - if (!UnlinkFile(dex_file) || !UnlinkFile(profile_file) || !UnlinkFile(output_dex)) { - return false; - } - return true; - } - - // Runs DexFileLayout test twice (second time is run on output of first time) - // for behavior consistency. - bool DexFileLayoutFixedPointExec(std::string* error_msg) { - ScratchFile tmp_file; - const 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); - - // Unzip the test dex file to the classes.dex destination. It is required to unzip since - // opening from jar recalculates the dex location checksum. - std::string dex_file = tmp_dir + "classes.dex"; - - std::vector<std::string> unzip_args = { - "/usr/bin/unzip", - GetTestDexFileName("ManyMethods"), - "classes.dex", - "-d", - tmp_dir, - }; - if (!art::Exec(unzip_args, error_msg)) { - LOG(ERROR) << "Failed to unzip dex"; - return false; - } - - std::string profile_file = tmp_dir + "primary.prof"; - CreateProfile(dex_file, profile_file); - std::string output_dex = tmp_dir + "classes.dex.new"; - std::string second_output_dex = tmp_dir + "classes.dex.new.new"; - - // -v makes sure that the layout did not corrupt the dex file. - std::vector<std::string> dexlayout_args = - { "-v", "-w", tmp_dir, "-o", tmp_name, "-p", profile_file, dex_file }; - if (!DexLayoutExec(dexlayout_args, error_msg, /*pass_default_cdex_option=*/ false)) { - return false; - } - - // Recreate the profile with the new dex location. This is required so that the profile dex - // location matches. - CreateProfile(output_dex, profile_file); - // -v makes sure that the layout did not corrupt the dex file. - // -i since the checksum won't match from the first layout. - std::vector<std::string> second_dexlayout_args = - { "-i", "-v", "-w", tmp_dir, "-o", tmp_name, "-p", profile_file, output_dex }; - if (!DexLayoutExec(second_dexlayout_args, error_msg, /*pass_default_cdex_option=*/ false)) { - return false; - } - - bool diff_result = true; - std::vector<std::string> diff_exec_argv = - { "/usr/bin/diff", output_dex, second_output_dex }; - if (!::art::Exec(diff_exec_argv, error_msg)) { - diff_result = false; - } - - std::vector<std::string> test_files = { dex_file, profile_file, output_dex, second_output_dex }; - for (const std::string& test_file : test_files) { - if (!UnlinkFile(test_file)) { - return false; - } - } - - return diff_result; - } - - // Runs UnreferencedCatchHandlerTest & Unreferenced0SizeCatchHandlerTest. - bool UnreferencedCatchHandlerExec(std::string* error_msg, const char* filename) { - ScratchFile tmp_file; - const 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); - - // Write inputs and expected outputs. - std::string input_dex = tmp_dir + "classes.dex"; - WriteFileBase64(filename, input_dex.c_str()); - std::string output_dex = tmp_dir + "classes.dex.new"; - - std::vector<std::string> dexlayout_args = { "-w", tmp_dir, "-o", "/dev/null", input_dex }; - if (!DexLayoutExec(dexlayout_args, error_msg, /*pass_default_cdex_option=*/ false)) { - return false; - } - - // Diff input and output. They should be the same. - std::vector<std::string> diff_exec_argv = { "/usr/bin/diff", input_dex, output_dex }; - if (!::art::Exec(diff_exec_argv, error_msg)) { - return false; - } - - std::vector<std::string> dex_files = { input_dex, output_dex }; - for (const std::string& dex_file : dex_files) { - if (!UnlinkFile(dex_file)) { - return false; - } - } - return true; - } - - bool DexLayoutExec(ScratchFile* dex_file, - const char* dex_filename, - ScratchFile* profile_file, - const std::vector<std::string>& dexlayout_args) { - if (dex_filename != nullptr) { - WriteBase64ToFile(dex_filename, dex_file->GetFile()); - EXPECT_EQ(dex_file->GetFile()->Flush(), 0); - } - if (profile_file != nullptr) { - CreateProfile(dex_file->GetFilename(), profile_file->GetFilename()); - } - - std::string error_msg; - const bool result = DexLayoutExec(dexlayout_args, &error_msg); - if (!result) { - LOG(ERROR) << "Error: " << error_msg; - return false; - } - return true; - } - - bool DexLayoutExec(const std::vector<std::string>& dexlayout_args, - std::string* error_msg, - bool pass_default_cdex_option = true) { - std::vector<std::string> argv; - - std::string dexlayout = GetDexLayoutPath(); - CHECK(OS::FileExists(dexlayout.c_str())) << dexlayout << " should be a valid file path"; - argv.push_back(dexlayout); - if (pass_default_cdex_option) { - std::vector<std::string> cdex_level = DefaultCompactDexOption(); - argv.insert(argv.end(), cdex_level.begin(), cdex_level.end()); - } - - argv.insert(argv.end(), dexlayout_args.begin(), dexlayout_args.end()); - - return ::art::Exec(argv, error_msg); - } - - bool UnlinkFile(const std::string& file_path) { - return unix_file::FdFile(file_path, 0, false).Unlink(); - } -}; - - -TEST_F(DexLayoutTest, FullPlainOutput) { - // TODO(b/256664509): Clean this up. - GTEST_SKIP() << "Compact dex is disabled"; -#if 0 - // Disable test on target. - TEST_DISABLED_FOR_TARGET(); - std::string error_msg; - ASSERT_TRUE(FullPlainOutputExec(&error_msg)) << error_msg; -#endif -} - -TEST_F(DexLayoutTest, DexFileOutput) { - // TODO(b/256664509): Clean this up. - GTEST_SKIP() << "Compact dex is disabled"; -#if 0 - // Disable test on target. - TEST_DISABLED_FOR_TARGET(); - std::string error_msg; - ASSERT_TRUE(DexFileOutputExec(&error_msg)) << error_msg; -#endif -} - -TEST_F(DexLayoutTest, DexFileLayout) { - // Disable test on target. - TEST_DISABLED_FOR_TARGET(); - std::string error_msg; - ASSERT_TRUE(DexFileLayoutExec(&error_msg)) << error_msg; -} - -TEST_F(DexLayoutTest, DexFileLayoutFixedPoint) { - // Disable test on target. - TEST_DISABLED_FOR_TARGET(); - std::string error_msg; - ASSERT_TRUE(DexFileLayoutFixedPointExec(&error_msg)) << error_msg; -} - -TEST_F(DexLayoutTest, UnreferencedCatchHandler) { - // Disable test on target. - TEST_DISABLED_FOR_TARGET(); - std::string error_msg; - ASSERT_TRUE(UnreferencedCatchHandlerExec(&error_msg, - kUnreferencedCatchHandlerInputDex)) << error_msg; -} - -TEST_F(DexLayoutTest, Unreferenced0SizeCatchHandler) { - // Disable test on target. - TEST_DISABLED_FOR_TARGET(); - std::string error_msg; - ASSERT_TRUE(UnreferencedCatchHandlerExec(&error_msg, - kUnreferenced0SizeCatchHandlerInputDex)) << error_msg; -} - -TEST_F(DexLayoutTest, UnreferencedEndingCatchHandler) { - // Disable test on target. - TEST_DISABLED_FOR_TARGET(); - std::string error_msg; - ASSERT_TRUE(UnreferencedCatchHandlerExec(&error_msg, - kUnreferencedEndingCatchHandlerInputDex)) << error_msg; -} - -TEST_F(DexLayoutTest, DuplicateOffset) { - ScratchFile temp_dex; - std::vector<std::string> dexlayout_args = - { "-a", "-i", "-o", "/dev/null", temp_dex.GetFilename() }; - ASSERT_TRUE(DexLayoutExec(&temp_dex, - kDexFileDuplicateOffset, - /* profile_file= */ nullptr, - dexlayout_args)); -} - -TEST_F(DexLayoutTest, NullSetRefListElement) { - ScratchFile temp_dex; - std::vector<std::string> dexlayout_args = { "-o", "/dev/null", temp_dex.GetFilename() }; - ASSERT_TRUE(DexLayoutExec(&temp_dex, - kNullSetRefListElementInputDex, - /* profile_file= */ nullptr, - dexlayout_args)); -} - -TEST_F(DexLayoutTest, MultiClassData) { - ScratchFile temp_dex; - ScratchFile temp_profile; - std::vector<std::string> dexlayout_args = - { "-p", temp_profile.GetFilename(), "-o", "/dev/null", temp_dex.GetFilename() }; - ASSERT_TRUE(DexLayoutExec(&temp_dex, - kMultiClassDataInputDex, - &temp_profile, - dexlayout_args)); -} - -TEST_F(DexLayoutTest, UnalignedCodeInfo) { - ScratchFile temp_dex; - ScratchFile temp_profile; - std::vector<std::string> dexlayout_args = - { "-p", temp_profile.GetFilename(), "-o", "/dev/null", temp_dex.GetFilename() }; - ASSERT_TRUE(DexLayoutExec(&temp_dex, - kUnalignedCodeInfoInputDex, - &temp_profile, - dexlayout_args)); -} - -TEST_F(DexLayoutTest, ClassDataBeforeCode) { - ScratchFile temp_dex; - ScratchFile temp_profile; - std::vector<std::string> dexlayout_args = - { "-p", temp_profile.GetFilename(), "-o", "/dev/null", temp_dex.GetFilename() }; - ASSERT_TRUE(DexLayoutExec(&temp_dex, - kClassDataBeforeCodeInputDex, - &temp_profile, - dexlayout_args)); -} - -TEST_F(DexLayoutTest, UnknownTypeDebugInfo) { - ScratchFile temp_dex; - std::vector<std::string> dexlayout_args = { "-o", "/dev/null", temp_dex.GetFilename() }; - ASSERT_TRUE(DexLayoutExec(&temp_dex, - kUnknownTypeDebugInfoInputDex, - /* profile_file= */ nullptr, - dexlayout_args)); -} - -TEST_F(DexLayoutTest, DuplicateCodeItem) { - ScratchFile temp_dex; - std::vector<std::string> dexlayout_args = { "-o", "/dev/null", temp_dex.GetFilename() }; - ASSERT_TRUE(DexLayoutExec(&temp_dex, - kDuplicateCodeItemInputDex, - /* profile_file= */ nullptr, - dexlayout_args)); -} - -// Test that instructions that go past the end of the code items don't cause crashes. -TEST_F(DexLayoutTest, CodeItemOverrun) { - ScratchFile temp_dex; - MutateDexFile(temp_dex.GetFile(), GetTestDexFileName("ManyMethods"), [] (DexFile* dex) { - bool mutated_successfully = false; - // Change the dex instructions to make an opcode that spans past the end of the code item. - for (ClassAccessor accessor : dex->GetClasses()) { - for (const ClassAccessor::Method& method : accessor.GetMethods()) { - dex::CodeItem* item = const_cast<dex::CodeItem*>(method.GetCodeItem()); - if (item != nullptr) { - CodeItemInstructionAccessor instructions(*dex, item); - if (instructions.begin() != instructions.end()) { - DexInstructionIterator last_instruction = instructions.begin(); - for (auto dex_it = instructions.begin(); dex_it != instructions.end(); ++dex_it) { - last_instruction = dex_it; - } - if (last_instruction->SizeInCodeUnits() == 1) { - // Set the opcode to something that will go past the end of the code item. - const_cast<Instruction&>(last_instruction.Inst()).SetOpcode( - Instruction::CONST_STRING_JUMBO); - mutated_successfully = true; - // Test that the safe iterator doesn't go past the end. - SafeDexInstructionIterator it2(instructions.begin(), instructions.end()); - while (!it2.IsErrorState()) { - ++it2; - } - EXPECT_TRUE(it2 == last_instruction); - EXPECT_TRUE(it2 < instructions.end()); - } - } - } - } - } - CHECK(mutated_successfully) - << "Failed to find candidate code item with only one code unit in last instruction."; - }); - - std::string error_msg; - - ScratchFile tmp_file; - const 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); - ScratchFile profile_file; - - std::vector<std::string> dexlayout_args = - { "-i", - "-v", - "-w", tmp_dir, - "-o", tmp_name, - "-p", profile_file.GetFilename(), - temp_dex.GetFilename() - }; - // -v makes sure that the layout did not corrupt the dex file. - ASSERT_TRUE(DexLayoutExec(&temp_dex, - /*dex_filename=*/ nullptr, - &profile_file, - dexlayout_args)); - ASSERT_TRUE(UnlinkFile(temp_dex.GetFilename() + ".new")); -} - -// Test that link data is written out (or at least the header is updated). -TEST_F(DexLayoutTest, LinkData) { - TEST_DISABLED_FOR_TARGET(); - ScratchFile temp_dex; - size_t file_size = 0; - MutateDexFile(temp_dex.GetFile(), GetTestDexFileName("ManyMethods"), [&] (DexFile* dex) { - DexFile::Header& header = const_cast<DexFile::Header&>(dex->GetHeader()); - header.link_off_ = header.file_size_; - header.link_size_ = 16 * KB; - header.file_size_ += header.link_size_; - header.SetDexContainer(0, header.file_size_); - file_size = header.file_size_; - }); - TEMP_FAILURE_RETRY(temp_dex.GetFile()->SetLength(file_size)); - - std::string error_msg; - - ScratchFile tmp_file; - const 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); - ScratchFile profile_file; - - std::vector<std::string> dexlayout_args = - { "-i", - "-v", - "-w", tmp_dir, - "-o", tmp_name, - "-p", profile_file.GetFilename(), - temp_dex.GetFilename() - }; - // -v makes sure that the layout did not corrupt the dex file. - ASSERT_TRUE(DexLayoutExec(&temp_dex, - /*dex_filename=*/ nullptr, - &profile_file, - dexlayout_args)); - ASSERT_TRUE(UnlinkFile(temp_dex.GetFilename() + ".new")); -} - -TEST_F(DexLayoutTest, ClassFilter) { - std::vector<std::unique_ptr<const DexFile>> dex_files; - std::string error_msg; - const std::string input_jar = GetTestDexFileName("ManyMethods"); - { - ArtDexFileLoader dex_file_loader(input_jar); - CHECK(dex_file_loader.Open(/*verify=*/true, - /*verify_checksum=*/true, - &error_msg, - &dex_files)) - << error_msg; - } - ASSERT_EQ(dex_files.size(), 1u); - for (const std::unique_ptr<const DexFile>& dex_file : dex_files) { - EXPECT_GT(dex_file->NumClassDefs(), 1u); - for (uint32_t i = 0; i < dex_file->NumClassDefs(); ++i) { - const dex::ClassDef& class_def = dex_file->GetClassDef(i); - LOG(INFO) << dex_file->GetClassDescriptor(class_def); - } - Options options; - // Filter out all the classes other than the one below based on class descriptor. - options.class_filter_.insert("LManyMethods$Strings;"); - DexLayout dexlayout(options, - /*info=*/ nullptr, - /*out_file=*/ nullptr, - /*header=*/ nullptr); - std::unique_ptr<DexContainer> out; - bool result = dexlayout.ProcessDexFile( - dex_file->GetLocation().c_str(), - dex_file.get(), - /*dex_file_index=*/ 0, - &out, - &error_msg); - ASSERT_TRUE(result) << "Failed to run dexlayout " << error_msg; - auto container = std::make_unique<DexLoaderContainer>(out->GetMainSection()->Begin(), - out->GetMainSection()->End(), - out->GetDataSection()->Begin(), - out->GetDataSection()->End()); - ArtDexFileLoader dex_file_loader(std::move(container), dex_file->GetLocation()); - std::unique_ptr<const DexFile> output_dex_file(dex_file_loader.Open(/* location_checksum= */ 0, - /*oat_dex_file=*/nullptr, - /* verify= */ true, - /*verify_checksum=*/false, - &error_msg)); - ASSERT_TRUE(output_dex_file != nullptr); - - ASSERT_EQ(output_dex_file->NumClassDefs(), options.class_filter_.size()); - for (uint32_t i = 0; i < output_dex_file->NumClassDefs(); ++i) { - // Check that every class in the output dex file is in the filter. - const dex::ClassDef& class_def = output_dex_file->GetClassDef(i); - ASSERT_TRUE(options.class_filter_.find(output_dex_file->GetClassDescriptor(class_def)) != - options.class_filter_.end()); - } - } -} - -} // namespace art |