upload android base code part3

This commit is contained in:
August 2018-08-08 16:48:17 +08:00
parent 71b83c22f1
commit b9e30e05b1
15122 changed files with 2089659 additions and 0 deletions

View file

@ -0,0 +1,89 @@
// 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.
art_cc_defaults {
name: "libart-dexlayout-defaults",
defaults: ["art_defaults"],
host_supported: true,
srcs: [
"dexlayout.cc",
"dex_ir.cc",
"dex_ir_builder.cc",
"dex_verify.cc",
"dex_visualize.cc",
"dex_writer.cc",
],
export_include_dirs: ["."],
shared_libs: ["libbase"],
static_libs: ["libz"],
}
art_cc_library {
name: "libart-dexlayout",
defaults: ["libart-dexlayout-defaults"],
shared_libs: ["libart"],
}
art_cc_library {
name: "libartd-dexlayout",
defaults: ["libart-dexlayout-defaults"],
shared_libs: ["libartd"],
}
art_cc_binary {
name: "dexlayout",
defaults: ["art_defaults"],
host_supported: true,
srcs: ["dexlayout_main.cc"],
cflags: ["-Wall"],
shared_libs: [
"libart",
"libart-dexlayout",
"libbase",
],
}
art_cc_test {
name: "art_dexlayout_tests",
defaults: ["art_gtest_defaults"],
srcs: ["dexlayout_test.cc"],
}
art_cc_binary {
name: "dexdiag",
defaults: ["art_defaults"],
host_supported: true,
srcs: ["dexdiag.cc"],
cflags: ["-Wall"],
shared_libs: [
"libart",
"libart-dexlayout",
],
target: {
android: {
shared_libs: [
"libpagemap",
]
},
}
}
art_cc_test {
name: "art_dexdiag_tests",
host_supported: true,
defaults: [
"art_gtest_defaults",
],
srcs: ["dexdiag_test.cc"],
}

View file

