// See the License for the specific language governing permissions and
// limitations under the License.
-art_cc_binary {
- name: "dexlayout",
+art_cc_defaults {
+ name: "libart-dexlayout-defaults",
host_supported: true,
srcs: [
- "dexlayout_main.cc",
"dexlayout.cc",
"dex_ir.cc",
"dex_ir_builder.cc",
"dex_visualize.cc",
"dex_writer.cc",
],
+ export_include_dirs: ["."],
+ shared_libs: ["libbase"],
+ static_libs: ["libz"],
+}
+
+art_cc_library {
+ name: "libart-dexlayout",
+ defaults: ["libart-dexlayout-defaults"],
+ shared_libs: ["libart"],
+}
+
+art_cc_library {
+ name: "libartd-dexlayout",
+ defaults: ["libart-dexlayout-defaults"],
+ shared_libs: ["libartd"],
+}
+
+art_cc_binary {
+ name: "dexlayout",
+ host_supported: true,
+ srcs: ["dexlayout_main.cc"],
cflags: ["-Wall"],
shared_libs: [
"libart",
- "libbase",
+ "libart-dexlayout",
],
}
art_cc_test {
name: "art_dexlayout_tests",
- defaults: [
- "art_gtest_defaults",
- ],
+ defaults: ["art_gtest_defaults"],
srcs: ["dexlayout_test.cc"],
}
entry.end_address_, entry.reg_)));
}
+static uint32_t GetCodeItemSize(const DexFile& dex_file, const DexFile::CodeItem& disk_code_item) {
+ uintptr_t code_item_start = reinterpret_cast<uintptr_t>(&disk_code_item);
+ uint32_t insns_size = disk_code_item.insns_size_in_code_units_;
+ uint32_t tries_size = disk_code_item.tries_size_;
+ if (tries_size == 0) {
+ uintptr_t insns_end = reinterpret_cast<uintptr_t>(&disk_code_item.insns_[insns_size]);
+ return insns_end - code_item_start;
+ } else {
+ uint32_t last_handler_off = 0;
+ for (uint32_t i = 0; i < tries_size; ++i) {
+ // Iterate over the try items to find the last catch handler.
+ const DexFile::TryItem* disk_try_item = dex_file.GetTryItems(disk_code_item, i);
+ uint16_t handler_off = disk_try_item->handler_off_;
+ if (handler_off > last_handler_off) {
+ last_handler_off = handler_off;
+ }
+ }
+ // Decode the final handler to see where it ends.
+ const uint8_t* handler_data = DexFile::GetCatchHandlerData(disk_code_item, last_handler_off);
+ int32_t uleb128_count = DecodeSignedLeb128(&handler_data) * 2;
+ if (uleb128_count <= 0) {
+ uleb128_count = -uleb128_count + 1;
+ }
+ for (int32_t i = 0; i < uleb128_count; ++i) {
+ DecodeUnsignedLeb128(&handler_data);
+ }
+ return reinterpret_cast<uintptr_t>(handler_data) - code_item_start;
+ }
+}
+
static uint32_t GetDebugInfoStreamSize(const uint8_t* debug_info_stream) {
const uint8_t* stream = debug_info_stream;
DecodeUnsignedLeb128(&stream); // line_start
if (dex_type_list == nullptr) {
return nullptr;
}
- // TODO: Create more efficient lookup for existing type lists.
- for (std::unique_ptr<TypeList>& type_list : TypeLists()) {
- if (type_list->GetOffset() == offset) {
- return type_list.get();
- }
+ auto found_type_list = TypeLists().find(offset);
+ if (found_type_list != TypeLists().end()) {
+ return found_type_list->second.get();
}
TypeIdVector* type_vector = new TypeIdVector();
uint32_t size = dex_type_list->Size();
if (static_data == nullptr) {
return nullptr;
}
- for (std::unique_ptr<EncodedArrayItem>& existing_array_item : EncodedArrayItems()) {
- if (existing_array_item->GetOffset() == offset) {
- return existing_array_item.get();
- }
+ 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();
AnnotationItem* Collections::CreateAnnotationItem(const DexFile::AnnotationItem* annotation,
uint32_t offset) {
- for (std::unique_ptr<AnnotationItem>& existing_annotation_item : AnnotationItems()) {
- if (existing_annotation_item->GetOffset() == offset) {
- return existing_annotation_item.get();
- }
+ 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_;
if (disk_annotations_item.size_ == 0 && offset == 0) {
return nullptr;
}
- for (std::unique_ptr<AnnotationSetItem>& existing_anno_set_item : AnnotationSetItems()) {
- if (existing_anno_set_item->GetOffset() == offset) {
- return existing_anno_set_item.get();
- }
+ 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) {
AnnotationsDirectoryItem* Collections::CreateAnnotationsDirectoryItem(const DexFile& dex_file,
const DexFile::AnnotationsDirectoryItem* disk_annotations_item, uint32_t offset) {
- for (std::unique_ptr<AnnotationsDirectoryItem>& anno_dir_item : AnnotationsDirectoryItems()) {
- if (anno_dir_item->GetOffset() == offset) {
- return anno_dir_item.get();
- }
+ 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);
const DexFile& dex_file, MethodId* method_id,
const DexFile::AnnotationSetRefList* annotation_set_ref_list, uint32_t offset) {
AnnotationSetRefList* set_ref_list = nullptr;
- for (std::unique_ptr<AnnotationSetRefList>& existing_set_ref_list : AnnotationSetRefLists()) {
- if (existing_set_ref_list->GetOffset() == offset) {
- set_ref_list = existing_set_ref_list.get();
- break;
- }
+ auto found_set_ref_list = AnnotationSetRefLists().find(offset);
+ if (found_set_ref_list != AnnotationSetRefLists().end()) {
+ set_ref_list = found_set_ref_list->second.get();
}
if (set_ref_list == nullptr) {
std::vector<AnnotationSetItem*>* annotations = new std::vector<AnnotationSetItem*>();
tries->push_back(std::unique_ptr<const TryItem>(try_item));
}
}
- // TODO: Calculate the size of the code item.
+ uint32_t size = GetCodeItemSize(dex_file, disk_code_item);
CodeItem* code_item = new CodeItem(
registers_size, ins_size, outs_size, debug_info, insns_size, insns, tries, handler_list);
+ code_item->SetSize(size);
code_items_.AddItem(code_item, offset);
// Add "fixup" references to types, strings, methods, and fields.
// This is temporary, as we will probably want more detailed parsing of the
virtual_methods->push_back(
std::unique_ptr<MethodItem>(GenerateMethodItem(dex_file, cdii)));
}
- // TODO: Calculate the size of the class data.
class_data = new ClassData(static_fields, instance_fields, direct_methods, virtual_methods);
+ class_data->SetSize(cdii.EndDataPointer() - encoded_data);
class_datas_.AddItem(class_data, offset);
}
return class_data;
#ifndef ART_DEXLAYOUT_DEX_IR_H_
#define ART_DEXLAYOUT_DEX_IR_H_
+#include <map>
#include <vector>
#include <stdint.h>
};
// Collections become owners of the objects added by moving them into unique pointers.
-template<class T> class CollectionWithOffset {
+template<class T> class CollectionBase {
public:
- CollectionWithOffset() = default;
- std::vector<std::unique_ptr<T>>& Collection() { return collection_; }
- // Read-time support methods
- void AddItem(T* object, uint32_t offset) {
- object->SetOffset(offset);
- collection_.push_back(std::unique_ptr<T>(object));
- }
+ CollectionBase() = default;
+
+ uint32_t GetOffset() const { return offset_; }
+ void SetOffset(uint32_t new_offset) { offset_ = new_offset; }
+
+ private:
+ uint32_t offset_ = 0;
+
+ DISALLOW_COPY_AND_ASSIGN(CollectionBase);
+};
+
+template<class T> class CollectionVector : public CollectionBase<T> {
+ public:
+ CollectionVector() = default;
+
void AddIndexedItem(T* object, uint32_t offset, uint32_t index) {
object->SetOffset(offset);
object->SetIndex(index);
collection_.push_back(std::unique_ptr<T>(object));
}
- // Ordinary object insertion into collection.
- void Insert(T object ATTRIBUTE_UNUSED) {
- // TODO(sehr): add ordered insertion support.
- UNIMPLEMENTED(FATAL) << "Insertion not ready";
- }
- uint32_t GetOffset() const { return offset_; }
- void SetOffset(uint32_t new_offset) { offset_ = new_offset; }
uint32_t Size() const { return collection_.size(); }
+ std::vector<std::unique_ptr<T>>& Collection() { return collection_; }
private:
std::vector<std::unique_ptr<T>> collection_;
- uint32_t offset_ = 0;
- DISALLOW_COPY_AND_ASSIGN(CollectionWithOffset);
+ DISALLOW_COPY_AND_ASSIGN(CollectionVector);
+};
+
+template<class T> class CollectionMap : public CollectionBase<T> {
+ public:
+ CollectionMap() = default;
+
+ void AddItem(T* object, uint32_t offset) {
+ object->SetOffset(offset);
+ collection_.emplace(offset, std::unique_ptr<T>(object));
+ }
+ uint32_t Size() const { return collection_.size(); }
+ std::map<uint32_t, std::unique_ptr<T>>& Collection() { return collection_; }
+
+ private:
+ std::map<uint32_t, std::unique_ptr<T>> collection_;
+
+ DISALLOW_COPY_AND_ASSIGN(CollectionMap);
};
class Collections {
std::vector<std::unique_ptr<FieldId>>& FieldIds() { return field_ids_.Collection(); }
std::vector<std::unique_ptr<MethodId>>& MethodIds() { return method_ids_.Collection(); }
std::vector<std::unique_ptr<ClassDef>>& ClassDefs() { return class_defs_.Collection(); }
- std::vector<std::unique_ptr<StringData>>& StringDatas() { return string_datas_.Collection(); }
- std::vector<std::unique_ptr<TypeList>>& TypeLists() { return type_lists_.Collection(); }
- std::vector<std::unique_ptr<EncodedArrayItem>>& EncodedArrayItems()
+ std::map<uint32_t, std::unique_ptr<StringData>>& StringDatas()
+ { return string_datas_.Collection(); }
+ std::map<uint32_t, std::unique_ptr<TypeList>>& TypeLists() { return type_lists_.Collection(); }
+ std::map<uint32_t, std::unique_ptr<EncodedArrayItem>>& EncodedArrayItems()
{ return encoded_array_items_.Collection(); }
- std::vector<std::unique_ptr<AnnotationItem>>& AnnotationItems()
+ std::map<uint32_t, std::unique_ptr<AnnotationItem>>& AnnotationItems()
{ return annotation_items_.Collection(); }
- std::vector<std::unique_ptr<AnnotationSetItem>>& AnnotationSetItems()
+ std::map<uint32_t, std::unique_ptr<AnnotationSetItem>>& AnnotationSetItems()
{ return annotation_set_items_.Collection(); }
- std::vector<std::unique_ptr<AnnotationSetRefList>>& AnnotationSetRefLists()
+ std::map<uint32_t, std::unique_ptr<AnnotationSetRefList>>& AnnotationSetRefLists()
{ return annotation_set_ref_lists_.Collection(); }
- std::vector<std::unique_ptr<AnnotationsDirectoryItem>>& AnnotationsDirectoryItems()
+ std::map<uint32_t, std::unique_ptr<AnnotationsDirectoryItem>>& AnnotationsDirectoryItems()
{ return annotations_directory_items_.Collection(); }
- std::vector<std::unique_ptr<DebugInfoItem>>& DebugInfoItems()
+ std::map<uint32_t, std::unique_ptr<DebugInfoItem>>& DebugInfoItems()
{ return debug_info_items_.Collection(); }
- std::vector<std::unique_ptr<CodeItem>>& CodeItems() { return code_items_.Collection(); }
- std::vector<std::unique_ptr<ClassData>>& ClassDatas() { return class_datas_.Collection(); }
+ std::map<uint32_t, std::unique_ptr<CodeItem>>& CodeItems() { return code_items_.Collection(); }
+ std::map<uint32_t, std::unique_ptr<ClassData>>& ClassDatas() { return class_datas_.Collection(); }
void CreateStringId(const DexFile& dex_file, uint32_t i);
void CreateTypeId(const DexFile& dex_file, uint32_t i);
uint32_t DebugInfoItemsOffset() const { return debug_info_items_.GetOffset(); }
uint32_t CodeItemsOffset() const { return code_items_.GetOffset(); }
uint32_t ClassDatasOffset() const { return class_datas_.GetOffset(); }
- uint32_t MapItemOffset() const { return map_item_offset_; }
+ uint32_t MapListOffset() const { return map_list_offset_; }
void SetStringIdsOffset(uint32_t new_offset) { string_ids_.SetOffset(new_offset); }
void SetTypeIdsOffset(uint32_t new_offset) { type_ids_.SetOffset(new_offset); }
void SetDebugInfoItemsOffset(uint32_t new_offset) { debug_info_items_.SetOffset(new_offset); }
void SetCodeItemsOffset(uint32_t new_offset) { code_items_.SetOffset(new_offset); }
void SetClassDatasOffset(uint32_t new_offset) { class_datas_.SetOffset(new_offset); }
- void SetMapItemOffset(uint32_t new_offset) { map_item_offset_ = new_offset; }
+ void SetMapListOffset(uint32_t new_offset) { map_list_offset_ = new_offset; }
uint32_t StringIdsSize() const { return string_ids_.Size(); }
uint32_t TypeIdsSize() const { return type_ids_.Size(); }
const DexFile::AnnotationSetRefList* annotation_set_ref_list, uint32_t offset);
MethodItem* GenerateMethodItem(const DexFile& dex_file, ClassDataItemIterator& cdii);
- CollectionWithOffset<StringId> string_ids_;
- CollectionWithOffset<TypeId> type_ids_;
- CollectionWithOffset<ProtoId> proto_ids_;
- CollectionWithOffset<FieldId> field_ids_;
- CollectionWithOffset<MethodId> method_ids_;
- CollectionWithOffset<ClassDef> class_defs_;
-
- CollectionWithOffset<StringData> string_datas_;
- CollectionWithOffset<TypeList> type_lists_;
- CollectionWithOffset<EncodedArrayItem> encoded_array_items_;
- CollectionWithOffset<AnnotationItem> annotation_items_;
- CollectionWithOffset<AnnotationSetItem> annotation_set_items_;
- CollectionWithOffset<AnnotationSetRefList> annotation_set_ref_lists_;
- CollectionWithOffset<AnnotationsDirectoryItem> annotations_directory_items_;
- CollectionWithOffset<DebugInfoItem> debug_info_items_;
- CollectionWithOffset<CodeItem> code_items_;
- CollectionWithOffset<ClassData> class_datas_;
-
- uint32_t map_item_offset_ = 0;
+ CollectionVector<StringId> string_ids_;
+ CollectionVector<TypeId> type_ids_;
+ CollectionVector<ProtoId> proto_ids_;
+ CollectionVector<FieldId> field_ids_;
+ CollectionVector<MethodId> method_ids_;
+ CollectionVector<ClassDef> class_defs_;
+
+ CollectionMap<StringData> string_datas_;
+ CollectionMap<TypeList> type_lists_;
+ CollectionMap<EncodedArrayItem> encoded_array_items_;
+ CollectionMap<AnnotationItem> annotation_items_;
+ CollectionMap<AnnotationSetItem> annotation_set_items_;
+ CollectionMap<AnnotationSetRefList> annotation_set_ref_lists_;
+ CollectionMap<AnnotationsDirectoryItem> annotations_directory_items_;
+ CollectionMap<DebugInfoItem> debug_info_items_;
+ CollectionMap<CodeItem> code_items_;
+ CollectionMap<ClassData> class_datas_;
+
+ uint32_t map_list_offset_ = 0;
DISALLOW_COPY_AND_ASSIGN(Collections);
};
class MethodItem : public Item {
public:
- MethodItem(uint32_t access_flags, const MethodId* method_id, const CodeItem* code)
+ MethodItem(uint32_t access_flags, const MethodId* method_id, CodeItem* code)
: access_flags_(access_flags), method_id_(method_id), code_(code) { }
~MethodItem() OVERRIDE { }
uint32_t GetAccessFlags() const { return access_flags_; }
const MethodId* GetMethodId() const { return method_id_; }
- const CodeItem* GetCodeItem() const { return code_; }
+ CodeItem* GetCodeItem() { return code_; }
void Accept(AbstractDispatcher* dispatch) { dispatch->Dispatch(this); }
private:
uint32_t access_flags_;
const MethodId* method_id_;
- const CodeItem* code_; // This can be nullptr.
+ CodeItem* code_; // This can be nullptr.
DISALLOW_COPY_AND_ASSIGN(MethodItem);
};
collections.CreateClassDef(dex_file, i);
}
// MapItem.
- collections.SetMapItemOffset(disk_header.map_off_);
+ collections.SetMapListOffset(disk_header.map_off_);
CheckAndSetRemainingOffsets(dex_file, &collections);
DumpStringId(method_id->Name(), class_index);
}
- void DumpMethodItem(const dex_ir::MethodItem* method, const DexFile* dex_file, int class_index) {
- if (profile_info_ != nullptr) {
+ void DumpMethodItem(dex_ir::MethodItem* method,
+ const DexFile* dex_file,
+ int class_index,
+ ProfileCompilationInfo* profile_info) {
+ if (profile_info != nullptr) {
uint32_t method_idx = method->GetMethodId()->GetIndex();
- MethodReference mr(dex_file, method_idx);
- if (!profile_info_->ContainsMethod(mr)) {
+ if (!profile_info->ContainsMethod(MethodReference(dex_file, method_idx))) {
return;
}
}
* Dumps a gnuplot data file showing the parts of the dex_file that belong to each class.
* If profiling information is present, it dumps only those classes that are marked as hot.
*/
-void VisualizeDexLayout(dex_ir::Header* header, const DexFile* dex_file, size_t dex_file_index) {
+void VisualizeDexLayout(dex_ir::Header* header,
+ const DexFile* dex_file,
+ size_t dex_file_index,
+ ProfileCompilationInfo* profile_info) {
std::unique_ptr<Dumper> dumper(new Dumper(header->GetCollections(), dex_file_index));
const uint32_t class_defs_size = header->GetCollections().ClassDefsSize();
for (uint32_t class_index = 0; class_index < class_defs_size; class_index++) {
dex_ir::ClassDef* class_def = header->GetCollections().GetClassDef(class_index);
dex::TypeIndex type_idx(class_def->ClassType()->GetIndex());
- if (profile_info_ != nullptr && !profile_info_->ContainsClass(*dex_file, type_idx)) {
+ if (profile_info != nullptr && !profile_info->ContainsClass(*dex_file, type_idx)) {
continue;
}
dumper->DumpAddressRange(class_def, class_index);
}
if (class_data->DirectMethods()) {
for (auto& method_item : *class_data->DirectMethods()) {
- dumper->DumpMethodItem(method_item.get(), dex_file, class_index);
+ dumper->DumpMethodItem(method_item.get(), dex_file, class_index, profile_info);
}
}
if (class_data->VirtualMethods()) {
for (auto& method_item : *class_data->VirtualMethods()) {
- dumper->DumpMethodItem(method_item.get(), dex_file, class_index);
+ dumper->DumpMethodItem(method_item.get(), dex_file, class_index, profile_info);
}
}
}
namespace art {
class DexFile;
+class ProfileCompilationInfo;
namespace dex_ir {
class Header;
} // namespace dex_ir
-void VisualizeDexLayout(dex_ir::Header* header, const DexFile* dex_file, size_t dex_file_index);
+void VisualizeDexLayout(dex_ir::Header* header,
+ const DexFile* dex_file,
+ size_t dex_file_index,
+ ProfileCompilationInfo* profile_info);
} // namespace art
}
size_t DexWriter::Write(const void* buffer, size_t length, size_t offset) {
- return dex_file_->PwriteFully(buffer, length, offset) ? length : 0;
+ DCHECK_LE(offset + length, mem_map_->Size());
+ memcpy(mem_map_->Begin() + offset, buffer, length);
+ return length;
}
size_t DexWriter::WriteSleb128(uint32_t value, size_t offset) {
void DexWriter::WriteStrings() {
uint32_t string_data_off[1];
- for (std::unique_ptr<dex_ir::StringId>& string_id : header_.GetCollections().StringIds()) {
+ for (std::unique_ptr<dex_ir::StringId>& string_id : header_->GetCollections().StringIds()) {
string_data_off[0] = string_id->DataItem()->GetOffset();
Write(string_data_off, string_id->GetSize(), string_id->GetOffset());
}
- for (std::unique_ptr<dex_ir::StringData>& string_data : header_.GetCollections().StringDatas()) {
+ 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()) {
+ for (std::unique_ptr<dex_ir::TypeId>& type_id : header_->GetCollections().TypeIds()) {
descriptor_idx[0] = type_id->GetStringId()->GetIndex();
Write(descriptor_idx, type_id->GetSize(), type_id->GetOffset());
}
void DexWriter::WriteTypeLists() {
uint32_t size[1];
uint16_t list[1];
- for (std::unique_ptr<dex_ir::TypeList>& type_list : header_.GetCollections().TypeLists()) {
+ 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);
void DexWriter::WriteProtos() {
uint32_t buffer[3];
- for (std::unique_ptr<dex_ir::ProtoId>& proto_id : header_.GetCollections().ProtoIds()) {
+ 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();
void DexWriter::WriteFields() {
uint16_t buffer[4];
- for (std::unique_ptr<dex_ir::FieldId>& field_id : header_.GetCollections().FieldIds()) {
+ 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();
void DexWriter::WriteMethods() {
uint16_t buffer[4];
- for (std::unique_ptr<dex_ir::MethodId>& method_id : header_.GetCollections().MethodIds()) {
+ 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();
}
void DexWriter::WriteEncodedArrays() {
- for (std::unique_ptr<dex_ir::EncodedArrayItem>& encoded_array :
- header_.GetCollections().EncodedArrayItems()) {
+ 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 (std::unique_ptr<dex_ir::AnnotationItem>& annotation :
- header_.GetCollections().AnnotationItems()) {
+ 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);
void DexWriter::WriteAnnotationSets() {
uint32_t size[1];
uint32_t annotation_off[1];
- for (std::unique_ptr<dex_ir::AnnotationSetItem>& annotation_set :
- header_.GetCollections().AnnotationSetItems()) {
+ 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);
void DexWriter::WriteAnnotationSetRefs() {
uint32_t size[1];
uint32_t annotations_off[1];
- for (std::unique_ptr<dex_ir::AnnotationSetRefList>& annotation_set_ref :
- header_.GetCollections().AnnotationSetRefLists()) {
+ 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);
void DexWriter::WriteAnnotationsDirectories() {
uint32_t directory_buffer[4];
uint32_t annotation_buffer[2];
- for (std::unique_ptr<dex_ir::AnnotationsDirectoryItem>& annotations_directory :
- header_.GetCollections().AnnotationsDirectoryItems()) {
+ 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 :
}
void DexWriter::WriteDebugInfoItems() {
- for (std::unique_ptr<dex_ir::DebugInfoItem>& info : header_.GetCollections().DebugInfoItems()) {
- Write(info->GetDebugInfo(), info->GetDebugInfoSize(), info->GetOffset());
+ 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 (std::unique_ptr<dex_ir::CodeItem>& code_item : header_.GetCollections().CodeItems()) {
+ 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();
void DexWriter::WriteClasses() {
uint32_t class_def_buffer[8];
- for (std::unique_ptr<dex_ir::ClassDef>& class_def : header_.GetCollections().ClassDefs()) {
+ 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 :
Write(class_def_buffer, class_def->GetSize(), offset);
}
- for (std::unique_ptr<dex_ir::ClassData>& class_data : header_.GetCollections().ClassDatas()) {
+ 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);
};
void DexWriter::WriteMapItem() {
- dex_ir::Collections& collection = header_.GetCollections();
+ dex_ir::Collections& collection = header_->GetCollections();
std::priority_queue<MapItemContainer> queue;
// Header and index section.
}
// Data section.
- queue.push(MapItemContainer(DexFile::kDexTypeMapList, 1, collection.MapItemOffset()));
+ queue.push(MapItemContainer(DexFile::kDexTypeMapList, 1, collection.MapListOffset()));
if (collection.TypeListsSize() != 0) {
queue.push(MapItemContainer(DexFile::kDexTypeTypeList, collection.TypeListsSize(),
collection.TypeListsOffset()));
collection.AnnotationsDirectoryItemsSize(), collection.AnnotationsDirectoryItemsOffset()));
}
- uint32_t offset = collection.MapItemOffset();
+ uint32_t offset = collection.MapListOffset();
uint16_t uint16_buffer[2];
uint32_t uint32_buffer[2];
uint16_buffer[1] = 0;
void DexWriter::WriteHeader() {
uint32_t buffer[20];
- dex_ir::Collections& collections = header_.GetCollections();
+ dex_ir::Collections& collections = header_->GetCollections();
size_t offset = 0;
- offset += Write(header_.Magic(), 8 * sizeof(uint8_t), offset);
- buffer[0] = header_.Checksum();
+ offset += Write(header_->Magic(), 8 * sizeof(uint8_t), offset);
+ buffer[0] = header_->Checksum();
offset += Write(buffer, sizeof(uint32_t), offset);
- offset += Write(header_.Signature(), 20 * sizeof(uint8_t), offset);
- uint32_t file_size = header_.FileSize();
+ offset += Write(header_->Signature(), 20 * sizeof(uint8_t), offset);
+ uint32_t file_size = header_->FileSize();
buffer[0] = file_size;
- buffer[1] = header_.GetSize();
- buffer[2] = header_.EndianTag();
- buffer[3] = header_.LinkSize();
- buffer[4] = header_.LinkOffset();
- buffer[5] = collections.MapItemOffset();
+ buffer[1] = header_->GetSize();
+ buffer[2] = header_->EndianTag();
+ buffer[3] = header_->LinkSize();
+ buffer[4] = header_->LinkOffset();
+ buffer[5] = collections.MapListOffset();
buffer[6] = collections.StringIdsSize();
buffer[7] = collections.StringIdsOffset();
buffer[8] = collections.TypeIdsSize();
Write(buffer, 20 * sizeof(uint32_t), offset);
}
-void DexWriter::WriteFile() {
- if (dex_file_.get() == nullptr) {
- fprintf(stderr, "Can't open output dex file\n");
- return;
- }
-
+void DexWriter::WriteMemMap() {
WriteStrings();
WriteTypes();
WriteTypeLists();
WriteHeader();
}
-void DexWriter::OutputDexFile(dex_ir::Header& header, const char* file_name) {
- (new DexWriter(header, file_name))->WriteFile();
+void DexWriter::Output(dex_ir::Header* header, MemMap* mem_map) {
+ DexWriter dex_writer(header, mem_map);
+ dex_writer.WriteMemMap();
}
} // namespace art
#include "base/unix_file/fd_file.h"
#include "dex_ir.h"
+#include "mem_map.h"
#include "os.h"
namespace art {
class DexWriter {
public:
- DexWriter(dex_ir::Header& header, const char* file_name) : header_(header),
- dex_file_(OS::CreateEmptyFileWriteOnly(file_name)) { }
+ DexWriter(dex_ir::Header* header, MemMap* mem_map) : header_(header), mem_map_(mem_map) { }
- static void OutputDexFile(dex_ir::Header& header, const char* file_name);
+ static void Output(dex_ir::Header* header, MemMap* mem_map);
private:
- void WriteFile();
+ void WriteMemMap();
size_t Write(const void* buffer, size_t length, size_t offset);
size_t WriteSleb128(uint32_t value, size_t offset);
void WriteMapItem();
void WriteHeader();
- dex_ir::Header& header_;
- std::unique_ptr<File> dex_file_;
+ dex_ir::Header* const header_;
+ MemMap* const mem_map_;
DISALLOW_COPY_AND_ASSIGN(DexWriter);
};
-
} // namespace art
#endif // ART_DEXLAYOUT_DEX_WRITER_H_
#include "dex_visualize.h"
#include "dex_writer.h"
#include "jit/offline_profiling_info.h"
+#include "mem_map.h"
#include "os.h"
#include "utils.h"
namespace art {
/*
- * Options parsed in main driver.
- */
-struct Options options_;
-
-/*
- * Output file. Defaults to stdout.
- */
-FILE* out_file_ = stdout;
-
-/*
- * Profile information file.
- */
-ProfileCompilationInfo* profile_info_ = nullptr;
-
-/*
* Flags for use with createAccessFlagStr().
*/
enum AccessFor {
/*
* Dumps a string value with some escape characters.
*/
-static void DumpEscapedString(const char* p) {
- fputs("\"", out_file_);
+static void DumpEscapedString(const char* p, FILE* out_file) {
+ fputs("\"", out_file);
for (; *p; p++) {
switch (*p) {
case '\\':
- fputs("\\\\", out_file_);
+ fputs("\\\\", out_file);
break;
case '\"':
- fputs("\\\"", out_file_);
+ fputs("\\\"", out_file);
break;
case '\t':
- fputs("\\t", out_file_);
+ fputs("\\t", out_file);
break;
case '\n':
- fputs("\\n", out_file_);
+ fputs("\\n", out_file);
break;
case '\r':
- fputs("\\r", out_file_);
+ fputs("\\r", out_file);
break;
default:
- putc(*p, out_file_);
+ putc(*p, out_file);
} // switch
} // for
- fputs("\"", out_file_);
+ fputs("\"", out_file);
}
/*
* Dumps a string as an XML attribute value.
*/
-static void DumpXmlAttribute(const char* p) {
+static void DumpXmlAttribute(const char* p, FILE* out_file) {
for (; *p; p++) {
switch (*p) {
case '&':
- fputs("&", out_file_);
+ fputs("&", out_file);
break;
case '<':
- fputs("<", out_file_);
+ fputs("<", out_file);
break;
case '>':
- fputs(">", out_file_);
+ fputs(">", out_file);
break;
case '"':
- fputs(""", out_file_);
+ fputs(""", out_file);
break;
case '\t':
- fputs("	", out_file_);
+ fputs("	", out_file);
break;
case '\n':
- fputs("
", out_file_);
+ fputs("
", out_file);
break;
case '\r':
- fputs("
", out_file_);
+ fputs("
", out_file);
break;
default:
- putc(*p, out_file_);
+ putc(*p, out_file);
} // switch
} // for
}
-// Forward declare to resolve circular dependence.
-static void DumpEncodedValue(const dex_ir::EncodedValue* data);
+/*
+ * Helper for dumpInstruction(), which builds the string
+ * representation for the index in the given instruction.
+ * Returns a pointer to a buffer of sufficient size.
+ */
+static std::unique_ptr<char[]> IndexString(dex_ir::Header* header,
+ const Instruction* dec_insn,
+ size_t buf_size) {
+ std::unique_ptr<char[]> buf(new char[buf_size]);
+ // Determine index and width of the string.
+ uint32_t index = 0;
+ uint32_t secondary_index = DexFile::kDexNoIndex;
+ uint32_t width = 4;
+ switch (Instruction::FormatOf(dec_insn->Opcode())) {
+ // SOME NOT SUPPORTED:
+ // case Instruction::k20bc:
+ case Instruction::k21c:
+ case Instruction::k35c:
+ // case Instruction::k35ms:
+ case Instruction::k3rc:
+ // case Instruction::k3rms:
+ // case Instruction::k35mi:
+ // case Instruction::k3rmi:
+ index = dec_insn->VRegB();
+ width = 4;
+ break;
+ case Instruction::k31c:
+ index = dec_insn->VRegB();
+ width = 8;
+ break;
+ case Instruction::k22c:
+ // case Instruction::k22cs:
+ index = dec_insn->VRegC();
+ width = 4;
+ break;
+ case Instruction::k45cc:
+ case Instruction::k4rcc:
+ index = dec_insn->VRegB();
+ secondary_index = dec_insn->VRegH();
+ width = 4;
+ default:
+ break;
+ } // switch
+
+ // Determine index type.
+ size_t outSize = 0;
+ switch (Instruction::IndexTypeOf(dec_insn->Opcode())) {
+ case Instruction::kIndexUnknown:
+ // This function should never get called for this type, but do
+ // something sensible here, just to help with debugging.
+ outSize = snprintf(buf.get(), buf_size, "<unknown-index>");
+ break;
+ case Instruction::kIndexNone:
+ // This function should never get called for this type, but do
+ // something sensible here, just to help with debugging.
+ outSize = snprintf(buf.get(), buf_size, "<no-index>");
+ break;
+ case Instruction::kIndexTypeRef:
+ if (index < header->GetCollections().TypeIdsSize()) {
+ const char* tp = header->GetCollections().GetTypeId(index)->GetStringId()->Data();
+ outSize = snprintf(buf.get(), buf_size, "%s // type@%0*x", tp, width, index);
+ } else {
+ outSize = snprintf(buf.get(), buf_size, "<type?> // type@%0*x", width, index);
+ }
+ break;
+ case Instruction::kIndexStringRef:
+ if (index < header->GetCollections().StringIdsSize()) {
+ const char* st = header->GetCollections().GetStringId(index)->Data();
+ outSize = snprintf(buf.get(), buf_size, "\"%s\" // string@%0*x", st, width, index);
+ } else {
+ outSize = snprintf(buf.get(), buf_size, "<string?> // string@%0*x", width, index);
+ }
+ break;
+ case Instruction::kIndexMethodRef:
+ if (index < header->GetCollections().MethodIdsSize()) {
+ dex_ir::MethodId* method_id = header->GetCollections().GetMethodId(index);
+ const char* name = method_id->Name()->Data();
+ std::string type_descriptor = GetSignatureForProtoId(method_id->Proto());
+ const char* back_descriptor = method_id->Class()->GetStringId()->Data();
+ outSize = snprintf(buf.get(), buf_size, "%s.%s:%s // method@%0*x",
+ back_descriptor, name, type_descriptor.c_str(), width, index);
+ } else {
+ outSize = snprintf(buf.get(), buf_size, "<method?> // method@%0*x", width, index);
+ }
+ break;
+ case Instruction::kIndexFieldRef:
+ if (index < header->GetCollections().FieldIdsSize()) {
+ dex_ir::FieldId* field_id = header->GetCollections().GetFieldId(index);
+ const char* name = field_id->Name()->Data();
+ const char* type_descriptor = field_id->Type()->GetStringId()->Data();
+ const char* back_descriptor = field_id->Class()->GetStringId()->Data();
+ outSize = snprintf(buf.get(), buf_size, "%s.%s:%s // field@%0*x",
+ back_descriptor, name, type_descriptor, width, index);
+ } else {
+ outSize = snprintf(buf.get(), buf_size, "<field?> // field@%0*x", width, index);
+ }
+ break;
+ case Instruction::kIndexVtableOffset:
+ outSize = snprintf(buf.get(), buf_size, "[%0*x] // vtable #%0*x",
+ width, index, width, index);
+ break;
+ case Instruction::kIndexFieldOffset:
+ outSize = snprintf(buf.get(), buf_size, "[obj+%0*x]", width, index);
+ break;
+ case Instruction::kIndexMethodAndProtoRef: {
+ std::string method("<method?>");
+ std::string proto("<proto?>");
+ if (index < header->GetCollections().MethodIdsSize()) {
+ dex_ir::MethodId* method_id = header->GetCollections().GetMethodId(index);
+ const char* name = method_id->Name()->Data();
+ std::string type_descriptor = GetSignatureForProtoId(method_id->Proto());
+ const char* back_descriptor = method_id->Class()->GetStringId()->Data();
+ method = StringPrintf("%s.%s:%s", back_descriptor, name, type_descriptor.c_str());
+ }
+ if (secondary_index < header->GetCollections().ProtoIdsSize()) {
+ dex_ir::ProtoId* proto_id = header->GetCollections().GetProtoId(secondary_index);
+ proto = GetSignatureForProtoId(proto_id);
+ }
+ outSize = snprintf(buf.get(), buf_size, "%s, %s // method@%0*x, proto@%0*x",
+ method.c_str(), proto.c_str(), width, index, width, secondary_index);
+ }
+ break;
+ // SOME NOT SUPPORTED:
+ // case Instruction::kIndexVaries:
+ // case Instruction::kIndexInlineMethod:
+ default:
+ outSize = snprintf(buf.get(), buf_size, "<?>");
+ break;
+ } // switch
+
+ // Determine success of string construction.
+ if (outSize >= buf_size) {
+ // The buffer wasn't big enough; retry with computed size. Note: snprintf()
+ // doesn't count/ the '\0' as part of its returned size, so we add explicit
+ // space for it here.
+ return IndexString(header, dec_insn, outSize + 1);
+ }
+ return buf;
+}
/*
* Dumps encoded annotation.
*/
-static void DumpEncodedAnnotation(dex_ir::EncodedAnnotation* annotation) {
+void DexLayout::DumpEncodedAnnotation(dex_ir::EncodedAnnotation* annotation) {
fputs(annotation->GetType()->GetStringId()->Data(), out_file_);
// Display all name=value pairs.
for (auto& subannotation : *annotation->GetAnnotationElements()) {
/*
* Dumps encoded value.
*/
-static void DumpEncodedValue(const dex_ir::EncodedValue* data) {
+void DexLayout::DumpEncodedValue(const dex_ir::EncodedValue* data) {
switch (data->Type()) {
case DexFile::kDexAnnotationByte:
fprintf(out_file_, "%" PRId8, data->GetByte());
case DexFile::kDexAnnotationString: {
dex_ir::StringId* string_id = data->GetStringId();
if (options_.output_format_ == kOutputPlain) {
- DumpEscapedString(string_id->Data());
+ DumpEscapedString(string_id->Data(), out_file_);
} else {
- DumpXmlAttribute(string_id->Data());
+ DumpXmlAttribute(string_id->Data(), out_file_);
}
break;
}
/*
* Dumps the file header.
*/
-static void DumpFileHeader(dex_ir::Header* header) {
+void DexLayout::DumpFileHeader() {
char sanitized[8 * 2 + 1];
- dex_ir::Collections& collections = header->GetCollections();
+ dex_ir::Collections& collections = header_->GetCollections();
fprintf(out_file_, "DEX file header:\n");
- Asciify(sanitized, header->Magic(), 8);
+ Asciify(sanitized, header_->Magic(), 8);
fprintf(out_file_, "magic : '%s'\n", sanitized);
- fprintf(out_file_, "checksum : %08x\n", header->Checksum());
+ fprintf(out_file_, "checksum : %08x\n", header_->Checksum());
fprintf(out_file_, "signature : %02x%02x...%02x%02x\n",
- header->Signature()[0], header->Signature()[1],
- header->Signature()[DexFile::kSha1DigestSize - 2],
- header->Signature()[DexFile::kSha1DigestSize - 1]);
- fprintf(out_file_, "file_size : %d\n", header->FileSize());
- fprintf(out_file_, "header_size : %d\n", header->HeaderSize());
- fprintf(out_file_, "link_size : %d\n", header->LinkSize());
+ header_->Signature()[0], header_->Signature()[1],
+ header_->Signature()[DexFile::kSha1DigestSize - 2],
+ header_->Signature()[DexFile::kSha1DigestSize - 1]);
+ fprintf(out_file_, "file_size : %d\n", header_->FileSize());
+ fprintf(out_file_, "header_size : %d\n", header_->HeaderSize());
+ fprintf(out_file_, "link_size : %d\n", header_->LinkSize());
fprintf(out_file_, "link_off : %d (0x%06x)\n",
- header->LinkOffset(), header->LinkOffset());
+ header_->LinkOffset(), header_->LinkOffset());
fprintf(out_file_, "string_ids_size : %d\n", collections.StringIdsSize());
fprintf(out_file_, "string_ids_off : %d (0x%06x)\n",
collections.StringIdsOffset(), collections.StringIdsOffset());
fprintf(out_file_, "class_defs_size : %d\n", collections.ClassDefsSize());
fprintf(out_file_, "class_defs_off : %d (0x%06x)\n",
collections.ClassDefsOffset(), collections.ClassDefsOffset());
- fprintf(out_file_, "data_size : %d\n", header->DataSize());
+ fprintf(out_file_, "data_size : %d\n", header_->DataSize());
fprintf(out_file_, "data_off : %d (0x%06x)\n\n",
- header->DataOffset(), header->DataOffset());
+ header_->DataOffset(), header_->DataOffset());
}
/*
* Dumps a class_def_item.
*/
-static void DumpClassDef(dex_ir::Header* header, int idx) {
+void DexLayout::DumpClassDef(int idx) {
// General class information.
- dex_ir::ClassDef* class_def = header->GetCollections().GetClassDef(idx);
+ dex_ir::ClassDef* class_def = header_->GetCollections().GetClassDef(idx);
fprintf(out_file_, "Class #%d header:\n", idx);
fprintf(out_file_, "class_idx : %d\n", class_def->ClassType()->GetIndex());
fprintf(out_file_, "access_flags : %d (0x%04x)\n",
/**
* Dumps an annotation set item.
*/
-static void DumpAnnotationSetItem(dex_ir::AnnotationSetItem* set_item) {
+void DexLayout::DumpAnnotationSetItem(dex_ir::AnnotationSetItem* set_item) {
if (set_item == nullptr || set_item->GetItems()->size() == 0) {
fputs(" empty-annotation-set\n", out_file_);
return;
/*
* Dumps class annotations.
*/
-static void DumpClassAnnotations(dex_ir::Header* header, int idx) {
- dex_ir::ClassDef* class_def = header->GetCollections().GetClassDef(idx);
+void DexLayout::DumpClassAnnotations(int idx) {
+ dex_ir::ClassDef* class_def = header_->GetCollections().GetClassDef(idx);
dex_ir::AnnotationsDirectoryItem* annotations_directory = class_def->Annotations();
if (annotations_directory == nullptr) {
return; // none
/*
* Dumps an interface that a class declares to implement.
*/
-static void DumpInterface(const dex_ir::TypeId* type_item, int i) {
+void DexLayout::DumpInterface(const dex_ir::TypeId* type_item, int i) {
const char* interface_name = type_item->GetStringId()->Data();
if (options_.output_format_ == kOutputPlain) {
fprintf(out_file_, " #%d : '%s'\n", i, interface_name);
/*
* Dumps the catches table associated with the code.
*/
-static void DumpCatches(const dex_ir::CodeItem* code) {
+void DexLayout::DumpCatches(const dex_ir::CodeItem* code) {
const uint16_t tries_size = code->TriesSize();
// No catch table.
/*
* Dumps all positions table entries associated with the code.
*/
-static void DumpPositionInfo(const dex_ir::CodeItem* code) {
+void DexLayout::DumpPositionInfo(const dex_ir::CodeItem* code) {
dex_ir::DebugInfoItem* debug_info = code->DebugInfo();
if (debug_info == nullptr) {
return;
/*
* Dumps all locals table entries associated with the code.
*/
-static void DumpLocalInfo(const dex_ir::CodeItem* code) {
+void DexLayout::DumpLocalInfo(const dex_ir::CodeItem* code) {
dex_ir::DebugInfoItem* debug_info = code->DebugInfo();
if (debug_info == nullptr) {
return;
}
/*
- * Helper for dumpInstruction(), which builds the string
- * representation for the index in the given instruction.
- * Returns a pointer to a buffer of sufficient size.
- */
-static std::unique_ptr<char[]> IndexString(dex_ir::Header* header,
- const Instruction* dec_insn,
- size_t buf_size) {
- static const uint32_t kInvalidIndex = std::numeric_limits<uint32_t>::max();
- std::unique_ptr<char[]> buf(new char[buf_size]);
- // Determine index and width of the string.
- uint32_t index = 0;
- uint32_t secondary_index = kInvalidIndex;
- uint32_t width = 4;
- switch (Instruction::FormatOf(dec_insn->Opcode())) {
- // SOME NOT SUPPORTED:
- // case Instruction::k20bc:
- case Instruction::k21c:
- case Instruction::k35c:
- // case Instruction::k35ms:
- case Instruction::k3rc:
- // case Instruction::k3rms:
- // case Instruction::k35mi:
- // case Instruction::k3rmi:
- index = dec_insn->VRegB();
- width = 4;
- break;
- case Instruction::k31c:
- index = dec_insn->VRegB();
- width = 8;
- break;
- case Instruction::k22c:
- // case Instruction::k22cs:
- index = dec_insn->VRegC();
- width = 4;
- break;
- case Instruction::k45cc:
- case Instruction::k4rcc:
- index = dec_insn->VRegB();
- secondary_index = dec_insn->VRegH();
- width = 4;
- break;
- default:
- break;
- } // switch
-
- // Determine index type.
- size_t outSize = 0;
- switch (Instruction::IndexTypeOf(dec_insn->Opcode())) {
- case Instruction::kIndexUnknown:
- // This function should never get called for this type, but do
- // something sensible here, just to help with debugging.
- outSize = snprintf(buf.get(), buf_size, "<unknown-index>");
- break;
- case Instruction::kIndexNone:
- // This function should never get called for this type, but do
- // something sensible here, just to help with debugging.
- outSize = snprintf(buf.get(), buf_size, "<no-index>");
- break;
- case Instruction::kIndexTypeRef:
- if (index < header->GetCollections().TypeIdsSize()) {
- const char* tp = header->GetCollections().GetTypeId(index)->GetStringId()->Data();
- outSize = snprintf(buf.get(), buf_size, "%s // type@%0*x", tp, width, index);
- } else {
- outSize = snprintf(buf.get(), buf_size, "<type?> // type@%0*x", width, index);
- }
- break;
- case Instruction::kIndexStringRef:
- if (index < header->GetCollections().StringIdsSize()) {
- const char* st = header->GetCollections().GetStringId(index)->Data();
- outSize = snprintf(buf.get(), buf_size, "\"%s\" // string@%0*x", st, width, index);
- } else {
- outSize = snprintf(buf.get(), buf_size, "<string?> // string@%0*x", width, index);
- }
- break;
- case Instruction::kIndexMethodRef:
- if (index < header->GetCollections().MethodIdsSize()) {
- dex_ir::MethodId* method_id = header->GetCollections().GetMethodId(index);
- const char* name = method_id->Name()->Data();
- std::string type_descriptor = GetSignatureForProtoId(method_id->Proto());
- const char* back_descriptor = method_id->Class()->GetStringId()->Data();
- outSize = snprintf(buf.get(), buf_size, "%s.%s:%s // method@%0*x",
- back_descriptor, name, type_descriptor.c_str(), width, index);
- } else {
- outSize = snprintf(buf.get(), buf_size, "<method?> // method@%0*x", width, index);
- }
- break;
- case Instruction::kIndexFieldRef:
- if (index < header->GetCollections().FieldIdsSize()) {
- dex_ir::FieldId* field_id = header->GetCollections().GetFieldId(index);
- const char* name = field_id->Name()->Data();
- const char* type_descriptor = field_id->Type()->GetStringId()->Data();
- const char* back_descriptor = field_id->Class()->GetStringId()->Data();
- outSize = snprintf(buf.get(), buf_size, "%s.%s:%s // field@%0*x",
- back_descriptor, name, type_descriptor, width, index);
- } else {
- outSize = snprintf(buf.get(), buf_size, "<field?> // field@%0*x", width, index);
- }
- break;
- case Instruction::kIndexVtableOffset:
- outSize = snprintf(buf.get(), buf_size, "[%0*x] // vtable #%0*x",
- width, index, width, index);
- break;
- case Instruction::kIndexFieldOffset:
- outSize = snprintf(buf.get(), buf_size, "[obj+%0*x]", width, index);
- break;
- // SOME NOT SUPPORTED:
- // case Instruction::kIndexVaries:
- // case Instruction::kIndexInlineMethod:
- case Instruction::kIndexMethodAndProtoRef: {
- std::string method("<method?>");
- std::string proto("<proto?>");
- if (index < header->GetCollections().MethodIdsSize()) {
- dex_ir::MethodId* method_id = header->GetCollections().GetMethodId(index);
- const char* name = method_id->Name()->Data();
- std::string type_descriptor = GetSignatureForProtoId(method_id->Proto());
- const char* back_descriptor = method_id->Class()->GetStringId()->Data();
- method = StringPrintf("%s.%s:%s", back_descriptor, name, type_descriptor.c_str());
- }
- if (secondary_index < header->GetCollections().ProtoIdsSize()) {
- dex_ir::ProtoId* proto_id = header->GetCollections().GetProtoId(secondary_index);
- proto = GetSignatureForProtoId(proto_id);
- }
- outSize = snprintf(buf.get(), buf_size, "%s, %s // method@%0*x, proto@%0*x",
- method.c_str(), proto.c_str(), width, index, width, secondary_index);
- }
- break;
- default:
- outSize = snprintf(buf.get(), buf_size, "<?>");
- break;
- } // switch
-
- // Determine success of string construction.
- if (outSize >= buf_size) {
- // The buffer wasn't big enough; retry with computed size. Note: snprintf()
- // doesn't count/ the '\0' as part of its returned size, so we add explicit
- // space for it here.
- return IndexString(header, dec_insn, outSize + 1);
- }
- return buf;
-}
-
-/*
* Dumps a single instruction.
*/
-static void DumpInstruction(dex_ir::Header* header, const dex_ir::CodeItem* code,
- uint32_t code_offset, uint32_t insn_idx, uint32_t insn_width,
- const Instruction* dec_insn) {
+void DexLayout::DumpInstruction(const dex_ir::CodeItem* code,
+ uint32_t code_offset,
+ uint32_t insn_idx,
+ uint32_t insn_width,
+ const Instruction* dec_insn) {
// Address of instruction (expressed as byte offset).
fprintf(out_file_, "%06x:", code_offset + 0x10 + insn_idx * 2);
// Set up additional argument.
std::unique_ptr<char[]> index_buf;
if (Instruction::IndexTypeOf(dec_insn->Opcode()) != Instruction::kIndexNone) {
- index_buf = IndexString(header, dec_insn, 200);
+ index_buf = IndexString(header_, dec_insn, 200);
}
// Dump the instruction.
/*
* Dumps a bytecode disassembly.
*/
-static void DumpBytecodes(dex_ir::Header* header, uint32_t idx,
- const dex_ir::CodeItem* code, uint32_t code_offset) {
- dex_ir::MethodId* method_id = header->GetCollections().GetMethodId(idx);
+void DexLayout::DumpBytecodes(uint32_t idx, const dex_ir::CodeItem* code, uint32_t code_offset) {
+ dex_ir::MethodId* method_id = header_->GetCollections().GetMethodId(idx);
const char* name = method_id->Name()->Data();
std::string type_descriptor = GetSignatureForProtoId(method_id->Proto());
const char* back_descriptor = method_id->Class()->GetStringId()->Data();
fprintf(stderr, "GLITCH: zero-width instruction at idx=0x%04x\n", insn_idx);
break;
}
- DumpInstruction(header, code, code_offset, insn_idx, insn_width, instruction);
+ DumpInstruction(code, code_offset, insn_idx, insn_width, instruction);
insn_idx += insn_width;
} // for
}
/*
* Dumps code of a method.
*/
-static void DumpCode(dex_ir::Header* header, uint32_t idx, const dex_ir::CodeItem* code,
- uint32_t code_offset) {
+void DexLayout::DumpCode(uint32_t idx, const dex_ir::CodeItem* code, uint32_t code_offset) {
fprintf(out_file_, " registers : %d\n", code->RegistersSize());
fprintf(out_file_, " ins : %d\n", code->InsSize());
fprintf(out_file_, " outs : %d\n", code->OutsSize());
// Bytecode disassembly, if requested.
if (options_.disassemble_) {
- DumpBytecodes(header, idx, code, code_offset);
+ DumpBytecodes(idx, code, code_offset);
}
// Try-catch blocks.
/*
* Dumps a method.
*/
-static void DumpMethod(dex_ir::Header* header, uint32_t idx, uint32_t flags,
- const dex_ir::CodeItem* code, int i) {
+void DexLayout::DumpMethod(uint32_t idx, uint32_t flags, const dex_ir::CodeItem* code, int i) {
// Bail for anything private if export only requested.
if (options_.exports_only_ && (flags & (kAccPublic | kAccProtected)) == 0) {
return;
}
- dex_ir::MethodId* method_id = header->GetCollections().GetMethodId(idx);
+ dex_ir::MethodId* method_id = header_->GetCollections().GetMethodId(idx);
const char* name = method_id->Name()->Data();
char* type_descriptor = strdup(GetSignatureForProtoId(method_id->Proto()).c_str());
const char* back_descriptor = method_id->Class()->GetStringId()->Data();
fprintf(out_file_, " code : (none)\n");
} else {
fprintf(out_file_, " code -\n");
- DumpCode(header, idx, code, code->GetOffset());
+ DumpCode(idx, code, code->GetOffset());
}
if (options_.disassemble_) {
fputc('\n', out_file_);
/*
* Dumps a static (class) field.
*/
-static void DumpSField(dex_ir::Header* header, uint32_t idx, uint32_t flags,
- int i, dex_ir::EncodedValue* init) {
+void DexLayout::DumpSField(uint32_t idx, uint32_t flags, int i, dex_ir::EncodedValue* init) {
// Bail for anything private if export only requested.
if (options_.exports_only_ && (flags & (kAccPublic | kAccProtected)) == 0) {
return;
}
- dex_ir::FieldId* field_id = header->GetCollections().GetFieldId(idx);
+ dex_ir::FieldId* field_id = header_->GetCollections().GetFieldId(idx);
const char* name = field_id->Name()->Data();
const char* type_descriptor = field_id->Type()->GetStringId()->Data();
const char* back_descriptor = field_id->Class()->GetStringId()->Data();
/*
* Dumps an instance field.
*/
-static void DumpIField(dex_ir::Header* header, uint32_t idx, uint32_t flags, int i) {
- DumpSField(header, idx, flags, i, nullptr);
+void DexLayout::DumpIField(uint32_t idx, uint32_t flags, int i) {
+ DumpSField(idx, flags, i, nullptr);
}
/*
* If "*last_package" is nullptr or does not match the current class' package,
* the value will be replaced with a newly-allocated string.
*/
-static void DumpClass(dex_ir::Header* header, int idx, char** last_package) {
- dex_ir::ClassDef* class_def = header->GetCollections().GetClassDef(idx);
+void DexLayout::DumpClass(int idx, char** last_package) {
+ dex_ir::ClassDef* class_def = header_->GetCollections().GetClassDef(idx);
// Omitting non-public class.
if (options_.exports_only_ && (class_def->GetAccessFlags() & kAccPublic) == 0) {
return;
}
if (options_.show_section_headers_) {
- DumpClassDef(header, idx);
+ DumpClassDef(idx);
}
if (options_.show_annotations_) {
- DumpClassAnnotations(header, idx);
+ DumpClassAnnotations(idx);
}
// For the XML output, show the package name. Ideally we'd gather
// package name wouldn't jump around, but that's not a great plan
// for something that needs to run on the device.
const char* class_descriptor =
- header->GetCollections().GetClassDef(idx)->ClassType()->GetStringId()->Data();
+ header_->GetCollections().GetClassDef(idx)->ClassType()->GetStringId()->Data();
if (!(class_descriptor[0] == 'L' &&
class_descriptor[strlen(class_descriptor)-1] == ';')) {
// Arrays and primitives should not be defined explicitly. Keep going?
dex_ir::FieldItemVector* static_fields = class_data->StaticFields();
if (static_fields != nullptr) {
for (uint32_t i = 0; i < static_fields->size(); i++) {
- DumpSField(header,
- (*static_fields)[i]->GetFieldId()->GetIndex(),
+ DumpSField((*static_fields)[i]->GetFieldId()->GetIndex(),
(*static_fields)[i]->GetAccessFlags(),
i,
i < encoded_values_size ? (*encoded_values)[i].get() : nullptr);
dex_ir::FieldItemVector* instance_fields = class_data->InstanceFields();
if (instance_fields != nullptr) {
for (uint32_t i = 0; i < instance_fields->size(); i++) {
- DumpIField(header,
- (*instance_fields)[i]->GetFieldId()->GetIndex(),
+ DumpIField((*instance_fields)[i]->GetFieldId()->GetIndex(),
(*instance_fields)[i]->GetAccessFlags(),
i);
} // for
dex_ir::MethodItemVector* direct_methods = class_data->DirectMethods();
if (direct_methods != nullptr) {
for (uint32_t i = 0; i < direct_methods->size(); i++) {
- DumpMethod(header,
- (*direct_methods)[i]->GetMethodId()->GetIndex(),
+ DumpMethod((*direct_methods)[i]->GetMethodId()->GetIndex(),
(*direct_methods)[i]->GetAccessFlags(),
(*direct_methods)[i]->GetCodeItem(),
i);
dex_ir::MethodItemVector* virtual_methods = class_data->VirtualMethods();
if (virtual_methods != nullptr) {
for (uint32_t i = 0; i < virtual_methods->size(); i++) {
- DumpMethod(header,
- (*virtual_methods)[i]->GetMethodId()->GetIndex(),
+ DumpMethod((*virtual_methods)[i]->GetMethodId()->GetIndex(),
(*virtual_methods)[i]->GetAccessFlags(),
(*virtual_methods)[i]->GetCodeItem(),
i);
free(access_str);
}
-/*
- * Dumps the requested sections of the file.
- */
-static void ProcessDexFile(const char* file_name, const DexFile* dex_file, size_t dex_file_index) {
- if (options_.verbose_) {
- fprintf(out_file_, "Opened '%s', DEX version '%.3s'\n",
- file_name, dex_file->GetHeader().magic_ + 4);
- }
- std::unique_ptr<dex_ir::Header> header(dex_ir::DexIrBuilder(*dex_file));
-
- if (options_.visualize_pattern_) {
- VisualizeDexLayout(header.get(), dex_file, dex_file_index);
- return;
- }
-
+void DexLayout::DumpDexFile() {
// Headers.
if (options_.show_file_headers_) {
- DumpFileHeader(header.get());
+ DumpFileHeader();
}
// Open XML context.
// Iterate over all classes.
char* package = nullptr;
- const uint32_t class_defs_size = header->GetCollections().ClassDefsSize();
+ const uint32_t class_defs_size = header_->GetCollections().ClassDefsSize();
for (uint32_t i = 0; i < class_defs_size; i++) {
- DumpClass(header.get(), i, &package);
+ DumpClass(i, &package);
} // for
// Free the last package allocated.
if (options_.output_format_ == kOutputXml) {
fprintf(out_file_, "</api>\n");
}
+}
- // Output dex file.
- if (options_.output_dex_directory_ != nullptr) {
+void DexLayout::OutputDexFile(const std::string& dex_file_location) {
+ std::string error_msg;
+ std::unique_ptr<File> new_file;
+ if (!options_.output_to_memmap_) {
std::string output_location(options_.output_dex_directory_);
- size_t last_slash = dex_file->GetLocation().rfind('/');
- output_location.append(dex_file->GetLocation().substr(last_slash));
- DexWriter::OutputDexFile(*header, output_location.c_str());
+ size_t last_slash = dex_file_location.rfind("/");
+ std::string dex_file_directory = dex_file_location.substr(0, last_slash + 1);
+ if (output_location == dex_file_directory) {
+ output_location = dex_file_location + ".new";
+ } else if (last_slash != std::string::npos) {
+ output_location += dex_file_location.substr(last_slash);
+ } else {
+ output_location += "/" + dex_file_location + ".new";
+ }
+ new_file.reset(OS::CreateEmptyFile(output_location.c_str()));
+ ftruncate(new_file->Fd(), header_->FileSize());
+ mem_map_.reset(MemMap::MapFile(header_->FileSize(), PROT_READ | PROT_WRITE, MAP_SHARED,
+ new_file->Fd(), 0, /*low_4gb*/ false, output_location.c_str(), &error_msg));
+ } else {
+ mem_map_.reset(MemMap::MapAnonymous("layout dex", nullptr, header_->FileSize(),
+ PROT_READ | PROT_WRITE, /* low_4gb */ false, /* reuse */ false, &error_msg));
+ }
+ if (mem_map_ == nullptr) {
+ LOG(ERROR) << "Could not create mem map for dex writer output: " << error_msg;
+ if (new_file.get() != nullptr) {
+ new_file->Erase();
+ }
+ return;
+ }
+ DexWriter::Output(header_, mem_map_.get());
+ if (new_file != nullptr) {
+ UNUSED(new_file->FlushCloseOrErase());
+ }
+}
+
+/*
+ * Dumps the requested sections of the file.
+ */
+void DexLayout::ProcessDexFile(const char* file_name,
+ const DexFile* dex_file,
+ size_t dex_file_index) {
+ std::unique_ptr<dex_ir::Header> header(dex_ir::DexIrBuilder(*dex_file));
+ SetHeader(header.get());
+
+ if (options_.verbose_) {
+ fprintf(out_file_, "Opened '%s', DEX version '%.3s'\n",
+ file_name, dex_file->GetHeader().magic_ + 4);
+ }
+
+ if (options_.visualize_pattern_) {
+ VisualizeDexLayout(header_, dex_file, dex_file_index, info_);
+ return;
+ }
+
+ // Dump dex file.
+ if (options_.dump_) {
+ DumpDexFile();
+ }
+
+ // Output dex file as file or memmap.
+ if (options_.output_dex_directory_ != nullptr || options_.output_to_memmap_) {
+ OutputDexFile(dex_file->GetLocation());
}
}
/*
* Processes a single file (either direct .dex or indirect .zip/.jar/.apk).
*/
-int ProcessFile(const char* file_name) {
+int DexLayout::ProcessFile(const char* file_name) {
if (options_.verbose_) {
fprintf(out_file_, "Processing '%s'...\n", file_name);
}
#include <stdint.h>
#include <stdio.h>
+#include "dex_ir.h"
+#include "mem_map.h"
+
namespace art {
+class DexFile;
+class Instruction;
class ProfileCompilationInfo;
/* Supported output formats. */
};
/* Command-line options. */
-struct Options {
- bool build_dex_ir_;
- bool checksum_only_;
- bool disassemble_;
- bool exports_only_;
- bool ignore_bad_checksum_;
- bool show_annotations_;
- bool show_file_headers_;
- bool show_section_headers_;
- bool verbose_;
- bool visualize_pattern_;
- OutputFormat output_format_;
- const char* output_dex_directory_;
- const char* output_file_name_;
- const char* profile_file_name_;
+class Options {
+ public:
+ Options() = default;
+
+ bool dump_ = false;
+ bool build_dex_ir_ = false;
+ bool checksum_only_ = false;
+ bool disassemble_ = false;
+ bool exports_only_ = false;
+ bool ignore_bad_checksum_ = false;
+ bool output_to_memmap_ = false;
+ bool show_annotations_ = false;
+ bool show_file_headers_ = false;
+ bool show_section_headers_ = false;
+ bool verbose_ = false;
+ bool visualize_pattern_ = false;
+ OutputFormat output_format_ = kOutputPlain;
+ const char* output_dex_directory_ = nullptr;
+ const char* output_file_name_ = nullptr;
+ const char* profile_file_name_ = nullptr;
};
-/* Prototypes. */
-extern struct Options options_;
-extern FILE* out_file_;
-extern ProfileCompilationInfo* profile_info_;
-int ProcessFile(const char* file_name);
+class DexLayout {
+ public:
+ DexLayout(Options& options,
+ ProfileCompilationInfo* info,
+ FILE* out_file,
+ dex_ir::Header*
+ header = nullptr)
+ : options_(options), info_(info), out_file_(out_file), header_(header) { }
+
+ int ProcessFile(const char* file_name);
+ void ProcessDexFile(const char* file_name, const DexFile* dex_file, size_t dex_file_index);
+
+ dex_ir::Header* GetHeader() const { return header_; }
+ void SetHeader(dex_ir::Header* header) { header_ = header; }
+
+ MemMap* GetAndReleaseMemMap() { return mem_map_.release(); }
+
+ private:
+ void DumpAnnotationSetItem(dex_ir::AnnotationSetItem* set_item);
+ void DumpBytecodes(uint32_t idx, const dex_ir::CodeItem* code, uint32_t code_offset);
+ void DumpCatches(const dex_ir::CodeItem* code);
+ void DumpClass(int idx, char** last_package);
+ void DumpClassAnnotations(int idx);
+ void DumpClassDef(int idx);
+ void DumpCode(uint32_t idx, const dex_ir::CodeItem* code, uint32_t code_offset);
+ void DumpEncodedAnnotation(dex_ir::EncodedAnnotation* annotation);
+ void DumpEncodedValue(const dex_ir::EncodedValue* data);
+ void DumpFileHeader();
+ void DumpIField(uint32_t idx, uint32_t flags, int i);
+ void DumpInstruction(const dex_ir::CodeItem* code,
+ uint32_t code_offset,
+ uint32_t insn_idx,
+ uint32_t insn_width,
+ const Instruction* dec_insn);
+ void DumpInterface(const dex_ir::TypeId* type_item, int i);
+ void DumpLocalInfo(const dex_ir::CodeItem* code);
+ void DumpMethod(uint32_t idx, uint32_t flags, const dex_ir::CodeItem* code, int i);
+ void DumpPositionInfo(const dex_ir::CodeItem* code);
+ void DumpSField(uint32_t idx, uint32_t flags, int i, dex_ir::EncodedValue* init);
+
+ void DumpDexFile();
+ std::vector<dex_ir::ClassDef*> LayoutClassDefsAndClassData(const DexFile* dex_file);
+ int32_t LayoutCodeItems(std::vector<dex_ir::ClassDef*> new_class_def_order);
+ 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);
+ void LayoutOutputFile(const DexFile* dex_file);
+ void OutputDexFile(const std::string& dex_file_location);
+
+ void DumpCFG(const DexFile* dex_file, int idx);
+ void DumpCFG(const DexFile* dex_file, uint32_t dex_method_idx, const DexFile::CodeItem* code);
+
+ Options& options_;
+ ProfileCompilationInfo* info_;
+ FILE* out_file_;
+ dex_ir::Header* header_;
+ std::unique_ptr<MemMap> mem_map_;
+
+ DISALLOW_COPY_AND_ASSIGN(DexLayout);
+};
} // namespace art
InitLogging(argv, Runtime::Aborter);
MemMap::Init();
- // Reset options.
+ Options options;
+ options.dump_ = true;
+ options.verbose_ = true;
bool want_usage = false;
- memset(&options_, 0, sizeof(options_));
- options_.verbose_ = true;
// Parse all arguments.
while (1) {
- const int ic = getopt(argc, argv, "abcdefghil:o:p:sw:");
+ const int ic = getopt(argc, argv, "abcdefghil:mo:p:sw:");
if (ic < 0) {
break; // done
}
switch (ic) {
case 'a': // display annotations
- options_.show_annotations_ = true;
+ options.show_annotations_ = true;
break;
case 'b': // build dex_ir
- options_.build_dex_ir_ = true;
+ options.build_dex_ir_ = true;
break;
case 'c': // verify the checksum then exit
- options_.checksum_only_ = true;
+ options.checksum_only_ = true;
break;
case 'd': // disassemble Dalvik instructions
- options_.disassemble_ = true;
+ options.disassemble_ = true;
break;
case 'e': // exported items only
- options_.exports_only_ = true;
+ options.exports_only_ = true;
break;
case 'f': // display outer file header
- options_.show_file_headers_ = true;
+ options.show_file_headers_ = true;
break;
case 'h': // display section headers, i.e. all meta-data
- options_.show_section_headers_ = true;
+ options.show_section_headers_ = true;
break;
case 'i': // continue even if checksum is bad
- options_.ignore_bad_checksum_ = true;
+ options.ignore_bad_checksum_ = true;
break;
case 'l': // layout
if (strcmp(optarg, "plain") == 0) {
- options_.output_format_ = kOutputPlain;
+ options.output_format_ = kOutputPlain;
} else if (strcmp(optarg, "xml") == 0) {
- options_.output_format_ = kOutputXml;
- options_.verbose_ = false;
+ options.output_format_ = kOutputXml;
+ options.verbose_ = false;
} else {
want_usage = true;
}
break;
+ case 'm': // output dex files to a memmap
+ options.output_to_memmap_ = true;
+ break;
case 'o': // output file
- options_.output_file_name_ = optarg;
+ options.output_file_name_ = optarg;
break;
case 'p': // profile file
- options_.profile_file_name_ = optarg;
+ options.profile_file_name_ = optarg;
break;
case 's': // visualize access pattern
- options_.visualize_pattern_ = true;
- options_.verbose_ = false;
+ options.visualize_pattern_ = true;
+ options.verbose_ = false;
break;
case 'w': // output dex files directory
- options_.output_dex_directory_ = optarg;
+ options.output_dex_directory_ = optarg;
break;
default:
want_usage = true;
fprintf(stderr, "%s: no file specified\n", kProgramName);
want_usage = true;
}
- if (options_.checksum_only_ && options_.ignore_bad_checksum_) {
+ if (options.checksum_only_ && options.ignore_bad_checksum_) {
fprintf(stderr, "Can't specify both -c and -i\n");
want_usage = true;
}
}
// Open alternative output file.
- if (options_.output_file_name_) {
- out_file_ = fopen(options_.output_file_name_, "w");
- if (!out_file_) {
- fprintf(stderr, "Can't open %s\n", options_.output_file_name_);
+ FILE* out_file = stdout;
+ if (options.output_file_name_) {
+ out_file = fopen(options.output_file_name_, "w");
+ if (!out_file) {
+ fprintf(stderr, "Can't open %s\n", options.output_file_name_);
return 1;
}
}
// Open profile file.
- if (options_.profile_file_name_) {
- int profile_fd = open(options_.profile_file_name_, O_RDONLY);
+ ProfileCompilationInfo* profile_info = nullptr;
+ if (options.profile_file_name_) {
+ int profile_fd = open(options.profile_file_name_, O_RDONLY);
if (profile_fd < 0) {
- fprintf(stderr, "Can't open %s\n", options_.profile_file_name_);
+ fprintf(stderr, "Can't open %s\n", options.profile_file_name_);
return 1;
}
- profile_info_ = new ProfileCompilationInfo();
- if (!profile_info_->Load(profile_fd)) {
- fprintf(stderr, "Can't read profile info from %s\n", options_.profile_file_name_);
+ profile_info = new ProfileCompilationInfo();
+ if (!profile_info->Load(profile_fd)) {
+ fprintf(stderr, "Can't read profile info from %s\n", options.profile_file_name_);
return 1;
}
}
+ // Create DexLayout instance.
+ DexLayout dex_layout(options, profile_info, out_file);
+
// Process all files supplied on command line.
int result = 0;
while (optind < argc) {
- result |= ProcessFile(argv[optind++]);
+ result |= dex_layout.ProcessFile(argv[optind++]);
} // while
return result != 0;
}