summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Martin Stjernholm <mast@google.com> 2024-06-07 18:37:36 +0100
committer Martin Stjernholm <mast@google.com> 2024-06-11 17:04:48 +0000
commite472bb5932be0104f43a027db60e64dd8635cd0a (patch)
tree786790b1ec3971606ae1ab4bb9f03a9bca885ef9
parentd61b2041348830473064d3f934cdf18d49a6170f (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.bp299
-rw-r--r--dexlayout/compact_dex_writer.cc528
-rw-r--r--dexlayout/compact_dex_writer.h179
-rw-r--r--dexlayout/dex_container.h96
-rw-r--r--dexlayout/dex_ir.cc174
-rw-r--r--dexlayout/dex_ir.h1369
-rw-r--r--dexlayout/dex_ir_builder.cc1263
-rw-r--r--dexlayout/dex_ir_builder.h39
-rw-r--r--dexlayout/dex_verify.cc1048
-rw-r--r--dexlayout/dex_verify.h117
-rw-r--r--dexlayout/dex_visualize.cc348
-rw-r--r--dexlayout/dex_visualize.h45
-rw-r--r--dexlayout/dex_writer.cc1007
-rw-r--r--dexlayout/dex_writer.h286
-rw-r--r--dexlayout/dexdiag.cc540
-rw-r--r--dexlayout/dexdiag_test.cc143
-rw-r--r--dexlayout/dexlayout.cc2332
-rw-r--r--dexlayout/dexlayout.h222
-rw-r--r--dexlayout/dexlayout_main.cc235
-rw-r--r--dexlayout/dexlayout_test.cc834
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(&parameters[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, &section_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("&amp;", out_file);
- break;
- case '<':
- fputs("&lt;", out_file);
- break;
- case '>':
- fputs("&gt;", out_file);
- break;
- case '"':
- fputs("&quot;", out_file);
- break;
- case '\t':
- fputs("&#x9;", out_file);
- break;
- case '\n':
- fputs("&#xA;", out_file);
- break;
- case '\r':
- fputs("&#xD;", 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