@ -0,0 +1,956 @@
/*
* 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_instruction-inl.h"
#include "dex_ir_builder.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 bool GetPositionsCb(void* context, const DexFile::PositionInfo& entry) {
DebugInfoItem* debug_info = reinterpret_cast<DebugInfoItem*>(context);
PositionInfoVector& positions = debug_info->GetPositionInfo();
positions.push_back(std::unique_ptr<PositionInfo>(new PositionInfo(entry.address_, entry.line_)));
return false;
}
static void GetLocalsCb(void* context, const DexFile::LocalInfo& entry) {
DebugInfoItem* debug_info = reinterpret_cast<DebugInfoItem*>(context);
LocalInfoVector& locals = debug_info->GetLocalInfo();
const char* name = entry.name_ != nullptr ? entry.name_ : "(null)";
const char* descriptor = entry.descriptor_ != nullptr ? entry.descriptor_ : "";
const char* signature = entry.signature_ != nullptr ? entry.signature_ : "";
locals.push_back(std::unique_ptr<LocalInfo>(
new LocalInfo(name, descriptor, signature, entry.start_address_, entry.end_address_,
entry.reg_)));
}
static uint32_t GetDebugInfoStreamSize(const uint8_t* debug_info_stream) {
const uint8_t* stream = debug_info_stream;
DecodeUnsignedLeb128(&stream); // line_start
uint32_t parameters_size = DecodeUnsignedLeb128(&stream);
for (uint32_t i = 0; i < parameters_size; ++i) {
DecodeUnsignedLeb128P1(&stream); // Parameter name.
}
for (;;) {
uint8_t opcode = *stream++;
switch (opcode) {
case DexFile::DBG_END_SEQUENCE:
return stream - debug_info_stream; // end of stream.
case DexFile::DBG_ADVANCE_PC:
DecodeUnsignedLeb128(&stream); // addr_diff
break;
case DexFile::DBG_ADVANCE_LINE:
DecodeSignedLeb128(&stream); // line_diff
break;
case DexFile::DBG_START_LOCAL:
DecodeUnsignedLeb128(&stream); // register_num
DecodeUnsignedLeb128P1(&stream); // name_idx
DecodeUnsignedLeb128P1(&stream); // type_idx
break;
case DexFile::DBG_START_LOCAL_EXTENDED:
DecodeUnsignedLeb128(&stream); // register_num
DecodeUnsignedLeb128P1(&stream); // name_idx
DecodeUnsignedLeb128P1(&stream); // type_idx
DecodeUnsignedLeb128P1(&stream); // sig_idx
break;
case DexFile::DBG_END_LOCAL:
case DexFile::DBG_RESTART_LOCAL:
DecodeUnsignedLeb128(&stream); // register_num
break;
case DexFile::DBG_SET_PROLOGUE_END:
case DexFile::DBG_SET_EPILOGUE_BEGIN:
break;
case DexFile::DBG_SET_FILE: {
DecodeUnsignedLeb128P1(&stream); // name_idx
break;
}
default: {
break;
}
}
}
}
static bool GetIdFromInstruction(Collections& collections,
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 < collections.TypeIdsSize()) {
type_ids->push_back(collections.GetTypeId(index));
return true;
}
break;
case Instruction::kIndexStringRef:
if (index < collections.StringIdsSize()) {
string_ids->push_back(collections.GetStringId(index));
return true;
}
break;
case Instruction::kIndexMethodRef:
case Instruction::kIndexMethodAndProtoRef:
if (index < collections.MethodIdsSize()) {
method_ids->push_back(collections.GetMethodId(index));
return true;
}
break;
case Instruction::kIndexFieldRef:
if (index < collections.FieldIdsSize()) {
field_ids->push_back(collections.GetFieldId(index));
return true;
}
break;
case Instruction::kIndexUnknown:
case Instruction::kIndexNone:
case Instruction::kIndexVtableOffset:
case Instruction::kIndexFieldOffset:
default:
break;
} // switch
return false;
}
/*
* Get all the types, strings, methods, and fields referred to from bytecode.
*/
static bool GetIdsFromByteCode(Collections& collections,
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;
// Iterate over all instructions.
const uint16_t* insns = code->Insns();
for (uint32_t insn_idx = 0; insn_idx < code->InsnsSize();) {
const Instruction* instruction = Instruction::At(&insns[insn_idx]);
const uint32_t insn_width = instruction->SizeInCodeUnits();
if (insn_width == 0) {
break;
}
has_id |= GetIdFromInstruction(collections,
instruction,
type_ids,
string_ids,
method_ids,
field_ids);
insn_idx += insn_width;
} // for
return has_id;
}
EncodedValue* Collections::ReadEncodedValue(const uint8_t** data) {
const uint8_t encoded_value = *(*data)++;
const uint8_t type = encoded_value & 0x1f;
EncodedValue* item = new EncodedValue(type);
ReadEncodedValue(data, type, encoded_value >> 5, item);
return item;
}
EncodedValue* Collections::ReadEncodedValue(const uint8_t** data, uint8_t type, uint8_t length) {
EncodedValue* item = new EncodedValue(type);
ReadEncodedValue(data, type, length, item);
return item;
}
void Collections::ReadEncodedValue(
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(GetProtoId(proto_index));
break;
}
case DexFile::kDexAnnotationMethodHandle: {
const uint32_t method_handle_index = static_cast<uint32_t>(ReadVarWidth(data, length, false));
item->SetMethodHandle(GetMethodHandle(method_handle_index));
break;
}
case DexFile::kDexAnnotationString: {
const uint32_t string_index = static_cast<uint32_t>(ReadVarWidth(data, length, false));
item->SetStringId(GetStringId(string_index));
break;
}
case DexFile::kDexAnnotationType: {
const uint32_t string_index = static_cast<uint32_t>(ReadVarWidth(data, length, false));
item->SetTypeId(GetTypeId(string_index));
break;
}
case DexFile::kDexAnnotationField:
case DexFile::kDexAnnotationEnum: {
const uint32_t field_index = static_cast<uint32_t>(ReadVarWidth(data, length, false));
item->SetFieldId(GetFieldId(field_index));
break;
}
case DexFile::kDexAnnotationMethod: {
const uint32_t method_index = static_cast<uint32_t>(ReadVarWidth(data, length, false));
item->SetMethodId(GetMethodId(method_index));
break;
}
case DexFile::kDexAnnotationArray: {
EncodedValueVector* values = new EncodedValueVector();
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(data)));
}
item->SetEncodedArray(new EncodedArrayItem(values));
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::unique_ptr<AnnotationElement>(
new AnnotationElement(GetStringId(name_index), ReadEncodedValue(data))));
}
item->SetEncodedAnnotation(new EncodedAnnotation(GetTypeId(type_idx), elements));
break;
}
case DexFile::kDexAnnotationNull:
break;
case DexFile::kDexAnnotationBoolean:
item->SetBoolean(length != 0);
break;
default:
break;
}
}
void Collections::CreateStringId(const DexFile& dex_file, uint32_t i) {
const DexFile::StringId& disk_string_id = dex_file.GetStringId(dex::StringIndex(i));
StringData* string_data = new StringData(dex_file.GetStringData(disk_string_id));
string_datas_.AddItem(string_data, disk_string_id.string_data_off_);
StringId* string_id = new StringId(string_data);
string_ids_.AddIndexedItem(string_id, StringIdsOffset() + i * StringId::ItemSize(), i);
}
void Collections::CreateTypeId(const DexFile& dex_file, uint32_t i) {
const DexFile::TypeId& disk_type_id = dex_file.GetTypeId(dex::TypeIndex(i));
TypeId* type_id = new TypeId(GetStringId(disk_type_id.descriptor_idx_.index_));
type_ids_.AddIndexedItem(type_id, TypeIdsOffset() + i * TypeId::ItemSize(), i);
}
void Collections::CreateProtoId(const DexFile& dex_file, uint32_t i) {
const DexFile::ProtoId& disk_proto_id = dex_file.GetProtoId(i);
const DexFile::TypeList* type_list = dex_file.GetProtoParameters(disk_proto_id);
TypeList* parameter_type_list = CreateTypeList(type_list, disk_proto_id.parameters_off_);
ProtoId* proto_id = new ProtoId(GetStringId(disk_proto_id.shorty_idx_.index_),
GetTypeId(disk_proto_id.return_type_idx_.index_),
parameter_type_list);
proto_ids_.AddIndexedItem(proto_id, ProtoIdsOffset() + i * ProtoId::ItemSize(), i);
}
void Collections::CreateFieldId(const DexFile& dex_file, uint32_t i) {
const DexFile::FieldId& disk_field_id = dex_file.GetFieldId(i);
FieldId* field_id = new FieldId(GetTypeId(disk_field_id.class_idx_.index_),
GetTypeId(disk_field_id.type_idx_.index_),
GetStringId(disk_field_id.name_idx_.index_));
field_ids_.AddIndexedItem(field_id, FieldIdsOffset() + i * FieldId::ItemSize(), i);
}
void Collections::CreateMethodId(const DexFile& dex_file, uint32_t i) {
const DexFile::MethodId& disk_method_id = dex_file.GetMethodId(i);
MethodId* method_id = new MethodId(GetTypeId(disk_method_id.class_idx_.index_),
GetProtoId(disk_method_id.proto_idx_),
GetStringId(disk_method_id.name_idx_.index_));
method_ids_.AddIndexedItem(method_id, MethodIdsOffset() + i * MethodId::ItemSize(), i);
}
void Collections::CreateClassDef(const DexFile& dex_file, uint32_t i) {
const DexFile::ClassDef& disk_class_def = dex_file.GetClassDef(i);
const TypeId* class_type = GetTypeId(disk_class_def.class_idx_.index_);
uint32_t access_flags = disk_class_def.access_flags_;
const TypeId* superclass = GetTypeIdOrNullPtr(disk_class_def.superclass_idx_.index_);
const DexFile::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 = GetStringIdOrNullPtr(disk_class_def.source_file_idx_.index_);
// Annotations.
AnnotationsDirectoryItem* annotations = nullptr;
const DexFile::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(static_data, disk_class_def.static_values_off_);
ClassData* class_data = CreateClassData(
dex_file, dex_file.GetClassData(disk_class_def), disk_class_def.class_data_off_);
ClassDef* class_def = new ClassDef(class_type, access_flags, superclass, interfaces_type_list,
source_file, annotations, static_values, class_data);
class_defs_.AddIndexedItem(class_def, ClassDefsOffset() + i * ClassDef::ItemSize(), i);
}
TypeList* Collections::CreateTypeList(const DexFile::TypeList* dex_type_list, uint32_t offset) {
if (dex_type_list == nullptr) {
return nullptr;
}
auto found_type_list = TypeLists().find(offset);
if (found_type_list != TypeLists().end()) {
return found_type_list->second.get();
}
TypeIdVector* type_vector = new TypeIdVector();
uint32_t size = dex_type_list->Size();
for (uint32_t index = 0; index < size; ++index) {
type_vector->push_back(GetTypeId(dex_type_list->GetTypeItem(index).type_idx_.index_));
}
TypeList* new_type_list = new TypeList(type_vector);
type_lists_.AddItem(new_type_list, offset);
return new_type_list;
}
EncodedArrayItem* Collections::CreateEncodedArrayItem(const uint8_t* static_data, uint32_t offset) {
if (static_data == nullptr) {
return nullptr;
}
auto found_encoded_array_item = EncodedArrayItems().find(offset);
if (found_encoded_array_item != EncodedArrayItems().end()) {
return found_encoded_array_item->second.get();
}
uint32_t size = DecodeUnsignedLeb128(&static_data);
EncodedValueVector* values = new EncodedValueVector();
for (uint32_t i = 0; i < size; ++i) {
values->push_back(std::unique_ptr<EncodedValue>(ReadEncodedValue(&static_data)));
}
// TODO: Calculate the size of the encoded array.
EncodedArrayItem* encoded_array_item = new EncodedArrayItem(values);
encoded_array_items_.AddItem(encoded_array_item, offset);
return encoded_array_item;
}
AnnotationItem* Collections::CreateAnnotationItem(const DexFile::AnnotationItem* annotation,
uint32_t offset) {
auto found_annotation_item = AnnotationItems().find(offset);
if (found_annotation_item != AnnotationItems().end()) {
return found_annotation_item->second.get();
}
uint8_t visibility = annotation->visibility_;
const uint8_t* annotation_data = annotation->annotation_;
std::unique_ptr<EncodedValue> encoded_value(
ReadEncodedValue(&annotation_data, DexFile::kDexAnnotationAnnotation, 0));
// TODO: Calculate the size of the annotation.
AnnotationItem* annotation_item =
new AnnotationItem(visibility, encoded_value->ReleaseEncodedAnnotation());
annotation_items_.AddItem(annotation_item, offset);
return annotation_item;
}
AnnotationSetItem* Collections::CreateAnnotationSetItem(const DexFile& dex_file,
const DexFile::AnnotationSetItem* disk_annotations_item, uint32_t offset) {
if (disk_annotations_item == nullptr || (disk_annotations_item->size_ == 0 && offset == 0)) {
return nullptr;
}
auto found_anno_set_item = AnnotationSetItems().find(offset);
if (found_anno_set_item != AnnotationSetItems().end()) {
return found_anno_set_item->second.get();
}
std::vector<AnnotationItem*>* items = new std::vector<AnnotationItem*>();
for (uint32_t i = 0; i < disk_annotations_item->size_; ++i) {
const DexFile::AnnotationItem* annotation =
dex_file.GetAnnotationItem(disk_annotations_item, i);
if (annotation == nullptr) {
continue;
}
AnnotationItem* annotation_item =
CreateAnnotationItem(annotation, disk_annotations_item->entries_[i]);
items->push_back(annotation_item);
}
AnnotationSetItem* annotation_set_item = new AnnotationSetItem(items);
annotation_set_items_.AddItem(annotation_set_item, offset);
return annotation_set_item;
}
AnnotationsDirectoryItem* Collections::CreateAnnotationsDirectoryItem(const DexFile& dex_file,
const DexFile::AnnotationsDirectoryItem* disk_annotations_item, uint32_t offset) {
auto found_anno_dir_item = AnnotationsDirectoryItems().find(offset);
if (found_anno_dir_item != AnnotationsDirectoryItems().end()) {
return found_anno_dir_item->second.get();
}
const DexFile::AnnotationSetItem* class_set_item =
dex_file.GetClassAnnotationSet(disk_annotations_item);
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 DexFile::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 = GetFieldId(fields[i].field_idx_);
const DexFile::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::unique_ptr<FieldAnnotation>(
new FieldAnnotation(field_id, annotation_set_item)));
}
}
const DexFile::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 = GetMethodId(methods[i].method_idx_);
const DexFile::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::unique_ptr<MethodAnnotation>(
new MethodAnnotation(method_id, annotation_set_item)));
}
}
const DexFile::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 = GetMethodId(parameters[i].method_idx_);
const DexFile::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.
AnnotationsDirectoryItem* annotations_directory_item = new AnnotationsDirectoryItem(
class_annotation, field_annotations, method_annotations, parameter_annotations);
annotations_directory_items_.AddItem(annotations_directory_item, offset);
return annotations_directory_item;
}
ParameterAnnotation* Collections::GenerateParameterAnnotation(
const DexFile& dex_file, MethodId* method_id,
const DexFile::AnnotationSetRefList* annotation_set_ref_list, uint32_t offset) {
AnnotationSetRefList* set_ref_list = nullptr;
auto found_set_ref_list = AnnotationSetRefLists().find(offset);
if (found_set_ref_list != AnnotationSetRefLists().end()) {
set_ref_list = found_set_ref_list->second.get();
}
if (set_ref_list == nullptr) {
std::vector<AnnotationSetItem*>* annotations = new std::vector<AnnotationSetItem*>();
for (uint32_t i = 0; i < annotation_set_ref_list->size_; ++i) {
const DexFile::AnnotationSetItem* annotation_set_item =
dex_file.GetSetRefItemItem(&annotation_set_ref_list->list_[i]);
uint32_t set_offset = annotation_set_ref_list->list_[i].annotations_off_;
annotations->push_back(CreateAnnotationSetItem(dex_file, annotation_set_item, set_offset));
}
set_ref_list = new AnnotationSetRefList(annotations);
annotation_set_ref_lists_.AddItem(set_ref_list, offset);
}
return new ParameterAnnotation(method_id, set_ref_list);
}
CodeItem* Collections::CreateCodeItem(const DexFile& dex_file,
const DexFile::CodeItem& disk_code_item, uint32_t offset) {
uint16_t registers_size = disk_code_item.registers_size_;
uint16_t ins_size = disk_code_item.ins_size_;
uint16_t outs_size = disk_code_item.outs_size_;
uint32_t tries_size = disk_code_item.tries_size_;
// TODO: Calculate the size of the debug info.
const uint8_t* debug_info_stream = dex_file.GetDebugInfoStream(&disk_code_item);
DebugInfoItem* debug_info = nullptr;
if (debug_info_stream != nullptr) {
debug_info = debug_info_items_.GetExistingObject(disk_code_item.debug_info_off_);
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 = new DebugInfoItem(debug_info_size, debug_info_buffer);
debug_info_items_.AddItem(debug_info, disk_code_item.debug_info_off_);
}
}
uint32_t insns_size = disk_code_item.insns_size_in_code_units_;
uint16_t* insns = new uint16_t[insns_size];
memcpy(insns, disk_code_item.insns_, insns_size * sizeof(uint16_t));
TryItemVector* tries = nullptr;
CatchHandlerVector* handler_list = nullptr;
if (tries_size > 0) {
tries = new TryItemVector();
handler_list = new CatchHandlerVector();
for (uint32_t i = 0; i < tries_size; ++i) {
const DexFile::TryItem* disk_try_item = dex_file.GetTryItems(disk_code_item, i);
uint32_t start_addr = disk_try_item->start_addr_;
uint16_t insn_count = disk_try_item->insn_count_;
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(disk_code_item, *disk_try_item); it.HasNext(); it.Next()) {
const dex::TypeIndex type_index = it.GetHandlerTypeIndex();
const TypeId* type_id = 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 = DexFile::GetCatchHandlerData(disk_code_item, 0);
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 = 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 = DexFile::GetCodeItemSize(disk_code_item);
CodeItem* code_item = new CodeItem(
registers_size, ins_size, outs_size, debug_info, insns_size, insns, tries, handler_list);
code_item->SetSize(size);
code_items_.AddItem(code_item, offset);
// Add "fixup" references to types, strings, methods, and fields.
// This is temporary, as we will probably want more detailed parsing of the
// instructions here.
std::unique_ptr<std::vector<TypeId*>> type_ids(new std::vector<TypeId*>());
std::unique_ptr<std::vector<StringId*>> string_ids(new std::vector<StringId*>());
std::unique_ptr<std::vector<MethodId*>> method_ids(new std::vector<MethodId*>());
std::unique_ptr<std::vector<FieldId*>> field_ids(new std::vector<FieldId*>());
if (GetIdsFromByteCode(*this,
code_item,
type_ids.get(),
string_ids.get(),
method_ids.get(),
field_ids.get())) {
CodeFixups* fixups = new CodeFixups(type_ids.release(),
string_ids.release(),
method_ids.release(),
field_ids.release());
code_item->SetCodeFixups(fixups);
}
return code_item;
}
MethodItem* Collections::GenerateMethodItem(const DexFile& dex_file, ClassDataItemIterator& cdii) {
MethodId* method_id = GetMethodId(cdii.GetMemberIndex());
uint32_t access_flags = cdii.GetRawMemberAccessFlags();
const DexFile::CodeItem* disk_code_item = cdii.GetMethodCodeItem();
CodeItem* code_item = code_items_.GetExistingObject(cdii.GetMethodCodeItemOffset());
DebugInfoItem* debug_info = nullptr;
if (disk_code_item != nullptr) {
if (code_item == nullptr) {
code_item = CreateCodeItem(dex_file, *disk_code_item, cdii.GetMethodCodeItemOffset());
}
debug_info = code_item->DebugInfo();
}
if (debug_info != nullptr) {
bool is_static = (access_flags & kAccStatic) != 0;
dex_file.DecodeDebugLocalInfo(
disk_code_item, is_static, cdii.GetMemberIndex(), GetLocalsCb, debug_info);
dex_file.DecodeDebugPositionInfo(disk_code_item, GetPositionsCb, debug_info);
}
return new MethodItem(access_flags, method_id, code_item);
}
ClassData* Collections::CreateClassData(
const DexFile& dex_file, const uint8_t* encoded_data, uint32_t offset) {
// Read the fields and methods defined by the class, resolving the circular reference from those
// to classes by setting class at the same time.
ClassData* class_data = class_datas_.GetExistingObject(offset);
if (class_data == nullptr && encoded_data != nullptr) {
ClassDataItemIterator cdii(dex_file, encoded_data);
// Static fields.
FieldItemVector* static_fields = new FieldItemVector();
for (; cdii.HasNextStaticField(); cdii.Next()) {
FieldId* field_item = GetFieldId(cdii.GetMemberIndex());
uint32_t access_flags = cdii.GetRawMemberAccessFlags();
static_fields->push_back(std::unique_ptr<FieldItem>(new FieldItem(access_flags, field_item)));
}
// Instance fields.
FieldItemVector* instance_fields = new FieldItemVector();
for (; cdii.HasNextInstanceField(); cdii.Next()) {
FieldId* field_item = GetFieldId(cdii.GetMemberIndex());
uint32_t access_flags = cdii.GetRawMemberAccessFlags();
instance_fields->push_back(
std::unique_ptr<FieldItem>(new FieldItem(access_flags, field_item)));
}
// Direct methods.
MethodItemVector* direct_methods = new MethodItemVector();
for (; cdii.HasNextDirectMethod(); cdii.Next()) {
direct_methods->push_back(std::unique_ptr<MethodItem>(GenerateMethodItem(dex_file, cdii)));
}
// Virtual methods.
MethodItemVector* virtual_methods = new MethodItemVector();
for (; cdii.HasNextVirtualMethod(); cdii.Next()) {
virtual_methods->push_back(std::unique_ptr<MethodItem>(GenerateMethodItem(dex_file, cdii)));
}
class_data = new ClassData(static_fields, instance_fields, direct_methods, virtual_methods);
class_data->SetSize(cdii.EndDataPointer() - encoded_data);
class_datas_.AddItem(class_data, offset);
}
return class_data;
}
void Collections::CreateCallSitesAndMethodHandles(const DexFile& dex_file) {
// Iterate through the map list and set the offset of the CallSiteIds and MethodHandleItems.
const DexFile::MapList* map =
reinterpret_cast<const DexFile::MapList*>(dex_file.Begin() + MapListOffset());
for (uint32_t i = 0; i < map->size_; ++i) {
const DexFile::MapItem* item = map->list_ + i;
switch (item->type_) {
case DexFile::kDexTypeCallSiteIdItem:
SetCallSiteIdsOffset(item->offset_);
break;
case DexFile::kDexTypeMethodHandleItem:
SetMethodHandleItemsOffset(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);
}
}
void Collections::CreateCallSiteId(const DexFile& dex_file, uint32_t i) {
const DexFile::CallSiteIdItem& disk_call_site_id = dex_file.GetCallSiteId(i);
const uint8_t* disk_call_item_ptr = dex_file.Begin() + disk_call_site_id.data_off_;
EncodedArrayItem* call_site_item =
CreateEncodedArrayItem(disk_call_item_ptr, disk_call_site_id.data_off_);
CallSiteId* call_site_id = new CallSiteId(call_site_item);
call_site_ids_.AddIndexedItem(call_site_id, CallSiteIdsOffset() + i * CallSiteId::ItemSize(), i);
}
void Collections::CreateMethodHandleItem(const DexFile& dex_file, uint32_t i) {
const DexFile::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 = GetMethodId(index);
} else {
field_or_method_id = GetFieldId(index);
}
MethodHandleItem* method_handle = new MethodHandleItem(type, field_or_method_id);
method_handle_items_.AddIndexedItem(
method_handle, MethodHandleItemsOffset() + i * MethodHandleItem::ItemSize(), i);
}
static uint32_t HeaderOffset(const dex_ir::Collections& collections ATTRIBUTE_UNUSED) {
return 0;
}
static uint32_t HeaderSize(const dex_ir::Collections& collections ATTRIBUTE_UNUSED) {
// 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(const dex_ir::Collections&)> size_fn;
// A function that when applied to a collection object, gives the offset of the section.
std::function<uint32_t(const dex_ir::Collections&)> offset_fn;
};
static const FileSectionDescriptor kFileSectionDescriptors[] = {
{
"Header",
DexFile::kDexTypeHeaderItem,
&HeaderSize,
&HeaderOffset,
}, {
"StringId",
DexFile::kDexTypeStringIdItem,
&dex_ir::Collections::StringIdsSize,
&dex_ir::Collections::StringIdsOffset
}, {
"TypeId",
DexFile::kDexTypeTypeIdItem,
&dex_ir::Collections::TypeIdsSize,
&dex_ir::Collections::TypeIdsOffset
}, {
"ProtoId",
DexFile::kDexTypeProtoIdItem,
&dex_ir::Collections::ProtoIdsSize,
&dex_ir::Collections::ProtoIdsOffset
}, {
"FieldId",
DexFile::kDexTypeFieldIdItem,
&dex_ir::Collections::FieldIdsSize,
&dex_ir::Collections::FieldIdsOffset
}, {
"MethodId",
DexFile::kDexTypeMethodIdItem,
&dex_ir::Collections::MethodIdsSize,
&dex_ir::Collections::MethodIdsOffset
}, {
"ClassDef",
DexFile::kDexTypeClassDefItem,
&dex_ir::Collections::ClassDefsSize,
&dex_ir::Collections::ClassDefsOffset
}, {
"CallSiteId",
DexFile::kDexTypeCallSiteIdItem,
&dex_ir::Collections::CallSiteIdsSize,
&dex_ir::Collections::CallSiteIdsOffset
}, {
"MethodHandle",
DexFile::kDexTypeMethodHandleItem,
&dex_ir::Collections::MethodHandleItemsSize,
&dex_ir::Collections::MethodHandleItemsOffset
}, {
"StringData",
DexFile::kDexTypeStringDataItem,
&dex_ir::Collections::StringDatasSize,
&dex_ir::Collections::StringDatasOffset
}, {
"TypeList",
DexFile::kDexTypeTypeList,
&dex_ir::Collections::TypeListsSize,
&dex_ir::Collections::TypeListsOffset
}, {
"EncArr",
DexFile::kDexTypeEncodedArrayItem,
&dex_ir::Collections::EncodedArrayItemsSize,
&dex_ir::Collections::EncodedArrayItemsOffset
}, {
"Annotation",
DexFile::kDexTypeAnnotationItem,
&dex_ir::Collections::AnnotationItemsSize,
&dex_ir::Collections::AnnotationItemsOffset
}, {
"AnnoSet",
DexFile::kDexTypeAnnotationSetItem,
&dex_ir::Collections::AnnotationSetItemsSize,
&dex_ir::Collections::AnnotationSetItemsOffset
}, {
"AnnoSetRL",
DexFile::kDexTypeAnnotationSetRefList,
&dex_ir::Collections::AnnotationSetRefListsSize,
&dex_ir::Collections::AnnotationSetRefListsOffset
}, {
"AnnoDir",
DexFile::kDexTypeAnnotationsDirectoryItem,
&dex_ir::Collections::AnnotationsDirectoryItemsSize,
&dex_ir::Collections::AnnotationsDirectoryItemsOffset
}, {
"DebugInfo",
DexFile::kDexTypeDebugInfoItem,
&dex_ir::Collections::DebugInfoItemsSize,
&dex_ir::Collections::DebugInfoItemsOffset
}, {
"CodeItem",
DexFile::kDexTypeCodeItem,
&dex_ir::Collections::CodeItemsSize,
&dex_ir::Collections::CodeItemsOffset
}, {
"ClassData",
DexFile::kDexTypeClassDataItem,
&dex_ir::Collections::ClassDatasSize,
&dex_ir::Collections::ClassDatasOffset
}
};
std::vector<dex_ir::DexFileSection> GetSortedDexFileSections(dex_ir::Header* header,
dex_ir::SortDirection direction) {
const dex_ir::Collections& collections = header->GetCollections();
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(collections),
s.offset_fn(collections)));
}
// 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

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,169 @@
/*
* 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 <vector>
#include "dex_ir_builder.h"
namespace art {
namespace dex_ir {
static void CheckAndSetRemainingOffsets(const DexFile& dex_file, Collections* collections);
Header* DexIrBuilder(const DexFile& dex_file) {
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_);
Collections& collections = header->GetCollections();
// Walk the rest of the header fields.
// StringId table.
collections.SetStringIdsOffset(disk_header.string_ids_off_);
for (uint32_t i = 0; i < dex_file.NumStringIds(); ++i) {
collections.CreateStringId(dex_file, i);
}
// TypeId table.
collections.SetTypeIdsOffset(disk_header.type_ids_off_);
for (uint32_t i = 0; i < dex_file.NumTypeIds(); ++i) {
collections.CreateTypeId(dex_file, i);
}
// ProtoId table.
collections.SetProtoIdsOffset(disk_header.proto_ids_off_);
for (uint32_t i = 0; i < dex_file.NumProtoIds(); ++i) {
collections.CreateProtoId(dex_file, i);
}
// FieldId table.
collections.SetFieldIdsOffset(disk_header.field_ids_off_);
for (uint32_t i = 0; i < dex_file.NumFieldIds(); ++i) {
collections.CreateFieldId(dex_file, i);
}
// MethodId table.
collections.SetMethodIdsOffset(disk_header.method_ids_off_);
for (uint32_t i = 0; i < dex_file.NumMethodIds(); ++i) {
collections.CreateMethodId(dex_file, i);
}
// ClassDef table.
collections.SetClassDefsOffset(disk_header.class_defs_off_);
for (uint32_t i = 0; i < dex_file.NumClassDefs(); ++i) {
collections.CreateClassDef(dex_file, i);
}
// MapItem.
collections.SetMapListOffset(disk_header.map_off_);
// CallSiteIds and MethodHandleItems.
collections.CreateCallSitesAndMethodHandles(dex_file);
CheckAndSetRemainingOffsets(dex_file, &collections);
return header;
}
static void CheckAndSetRemainingOffsets(const DexFile& dex_file, Collections* collections) {
const DexFile::Header& disk_header = dex_file.GetHeader();
// Read MapItems and validate/set remaining offsets.
const DexFile::MapList* map =
reinterpret_cast<const DexFile::MapList*>(dex_file.Begin() + disk_header.map_off_);
const uint32_t count = map->size_;
for (uint32_t i = 0; i < count; ++i) {
const DexFile::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_, collections->StringIdsSize());
CHECK_EQ(item->offset_, collections->StringIdsOffset());
break;
case DexFile::kDexTypeTypeIdItem:
CHECK_EQ(item->size_, collections->TypeIdsSize());
CHECK_EQ(item->offset_, collections->TypeIdsOffset());
break;
case DexFile::kDexTypeProtoIdItem:
CHECK_EQ(item->size_, collections->ProtoIdsSize());
CHECK_EQ(item->offset_, collections->ProtoIdsOffset());
break;
case DexFile::kDexTypeFieldIdItem:
CHECK_EQ(item->size_, collections->FieldIdsSize());
CHECK_EQ(item->offset_, collections->FieldIdsOffset());
break;
case DexFile::kDexTypeMethodIdItem:
CHECK_EQ(item->size_, collections->MethodIdsSize());
CHECK_EQ(item->offset_, collections->MethodIdsOffset());
break;
case DexFile::kDexTypeClassDefItem:
CHECK_EQ(item->size_, collections->ClassDefsSize());
CHECK_EQ(item->offset_, collections->ClassDefsOffset());
break;
case DexFile::kDexTypeCallSiteIdItem:
CHECK_EQ(item->size_, collections->CallSiteIdsSize());
CHECK_EQ(item->offset_, collections->CallSiteIdsOffset());
break;
case DexFile::kDexTypeMethodHandleItem:
CHECK_EQ(item->size_, collections->MethodHandleItemsSize());
CHECK_EQ(item->offset_, collections->MethodHandleItemsOffset());
break;
case DexFile::kDexTypeMapList:
CHECK_EQ(item->size_, 1u);
CHECK_EQ(item->offset_, disk_header.map_off_);
break;
case DexFile::kDexTypeTypeList:
collections->SetTypeListsOffset(item->offset_);
break;
case DexFile::kDexTypeAnnotationSetRefList:
collections->SetAnnotationSetRefListsOffset(item->offset_);
break;
case DexFile::kDexTypeAnnotationSetItem:
collections->SetAnnotationSetItemsOffset(item->offset_);
break;
case DexFile::kDexTypeClassDataItem:
collections->SetClassDatasOffset(item->offset_);
break;
case DexFile::kDexTypeCodeItem:
collections->SetCodeItemsOffset(item->offset_);
break;
case DexFile::kDexTypeStringDataItem:
collections->SetStringDatasOffset(item->offset_);
break;
case DexFile::kDexTypeDebugInfoItem:
collections->SetDebugInfoItemsOffset(item->offset_);
break;
case DexFile::kDexTypeAnnotationItem:
collections->SetAnnotationItemsOffset(item->offset_);
break;
case DexFile::kDexTypeEncodedArrayItem:
collections->SetEncodedArrayItemsOffset(item->offset_);
break;
case DexFile::kDexTypeAnnotationsDirectoryItem:
collections->SetAnnotationsDirectoryItemsOffset(item->offset_);
break;
default:
LOG(ERROR) << "Unknown map list item type.";
}
}
}
} // namespace dex_ir
} // namespace art

View file

@ -0,0 +1,32 @@
/*
* 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 {
namespace dex_ir {
dex_ir::Header* DexIrBuilder(const DexFile& dex_file);
} // namespace dex_ir
} // namespace art
#endif // ART_DEXLAYOUT_DEX_IR_BUILDER_H_

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,125 @@
/*
* 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(std::vector<std::unique_ptr<T>>& orig,
std::vector<std::unique_ptr<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(std::vector<std::unique_ptr<dex_ir::ClassDef>>& orig,
std::vector<std::unique_ptr<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 VerifyPositionInfo(dex_ir::PositionInfoVector& orig,
dex_ir::PositionInfoVector& output,
uint32_t orig_offset,
std::string* error_msg);
bool VerifyLocalInfo(dex_ir::LocalInfoVector& orig,
dex_ir::LocalInfoVector& output,
uint32_t orig_offset,
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_

View file

@ -0,0 +1,347 @@
/*
* 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 "dex_ir.h"
#include "dexlayout.h"
#include "jit/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)) { }
bool OpenAndPrintHeader(size_t dex_index) {
// Open the file and emit the gnuplot prologue.
out_file_ = fopen(MultidexName("layout", dex_index, ".gnuplot").c_str(), "w");
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\" %d", s.name.c_str(), s.offset / kPageSize);
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 / kPageSize;
const uint32_t high_page = (size > 0) ? (from + size - 1) / kPageSize : 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) {
std::vector<dex_ir::TypeId*>* type_ids = fixups->TypeIds();
for (dex_ir::TypeId* type_id : *type_ids) {
DumpTypeId(type_id, class_index);
}
std::vector<dex_ir::StringId*>* string_ids = fixups->StringIds();
for (dex_ir::StringId* string_id : *string_ids) {
DumpStringId(string_id, class_index);
}
std::vector<dex_ir::MethodId*>* method_ids = fixups->MethodIds();
for (dex_ir::MethodId* method_id : *method_ids) {
DumpMethodId(method_id, class_index);
}
std::vector<dex_ir::FieldId*>* field_ids = fixups->FieldIds();
for (dex_ir::FieldId* field_id : *field_ids) {
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_;
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)) {
fprintf(stderr, "Could not open output file.\n");
return;
}
const uint32_t class_defs_size = header->GetCollections().ClassDefsSize();
for (uint32_t class_index = 0; class_index < class_defs_size; class_index++) {
dex_ir::ClassDef* class_def = header->GetCollections().GetClassDef(class_index);
dex::TypeIndex type_idx(class_def->ClassType()->GetIndex());
if (profile_info != nullptr && !profile_info->ContainsClass(*dex_file, type_idx)) {
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.get(), class_index);
}
}
if (class_data->InstanceFields()) {
for (auto& field_item : *class_data->InstanceFields()) {
dumper->DumpFieldItem(field_item.get(), class_index);
}
}
if (class_data->DirectMethods()) {
for (auto& method_item : *class_data->DirectMethods()) {
dumper->DumpMethodItem(method_item.get(), dex_file, class_index, profile_info);
}
}
if (class_data->VirtualMethods()) {
for (auto& method_item : *class_data->VirtualMethods()) {
dumper->DumpMethodItem(method_item.get(), dex_file, class_index, 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.at(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) {
// 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 %8d %%%02d\n",
file_section.name.c_str(),
file_section.offset,
file_section.size,
bytes,
RoundUp(bytes, kPageSize) / kPageSize,
100 * bytes / header->FileSize());
}
fprintf(stdout, "\n");
}
} // namespace art

View file

@ -0,0 +1,45 @@
/*
* 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);
} // namespace art
#endif // ART_DEXLAYOUT_DEX_VISUALIZE_H_

View file

@ -0,0 +1,687 @@
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Header file of an in-memory representation of DEX files.
*/
#include <stdint.h>
#include <queue>
#include <vector>
#include "dex_writer.h"
#include "utf.h"
namespace art {
size_t EncodeIntValue(int32_t value, uint8_t* buffer) {
size_t length = 0;
if (value >= 0) {
while (value > 0x7f) {
buffer[length++] = static_cast<uint8_t>(value);
value >>= 8;
}
} else {
while (value < -0x80) {
buffer[length++] = static_cast<uint8_t>(value);
value >>= 8;
}
}
buffer[length++] = static_cast<uint8_t>(value);
return length;
}
size_t EncodeUIntValue(uint32_t value, uint8_t* buffer) {
size_t length = 0;
do {
buffer[length++] = static_cast<uint8_t>(value);
value >>= 8;
} while (value != 0);
return length;
}
size_t EncodeLongValue(int64_t value, uint8_t* buffer) {
size_t length = 0;
if (value >= 0) {
while (value > 0x7f) {
buffer[length++] = static_cast<uint8_t>(value);
value >>= 8;
}
} else {
while (value < -0x80) {
buffer[length++] = static_cast<uint8_t>(value);
value >>= 8;
}
}
buffer[length++] = static_cast<uint8_t>(value);
return length;
}
union FloatUnion {
float f_;
uint32_t i_;
};
size_t EncodeFloatValue(float value, uint8_t* buffer) {
FloatUnion float_union;
float_union.f_ = value;
uint32_t int_value = float_union.i_;
size_t index = 3;
do {
buffer[index--] = int_value >> 24;
int_value <<= 8;
} while (int_value != 0);
return 3 - index;
}
union DoubleUnion {
double d_;
uint64_t l_;
};
size_t EncodeDoubleValue(double value, uint8_t* buffer) {
DoubleUnion double_union;
double_union.d_ = value;
uint64_t long_value = double_union.l_;
size_t index = 7;
do {
buffer[index--] = long_value >> 56;
long_value <<= 8;
} while (long_value != 0);
return 7 - index;
}
size_t DexWriter::Write(const void* buffer, size_t length, size_t offset) {
DCHECK_LE(offset + length, mem_map_->Size());
memcpy(mem_map_->Begin() + offset, buffer, length);
return length;
}
size_t DexWriter::WriteSleb128(uint32_t value, size_t offset) {
uint8_t buffer[8];
EncodeSignedLeb128(buffer, value);
return Write(buffer, SignedLeb128Size(value), offset);
}
size_t DexWriter::WriteUleb128(uint32_t value, size_t offset) {
uint8_t buffer[8];
EncodeUnsignedLeb128(buffer, value);
return Write(buffer, UnsignedLeb128Size(value), offset);
}
size_t DexWriter::WriteEncodedValue(dex_ir::EncodedValue* encoded_value, size_t offset) {
size_t original_offset = offset;
size_t start = 0;
size_t length;
uint8_t buffer[8];
int8_t type = encoded_value->Type();
switch (type) {
case DexFile::kDexAnnotationByte:
length = EncodeIntValue(encoded_value->GetByte(), buffer);
break;
case DexFile::kDexAnnotationShort:
length = EncodeIntValue(encoded_value->GetShort(), buffer);
break;
case DexFile::kDexAnnotationChar:
length = EncodeUIntValue(encoded_value->GetChar(), buffer);
break;
case DexFile::kDexAnnotationInt:
length = EncodeIntValue(encoded_value->GetInt(), buffer);
break;
case DexFile::kDexAnnotationLong:
length = EncodeLongValue(encoded_value->GetLong(), buffer);
break;
case DexFile::kDexAnnotationFloat:
length = EncodeFloatValue(encoded_value->GetFloat(), buffer);
start = 4 - length;
break;
case DexFile::kDexAnnotationDouble:
length = EncodeDoubleValue(encoded_value->GetDouble(), buffer);
start = 8 - length;
break;
case DexFile::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:
offset += WriteEncodedValueHeader(type, 0, offset);
offset += WriteEncodedArray(encoded_value->GetEncodedArray()->GetEncodedValues(), offset);
return offset - original_offset;
case DexFile::kDexAnnotationAnnotation:
offset += WriteEncodedValueHeader(type, 0, offset);
offset += WriteEncodedAnnotation(encoded_value->GetEncodedAnnotation(), offset);
return offset - original_offset;
case DexFile::kDexAnnotationNull:
return WriteEncodedValueHeader(type, 0, offset);
case DexFile::kDexAnnotationBoolean:
return WriteEncodedValueHeader(type, encoded_value->GetBoolean() ? 1 : 0, offset);
default:
return 0;
}
offset += WriteEncodedValueHeader(type, length - 1, offset);
offset += Write(buffer + start, length, offset);
return offset - original_offset;
}
size_t DexWriter::WriteEncodedValueHeader(int8_t value_type, size_t value_arg, size_t offset) {
uint8_t buffer[1] = { static_cast<uint8_t>((value_arg << 5) | value_type) };
return Write(buffer, sizeof(uint8_t), offset);
}
size_t DexWriter::WriteEncodedArray(dex_ir::EncodedValueVector* values, size_t offset) {
size_t original_offset = offset;
offset += WriteUleb128(values->size(), offset);
for (std::unique_ptr<dex_ir::EncodedValue>& value : *values) {
offset += WriteEncodedValue(value.get(), offset);
}
return offset - original_offset;
}
size_t DexWriter::WriteEncodedAnnotation(dex_ir::EncodedAnnotation* annotation, size_t offset) {
size_t original_offset = offset;
offset += WriteUleb128(annotation->GetType()->GetIndex(), offset);
offset += WriteUleb128(annotation->GetAnnotationElements()->size(), offset);
for (std::unique_ptr<dex_ir::AnnotationElement>& annotation_element :
*annotation->GetAnnotationElements()) {
offset += WriteUleb128(annotation_element->GetName()->GetIndex(), offset);
offset += WriteEncodedValue(annotation_element->GetValue(), offset);
}
return offset - original_offset;
}
size_t DexWriter::WriteEncodedFields(dex_ir::FieldItemVector* fields, size_t offset) {
size_t original_offset = offset;
uint32_t prev_index = 0;
for (std::unique_ptr<dex_ir::FieldItem>& field : *fields) {
uint32_t index = field->GetFieldId()->GetIndex();
offset += WriteUleb128(index - prev_index, offset);
offset += WriteUleb128(field->GetAccessFlags(), offset);
prev_index = index;
}
return offset - original_offset;
}
size_t DexWriter::WriteEncodedMethods(dex_ir::MethodItemVector* methods, size_t offset) {
size_t original_offset = offset;
uint32_t prev_index = 0;
for (std::unique_ptr<dex_ir::MethodItem>& method : *methods) {
uint32_t index = method->GetMethodId()->GetIndex();
uint32_t code_off = method->GetCodeItem() == nullptr ? 0 : method->GetCodeItem()->GetOffset();
offset += WriteUleb128(index - prev_index, offset);
offset += WriteUleb128(method->GetAccessFlags(), offset);
offset += WriteUleb128(code_off, offset);
prev_index = index;
}
return offset - original_offset;
}
void DexWriter::WriteStrings() {
uint32_t string_data_off[1];
for (std::unique_ptr<dex_ir::StringId>& string_id : header_->GetCollections().StringIds()) {
string_data_off[0] = string_id->DataItem()->GetOffset();
Write(string_data_off, string_id->GetSize(), string_id->GetOffset());
}
for (auto& string_data_pair : header_->GetCollections().StringDatas()) {
std::unique_ptr<dex_ir::StringData>& string_data = string_data_pair.second;
uint32_t offset = string_data->GetOffset();
offset += WriteUleb128(CountModifiedUtf8Chars(string_data->Data()), offset);
Write(string_data->Data(), strlen(string_data->Data()), offset);
}
}
void DexWriter::WriteTypes() {
uint32_t descriptor_idx[1];
for (std::unique_ptr<dex_ir::TypeId>& type_id : header_->GetCollections().TypeIds()) {
descriptor_idx[0] = type_id->GetStringId()->GetIndex();
Write(descriptor_idx, type_id->GetSize(), type_id->GetOffset());
}
}
void DexWriter::WriteTypeLists() {
uint32_t size[1];
uint16_t list[1];
for (auto& type_list_pair : header_->GetCollections().TypeLists()) {
std::unique_ptr<dex_ir::TypeList>& type_list = type_list_pair.second;
size[0] = type_list->GetTypeList()->size();
uint32_t offset = type_list->GetOffset();
offset += Write(size, sizeof(uint32_t), offset);
for (const dex_ir::TypeId* type_id : *type_list->GetTypeList()) {
list[0] = type_id->GetIndex();
offset += Write(list, sizeof(uint16_t), offset);
}
}
}
void DexWriter::WriteProtos() {
uint32_t buffer[3];
for (std::unique_ptr<dex_ir::ProtoId>& proto_id : header_->GetCollections().ProtoIds()) {
buffer[0] = proto_id->Shorty()->GetIndex();
buffer[1] = proto_id->ReturnType()->GetIndex();
buffer[2] = proto_id->Parameters() == nullptr ? 0 : proto_id->Parameters()->GetOffset();
Write(buffer, proto_id->GetSize(), proto_id->GetOffset());
}
}
void DexWriter::WriteFields() {
uint16_t buffer[4];
for (std::unique_ptr<dex_ir::FieldId>& field_id : header_->GetCollections().FieldIds()) {
buffer[0] = field_id->Class()->GetIndex();
buffer[1] = field_id->Type()->GetIndex();
buffer[2] = field_id->Name()->GetIndex();
buffer[3] = field_id->Name()->GetIndex() >> 16;
Write(buffer, field_id->GetSize(), field_id->GetOffset());
}
}
void DexWriter::WriteMethods() {
uint16_t buffer[4];
for (std::unique_ptr<dex_ir::MethodId>& method_id : header_->GetCollections().MethodIds()) {
buffer[0] = method_id->Class()->GetIndex();
buffer[1] = method_id->Proto()->GetIndex();
buffer[2] = method_id->Name()->GetIndex();
buffer[3] = method_id->Name()->GetIndex() >> 16;
Write(buffer, method_id->GetSize(), method_id->GetOffset());
}
}
void DexWriter::WriteEncodedArrays() {
for (auto& encoded_array_pair : header_->GetCollections().EncodedArrayItems()) {
std::unique_ptr<dex_ir::EncodedArrayItem>& encoded_array = encoded_array_pair.second;
WriteEncodedArray(encoded_array->GetEncodedValues(), encoded_array->GetOffset());
}
}
void DexWriter::WriteAnnotations() {
uint8_t visibility[1];
for (auto& annotation_pair : header_->GetCollections().AnnotationItems()) {
std::unique_ptr<dex_ir::AnnotationItem>& annotation = annotation_pair.second;
visibility[0] = annotation->GetVisibility();
size_t offset = annotation->GetOffset();
offset += Write(visibility, sizeof(uint8_t), offset);
WriteEncodedAnnotation(annotation->GetAnnotation(), offset);
}
}
void DexWriter::WriteAnnotationSets() {
uint32_t size[1];
uint32_t annotation_off[1];
for (auto& annotation_set_pair : header_->GetCollections().AnnotationSetItems()) {
std::unique_ptr<dex_ir::AnnotationSetItem>& annotation_set = annotation_set_pair.second;
size[0] = annotation_set->GetItems()->size();
size_t offset = annotation_set->GetOffset();
offset += Write(size, sizeof(uint32_t), offset);
for (dex_ir::AnnotationItem* annotation : *annotation_set->GetItems()) {
annotation_off[0] = annotation->GetOffset();
offset += Write(annotation_off, sizeof(uint32_t), offset);
}
}
}
void DexWriter::WriteAnnotationSetRefs() {
uint32_t size[1];
uint32_t annotations_off[1];
for (auto& anno_set_ref_pair : header_->GetCollections().AnnotationSetRefLists()) {
std::unique_ptr<dex_ir::AnnotationSetRefList>& annotation_set_ref = anno_set_ref_pair.second;
size[0] = annotation_set_ref->GetItems()->size();
size_t offset = annotation_set_ref->GetOffset();
offset += Write(size, sizeof(uint32_t), offset);
for (dex_ir::AnnotationSetItem* annotation_set : *annotation_set_ref->GetItems()) {
annotations_off[0] = annotation_set == nullptr ? 0 : annotation_set->GetOffset();
offset += Write(annotations_off, sizeof(uint32_t), offset);
}
}
}
void DexWriter::WriteAnnotationsDirectories() {
uint32_t directory_buffer[4];
uint32_t annotation_buffer[2];
for (auto& annotations_directory_pair : header_->GetCollections().AnnotationsDirectoryItems()) {
std::unique_ptr<dex_ir::AnnotationsDirectoryItem>& annotations_directory =
annotations_directory_pair.second;
directory_buffer[0] = annotations_directory->GetClassAnnotation() == nullptr ? 0 :
annotations_directory->GetClassAnnotation()->GetOffset();
directory_buffer[1] = annotations_directory->GetFieldAnnotations() == nullptr ? 0 :
annotations_directory->GetFieldAnnotations()->size();
directory_buffer[2] = annotations_directory->GetMethodAnnotations() == nullptr ? 0 :
annotations_directory->GetMethodAnnotations()->size();
directory_buffer[3] = annotations_directory->GetParameterAnnotations() == nullptr ? 0 :
annotations_directory->GetParameterAnnotations()->size();
uint32_t offset = annotations_directory->GetOffset();
offset += Write(directory_buffer, 4 * sizeof(uint32_t), offset);
if (annotations_directory->GetFieldAnnotations() != nullptr) {
for (std::unique_ptr<dex_ir::FieldAnnotation>& field :
*annotations_directory->GetFieldAnnotations()) {
annotation_buffer[0] = field->GetFieldId()->GetIndex();
annotation_buffer[1] = field->GetAnnotationSetItem()->GetOffset();
offset += Write(annotation_buffer, 2 * sizeof(uint32_t), offset);
}
}
if (annotations_directory->GetMethodAnnotations() != nullptr) {
for (std::unique_ptr<dex_ir::MethodAnnotation>& method :
*annotations_directory->GetMethodAnnotations()) {
annotation_buffer[0] = method->GetMethodId()->GetIndex();
annotation_buffer[1] = method->GetAnnotationSetItem()->GetOffset();
offset += Write(annotation_buffer, 2 * sizeof(uint32_t), offset);
}
}
if (annotations_directory->GetParameterAnnotations() != nullptr) {
for (std::unique_ptr<dex_ir::ParameterAnnotation>& parameter :
*annotations_directory->GetParameterAnnotations()) {
annotation_buffer[0] = parameter->GetMethodId()->GetIndex();
annotation_buffer[1] = parameter->GetAnnotations()->GetOffset();
offset += Write(annotation_buffer, 2 * sizeof(uint32_t), offset);
}
}
}
}
void DexWriter::WriteDebugInfoItems() {
for (auto& debug_info_pair : header_->GetCollections().DebugInfoItems()) {
std::unique_ptr<dex_ir::DebugInfoItem>& debug_info = debug_info_pair.second;
Write(debug_info->GetDebugInfo(), debug_info->GetDebugInfoSize(), debug_info->GetOffset());
}
}
void DexWriter::WriteCodeItems() {
uint16_t uint16_buffer[4];
uint32_t uint32_buffer[2];
for (auto& code_item_pair : header_->GetCollections().CodeItems()) {
std::unique_ptr<dex_ir::CodeItem>& code_item = code_item_pair.second;
uint16_buffer[0] = code_item->RegistersSize();
uint16_buffer[1] = code_item->InsSize();
uint16_buffer[2] = code_item->OutsSize();
uint16_buffer[3] = code_item->TriesSize();
uint32_buffer[0] = code_item->DebugInfo() == nullptr ? 0 : code_item->DebugInfo()->GetOffset();
uint32_buffer[1] = code_item->InsnsSize();
size_t offset = code_item->GetOffset();
offset += Write(uint16_buffer, 4 * sizeof(uint16_t), offset);
offset += Write(uint32_buffer, 2 * sizeof(uint32_t), offset);
offset += Write(code_item->Insns(), code_item->InsnsSize() * sizeof(uint16_t), offset);
if (code_item->TriesSize() != 0) {
if (code_item->InsnsSize() % 2 != 0) {
uint16_t padding[1] = { 0 };
offset += Write(padding, sizeof(uint16_t), offset);
}
uint32_t start_addr[1];
uint16_t insn_count_and_handler_off[2];
for (std::unique_ptr<const dex_ir::TryItem>& try_item : *code_item->Tries()) {
start_addr[0] = try_item->StartAddr();
insn_count_and_handler_off[0] = try_item->InsnCount();
insn_count_and_handler_off[1] = try_item->GetHandlers()->GetListOffset();
offset += Write(start_addr, sizeof(uint32_t), offset);
offset += Write(insn_count_and_handler_off, 2 * sizeof(uint16_t), offset);
}
// Leave offset pointing to the end of the try items.
WriteUleb128(code_item->Handlers()->size(), offset);
for (std::unique_ptr<const dex_ir::CatchHandler>& handlers : *code_item->Handlers()) {
size_t list_offset = offset + handlers->GetListOffset();
uint32_t size = handlers->HasCatchAll() ? (handlers->GetHandlers()->size() - 1) * -1 :
handlers->GetHandlers()->size();
list_offset += WriteSleb128(size, list_offset);
for (std::unique_ptr<const dex_ir::TypeAddrPair>& handler : *handlers->GetHandlers()) {
if (handler->GetTypeId() != nullptr) {
list_offset += WriteUleb128(handler->GetTypeId()->GetIndex(), list_offset);
}
list_offset += WriteUleb128(handler->GetAddress(), list_offset);
}
}
}
}
}
void DexWriter::WriteClasses() {
uint32_t class_def_buffer[8];
for (std::unique_ptr<dex_ir::ClassDef>& class_def : header_->GetCollections().ClassDefs()) {
class_def_buffer[0] = class_def->ClassType()->GetIndex();
class_def_buffer[1] = class_def->GetAccessFlags();
class_def_buffer[2] = class_def->Superclass() == nullptr ? DexFile::kDexNoIndex :
class_def->Superclass()->GetIndex();
class_def_buffer[3] = class_def->InterfacesOffset();
class_def_buffer[4] = class_def->SourceFile() == nullptr ? DexFile::kDexNoIndex :
class_def->SourceFile()->GetIndex();
class_def_buffer[5] = class_def->Annotations() == nullptr ? 0 :
class_def->Annotations()->GetOffset();
class_def_buffer[6] = class_def->GetClassData() == nullptr ? 0 :
class_def->GetClassData()->GetOffset();
class_def_buffer[7] = class_def->StaticValues() == nullptr ? 0 :
class_def->StaticValues()->GetOffset();
size_t offset = class_def->GetOffset();
Write(class_def_buffer, class_def->GetSize(), offset);
}
for (auto& class_data_pair : header_->GetCollections().ClassDatas()) {
std::unique_ptr<dex_ir::ClassData>& class_data = class_data_pair.second;
size_t offset = class_data->GetOffset();
offset += WriteUleb128(class_data->StaticFields()->size(), offset);
offset += WriteUleb128(class_data->InstanceFields()->size(), offset);
offset += WriteUleb128(class_data->DirectMethods()->size(), offset);
offset += WriteUleb128(class_data->VirtualMethods()->size(), offset);
offset += WriteEncodedFields(class_data->StaticFields(), offset);
offset += WriteEncodedFields(class_data->InstanceFields(), offset);
offset += WriteEncodedMethods(class_data->DirectMethods(), offset);
offset += WriteEncodedMethods(class_data->VirtualMethods(), offset);
}
}
void DexWriter::WriteCallSites() {
uint32_t call_site_off[1];
for (std::unique_ptr<dex_ir::CallSiteId>& call_site_id :
header_->GetCollections().CallSiteIds()) {
call_site_off[0] = call_site_id->CallSiteItem()->GetOffset();
Write(call_site_off, call_site_id->GetSize(), call_site_id->GetOffset());
}
}
void DexWriter::WriteMethodHandles() {
uint16_t method_handle_buff[4];
for (std::unique_ptr<dex_ir::MethodHandleItem>& method_handle :
header_->GetCollections().MethodHandleItems()) {
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.
Write(method_handle_buff, method_handle->GetSize(), method_handle->GetOffset());
}
}
struct MapItemContainer {
MapItemContainer(uint32_t type, uint32_t size, uint32_t offset)
: type_(type), size_(size), offset_(offset) { }
bool operator<(const MapItemContainer& other) const {
return offset_ > other.offset_;
}
uint32_t type_;
uint32_t size_;
uint32_t offset_;
};
void DexWriter::WriteMapItem() {
dex_ir::Collections& collection = header_->GetCollections();
std::priority_queue<MapItemContainer> queue;
// Header and index section.
queue.push(MapItemContainer(DexFile::kDexTypeHeaderItem, 1, 0));
if (collection.StringIdsSize() != 0) {
queue.push(MapItemContainer(DexFile::kDexTypeStringIdItem, collection.StringIdsSize(),
collection.StringIdsOffset()));
}
if (collection.TypeIdsSize() != 0) {
queue.push(MapItemContainer(DexFile::kDexTypeTypeIdItem, collection.TypeIdsSize(),
collection.TypeIdsOffset()));
}
if (collection.ProtoIdsSize() != 0) {
queue.push(MapItemContainer(DexFile::kDexTypeProtoIdItem, collection.ProtoIdsSize(),
collection.ProtoIdsOffset()));
}
if (collection.FieldIdsSize() != 0) {
queue.push(MapItemContainer(DexFile::kDexTypeFieldIdItem, collection.FieldIdsSize(),
collection.FieldIdsOffset()));
}
if (collection.MethodIdsSize() != 0) {
queue.push(MapItemContainer(DexFile::kDexTypeMethodIdItem, collection.MethodIdsSize(),
collection.MethodIdsOffset()));
}
if (collection.ClassDefsSize() != 0) {
queue.push(MapItemContainer(DexFile::kDexTypeClassDefItem, collection.ClassDefsSize(),
collection.ClassDefsOffset()));
}
if (collection.CallSiteIdsSize() != 0) {
queue.push(MapItemContainer(DexFile::kDexTypeCallSiteIdItem, collection.CallSiteIdsSize(),
collection.CallSiteIdsOffset()));
}
if (collection.MethodHandleItemsSize() != 0) {
queue.push(MapItemContainer(DexFile::kDexTypeMethodHandleItem,
collection.MethodHandleItemsSize(), collection.MethodHandleItemsOffset()));
}
// Data section.
queue.push(MapItemContainer(DexFile::kDexTypeMapList, 1, collection.MapListOffset()));
if (collection.TypeListsSize() != 0) {
queue.push(MapItemContainer(DexFile::kDexTypeTypeList, collection.TypeListsSize(),
collection.TypeListsOffset()));
}
if (collection.AnnotationSetRefListsSize() != 0) {
queue.push(MapItemContainer(DexFile::kDexTypeAnnotationSetRefList,
collection.AnnotationSetRefListsSize(), collection.AnnotationSetRefListsOffset()));
}
if (collection.AnnotationSetItemsSize() != 0) {
queue.push(MapItemContainer(DexFile::kDexTypeAnnotationSetItem,
collection.AnnotationSetItemsSize(), collection.AnnotationSetItemsOffset()));
}
if (collection.ClassDatasSize() != 0) {
queue.push(MapItemContainer(DexFile::kDexTypeClassDataItem, collection.ClassDatasSize(),
collection.ClassDatasOffset()));
}
if (collection.CodeItemsSize() != 0) {
queue.push(MapItemContainer(DexFile::kDexTypeCodeItem, collection.CodeItemsSize(),
collection.CodeItemsOffset()));
}
if (collection.StringDatasSize() != 0) {
queue.push(MapItemContainer(DexFile::kDexTypeStringDataItem, collection.StringDatasSize(),
collection.StringDatasOffset()));
}
if (collection.DebugInfoItemsSize() != 0) {
queue.push(MapItemContainer(DexFile::kDexTypeDebugInfoItem, collection.DebugInfoItemsSize(),
collection.DebugInfoItemsOffset()));
}
if (collection.AnnotationItemsSize() != 0) {
queue.push(MapItemContainer(DexFile::kDexTypeAnnotationItem, collection.AnnotationItemsSize(),
collection.AnnotationItemsOffset()));
}
if (collection.EncodedArrayItemsSize() != 0) {
queue.push(MapItemContainer(DexFile::kDexTypeEncodedArrayItem,
collection.EncodedArrayItemsSize(), collection.EncodedArrayItemsOffset()));
}
if (collection.AnnotationsDirectoryItemsSize() != 0) {
queue.push(MapItemContainer(DexFile::kDexTypeAnnotationsDirectoryItem,
collection.AnnotationsDirectoryItemsSize(), collection.AnnotationsDirectoryItemsOffset()));
}
uint32_t offset = collection.MapListOffset();
uint16_t uint16_buffer[2];
uint32_t uint32_buffer[2];
uint16_buffer[1] = 0;
uint32_buffer[0] = queue.size();
offset += Write(uint32_buffer, sizeof(uint32_t), offset);
while (!queue.empty()) {
const MapItemContainer& map_item = queue.top();
uint16_buffer[0] = map_item.type_;
uint32_buffer[0] = map_item.size_;
uint32_buffer[1] = map_item.offset_;
offset += Write(uint16_buffer, 2 * sizeof(uint16_t), offset);
offset += Write(uint32_buffer, 2 * sizeof(uint32_t), offset);
queue.pop();
}
}
void DexWriter::WriteHeader() {
uint32_t buffer[20];
dex_ir::Collections& collections = header_->GetCollections();
size_t offset = 0;
offset += Write(header_->Magic(), 8 * sizeof(uint8_t), offset);
buffer[0] = header_->Checksum();
offset += Write(buffer, sizeof(uint32_t), offset);
offset += Write(header_->Signature(), 20 * sizeof(uint8_t), offset);
uint32_t file_size = header_->FileSize();
buffer[0] = file_size;
buffer[1] = header_->GetSize();
buffer[2] = header_->EndianTag();
buffer[3] = header_->LinkSize();
buffer[4] = header_->LinkOffset();
buffer[5] = collections.MapListOffset();
buffer[6] = collections.StringIdsSize();
buffer[7] = collections.StringIdsOffset();
buffer[8] = collections.TypeIdsSize();
buffer[9] = collections.TypeIdsOffset();
buffer[10] = collections.ProtoIdsSize();
buffer[11] = collections.ProtoIdsOffset();
buffer[12] = collections.FieldIdsSize();
buffer[13] = collections.FieldIdsOffset();
buffer[14] = collections.MethodIdsSize();
buffer[15] = collections.MethodIdsOffset();
uint32_t class_defs_size = collections.ClassDefsSize();
uint32_t class_defs_off = collections.ClassDefsOffset();
buffer[16] = class_defs_size;
buffer[17] = class_defs_off;
buffer[18] = header_->DataSize();
buffer[19] = header_->DataOffset();
Write(buffer, 20 * sizeof(uint32_t), offset);
}
void DexWriter::WriteMemMap() {
WriteStrings();
WriteTypes();
WriteTypeLists();
WriteProtos();
WriteFields();
WriteMethods();
WriteEncodedArrays();
WriteAnnotations();
WriteAnnotationSets();
WriteAnnotationSetRefs();
WriteAnnotationsDirectories();
WriteDebugInfoItems();
WriteCodeItems();
WriteClasses();
WriteCallSites();
WriteMethodHandles();
WriteMapItem();
WriteHeader();
}
void DexWriter::Output(dex_ir::Header* header, MemMap* mem_map) {
DexWriter dex_writer(header, mem_map);
dex_writer.WriteMemMap();
}
} // namespace art

