├── .travis.yml ├── CMakeLists.txt ├── README.md ├── assets └── yadd_cover.png ├── clean.py ├── engine ├── CMakeLists.txt └── dumper │ ├── CMakeLists.txt │ ├── dex_file-inl.h │ ├── dex_file.cc │ ├── dex_file.h │ ├── dex_instruction-inl.h │ ├── dex_instruction.cc │ ├── dex_instruction.h │ ├── dex_instruction_list.h │ ├── dumper.cc │ ├── invoke_type.h │ ├── leb128.h │ └── modifiers.h └── util ├── cmd_opt.cc ├── cmd_opt.h ├── globals.h ├── log.cc ├── log.h ├── macros.h ├── misc.cc ├── misc.h ├── scoped_fd.h ├── scoped_map.h ├── stringpiece.cc ├── stringpiece.h ├── stringprintf.cc ├── stringprintf.h ├── utf-inl.h ├── utf.cc └── utf.h /.travis.yml: -------------------------------------------------------------------------------- 1 | language: cpp 2 | 3 | compiler: 4 | - gcc 5 | 6 | git: 7 | depth: 1 8 | 9 | install: 10 | - sudo pip install cpp-coveralls 11 | - sudo apt-get update -qq 12 | - sudo apt-get install -qq cmake python3-minimal 13 | - sudo apt-get install -qq valgrind 14 | - if [ "$CXX" = "g++" ]; then export CXX="g++-4.8" CC="gcc-4.8"; fi 15 | 16 | addons: 17 | apt: 18 | sources: 19 | - ubuntu-toolchain-r-test 20 | 21 | packages: 22 | - gcc-4.8 23 | - g++-4.8 24 | 25 | script: 26 | - ./clean.py --rebuild 27 | - cd build 28 | - cmake .. 29 | - make 30 | 31 | after_success: 32 | #- coveralls 33 | 34 | 35 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8) 2 | 3 | 4 | set(DIR_ENGINE "${CMAKE_CURRENT_SOURCE_DIR}/engine") 5 | 6 | 7 | add_subdirectory(${DIR_ENGINE}) 8 | 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.org/ZSShen/YADD.svg?branch=master)](https://travis-ci.org/ZSShen/YADD) 2 | 3 | 4 | 5 | 6 | ## **Objective** 7 | YADD is designed to be a complex disassembler for static Android app analysis, which supports bytecode-level class and method signature extraction and offers an easy-to-use interface for reverse engineering. 8 | 9 | As a reverse engineering toolkit, YADD should basically support: 10 | + Code block differentiation and control flow visualization. 11 | + Symbolic level def-use chain to highlight the data dependency between instructions. 12 | 13 | ## **Current Progress** 14 | YADD is now `relying on the Dex file parsing and the instruction decoding algorithm provided by Android Open Source Project`. It can now be built as a `independent executable for Dex code disassembling and signature extraction`. More features about control and data flow analysis will be updated in the near future. 15 | 16 | ## **Installation** 17 | Clone the project to your working directory. 18 | In the working directory, type the following commands. 19 | ``` 20 | $ ./clean.py --rebuild 21 | $ cd build 22 | $ cmake .. 23 | $ make 24 | ``` 25 | Done! And the executable should locate at: 26 | `/PATH/TO/YOUR/WORKING/DIRECTORY/bin/dumper` 27 | 28 | ## **Usage** 29 | ``` 30 | Usage: dumper [options] 31 | Example: dumper --granularity=instruction --input=/PATH/TO/MY/DEX --output=PATH/TO/MY/LOG 32 | 33 | --granularity=(class|method|instruction): For data granularity 34 | class : List class names only 35 | method : List method signatures only 36 | instruction: Full dump 37 | 38 | --input=: Specify the input dex pathname 39 | 40 | --output=: Specify the output dump pathname 41 | 42 | ``` 43 | 44 | ## **Contact** 45 | Any problems? please contact me via the mail: andy.zsshen@gmail.com 46 | -------------------------------------------------------------------------------- /assets/yadd_cover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZSShen/YADD/ffe04e1160cb56c10feae6a613909bd3fa81ef67/assets/yadd_cover.png -------------------------------------------------------------------------------- /clean.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | 4 | import os; 5 | import sys; 6 | import argparse; 7 | import shutil; 8 | 9 | 10 | def main(): 11 | 12 | parser = argparse.ArgumentParser(); 13 | parser.add_argument("--rebuild", dest = "rebuild", action = "store_true"); 14 | parser.add_argument("--no-rebuild", dest = "rebuild", action = "store_false"); 15 | parser.set_defaults(rebuild = False); 16 | 17 | args = parser.parse_args(); 18 | rebuild = args.rebuild; 19 | 20 | # Recursivly clean all the binary directories. 21 | list_clean = list(); 22 | path_cur = os.getcwd(); 23 | for path_dir, list_dir, list_file in os.walk(path_cur): 24 | if path_dir.endswith("build"): 25 | list_clean.append(path_dir); 26 | elif path_dir.endswith("lib"): 27 | list_clean.append(path_dir); 28 | elif path_dir.endswith("bin"): 29 | list_clean.append(path_dir); 30 | elif path_dir.endswith("export"): 31 | list_clean.append(path_dir); 32 | for path_clean in list_clean: 33 | if os.path.isdir(path_clean) == True: 34 | shutil.rmtree(path_clean); 35 | 36 | # Create the build folder if necessary. 37 | if rebuild == False: 38 | return; 39 | for path_dir, list_dir, list_file in os.walk(path_cur): 40 | if path_dir.endswith("engine"): 41 | path_build = path_dir.replace("engine", "build"); 42 | if os.path.isdir(path_build) == False: 43 | os.makedirs(path_build); 44 | 45 | return; 46 | 47 | 48 | if __name__ == "__main__": 49 | main(); 50 | -------------------------------------------------------------------------------- /engine/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8) 2 | 3 | 4 | set(DIR_DUMPER "${CMAKE_CURRENT_SOURCE_DIR}/dumper") 5 | 6 | 7 | add_subdirectory(${DIR_DUMPER}) 8 | -------------------------------------------------------------------------------- /engine/dumper/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8) 2 | 3 | 4 | #==================================================================# 5 | # The subroutines for specific task # 6 | #==================================================================# 7 | # This subroutine builds the dumper part of YADD. 8 | function(SUB_BUILD_PURE_DUMPER) 9 | set(TYPE_LIB "lib") 10 | set(TYPE_EXE "exe") 11 | 12 | include_directories(${PATH_INC_DUMPER} 13 | ${PATH_INC_UTIL}) 14 | 15 | if (BIN_TYPE STREQUAL TYPE_LIB) 16 | set(LIB_NAME "dexdump") 17 | set(LIB_TYPE "SHARED") 18 | 19 | add_library(${TGE} ${LIB_TYPE} 20 | ${PATH_SRC_UTF} 21 | ${PATH_SRC_MISC} 22 | ${PATH_SRC_STRINGPIECE} 23 | ${PATH_SRC_STRINGPRINTF} 24 | ${PATH_SRC_LOG} 25 | ${PATH_SRC_DEX_FILE} 26 | ${PATH_SRC_DEX_INSTRUCTION} 27 | ${PATH_SRC_CMD_OPT} 28 | ${PATH_SRC_DUMPER}) 29 | 30 | set_target_properties( ${TGE} PROPERTIES 31 | LIBRARY_OUTPUT_DIRECTORY ${PATH_OUT} 32 | OUTPUT_NAME ${LIB_NAME}) 33 | 34 | elseif (BIN_TYPE STREQUAL TYPE_EXE) 35 | set(EXE_NAME "dumper") 36 | 37 | add_executable( ${TGE} 38 | ${PATH_SRC_UTF} 39 | ${PATH_SRC_MISC} 40 | ${PATH_SRC_STRINGPIECE} 41 | ${PATH_SRC_STRINGPRINTF} 42 | ${PATH_SRC_LOG} 43 | ${PATH_SRC_DEX_FILE} 44 | ${PATH_SRC_DEX_INSTRUCTION} 45 | ${PATH_SRC_CMD_OPT} 46 | ${PATH_SRC_DUMPER}) 47 | 48 | set_target_properties( ${TGE} PROPERTIES 49 | RUNTIME_OUTPUT_DIRECTORY ${PATH_OUT} 50 | OUTPUT_NAME ${EXE_NAME}) 51 | else() 52 | message("Error: BIN_TYPE is not properly specified.") 53 | return() 54 | endif() 55 | endfunction() 56 | 57 | 58 | #==================================================================# 59 | # The CMakeLists entry point # 60 | #==================================================================# 61 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") 62 | 63 | # Abbreviate the variable 64 | set(ROOT_SRC "${CMAKE_CURRENT_SOURCE_DIR}") 65 | 66 | # The paths of to be built source files. 67 | set(PATH_SRC_DEX_FILE "${ROOT_SRC}/dex_file.cc") 68 | set(PATH_SRC_DEX_INSTRUCTION "${ROOT_SRC}/dex_instruction.cc") 69 | set(PATH_SRC_DUMPER "${ROOT_SRC}/dumper.cc") 70 | set(PATH_SRC_SPEW "${ROOT_SRC}/../../util/spew.cc") 71 | set(PATH_SRC_LOG "${ROOT_SRC}/../../util/log.cc") 72 | set(PATH_SRC_STRINGPRINTF "${ROOT_SRC}/../../util/stringprintf.cc") 73 | set(PATH_SRC_STRINGPIECE "${ROOT_SRC}/../../util/stringpiece.cc") 74 | set(PATH_SRC_MISC "${ROOT_SRC}/../../util/misc.cc") 75 | set(PATH_SRC_UTF "${ROOT_SRC}/../../util/utf.cc") 76 | set(PATH_SRC_CMD_OPT "${ROOT_SRC}/../../util/cmd_opt.cc") 77 | 78 | # The header inclusion paths. 79 | set(PATH_INC_UTIL "${ROOT_SRC}/../../util/") 80 | set(PATH_INC_DUMPER "${ROOT_SRC}") 81 | 82 | # The binary output path. 83 | set(PATH_OUT "${ROOT_SRC}/../../bin") 84 | 85 | # In this POC stage, I prefer pure dumper executable. 86 | set(PURE_DUMPER "true") 87 | set(BIN_TYPE "exe") 88 | 89 | add_definitions(-D__STDC_FORMAT_MACROS) 90 | 91 | set(TGE "YADD") 92 | if (PURE_DUMPER) 93 | SUB_BUILD_PURE_DUMPER() 94 | else() 95 | 96 | endif() 97 | 98 | -------------------------------------------------------------------------------- /engine/dumper/dex_file-inl.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _ART_DEX_FILE_INL_H_ 3 | #define _ART_DEX_FILE_INL_H_ 4 | 5 | 6 | #include "dex_file.h" 7 | 8 | 9 | inline int32_t DexFile::GetStringLength(const StringId& string_id) const 10 | { 11 | const byte* ptr = begin_ + string_id.string_data_off_; 12 | return DecodeUnsignedLeb128(&ptr); 13 | } 14 | 15 | inline const char* DexFile::GetStringDataAndUtf16Length(const StringId& string_id, 16 | uint32_t* utf16_length) const 17 | { 18 | CHECK(utf16_length != nullptr); 19 | const byte* ptr = begin_ + string_id.string_data_off_; 20 | *utf16_length = DecodeUnsignedLeb128(&ptr); 21 | return reinterpret_cast(ptr); 22 | } 23 | 24 | inline const Signature DexFile::GetMethodSignature(const MethodId& method_id) const 25 | { 26 | return Signature(this, GetProtoId(method_id.proto_idx_)); 27 | } 28 | 29 | static inline bool DexFileStringEquals(const DexFile* df1, uint32_t sidx1, 30 | const DexFile* df2, uint32_t sidx2) 31 | { 32 | uint32_t s1_len; // Note: utf16 length != mutf8 length. 33 | const char* s1_data = df1->StringDataAndUtf16LengthByIdx(sidx1, &s1_len); 34 | uint32_t s2_len; 35 | const char* s2_data = df2->StringDataAndUtf16LengthByIdx(sidx2, &s2_len); 36 | return (s1_len == s2_len) && (strcmp(s1_data, s2_data) == 0); 37 | } 38 | 39 | inline bool Signature::operator==(const Signature& rhs) const 40 | { 41 | if (dex_file_ == nullptr) 42 | return rhs.dex_file_ == nullptr; 43 | if (rhs.dex_file_ == nullptr) 44 | return false; 45 | if (dex_file_ == rhs.dex_file_) 46 | return proto_id_ == rhs.proto_id_; 47 | 48 | uint32_t lhs_shorty_len; // For a shorty utf16 length == mutf8 length. 49 | const char* lhs_shorty_data = dex_file_->StringDataAndUtf16LengthByIdx(proto_id_->shorty_idx_, 50 | &lhs_shorty_len); 51 | StringPiece lhs_shorty(lhs_shorty_data, lhs_shorty_len); 52 | { 53 | uint32_t rhs_shorty_len; 54 | const char* rhs_shorty_data = 55 | rhs.dex_file_->StringDataAndUtf16LengthByIdx(rhs.proto_id_->shorty_idx_, 56 | &rhs_shorty_len); 57 | StringPiece rhs_shorty(rhs_shorty_data, rhs_shorty_len); 58 | if (lhs_shorty != rhs_shorty) { 59 | return false; // Shorty mismatch. 60 | } 61 | } 62 | if (lhs_shorty[0] == 'L') { 63 | const DexFile::TypeId& return_type_id = dex_file_->GetTypeId(proto_id_->return_type_idx_); 64 | const DexFile::TypeId& rhs_return_type_id = 65 | rhs.dex_file_->GetTypeId(rhs.proto_id_->return_type_idx_); 66 | if (!DexFileStringEquals(dex_file_, return_type_id.descriptor_idx_, 67 | rhs.dex_file_, rhs_return_type_id.descriptor_idx_)) 68 | return false; // Return type mismatch. 69 | } 70 | if (lhs_shorty.find('L', 1) != StringPiece::npos) { 71 | const DexFile::TypeList* params = dex_file_->GetProtoParameters(*proto_id_); 72 | const DexFile::TypeList* rhs_params = rhs.dex_file_->GetProtoParameters(*rhs.proto_id_); 73 | // Both lists are empty or have contents, or else shorty is broken. 74 | CHECK_EQ((params == nullptr), (rhs_params == nullptr)); 75 | if (params != nullptr) { 76 | uint32_t params_size = params->Size(); 77 | CHECK_EQ(params_size, rhs_params->Size()); // Parameter list size must match. 78 | for (uint32_t i = 0; i < params_size; ++i) { 79 | const DexFile::TypeId& param_id = dex_file_->GetTypeId(params->GetTypeItem(i).type_idx_); 80 | const DexFile::TypeId& rhs_param_id = 81 | rhs.dex_file_->GetTypeId(rhs_params->GetTypeItem(i).type_idx_); 82 | if (!DexFileStringEquals(dex_file_, param_id.descriptor_idx_, 83 | rhs.dex_file_, rhs_param_id.descriptor_idx_)) 84 | return false; // Parameter type mismatch. 85 | } 86 | } 87 | } 88 | return true; 89 | } 90 | 91 | #endif -------------------------------------------------------------------------------- /engine/dumper/dex_file.cc: -------------------------------------------------------------------------------- 1 | 2 | #include "dex_file.h" 3 | #include "dex_file-inl.h" 4 | 5 | 6 | const byte DexFile::kDexMagic[] = { 'd', 'e', 'x', '\n' }; 7 | const byte DexFile::kDexMagicVersion[] = { '0', '3', '5', '\0' }; 8 | 9 | 10 | DexFile::~DexFile() 11 | {} 12 | 13 | bool DexFile::IsMagicValid(const byte* magic) 14 | { 15 | return (memcmp(magic, kDexMagic, sizeof(kDexMagic)) == 0); 16 | } 17 | 18 | bool DexFile::IsVersionValid(const byte* magic) 19 | { 20 | return (memcmp(magic, kDexMagicVersion, sizeof(kDexMagicVersion)) == 0); 21 | } 22 | 23 | std::string Signature::ToString() const 24 | { 25 | if (dex_file_ == nullptr) { 26 | CHECK(proto_id_ == nullptr); 27 | return ""; 28 | } 29 | const DexFile::TypeList* params = dex_file_->GetProtoParameters(*proto_id_); 30 | std::string result; 31 | if (params == nullptr) 32 | result += "()"; 33 | else { 34 | result += "("; 35 | for (uint32_t i = 0; i < params->Size(); ++i) 36 | result += dex_file_->StringByTypeIdx(params->GetTypeItem(i).type_idx_); 37 | result += ")"; 38 | } 39 | result += dex_file_->StringByTypeIdx(proto_id_->return_type_idx_); 40 | return result; 41 | } 42 | 43 | bool Signature::operator==(const StringPiece& rhs) const 44 | { 45 | if (dex_file_ == nullptr) 46 | return false; 47 | StringPiece tail(rhs); 48 | if (!tail.starts_with("(")) 49 | return false; // Invalid signature 50 | tail.remove_prefix(1); // "("; 51 | const DexFile::TypeList* params = dex_file_->GetProtoParameters(*proto_id_); 52 | if (params != nullptr) { 53 | for (uint32_t i = 0; i < params->Size(); ++i) { 54 | StringPiece param(dex_file_->StringByTypeIdx(params->GetTypeItem(i).type_idx_)); 55 | if (!tail.starts_with(param)) 56 | return false; 57 | tail.remove_prefix(param.length()); 58 | } 59 | } 60 | if (!tail.starts_with(")")) 61 | return false; 62 | tail.remove_prefix(1); // ")"; 63 | return tail == dex_file_->StringByTypeIdx(proto_id_->return_type_idx_); 64 | } 65 | 66 | 67 | DexFile::DexFile(byte* base, size_t size, ScopedMap& mem_map) 68 | : begin_(base), 69 | size_(size), 70 | mem_map_(base, size, mem_map.GetAlignedSize()), 71 | header_(reinterpret_cast(base)), 72 | string_ids_(reinterpret_cast(base + header_->string_ids_off_)), 73 | type_ids_(reinterpret_cast(base + header_->type_ids_off_)), 74 | field_ids_(reinterpret_cast(base + header_->field_ids_off_)), 75 | method_ids_(reinterpret_cast(base + header_->method_ids_off_)), 76 | proto_ids_(reinterpret_cast(base + header_->proto_ids_off_)), 77 | class_defs_(reinterpret_cast(base + header_->class_defs_off_)) 78 | { 79 | mem_map.release(); 80 | } 81 | 82 | const DexFile* DexFile::OpenMemory(byte* base, size_t size, ScopedMap& mem_map) 83 | { 84 | std::unique_ptr dex_file(new DexFile(base, size, mem_map)); 85 | if (!IsMagicValid(dex_file->header_->magic_)) { 86 | LOG(ERROR) << "Invalid DEX magic."; 87 | return nullptr; 88 | } 89 | if (!IsVersionValid(dex_file->header_->magic_ + 4)) { 90 | LOG(ERROR) << "Invalid DEX magic version."; 91 | return nullptr; 92 | } 93 | return dex_file.release(); 94 | } 95 | 96 | // Decodes the header section from the class data bytes. 97 | void ClassDataItemIterator::ReadClassDataHeader() 98 | { 99 | CHECK(ptr_pos_ != nullptr); 100 | header_.static_fields_size_ = DecodeUnsignedLeb128(&ptr_pos_); 101 | header_.instance_fields_size_ = DecodeUnsignedLeb128(&ptr_pos_); 102 | header_.direct_methods_size_ = DecodeUnsignedLeb128(&ptr_pos_); 103 | header_.virtual_methods_size_ = DecodeUnsignedLeb128(&ptr_pos_); 104 | } 105 | 106 | void ClassDataItemIterator::ReadClassDataField() 107 | { 108 | field_.field_idx_delta_ = DecodeUnsignedLeb128(&ptr_pos_); 109 | field_.access_flags_ = DecodeUnsignedLeb128(&ptr_pos_); 110 | if (last_idx_ != 0 && field_.field_idx_delta_ == 0) 111 | LOG(WARNING) << "Duplicated field."; 112 | } 113 | 114 | void ClassDataItemIterator::ReadClassDataMethod() 115 | { 116 | method_.method_idx_delta_ = DecodeUnsignedLeb128(&ptr_pos_); 117 | method_.access_flags_ = DecodeUnsignedLeb128(&ptr_pos_); 118 | method_.code_off_ = DecodeUnsignedLeb128(&ptr_pos_); 119 | if (last_idx_ != 0 && method_.method_idx_delta_ == 0) 120 | LOG(WARNING) << "Duplicated field."; 121 | } 122 | -------------------------------------------------------------------------------- /engine/dumper/dex_file.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _ART_DEX_FILE_H_ 3 | #define _ART_DEX_FILE_H_ 4 | 5 | 6 | #include "globals.h" 7 | #include "macros.h" 8 | #include "log.h" 9 | #include "scoped_fd.h" 10 | #include "scoped_map.h" 11 | 12 | #include "modifiers.h" 13 | #include "invoke_type.h" 14 | #include "leb128.h" 15 | #include "stringpiece.h" 16 | 17 | 18 | class Signature; 19 | 20 | class DexFile 21 | { 22 | public: 23 | static const byte kDexMagic[]; 24 | static const byte kDexMagicVersion[]; 25 | static const size_t kSha1DigestSize = 20; 26 | static const uint32_t kDexEndianConstant = 0x12345678; 27 | 28 | // name of the DexFile entry within a zip archive. 29 | static const char* kClassesDex; 30 | 31 | // The value of an invalid index. 32 | static const uint32_t kDexNoIndex = 0xFFFFFFFF; 33 | 34 | // The value of an invalid index. 35 | static const uint16_t kDexNoIndex16 = 0xFFFF; 36 | 37 | // The separator charactor in MultiDex locations. 38 | static constexpr char kMultiDexSeparator = ':'; 39 | 40 | // A string version of the previous. This is a define so that we can merge string literals in the 41 | // preprocessor. 42 | #define kMultiDexSeparatorString ":" 43 | 44 | // Raw header_item. 45 | struct Header 46 | { 47 | uint8_t magic_[8]; 48 | uint32_t checksum_; // See also location_checksum_ 49 | uint8_t signature_[kSha1DigestSize]; 50 | uint32_t file_size_; // size of entire file 51 | uint32_t header_size_; // offset to start of next section 52 | uint32_t endian_tag_; 53 | uint32_t link_size_; // unused 54 | uint32_t link_off_; // unused 55 | uint32_t map_off_; // unused 56 | uint32_t string_ids_size_; // number of StringIds 57 | uint32_t string_ids_off_; // file offset of StringIds array 58 | uint32_t type_ids_size_; // number of TypeIds, we don't support more than 65535 59 | uint32_t type_ids_off_; // file offset of TypeIds array 60 | uint32_t proto_ids_size_; // number of ProtoIds, we don't support more than 65535 61 | uint32_t proto_ids_off_; // file offset of ProtoIds array 62 | uint32_t field_ids_size_; // number of FieldIds 63 | uint32_t field_ids_off_; // file offset of FieldIds array 64 | uint32_t method_ids_size_; // number of MethodIds 65 | uint32_t method_ids_off_; // file offset of MethodIds array 66 | uint32_t class_defs_size_; // number of ClassDefs 67 | uint32_t class_defs_off_; // file offset of ClassDef array 68 | uint32_t data_size_; // unused 69 | uint32_t data_off_; // unused 70 | 71 | private: 72 | DISALLOW_COPY_AND_ASSIGN(Header); 73 | }; 74 | 75 | // Map item type codes. 76 | enum 77 | { 78 | kDexTypeHeaderItem = 0x0000, 79 | kDexTypeStringIdItem = 0x0001, 80 | kDexTypeTypeIdItem = 0x0002, 81 | kDexTypeProtoIdItem = 0x0003, 82 | kDexTypeFieldIdItem = 0x0004, 83 | kDexTypeMethodIdItem = 0x0005, 84 | kDexTypeClassDefItem = 0x0006, 85 | kDexTypeMapList = 0x1000, 86 | kDexTypeTypeList = 0x1001, 87 | kDexTypeAnnotationSetRefList = 0x1002, 88 | kDexTypeAnnotationSetItem = 0x1003, 89 | kDexTypeClassDataItem = 0x2000, 90 | kDexTypeCodeItem = 0x2001, 91 | kDexTypeStringDataItem = 0x2002, 92 | kDexTypeDebugInfoItem = 0x2003, 93 | kDexTypeAnnotationItem = 0x2004, 94 | kDexTypeEncodedArrayItem = 0x2005, 95 | kDexTypeAnnotationsDirectoryItem = 0x2006, 96 | }; 97 | 98 | struct MapItem 99 | { 100 | uint16_t type_; 101 | uint16_t unused_; 102 | uint32_t size_; 103 | uint32_t offset_; 104 | 105 | private: 106 | DISALLOW_COPY_AND_ASSIGN(MapItem); 107 | }; 108 | 109 | struct MapList 110 | { 111 | uint32_t size_; 112 | MapItem list_[1]; 113 | 114 | private: 115 | DISALLOW_COPY_AND_ASSIGN(MapList); 116 | }; 117 | 118 | // Raw string_id_item. 119 | struct StringId 120 | { 121 | uint32_t string_data_off_; // offset in bytes from the base address 122 | 123 | private: 124 | DISALLOW_COPY_AND_ASSIGN(StringId); 125 | }; 126 | 127 | // Raw type_id_item. 128 | struct TypeId 129 | { 130 | uint32_t descriptor_idx_; // index into string_ids 131 | 132 | private: 133 | DISALLOW_COPY_AND_ASSIGN(TypeId); 134 | }; 135 | 136 | // Raw field_id_item. 137 | struct FieldId 138 | { 139 | uint16_t class_idx_; // index into type_ids_ array for defining class 140 | uint16_t type_idx_; // index into type_ids_ array for field type 141 | uint32_t name_idx_; // index into string_ids_ array for field name 142 | 143 | private: 144 | DISALLOW_COPY_AND_ASSIGN(FieldId); 145 | }; 146 | 147 | // Raw method_id_item. 148 | struct MethodId 149 | { 150 | uint16_t class_idx_; // index into type_ids_ array for defining class 151 | uint16_t proto_idx_; // index into proto_ids_ array for method prototype 152 | uint32_t name_idx_; // index into string_ids_ array for method name 153 | 154 | private: 155 | DISALLOW_COPY_AND_ASSIGN(MethodId); 156 | }; 157 | 158 | // Raw proto_id_item. 159 | struct ProtoId 160 | { 161 | uint32_t shorty_idx_; // index into string_ids array for shorty descriptor 162 | uint16_t return_type_idx_; // index into type_ids array for return type 163 | uint16_t pad_; // padding = 0 164 | uint32_t parameters_off_; // file offset to type_list for parameter types 165 | 166 | private: 167 | DISALLOW_COPY_AND_ASSIGN(ProtoId); 168 | }; 169 | 170 | // Raw class_def_item. 171 | struct ClassDef 172 | { 173 | uint16_t class_idx_; // index into type_ids_ array for this class 174 | uint16_t pad1_; // padding = 0 175 | uint32_t access_flags_; 176 | uint16_t superclass_idx_; // index into type_ids_ array for superclass 177 | uint16_t pad2_; // padding = 0 178 | uint32_t interfaces_off_; // file offset to TypeList 179 | uint32_t source_file_idx_; // index into string_ids_ for source file name 180 | uint32_t annotations_off_; // file offset to annotations_directory_item 181 | uint32_t class_data_off_; // file offset to class_data_item 182 | uint32_t static_values_off_; // file offset to EncodedArray 183 | 184 | // Returns the valid access flags, that is, Java modifier bits relevant to the ClassDef type 185 | // (class or interface). These are all in the lower 16b and do not contain runtime flags. 186 | uint32_t GetJavaAccessFlags() const 187 | { 188 | if ((access_flags_ & kAccInterface) != 0) { 189 | // Interface. 190 | return access_flags_ & kAccValidInterfaceFlags; 191 | } else { 192 | // Class. 193 | return access_flags_ & kAccValidClassFlags; 194 | } 195 | } 196 | 197 | private: 198 | DISALLOW_COPY_AND_ASSIGN(ClassDef); 199 | }; 200 | 201 | // Raw type_item. 202 | struct TypeItem 203 | { 204 | uint16_t type_idx_; // index into type_ids section 205 | 206 | private: 207 | DISALLOW_COPY_AND_ASSIGN(TypeItem); 208 | }; 209 | 210 | // Raw type_list. 211 | class TypeList 212 | { 213 | public: 214 | uint32_t Size() const 215 | { 216 | return size_; 217 | } 218 | 219 | const TypeItem& GetTypeItem(uint32_t idx) const 220 | { 221 | CHECK_LT(idx, this->size_); 222 | return this->list_[idx]; 223 | } 224 | 225 | // Size in bytes of the part of the list that is common. 226 | static constexpr size_t GetHeaderSize() 227 | { 228 | return 4U; 229 | } 230 | 231 | // Size in bytes of the whole type list including all the stored elements. 232 | static constexpr size_t GetListSize(size_t count) 233 | { 234 | return GetHeaderSize() + sizeof(TypeItem) * count; 235 | } 236 | 237 | private: 238 | uint32_t size_; // size of the list, in entries 239 | TypeItem list_[1]; // elements of the list 240 | DISALLOW_COPY_AND_ASSIGN(TypeList); 241 | }; 242 | 243 | // Raw code_item. 244 | struct CodeItem 245 | { 246 | uint16_t registers_size_; 247 | uint16_t ins_size_; 248 | uint16_t outs_size_; 249 | uint16_t tries_size_; 250 | uint32_t debug_info_off_; // file offset to debug info stream 251 | uint32_t insns_size_in_code_units_; // size of the insns array, in 2 byte code units 252 | uint16_t insns_[1]; 253 | 254 | private: 255 | DISALLOW_COPY_AND_ASSIGN(CodeItem); 256 | }; 257 | 258 | // Raw try_item. 259 | struct TryItem 260 | { 261 | uint32_t start_addr_; 262 | uint16_t insn_count_; 263 | uint16_t handler_off_; 264 | 265 | private: 266 | DISALLOW_COPY_AND_ASSIGN(TryItem); 267 | }; 268 | 269 | // Annotation constants. 270 | enum 271 | { 272 | kDexVisibilityBuild = 0x00, /* annotation visibility */ 273 | kDexVisibilityRuntime = 0x01, 274 | kDexVisibilitySystem = 0x02, 275 | 276 | kDexAnnotationByte = 0x00, 277 | kDexAnnotationShort = 0x02, 278 | kDexAnnotationChar = 0x03, 279 | kDexAnnotationInt = 0x04, 280 | kDexAnnotationLong = 0x06, 281 | kDexAnnotationFloat = 0x10, 282 | kDexAnnotationDouble = 0x11, 283 | kDexAnnotationString = 0x17, 284 | kDexAnnotationType = 0x18, 285 | kDexAnnotationField = 0x19, 286 | kDexAnnotationMethod = 0x1a, 287 | kDexAnnotationEnum = 0x1b, 288 | kDexAnnotationArray = 0x1c, 289 | kDexAnnotationAnnotation = 0x1d, 290 | kDexAnnotationNull = 0x1e, 291 | kDexAnnotationBoolean = 0x1f, 292 | 293 | kDexAnnotationValueTypeMask = 0x1f, /* low 5 bits */ 294 | kDexAnnotationValueArgShift = 5, 295 | }; 296 | 297 | struct AnnotationsDirectoryItem 298 | { 299 | uint32_t class_annotations_off_; 300 | uint32_t fields_size_; 301 | uint32_t methods_size_; 302 | uint32_t parameters_size_; 303 | 304 | private: 305 | DISALLOW_COPY_AND_ASSIGN(AnnotationsDirectoryItem); 306 | }; 307 | 308 | struct FieldAnnotationsItem 309 | { 310 | uint32_t field_idx_; 311 | uint32_t annotations_off_; 312 | 313 | private: 314 | DISALLOW_COPY_AND_ASSIGN(FieldAnnotationsItem); 315 | }; 316 | 317 | struct MethodAnnotationsItem 318 | { 319 | uint32_t method_idx_; 320 | uint32_t annotations_off_; 321 | 322 | private: 323 | DISALLOW_COPY_AND_ASSIGN(MethodAnnotationsItem); 324 | }; 325 | 326 | struct ParameterAnnotationsItem 327 | { 328 | uint32_t method_idx_; 329 | uint32_t annotations_off_; 330 | 331 | private: 332 | DISALLOW_COPY_AND_ASSIGN(ParameterAnnotationsItem); 333 | }; 334 | 335 | struct AnnotationSetRefItem 336 | { 337 | uint32_t annotations_off_; 338 | 339 | private: 340 | DISALLOW_COPY_AND_ASSIGN(AnnotationSetRefItem); 341 | }; 342 | 343 | struct AnnotationSetRefList 344 | { 345 | uint32_t size_; 346 | AnnotationSetRefItem list_[1]; 347 | 348 | private: 349 | DISALLOW_COPY_AND_ASSIGN(AnnotationSetRefList); 350 | }; 351 | 352 | struct AnnotationSetItem 353 | { 354 | uint32_t size_; 355 | uint32_t entries_[1]; 356 | 357 | private: 358 | DISALLOW_COPY_AND_ASSIGN(AnnotationSetItem); 359 | }; 360 | 361 | struct AnnotationItem 362 | { 363 | uint8_t visibility_; 364 | uint8_t annotation_[1]; 365 | 366 | private: 367 | DISALLOW_COPY_AND_ASSIGN(AnnotationItem); 368 | }; 369 | 370 | 371 | ~DexFile(); 372 | 373 | // Opens a .dex file at the given memory address. 374 | static const DexFile* OpenMemory(ScopedMap& mem_map) 375 | { 376 | return OpenMemory(mem_map.GetBase(), mem_map.GetSize(), mem_map); 377 | } 378 | 379 | // Returns true if the byte string points to the magic value. 380 | static bool IsMagicValid(const byte* magic); 381 | 382 | // Returns true if the byte string after the magic is the correct value. 383 | static bool IsVersionValid(const byte* magic); 384 | 385 | /*------------------------------------------------------------------* 386 | * Functions for string_id_item Manipulation * 387 | *------------------------------------------------------------------*/ 388 | // Returns the number of string identifiers in the .dex file. 389 | size_t NumStringIds() const 390 | { 391 | CHECK(header_ != nullptr); 392 | return header_->string_ids_size_; 393 | } 394 | 395 | // Returns the StringId at the specified index. 396 | const StringId& GetStringId(uint32_t idx) const 397 | { 398 | CHECK_LT(idx, NumStringIds()); 399 | return string_ids_[idx]; 400 | } 401 | 402 | uint32_t GetIndexForStringId(const StringId& string_id) const 403 | { 404 | CHECK_GE(&string_id, string_ids_); 405 | CHECK_LT(&string_id, string_ids_ + header_->string_ids_size_); 406 | return &string_id - string_ids_; 407 | } 408 | 409 | int32_t GetStringLength(const StringId& string_id) const; 410 | 411 | // Returns a pointer to the UTF-8 string data referred to by the given 412 | // string_id as well as the length of the string when decoded as a UTF-16 413 | // string. Note the UTF-16 length is not the same as the string length of 414 | // the string data. 415 | const char* GetStringDataAndUtf16Length(const StringId& string_id, 416 | uint32_t* utf16_length) const; 417 | 418 | const char* GetStringData(const StringId& string_id) const 419 | { 420 | uint32_t ignored; 421 | return GetStringDataAndUtf16Length(string_id, &ignored); 422 | } 423 | 424 | // Index version of GetStringDataAndUtf16Length. 425 | const char* StringDataAndUtf16LengthByIdx(uint32_t idx, uint32_t* utf16_length) const 426 | { 427 | if (idx == kDexNoIndex) { 428 | *utf16_length = 0; 429 | return nullptr; 430 | } 431 | const StringId& string_id = GetStringId(idx); 432 | return GetStringDataAndUtf16Length(string_id, utf16_length); 433 | } 434 | 435 | const char* StringDataByIdx(uint32_t idx) const 436 | { 437 | uint32_t unicode_length; 438 | return StringDataAndUtf16LengthByIdx(idx, &unicode_length); 439 | } 440 | 441 | 442 | /*------------------------------------------------------------------* 443 | * Functions for type_id_item Manipulation * 444 | *------------------------------------------------------------------*/ 445 | // Returns the number of type identifiers in the .dex file. 446 | uint32_t NumTypeIds() const 447 | { 448 | CHECK(header_ != nullptr); 449 | return header_->type_ids_size_; 450 | } 451 | 452 | // Returns the TypeId at the specified index. 453 | const TypeId& GetTypeId(uint32_t idx) const 454 | { 455 | CHECK_LT(idx, NumTypeIds()); 456 | return type_ids_[idx]; 457 | } 458 | 459 | uint16_t GetIndexForTypeId(const TypeId& type_id) const 460 | { 461 | CHECK_GE(&type_id, type_ids_); 462 | CHECK_LT(&type_id, type_ids_ + header_->type_ids_size_); 463 | size_t result = &type_id - type_ids_; 464 | CHECK_LT(result, 65536U); 465 | return static_cast(result); 466 | } 467 | 468 | // Get the descriptor string associated with a given type index. 469 | const char* StringByTypeIdx(uint32_t idx, uint32_t* unicode_length) const 470 | { 471 | const TypeId& type_id = GetTypeId(idx); 472 | return StringDataAndUtf16LengthByIdx(type_id.descriptor_idx_, unicode_length); 473 | } 474 | 475 | const char* StringByTypeIdx(uint32_t idx) const 476 | { 477 | const TypeId& type_id = GetTypeId(idx); 478 | return StringDataByIdx(type_id.descriptor_idx_); 479 | } 480 | 481 | // Returns the type descriptor string of a type id. 482 | const char* GetTypeDescriptor(const TypeId& type_id) const 483 | { 484 | return StringDataByIdx(type_id.descriptor_idx_); 485 | } 486 | 487 | 488 | /*------------------------------------------------------------------* 489 | * Functions for field_id_item Manipulation * 490 | *------------------------------------------------------------------*/ 491 | // Returns the number of field identifiers in the .dex file. 492 | size_t NumFieldIds() const 493 | { 494 | CHECK(header_ != nullptr); 495 | return header_->field_ids_size_; 496 | } 497 | 498 | // Returns the FieldId at the specified index. 499 | const FieldId& GetFieldId(uint32_t idx) const 500 | { 501 | CHECK_LT(idx, NumFieldIds()); 502 | return field_ids_[idx]; 503 | } 504 | 505 | uint32_t GetIndexForFieldId(const FieldId& field_id) const 506 | { 507 | CHECK_GE(&field_id, field_ids_); 508 | CHECK_LT(&field_id, field_ids_ + header_->field_ids_size_); 509 | return &field_id - field_ids_; 510 | } 511 | 512 | // Returns the declaring class descriptor string of a field id. 513 | const char* GetFieldDeclaringClassDescriptor(const FieldId& field_id) const 514 | { 515 | const DexFile::TypeId& type_id = GetTypeId(field_id.class_idx_); 516 | return GetTypeDescriptor(type_id); 517 | } 518 | 519 | // Returns the class descriptor string of a field id. 520 | const char* GetFieldTypeDescriptor(const FieldId& field_id) const 521 | { 522 | const DexFile::TypeId& type_id = GetTypeId(field_id.type_idx_); 523 | return GetTypeDescriptor(type_id); 524 | } 525 | 526 | // Returns the name of a field id. 527 | const char* GetFieldName(const FieldId& field_id) const 528 | { 529 | return StringDataByIdx(field_id.name_idx_); 530 | } 531 | 532 | /*------------------------------------------------------------------* 533 | * Functions for method_id_item Manipulation * 534 | *------------------------------------------------------------------*/ 535 | // Returns the number of method identifiers in the .dex file. 536 | size_t NumMethodIds() const 537 | { 538 | CHECK(header_ != nullptr); 539 | return header_->method_ids_size_; 540 | } 541 | 542 | // Returns the MethodId at the specified index. 543 | const MethodId& GetMethodId(uint32_t idx) const 544 | { 545 | CHECK_LT(idx, NumMethodIds()); 546 | return method_ids_[idx]; 547 | } 548 | 549 | uint32_t GetIndexForMethodId(const MethodId& method_id) const 550 | { 551 | CHECK_GE(&method_id, method_ids_); 552 | CHECK_LT(&method_id, method_ids_ + header_->method_ids_size_); 553 | return &method_id - method_ids_; 554 | } 555 | 556 | // Returns the declaring class descriptor string of a method id. 557 | const char* GetMethodDeclaringClassDescriptor(const MethodId& method_id) const 558 | { 559 | const DexFile::TypeId& type_id = GetTypeId(method_id.class_idx_); 560 | return GetTypeDescriptor(type_id); 561 | } 562 | 563 | // Returns the prototype of a method id. 564 | const ProtoId& GetMethodPrototype(const MethodId& method_id) const 565 | { 566 | return GetProtoId(method_id.proto_idx_); 567 | } 568 | 569 | const Signature GetMethodSignature(const MethodId& method_id) const; 570 | 571 | // Returns the name of a method id. 572 | const char* GetMethodName(const MethodId& method_id) const 573 | { 574 | return StringDataByIdx(method_id.name_idx_); 575 | } 576 | 577 | // Returns the shorty of a method id. 578 | const char* GetMethodShorty(const MethodId& method_id) const 579 | { 580 | return StringDataByIdx(GetProtoId(method_id.proto_idx_).shorty_idx_); 581 | } 582 | 583 | const char* GetMethodShorty(const MethodId& method_id, uint32_t* length) const 584 | { 585 | // Using the UTF16 length is safe here as shorties are guaranteed to be ASCII characters. 586 | return StringDataAndUtf16LengthByIdx(GetProtoId(method_id.proto_idx_).shorty_idx_, length); 587 | } 588 | 589 | 590 | /*------------------------------------------------------------------* 591 | * Functions for class_def_item Manipulation * 592 | *------------------------------------------------------------------*/ 593 | // Returns the number of class definitions in the .dex file. 594 | uint32_t NumClassDefs() const 595 | { 596 | CHECK(header_ != nullptr); 597 | return header_->class_defs_size_; 598 | } 599 | 600 | // Returns the ClassDef at the specified index. 601 | const ClassDef& GetClassDef(uint16_t idx) const 602 | { 603 | CHECK_LT(idx, NumClassDefs()); 604 | return class_defs_[idx]; 605 | } 606 | 607 | uint16_t GetIndexForClassDef(const ClassDef& class_def) const 608 | { 609 | CHECK_GE(&class_def, class_defs_); 610 | CHECK_LT(&class_def, class_defs_ + header_->class_defs_size_); 611 | return &class_def - class_defs_; 612 | } 613 | 614 | // Returns the class descriptor string of a class definition. 615 | const char* GetClassDescriptor(const ClassDef& class_def) const 616 | { 617 | return StringByTypeIdx(class_def.class_idx_); 618 | } 619 | 620 | const TypeList* GetInterfacesList(const ClassDef& class_def) const 621 | { 622 | if (class_def.interfaces_off_ == 0) 623 | return nullptr; 624 | else { 625 | const byte* addr = begin_ + class_def.interfaces_off_; 626 | return reinterpret_cast(addr); 627 | } 628 | } 629 | 630 | 631 | /*------------------------------------------------------------------* 632 | * Functions for class_data_item and code_item Manipulation * 633 | *------------------------------------------------------------------*/ 634 | // Returns a pointer to the raw memory mapped class_data_item 635 | const byte* GetClassData(const ClassDef& class_def) const 636 | { 637 | if (class_def.class_data_off_ == 0) 638 | return nullptr; 639 | else 640 | return begin_ + class_def.class_data_off_; 641 | } 642 | 643 | const CodeItem* GetCodeItem(const uint32_t code_off) const 644 | { 645 | if (code_off == 0) 646 | return nullptr; // native or abstract method 647 | else { 648 | const byte* addr = begin_ + code_off; 649 | return reinterpret_cast(addr); 650 | } 651 | } 652 | 653 | 654 | /*------------------------------------------------------------------* 655 | * Functions for proto_id_item Manipulation * 656 | *------------------------------------------------------------------*/ 657 | const char* GetReturnTypeDescriptor(const ProtoId& proto_id) const 658 | { 659 | return StringByTypeIdx(proto_id.return_type_idx_); 660 | } 661 | 662 | // Returns the number of prototype identifiers in the .dex file. 663 | size_t NumProtoIds() const 664 | { 665 | CHECK(header_ != nullptr); 666 | return header_->proto_ids_size_; 667 | } 668 | 669 | // Returns the ProtoId at the specified index. 670 | const ProtoId& GetProtoId(uint32_t idx) const 671 | { 672 | CHECK_LT(idx, NumProtoIds()); 673 | return proto_ids_[idx]; 674 | } 675 | 676 | uint16_t GetIndexForProtoId(const ProtoId& proto_id) const 677 | { 678 | CHECK_GE(&proto_id, proto_ids_); 679 | CHECK_LT(&proto_id, proto_ids_ + header_->proto_ids_size_); 680 | return &proto_id - proto_ids_; 681 | } 682 | 683 | // Returns the short form method descriptor for the given prototype. 684 | const char* GetShorty(uint32_t proto_idx) const 685 | { 686 | const ProtoId& proto_id = GetProtoId(proto_idx); 687 | return StringDataByIdx(proto_id.shorty_idx_); 688 | } 689 | 690 | const TypeList* GetProtoParameters(const ProtoId& proto_id) const 691 | { 692 | if (proto_id.parameters_off_ == 0) 693 | return nullptr; 694 | else { 695 | const byte* addr = begin_ + proto_id.parameters_off_; 696 | return reinterpret_cast(addr); 697 | } 698 | } 699 | 700 | private: 701 | 702 | static const DexFile* OpenMemory(byte* base, size_t size, ScopedMap& mem_map); 703 | 704 | DexFile(byte* base, size_t size, ScopedMap& mem_map); 705 | 706 | // The base address of the memory mapping. 707 | const byte* const begin_; 708 | 709 | // The size of the underlying memory allocation in bytes. 710 | const size_t size_; 711 | 712 | // Manages the underlying memory allocation. 713 | ScopedMap mem_map_; 714 | 715 | // Points to the header section. 716 | const Header* const header_; 717 | 718 | // Points to the base of the string identifier list. 719 | const StringId* const string_ids_; 720 | 721 | // Points to the base of the type identifier list. 722 | const TypeId* const type_ids_; 723 | 724 | // Points to the base of the field identifier list. 725 | const FieldId* const field_ids_; 726 | 727 | // Points to the base of the method identifier list. 728 | const MethodId* const method_ids_; 729 | 730 | // Points to the base of the prototype identifier list. 731 | const ProtoId* const proto_ids_; 732 | 733 | // Points to the base of the class definition list. 734 | const ClassDef* const class_defs_; 735 | 736 | }; 737 | 738 | 739 | // Abstract the signature of a method. 740 | class Signature 741 | { 742 | public: 743 | std::string ToString() const; 744 | 745 | static Signature NoSignature() 746 | { 747 | return Signature(); 748 | } 749 | 750 | bool operator==(const Signature& rhs) const; 751 | bool operator!=(const Signature& rhs) const 752 | { 753 | return !(*this == rhs); 754 | } 755 | 756 | bool operator==(const StringPiece& rhs) const; 757 | 758 | private: 759 | Signature(const DexFile* dex, const DexFile::ProtoId& proto) 760 | : dex_file_(dex), proto_id_(&proto) 761 | {} 762 | 763 | Signature() 764 | : dex_file_(nullptr), proto_id_(nullptr) 765 | {} 766 | 767 | friend class DexFile; 768 | 769 | const DexFile* const dex_file_; 770 | const DexFile::ProtoId* const proto_id_; 771 | }; 772 | 773 | // Iterate and decode class_data_item. 774 | class ClassDataItemIterator 775 | { 776 | public: 777 | ClassDataItemIterator(const DexFile& dex_file, const byte* raw_class_data_item) 778 | : dex_file_(dex_file), pos_(0), ptr_pos_(raw_class_data_item), last_idx_(0) 779 | { 780 | ReadClassDataHeader(); 781 | if (EndOfInstanceFieldsPos() > 0) 782 | ReadClassDataField(); 783 | else if (EndOfVirtualMethodsPos() > 0) 784 | ReadClassDataMethod(); 785 | } 786 | 787 | uint32_t NumStaticFields() const 788 | { 789 | return header_.static_fields_size_; 790 | } 791 | 792 | uint32_t NumInstanceFields() const 793 | { 794 | return header_.instance_fields_size_; 795 | } 796 | 797 | uint32_t NumDirectMethods() const 798 | { 799 | return header_.direct_methods_size_; 800 | } 801 | 802 | uint32_t NumVirtualMethods() const 803 | { 804 | return header_.virtual_methods_size_; 805 | } 806 | 807 | bool HasNextStaticField() const 808 | { 809 | return pos_ < EndOfStaticFieldsPos(); 810 | } 811 | 812 | bool HasNextInstanceField() const 813 | { 814 | return pos_ >= EndOfStaticFieldsPos() && pos_ < EndOfInstanceFieldsPos(); 815 | } 816 | 817 | bool HasNextDirectMethod() const 818 | { 819 | return pos_ >= EndOfInstanceFieldsPos() && pos_ < EndOfDirectMethodsPos(); 820 | } 821 | 822 | bool HasNextVirtualMethod() const 823 | { 824 | return pos_ >= EndOfDirectMethodsPos() && pos_ < EndOfVirtualMethodsPos(); 825 | } 826 | 827 | bool HasNext() const 828 | { 829 | return pos_ < EndOfVirtualMethodsPos(); 830 | } 831 | 832 | inline void Next() 833 | { 834 | pos_++; 835 | if (pos_ < EndOfStaticFieldsPos()) { 836 | last_idx_ = GetMemberIndex(); 837 | ReadClassDataField(); 838 | } else if (pos_ == EndOfStaticFieldsPos() && NumInstanceFields() > 0) { 839 | last_idx_ = 0; // transition to next array, reset last index 840 | ReadClassDataField(); 841 | } else if (pos_ < EndOfInstanceFieldsPos()) { 842 | last_idx_ = GetMemberIndex(); 843 | ReadClassDataField(); 844 | } else if (pos_ == EndOfInstanceFieldsPos() && NumDirectMethods() > 0) { 845 | last_idx_ = 0; // transition to next array, reset last index 846 | ReadClassDataMethod(); 847 | } else if (pos_ < EndOfDirectMethodsPos()) { 848 | last_idx_ = GetMemberIndex(); 849 | ReadClassDataMethod(); 850 | } else if (pos_ == EndOfDirectMethodsPos() && NumVirtualMethods() > 0) { 851 | last_idx_ = 0; // transition to next array, reset last index 852 | ReadClassDataMethod(); 853 | } else if (pos_ < EndOfVirtualMethodsPos()) { 854 | last_idx_ = GetMemberIndex(); 855 | ReadClassDataMethod(); 856 | } else 857 | CHECK(!HasNext()); 858 | } 859 | 860 | uint32_t GetMemberIndex() const 861 | { 862 | if (pos_ < EndOfInstanceFieldsPos()) 863 | return last_idx_ + field_.field_idx_delta_; 864 | else { 865 | CHECK_LT(pos_, EndOfVirtualMethodsPos()); 866 | return last_idx_ + method_.method_idx_delta_; 867 | } 868 | } 869 | 870 | uint32_t GetRawMemberAccessFlags() const 871 | { 872 | if (pos_ < EndOfInstanceFieldsPos()) { 873 | return field_.access_flags_; 874 | } else { 875 | CHECK_LT(pos_, EndOfVirtualMethodsPos()); 876 | return method_.access_flags_; 877 | } 878 | } 879 | 880 | uint32_t GetFieldAccessFlags() const 881 | { 882 | return GetRawMemberAccessFlags() & kAccValidFieldFlags; 883 | } 884 | 885 | uint32_t GetMethodAccessFlags() const 886 | { 887 | return GetRawMemberAccessFlags() & kAccValidMethodFlags; 888 | } 889 | 890 | bool MemberIsNative() const 891 | { 892 | return GetRawMemberAccessFlags() & kAccNative; 893 | } 894 | 895 | bool MemberIsFinal() const 896 | { 897 | return GetRawMemberAccessFlags() & kAccFinal; 898 | } 899 | 900 | InvokeType GetMethodInvokeType(const DexFile::ClassDef& class_def) const 901 | { 902 | if (HasNextDirectMethod()) { 903 | if ((GetRawMemberAccessFlags() & kAccStatic) != 0) 904 | return kStatic; 905 | else 906 | return kDirect; 907 | } else { 908 | CHECK_EQ(GetRawMemberAccessFlags() & kAccStatic, 0U); 909 | if ((class_def.access_flags_ & kAccInterface) != 0) 910 | return kInterface; 911 | else if ((GetRawMemberAccessFlags() & kAccConstructor) != 0) 912 | return kSuper; 913 | else 914 | return kVirtual; 915 | } 916 | } 917 | 918 | const DexFile::CodeItem* GetMethodCodeItem() const 919 | { 920 | return dex_file_.GetCodeItem(method_.code_off_); 921 | } 922 | 923 | uint32_t GetMethodCodeItemOffset() const 924 | { 925 | return method_.code_off_; 926 | } 927 | 928 | const byte* EndDataPointer() const 929 | { 930 | CHECK(!HasNext()); 931 | return ptr_pos_; 932 | } 933 | 934 | private: 935 | 936 | // A dex file's class_data_item is leb128 encoded, this structure holds a 937 | // decoded form of the header for a class_data_item. 938 | struct ClassDataHeader 939 | { 940 | uint32_t static_fields_size_; // the number of static fields 941 | uint32_t instance_fields_size_; // the number of instance fields 942 | uint32_t direct_methods_size_; // the number of direct methods 943 | uint32_t virtual_methods_size_; // the number of virtual methods 944 | } header_; 945 | 946 | // Read and decode header from a class_data_item stream into header. 947 | void ReadClassDataHeader(); 948 | 949 | uint32_t EndOfStaticFieldsPos() const 950 | { 951 | return header_.static_fields_size_; 952 | } 953 | 954 | uint32_t EndOfInstanceFieldsPos() const 955 | { 956 | return EndOfStaticFieldsPos() + header_.instance_fields_size_; 957 | } 958 | 959 | uint32_t EndOfDirectMethodsPos() const 960 | { 961 | return EndOfInstanceFieldsPos() + header_.direct_methods_size_; 962 | } 963 | 964 | uint32_t EndOfVirtualMethodsPos() const 965 | { 966 | return EndOfDirectMethodsPos() + header_.virtual_methods_size_; 967 | } 968 | 969 | // A decoded version of the field of a class_data_item. 970 | struct ClassDataField 971 | { 972 | uint32_t field_idx_delta_; // delta of index into the field_ids array for FieldId 973 | uint32_t access_flags_; // access flags for the field 974 | 975 | ClassDataField() 976 | : field_idx_delta_(0), access_flags_(0) 977 | {} 978 | 979 | private: 980 | DISALLOW_COPY_AND_ASSIGN(ClassDataField); 981 | }; 982 | ClassDataField field_; 983 | 984 | // Read and decode a field from a class_data_item stream into field 985 | void ReadClassDataField(); 986 | 987 | // A decoded version of the method of a class_data_item. 988 | struct ClassDataMethod 989 | { 990 | uint32_t method_idx_delta_; // delta of index into the method_ids array for MethodId 991 | uint32_t access_flags_; 992 | uint32_t code_off_; 993 | 994 | ClassDataMethod() 995 | : method_idx_delta_(0), access_flags_(0), code_off_(0) 996 | {} 997 | 998 | private: 999 | DISALLOW_COPY_AND_ASSIGN(ClassDataMethod); 1000 | }; 1001 | ClassDataMethod method_; 1002 | 1003 | // Read and decode a method from a class_data_item stream into method 1004 | void ReadClassDataMethod(); 1005 | 1006 | const DexFile& dex_file_; 1007 | size_t pos_; // integral number of items passed 1008 | const byte* ptr_pos_; // pointer into stream of class_data_item 1009 | uint32_t last_idx_; // last read field or method index to apply delta to 1010 | DISALLOW_IMPLICIT_CONSTRUCTORS(ClassDataItemIterator); 1011 | }; 1012 | 1013 | #endif -------------------------------------------------------------------------------- /engine/dumper/dex_instruction-inl.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _ART_DEX_INSTRUCTION_INL_H_ 3 | #define _ART_DEX_INSTRUCTION_INL_H_ 4 | 5 | 6 | #include "dex_instruction.h" 7 | 8 | 9 | //------------------------------------------------------------------------------ 10 | // VRegA 11 | //------------------------------------------------------------------------------ 12 | inline bool Instruction::HasVRegA() const 13 | { 14 | switch (FormatOf(Opcode())) { 15 | case k10t: return true; 16 | case k10x: return true; 17 | case k11n: return true; 18 | case k11x: return true; 19 | case k12x: return true; 20 | case k20t: return true; 21 | case k21c: return true; 22 | case k21h: return true; 23 | case k21s: return true; 24 | case k21t: return true; 25 | case k22b: return true; 26 | case k22c: return true; 27 | case k22s: return true; 28 | case k22t: return true; 29 | case k22x: return true; 30 | case k23x: return true; 31 | case k30t: return true; 32 | case k31c: return true; 33 | case k31i: return true; 34 | case k31t: return true; 35 | case k32x: return true; 36 | case k35c: return true; 37 | case k3rc: return true; 38 | case k51l: return true; 39 | default: return false; 40 | } 41 | } 42 | 43 | inline int32_t Instruction::VRegA() const 44 | { 45 | switch (FormatOf(Opcode())) { 46 | case k10t: return VRegA_10t(); 47 | case k10x: return VRegA_10x(); 48 | case k11n: return VRegA_11n(); 49 | case k11x: return VRegA_11x(); 50 | case k12x: return VRegA_12x(); 51 | case k20t: return VRegA_20t(); 52 | case k21c: return VRegA_21c(); 53 | case k21h: return VRegA_21h(); 54 | case k21s: return VRegA_21s(); 55 | case k21t: return VRegA_21t(); 56 | case k22b: return VRegA_22b(); 57 | case k22c: return VRegA_22c(); 58 | case k22s: return VRegA_22s(); 59 | case k22t: return VRegA_22t(); 60 | case k22x: return VRegA_22x(); 61 | case k23x: return VRegA_23x(); 62 | case k30t: return VRegA_30t(); 63 | case k31c: return VRegA_31c(); 64 | case k31i: return VRegA_31i(); 65 | case k31t: return VRegA_31t(); 66 | case k32x: return VRegA_32x(); 67 | case k35c: return VRegA_35c(); 68 | case k3rc: return VRegA_3rc(); 69 | case k51l: return VRegA_51l(); 70 | default: 71 | LOG(FATAL) << "Tried to access vA of instruction " << Name() 72 | << " which has no A operand."; 73 | } 74 | } 75 | 76 | inline int8_t Instruction::VRegA_10t(uint16_t inst_data) const 77 | { 78 | CHECK_EQ(FormatOf(Opcode()), k10t); 79 | return static_cast(InstAA(inst_data)); 80 | } 81 | 82 | inline uint8_t Instruction::VRegA_10x(uint16_t inst_data) const 83 | { 84 | CHECK_EQ(FormatOf(Opcode()), k10x); 85 | return InstAA(inst_data); 86 | } 87 | 88 | inline uint4_t Instruction::VRegA_11n(uint16_t inst_data) const 89 | { 90 | CHECK_EQ(FormatOf(Opcode()), k11n); 91 | return InstA(inst_data); 92 | } 93 | 94 | inline uint8_t Instruction::VRegA_11x(uint16_t inst_data) const 95 | { 96 | CHECK_EQ(FormatOf(Opcode()), k11x); 97 | return InstAA(inst_data); 98 | } 99 | 100 | inline uint4_t Instruction::VRegA_12x(uint16_t inst_data) const 101 | { 102 | CHECK_EQ(FormatOf(Opcode()), k12x); 103 | return InstA(inst_data); 104 | } 105 | 106 | inline int16_t Instruction::VRegA_20t() const 107 | { 108 | CHECK_EQ(FormatOf(Opcode()), k20t); 109 | return static_cast(Fetch16(1)); 110 | } 111 | 112 | inline uint8_t Instruction::VRegA_21c(uint16_t inst_data) const 113 | { 114 | CHECK_EQ(FormatOf(Opcode()), k21c); 115 | return InstAA(inst_data); 116 | } 117 | 118 | inline uint8_t Instruction::VRegA_21h(uint16_t inst_data) const 119 | { 120 | CHECK_EQ(FormatOf(Opcode()), k21h); 121 | return InstAA(inst_data); 122 | } 123 | 124 | inline uint8_t Instruction::VRegA_21s(uint16_t inst_data) const 125 | { 126 | CHECK_EQ(FormatOf(Opcode()), k21s); 127 | return InstAA(inst_data); 128 | } 129 | 130 | inline uint8_t Instruction::VRegA_21t(uint16_t inst_data) const 131 | { 132 | CHECK_EQ(FormatOf(Opcode()), k21t); 133 | return InstAA(inst_data); 134 | } 135 | 136 | inline uint8_t Instruction::VRegA_22b(uint16_t inst_data) const 137 | { 138 | CHECK_EQ(FormatOf(Opcode()), k22b); 139 | return InstAA(inst_data); 140 | } 141 | 142 | inline uint4_t Instruction::VRegA_22c(uint16_t inst_data) const 143 | { 144 | CHECK_EQ(FormatOf(Opcode()), k22c); 145 | return InstA(inst_data); 146 | } 147 | 148 | inline uint4_t Instruction::VRegA_22s(uint16_t inst_data) const 149 | { 150 | CHECK_EQ(FormatOf(Opcode()), k22s); 151 | return InstA(inst_data); 152 | } 153 | 154 | inline uint4_t Instruction::VRegA_22t(uint16_t inst_data) const 155 | { 156 | CHECK_EQ(FormatOf(Opcode()), k22t); 157 | return InstA(inst_data); 158 | } 159 | 160 | inline uint8_t Instruction::VRegA_22x(uint16_t inst_data) const 161 | { 162 | CHECK_EQ(FormatOf(Opcode()), k22x); 163 | return InstAA(inst_data); 164 | } 165 | 166 | inline uint8_t Instruction::VRegA_23x(uint16_t inst_data) const 167 | { 168 | CHECK_EQ(FormatOf(Opcode()), k23x); 169 | return InstAA(inst_data); 170 | } 171 | 172 | inline int32_t Instruction::VRegA_30t() const 173 | { 174 | CHECK_EQ(FormatOf(Opcode()), k30t); 175 | return static_cast(Fetch32(1)); 176 | } 177 | 178 | inline uint8_t Instruction::VRegA_31c(uint16_t inst_data) const 179 | { 180 | CHECK_EQ(FormatOf(Opcode()), k31c); 181 | return InstAA(inst_data); 182 | } 183 | 184 | inline uint8_t Instruction::VRegA_31i(uint16_t inst_data) const 185 | { 186 | CHECK_EQ(FormatOf(Opcode()), k31i); 187 | return InstAA(inst_data); 188 | } 189 | 190 | inline uint8_t Instruction::VRegA_31t(uint16_t inst_data) const 191 | { 192 | CHECK_EQ(FormatOf(Opcode()), k31t); 193 | return InstAA(inst_data); 194 | } 195 | 196 | inline uint16_t Instruction::VRegA_32x() const 197 | { 198 | CHECK_EQ(FormatOf(Opcode()), k32x); 199 | return Fetch16(1); 200 | } 201 | 202 | inline uint4_t Instruction::VRegA_35c(uint16_t inst_data) const 203 | { 204 | CHECK_EQ(FormatOf(Opcode()), k35c); 205 | return InstB(inst_data); // This is labeled A in the spec. 206 | } 207 | 208 | inline uint8_t Instruction::VRegA_3rc(uint16_t inst_data) const 209 | { 210 | CHECK_EQ(FormatOf(Opcode()), k3rc); 211 | return InstAA(inst_data); 212 | } 213 | 214 | inline uint8_t Instruction::VRegA_51l(uint16_t inst_data) const 215 | { 216 | CHECK_EQ(FormatOf(Opcode()), k51l); 217 | return InstAA(inst_data); 218 | } 219 | 220 | //------------------------------------------------------------------------------ 221 | // VRegB 222 | //------------------------------------------------------------------------------ 223 | inline bool Instruction::HasVRegB() const 224 | { 225 | switch (FormatOf(Opcode())) { 226 | case k11n: return true; 227 | case k12x: return true; 228 | case k21c: return true; 229 | case k21h: return true; 230 | case k21s: return true; 231 | case k21t: return true; 232 | case k22b: return true; 233 | case k22c: return true; 234 | case k22s: return true; 235 | case k22t: return true; 236 | case k22x: return true; 237 | case k23x: return true; 238 | case k31c: return true; 239 | case k31i: return true; 240 | case k31t: return true; 241 | case k32x: return true; 242 | case k35c: return true; 243 | case k3rc: return true; 244 | case k51l: return true; 245 | default: return false; 246 | } 247 | } 248 | 249 | inline bool Instruction::HasWideVRegB() const 250 | { 251 | return FormatOf(Opcode()), k51l; 252 | } 253 | 254 | inline int32_t Instruction::VRegB() const 255 | { 256 | switch (FormatOf(Opcode())) { 257 | case k11n: return VRegB_11n(); 258 | case k12x: return VRegB_12x(); 259 | case k21c: return VRegB_21c(); 260 | case k21h: return VRegB_21h(); 261 | case k21s: return VRegB_21s(); 262 | case k21t: return VRegB_21t(); 263 | case k22b: return VRegB_22b(); 264 | case k22c: return VRegB_22c(); 265 | case k22s: return VRegB_22s(); 266 | case k22t: return VRegB_22t(); 267 | case k22x: return VRegB_22x(); 268 | case k23x: return VRegB_23x(); 269 | case k31c: return VRegB_31c(); 270 | case k31i: return VRegB_31i(); 271 | case k31t: return VRegB_31t(); 272 | case k32x: return VRegB_32x(); 273 | case k35c: return VRegB_35c(); 274 | case k3rc: return VRegB_3rc(); 275 | case k51l: return VRegB_51l(); 276 | default: 277 | LOG(FATAL) << "Tried to access vB of instruction " << Name() 278 | << " which has no B operand."; 279 | } 280 | } 281 | 282 | inline uint64_t Instruction::WideVRegB() const 283 | { 284 | return VRegB_51l(); 285 | } 286 | 287 | inline int4_t Instruction::VRegB_11n(uint16_t inst_data) const 288 | { 289 | CHECK_EQ(FormatOf(Opcode()), k11n); 290 | return static_cast((InstB(inst_data) << 28) >> 28); 291 | } 292 | 293 | inline uint4_t Instruction::VRegB_12x(uint16_t inst_data) const 294 | { 295 | CHECK_EQ(FormatOf(Opcode()), k12x); 296 | return InstB(inst_data); 297 | } 298 | 299 | inline uint16_t Instruction::VRegB_21c() const 300 | { 301 | CHECK_EQ(FormatOf(Opcode()), k21c); 302 | return Fetch16(1); 303 | } 304 | 305 | inline uint16_t Instruction::VRegB_21h() const 306 | { 307 | CHECK_EQ(FormatOf(Opcode()), k21h); 308 | return Fetch16(1); 309 | } 310 | 311 | inline int16_t Instruction::VRegB_21s() const 312 | { 313 | CHECK_EQ(FormatOf(Opcode()), k21s); 314 | return static_cast(Fetch16(1)); 315 | } 316 | 317 | inline int16_t Instruction::VRegB_21t() const 318 | { 319 | CHECK_EQ(FormatOf(Opcode()), k21t); 320 | return static_cast(Fetch16(1)); 321 | } 322 | 323 | inline uint8_t Instruction::VRegB_22b() const 324 | { 325 | CHECK_EQ(FormatOf(Opcode()), k22b); 326 | return static_cast(Fetch16(1) & 0xff); 327 | } 328 | 329 | inline uint4_t Instruction::VRegB_22c(uint16_t inst_data) const 330 | { 331 | CHECK_EQ(FormatOf(Opcode()), k22c); 332 | return InstB(inst_data); 333 | } 334 | 335 | inline uint4_t Instruction::VRegB_22s(uint16_t inst_data) const 336 | { 337 | CHECK_EQ(FormatOf(Opcode()), k22s); 338 | return InstB(inst_data); 339 | } 340 | 341 | inline uint4_t Instruction::VRegB_22t(uint16_t inst_data) const 342 | { 343 | CHECK_EQ(FormatOf(Opcode()), k22t); 344 | return InstB(inst_data); 345 | } 346 | 347 | inline uint16_t Instruction::VRegB_22x() const 348 | { 349 | CHECK_EQ(FormatOf(Opcode()), k22x); 350 | return Fetch16(1); 351 | } 352 | 353 | inline uint8_t Instruction::VRegB_23x() const 354 | { 355 | CHECK_EQ(FormatOf(Opcode()), k23x); 356 | return static_cast(Fetch16(1) & 0xff); 357 | } 358 | 359 | inline uint32_t Instruction::VRegB_31c() const 360 | { 361 | CHECK_EQ(FormatOf(Opcode()), k31c); 362 | return Fetch32(1); 363 | } 364 | 365 | inline int32_t Instruction::VRegB_31i() const 366 | { 367 | CHECK_EQ(FormatOf(Opcode()), k31i); 368 | return static_cast(Fetch32(1)); 369 | } 370 | 371 | inline int32_t Instruction::VRegB_31t() const 372 | { 373 | CHECK_EQ(FormatOf(Opcode()), k31t); 374 | return static_cast(Fetch32(1)); 375 | } 376 | 377 | inline uint16_t Instruction::VRegB_32x() const 378 | { 379 | CHECK_EQ(FormatOf(Opcode()), k32x); 380 | return Fetch16(2); 381 | } 382 | 383 | inline uint16_t Instruction::VRegB_35c() const 384 | { 385 | CHECK_EQ(FormatOf(Opcode()), k35c); 386 | return Fetch16(1); 387 | } 388 | 389 | inline uint16_t Instruction::VRegB_3rc() const 390 | { 391 | CHECK_EQ(FormatOf(Opcode()), k3rc); 392 | return Fetch16(1); 393 | } 394 | 395 | inline uint64_t Instruction::VRegB_51l() const 396 | { 397 | CHECK_EQ(FormatOf(Opcode()), k51l); 398 | uint64_t vB_wide = Fetch32(1) | ((uint64_t) Fetch32(3) << 32); 399 | return vB_wide; 400 | } 401 | 402 | //------------------------------------------------------------------------------ 403 | // VRegC 404 | //------------------------------------------------------------------------------ 405 | inline bool Instruction::HasVRegC() const 406 | { 407 | switch (FormatOf(Opcode())) { 408 | case k22b: return true; 409 | case k22c: return true; 410 | case k22s: return true; 411 | case k22t: return true; 412 | case k23x: return true; 413 | case k35c: return true; 414 | case k3rc: return true; 415 | default: return false; 416 | } 417 | } 418 | 419 | inline int32_t Instruction::VRegC() const 420 | { 421 | switch (FormatOf(Opcode())) { 422 | case k22b: return VRegC_22b(); 423 | case k22c: return VRegC_22c(); 424 | case k22s: return VRegC_22s(); 425 | case k22t: return VRegC_22t(); 426 | case k23x: return VRegC_23x(); 427 | case k35c: return VRegC_35c(); 428 | case k3rc: return VRegC_3rc(); 429 | default: 430 | LOG(FATAL) << "Tried to access vC of instruction " << Name() 431 | << " which has no C operand."; 432 | } 433 | } 434 | 435 | inline int8_t Instruction::VRegC_22b() const 436 | { 437 | CHECK_EQ(FormatOf(Opcode()), k22b); 438 | return static_cast(Fetch16(1) >> 8); 439 | } 440 | 441 | inline uint16_t Instruction::VRegC_22c() const 442 | { 443 | CHECK_EQ(FormatOf(Opcode()), k22c); 444 | return Fetch16(1); 445 | } 446 | 447 | inline int16_t Instruction::VRegC_22s() const 448 | { 449 | CHECK_EQ(FormatOf(Opcode()), k22s); 450 | return static_cast(Fetch16(1)); 451 | } 452 | 453 | inline int16_t Instruction::VRegC_22t() const 454 | { 455 | CHECK_EQ(FormatOf(Opcode()), k22t); 456 | return static_cast(Fetch16(1)); 457 | } 458 | 459 | inline uint8_t Instruction::VRegC_23x() const 460 | { 461 | CHECK_EQ(FormatOf(Opcode()), k23x); 462 | return static_cast(Fetch16(1) >> 8); 463 | } 464 | 465 | inline uint4_t Instruction::VRegC_35c() const 466 | { 467 | CHECK_EQ(FormatOf(Opcode()), k35c); 468 | return static_cast(Fetch16(2) & 0x0f); 469 | } 470 | 471 | inline uint16_t Instruction::VRegC_3rc() const 472 | { 473 | CHECK_EQ(FormatOf(Opcode()), k3rc); 474 | return Fetch16(2); 475 | } 476 | 477 | inline bool Instruction::HasVarArgs() const 478 | { 479 | return FormatOf(Opcode()), k35c; 480 | } 481 | 482 | inline void Instruction::GetVarArgs(uint32_t arg[5], uint16_t inst_data) const 483 | { 484 | CHECK_EQ(FormatOf(Opcode()), k35c); 485 | 486 | /* 487 | * Note that the fields mentioned in the spec don't appear in 488 | * their "usual" positions here compared to most formats. This 489 | * was done so that the field names for the argument count and 490 | * reference index match between this format and the corresponding 491 | * range formats (3rc and friends). 492 | * 493 | * Bottom line: The argument count is always in vA, and the 494 | * method constant (or equivalent) is always in vB. 495 | */ 496 | uint16_t regList = Fetch16(2); 497 | uint4_t count = InstB(inst_data); // This is labeled A in the spec. 498 | CHECK_LE(count, 5U) << "Invalid arg count in 35c (" << count << ")"; 499 | 500 | /* 501 | * Copy the argument registers into the arg[] array, and 502 | * also copy the first argument (if any) into vC. (The 503 | * DecodedInstruction structure doesn't have separate 504 | * fields for {vD, vE, vF, vG}, so there's no need to make 505 | * copies of those.) Note that cases 5..2 fall through. 506 | */ 507 | switch (count) { 508 | case 5: arg[4] = InstA(inst_data); 509 | case 4: arg[3] = (regList >> 12) & 0x0f; 510 | case 3: arg[2] = (regList >> 8) & 0x0f; 511 | case 2: arg[1] = (regList >> 4) & 0x0f; 512 | case 1: arg[0] = regList & 0x0f; break; 513 | default: // case 0 514 | break; // Valid, but no need to do anything. 515 | } 516 | } 517 | 518 | #endif 519 | -------------------------------------------------------------------------------- /engine/dumper/dex_instruction.cc: -------------------------------------------------------------------------------- 1 | 2 | #include "misc.h" 3 | #include "stringprintf.h" 4 | #include "log.h" 5 | #include "dex_instruction-inl.h" 6 | #include "dex_file.h" 7 | 8 | 9 | const char* const Instruction::kInstructionNames[] = 10 | { 11 | #define INSTRUCTION_NAME(o, c, pname, f, r, i, a, v) pname, 12 | #include "dex_instruction_list.h" 13 | DEX_INSTRUCTION_LIST(INSTRUCTION_NAME) 14 | #undef DEX_INSTRUCTION_LIST 15 | #undef INSTRUCTION_NAME 16 | }; 17 | 18 | Instruction::Format const Instruction::kInstructionFormats[] = 19 | { 20 | #define INSTRUCTION_FORMAT(o, c, p, format, r, i, a, v) format, 21 | #include "dex_instruction_list.h" 22 | DEX_INSTRUCTION_LIST(INSTRUCTION_FORMAT) 23 | #undef DEX_INSTRUCTION_LIST 24 | #undef INSTRUCTION_FORMAT 25 | }; 26 | 27 | int const Instruction::kInstructionFlags[] = 28 | { 29 | #define INSTRUCTION_FLAGS(o, c, p, f, r, i, flags, v) flags, 30 | #include "dex_instruction_list.h" 31 | DEX_INSTRUCTION_LIST(INSTRUCTION_FLAGS) 32 | #undef DEX_INSTRUCTION_LIST 33 | #undef INSTRUCTION_FLAGS 34 | }; 35 | 36 | int const Instruction::kInstructionVerifyFlags[] = 37 | { 38 | #define INSTRUCTION_VERIFY_FLAGS(o, c, p, f, r, i, a, vflags) vflags, 39 | #include "dex_instruction_list.h" 40 | DEX_INSTRUCTION_LIST(INSTRUCTION_VERIFY_FLAGS) 41 | #undef DEX_INSTRUCTION_LIST 42 | #undef INSTRUCTION_VERIFY_FLAGS 43 | }; 44 | 45 | int const Instruction::kInstructionSizeInCodeUnits[] = 46 | { 47 | #define INSTRUCTION_SIZE(opcode, c, p, format, r, i, a, v) \ 48 | ((opcode == NOP) ? -1 : \ 49 | ((format >= k10x) && (format <= k10t)) ? 1 : \ 50 | ((format >= k20t) && (format <= k22c)) ? 2 : \ 51 | ((format >= k32x) && (format <= k3rc)) ? 3 : \ 52 | (format == k51l) ? 5 : -1), 53 | #include "dex_instruction_list.h" 54 | DEX_INSTRUCTION_LIST(INSTRUCTION_SIZE) 55 | #undef DEX_INSTRUCTION_LIST 56 | #undef INSTRUCTION_SIZE 57 | }; 58 | 59 | int32_t Instruction::GetTargetOffset() const 60 | { 61 | switch (FormatOf(Opcode())) { 62 | // Cases for conditional branches follow. 63 | case k22t: return VRegC_22t(); 64 | case k21t: return VRegB_21t(); 65 | // Cases for unconditional branches follow. 66 | case k10t: return VRegA_10t(); 67 | case k20t: return VRegA_20t(); 68 | case k30t: return VRegA_30t(); 69 | default: 70 | LOG(FATAL) << "Tried to access the branch offset of an instruction " << 71 | Name() << " which does not have a target operand."; 72 | } 73 | return 0; 74 | } 75 | 76 | bool Instruction::CanFlowThrough() const 77 | { 78 | const uint16_t* insns = reinterpret_cast(this); 79 | uint16_t insn = *insns; 80 | Code opcode = static_cast(insn & 0xFF); 81 | return FlagsOf(opcode) & Instruction::kContinue; 82 | } 83 | 84 | size_t Instruction::SizeInCodeUnitsComplexOpcode() const 85 | { 86 | const uint16_t* insns = reinterpret_cast(this); 87 | // Handle special NOP encoded variable length sequences. 88 | switch (*insns) { 89 | case kPackedSwitchSignature: 90 | return (4 + insns[1] * 2); 91 | case kSparseSwitchSignature: 92 | return (2 + insns[1] * 4); 93 | case kArrayDataSignature: { 94 | uint16_t element_size = insns[1]; 95 | uint32_t length = insns[2] | (((uint32_t)insns[3]) << 16); 96 | // The plus 1 is to round up for odd size and width. 97 | return (4 + (element_size * length + 1) / 2); 98 | } 99 | default: 100 | if ((*insns & 0xFF) == 0) 101 | return 1; // NOP. 102 | else { 103 | LOG(FATAL) << "Unreachable: " << DumpString(NULL); 104 | return 0; 105 | } 106 | } 107 | } 108 | 109 | std::string Instruction::DumpHex(size_t code_units) const 110 | { 111 | size_t inst_length = SizeInCodeUnits(); 112 | if (inst_length > code_units) 113 | inst_length = code_units; 114 | 115 | std::ostringstream os; 116 | const uint16_t* insn = reinterpret_cast(this); 117 | for (size_t i = 0; i < inst_length; i++) 118 | os << StringPrintf("0x%04x", insn[i]) << " "; 119 | for (size_t i = inst_length; i < code_units; i++) 120 | os << " "; 121 | return os.str(); 122 | } 123 | 124 | std::string Instruction::DumpString(const DexFile* file) const 125 | { 126 | std::ostringstream os; 127 | const char* opcode = kInstructionNames[Opcode()]; 128 | switch (FormatOf(Opcode())) { 129 | case k10x: os << opcode; break; 130 | case k12x: os << StringPrintf("%s v%d, v%d", opcode, VRegA_12x(), VRegB_12x()); break; 131 | case k11n: os << StringPrintf("%s v%d, #%+d", opcode, VRegA_11n(), VRegB_11n()); break; 132 | case k11x: os << StringPrintf("%s v%d", opcode, VRegA_11x()); break; 133 | case k10t: os << StringPrintf("%s %+d", opcode, VRegA_10t()); break; 134 | case k20t: os << StringPrintf("%s %+d", opcode, VRegA_20t()); break; 135 | case k22x: os << StringPrintf("%s v%d, v%d", opcode, VRegA_22x(), VRegB_22x()); break; 136 | case k21t: os << StringPrintf("%s v%d, %+d", opcode, VRegA_21t(), VRegB_21t()); break; 137 | case k21s: os << StringPrintf("%s v%d, #%+d", opcode, VRegA_21s(), VRegB_21s()); break; 138 | case k21h: { 139 | // op vAA, #+BBBB0000[00000000] 140 | if (Opcode() == CONST_HIGH16) { 141 | uint32_t value = VRegB_21h() << 16; 142 | os << StringPrintf("%s v%d, #int %+d // 0x%x", opcode, VRegA_21h(), value, value); 143 | } else { 144 | uint64_t value = static_cast(VRegB_21h()) << 48; 145 | os << StringPrintf("%s v%d, #long %+" PRId64 " // 0x%" PRIx64, opcode, VRegA_21h(), 146 | value, value); 147 | } 148 | } 149 | break; 150 | case k21c: { 151 | switch (Opcode()) { 152 | case CONST_STRING: 153 | if (file != NULL) { 154 | uint32_t string_idx = VRegB_21c(); 155 | os << StringPrintf("const-string v%d, %s // string@%d", VRegA_21c(), 156 | PrintableString(file->StringDataByIdx(string_idx)).c_str(), string_idx); 157 | break; 158 | } // else fall-through 159 | case CHECK_CAST: 160 | case CONST_CLASS: 161 | case NEW_INSTANCE: 162 | if (file != NULL) { 163 | uint32_t type_idx = VRegB_21c(); 164 | os << opcode << " v" << static_cast(VRegA_21c()) << ", " << PrettyType(type_idx, *file) 165 | << " // type@" << type_idx; 166 | break; 167 | } // else fall-through 168 | case SGET: 169 | case SGET_WIDE: 170 | case SGET_OBJECT: 171 | case SGET_BOOLEAN: 172 | case SGET_BYTE: 173 | case SGET_CHAR: 174 | case SGET_SHORT: 175 | if (file != NULL) { 176 | uint32_t field_idx = VRegB_21c(); 177 | os << opcode << " v" << static_cast(VRegA_21c()) << ", " << PrettyField(field_idx, *file, true) 178 | << " // field@" << field_idx; 179 | break; 180 | } // else fall-through 181 | case SPUT: 182 | case SPUT_WIDE: 183 | case SPUT_OBJECT: 184 | case SPUT_BOOLEAN: 185 | case SPUT_BYTE: 186 | case SPUT_CHAR: 187 | case SPUT_SHORT: 188 | if (file != NULL) { 189 | uint32_t field_idx = VRegB_21c(); 190 | os << opcode << " v" << static_cast(VRegA_21c()) << ", " << PrettyField(field_idx, *file, true) 191 | << " // field@" << field_idx; 192 | break; 193 | } // else fall-through 194 | default: 195 | os << StringPrintf("%s v%d, thing@%d", opcode, VRegA_21c(), VRegB_21c()); 196 | break; 197 | } 198 | break; 199 | } 200 | case k23x: os << StringPrintf("%s v%d, v%d, v%d", opcode, VRegA_23x(), VRegB_23x(), VRegC_23x()); break; 201 | case k22b: os << StringPrintf("%s v%d, v%d, #%+d", opcode, VRegA_22b(), VRegB_22b(), VRegC_22b()); break; 202 | case k22t: os << StringPrintf("%s v%d, v%d, %+d", opcode, VRegA_22t(), VRegB_22t(), VRegC_22t()); break; 203 | case k22s: os << StringPrintf("%s v%d, v%d, #%+d", opcode, VRegA_22s(), VRegB_22s(), VRegC_22s()); break; 204 | case k22c: { 205 | switch (Opcode()) { 206 | case IGET: 207 | case IGET_WIDE: 208 | case IGET_OBJECT: 209 | case IGET_BOOLEAN: 210 | case IGET_BYTE: 211 | case IGET_CHAR: 212 | case IGET_SHORT: 213 | if (file != NULL) { 214 | uint32_t field_idx = VRegC_22c(); 215 | os << opcode << " v" << static_cast(VRegA_22c()) << ", v" << static_cast(VRegB_22c()) << ", " 216 | << PrettyField(field_idx, *file, true) << " // field@" << field_idx; 217 | break; 218 | } // else fall-through 219 | case IGET_QUICK: 220 | case IGET_OBJECT_QUICK: 221 | if (file != NULL) { 222 | uint32_t field_idx = VRegC_22c(); 223 | os << opcode << " v" << static_cast(VRegA_22c()) << ", v" << static_cast(VRegB_22c()) << ", " 224 | << "// offset@" << field_idx; 225 | break; 226 | } // else fall-through 227 | case IPUT: 228 | case IPUT_WIDE: 229 | case IPUT_OBJECT: 230 | case IPUT_BOOLEAN: 231 | case IPUT_BYTE: 232 | case IPUT_CHAR: 233 | case IPUT_SHORT: 234 | if (file != NULL) { 235 | uint32_t field_idx = VRegC_22c(); 236 | os << opcode << " v" << static_cast(VRegA_22c()) << ", v" << static_cast(VRegB_22c()) << ", " 237 | << PrettyField(field_idx, *file, true) << " // field@" << field_idx; 238 | break; 239 | } // else fall-through 240 | case IPUT_QUICK: 241 | case IPUT_OBJECT_QUICK: 242 | if (file != NULL) { 243 | uint32_t field_idx = VRegC_22c(); 244 | os << opcode << " v" << static_cast(VRegA_22c()) << ", v" << static_cast(VRegB_22c()) << ", " 245 | << "// offset@" << field_idx; 246 | break; 247 | } // else fall-through 248 | case INSTANCE_OF: 249 | if (file != NULL) { 250 | uint32_t type_idx = VRegC_22c(); 251 | os << opcode << " v" << static_cast(VRegA_22c()) << ", v" << static_cast(VRegB_22c()) << ", " 252 | << PrettyType(type_idx, *file) << " // type@" << type_idx; 253 | break; 254 | } 255 | case NEW_ARRAY: 256 | if (file != NULL) { 257 | uint32_t type_idx = VRegC_22c(); 258 | os << opcode << " v" << static_cast(VRegA_22c()) << ", v" << static_cast(VRegB_22c()) << ", " 259 | << PrettyType(type_idx, *file) << " // type@" << type_idx; 260 | break; 261 | } // else fall-through 262 | default: 263 | os << StringPrintf("%s v%d, v%d, thing@%d", opcode, VRegA_22c(), VRegB_22c(), VRegC_22c()); 264 | break; 265 | } 266 | break; 267 | } 268 | case k32x: os << StringPrintf("%s v%d, v%d", opcode, VRegA_32x(), VRegB_32x()); break; 269 | case k30t: os << StringPrintf("%s %+d", opcode, VRegA_30t()); break; 270 | case k31t: os << StringPrintf("%s v%d, %+d", opcode, VRegA_31t(), VRegB_31t()); break; 271 | case k31i: os << StringPrintf("%s v%d, #%+d", opcode, VRegA_31i(), VRegB_31i()); break; 272 | case k31c: 273 | if (Opcode() == CONST_STRING_JUMBO) { 274 | uint32_t string_idx = VRegB_31c(); 275 | if (file != NULL) { 276 | os << StringPrintf("%s v%d, %s // string@%d", opcode, VRegA_31c(), 277 | PrintableString(file->StringDataByIdx(string_idx)).c_str(), string_idx); 278 | } else 279 | os << StringPrintf("%s v%d, string@%d", opcode, VRegA_31c(), string_idx); 280 | } else 281 | os << StringPrintf("%s v%d, thing@%d", opcode, VRegA_31c(), VRegB_31c()); break; 282 | break; 283 | case k35c: { 284 | uint32_t arg[5]; 285 | GetVarArgs(arg); 286 | switch (Opcode()) { 287 | case FILLED_NEW_ARRAY: 288 | { 289 | const int32_t a = VRegA_35c(); 290 | os << opcode << " {"; 291 | for (int i = 0; i < a; ++i) { 292 | if (i > 0) 293 | os << ", "; 294 | os << "v" << arg[i]; 295 | } 296 | os << "}, type@" << VRegB_35c(); 297 | } 298 | break; 299 | 300 | case INVOKE_VIRTUAL: 301 | case INVOKE_SUPER: 302 | case INVOKE_DIRECT: 303 | case INVOKE_STATIC: 304 | case INVOKE_INTERFACE: 305 | if (file != NULL) { 306 | os << opcode << " {"; 307 | uint32_t method_idx = VRegB_35c(); 308 | for (size_t i = 0; i < VRegA_35c(); ++i) { 309 | if (i != 0) 310 | os << ", "; 311 | os << "v" << arg[i]; 312 | } 313 | os << "}, " << PrettyMethod(method_idx, *file) << " // method@" << method_idx; 314 | break; 315 | } // else fall-through 316 | case INVOKE_VIRTUAL_QUICK: 317 | if (file != NULL) { 318 | os << opcode << " {"; 319 | uint32_t method_idx = VRegB_35c(); 320 | for (size_t i = 0; i < VRegA_35c(); ++i) { 321 | if (i != 0) 322 | os << ", "; 323 | os << "v" << arg[i]; 324 | } 325 | os << "}, // vtable@" << method_idx; 326 | break; 327 | } // else fall-through 328 | default: 329 | os << opcode << " {v" << arg[0] << ", v" << arg[1] << ", v" << arg[2] 330 | << ", v" << arg[3] << ", v" << arg[4] << "}, thing@" << VRegB_35c(); 331 | break; 332 | } 333 | break; 334 | } 335 | case k3rc: { 336 | switch (Opcode()) { 337 | case INVOKE_VIRTUAL_RANGE: 338 | case INVOKE_SUPER_RANGE: 339 | case INVOKE_DIRECT_RANGE: 340 | case INVOKE_STATIC_RANGE: 341 | case INVOKE_INTERFACE_RANGE: 342 | if (file != NULL) { 343 | uint32_t method_idx = VRegB_3rc(); 344 | os << StringPrintf("%s, {v%d .. v%d}, ", opcode, VRegC_3rc(), (VRegC_3rc() + VRegA_3rc() - 1)) 345 | << PrettyMethod(method_idx, *file) << " // method@" << method_idx; 346 | break; 347 | } // else fall-through 348 | case INVOKE_VIRTUAL_RANGE_QUICK: 349 | if (file != NULL) { 350 | uint32_t method_idx = VRegB_3rc(); 351 | os << StringPrintf("%s, {v%d .. v%d}, ", opcode, VRegC_3rc(), (VRegC_3rc() + VRegA_3rc() - 1)) 352 | << "// vtable@" << method_idx; 353 | break; 354 | } // else fall-through 355 | default: 356 | os << StringPrintf("%s, {v%d .. v%d}, thing@%d", opcode, VRegC_3rc(), 357 | (VRegC_3rc() + VRegA_3rc() - 1), VRegB_3rc()); 358 | break; 359 | } 360 | break; 361 | } 362 | case k51l: os << StringPrintf("%s v%d, #%+" PRId64, opcode, VRegA_51l(), VRegB_51l()); break; 363 | default: os << " unknown format (" << DumpHex(5) << ")"; break; 364 | } 365 | return os.str(); 366 | } 367 | -------------------------------------------------------------------------------- /engine/dumper/dex_instruction.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _ART_DEX_INSTRUCTION_H_ 3 | #define _ART_DEX_INSTRUCTION_H_ 4 | 5 | 6 | #include "globals.h" 7 | #include "macros.h" 8 | 9 | 10 | typedef uint8_t uint4_t; 11 | typedef int8_t int4_t; 12 | 13 | class DexFile; 14 | 15 | enum 16 | { 17 | kNumPackedOpcodes = 0x100 18 | }; 19 | 20 | 21 | class Instruction 22 | { 23 | public: 24 | // NOP-encoded switch-statement signatures. 25 | enum 26 | { 27 | kPackedSwitchSignature = 0x0100, 28 | kSparseSwitchSignature = 0x0200, 29 | kArrayDataSignature = 0x0300, 30 | }; 31 | 32 | struct PACKED(4) PackedSwitchPayload 33 | { 34 | const uint16_t ident; 35 | const uint16_t case_count; 36 | const int32_t first_key; 37 | const int32_t targets[]; 38 | 39 | private: 40 | DISALLOW_COPY_AND_ASSIGN(PackedSwitchPayload); 41 | }; 42 | 43 | struct PACKED(4) SparseSwitchPayload 44 | { 45 | const uint16_t ident; 46 | const uint16_t case_count; 47 | const int32_t keys_and_targets[]; 48 | 49 | public: 50 | const int32_t* GetKeys() const 51 | { 52 | return keys_and_targets; 53 | } 54 | 55 | const int32_t* GetTargets() const 56 | { 57 | return keys_and_targets + case_count; 58 | } 59 | 60 | private: 61 | DISALLOW_COPY_AND_ASSIGN(SparseSwitchPayload); 62 | }; 63 | 64 | struct PACKED(4) ArrayDataPayload 65 | { 66 | const uint16_t ident; 67 | const uint16_t element_width; 68 | const uint32_t element_count; 69 | const uint8_t data[]; 70 | 71 | private: 72 | DISALLOW_COPY_AND_ASSIGN(ArrayDataPayload); 73 | }; 74 | 75 | enum Code 76 | { // NOLINT(whitespace/braces) 77 | #define INSTRUCTION_ENUM(opcode, cname, p, f, r, i, a, v) cname = opcode, 78 | #include "dex_instruction_list.h" 79 | DEX_INSTRUCTION_LIST(INSTRUCTION_ENUM) 80 | #undef DEX_INSTRUCTION_LIST 81 | #undef INSTRUCTION_ENUM 82 | }; 83 | 84 | enum Format 85 | { 86 | k10x, // op 87 | k12x, // op vA, vB 88 | k11n, // op vA, #+B 89 | k11x, // op vAA 90 | k10t, // op +AA 91 | k20t, // op +AAAA 92 | k22x, // op vAA, vBBBB 93 | k21t, // op vAA, +BBBB 94 | k21s, // op vAA, #+BBBB 95 | k21h, // op vAA, #+BBBB00000[00000000] 96 | k21c, // op vAA, thing@BBBB 97 | k23x, // op vAA, vBB, vCC 98 | k22b, // op vAA, vBB, #+CC 99 | k22t, // op vA, vB, +CCCC 100 | k22s, // op vA, vB, #+CCCC 101 | k22c, // op vA, vB, thing@CCCC 102 | k32x, // op vAAAA, vBBBB 103 | k30t, // op +AAAAAAAA 104 | k31t, // op vAA, +BBBBBBBB 105 | k31i, // op vAA, #+BBBBBBBB 106 | k31c, // op vAA, thing@BBBBBBBB 107 | k35c, // op {vC, vD, vE, vF, vG}, thing@BBBB (B: count, A: vG) 108 | k3rc, // op {vCCCC .. v(CCCC+AA-1)}, meth@BBBB 109 | k51l, // op vAA, #+BBBBBBBBBBBBBBBB 110 | }; 111 | 112 | enum Flags 113 | { 114 | kBranch = 0x000001, // conditional or unconditional branch 115 | kContinue = 0x000002, // flow can continue to next statement 116 | kSwitch = 0x000004, // switch statement 117 | kThrow = 0x000008, // could cause an exception to be thrown 118 | kReturn = 0x000010, // returns, no additional statements 119 | kInvoke = 0x000020, // a flavor of invoke 120 | kUnconditional = 0x000040, // unconditional branch 121 | kAdd = 0x000080, // addition 122 | kSubtract = 0x000100, // subtract 123 | kMultiply = 0x000200, // multiply 124 | kDivide = 0x000400, // division 125 | kRemainder = 0x000800, // remainder 126 | kAnd = 0x001000, // and 127 | kOr = 0x002000, // or 128 | kXor = 0x004000, // xor 129 | kShl = 0x008000, // shl 130 | kShr = 0x010000, // shr 131 | kUshr = 0x020000, // ushr 132 | kCast = 0x040000, // cast 133 | kStore = 0x080000, // store opcode 134 | kLoad = 0x100000, // load opcode 135 | kClobber = 0x200000, // clobbers memory in a big way (not just a write) 136 | kRegCFieldOrConstant = 0x400000, // is the third virtual register a field or literal constant (vC) 137 | kRegBFieldOrConstant = 0x800000, // is the second virtual register a field or literal constant (vB) 138 | }; 139 | 140 | enum VerifyFlag 141 | { 142 | kVerifyNone = 0x000000, 143 | kVerifyRegA = 0x000001, 144 | kVerifyRegAWide = 0x000002, 145 | kVerifyRegB = 0x000004, 146 | kVerifyRegBField = 0x000008, 147 | kVerifyRegBMethod = 0x000010, 148 | kVerifyRegBNewInstance = 0x000020, 149 | kVerifyRegBString = 0x000040, 150 | kVerifyRegBType = 0x000080, 151 | kVerifyRegBWide = 0x000100, 152 | kVerifyRegC = 0x000200, 153 | kVerifyRegCField = 0x000400, 154 | kVerifyRegCNewArray = 0x000800, 155 | kVerifyRegCType = 0x001000, 156 | kVerifyRegCWide = 0x002000, 157 | kVerifyArrayData = 0x004000, 158 | kVerifyBranchTarget = 0x008000, 159 | kVerifySwitchTargets = 0x010000, 160 | kVerifyVarArg = 0x020000, 161 | kVerifyVarArgNonZero = 0x040000, 162 | kVerifyVarArgRange = 0x080000, 163 | kVerifyVarArgRangeNonZero = 0x100000, 164 | kVerifyRuntimeOnly = 0x200000, 165 | kVerifyError = 0x400000, 166 | }; 167 | 168 | static constexpr uint32_t kMaxVarArgRegs = 5; 169 | 170 | // Returns the size (in 2 byte code units) of this instruction. 171 | size_t SizeInCodeUnits() const 172 | { 173 | int result = kInstructionSizeInCodeUnits[Opcode()]; 174 | if (UNLIKELY(result < 0)) 175 | return SizeInCodeUnitsComplexOpcode(); 176 | else 177 | return static_cast(result); 178 | } 179 | 180 | // Reads an instruction out of the stream at the specified address. 181 | static const Instruction* At(const uint16_t* code) 182 | { 183 | CHECK(code != nullptr); 184 | return reinterpret_cast(code); 185 | } 186 | 187 | // Reads an instruction out of the stream from the current address plus an offset. 188 | const Instruction* RelativeAt(int32_t offset) const 189 | { 190 | return At(reinterpret_cast(this) + offset); 191 | } 192 | 193 | // Returns a pointer to the next instruction in the stream. 194 | const Instruction* Next() const 195 | { 196 | return RelativeAt(SizeInCodeUnits()); 197 | } 198 | 199 | // Returns a pointer to the instruction after this 1xx instruction in the stream. 200 | const Instruction* Next_1xx() const 201 | { 202 | CHECK(FormatOf(Opcode()) >= k10x && FormatOf(Opcode()) <= k10t); 203 | return RelativeAt(1); 204 | } 205 | 206 | // Returns a pointer to the instruction after this 2xx instruction in the stream. 207 | const Instruction* Next_2xx() const 208 | { 209 | CHECK(FormatOf(Opcode()) >= k20t && FormatOf(Opcode()) <= k22c); 210 | return RelativeAt(2); 211 | } 212 | 213 | // Returns a pointer to the instruction after this 3xx instruction in the stream. 214 | const Instruction* Next_3xx() const 215 | { 216 | CHECK(FormatOf(Opcode()) >= k32x && FormatOf(Opcode()) <= k3rc); 217 | return RelativeAt(3); 218 | } 219 | 220 | // Returns a pointer to the instruction after this 51l instruction in the stream. 221 | const Instruction* Next_51l() const 222 | { 223 | CHECK(FormatOf(Opcode()) == k51l); 224 | return RelativeAt(5); 225 | } 226 | 227 | // Returns the name of this instruction's opcode. 228 | const char* Name() const 229 | { 230 | return Instruction::Name(Opcode()); 231 | } 232 | 233 | // Returns the name of the given opcode. 234 | static const char* Name(Code opcode) 235 | { 236 | return kInstructionNames[opcode]; 237 | } 238 | 239 | // VRegA 240 | bool HasVRegA() const; 241 | int32_t VRegA() const; 242 | 243 | int8_t VRegA_10t() const 244 | { 245 | return VRegA_10t(Fetch16(0)); 246 | } 247 | 248 | uint8_t VRegA_10x() const 249 | { 250 | return VRegA_10x(Fetch16(0)); 251 | } 252 | 253 | uint4_t VRegA_11n() const 254 | { 255 | return VRegA_11n(Fetch16(0)); 256 | } 257 | 258 | uint8_t VRegA_11x() const 259 | { 260 | return VRegA_11x(Fetch16(0)); 261 | } 262 | 263 | uint4_t VRegA_12x() const 264 | { 265 | return VRegA_12x(Fetch16(0)); 266 | } 267 | 268 | int16_t VRegA_20t() const; 269 | 270 | uint8_t VRegA_21c() const 271 | { 272 | return VRegA_21c(Fetch16(0)); 273 | } 274 | 275 | uint8_t VRegA_21h() const 276 | { 277 | return VRegA_21h(Fetch16(0)); 278 | } 279 | 280 | uint8_t VRegA_21s() const 281 | { 282 | return VRegA_21s(Fetch16(0)); 283 | } 284 | 285 | uint8_t VRegA_21t() const 286 | { 287 | return VRegA_21t(Fetch16(0)); 288 | } 289 | 290 | uint8_t VRegA_22b() const 291 | { 292 | return VRegA_22b(Fetch16(0)); 293 | } 294 | 295 | uint4_t VRegA_22c() const 296 | { 297 | return VRegA_22c(Fetch16(0)); 298 | } 299 | 300 | uint4_t VRegA_22s() const 301 | { 302 | return VRegA_22s(Fetch16(0)); 303 | } 304 | 305 | uint4_t VRegA_22t() const 306 | { 307 | return VRegA_22t(Fetch16(0)); 308 | } 309 | 310 | uint8_t VRegA_22x() const 311 | { 312 | return VRegA_22x(Fetch16(0)); 313 | } 314 | 315 | uint8_t VRegA_23x() const 316 | { 317 | return VRegA_23x(Fetch16(0)); 318 | } 319 | 320 | int32_t VRegA_30t() const; 321 | 322 | uint8_t VRegA_31c() const 323 | { 324 | return VRegA_31c(Fetch16(0)); 325 | } 326 | 327 | uint8_t VRegA_31i() const 328 | { 329 | return VRegA_31i(Fetch16(0)); 330 | } 331 | 332 | uint8_t VRegA_31t() const 333 | { 334 | return VRegA_31t(Fetch16(0)); 335 | } 336 | 337 | uint16_t VRegA_32x() const; 338 | 339 | uint4_t VRegA_35c() const 340 | { 341 | return VRegA_35c(Fetch16(0)); 342 | } 343 | 344 | uint8_t VRegA_3rc() const 345 | { 346 | return VRegA_3rc(Fetch16(0)); 347 | } 348 | 349 | uint8_t VRegA_51l() const 350 | { 351 | return VRegA_51l(Fetch16(0)); 352 | } 353 | 354 | // The following methods return the vA operand for various instruction formats. The "inst_data" 355 | // parameter holds the first 16 bits of instruction which the returned value is decoded from. 356 | int8_t VRegA_10t(uint16_t inst_data) const; 357 | uint8_t VRegA_10x(uint16_t inst_data) const; 358 | uint4_t VRegA_11n(uint16_t inst_data) const; 359 | uint8_t VRegA_11x(uint16_t inst_data) const; 360 | uint4_t VRegA_12x(uint16_t inst_data) const; 361 | uint8_t VRegA_21c(uint16_t inst_data) const; 362 | uint8_t VRegA_21h(uint16_t inst_data) const; 363 | uint8_t VRegA_21s(uint16_t inst_data) const; 364 | uint8_t VRegA_21t(uint16_t inst_data) const; 365 | uint8_t VRegA_22b(uint16_t inst_data) const; 366 | uint4_t VRegA_22c(uint16_t inst_data) const; 367 | uint4_t VRegA_22s(uint16_t inst_data) const; 368 | uint4_t VRegA_22t(uint16_t inst_data) const; 369 | uint8_t VRegA_22x(uint16_t inst_data) const; 370 | uint8_t VRegA_23x(uint16_t inst_data) const; 371 | uint8_t VRegA_31c(uint16_t inst_data) const; 372 | uint8_t VRegA_31i(uint16_t inst_data) const; 373 | uint8_t VRegA_31t(uint16_t inst_data) const; 374 | uint4_t VRegA_35c(uint16_t inst_data) const; 375 | uint8_t VRegA_3rc(uint16_t inst_data) const; 376 | uint8_t VRegA_51l(uint16_t inst_data) const; 377 | 378 | // VRegB 379 | bool HasVRegB() const; 380 | int32_t VRegB() const; 381 | 382 | bool HasWideVRegB() const; 383 | uint64_t WideVRegB() const; 384 | 385 | int4_t VRegB_11n() const 386 | { 387 | return VRegB_11n(Fetch16(0)); 388 | } 389 | 390 | uint4_t VRegB_12x() const 391 | { 392 | return VRegB_12x(Fetch16(0)); 393 | } 394 | 395 | uint16_t VRegB_21c() const; 396 | uint16_t VRegB_21h() const; 397 | int16_t VRegB_21s() const; 398 | int16_t VRegB_21t() const; 399 | uint8_t VRegB_22b() const; 400 | 401 | uint4_t VRegB_22c() const 402 | { 403 | return VRegB_22c(Fetch16(0)); 404 | } 405 | 406 | uint4_t VRegB_22s() const 407 | { 408 | return VRegB_22s(Fetch16(0)); 409 | } 410 | 411 | uint4_t VRegB_22t() const 412 | { 413 | return VRegB_22t(Fetch16(0)); 414 | } 415 | 416 | uint16_t VRegB_22x() const; 417 | uint8_t VRegB_23x() const; 418 | uint32_t VRegB_31c() const; 419 | int32_t VRegB_31i() const; 420 | int32_t VRegB_31t() const; 421 | uint16_t VRegB_32x() const; 422 | uint16_t VRegB_35c() const; 423 | uint16_t VRegB_3rc() const; 424 | uint64_t VRegB_51l() const; // vB_wide 425 | 426 | // The following methods return the vB operand for all instruction formats 427 | // where it is encoded in the first 16 bits of instruction. The "inst_data" 428 | // parameter holds these 16 bits. The returned value is decoded from it. 429 | int4_t VRegB_11n(uint16_t inst_data) const; 430 | uint4_t VRegB_12x(uint16_t inst_data) const; 431 | uint4_t VRegB_22c(uint16_t inst_data) const; 432 | uint4_t VRegB_22s(uint16_t inst_data) const; 433 | uint4_t VRegB_22t(uint16_t inst_data) const; 434 | 435 | // VRegC 436 | bool HasVRegC() const; 437 | int32_t VRegC() const; 438 | 439 | int8_t VRegC_22b() const; 440 | uint16_t VRegC_22c() const; 441 | int16_t VRegC_22s() const; 442 | int16_t VRegC_22t() const; 443 | uint8_t VRegC_23x() const; 444 | uint4_t VRegC_35c() const; 445 | uint16_t VRegC_3rc() const; 446 | 447 | // Fills the given array with the 'arg' array of the instruction. 448 | bool HasVarArgs() const; 449 | void GetVarArgs(uint32_t args[kMaxVarArgRegs], uint16_t inst_data) const; 450 | void GetVarArgs(uint32_t args[kMaxVarArgRegs]) const 451 | { 452 | return GetVarArgs(args, Fetch16(0)); 453 | } 454 | 455 | // Returns the opcode field of the instruction. The given "inst_data" 456 | // parameter must be the first 16 bits of instruction. 457 | Code Opcode(uint16_t inst_data) const 458 | { 459 | CHECK_EQ(inst_data, Fetch16(0)); 460 | return static_cast(inst_data & 0xFF); 461 | } 462 | 463 | // Returns the opcode field of the instruction from the first 16 bits of instruction. 464 | Code Opcode() const 465 | { 466 | return Opcode(Fetch16(0)); 467 | } 468 | 469 | void SetOpcode(Code opcode) 470 | { 471 | CHECK_LT(static_cast(opcode), 256u); 472 | uint16_t* insns = reinterpret_cast(this); 473 | insns[0] = (insns[0] & 0xff00) | static_cast(opcode); 474 | } 475 | 476 | void SetVRegA_10x(uint8_t val) 477 | { 478 | CHECK(FormatOf(Opcode()) == k10x); 479 | uint16_t* insns = reinterpret_cast(this); 480 | insns[0] = (val << 8) | (insns[0] & 0x00ff); 481 | } 482 | 483 | void SetVRegB_3rc(uint16_t val) 484 | { 485 | CHECK(FormatOf(Opcode()) == k3rc); 486 | uint16_t* insns = reinterpret_cast(this); 487 | insns[1] = val; 488 | } 489 | 490 | void SetVRegB_35c(uint16_t val) 491 | { 492 | CHECK(FormatOf(Opcode()) == k35c); 493 | uint16_t* insns = reinterpret_cast(this); 494 | insns[1] = val; 495 | } 496 | 497 | void SetVRegC_22c(uint16_t val) 498 | { 499 | CHECK(FormatOf(Opcode()) == k22c); 500 | uint16_t* insns = reinterpret_cast(this); 501 | insns[1] = val; 502 | } 503 | 504 | // Returns the format of the given opcode. 505 | static Format FormatOf(Code opcode) 506 | { 507 | return kInstructionFormats[opcode]; 508 | } 509 | 510 | // Returns the flags for the given opcode. 511 | static int FlagsOf(Code opcode) 512 | { 513 | return kInstructionFlags[opcode]; 514 | } 515 | 516 | // Return the verify flags for the given opcode. 517 | static int VerifyFlagsOf(Code opcode) 518 | { 519 | return kInstructionVerifyFlags[opcode]; 520 | } 521 | 522 | // Returns true if this instruction is a branch. 523 | bool IsBranch() const 524 | { 525 | return (kInstructionFlags[Opcode()] & kBranch) != 0; 526 | } 527 | 528 | // Returns true if this instruction is a unconditional branch. 529 | bool IsUnconditional() const 530 | { 531 | return (kInstructionFlags[Opcode()] & kUnconditional) != 0; 532 | } 533 | 534 | // Returns the branch offset if this instruction is a branch. 535 | int32_t GetTargetOffset() const; 536 | 537 | // Returns true if the instruction allows control flow to go to the 538 | // following instruction. 539 | bool CanFlowThrough() const; 540 | 541 | // Returns true if this instruction is a switch. 542 | bool IsSwitch() const 543 | { 544 | return (kInstructionFlags[Opcode()] & kSwitch) != 0; 545 | } 546 | 547 | // Returns true if this instruction can throw. 548 | bool IsThrow() const 549 | { 550 | return (kInstructionFlags[Opcode()] & kThrow) != 0; 551 | } 552 | 553 | // Determine if the instruction is any of 'return' instructions. 554 | bool IsReturn() const 555 | { 556 | return (kInstructionFlags[Opcode()] & kReturn) != 0; 557 | } 558 | 559 | // Determine if this instruction ends execution of its basic block. 560 | bool IsBasicBlockEnd() const 561 | { 562 | return IsBranch() || IsReturn() || Opcode() == THROW; 563 | } 564 | 565 | // Determine if this instruction is an invoke. 566 | bool IsInvoke() const 567 | { 568 | return (kInstructionFlags[Opcode()] & kInvoke) != 0; 569 | } 570 | 571 | int GetVerifyTypeArgumentA() const 572 | { 573 | return (kInstructionVerifyFlags[Opcode()] & (kVerifyRegA | kVerifyRegAWide)); 574 | } 575 | 576 | int GetVerifyTypeArgumentB() const 577 | { 578 | return (kInstructionVerifyFlags[Opcode()] & (kVerifyRegB | kVerifyRegBField | 579 | kVerifyRegBMethod | kVerifyRegBNewInstance | kVerifyRegBString | kVerifyRegBType | 580 | kVerifyRegBWide)); 581 | } 582 | 583 | int GetVerifyTypeArgumentC() const 584 | { 585 | return (kInstructionVerifyFlags[Opcode()] & (kVerifyRegC | kVerifyRegCField | 586 | kVerifyRegCNewArray | kVerifyRegCType | kVerifyRegCWide)); 587 | } 588 | 589 | int GetVerifyExtraFlags() const 590 | { 591 | return (kInstructionVerifyFlags[Opcode()] & (kVerifyArrayData | kVerifyBranchTarget | 592 | kVerifySwitchTargets | kVerifyVarArg | kVerifyVarArgNonZero | kVerifyVarArgRange | 593 | kVerifyVarArgRangeNonZero | kVerifyError)); 594 | } 595 | 596 | bool GetVerifyIsRuntimeOnly() const 597 | { 598 | return (kInstructionVerifyFlags[Opcode()] & kVerifyRuntimeOnly) != 0; 599 | } 600 | 601 | // Get the dex PC of this instruction as an offset in code units from the beginning of insns. 602 | uint32_t GetDexPc(const uint16_t* insns) const 603 | { 604 | return (reinterpret_cast(this) - insns); 605 | } 606 | 607 | // Dump decoded version of instruction 608 | std::string DumpString(const DexFile*) const; 609 | 610 | // Dump code_units worth of this instruction, padding to code_units for shorter instructions 611 | std::string DumpHex(size_t code_units) const; 612 | 613 | uint16_t Fetch16(size_t offset) const 614 | { 615 | const uint16_t* insns = reinterpret_cast(this); 616 | return insns[offset]; 617 | } 618 | 619 | private: 620 | size_t SizeInCodeUnitsComplexOpcode() const; 621 | 622 | uint32_t Fetch32(size_t offset) const 623 | { 624 | return (Fetch16(offset) | ((uint32_t) Fetch16(offset + 1) << 16)); 625 | } 626 | 627 | uint4_t InstA() const 628 | { 629 | return InstA(Fetch16(0)); 630 | } 631 | 632 | uint4_t InstB() const 633 | { 634 | return InstB(Fetch16(0)); 635 | } 636 | 637 | uint8_t InstAA() const 638 | { 639 | return InstAA(Fetch16(0)); 640 | } 641 | 642 | uint4_t InstA(uint16_t inst_data) const 643 | { 644 | CHECK_EQ(inst_data, Fetch16(0)); 645 | return static_cast((inst_data >> 8) & 0x0f); 646 | } 647 | 648 | uint4_t InstB(uint16_t inst_data) const 649 | { 650 | CHECK_EQ(inst_data, Fetch16(0)); 651 | return static_cast(inst_data >> 12); 652 | } 653 | 654 | uint8_t InstAA(uint16_t inst_data) const 655 | { 656 | CHECK_EQ(inst_data, Fetch16(0)); 657 | return static_cast(inst_data >> 8); 658 | } 659 | 660 | static const char* const kInstructionNames[]; 661 | static Format const kInstructionFormats[]; 662 | static int const kInstructionFlags[]; 663 | static int const kInstructionVerifyFlags[]; 664 | static int const kInstructionSizeInCodeUnits[]; 665 | DISALLOW_IMPLICIT_CONSTRUCTORS(Instruction); 666 | }; 667 | 668 | #endif 669 | -------------------------------------------------------------------------------- /engine/dumper/dex_instruction_list.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ifndef _ART_DEX_INSTRUCTION_LIST_H_ 4 | #define _ART_DEX_INSTRUCTION_LIST_H_ 5 | 6 | #define DEX_INSTRUCTION_LIST(V) \ 7 | V(0x00, NOP, "nop", k10x, false, kNone, kContinue, kVerifyNone) \ 8 | V(0x01, MOVE, "move", k12x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \ 9 | V(0x02, MOVE_FROM16, "move/from16", k22x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \ 10 | V(0x03, MOVE_16, "move/16", k32x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \ 11 | V(0x04, MOVE_WIDE, "move-wide", k12x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide) \ 12 | V(0x05, MOVE_WIDE_FROM16, "move-wide/from16", k22x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide) \ 13 | V(0x06, MOVE_WIDE_16, "move-wide/16", k32x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide) \ 14 | V(0x07, MOVE_OBJECT, "move-object", k12x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \ 15 | V(0x08, MOVE_OBJECT_FROM16, "move-object/from16", k22x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \ 16 | V(0x09, MOVE_OBJECT_16, "move-object/16", k32x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \ 17 | V(0x0A, MOVE_RESULT, "move-result", k11x, true, kNone, kContinue, kVerifyRegA) \ 18 | V(0x0B, MOVE_RESULT_WIDE, "move-result-wide", k11x, true, kNone, kContinue, kVerifyRegAWide) \ 19 | V(0x0C, MOVE_RESULT_OBJECT, "move-result-object", k11x, true, kNone, kContinue, kVerifyRegA) \ 20 | V(0x0D, MOVE_EXCEPTION, "move-exception", k11x, true, kNone, kContinue, kVerifyRegA) \ 21 | V(0x0E, RETURN_VOID, "return-void", k10x, false, kNone, kReturn, kVerifyNone) \ 22 | V(0x0F, RETURN, "return", k11x, false, kNone, kReturn, kVerifyRegA) \ 23 | V(0x10, RETURN_WIDE, "return-wide", k11x, false, kNone, kReturn, kVerifyRegAWide) \ 24 | V(0x11, RETURN_OBJECT, "return-object", k11x, false, kNone, kReturn, kVerifyRegA) \ 25 | V(0x12, CONST_4, "const/4", k11n, true, kNone, kContinue | kRegBFieldOrConstant, kVerifyRegA) \ 26 | V(0x13, CONST_16, "const/16", k21s, true, kNone, kContinue | kRegBFieldOrConstant, kVerifyRegA) \ 27 | V(0x14, CONST, "const", k31i, true, kNone, kContinue | kRegBFieldOrConstant, kVerifyRegA) \ 28 | V(0x15, CONST_HIGH16, "const/high16", k21h, true, kNone, kContinue | kRegBFieldOrConstant, kVerifyRegA) \ 29 | V(0x16, CONST_WIDE_16, "const-wide/16", k21s, true, kNone, kContinue | kRegBFieldOrConstant, kVerifyRegAWide) \ 30 | V(0x17, CONST_WIDE_32, "const-wide/32", k31i, true, kNone, kContinue | kRegBFieldOrConstant, kVerifyRegAWide) \ 31 | V(0x18, CONST_WIDE, "const-wide", k51l, true, kNone, kContinue | kRegBFieldOrConstant, kVerifyRegAWide) \ 32 | V(0x19, CONST_WIDE_HIGH16, "const-wide/high16", k21h, true, kNone, kContinue | kRegBFieldOrConstant, kVerifyRegAWide) \ 33 | V(0x1A, CONST_STRING, "const-string", k21c, true, kStringRef, kContinue | kThrow, kVerifyRegA | kVerifyRegBString) \ 34 | V(0x1B, CONST_STRING_JUMBO, "const-string/jumbo", k31c, true, kStringRef, kContinue | kThrow, kVerifyRegA | kVerifyRegBString) \ 35 | V(0x1C, CONST_CLASS, "const-class", k21c, true, kTypeRef, kContinue | kThrow, kVerifyRegA | kVerifyRegBType) \ 36 | V(0x1D, MONITOR_ENTER, "monitor-enter", k11x, false, kNone, kContinue | kThrow | kClobber, kVerifyRegA) \ 37 | V(0x1E, MONITOR_EXIT, "monitor-exit", k11x, false, kNone, kContinue | kThrow | kClobber, kVerifyRegA) \ 38 | V(0x1F, CHECK_CAST, "check-cast", k21c, true, kTypeRef, kContinue | kThrow, kVerifyRegA | kVerifyRegBType) \ 39 | V(0x20, INSTANCE_OF, "instance-of", k22c, true, kTypeRef, kContinue | kThrow, kVerifyRegA | kVerifyRegB | kVerifyRegCType) \ 40 | V(0x21, ARRAY_LENGTH, "array-length", k12x, true, kNone, kContinue | kThrow, kVerifyRegA | kVerifyRegB) \ 41 | V(0x22, NEW_INSTANCE, "new-instance", k21c, true, kTypeRef, kContinue | kThrow | kClobber, kVerifyRegA | kVerifyRegBNewInstance) \ 42 | V(0x23, NEW_ARRAY, "new-array", k22c, true, kTypeRef, kContinue | kThrow | kClobber, kVerifyRegA | kVerifyRegB | kVerifyRegCNewArray) \ 43 | V(0x24, FILLED_NEW_ARRAY, "filled-new-array", k35c, false, kTypeRef, kContinue | kThrow | kClobber, kVerifyRegBType | kVerifyVarArg) \ 44 | V(0x25, FILLED_NEW_ARRAY_RANGE, "filled-new-array/range", k3rc, false, kTypeRef, kContinue | kThrow | kClobber, kVerifyRegBType | kVerifyVarArgRange) \ 45 | V(0x26, FILL_ARRAY_DATA, "fill-array-data", k31t, false, kNone, kContinue | kThrow | kClobber, kVerifyRegA | kVerifyArrayData) \ 46 | V(0x27, THROW, "throw", k11x, false, kNone, kThrow, kVerifyRegA) \ 47 | V(0x28, GOTO, "goto", k10t, false, kNone, kBranch | kUnconditional, kVerifyBranchTarget) \ 48 | V(0x29, GOTO_16, "goto/16", k20t, false, kNone, kBranch | kUnconditional, kVerifyBranchTarget) \ 49 | V(0x2A, GOTO_32, "goto/32", k30t, false, kNone, kBranch | kUnconditional, kVerifyBranchTarget) \ 50 | V(0x2B, PACKED_SWITCH, "packed-switch", k31t, false, kNone, kContinue | kSwitch, kVerifyRegA | kVerifySwitchTargets) \ 51 | V(0x2C, SPARSE_SWITCH, "sparse-switch", k31t, false, kNone, kContinue | kSwitch, kVerifyRegA | kVerifySwitchTargets) \ 52 | V(0x2D, CMPL_FLOAT, "cmpl-float", k23x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ 53 | V(0x2E, CMPG_FLOAT, "cmpg-float", k23x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ 54 | V(0x2F, CMPL_DOUBLE, "cmpl-double", k23x, true, kNone, kContinue, kVerifyRegA | kVerifyRegBWide | kVerifyRegCWide) \ 55 | V(0x30, CMPG_DOUBLE, "cmpg-double", k23x, true, kNone, kContinue, kVerifyRegA | kVerifyRegBWide | kVerifyRegCWide) \ 56 | V(0x31, CMP_LONG, "cmp-long", k23x, true, kNone, kContinue, kVerifyRegA | kVerifyRegBWide | kVerifyRegCWide) \ 57 | V(0x32, IF_EQ, "if-eq", k22t, false, kNone, kContinue | kBranch, kVerifyRegA | kVerifyRegB | kVerifyBranchTarget) \ 58 | V(0x33, IF_NE, "if-ne", k22t, false, kNone, kContinue | kBranch, kVerifyRegA | kVerifyRegB | kVerifyBranchTarget) \ 59 | V(0x34, IF_LT, "if-lt", k22t, false, kNone, kContinue | kBranch, kVerifyRegA | kVerifyRegB | kVerifyBranchTarget) \ 60 | V(0x35, IF_GE, "if-ge", k22t, false, kNone, kContinue | kBranch, kVerifyRegA | kVerifyRegB | kVerifyBranchTarget) \ 61 | V(0x36, IF_GT, "if-gt", k22t, false, kNone, kContinue | kBranch, kVerifyRegA | kVerifyRegB | kVerifyBranchTarget) \ 62 | V(0x37, IF_LE, "if-le", k22t, false, kNone, kContinue | kBranch, kVerifyRegA | kVerifyRegB | kVerifyBranchTarget) \ 63 | V(0x38, IF_EQZ, "if-eqz", k21t, false, kNone, kContinue | kBranch, kVerifyRegA | kVerifyBranchTarget) \ 64 | V(0x39, IF_NEZ, "if-nez", k21t, false, kNone, kContinue | kBranch, kVerifyRegA | kVerifyBranchTarget) \ 65 | V(0x3A, IF_LTZ, "if-ltz", k21t, false, kNone, kContinue | kBranch, kVerifyRegA | kVerifyBranchTarget) \ 66 | V(0x3B, IF_GEZ, "if-gez", k21t, false, kNone, kContinue | kBranch, kVerifyRegA | kVerifyBranchTarget) \ 67 | V(0x3C, IF_GTZ, "if-gtz", k21t, false, kNone, kContinue | kBranch, kVerifyRegA | kVerifyBranchTarget) \ 68 | V(0x3D, IF_LEZ, "if-lez", k21t, false, kNone, kContinue | kBranch, kVerifyRegA | kVerifyBranchTarget) \ 69 | V(0x3E, UNUSED_3E, "unused-3e", k10x, false, kUnknown, 0, kVerifyError) \ 70 | V(0x3F, UNUSED_3F, "unused-3f", k10x, false, kUnknown, 0, kVerifyError) \ 71 | V(0x40, UNUSED_40, "unused-40", k10x, false, kUnknown, 0, kVerifyError) \ 72 | V(0x41, UNUSED_41, "unused-41", k10x, false, kUnknown, 0, kVerifyError) \ 73 | V(0x42, UNUSED_42, "unused-42", k10x, false, kUnknown, 0, kVerifyError) \ 74 | V(0x43, UNUSED_43, "unused-43", k10x, false, kUnknown, 0, kVerifyError) \ 75 | V(0x44, AGET, "aget", k23x, true, kNone, kContinue | kThrow | kLoad, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ 76 | V(0x45, AGET_WIDE, "aget-wide", k23x, true, kNone, kContinue | kThrow | kLoad, kVerifyRegAWide | kVerifyRegB | kVerifyRegC) \ 77 | V(0x46, AGET_OBJECT, "aget-object", k23x, true, kNone, kContinue | kThrow | kLoad, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ 78 | V(0x47, AGET_BOOLEAN, "aget-boolean", k23x, true, kNone, kContinue | kThrow | kLoad, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ 79 | V(0x48, AGET_BYTE, "aget-byte", k23x, true, kNone, kContinue | kThrow | kLoad, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ 80 | V(0x49, AGET_CHAR, "aget-char", k23x, true, kNone, kContinue | kThrow | kLoad, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ 81 | V(0x4A, AGET_SHORT, "aget-short", k23x, true, kNone, kContinue | kThrow | kLoad, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ 82 | V(0x4B, APUT, "aput", k23x, false, kNone, kContinue | kThrow | kStore, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ 83 | V(0x4C, APUT_WIDE, "aput-wide", k23x, false, kNone, kContinue | kThrow | kStore, kVerifyRegAWide | kVerifyRegB | kVerifyRegC) \ 84 | V(0x4D, APUT_OBJECT, "aput-object", k23x, false, kNone, kContinue | kThrow | kStore, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ 85 | V(0x4E, APUT_BOOLEAN, "aput-boolean", k23x, false, kNone, kContinue | kThrow | kStore, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ 86 | V(0x4F, APUT_BYTE, "aput-byte", k23x, false, kNone, kContinue | kThrow | kStore, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ 87 | V(0x50, APUT_CHAR, "aput-char", k23x, false, kNone, kContinue | kThrow | kStore, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ 88 | V(0x51, APUT_SHORT, "aput-short", k23x, false, kNone, kContinue | kThrow | kStore, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ 89 | V(0x52, IGET, "iget", k22c, true, kFieldRef, kContinue | kThrow | kLoad | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \ 90 | V(0x53, IGET_WIDE, "iget-wide", k22c, true, kFieldRef, kContinue | kThrow | kLoad | kRegCFieldOrConstant, kVerifyRegAWide | kVerifyRegB | kVerifyRegCField) \ 91 | V(0x54, IGET_OBJECT, "iget-object", k22c, true, kFieldRef, kContinue | kThrow | kLoad | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \ 92 | V(0x55, IGET_BOOLEAN, "iget-boolean", k22c, true, kFieldRef, kContinue | kThrow | kLoad | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \ 93 | V(0x56, IGET_BYTE, "iget-byte", k22c, true, kFieldRef, kContinue | kThrow | kLoad | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \ 94 | V(0x57, IGET_CHAR, "iget-char", k22c, true, kFieldRef, kContinue | kThrow | kLoad | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \ 95 | V(0x58, IGET_SHORT, "iget-short", k22c, true, kFieldRef, kContinue | kThrow | kLoad | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \ 96 | V(0x59, IPUT, "iput", k22c, false, kFieldRef, kContinue | kThrow | kStore | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \ 97 | V(0x5A, IPUT_WIDE, "iput-wide", k22c, false, kFieldRef, kContinue | kThrow | kStore | kRegCFieldOrConstant, kVerifyRegAWide | kVerifyRegB | kVerifyRegCField) \ 98 | V(0x5B, IPUT_OBJECT, "iput-object", k22c, false, kFieldRef, kContinue | kThrow | kStore | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \ 99 | V(0x5C, IPUT_BOOLEAN, "iput-boolean", k22c, false, kFieldRef, kContinue | kThrow | kStore | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \ 100 | V(0x5D, IPUT_BYTE, "iput-byte", k22c, false, kFieldRef, kContinue | kThrow | kStore | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \ 101 | V(0x5E, IPUT_CHAR, "iput-char", k22c, false, kFieldRef, kContinue | kThrow | kStore | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \ 102 | V(0x5F, IPUT_SHORT, "iput-short", k22c, false, kFieldRef, kContinue | kThrow | kStore | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \ 103 | V(0x60, SGET, "sget", k21c, true, kFieldRef, kContinue | kThrow | kLoad | kRegBFieldOrConstant, kVerifyRegA | kVerifyRegBField) \ 104 | V(0x61, SGET_WIDE, "sget-wide", k21c, true, kFieldRef, kContinue | kThrow | kLoad | kRegBFieldOrConstant, kVerifyRegAWide | kVerifyRegBField) \ 105 | V(0x62, SGET_OBJECT, "sget-object", k21c, true, kFieldRef, kContinue | kThrow | kLoad | kRegBFieldOrConstant, kVerifyRegA | kVerifyRegBField) \ 106 | V(0x63, SGET_BOOLEAN, "sget-boolean", k21c, true, kFieldRef, kContinue | kThrow | kLoad | kRegBFieldOrConstant, kVerifyRegA | kVerifyRegBField) \ 107 | V(0x64, SGET_BYTE, "sget-byte", k21c, true, kFieldRef, kContinue | kThrow | kLoad | kRegBFieldOrConstant, kVerifyRegA | kVerifyRegBField) \ 108 | V(0x65, SGET_CHAR, "sget-char", k21c, true, kFieldRef, kContinue | kThrow | kLoad | kRegBFieldOrConstant, kVerifyRegA | kVerifyRegBField) \ 109 | V(0x66, SGET_SHORT, "sget-short", k21c, true, kFieldRef, kContinue | kThrow | kLoad | kRegBFieldOrConstant, kVerifyRegA | kVerifyRegBField) \ 110 | V(0x67, SPUT, "sput", k21c, false, kFieldRef, kContinue | kThrow | kStore | kRegBFieldOrConstant, kVerifyRegA | kVerifyRegBField) \ 111 | V(0x68, SPUT_WIDE, "sput-wide", k21c, false, kFieldRef, kContinue | kThrow | kStore | kRegBFieldOrConstant, kVerifyRegAWide | kVerifyRegBField) \ 112 | V(0x69, SPUT_OBJECT, "sput-object", k21c, false, kFieldRef, kContinue | kThrow | kStore | kRegBFieldOrConstant, kVerifyRegA | kVerifyRegBField) \ 113 | V(0x6A, SPUT_BOOLEAN, "sput-boolean", k21c, false, kFieldRef, kContinue | kThrow | kStore | kRegBFieldOrConstant, kVerifyRegA | kVerifyRegBField) \ 114 | V(0x6B, SPUT_BYTE, "sput-byte", k21c, false, kFieldRef, kContinue | kThrow | kStore | kRegBFieldOrConstant, kVerifyRegA | kVerifyRegBField) \ 115 | V(0x6C, SPUT_CHAR, "sput-char", k21c, false, kFieldRef, kContinue | kThrow | kStore | kRegBFieldOrConstant, kVerifyRegA | kVerifyRegBField) \ 116 | V(0x6D, SPUT_SHORT, "sput-short", k21c, false, kFieldRef, kContinue | kThrow | kStore | kRegBFieldOrConstant, kVerifyRegA | kVerifyRegBField) \ 117 | V(0x6E, INVOKE_VIRTUAL, "invoke-virtual", k35c, false, kMethodRef, kContinue | kThrow | kInvoke, kVerifyRegBMethod | kVerifyVarArgNonZero) \ 118 | V(0x6F, INVOKE_SUPER, "invoke-super", k35c, false, kMethodRef, kContinue | kThrow | kInvoke, kVerifyRegBMethod | kVerifyVarArgNonZero) \ 119 | V(0x70, INVOKE_DIRECT, "invoke-direct", k35c, false, kMethodRef, kContinue | kThrow | kInvoke, kVerifyRegBMethod | kVerifyVarArgNonZero) \ 120 | V(0x71, INVOKE_STATIC, "invoke-static", k35c, false, kMethodRef, kContinue | kThrow | kInvoke, kVerifyRegBMethod | kVerifyVarArg) \ 121 | V(0x72, INVOKE_INTERFACE, "invoke-interface", k35c, false, kMethodRef, kContinue | kThrow | kInvoke, kVerifyRegBMethod | kVerifyVarArgNonZero) \ 122 | V(0x73, RETURN_VOID_BARRIER, "return-void-barrier", k10x, false, kNone, kReturn, kVerifyNone) \ 123 | V(0x74, INVOKE_VIRTUAL_RANGE, "invoke-virtual/range", k3rc, false, kMethodRef, kContinue | kThrow | kInvoke, kVerifyRegBMethod | kVerifyVarArgRangeNonZero) \ 124 | V(0x75, INVOKE_SUPER_RANGE, "invoke-super/range", k3rc, false, kMethodRef, kContinue | kThrow | kInvoke, kVerifyRegBMethod | kVerifyVarArgRangeNonZero) \ 125 | V(0x76, INVOKE_DIRECT_RANGE, "invoke-direct/range", k3rc, false, kMethodRef, kContinue | kThrow | kInvoke, kVerifyRegBMethod | kVerifyVarArgRangeNonZero) \ 126 | V(0x77, INVOKE_STATIC_RANGE, "invoke-static/range", k3rc, false, kMethodRef, kContinue | kThrow | kInvoke, kVerifyRegBMethod | kVerifyVarArgRange) \ 127 | V(0x78, INVOKE_INTERFACE_RANGE, "invoke-interface/range", k3rc, false, kMethodRef, kContinue | kThrow | kInvoke, kVerifyRegBMethod | kVerifyVarArgRangeNonZero) \ 128 | V(0x79, UNUSED_79, "unused-79", k10x, false, kUnknown, 0, kVerifyError) \ 129 | V(0x7A, UNUSED_7A, "unused-7a", k10x, false, kUnknown, 0, kVerifyError) \ 130 | V(0x7B, NEG_INT, "neg-int", k12x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \ 131 | V(0x7C, NOT_INT, "not-int", k12x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \ 132 | V(0x7D, NEG_LONG, "neg-long", k12x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide) \ 133 | V(0x7E, NOT_LONG, "not-long", k12x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide) \ 134 | V(0x7F, NEG_FLOAT, "neg-float", k12x, true, kNone, kContinue, kVerifyRegA | kVerifyRegB) \ 135 | V(0x80, NEG_DOUBLE, "neg-double", k12x, true, kNone, kContinue, kVerifyRegAWide | kVerifyRegBWide) \ 136 | V(0x81, INT_TO_LONG, "int-to-long", k12x, true, kNone, kContinue | kCast, kVerifyRegAWide | kVerifyRegB) \ 137 | V(0x82, INT_TO_FLOAT, "int-to-float", k12x, true, kNone, kContinue | kCast, kVerifyRegA | kVerifyRegB) \ 138 | V(0x83, INT_TO_DOUBLE, "int-to-double", k12x, true, kNone, kContinue | kCast, kVerifyRegAWide | kVerifyRegB) \ 139 | V(0x84, LONG_TO_INT, "long-to-int", k12x, true, kNone, kContinue | kCast, kVerifyRegA | kVerifyRegBWide) \ 140 | V(0x85, LONG_TO_FLOAT, "long-to-float", k12x, true, kNone, kContinue | kCast, kVerifyRegA | kVerifyRegBWide) \ 141 | V(0x86, LONG_TO_DOUBLE, "long-to-double", k12x, true, kNone, kContinue | kCast, kVerifyRegAWide | kVerifyRegBWide) \ 142 | V(0x87, FLOAT_TO_INT, "float-to-int", k12x, true, kNone, kContinue | kCast, kVerifyRegA | kVerifyRegB) \ 143 | V(0x88, FLOAT_TO_LONG, "float-to-long", k12x, true, kNone, kContinue | kCast, kVerifyRegAWide | kVerifyRegB) \ 144 | V(0x89, FLOAT_TO_DOUBLE, "float-to-double", k12x, true, kNone, kContinue | kCast, kVerifyRegAWide | kVerifyRegB) \ 145 | V(0x8A, DOUBLE_TO_INT, "double-to-int", k12x, true, kNone, kContinue | kCast, kVerifyRegA | kVerifyRegBWide) \ 146 | V(0x8B, DOUBLE_TO_LONG, "double-to-long", k12x, true, kNone, kContinue | kCast, kVerifyRegAWide | kVerifyRegBWide) \ 147 | V(0x8C, DOUBLE_TO_FLOAT, "double-to-float", k12x, true, kNone, kContinue | kCast, kVerifyRegA | kVerifyRegBWide) \ 148 | V(0x8D, INT_TO_BYTE, "int-to-byte", k12x, true, kNone, kContinue | kCast, kVerifyRegA | kVerifyRegB) \ 149 | V(0x8E, INT_TO_CHAR, "int-to-char", k12x, true, kNone, kContinue | kCast, kVerifyRegA | kVerifyRegB) \ 150 | V(0x8F, INT_TO_SHORT, "int-to-short", k12x, true, kNone, kContinue | kCast, kVerifyRegA | kVerifyRegB) \ 151 | V(0x90, ADD_INT, "add-int", k23x, true, kNone, kContinue | kAdd, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ 152 | V(0x91, SUB_INT, "sub-int", k23x, true, kNone, kContinue | kSubtract, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ 153 | V(0x92, MUL_INT, "mul-int", k23x, true, kNone, kContinue | kMultiply, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ 154 | V(0x93, DIV_INT, "div-int", k23x, true, kNone, kContinue | kThrow | kDivide, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ 155 | V(0x94, REM_INT, "rem-int", k23x, true, kNone, kContinue | kThrow | kRemainder, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ 156 | V(0x95, AND_INT, "and-int", k23x, true, kNone, kContinue | kAnd, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ 157 | V(0x96, OR_INT, "or-int", k23x, true, kNone, kContinue | kOr, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ 158 | V(0x97, XOR_INT, "xor-int", k23x, true, kNone, kContinue | kXor, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ 159 | V(0x98, SHL_INT, "shl-int", k23x, true, kNone, kContinue | kShl, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ 160 | V(0x99, SHR_INT, "shr-int", k23x, true, kNone, kContinue | kShr, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ 161 | V(0x9A, USHR_INT, "ushr-int", k23x, true, kNone, kContinue | kUshr, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ 162 | V(0x9B, ADD_LONG, "add-long", k23x, true, kNone, kContinue | kAdd, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \ 163 | V(0x9C, SUB_LONG, "sub-long", k23x, true, kNone, kContinue | kSubtract, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \ 164 | V(0x9D, MUL_LONG, "mul-long", k23x, true, kNone, kContinue | kMultiply, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \ 165 | V(0x9E, DIV_LONG, "div-long", k23x, true, kNone, kContinue | kThrow | kDivide, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \ 166 | V(0x9F, REM_LONG, "rem-long", k23x, true, kNone, kContinue | kThrow | kRemainder, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \ 167 | V(0xA0, AND_LONG, "and-long", k23x, true, kNone, kContinue | kAnd, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \ 168 | V(0xA1, OR_LONG, "or-long", k23x, true, kNone, kContinue | kOr, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \ 169 | V(0xA2, XOR_LONG, "xor-long", k23x, true, kNone, kContinue | kXor, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \ 170 | V(0xA3, SHL_LONG, "shl-long", k23x, true, kNone, kContinue | kShl, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegC) \ 171 | V(0xA4, SHR_LONG, "shr-long", k23x, true, kNone, kContinue | kShr, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegC) \ 172 | V(0xA5, USHR_LONG, "ushr-long", k23x, true, kNone, kContinue | kUshr, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegC) \ 173 | V(0xA6, ADD_FLOAT, "add-float", k23x, true, kNone, kContinue | kAdd, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ 174 | V(0xA7, SUB_FLOAT, "sub-float", k23x, true, kNone, kContinue | kSubtract, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ 175 | V(0xA8, MUL_FLOAT, "mul-float", k23x, true, kNone, kContinue | kMultiply, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ 176 | V(0xA9, DIV_FLOAT, "div-float", k23x, true, kNone, kContinue | kDivide, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ 177 | V(0xAA, REM_FLOAT, "rem-float", k23x, true, kNone, kContinue | kRemainder, kVerifyRegA | kVerifyRegB | kVerifyRegC) \ 178 | V(0xAB, ADD_DOUBLE, "add-double", k23x, true, kNone, kContinue | kAdd, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \ 179 | V(0xAC, SUB_DOUBLE, "sub-double", k23x, true, kNone, kContinue | kSubtract, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \ 180 | V(0xAD, MUL_DOUBLE, "mul-double", k23x, true, kNone, kContinue | kMultiply, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \ 181 | V(0xAE, DIV_DOUBLE, "div-double", k23x, true, kNone, kContinue | kDivide, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \ 182 | V(0xAF, REM_DOUBLE, "rem-double", k23x, true, kNone, kContinue | kRemainder, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \ 183 | V(0xB0, ADD_INT_2ADDR, "add-int/2addr", k12x, true, kNone, kContinue | kAdd, kVerifyRegA | kVerifyRegB) \ 184 | V(0xB1, SUB_INT_2ADDR, "sub-int/2addr", k12x, true, kNone, kContinue | kSubtract, kVerifyRegA | kVerifyRegB) \ 185 | V(0xB2, MUL_INT_2ADDR, "mul-int/2addr", k12x, true, kNone, kContinue | kMultiply, kVerifyRegA | kVerifyRegB) \ 186 | V(0xB3, DIV_INT_2ADDR, "div-int/2addr", k12x, true, kNone, kContinue | kThrow | kDivide, kVerifyRegA | kVerifyRegB) \ 187 | V(0xB4, REM_INT_2ADDR, "rem-int/2addr", k12x, true, kNone, kContinue | kThrow | kRemainder, kVerifyRegA | kVerifyRegB) \ 188 | V(0xB5, AND_INT_2ADDR, "and-int/2addr", k12x, true, kNone, kContinue | kAnd, kVerifyRegA | kVerifyRegB) \ 189 | V(0xB6, OR_INT_2ADDR, "or-int/2addr", k12x, true, kNone, kContinue | kOr, kVerifyRegA | kVerifyRegB) \ 190 | V(0xB7, XOR_INT_2ADDR, "xor-int/2addr", k12x, true, kNone, kContinue | kXor, kVerifyRegA | kVerifyRegB) \ 191 | V(0xB8, SHL_INT_2ADDR, "shl-int/2addr", k12x, true, kNone, kContinue | kShl, kVerifyRegA | kVerifyRegB) \ 192 | V(0xB9, SHR_INT_2ADDR, "shr-int/2addr", k12x, true, kNone, kContinue | kShr, kVerifyRegA | kVerifyRegB) \ 193 | V(0xBA, USHR_INT_2ADDR, "ushr-int/2addr", k12x, true, kNone, kContinue | kUshr, kVerifyRegA | kVerifyRegB) \ 194 | V(0xBB, ADD_LONG_2ADDR, "add-long/2addr", k12x, true, kNone, kContinue | kAdd, kVerifyRegAWide | kVerifyRegBWide) \ 195 | V(0xBC, SUB_LONG_2ADDR, "sub-long/2addr", k12x, true, kNone, kContinue | kSubtract, kVerifyRegAWide | kVerifyRegBWide) \ 196 | V(0xBD, MUL_LONG_2ADDR, "mul-long/2addr", k12x, true, kNone, kContinue | kMultiply, kVerifyRegAWide | kVerifyRegBWide) \ 197 | V(0xBE, DIV_LONG_2ADDR, "div-long/2addr", k12x, true, kNone, kContinue | kThrow | kDivide, kVerifyRegAWide | kVerifyRegBWide) \ 198 | V(0xBF, REM_LONG_2ADDR, "rem-long/2addr", k12x, true, kNone, kContinue | kThrow | kRemainder, kVerifyRegAWide | kVerifyRegBWide) \ 199 | V(0xC0, AND_LONG_2ADDR, "and-long/2addr", k12x, true, kNone, kContinue | kAnd, kVerifyRegAWide | kVerifyRegBWide) \ 200 | V(0xC1, OR_LONG_2ADDR, "or-long/2addr", k12x, true, kNone, kContinue | kOr, kVerifyRegAWide | kVerifyRegBWide) \ 201 | V(0xC2, XOR_LONG_2ADDR, "xor-long/2addr", k12x, true, kNone, kContinue | kXor, kVerifyRegAWide | kVerifyRegBWide) \ 202 | V(0xC3, SHL_LONG_2ADDR, "shl-long/2addr", k12x, true, kNone, kContinue | kShl, kVerifyRegAWide | kVerifyRegB) \ 203 | V(0xC4, SHR_LONG_2ADDR, "shr-long/2addr", k12x, true, kNone, kContinue | kShr, kVerifyRegAWide | kVerifyRegB) \ 204 | V(0xC5, USHR_LONG_2ADDR, "ushr-long/2addr", k12x, true, kNone, kContinue | kUshr, kVerifyRegAWide | kVerifyRegB) \ 205 | V(0xC6, ADD_FLOAT_2ADDR, "add-float/2addr", k12x, true, kNone, kContinue | kAdd, kVerifyRegA | kVerifyRegB) \ 206 | V(0xC7, SUB_FLOAT_2ADDR, "sub-float/2addr", k12x, true, kNone, kContinue | kSubtract, kVerifyRegA | kVerifyRegB) \ 207 | V(0xC8, MUL_FLOAT_2ADDR, "mul-float/2addr", k12x, true, kNone, kContinue | kMultiply, kVerifyRegA | kVerifyRegB) \ 208 | V(0xC9, DIV_FLOAT_2ADDR, "div-float/2addr", k12x, true, kNone, kContinue | kDivide, kVerifyRegA | kVerifyRegB) \ 209 | V(0xCA, REM_FLOAT_2ADDR, "rem-float/2addr", k12x, true, kNone, kContinue | kRemainder, kVerifyRegA | kVerifyRegB) \ 210 | V(0xCB, ADD_DOUBLE_2ADDR, "add-double/2addr", k12x, true, kNone, kContinue | kAdd, kVerifyRegAWide | kVerifyRegBWide) \ 211 | V(0xCC, SUB_DOUBLE_2ADDR, "sub-double/2addr", k12x, true, kNone, kContinue | kSubtract, kVerifyRegAWide | kVerifyRegBWide) \ 212 | V(0xCD, MUL_DOUBLE_2ADDR, "mul-double/2addr", k12x, true, kNone, kContinue | kMultiply, kVerifyRegAWide | kVerifyRegBWide) \ 213 | V(0xCE, DIV_DOUBLE_2ADDR, "div-double/2addr", k12x, true, kNone, kContinue | kDivide, kVerifyRegAWide | kVerifyRegBWide) \ 214 | V(0xCF, REM_DOUBLE_2ADDR, "rem-double/2addr", k12x, true, kNone, kContinue | kRemainder, kVerifyRegAWide | kVerifyRegBWide) \ 215 | V(0xD0, ADD_INT_LIT16, "add-int/lit16", k22s, true, kNone, kContinue | kAdd | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \ 216 | V(0xD1, RSUB_INT, "rsub-int", k22s, true, kNone, kContinue | kSubtract | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \ 217 | V(0xD2, MUL_INT_LIT16, "mul-int/lit16", k22s, true, kNone, kContinue | kMultiply | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \ 218 | V(0xD3, DIV_INT_LIT16, "div-int/lit16", k22s, true, kNone, kContinue | kThrow | kDivide | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \ 219 | V(0xD4, REM_INT_LIT16, "rem-int/lit16", k22s, true, kNone, kContinue | kThrow | kRemainder | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \ 220 | V(0xD5, AND_INT_LIT16, "and-int/lit16", k22s, true, kNone, kContinue | kAnd | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \ 221 | V(0xD6, OR_INT_LIT16, "or-int/lit16", k22s, true, kNone, kContinue | kOr | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \ 222 | V(0xD7, XOR_INT_LIT16, "xor-int/lit16", k22s, true, kNone, kContinue | kXor | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \ 223 | V(0xD8, ADD_INT_LIT8, "add-int/lit8", k22b, true, kNone, kContinue | kAdd | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \ 224 | V(0xD9, RSUB_INT_LIT8, "rsub-int/lit8", k22b, true, kNone, kContinue | kSubtract | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \ 225 | V(0xDA, MUL_INT_LIT8, "mul-int/lit8", k22b, true, kNone, kContinue | kMultiply | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \ 226 | V(0xDB, DIV_INT_LIT8, "div-int/lit8", k22b, true, kNone, kContinue | kThrow | kDivide | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \ 227 | V(0xDC, REM_INT_LIT8, "rem-int/lit8", k22b, true, kNone, kContinue | kThrow | kRemainder | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \ 228 | V(0xDD, AND_INT_LIT8, "and-int/lit8", k22b, true, kNone, kContinue | kAnd | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \ 229 | V(0xDE, OR_INT_LIT8, "or-int/lit8", k22b, true, kNone, kContinue | kOr | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \ 230 | V(0xDF, XOR_INT_LIT8, "xor-int/lit8", k22b, true, kNone, kContinue | kXor | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \ 231 | V(0xE0, SHL_INT_LIT8, "shl-int/lit8", k22b, true, kNone, kContinue | kShl | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \ 232 | V(0xE1, SHR_INT_LIT8, "shr-int/lit8", k22b, true, kNone, kContinue | kShr | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \ 233 | V(0xE2, USHR_INT_LIT8, "ushr-int/lit8", k22b, true, kNone, kContinue | kUshr | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \ 234 | V(0xE3, IGET_QUICK, "iget-quick", k22c, true, kFieldRef, kContinue | kThrow | kLoad | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRuntimeOnly) \ 235 | V(0xE4, IGET_WIDE_QUICK, "iget-wide-quick", k22c, true, kFieldRef, kContinue | kThrow | kLoad | kRegCFieldOrConstant, kVerifyRegAWide | kVerifyRegB | kVerifyRuntimeOnly) \ 236 | V(0xE5, IGET_OBJECT_QUICK, "iget-object-quick", k22c, true, kFieldRef, kContinue | kThrow | kLoad | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRuntimeOnly) \ 237 | V(0xE6, IPUT_QUICK, "iput-quick", k22c, false, kFieldRef, kContinue | kThrow | kStore | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRuntimeOnly) \ 238 | V(0xE7, IPUT_WIDE_QUICK, "iput-wide-quick", k22c, false, kFieldRef, kContinue | kThrow | kStore | kRegCFieldOrConstant, kVerifyRegAWide | kVerifyRegB | kVerifyRuntimeOnly) \ 239 | V(0xE8, IPUT_OBJECT_QUICK, "iput-object-quick", k22c, false, kFieldRef, kContinue | kThrow | kStore | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRuntimeOnly) \ 240 | V(0xE9, INVOKE_VIRTUAL_QUICK, "invoke-virtual-quick", k35c, false, kMethodRef, kContinue | kThrow | kInvoke, kVerifyVarArgNonZero | kVerifyRuntimeOnly) \ 241 | V(0xEA, INVOKE_VIRTUAL_RANGE_QUICK, "invoke-virtual/range-quick", k3rc, false, kMethodRef, kContinue | kThrow | kInvoke, kVerifyVarArgRangeNonZero | kVerifyRuntimeOnly) \ 242 | V(0xEB, UNUSED_EB, "unused-eb", k10x, false, kUnknown, 0, kVerifyError) \ 243 | V(0xEC, UNUSED_EC, "unused-ec", k10x, false, kUnknown, 0, kVerifyError) \ 244 | V(0xED, UNUSED_ED, "unused-ed", k10x, false, kUnknown, 0, kVerifyError) \ 245 | V(0xEE, UNUSED_EE, "unused-ee", k10x, false, kUnknown, 0, kVerifyError) \ 246 | V(0xEF, UNUSED_EF, "unused-ef", k10x, false, kUnknown, 0, kVerifyError) \ 247 | V(0xF0, UNUSED_F0, "unused-f0", k10x, false, kUnknown, 0, kVerifyError) \ 248 | V(0xF1, UNUSED_F1, "unused-f1", k10x, false, kUnknown, 0, kVerifyError) \ 249 | V(0xF2, UNUSED_F2, "unused-f2", k10x, false, kUnknown, 0, kVerifyError) \ 250 | V(0xF3, UNUSED_F3, "unused-f3", k10x, false, kUnknown, 0, kVerifyError) \ 251 | V(0xF4, UNUSED_F4, "unused-f4", k10x, false, kUnknown, 0, kVerifyError) \ 252 | V(0xF5, UNUSED_F5, "unused-f5", k10x, false, kUnknown, 0, kVerifyError) \ 253 | V(0xF6, UNUSED_F6, "unused-f6", k10x, false, kUnknown, 0, kVerifyError) \ 254 | V(0xF7, UNUSED_F7, "unused-f7", k10x, false, kUnknown, 0, kVerifyError) \ 255 | V(0xF8, UNUSED_F8, "unused-f8", k10x, false, kUnknown, 0, kVerifyError) \ 256 | V(0xF9, UNUSED_F9, "unused-f9", k10x, false, kUnknown, 0, kVerifyError) \ 257 | V(0xFA, UNUSED_FA, "unused-fa", k10x, false, kUnknown, 0, kVerifyError) \ 258 | V(0xFB, UNUSED_FB, "unused-fb", k10x, false, kUnknown, 0, kVerifyError) \ 259 | V(0xFC, UNUSED_FC, "unused-fc", k10x, false, kUnknown, 0, kVerifyError) \ 260 | V(0xFD, UNUSED_FD, "unused-fd", k10x, false, kUnknown, 0, kVerifyError) \ 261 | V(0xFE, UNUSED_FE, "unused-fe", k10x, false, kUnknown, 0, kVerifyError) \ 262 | V(0xFF, UNUSED_FF, "unused-ff", k10x, false, kUnknown, 0, kVerifyError) 263 | 264 | #define DEX_INSTRUCTION_FORMAT_LIST(V) \ 265 | V(k10x) \ 266 | V(k12x) \ 267 | V(k11n) \ 268 | V(k11x) \ 269 | V(k10t) \ 270 | V(k20t) \ 271 | V(k22x) \ 272 | V(k21t) \ 273 | V(k21s) \ 274 | V(k21h) \ 275 | V(k21c) \ 276 | V(k23x) \ 277 | V(k22b) \ 278 | V(k22t) \ 279 | V(k22s) \ 280 | V(k22c) \ 281 | V(k32x) \ 282 | V(k30t) \ 283 | V(k31t) \ 284 | V(k31i) \ 285 | V(k31c) \ 286 | V(k35c) \ 287 | V(k3rc) \ 288 | V(k51l) 289 | 290 | #endif 291 | #undef _ART_DEX_INSTRUCTION_LIST_H_ // the guard in this file is just for cpplint 292 | -------------------------------------------------------------------------------- /engine/dumper/dumper.cc: -------------------------------------------------------------------------------- 1 | 2 | #include "globals.h" 3 | #include "cmd_opt.h" 4 | #include "log.h" 5 | 6 | #include "scoped_fd.h" 7 | #include "scoped_map.h" 8 | #include "stringprintf.h" 9 | 10 | #include "dex_file.h" 11 | #include "dex_instruction.h" 12 | 13 | 14 | void SkipAllFields(); 15 | void DumpDexFile(std::ostream&, char, const DexFile&); 16 | void DumpDexClass(std::ostream&, char, const DexFile&, const DexFile::ClassDef&); 17 | void DumpDexCode(std::ostream&, const DexFile&, const DexFile::CodeItem*); 18 | 19 | 20 | int main(int argc, char** argv) 21 | { 22 | char opt_granu, *opt_in, *opt_out; 23 | 24 | if (!ParseDumperOption(argc, argv, &opt_granu, &opt_in, &opt_out)) 25 | return EXIT_FAILURE; 26 | 27 | // Calculate the to be mapped space size. 28 | ScopedFd fd(open(opt_in, O_RDONLY, 0)); 29 | if (fd.get() == -1) 30 | LOG(FATAL) << "Fail to open the dex file."; 31 | size_t size = static_cast(lseek(fd.get(), 0, SEEK_END)); 32 | div_t result = div(size, kPageSize); 33 | size_t algn_size = (result.rem != 0)? (kPageSize * (result.quot + 1)) : 34 | (kPageSize * result.quot); 35 | 36 | // Map the file into memory. 37 | byte* base = reinterpret_cast(mmap(nullptr, size, PROT_READ, 38 | MAP_PRIVATE, fd.get(), 0)); 39 | if (base == MAP_FAILED) 40 | LOG(FATAL) << "Fail to map the dex file into memory."; 41 | ScopedMap mem_map(base, size, algn_size); 42 | std::unique_ptr dex_file(DexFile::OpenMemory(mem_map)); 43 | if (dex_file.get() == nullptr) 44 | return EXIT_FAILURE; 45 | 46 | if (!opt_out) 47 | DumpDexFile(std::cout, opt_granu, *dex_file.get()); 48 | else { 49 | std::ofstream ofs(opt_out, std::ofstream::out); 50 | if (!ofs.good()) 51 | return EXIT_FAILURE; 52 | DumpDexFile(ofs, opt_granu, *dex_file.get()); 53 | } 54 | return EXIT_SUCCESS; 55 | } 56 | 57 | 58 | void SkipAllFields(ClassDataItemIterator& it) 59 | { 60 | while (it.HasNextStaticField()) 61 | it.Next(); 62 | while (it.HasNextInstanceField()) 63 | it.Next(); 64 | } 65 | 66 | void DumpDexFile(std::ostream& os, char opt_granu, const DexFile& dex_file) 67 | { 68 | uint32_t num_class_def = dex_file.NumClassDefs(); 69 | for (uint32_t class_def_idx = 0 ; class_def_idx < num_class_def ; ++class_def_idx) { 70 | os << StringPrintf("%d: %s\n", class_def_idx, 71 | PrettyClass(class_def_idx, dex_file).c_str()); 72 | if (opt_granu == kGranuCodeClass) 73 | continue; 74 | const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_idx); 75 | DumpDexClass(os, opt_granu, dex_file, class_def); 76 | os << '\n'; 77 | } 78 | } 79 | 80 | void DumpDexClass(std::ostream& os, char opt_granu, const DexFile& dex_file, 81 | const DexFile::ClassDef& class_def) 82 | { 83 | const byte* class_data = dex_file.GetClassData(class_def); 84 | if (class_data == nullptr) // empty class such as a marker interface? 85 | return; 86 | 87 | ClassDataItemIterator it(dex_file, class_data); 88 | SkipAllFields(it); 89 | 90 | uint32_t class_method_idx = 0; 91 | while (it.HasNextDirectMethod()) { 92 | uint32_t dex_method_idx = it.GetMemberIndex(); 93 | os << StringPrintf("\t%d: %s (dex_method_idx=%d)\n", class_method_idx, 94 | PrettyMethod(dex_method_idx, dex_file, true).c_str(), 95 | dex_method_idx); 96 | if (opt_granu == kGranuCodeInstruction) { 97 | const DexFile::CodeItem* code_item = it.GetMethodCodeItem(); 98 | DumpDexCode(os, dex_file, code_item); 99 | os << '\n'; 100 | } 101 | it.Next(); 102 | ++class_method_idx; 103 | } 104 | 105 | while (it.HasNextVirtualMethod()) { 106 | uint32_t dex_method_idx = it.GetMemberIndex(); 107 | os << StringPrintf("\t%d: %s (dex_method_idx=%d)\n", class_method_idx, 108 | PrettyMethod(dex_method_idx, dex_file, true).c_str(), 109 | dex_method_idx); 110 | if (opt_granu == kGranuCodeInstruction) { 111 | const DexFile::CodeItem* code_item = it.GetMethodCodeItem(); 112 | DumpDexCode(os, dex_file, code_item); 113 | os << '\n'; 114 | } 115 | it.Next(); 116 | ++class_method_idx; 117 | } 118 | CHECK(!it.HasNext()); 119 | } 120 | 121 | void DumpDexCode(std::ostream& os, const DexFile& dex_file, 122 | const DexFile::CodeItem* code_item) 123 | { 124 | if (!code_item) 125 | return; 126 | size_t inst_off = 0; 127 | while (inst_off < code_item->insns_size_in_code_units_) { 128 | const Instruction* instruction = Instruction::At(&code_item->insns_[inst_off]); 129 | os << StringPrintf("\t\t0x%04zx: %s\n", inst_off, 130 | instruction->DumpString(&dex_file).c_str()); 131 | inst_off += instruction->SizeInCodeUnits(); 132 | } 133 | } -------------------------------------------------------------------------------- /engine/dumper/invoke_type.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _ART_INVOKE_TYPE_H_ 3 | #define _ART_INVOKE_TYPE_H_ 4 | 5 | 6 | enum InvokeType 7 | { 8 | kStatic, // <> 9 | kDirect, // <> 10 | kVirtual, // <> 11 | kSuper, // <> 12 | kInterface, // <> 13 | kMaxInvokeType = kInterface 14 | }; 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /engine/dumper/leb128.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _ART_LEB128_H_ 3 | #define _ART_LEB128_H_ 4 | 5 | 6 | #include "globals.h" 7 | #include "misc.h" 8 | 9 | 10 | // Reads an unsigned LEB128 value, updating the given pointer to point 11 | // just past the end of the read value. This function tolerates 12 | // non-zero high-order bits in the fifth encoded byte. 13 | static inline uint32_t DecodeUnsignedLeb128(const uint8_t** data) 14 | { 15 | const uint8_t* ptr = *data; 16 | int result = *(ptr++); 17 | if (UNLIKELY(result > 0x7f)) { 18 | int cur = *(ptr++); 19 | result = (result & 0x7f) | ((cur & 0x7f) << 7); 20 | if (cur > 0x7f) { 21 | cur = *(ptr++); 22 | result |= (cur & 0x7f) << 14; 23 | if (cur > 0x7f) { 24 | cur = *(ptr++); 25 | result |= (cur & 0x7f) << 21; 26 | if (cur > 0x7f) { 27 | // Note: We don't check to see if cur is out of range here, 28 | // meaning we tolerate garbage in the four high-order bits. 29 | cur = *(ptr++); 30 | result |= cur << 28; 31 | } 32 | } 33 | } 34 | } 35 | *data = ptr; 36 | return static_cast(result); 37 | } 38 | 39 | // Reads an unsigned LEB128 + 1 value. updating the given pointer to point 40 | // just past the end of the read value. This function tolerates 41 | // non-zero high-order bits in the fifth encoded byte. 42 | // It is possible for this function to return -1. 43 | static inline int32_t DecodeUnsignedLeb128P1(const uint8_t** data) 44 | { 45 | return DecodeUnsignedLeb128(data) - 1; 46 | } 47 | 48 | // Reads a signed LEB128 value, updating the given pointer to point 49 | // just past the end of the read value. This function tolerates 50 | // non-zero high-order bits in the fifth encoded byte. 51 | static inline int32_t DecodeSignedLeb128(const uint8_t** data) 52 | { 53 | const uint8_t* ptr = *data; 54 | int32_t result = *(ptr++); 55 | if (result <= 0x7f) 56 | result = (result << 25) >> 25; 57 | else { 58 | int cur = *(ptr++); 59 | result = (result & 0x7f) | ((cur & 0x7f) << 7); 60 | if (cur <= 0x7f) 61 | result = (result << 18) >> 18; 62 | else { 63 | cur = *(ptr++); 64 | result |= (cur & 0x7f) << 14; 65 | if (cur <= 0x7f) 66 | result = (result << 11) >> 11; 67 | else { 68 | cur = *(ptr++); 69 | result |= (cur & 0x7f) << 21; 70 | if (cur <= 0x7f) 71 | result = (result << 4) >> 4; 72 | else { 73 | // Note: We don't check to see if cur is out of range here, 74 | // meaning we tolerate garbage in the four high-order bits. 75 | cur = *(ptr++); 76 | result |= cur << 28; 77 | } 78 | } 79 | } 80 | } 81 | *data = ptr; 82 | return result; 83 | } 84 | 85 | // Returns the number of bytes needed to encode the value in unsigned LEB128. 86 | static inline uint32_t UnsignedLeb128Size(uint32_t data) 87 | { 88 | // bits_to_encode = (data != 0) ? 32 - CLZ(x) : 1 // 32 - CLZ(data | 1) 89 | // bytes = ceil(bits_to_encode / 7.0); // (6 + bits_to_encode) / 7 90 | uint32_t x = 6 + 32 - CLZ(data | 1); 91 | // Division by 7 is done by (x * 37) >> 8 where 37 = ceil(256 / 7). 92 | // This works for 0 <= x < 256 / (7 * 37 - 256), i.e. 0 <= x <= 85. 93 | return (x * 37) >> 8; 94 | } 95 | 96 | // Returns the number of bytes needed to encode the value in unsigned LEB128. 97 | static inline uint32_t SignedLeb128Size(int32_t data) 98 | { 99 | // Like UnsignedLeb128Size(), but we need one bit beyond the highest bit that differs from sign. 100 | data = data ^ (data >> 31); 101 | uint32_t x = 1 /* we need to encode the sign bit */ + 6 + 32 - CLZ(data | 1); 102 | return (x * 37) >> 8; 103 | } 104 | 105 | static inline uint8_t* EncodeUnsignedLeb128(uint8_t* dest, uint32_t value) 106 | { 107 | uint8_t out = value & 0x7f; 108 | value >>= 7; 109 | while (value != 0) { 110 | *dest++ = out | 0x80; 111 | out = value & 0x7f; 112 | value >>= 7; 113 | } 114 | *dest++ = out; 115 | return dest; 116 | } 117 | 118 | static inline uint8_t* EncodeSignedLeb128(uint8_t* dest, int32_t value) 119 | { 120 | uint32_t extra_bits = static_cast(value ^ (value >> 31)) >> 6; 121 | uint8_t out = value & 0x7f; 122 | while (extra_bits != 0u) { 123 | *dest++ = out | 0x80; 124 | value >>= 7; 125 | out = value & 0x7f; 126 | extra_bits >>= 7; 127 | } 128 | *dest++ = out; 129 | return dest; 130 | } 131 | 132 | #endif 133 | -------------------------------------------------------------------------------- /engine/dumper/modifiers.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _ART_MODIFIERS_H_ 3 | #define _ART_MODIFIERS_H_ 4 | 5 | 6 | #include "globals.h" 7 | 8 | 9 | static constexpr uint32_t kAccPublic = 0x0001; // class, field, method, ic 10 | static constexpr uint32_t kAccPrivate = 0x0002; // field, method, ic 11 | static constexpr uint32_t kAccProtected = 0x0004; // field, method, ic 12 | static constexpr uint32_t kAccStatic = 0x0008; // field, method, ic 13 | static constexpr uint32_t kAccFinal = 0x0010; // class, field, method, ic 14 | static constexpr uint32_t kAccSynchronized = 0x0020; // method (only allowed on natives) 15 | static constexpr uint32_t kAccSuper = 0x0020; // class (not used in dex) 16 | static constexpr uint32_t kAccVolatile = 0x0040; // field 17 | static constexpr uint32_t kAccBridge = 0x0040; // method (1.5) 18 | static constexpr uint32_t kAccTransient = 0x0080; // field 19 | static constexpr uint32_t kAccVarargs = 0x0080; // method (1.5) 20 | static constexpr uint32_t kAccNative = 0x0100; // method 21 | static constexpr uint32_t kAccInterface = 0x0200; // class, ic 22 | static constexpr uint32_t kAccAbstract = 0x0400; // class, method, ic 23 | static constexpr uint32_t kAccStrict = 0x0800; // method 24 | static constexpr uint32_t kAccSynthetic = 0x1000; // class, field, method, ic 25 | static constexpr uint32_t kAccAnnotation = 0x2000; // class, ic (1.5) 26 | static constexpr uint32_t kAccEnum = 0x4000; // class, field, ic (1.5) 27 | 28 | static constexpr uint32_t kAccJavaFlagsMask = 0xffff; // bits set from Java sources (low 16) 29 | 30 | static constexpr uint32_t kAccConstructor = 0x00010000; // method (dex only) <(cl)init> 31 | static constexpr uint32_t kAccDeclaredSynchronized = 0x00020000; // method (dex only) 32 | static constexpr uint32_t kAccClassIsProxy = 0x00040000; // class (dex only) 33 | static constexpr uint32_t kAccPreverified = 0x00080000; // class (runtime), 34 | // method (dex only) 35 | static constexpr uint32_t kAccFastNative = 0x00080000; // method (dex only) 36 | static constexpr uint32_t kAccPortableCompiled = 0x00100000; // method (dex only) 37 | static constexpr uint32_t kAccMiranda = 0x00200000; // method (dex only) 38 | 39 | // Special runtime-only flags. 40 | // Note: if only kAccClassIsReference is set, we have a soft reference. 41 | 42 | // class/ancestor overrides finalize() 43 | static constexpr uint32_t kAccClassIsFinalizable = 0x80000000; 44 | // class is a soft/weak/phantom ref 45 | static constexpr uint32_t kAccClassIsReference = 0x08000000; 46 | // class is a weak reference 47 | static constexpr uint32_t kAccClassIsWeakReference = 0x04000000; 48 | // class is a finalizer reference 49 | static constexpr uint32_t kAccClassIsFinalizerReference = 0x02000000; 50 | // class is a phantom reference 51 | static constexpr uint32_t kAccClassIsPhantomReference = 0x01000000; 52 | 53 | static constexpr uint32_t kAccReferenceFlagsMask = (kAccClassIsReference 54 | | kAccClassIsWeakReference 55 | | kAccClassIsFinalizerReference 56 | | kAccClassIsPhantomReference); 57 | 58 | // Valid (meaningful) bits for a field. 59 | static constexpr uint32_t kAccValidFieldFlags = kAccPublic | kAccPrivate | kAccProtected | 60 | kAccStatic | kAccFinal | kAccVolatile | kAccTransient | kAccSynthetic | kAccEnum; 61 | 62 | // Valid (meaningful) bits for a method. 63 | static constexpr uint32_t kAccValidMethodFlags = kAccPublic | kAccPrivate | kAccProtected | 64 | kAccStatic | kAccFinal | kAccSynchronized | kAccBridge | kAccVarargs | kAccNative | 65 | kAccAbstract | kAccStrict | kAccSynthetic | kAccMiranda | kAccConstructor | 66 | kAccDeclaredSynchronized; 67 | 68 | // Valid (meaningful) bits for a class (not interface). 69 | // Note 1. These are positive bits. Other bits may have to be zero. 70 | // Note 2. Inner classes can expose more access flags to Java programs. That is handled by libcore. 71 | static constexpr uint32_t kAccValidClassFlags = kAccPublic | kAccFinal | kAccSuper | 72 | kAccAbstract | kAccSynthetic | kAccEnum; 73 | 74 | // Valid (meaningful) bits for an interface. 75 | // Note 1. Annotations are interfaces. 76 | // Note 2. These are positive bits. Other bits may have to be zero. 77 | // Note 3. Inner classes can expose more access flags to Java programs. That is handled by libcore. 78 | static constexpr uint32_t kAccValidInterfaceFlags = kAccPublic | kAccInterface | 79 | kAccAbstract | kAccSynthetic | kAccAnnotation; 80 | 81 | #endif 82 | 83 | -------------------------------------------------------------------------------- /util/cmd_opt.cc: -------------------------------------------------------------------------------- 1 | 2 | #include "cmd_opt.h" 3 | 4 | 5 | static void PrintDumperUsage() 6 | { 7 | const char *usage = \ 8 | "Usage: dumper [options]\n" 9 | " Example: dumper --granularity=instruction --input=/PATH/TO/MY/DEX --output=PATH/TO/MY/TXT\n\n" 10 | " --granularity=(class|method|instruction): For data granularity\n" 11 | " class : List class names only\n" 12 | " method : List method signatures only\n" 13 | " instruction: Full dump\n\n" 14 | " --input=: Specify the input dex pathname\n\n" 15 | " --output=: Specify the output dump pathname\n\n"; 16 | std::cerr << usage; 17 | } 18 | 19 | 20 | bool ParseDumperOption(int argc, char **argv, 21 | char *opt_granu, char **opt_in, char **opt_out) 22 | { 23 | struct option opts[] = { 24 | {kOptLongGranularity, required_argument, 0, kOptGranularity}, 25 | {kOptLongInput, required_argument, 0, kOptInput}, 26 | {kOptLongOutput, required_argument, 0, kOptOutput}, 27 | }; 28 | 29 | char order[kBlahSizeTiny]; 30 | memset(order, 0, sizeof(char) * kBlahSizeTiny); 31 | sprintf(order, "%c:%c:%c:", kOptGranularity, kOptInput, kOptOutput); 32 | 33 | char *granu_str = nullptr; 34 | *opt_in = *opt_out = nullptr; 35 | int opt, idx_opt; 36 | pid_t pid_zygote = 0; 37 | char *sz_app = NULL, *sz_path = NULL; 38 | while ((opt = getopt_long(argc, argv, order, opts, &idx_opt)) != -1) { 39 | switch (opt) { 40 | case kOptGranularity: 41 | granu_str = optarg; 42 | break; 43 | case kOptInput: 44 | *opt_in = optarg; 45 | break; 46 | case kOptOutput: 47 | *opt_out = optarg; 48 | break; 49 | default: 50 | PrintDumperUsage(); 51 | return false; 52 | } 53 | } 54 | 55 | if (*opt_in == nullptr) { 56 | PrintDumperUsage(); 57 | return false; 58 | } 59 | if (granu_str == nullptr) 60 | granu_str = const_cast(kGranularityInstruction); 61 | 62 | if (strcmp(granu_str, kGranularityClass) == 0) 63 | *opt_granu = kGranuCodeClass; 64 | else { 65 | if (strcmp(granu_str, kGranularityMethod) == 0) 66 | *opt_granu = kGranuCodeMethod; 67 | else { 68 | if (strcmp(granu_str, kGranularityInstruction) == 0) 69 | *opt_granu = kGranuCodeInstruction; 70 | else { 71 | PrintDumperUsage(); 72 | return false; 73 | } 74 | } 75 | } 76 | return true; 77 | } -------------------------------------------------------------------------------- /util/cmd_opt.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _UTIL_CMD_OPT_H_ 3 | #define _UTIL_CMD_OPT_H_ 4 | 5 | 6 | #include "globals.h" 7 | 8 | 9 | static const char* kOptLongGranularity = "granularity"; 10 | static const char* kOptLongInput = "input"; 11 | static const char* kOptLongOutput = "output"; 12 | 13 | static const char kOptGranularity = 'g'; 14 | static const char kOptInput = 'i'; 15 | static const char kOptOutput = 'o'; 16 | 17 | static const char* kGranularityClass = "class"; 18 | static const char* kGranularityMethod = "method"; 19 | static const char* kGranularityInstruction = "instruction"; 20 | 21 | static const char kGranuCodeClass = 'c'; 22 | static const char kGranuCodeMethod = 'm'; 23 | static const char kGranuCodeInstruction = 'i'; 24 | 25 | bool ParseDumperOption(int argc, char **argv, 26 | char *opt_granu, char **opt_in, char **opt_out); 27 | 28 | #endif -------------------------------------------------------------------------------- /util/globals.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _UTIL_GLOBALS_H_ 3 | #define _UTIL_GLOBALS_H_ 4 | 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | #include 26 | #include 27 | #include 28 | 29 | #include 30 | #include 31 | #include 32 | 33 | 34 | typedef uint8_t byte; 35 | typedef intptr_t word; 36 | typedef uintptr_t uword; 37 | 38 | static constexpr size_t KB = 1024; 39 | static constexpr size_t MB = KB * KB; 40 | static constexpr size_t GB = KB * KB * KB; 41 | 42 | // System page size. 43 | static constexpr int kPageSize = 4096; 44 | 45 | // Auxiliary buffer size. 46 | static constexpr int kBlahSize = 1024; 47 | static constexpr int kBlahSizeTiny = 128; 48 | 49 | #endif -------------------------------------------------------------------------------- /util/log.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "log.h" 18 | 19 | 20 | void LogMessage::LogLine(const LogMessageData& data, const char* message) 21 | { 22 | char severity = "VDIWEFF"[data.severity]; 23 | fprintf(stderr, "%c %s:%d] %s\n", severity, data.file, data.line_number, message); 24 | } 25 | 26 | LogMessageData::LogMessageData(const char* file, int line, LogSeverity severity, int error) 27 | : file(file), 28 | line_number(line), 29 | severity(severity), 30 | error(error) 31 | { 32 | const char* last_slash = strrchr(file, '/'); 33 | file = (last_slash == NULL) ? file : last_slash + 1; 34 | } 35 | 36 | LogMessage::~LogMessage() 37 | { 38 | if (data_->error != -1) 39 | data_->buffer << ": " << strerror(data_->error); 40 | std::string msg(data_->buffer.str()); 41 | 42 | if (msg.find('\n') == std::string::npos) 43 | LogLine(*data_, msg.c_str()); 44 | else { 45 | msg += '\n'; 46 | size_t i = 0; 47 | while (i < msg.size()) { 48 | size_t nl = msg.find('\n', i); 49 | msg[nl] = '\0'; 50 | LogLine(*data_, &msg[i]); 51 | i = nl + 1; 52 | } 53 | } 54 | 55 | if (data_->severity == FATAL) 56 | exit(EXIT_FAILURE); 57 | } 58 | 59 | Inform::~Inform() 60 | { 61 | std::string msg(buffer_.str()); 62 | fputs(msg.c_str(), stdout); 63 | } -------------------------------------------------------------------------------- /util/log.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef _UTIL_LOG_H_ 18 | #define _UTIL_LOG_H_ 19 | 20 | 21 | #include "globals.h" 22 | #include "macros.h" 23 | 24 | 25 | typedef int LogSeverity; 26 | const int VERBOSE = 0, DEBUG = 1, INFO = 2, WARNING = 3, ERROR = 4, FATAL = 5; 27 | 28 | 29 | #define CHECK(x) \ 30 | if (UNLIKELY(!(x))) \ 31 | LogMessage(__FILE__, __LINE__, FATAL, -1).stream() \ 32 | << "Check failed: " #x << " " 33 | 34 | #define CHECK_OP(LHS, RHS, OP) \ 35 | for (auto _values = MakeEagerEvaluator(LHS, RHS); \ 36 | UNLIKELY(!(_values.lhs OP _values.rhs)); /* empty */) \ 37 | LogMessage(__FILE__, __LINE__, FATAL, -1).stream() \ 38 | << "Check failed: " << #LHS << " " << #OP << " " << #RHS \ 39 | << " (" #LHS "=" << _values.lhs << ", " #RHS "=" << _values.rhs << ") " 40 | 41 | #define CHECK_EQ(x, y) CHECK_OP(x, y, ==) 42 | #define CHECK_NE(x, y) CHECK_OP(x, y, !=) 43 | #define CHECK_LE(x, y) CHECK_OP(x, y, <=) 44 | #define CHECK_LT(x, y) CHECK_OP(x, y, <) 45 | #define CHECK_GE(x, y) CHECK_OP(x, y, >=) 46 | #define CHECK_GT(x, y) CHECK_OP(x, y, >) 47 | 48 | #define CHECK_STROP(s1, s2, sense) \ 49 | if (UNLIKELY((strcmp(s1, s2) == 0) != sense)) \ 50 | LOG(FATAL) << "Check failed: " \ 51 | << "\"" << s1 << "\"" \ 52 | << (sense ? " == " : " != ") \ 53 | << "\"" << s2 << "\"" 54 | 55 | #define CHECK_STREQ(s1, s2) CHECK_STROP(s1, s2, true) 56 | #define CHECK_STRNE(s1, s2) CHECK_STROP(s1, s2, false) 57 | 58 | #define LOG(severity) LogMessage(__FILE__, __LINE__, severity, -1).stream() 59 | #define PLOG(severity) LogMessage(__FILE__, __LINE__, severity, errno).stream() 60 | #define TIP() Inform().stream() 61 | 62 | 63 | template 64 | struct EagerEvaluator 65 | { 66 | EagerEvaluator(LHS lhs, RHS rhs) 67 | : lhs(lhs), rhs(rhs) 68 | {} 69 | LHS lhs; 70 | RHS rhs; 71 | }; 72 | 73 | template 74 | EagerEvaluator MakeEagerEvaluator(LHS lhs, RHS rhs) 75 | { 76 | return EagerEvaluator(lhs, rhs); 77 | } 78 | 79 | struct LogMessageData 80 | { 81 | public: 82 | LogMessageData(const char* file, int line, LogSeverity severity, int error); 83 | std::ostringstream buffer; 84 | const char* const file; 85 | const int line_number; 86 | const LogSeverity severity; 87 | const int error; 88 | 89 | private: 90 | DISALLOW_COPY_AND_ASSIGN(LogMessageData); 91 | }; 92 | 93 | class LogMessage 94 | { 95 | public: 96 | LogMessage(const char* file, int line, LogSeverity severity, int error) 97 | : data_(new LogMessageData(file, line, severity, error)) 98 | {} 99 | 100 | ~LogMessage(); 101 | 102 | std::ostream& stream() 103 | { 104 | return data_->buffer; 105 | } 106 | 107 | private: 108 | static void LogLine(const LogMessageData& data, const char*); 109 | 110 | const std::unique_ptr data_; 111 | 112 | DISALLOW_COPY_AND_ASSIGN(LogMessage); 113 | }; 114 | 115 | class Inform 116 | { 117 | public: 118 | Inform() 119 | {} 120 | 121 | ~Inform(); 122 | 123 | std::ostream& stream() 124 | { 125 | return buffer_; 126 | } 127 | 128 | private: 129 | std::ostringstream buffer_; 130 | 131 | DISALLOW_COPY_AND_ASSIGN(Inform); 132 | }; 133 | 134 | #endif -------------------------------------------------------------------------------- /util/macros.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2010 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef _UTIL_MACROS_H_ 18 | #define _UTIL_MACROS_H_ 19 | 20 | 21 | // Fire a warning when programmers forget to use the return value from callee method. 22 | #define WARN_UNUSED __attribute__((warn_unused_result)) 23 | 24 | // Disallows the copy and operator= functions. It goes in the private: 25 | // declarations in a class. 26 | #define DISALLOW_COPY_AND_ASSIGN(TypeName) \ 27 | TypeName(const TypeName&); \ 28 | void operator=(const TypeName&) 29 | 30 | // A macro to disallow all the implicit constructors, namely the default 31 | // constructor, copy constructor and operator= functions. This should be used in 32 | // the private: declarations for a class that wants to prevent anyone from 33 | // instantiating it. This is especially useful for classes containing only 34 | // static methods. 35 | #define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \ 36 | TypeName(); \ 37 | DISALLOW_COPY_AND_ASSIGN(TypeName) 38 | 39 | #define PACKED(x) __attribute__ ((__aligned__(x), __packed__)) 40 | 41 | // Hint compiler to generate optimized code for branch prediction. 42 | #define LIKELY(x) __builtin_expect((x), true) 43 | #define UNLIKELY(x) __builtin_expect((x), false) 44 | 45 | #ifndef NDEBUG 46 | #define ALWAYS_INLINE 47 | #else 48 | #define ALWAYS_INLINE __attribute__ ((always_inline)) 49 | #endif 50 | 51 | // Return the number of leading zeros in x. 52 | template 53 | static constexpr int CLZ(T x) 54 | { 55 | return (sizeof(T) == sizeof(uint32_t))? __builtin_clz(x) : __builtin_clzll(x); 56 | } 57 | 58 | #endif -------------------------------------------------------------------------------- /util/misc.cc: -------------------------------------------------------------------------------- 1 | 2 | #include "globals.h" 3 | #include "stringprintf.h" 4 | #include "misc.h" 5 | #include "utf.h" 6 | #include "dex_file-inl.h" 7 | #include "utf-inl.h" 8 | 9 | 10 | std::string PrintableString(const char* utf) 11 | { 12 | std::string result; 13 | result += '"'; 14 | const char* p = utf; 15 | size_t char_count = CountModifiedUtf8Chars(p); 16 | for (size_t i = 0; i < char_count; ++i) { 17 | uint16_t ch = GetUtf16FromUtf8(&p); 18 | if (ch == '\\') 19 | result += "\\\\"; 20 | else if (ch == '\n') 21 | result += "\\n"; 22 | else if (ch == '\r') 23 | result += "\\r"; 24 | else if (ch == '\t') 25 | result += "\\t"; 26 | else if (NeedsEscaping(ch)) 27 | StringAppendF(&result, "\\u%04x", ch); 28 | else 29 | result += ch; 30 | } 31 | result += '"'; 32 | return result; 33 | } 34 | 35 | std::string PrettyDescriptor(const char* descriptor) 36 | { 37 | // Count the number of '['s to get the dimensionality. 38 | const char* c = descriptor; 39 | size_t dim = 0; 40 | while (*c == '[') { 41 | dim++; 42 | c++; 43 | } 44 | 45 | // Reference or primitive? 46 | if (*c == 'L') { 47 | // "[[La/b/C;" -> "a.b.C[][]". 48 | c++; // Skip the 'L'. 49 | } else { 50 | // "[[B" -> "byte[][]". 51 | // To make life easier, we make primitives look like unqualified 52 | // reference types. 53 | switch (*c) { 54 | case 'B': c = "byte;"; break; 55 | case 'C': c = "char;"; break; 56 | case 'D': c = "double;"; break; 57 | case 'F': c = "float;"; break; 58 | case 'I': c = "int;"; break; 59 | case 'J': c = "long;"; break; 60 | case 'S': c = "short;"; break; 61 | case 'Z': c = "boolean;"; break; 62 | case 'V': c = "void;"; break; // Used when decoding return types. 63 | default: return descriptor; 64 | } 65 | } 66 | 67 | // At this point, 'c' is a string of the form "fully/qualified/Type;" 68 | // or "primitive;". Rewrite the type with '.' instead of '/': 69 | std::string result; 70 | const char* p = c; 71 | while (*p != ';') { 72 | char ch = *p++; 73 | if (ch == '/') 74 | ch = '.'; 75 | result.push_back(ch); 76 | } 77 | // ...and replace the semicolon with 'dim' "[]" pairs: 78 | for (size_t i = 0; i < dim; ++i) 79 | result += "[]"; 80 | return result; 81 | } 82 | 83 | std::string PrettyField(uint32_t field_idx, const DexFile& dex_file, bool with_type) 84 | { 85 | if (field_idx >= dex_file.NumFieldIds()) 86 | return StringPrintf("<>", field_idx); 87 | 88 | const DexFile::FieldId& field_id = dex_file.GetFieldId(field_idx); 89 | std::string result; 90 | if (with_type) { 91 | result += dex_file.GetFieldTypeDescriptor(field_id); 92 | result += ' '; 93 | } 94 | result += PrettyDescriptor(dex_file.GetFieldDeclaringClassDescriptor(field_id)); 95 | result += '.'; 96 | result += dex_file.GetFieldName(field_id); 97 | return result; 98 | } 99 | 100 | std::string PrettyArguments(const char* signature) 101 | { 102 | std::string result; 103 | result += '('; 104 | CHECK_EQ(*signature, '('); 105 | ++signature; // Skip the '('. 106 | while (*signature != ')') { 107 | size_t argument_length = 0; 108 | while (signature[argument_length] == '[') 109 | ++argument_length; 110 | if (signature[argument_length] == 'L') 111 | argument_length = (strchr(signature, ';') - signature + 1); 112 | else 113 | ++argument_length; 114 | { 115 | std::string argument_descriptor(signature, argument_length); 116 | result += PrettyDescriptor(argument_descriptor.c_str()); 117 | } 118 | if (signature[argument_length] != ')') 119 | result += ", "; 120 | signature += argument_length; 121 | } 122 | CHECK_EQ(*signature, ')'); 123 | ++signature; // Skip the ')'. 124 | result += ')'; 125 | return result; 126 | } 127 | 128 | std::string PrettyReturnType(const char* signature) 129 | { 130 | const char* return_type = strchr(signature, ')'); 131 | CHECK(return_type != nullptr); 132 | ++return_type; // Skip ')'. 133 | return PrettyDescriptor(return_type); 134 | } 135 | 136 | std::string PrettyMethod(uint32_t method_idx, const DexFile& dex_file, bool with_signature) 137 | { 138 | if (method_idx >= dex_file.NumMethodIds()) 139 | return StringPrintf("<>", method_idx); 140 | 141 | const DexFile::MethodId& method_id = dex_file.GetMethodId(method_idx); 142 | std::string result(PrettyDescriptor(dex_file.GetMethodDeclaringClassDescriptor(method_id))); 143 | result += '.'; 144 | result += dex_file.GetMethodName(method_id); 145 | if (with_signature) { 146 | const Signature signature = dex_file.GetMethodSignature(method_id); 147 | std::string sig_as_string(signature.ToString()); 148 | if (signature == Signature::NoSignature()) 149 | return result + sig_as_string; 150 | result = PrettyReturnType(sig_as_string.c_str()) + " " + result + 151 | PrettyArguments(sig_as_string.c_str()); 152 | } 153 | return result; 154 | } 155 | 156 | std::string PrettyClass(uint32_t class_def_idx, const DexFile& dex_file) 157 | { 158 | if (class_def_idx >= dex_file.NumClassDefs()) 159 | return StringPrintf("<>", class_def_idx); 160 | const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_idx); 161 | return PrettyDescriptor(dex_file.GetClassDescriptor(class_def)); 162 | } 163 | 164 | std::string PrettyType(uint32_t type_idx, const DexFile& dex_file) 165 | { 166 | if (type_idx >= dex_file.NumTypeIds()) 167 | return StringPrintf("<>", type_idx); 168 | const DexFile::TypeId& type_id = dex_file.GetTypeId(type_idx); 169 | return PrettyDescriptor(dex_file.GetTypeDescriptor(type_id)); 170 | } 171 | -------------------------------------------------------------------------------- /util/misc.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _UTIL_MISC_H_ 3 | #define _UTIL_MISC_H_ 4 | 5 | 6 | #include "dex_file.h" 7 | 8 | 9 | class DexFile; 10 | 11 | 12 | static inline bool NeedsEscaping(uint16_t ch) 13 | { 14 | return (ch < ' ' || ch > '~'); 15 | } 16 | 17 | // Returns an ASCII string corresponding to the given UTF-8 string. 18 | // Java escapes are used for non-ASCII characters. 19 | std::string PrintableString(const char* utf8); 20 | 21 | // Used to implement PrettyClass, PrettyField, PrettyMethod, and PrettyTypeOf, 22 | // one of which is probably more useful to you. 23 | // Returns a human-readable equivalent of 'descriptor'. So "I" would be "int", 24 | // "[[I" would be "int[][]", "[Ljava/lang/String;" would be 25 | // "java.lang.String[]", and so forth. 26 | std::string PrettyDescriptor(const char* descriptor); 27 | 28 | // Returns a human-readable signature for a field. Something like "a.b.C.f" or 29 | // "int a.b.C.f" (depending on the value of 'with_type'). 30 | std::string PrettyField(uint32_t field_idx, const DexFile& dex_file, 31 | bool with_type = true); 32 | 33 | // Returns a human-readable signature for a method. Something like "a.b.C.m" or 34 | // "a.b.C.m(II)V" (depending on the value of 'with_signature'). 35 | std::string PrettyMethod(uint32_t method_idx, const DexFile& dex_file, 36 | bool with_signature = true); 37 | 38 | // Returns a human-readable form of the name of the given class. 39 | std::string PrettyClass(uint32_t class_def_idx, const DexFile& dex_file); 40 | 41 | // Returns a human-readable form of the type at an index in the specified dex file. 42 | // Example outputs: char[], java.lang.String. 43 | std::string PrettyType(uint32_t type_idx, const DexFile& dex_file); 44 | 45 | 46 | #endif -------------------------------------------------------------------------------- /util/scoped_fd.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _UTIL_SCOPED_FD_H_ 3 | #define _UTIL_SCOPED_FD_H_ 4 | 5 | 6 | #include "globals.h" 7 | #include "macros.h" 8 | 9 | 10 | // A smart pointer that closes the given fd on going out of scope. 11 | class ScopedFd 12 | { 13 | public: 14 | explicit ScopedFd(int fd) 15 | : fd_(fd) 16 | {} 17 | 18 | ~ScopedFd() 19 | { 20 | reset(); 21 | } 22 | 23 | int get() const 24 | { 25 | return fd_; 26 | } 27 | 28 | int release() WARN_UNUSED 29 | { 30 | int hold_fd = fd_; 31 | fd_ = -1; 32 | return hold_fd; 33 | } 34 | 35 | void reset(int new_fd = -1) 36 | { 37 | if (fd_ != -1) 38 | close(fd_); 39 | fd_ = new_fd; 40 | } 41 | 42 | private: 43 | int fd_; 44 | 45 | DISALLOW_COPY_AND_ASSIGN(ScopedFd); 46 | }; 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /util/scoped_map.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _UTIL_SCOPED_MAP_H_ 3 | #define _UTIL_SCOPED_MAP_H_ 4 | 5 | 6 | #include "globals.h" 7 | #include "macros.h" 8 | 9 | 10 | // A smart pointer that unmaps the given memory segments on going out of scope. 11 | class ScopedMap 12 | { 13 | public: 14 | explicit ScopedMap(byte* base, size_t size, size_t algn_size) 15 | : base_(base), 16 | size_(size), 17 | algn_size_(algn_size) 18 | {} 19 | 20 | ~ScopedMap() 21 | { 22 | reset(); 23 | } 24 | 25 | byte* GetBase() const 26 | { 27 | return base_; 28 | } 29 | 30 | size_t GetSize() const 31 | { 32 | return size_; 33 | } 34 | 35 | size_t GetAlignedSize() const 36 | { 37 | return algn_size_; 38 | } 39 | 40 | void release() 41 | { 42 | base_ = nullptr; 43 | size_ = 0; 44 | algn_size_ = 0; 45 | } 46 | 47 | void reset(byte* base = nullptr, size_t size = 0, size_t algn_size = 0) 48 | { 49 | if (base_ != nullptr && size_ != 0 && algn_size_ != 0) 50 | munmap(base_, algn_size_); 51 | base_ = base; 52 | size_ = size; 53 | algn_size_ = algn_size; 54 | } 55 | 56 | private: 57 | byte* base_; 58 | size_t size_, algn_size_; 59 | 60 | DISALLOW_COPY_AND_ASSIGN(ScopedMap); 61 | }; 62 | 63 | #endif -------------------------------------------------------------------------------- /util/stringpiece.cc: -------------------------------------------------------------------------------- 1 | 2 | #include "stringpiece.h" 3 | 4 | 5 | void StringPiece::CopyToString(std::string* target) const 6 | { 7 | target->assign(ptr_, length_); 8 | } 9 | 10 | int StringPiece::copy(char* buf, size_type n, size_type pos) const 11 | { 12 | int ret = std::min(length_ - pos, n); 13 | memcpy(buf, ptr_ + pos, ret); 14 | return ret; 15 | } 16 | 17 | StringPiece::size_type StringPiece::find(const StringPiece& s, size_type pos) const 18 | { 19 | if (length_ < 0 || pos > static_cast(length_)) 20 | return npos; 21 | 22 | const char* result = std::search(ptr_ + pos, ptr_ + length_, 23 | s.ptr_, s.ptr_ + s.length_); 24 | const size_type xpos = result - ptr_; 25 | return xpos + s.length_ <= static_cast(length_) ? xpos : npos; 26 | } 27 | 28 | int StringPiece::compare(const StringPiece& x) const 29 | { 30 | int r = memcmp(ptr_, x.ptr_, std::min(length_, x.length_)); 31 | if (r == 0) { 32 | if (length_ < x.length_) 33 | r = -1; 34 | else if (length_ > x.length_) 35 | r = +1; 36 | } 37 | return r; 38 | } 39 | 40 | StringPiece::size_type StringPiece::find(char c, size_type pos) const 41 | { 42 | if (length_ <= 0 || pos >= static_cast(length_)) 43 | return npos; 44 | const char* result = std::find(ptr_ + pos, ptr_ + length_, c); 45 | return result != ptr_ + length_ ? result - ptr_ : npos; 46 | } 47 | 48 | StringPiece::size_type StringPiece::rfind(const StringPiece& s, size_type pos) const 49 | { 50 | if (length_ < s.length_) 51 | return npos; 52 | const size_t ulen = length_; 53 | if (s.length_ == 0) 54 | return std::min(ulen, pos); 55 | const char* last = ptr_ + std::min(ulen - s.length_, pos) + s.length_; 56 | const char* result = std::find_end(ptr_, last, s.ptr_, s.ptr_ + s.length_); 57 | return result != last ? result - ptr_ : npos; 58 | } 59 | 60 | StringPiece::size_type StringPiece::rfind(char c, size_type pos) const 61 | { 62 | if (length_ <= 0) 63 | return npos; 64 | for (int i = std::min(pos, static_cast(length_ - 1)); i >= 0; --i) { 65 | if (ptr_[i] == c) 66 | return i; 67 | } 68 | return npos; 69 | } 70 | 71 | StringPiece StringPiece::substr(size_type pos, size_type n) const 72 | { 73 | if (pos > static_cast(length_)) 74 | pos = length_; 75 | if (n > length_ - pos) 76 | n = length_ - pos; 77 | return StringPiece(ptr_ + pos, n); 78 | } 79 | 80 | const StringPiece::size_type StringPiece::npos = size_type(-1); 81 | 82 | std::ostream& operator<<(std::ostream& o, const StringPiece& piece) 83 | { 84 | o.write(piece.data(), piece.size()); 85 | return o; 86 | } 87 | -------------------------------------------------------------------------------- /util/stringpiece.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _ART_STRINGPIECE_H_ 3 | #define _ART_STRINGPIECE_H_ 4 | 5 | 6 | #include "globals.h" 7 | 8 | 9 | // A string-like object that points to a sized piece of memory. 10 | // 11 | // Functions or methods may use const StringPiece& parameters to accept either 12 | // a "const char*" or a "string" value that will be implicitly converted to 13 | // a StringPiece. The implicit conversion means that it is often appropriate 14 | // to include this .h file in other files rather than forward-declaring 15 | // StringPiece as would be appropriate for most other Google classes. 16 | // 17 | // Systematic usage of StringPiece is encouraged as it will reduce unnecessary 18 | // conversions from "const char*" to "string" and back again. 19 | class StringPiece 20 | { 21 | private: 22 | const char* ptr_; 23 | int length_; 24 | 25 | public: 26 | // We provide non-explicit singleton constructors so users can pass 27 | // in a "const char*" or a "string" wherever a "StringPiece" is expected. 28 | StringPiece() 29 | : ptr_(NULL), length_(0) 30 | {} 31 | 32 | StringPiece(const char* str) // NOLINT 33 | : ptr_(str), length_((str == NULL) ? 0 : static_cast(strlen(str))) 34 | {} 35 | 36 | StringPiece(const std::string& str) // NOLINT 37 | : ptr_(str.data()), length_(static_cast(str.size())) 38 | {} 39 | 40 | StringPiece(const char* offset, int len) 41 | : ptr_(offset), length_(len) 42 | {} 43 | 44 | // data() may return a pointer to a buffer with embedded NULs, and the 45 | // returned buffer may or may not be null terminated. Therefore it is 46 | // typically a mistake to pass data() to a routine that expects a NUL 47 | // terminated string. 48 | const char* data() const 49 | { 50 | return ptr_; 51 | } 52 | 53 | int size() const 54 | { 55 | return length_; 56 | } 57 | 58 | int length() const 59 | { 60 | return length_; 61 | } 62 | 63 | bool empty() const 64 | { 65 | return length_ == 0; 66 | } 67 | 68 | void clear() 69 | { 70 | ptr_ = nullptr; 71 | length_ = 0; 72 | } 73 | 74 | void set(const char* data, int len) 75 | { 76 | ptr_ = data; 77 | length_ = len; 78 | } 79 | 80 | void set(const char* str) 81 | { 82 | ptr_ = str; 83 | if (str != NULL) 84 | length_ = static_cast(strlen(str)); 85 | else 86 | length_ = 0; 87 | } 88 | 89 | void set(const void* data, int len) 90 | { 91 | ptr_ = reinterpret_cast(data); 92 | length_ = len; 93 | } 94 | 95 | char operator[](int i) const 96 | { 97 | return ptr_[i]; 98 | } 99 | 100 | void remove_prefix(int n) 101 | { 102 | ptr_ += n; 103 | length_ -= n; 104 | } 105 | 106 | void remove_suffix(int n) 107 | { 108 | length_ -= n; 109 | } 110 | 111 | int compare(const StringPiece& x) const; 112 | 113 | std::string as_string() const 114 | { 115 | return std::string(data(), size()); 116 | } 117 | 118 | // We also define ToString() here, since many other string-like 119 | // interfaces name the routine that converts to a C++ string 120 | // "ToString", and it's confusing to have the method that does that 121 | // for a StringPiece be called "as_string()". We also leave the 122 | // "as_string()" method defined here for existing code. 123 | std::string ToString() const 124 | { 125 | return std::string(data(), size()); 126 | } 127 | 128 | void CopyToString(std::string* target) const; 129 | void AppendToString(std::string* target) const; 130 | 131 | // Does "this" start with "x" 132 | bool starts_with(const StringPiece& x) const 133 | { 134 | return ((length_ >= x.length_) && (memcmp(ptr_, x.ptr_, x.length_) == 0)); 135 | } 136 | 137 | // Does "this" end with "x" 138 | bool ends_with(const StringPiece& x) const 139 | { 140 | return ((length_ >= x.length_) && 141 | (memcmp(ptr_ + (length_-x.length_), x.ptr_, x.length_) == 0)); 142 | } 143 | 144 | // standard STL container boilerplate 145 | typedef char value_type; 146 | typedef const char* pointer; 147 | typedef const char& reference; 148 | typedef const char& const_reference; 149 | typedef size_t size_type; 150 | typedef ptrdiff_t difference_type; 151 | static const size_type npos; 152 | typedef const char* const_iterator; 153 | typedef const char* iterator; 154 | typedef std::reverse_iterator const_reverse_iterator; 155 | typedef std::reverse_iterator reverse_iterator; 156 | 157 | iterator begin() const 158 | { 159 | return ptr_; 160 | } 161 | 162 | iterator end() const 163 | { 164 | return ptr_ + length_; 165 | } 166 | 167 | const_reverse_iterator rbegin() const 168 | { 169 | return const_reverse_iterator(ptr_ + length_); 170 | } 171 | 172 | const_reverse_iterator rend() const 173 | { 174 | return const_reverse_iterator(ptr_); 175 | } 176 | 177 | // STLS says return size_type, but Google says return int 178 | int max_size() const 179 | { 180 | return length_; 181 | } 182 | 183 | int capacity() const 184 | { 185 | return length_; 186 | } 187 | 188 | int copy(char* buf, size_type n, size_type pos = 0) const; 189 | 190 | size_type find(const StringPiece& s, size_type pos = 0) const; 191 | size_type find(char c, size_type pos = 0) const; 192 | size_type rfind(const StringPiece& s, size_type pos = npos) const; 193 | size_type rfind(char c, size_type pos = npos) const; 194 | 195 | StringPiece substr(size_type pos, size_type n = npos) const; 196 | }; 197 | 198 | // This large function is defined inline so that in a fairly common case where 199 | // one of the arguments is a literal, the compiler can elide a lot of the 200 | // following comparisons. 201 | inline bool operator==(const StringPiece& x, const StringPiece& y) 202 | { 203 | int len = x.size(); 204 | if (len != y.size()) 205 | return false; 206 | 207 | const char* p1 = x.data(); 208 | const char* p2 = y.data(); 209 | if (p1 == p2) 210 | return true; 211 | if (len <= 0) 212 | return true; 213 | 214 | // Test last byte in case strings share large common prefix 215 | if (p1[len-1] != p2[len-1]) 216 | return false; 217 | 218 | if (len == 1) 219 | return true; 220 | 221 | // At this point we can, but don't have to, ignore the last byte. We use 222 | // this observation to fold the odd-length case into the even-length case. 223 | len &= ~1; 224 | 225 | return memcmp(p1, p2, len) == 0; 226 | } 227 | 228 | inline bool operator!=(const StringPiece& x, const StringPiece& y) 229 | { 230 | return !(x == y); 231 | } 232 | 233 | inline bool operator<(const StringPiece& x, const StringPiece& y) 234 | { 235 | const int r = memcmp(x.data(), y.data(), std::min(x.size(), y.size())); 236 | return ((r < 0) || ((r == 0) && (x.size() < y.size()))); 237 | } 238 | 239 | inline bool operator>(const StringPiece& x, const StringPiece& y) 240 | { 241 | return y < x; 242 | } 243 | 244 | inline bool operator<=(const StringPiece& x, const StringPiece& y) 245 | { 246 | return !(x > y); 247 | } 248 | 249 | inline bool operator>=(const StringPiece& x, const StringPiece& y) 250 | { 251 | return !(x < y); 252 | } 253 | 254 | extern std::ostream& operator<<(std::ostream& o, const StringPiece& piece); 255 | 256 | #endif 257 | -------------------------------------------------------------------------------- /util/stringprintf.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "stringprintf.h" 18 | 19 | 20 | void StringAppendV(std::string* dst, const char* format, va_list ap) 21 | { 22 | // First try with a small fixed size buffer 23 | char space[kBlahSize]; 24 | 25 | // It's possible for methods that use a va_list to invalidate 26 | // the data in it upon use. The fix is to make a copy 27 | // of the structure before using it and use that copy instead. 28 | va_list backup_ap; 29 | va_copy(backup_ap, ap); 30 | int result = vsnprintf(space, sizeof(space), format, backup_ap); 31 | va_end(backup_ap); 32 | 33 | if (result < static_cast(sizeof(space))) { 34 | if (result >= 0) { 35 | // Normal case -- everything fit. 36 | dst->append(space, result); 37 | return; 38 | } 39 | 40 | if (result < 0) { 41 | // Just an error. 42 | return; 43 | } 44 | } 45 | 46 | // Increase the buffer size to the size requested by vsnprintf, 47 | // plus one for the closing \0. 48 | int length = result + 1; 49 | char* buf = new char[length]; 50 | 51 | // Restore the va_list before we use it again 52 | va_copy(backup_ap, ap); 53 | result = vsnprintf(buf, length, format, backup_ap); 54 | va_end(backup_ap); 55 | 56 | if (result >= 0 && result < length) { 57 | // It fit 58 | dst->append(buf, result); 59 | } 60 | delete[] buf; 61 | } 62 | 63 | std::string StringPrintf(const char* fmt, ...) 64 | { 65 | va_list ap; 66 | va_start(ap, fmt); 67 | std::string result; 68 | StringAppendV(&result, fmt, ap); 69 | va_end(ap); 70 | return result; 71 | } 72 | 73 | void StringAppendF(std::string* dst, const char* format, ...) 74 | { 75 | va_list ap; 76 | va_start(ap, format); 77 | StringAppendV(dst, format, ap); 78 | va_end(ap); 79 | } -------------------------------------------------------------------------------- /util/stringprintf.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef _UTIL_STRINGPRINTF_H_ 18 | #define _UTIL_STRINGPRINTF_H_ 19 | 20 | 21 | #include "globals.h" 22 | 23 | 24 | // Returns a string corresponding to printf-like formatting of the arguments. 25 | std::string StringPrintf(const char* fmt, ...) 26 | __attribute__((__format__(__printf__, 1, 2))); 27 | 28 | // Appends a printf-like formatting of the arguments to 'dst'. 29 | void StringAppendF(std::string* dst, const char* fmt, ...) 30 | __attribute__((__format__(__printf__, 2, 3))); 31 | 32 | // Appends a printf-like formatting of the arguments to 'dst'. 33 | void StringAppendV(std::string* dst, const char* format, va_list ap); 34 | 35 | #endif -------------------------------------------------------------------------------- /util/utf-inl.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef _UTIL_UTF_INL_H_ 18 | #define _UTIL_UTF_INL_H_ 19 | 20 | 21 | #include "utf.h" 22 | 23 | 24 | inline uint16_t GetUtf16FromUtf8(const char** utf8_data_in) 25 | { 26 | uint8_t one = *(*utf8_data_in)++; 27 | if ((one & 0x80) == 0) { 28 | // one-byte encoding 29 | return one; 30 | } 31 | // two- or three-byte encoding 32 | uint8_t two = *(*utf8_data_in)++; 33 | if ((one & 0x20) == 0) { 34 | // two-byte encoding 35 | return ((one & 0x1f) << 6) | (two & 0x3f); 36 | } 37 | // three-byte encoding 38 | uint8_t three = *(*utf8_data_in)++; 39 | return ((one & 0x0f) << 12) | ((two & 0x3f) << 6) | (three & 0x3f); 40 | } 41 | 42 | #endif -------------------------------------------------------------------------------- /util/utf.cc: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #include "utf.h" 18 | #include "utf-inl.h" 19 | 20 | 21 | size_t CountModifiedUtf8Chars(const char* utf8) 22 | { 23 | size_t len = 0; 24 | int ic; 25 | while ((ic = *utf8++) != '\0') { 26 | len++; 27 | if ((ic & 0x80) == 0) { 28 | // one-byte encoding 29 | continue; 30 | } 31 | // two- or three-byte encoding 32 | utf8++; 33 | if ((ic & 0x20) == 0) { 34 | // two-byte encoding 35 | continue; 36 | } 37 | // three-byte encoding 38 | utf8++; 39 | } 40 | return len; 41 | } 42 | 43 | void ConvertUtf16ToModifiedUtf8(char* utf8_out, const uint16_t* utf16_in, 44 | size_t char_count) 45 | { 46 | while (char_count--) { 47 | uint16_t ch = *utf16_in++; 48 | if (ch > 0 && ch <= 0x7f) 49 | *utf8_out++ = ch; 50 | else { 51 | if (ch > 0x07ff) { 52 | *utf8_out++ = (ch >> 12) | 0xe0; 53 | *utf8_out++ = ((ch >> 6) & 0x3f) | 0x80; 54 | *utf8_out++ = (ch & 0x3f) | 0x80; 55 | } else /*(ch > 0x7f || ch == 0)*/ { 56 | *utf8_out++ = (ch >> 6) | 0xc0; 57 | *utf8_out++ = (ch & 0x3f) | 0x80; 58 | } 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /util/utf.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2011 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | #ifndef _UTIL_UTF_H_ 18 | #define _UTIL_UTF_H_ 19 | 20 | 21 | #include "globals.h" 22 | 23 | 24 | /* 25 | * All UTF-8 in art is actually modified UTF-8. Mostly, this distinction 26 | * doesn't matter. 27 | * 28 | * See http://en.wikipedia.org/wiki/UTF-8#Modified_UTF-8 for the details. 29 | */ 30 | 31 | // Returns the number of UTF-16 characters in the given modified UTF-8 string. 32 | size_t CountModifiedUtf8Chars(const char* utf8); 33 | 34 | /* 35 | * Retrieve the next UTF-16 character from a UTF-8 string. 36 | * 37 | * Advances "*utf8_data_in" to the start of the next character. 38 | * 39 | * WARNING: If a string is corrupted by dropping a '\0' in the middle 40 | * of a 3-byte sequence, you can end up overrunning the buffer with 41 | * reads (and possibly with the writes if the length was computed and 42 | * cached before the damage). For performance reasons, this function 43 | * assumes that the string being parsed is known to be valid (e.g., by 44 | * already being verified). Most strings we process here are coming 45 | * out of dex files or other internal translations, so the only real 46 | * risk comes from the JNI NewStringUTF call. 47 | */ 48 | uint16_t GetUtf16FromUtf8(const char** utf8_data_in); 49 | 50 | /* 51 | * Convert from UTF-16 to Modified UTF-8. Note that the output is _not_ 52 | * NUL-terminated. You probably need to call CountUtf8Bytes before calling 53 | * this anyway, so if you want a NUL-terminated string, you know where to 54 | * put the NUL byte. 55 | */ 56 | void ConvertUtf16ToModifiedUtf8(char* utf8_out, const uint16_t* utf16_in, size_t char_count); 57 | 58 | #endif --------------------------------------------------------------------------------