├── .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 | [](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
--------------------------------------------------------------------------------