View file

@ -0,0 +1,75 @@
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Header file of an in-memory representation of DEX files.
*/
#ifndef ART_DEXLAYOUT_DEX_WRITER_H_
#define ART_DEXLAYOUT_DEX_WRITER_H_
#include "base/unix_file/fd_file.h"
#include "dex_ir.h"
#include "mem_map.h"
#include "os.h"
namespace art {
class DexWriter {
public:
DexWriter(dex_ir::Header* header, MemMap* mem_map) : header_(header), mem_map_(mem_map) { }
static void Output(dex_ir::Header* header, MemMap* mem_map);
private:
void WriteMemMap();
size_t Write(const void* buffer, size_t length, size_t offset);
size_t WriteSleb128(uint32_t value, size_t offset);
size_t WriteUleb128(uint32_t value, size_t offset);
size_t WriteEncodedValue(dex_ir::EncodedValue* encoded_value, size_t offset);
size_t WriteEncodedValueHeader(int8_t value_type, size_t value_arg, size_t offset);
size_t WriteEncodedArray(dex_ir::EncodedValueVector* values, size_t offset);
size_t WriteEncodedAnnotation(dex_ir::EncodedAnnotation* annotation, size_t offset);
size_t WriteEncodedFields(dex_ir::FieldItemVector* fields, size_t offset);
size_t WriteEncodedMethods(dex_ir::MethodItemVector* methods, size_t offset);
void WriteStrings();
void WriteTypes();
void WriteTypeLists();
void WriteProtos();
void WriteFields();
void WriteMethods();
void WriteEncodedArrays();
void WriteAnnotations();
void WriteAnnotationSets();
void WriteAnnotationSetRefs();
void WriteAnnotationsDirectories();
void WriteDebugInfoItems();
void WriteCodeItems();
void WriteClasses();
void WriteCallSites();
void WriteMethodHandles();
void WriteMapItem();
void WriteHeader();
dex_ir::Header* const header_;
MemMap* const mem_map_;
DISALLOW_COPY_AND_ASSIGN(DexWriter);
};
} // namespace art
#endif // ART_DEXLAYOUT_DEX_WRITER_H_

View file

@ -0,0 +1,539 @@
/*
* 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 <vector>
#include "android-base/stringprintf.h"
#include "base/stringpiece.h"
#include "dex_file.h"
#include "dex_ir.h"
#include "dex_ir_builder.h"
#ifdef ART_TARGET_ANDROID
#include "pagemap/pagemap.h"
#endif
#include "runtime.h"
#include "vdex_file.h"
namespace art {
using android::base::StringPrintf;
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 {
return map_.at(type);
}
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 / kPageSize;
// 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(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 (PM_PAGEMAP_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(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) / kPageSize;
uint64_t start_address = start_page * kPageSize;
uint64_t end_page = RoundUp(start_address + dex_file_size, kPageSize) / kPageSize;
std::cout << "DEX "
<< dex_file->GetLocation().c_str()
<< StringPrintf(": %" PRIx64 "-%" PRIx64,
map_start + start_page * kPageSize,
map_start + end_page * kPageSize)
<< std::endl;
// Build a list of the dex file section types, sorted from highest offset to lowest.
std::vector<dex_ir::DexFileSection> sections;
{
std::unique_ptr<dex_ir::Header> header(dex_ir::DexIrBuilder(*dex_file));
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(pm_map_t* map, Printer* printer) {
std::string vdex_name = pm_map_name(map);
// Extract all the dex files from the vdex file.
std::string error_msg;
std::unique_ptr<VdexFile> vdex(VdexFile::Open(vdex_name,
false /*writeable*/,
false /*low_4gb*/,
false /*unquicken */,
&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.
uint64_t* pagemap;
size_t len;
if (pm_map_pagemap(map, &pagemap, &len) != 0) {
std::cerr << "Error creating pagemap." << std::endl;
return false;
}
// Process the dex files.
std::cout << "MAPPING "
<< pm_map_name(map)
<< StringPrintf(": %" PRIx64 "-%" PRIx64, pm_map_start(map), pm_map_end(map))
<< std::endl;
for (const auto& dex_file : dex_files) {
ProcessOneDexMapping(pagemap,
pm_map_start(map),
dex_file.get(),
reinterpret_cast<uint64_t>(vdex->Begin()),
printer);
}
free(pagemap);
return true;
}
static void ProcessOneOatMapping(uint64_t* pagemap, size_t size, Printer* printer) {
static constexpr size_t kLineLength = 32;
size_t resident_page_count = 0;
for (size_t page = 0; page < size; ++page) {
char type_char = '.';
if (PM_PAGEMAP_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 (size % kLineLength != 0) {
std::cout << std::endl;
}
}
double percent_of_total = 100.0 * resident_page_count / size;
printer->PrintHeader();
printer->PrintOne("EXECUTABLE", resident_page_count, 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(pm_map_t* map, Printer* printer) {
// Open the page mapping (one uint64_t per page) for the entire vdex mapping.
uint64_t* pagemap;
size_t len;
if (pm_map_pagemap(map, &pagemap, &len) != 0) {
std::cerr << "Error creating pagemap." << std::endl;
return false;
}
// Process the dex files.
std::cout << "MAPPING "
<< pm_map_name(map)
<< StringPrintf(": %" PRIx64 "-%" PRIx64, pm_map_start(map), pm_map_end(map))
<< std::endl;
ProcessOneOatMapping(pagemap, len, printer);
free(pagemap);
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();
}
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 StringPiece option(argv[i]);
if (option == "--help") {
Usage(argv[0]);
return EXIT_SUCCESS;
} else if (option == "--verbose") {
g_verbose = true;
} else if (option.starts_with("--contains=")) {
std::string contains(option.substr(strlen("--contains=")).data());
name_filters.push_back(contains);
} else {
Usage(argv[0]);
return EXIT_FAILURE;
}
}
// Art specific set up.
InitLogging(argv, Runtime::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 libpagemap kernel information.
pm_kernel_t* ker;
if (pm_kernel_create(&ker) != 0) {
std::cerr << "Error creating kernel interface -- does this kernel have pagemap?" << std::endl;
return EXIT_FAILURE;
}
// get libpagemap process information.
pm_process_t* proc;
if (pm_process_create(ker, pid, &proc) != 0) {
std::cerr << "Error creating process interface -- does process "
<< pid
<< " really exist?"
<< std::endl;
return EXIT_FAILURE;
}
// Get the set of mappings by the specified process.
pm_map_t** maps;
size_t num_maps;
if (pm_process_maps(proc, &maps, &num_maps) != 0) {
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 (size_t i = 0; i < num_maps; ++i) {
std::string mapped_file_name = pm_map_name(maps[i]);
// Filter by name contains options (if any).
if (!FilterByNameContains(mapped_file_name, name_filters)) {
continue;
}
if (IsVdexFileMapping(mapped_file_name)) {
if (!DisplayMappingIfFromVdexFile(maps[i], &printer)) {
return EXIT_FAILURE;
}
match_found = true;
} else if (IsOatFileMapping(mapped_file_name)) {
if (!DisplayMappingIfFromOatFile(maps[i], &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);
}

View file

@ -0,0 +1,152 @@
/*
* 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 "common_runtime_test.h"
#include "runtime/exec_utils.h"
#include "runtime/oat_file.h"
#include "runtime/os.h"
namespace art {
static const char* kDexDiagContains = "--contains=core.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 CommonRuntimeTest {
protected:
virtual void SetUp() {
CommonRuntimeTest::SetUp();
}
// Path to the dexdiag(d?)[32|64] binary.
std::string GetDexDiagFilePath() {
std::string root = GetTestAndroidRoot();
root += "/bin/";
root += kDexDiagBinaryName;
std::string root32 = root + "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(root32.c_str()) && !Is64BitInstructionSet(kRuntimeISA)) {
return root32;
} else {
// This is a 64-bit build or only a single build exists.
return root;
}
}
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(oat_location.c_str(),
oat_location.c_str(),
nullptr,
nullptr,
false,
/*low_4gb*/false,
nullptr,
&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

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,143 @@
/*
* 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 "dex_file_layout.h"
#include "dex_ir.h"
#include "mem_map.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_memmap_ = 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_ = false;
bool visualize_pattern_ = false;
OutputFormat output_format_ = kOutputPlain;
const char* output_dex_directory_ = nullptr;
const char* output_file_name_ = nullptr;
const char* profile_file_name_ = nullptr;
};
class DexLayout {
public:
DexLayout(Options& options,
ProfileCompilationInfo* info,
FILE* out_file,
dex_ir::Header*
header = nullptr)
: options_(options), info_(info), out_file_(out_file), header_(header) { }
int ProcessFile(const char* file_name);
void ProcessDexFile(const char* file_name, const DexFile* dex_file, size_t dex_file_index);
dex_ir::Header* GetHeader() const { return header_; }
void SetHeader(dex_ir::Header* header) { header_ = header; }
MemMap* GetAndReleaseMemMap() { return mem_map_.release(); }
const DexLayoutSections& GetSections() const {
return dex_sections_;
}
private:
void DumpAnnotationSetItem(dex_ir::AnnotationSetItem* set_item);
void DumpBytecodes(uint32_t idx, const dex_ir::CodeItem* code, uint32_t code_offset);
void DumpCatches(const dex_ir::CodeItem* code);
void DumpClass(int idx, char** last_package);
void DumpClassAnnotations(int idx);
void DumpClassDef(int idx);
void DumpCode(uint32_t idx, const dex_ir::CodeItem* code, uint32_t code_offset);
void DumpEncodedAnnotation(dex_ir::EncodedAnnotation* annotation);
void DumpEncodedValue(const dex_ir::EncodedValue* data);
void DumpFileHeader();
void DumpIField(uint32_t idx, uint32_t flags, int i);
void DumpInstruction(const dex_ir::CodeItem* code,
uint32_t code_offset,
uint32_t insn_idx,
uint32_t insn_width,
const Instruction* dec_insn);
void DumpInterface(const dex_ir::TypeId* type_item, int i);
void DumpLocalInfo(const dex_ir::CodeItem* code);
void DumpMethod(uint32_t idx, uint32_t flags, const dex_ir::CodeItem* code, int i);
void DumpPositionInfo(const dex_ir::CodeItem* code);
void DumpSField(uint32_t idx, uint32_t flags, int i, dex_ir::EncodedValue* init);
void DumpDexFile();
std::vector<dex_ir::ClassData*> LayoutClassDefsAndClassData(const DexFile* dex_file);
int32_t LayoutCodeItems(const DexFile* dex_file,
std::vector<dex_ir::ClassData*> new_class_data_order);
void LayoutStringData(const DexFile* dex_file);
bool IsNextSectionCodeItemAligned(uint32_t offset);
template<class T> void FixupSection(std::map<uint32_t, std::unique_ptr<T>>& map, uint32_t diff);
void FixupSections(uint32_t offset, uint32_t diff);
// Creates a new layout for the dex file based on profile info.
// Currently reorders ClassDefs, ClassDataItems, and CodeItems.
void LayoutOutputFile(const DexFile* dex_file);
void OutputDexFile(const DexFile* dex_file);
void DumpCFG(const DexFile* dex_file, int idx);
void DumpCFG(const DexFile* dex_file, uint32_t dex_method_idx, const DexFile::CodeItem* code);
Options& options_;
ProfileCompilationInfo* info_;
FILE* out_file_;
dex_ir::Header* header_;
std::unique_ptr<MemMap> mem_map_;
DexLayoutSections dex_sections_;
DISALLOW_COPY_AND_ASSIGN(DexLayout);
};
} // namespace art
#endif // ART_DEXLAYOUT_DEXLAYOUT_H_

View file

@ -0,0 +1,208 @@
/*
* 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 <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "base/logging.h"
#include "jit/profile_compilation_info.h"
#include "runtime.h"
#include "mem_map.h"
namespace art {
static const char* kProgramName = "dexlayout";
/*
* Shows usage.
*/
static void Usage(void) {
fprintf(stderr, "Copyright (C) 2016 The Android Open Source Project\n\n");
fprintf(stderr, "%s: [-a] [-c] [-d] [-e] [-f] [-h] [-i] [-l layout] [-o outfile] [-p profile]"
" [-s] [-t] [-v] [-w directory] dexfile...\n\n", kProgramName);
fprintf(stderr, " -a : display annotations\n");
fprintf(stderr, " -b : build dex_ir\n");
fprintf(stderr, " -c : verify checksum and exit\n");
fprintf(stderr, " -d : disassemble code sections\n");
fprintf(stderr, " -e : display exported items only\n");
fprintf(stderr, " -f : display summary information from file header\n");
fprintf(stderr, " -h : display file header details\n");
fprintf(stderr, " -i : ignore checksum failures\n");
fprintf(stderr, " -l : output layout, either 'plain' or 'xml'\n");
fprintf(stderr, " -o : output file name (defaults to stdout)\n");
fprintf(stderr, " -p : profile file name (defaults to no profile)\n");
fprintf(stderr, " -s : visualize reference pattern\n");
fprintf(stderr, " -t : display file section sizes\n");
fprintf(stderr, " -v : verify output file is canonical to input (IR level comparison)\n");
fprintf(stderr, " -w : output dex directory \n");
}
/*
* Main driver of the dexlayout utility.
*/
int DexlayoutDriver(int argc, char** argv) {
// Art specific set up.
InitLogging(argv, Runtime::Abort);
MemMap::Init();
Options options;
options.dump_ = true;
options.verbose_ = true;
bool want_usage = false;
// Parse all arguments.
while (1) {
const int ic = getopt(argc, argv, "abcdefghil:mo:p:stvw:");
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 'm': // output dex files to a memmap
options.output_to_memmap_ = 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 'v': // verify output
options.verify_output_ = true;
break;
case 'w': // output dex files directory
options.output_dex_directory_ = optarg;
break;
default:
want_usage = true;
break;
} // switch
} // while
// Detect early problems.
if (optind == argc) {
fprintf(stderr, "%s: no file specified\n", kProgramName);
want_usage = true;
}
if (options.checksum_only_ && options.ignore_bad_checksum_) {
fprintf(stderr, "Can't specify both -c and -i\n");
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_, "w");
if (!out_file) {
fprintf(stderr, "Can't open %s\n", options.output_file_name_);
return 1;
}
}
// Open profile file.
std::unique_ptr<ProfileCompilationInfo> profile_info;
if (options.profile_file_name_) {
int profile_fd = open(options.profile_file_name_, O_RDONLY);
if (profile_fd < 0) {
fprintf(stderr, "Can't open %s\n", options.profile_file_name_);
return 1;
}
profile_info.reset(new ProfileCompilationInfo());
if (!profile_info->Load(profile_fd)) {
fprintf(stderr, "Can't read profile info from %s\n", options.profile_file_name_);
return 1;
}
}
// Create DexLayout instance.
DexLayout dex_layout(options, profile_info.get(), out_file);
// 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;
}
} // namespace art
int main(int argc, char** argv) {
return art::DexlayoutDriver(argc, argv);
}

View file

@ -0,0 +1,674 @@
/*
* 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 <string>
#include <vector>
#include <sstream>
#include <sys/types.h>
#include <unistd.h>
#include "base/unix_file/fd_file.h"
#include "common_runtime_test.h"
#include "dex_file-inl.h"
#include "exec_utils.h"
#include "jit/profile_compilation_info.h"
#include "utils.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=";
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 CommonRuntimeTest {
protected:
virtual void SetUp() {
CommonRuntimeTest::SetUp();
}
// Runs FullPlainOutput test.
bool FullPlainOutputExec(std::string* error_msg) {
// TODO: dexdump2 -> dexdump ?
ScratchFile dexdump_output;
const std::string& dexdump_filename = dexdump_output.GetFilename();
std::string dexdump = GetTestAndroidRoot() + "/bin/dexdump2";
EXPECT_TRUE(OS::FileExists(dexdump.c_str())) << dexdump << " should be a valid file path";
ScratchFile dexlayout_output;
const std::string& dexlayout_filename = dexlayout_output.GetFilename();
std::string dexlayout = GetTestAndroidRoot() + "/bin/dexlayout";
EXPECT_TRUE(OS::FileExists(dexlayout.c_str())) << dexlayout << " should be a valid file path";
for (const std::string &dex_file : GetLibCoreDexFileNames()) {
std::vector<std::string> dexdump_exec_argv =
{ dexdump, "-d", "-f", "-h", "-l", "plain", "-o", dexdump_filename, dex_file };
std::vector<std::string> dexlayout_exec_argv =
{ dexlayout, "-d", "-f", "-h", "-l", "plain", "-o", dexlayout_filename, dex_file };
if (!::art::Exec(dexdump_exec_argv, error_msg)) {
return false;
}
if (!::art::Exec(dexlayout_exec_argv, error_msg)) {
return false;
}
std::vector<std::string> diff_exec_argv =
{ "/usr/bin/diff", dexdump_filename, dexlayout_filename };
if (!::art::Exec(diff_exec_argv, error_msg)) {
return false;
}
}
return true;
}
// 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 dexlayout = GetTestAndroidRoot() + "/bin/dexlayout";
EXPECT_TRUE(OS::FileExists(dexlayout.c_str())) << dexlayout << " should be a valid file path";
for (const std::string &dex_file : GetLibCoreDexFileNames()) {
std::vector<std::string> dexlayout_exec_argv =
{ dexlayout, "-w", tmp_dir, "-o", tmp_name, dex_file };
if (!::art::Exec(dexlayout_exec_argv, error_msg)) {
return false;
}
size_t dex_file_last_slash = dex_file.rfind("/");
std::string dex_file_name = dex_file.substr(dex_file_last_slash + 1);
std::vector<std::string> unzip_exec_argv =
{ "/usr/bin/unzip", dex_file, "classes.dex", "-d", tmp_dir};
if (!::art::Exec(unzip_exec_argv, error_msg)) {
return false;
}
std::vector<std::string> diff_exec_argv =
{ "/usr/bin/diff", tmp_dir + "classes.dex" , tmp_dir + dex_file_name };
if (!::art::Exec(diff_exec_argv, error_msg)) {
return false;
}
std::vector<std::string> rm_zip_exec_argv = { "/bin/rm", tmp_dir + "classes.dex" };
if (!::art::Exec(rm_zip_exec_argv, error_msg)) {
return false;
}
std::vector<std::string> rm_out_exec_argv = { "/bin/rm", tmp_dir + dex_file_name };
if (!::art::Exec(rm_out_exec_argv, error_msg)) {
return false;
}
}
return true;
}
// Create a profile with some subset of methods and classes.
void CreateProfile(const std::string& input_dex,
const std::string& out_profile,
const std::string& dex_location) {
std::vector<std::unique_ptr<const DexFile>> dex_files;
std::string error_msg;
bool result = DexFile::Open(input_dex.c_str(),
input_dex,
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;
std::set<DexCacheResolvedClasses> classes;
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.AddMethodIndex(static_cast<ProfileCompilationInfo::MethodHotness::Flag>(flags),
dex_location,
dex_file->GetLocationChecksum(),
/*dex_method_idx*/i,
dex_file->NumMethodIds());
}
DexCacheResolvedClasses cur_classes(dex_location,
dex_location,
dex_file->GetLocationChecksum(),
dex_file->NumMethodIds());
// Add every even class too.
for (uint32_t i = 0; i < dex_file->NumClassDefs(); i += 1) {
if ((i & 2) == 0) {
cur_classes.AddClass(dex_file->GetClassDef(i).class_idx_);
++profile_classes;
}
}
classes.insert(cur_classes);
}
pfi.AddClasses(classes);
// 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;
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, dex_file);
// WriteFileBase64(kDexFileLayoutInputProfile, profile_file.c_str());
std::string output_dex = tmp_dir + "classes.dex.new";
std::string dexlayout = GetTestAndroidRoot() + "/bin/dexlayout";
EXPECT_TRUE(OS::FileExists(dexlayout.c_str())) << dexlayout << " should be a valid file path";
std::vector<std::string> dexlayout_exec_argv =
{ dexlayout, "-v", "-w", tmp_dir, "-o", tmp_name, "-p", profile_file, dex_file };
if (!::art::Exec(dexlayout_exec_argv, error_msg)) {
return false;
}
// -v makes sure that the layout did not corrupt the dex file.
std::vector<std::string> rm_exec_argv =
{ "/bin/rm", dex_file, profile_file, output_dex };
if (!::art::Exec(rm_exec_argv, error_msg)) {
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;
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, dex_file);
std::string output_dex = tmp_dir + "classes.dex.new";
std::string second_output_dex = tmp_dir + "classes.dex.new.new";
std::string dexlayout = GetTestAndroidRoot() + "/bin/dexlayout";
EXPECT_TRUE(OS::FileExists(dexlayout.c_str())) << dexlayout << " should be a valid file path";
// -v makes sure that the layout did not corrupt the dex file.
std::vector<std::string> dexlayout_exec_argv =
{ dexlayout, "-i", "-v", "-w", tmp_dir, "-o", tmp_name, "-p", profile_file, dex_file };
if (!::art::Exec(dexlayout_exec_argv, error_msg)) {
return false;
}
// Recreate the profile with the new dex location. This is required so that the profile dex
// location matches.
CreateProfile(dex_file, profile_file, output_dex);
// -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_exec_argv =
{ dexlayout, "-i", "-v", "-w", tmp_dir, "-o", tmp_name, "-p", profile_file, output_dex };
if (!::art::Exec(second_dexlayout_exec_argv, error_msg)) {
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> rm_exec_argv =
{ "/bin/rm", dex_file, profile_file, output_dex, second_output_dex };
if (!::art::Exec(rm_exec_argv, error_msg)) {
return false;
}
return diff_result;
}
// Runs UnreferencedCatchHandlerTest & Unreferenced0SizeCatchHandlerTest.
bool UnreferencedCatchHandlerExec(std::string* error_msg, const char* filename) {
ScratchFile tmp_file;
std::string tmp_name = tmp_file.GetFilename();
size_t tmp_last_slash = tmp_name.rfind("/");
std::string tmp_dir = tmp_name.substr(0, tmp_last_slash + 1);
// 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::string dexlayout = GetTestAndroidRoot() + "/bin/dexlayout";
EXPECT_TRUE(OS::FileExists(dexlayout.c_str())) << dexlayout << " should be a valid file path";
std::vector<std::string> dexlayout_exec_argv =
{ dexlayout, "-w", tmp_dir, "-o", "/dev/null", input_dex };
if (!::art::Exec(dexlayout_exec_argv, error_msg)) {
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> rm_exec_argv = { "/bin/rm", input_dex, output_dex };
if (!::art::Exec(rm_exec_argv, error_msg)) {
return false;
}
return true;
}
bool DexLayoutExec(ScratchFile* dex_file,
const char* dex_filename,
ScratchFile* profile_file,
std::vector<std::string>& dexlayout_exec_argv) {
WriteBase64ToFile(dex_filename, dex_file->GetFile());
EXPECT_EQ(dex_file->GetFile()->Flush(), 0);
if (profile_file != nullptr) {
CreateProfile(dex_file->GetFilename(), profile_file->GetFilename(), dex_file->GetFilename());
}
std::string error_msg;
const bool result = ::art::Exec(dexlayout_exec_argv, &error_msg);
if (!result) {
LOG(ERROR) << "Error: " << error_msg;
return false;
}
return true;
}
};
TEST_F(DexLayoutTest, FullPlainOutput) {
// Disable test on target.
TEST_DISABLED_FOR_TARGET();
std::string error_msg;
ASSERT_TRUE(FullPlainOutputExec(&error_msg)) << error_msg;
}
TEST_F(DexLayoutTest, DexFileOutput) {
// Disable test on target.
TEST_DISABLED_FOR_TARGET();
std::string error_msg;
ASSERT_TRUE(DexFileOutputExec(&error_msg)) << error_msg;
}
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::string dexlayout = GetTestAndroidRoot() + "/bin/dexlayout";
EXPECT_TRUE(OS::FileExists(dexlayout.c_str())) << dexlayout << " should be a valid file path";
std::vector<std::string> dexlayout_exec_argv =
{ dexlayout, "-a", "-i", "-o", "/dev/null", temp_dex.GetFilename() };
ASSERT_TRUE(DexLayoutExec(&temp_dex,
kDexFileDuplicateOffset,
nullptr /* profile_file */,
dexlayout_exec_argv));
}
TEST_F(DexLayoutTest, NullSetRefListElement) {
ScratchFile temp_dex;
std::string dexlayout = GetTestAndroidRoot() + "/bin/dexlayout";
EXPECT_TRUE(OS::FileExists(dexlayout.c_str())) << dexlayout << " should be a valid file path";
std::vector<std::string> dexlayout_exec_argv =
{ dexlayout, "-o", "/dev/null", temp_dex.GetFilename() };
ASSERT_TRUE(DexLayoutExec(&temp_dex,
kNullSetRefListElementInputDex,
nullptr /* profile_file */,
dexlayout_exec_argv));
}
TEST_F(DexLayoutTest, MultiClassData) {
ScratchFile temp_dex;
ScratchFile temp_profile;
std::string dexlayout = GetTestAndroidRoot() + "/bin/dexlayout";
EXPECT_TRUE(OS::FileExists(dexlayout.c_str())) << dexlayout << " should be a valid file path";
std::vector<std::string> dexlayout_exec_argv =
{ dexlayout, "-p", temp_profile.GetFilename(), "-o", "/dev/null", temp_dex.GetFilename() };
ASSERT_TRUE(DexLayoutExec(&temp_dex,
kMultiClassDataInputDex,
&temp_profile,
dexlayout_exec_argv));
}
TEST_F(DexLayoutTest, UnalignedCodeInfo) {
ScratchFile temp_dex;
ScratchFile temp_profile;
std::string dexlayout = GetTestAndroidRoot() + "/bin/dexlayout";
EXPECT_TRUE(OS::FileExists(dexlayout.c_str())) << dexlayout << " should be a valid file path";
std::vector<std::string> dexlayout_exec_argv =
{ dexlayout, "-p", temp_profile.GetFilename(), "-o", "/dev/null", temp_dex.GetFilename() };
ASSERT_TRUE(DexLayoutExec(&temp_dex,
kUnalignedCodeInfoInputDex,
&temp_profile,
dexlayout_exec_argv));
}
TEST_F(DexLayoutTest, ClassDataBeforeCode) {
ScratchFile temp_dex;
ScratchFile temp_profile;
std::string dexlayout = GetTestAndroidRoot() + "/bin/dexlayout";
EXPECT_TRUE(OS::FileExists(dexlayout.c_str())) << dexlayout << " should be a valid file path";
std::vector<std::string> dexlayout_exec_argv =
{ dexlayout, "-p", temp_profile.GetFilename(), "-o", "/dev/null", temp_dex.GetFilename() };
ASSERT_TRUE(DexLayoutExec(&temp_dex,
kClassDataBeforeCodeInputDex,
&temp_profile,
dexlayout_exec_argv));
}
TEST_F(DexLayoutTest, UnknownTypeDebugInfo) {
ScratchFile temp_dex;
std::string dexlayout = GetTestAndroidRoot() + "/bin/dexlayout";
EXPECT_TRUE(OS::FileExists(dexlayout.c_str())) << dexlayout << " should be a valid file path";
std::vector<std::string> dexlayout_exec_argv =
{ dexlayout, "-o", "/dev/null", temp_dex.GetFilename() };
ASSERT_TRUE(DexLayoutExec(&temp_dex,
kUnknownTypeDebugInfoInputDex,
nullptr /* profile_file */,
dexlayout_exec_argv));
}
TEST_F(DexLayoutTest, DuplicateCodeItem) {
ScratchFile temp_dex;
std::string dexlayout = GetTestAndroidRoot() + "/bin/dexlayout";
EXPECT_TRUE(OS::FileExists(dexlayout.c_str())) << dexlayout << " should be a valid file path";
std::vector<std::string> dexlayout_exec_argv =
{ dexlayout, "-o", "/dev/null", temp_dex.GetFilename() };
ASSERT_TRUE(DexLayoutExec(&temp_dex,
kDuplicateCodeItemInputDex,
nullptr /* profile_file */,
dexlayout_exec_argv));
}
} // namespace art