summaryrefslogtreecommitdiff
path: root/runtime/dex
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/dex')
-rw-r--r--runtime/dex/art_dex_file_loader.cc8
-rw-r--r--runtime/dex/art_dex_file_loader.h2
-rw-r--r--runtime/dex/art_dex_file_loader_test.cc307
-rw-r--r--runtime/dex/base64_test_util.h99
-rw-r--r--runtime/dex/code_item_accessors-inl.h204
-rw-r--r--runtime/dex/code_item_accessors-no_art-inl.h23
-rw-r--r--runtime/dex/code_item_accessors.h167
-rw-r--r--runtime/dex/code_item_accessors_test.cc114
-rw-r--r--runtime/dex/compact_dex_debug_info.cc117
-rw-r--r--runtime/dex/compact_dex_debug_info.h65
-rw-r--r--runtime/dex/compact_dex_debug_info_test.cc84
-rw-r--r--runtime/dex/compact_dex_file.cc108
-rw-r--r--runtime/dex/compact_dex_file.h291
-rw-r--r--runtime/dex/compact_dex_file_test.cc101
-rw-r--r--runtime/dex/compact_dex_level.h50
-rw-r--r--runtime/dex/compact_dex_utils.h37
-rw-r--r--runtime/dex/descriptors_names.cc426
-rw-r--r--runtime/dex/descriptors_names.h63
-rw-r--r--runtime/dex/dex_file-inl.h521
-rw-r--r--runtime/dex/dex_file.cc795
-rw-r--r--runtime/dex/dex_file.h1443
-rw-r--r--runtime/dex/dex_file_annotations.cc2
-rw-r--r--runtime/dex/dex_file_annotations.h2
-rw-r--r--runtime/dex/dex_file_exception_helpers.cc104
-rw-r--r--runtime/dex/dex_file_exception_helpers.h68
-rw-r--r--runtime/dex/dex_file_layout.cc3
-rw-r--r--runtime/dex/dex_file_loader.cc501
-rw-r--r--runtime/dex/dex_file_loader.h198
-rw-r--r--runtime/dex/dex_file_reference.h52
-rw-r--r--runtime/dex/dex_file_test.cc749
-rw-r--r--runtime/dex/dex_file_tracking_registrar.cc272
-rw-r--r--runtime/dex/dex_file_tracking_registrar.h81
-rw-r--r--runtime/dex/dex_file_types.h117
-rw-r--r--runtime/dex/dex_file_verifier.cc3290
-rw-r--r--runtime/dex/dex_file_verifier.h257
-rw-r--r--runtime/dex/dex_file_verifier_test.cc2186
-rw-r--r--runtime/dex/dex_instruction-inl.h558
-rw-r--r--runtime/dex/dex_instruction.cc561
-rw-r--r--runtime/dex/dex_instruction.h742
-rw-r--r--runtime/dex/dex_instruction_iterator.h237
-rw-r--r--runtime/dex/dex_instruction_list.h308
-rw-r--r--runtime/dex/dex_instruction_test.cc172
-rw-r--r--runtime/dex/dex_instruction_utils.h219
-rw-r--r--runtime/dex/invoke_type.h38
-rw-r--r--runtime/dex/modifiers.cc58
-rw-r--r--runtime/dex/modifiers.h148
-rw-r--r--runtime/dex/standard_dex_file.cc81
-rw-r--r--runtime/dex/standard_dex_file.h118
-rw-r--r--runtime/dex/utf-inl.h99
-rw-r--r--runtime/dex/utf.cc321
-rw-r--r--runtime/dex/utf.h135
-rw-r--r--runtime/dex/utf_test.cc381
52 files changed, 315 insertions, 16768 deletions
diff --git a/runtime/dex/art_dex_file_loader.cc b/runtime/dex/art_dex_file_loader.cc
index 08cf30d5bf..0817cb4b6a 100644
--- a/runtime/dex/art_dex_file_loader.cc
+++ b/runtime/dex/art_dex_file_loader.cc
@@ -25,10 +25,10 @@
#include "base/stl_util.h"
#include "base/systrace.h"
#include "base/unix_file/fd_file.h"
-#include "compact_dex_file.h"
-#include "dex_file.h"
-#include "dex_file_verifier.h"
-#include "standard_dex_file.h"
+#include "dex/compact_dex_file.h"
+#include "dex/dex_file.h"
+#include "dex/dex_file_verifier.h"
+#include "dex/standard_dex_file.h"
#include "zip_archive.h"
namespace art {
diff --git a/runtime/dex/art_dex_file_loader.h b/runtime/dex/art_dex_file_loader.h
index b31d1e94e0..3585381f9b 100644
--- a/runtime/dex/art_dex_file_loader.h
+++ b/runtime/dex/art_dex_file_loader.h
@@ -22,8 +22,8 @@
#include <string>
#include <vector>
-#include "dex_file_loader.h"
#include "base/macros.h"
+#include "dex/dex_file_loader.h"
namespace art {
diff --git a/runtime/dex/art_dex_file_loader_test.cc b/runtime/dex/art_dex_file_loader_test.cc
new file mode 100644
index 0000000000..25d4dd0875
--- /dev/null
+++ b/runtime/dex/art_dex_file_loader_test.cc
@@ -0,0 +1,307 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <sys/mman.h>
+
+#include <memory>
+
+#include "art_dex_file_loader.h"
+#include "base/stl_util.h"
+#include "base/unix_file/fd_file.h"
+#include "common_runtime_test.h"
+#include "dex/base64_test_util.h"
+#include "dex/code_item_accessors-inl.h"
+#include "dex/descriptors_names.h"
+#include "dex/dex_file.h"
+#include "dex/dex_file-inl.h"
+#include "dex/dex_file_loader.h"
+#include "mem_map.h"
+#include "os.h"
+#include "scoped_thread_state_change-inl.h"
+#include "thread-current-inl.h"
+
+namespace art {
+
+class ArtDexFileLoaderTest : public CommonRuntimeTest {};
+
+// TODO: Port OpenTestDexFile(s) need to be ported to use non-ART utilities, and
+// the tests that depend upon them should be moved to dex_file_loader_test.cc
+
+TEST_F(ArtDexFileLoaderTest, Open) {
+ ScopedObjectAccess soa(Thread::Current());
+ std::unique_ptr<const DexFile> dex(OpenTestDexFile("Nested"));
+ ASSERT_TRUE(dex.get() != nullptr);
+}
+
+TEST_F(ArtDexFileLoaderTest, GetLocationChecksum) {
+ ScopedObjectAccess soa(Thread::Current());
+ std::unique_ptr<const DexFile> raw(OpenTestDexFile("Main"));
+ EXPECT_NE(raw->GetHeader().checksum_, raw->GetLocationChecksum());
+}
+
+TEST_F(ArtDexFileLoaderTest, GetChecksum) {
+ std::vector<uint32_t> checksums;
+ ScopedObjectAccess soa(Thread::Current());
+ std::string error_msg;
+ const ArtDexFileLoader dex_file_loader;
+ EXPECT_TRUE(dex_file_loader.GetMultiDexChecksums(GetLibCoreDexFileNames()[0].c_str(),
+ &checksums,
+ &error_msg))
+ << error_msg;
+ ASSERT_EQ(1U, checksums.size());
+ EXPECT_EQ(java_lang_dex_file_->GetLocationChecksum(), checksums[0]);
+}
+
+TEST_F(ArtDexFileLoaderTest, GetMultiDexChecksums) {
+ std::string error_msg;
+ std::vector<uint32_t> checksums;
+ std::string multidex_file = GetTestDexFileName("MultiDex");
+ const ArtDexFileLoader dex_file_loader;
+ EXPECT_TRUE(dex_file_loader.GetMultiDexChecksums(multidex_file.c_str(),
+ &checksums,
+ &error_msg)) << error_msg;
+
+ std::vector<std::unique_ptr<const DexFile>> dexes = OpenTestDexFiles("MultiDex");
+ ASSERT_EQ(2U, dexes.size());
+ ASSERT_EQ(2U, checksums.size());
+
+ EXPECT_EQ(dexes[0]->GetLocation(), DexFileLoader::GetMultiDexLocation(0, multidex_file.c_str()));
+ EXPECT_EQ(dexes[0]->GetLocationChecksum(), checksums[0]);
+
+ EXPECT_EQ(dexes[1]->GetLocation(), DexFileLoader::GetMultiDexLocation(1, multidex_file.c_str()));
+ EXPECT_EQ(dexes[1]->GetLocationChecksum(), checksums[1]);
+}
+
+TEST_F(ArtDexFileLoaderTest, ClassDefs) {
+ ScopedObjectAccess soa(Thread::Current());
+ std::unique_ptr<const DexFile> raw(OpenTestDexFile("Nested"));
+ ASSERT_TRUE(raw.get() != nullptr);
+ EXPECT_EQ(3U, raw->NumClassDefs());
+
+ const DexFile::ClassDef& c0 = raw->GetClassDef(0);
+ EXPECT_STREQ("LNested$1;", raw->GetClassDescriptor(c0));
+
+ const DexFile::ClassDef& c1 = raw->GetClassDef(1);
+ EXPECT_STREQ("LNested$Inner;", raw->GetClassDescriptor(c1));
+
+ const DexFile::ClassDef& c2 = raw->GetClassDef(2);
+ EXPECT_STREQ("LNested;", raw->GetClassDescriptor(c2));
+}
+
+TEST_F(ArtDexFileLoaderTest, GetMethodSignature) {
+ ScopedObjectAccess soa(Thread::Current());
+ std::unique_ptr<const DexFile> raw(OpenTestDexFile("GetMethodSignature"));
+ ASSERT_TRUE(raw.get() != nullptr);
+ EXPECT_EQ(1U, raw->NumClassDefs());
+
+ const DexFile::ClassDef& class_def = raw->GetClassDef(0);
+ ASSERT_STREQ("LGetMethodSignature;", raw->GetClassDescriptor(class_def));
+
+ const uint8_t* class_data = raw->GetClassData(class_def);
+ ASSERT_TRUE(class_data != nullptr);
+ ClassDataItemIterator it(*raw, class_data);
+
+ EXPECT_EQ(1u, it.NumDirectMethods());
+
+ // Check the signature for the static initializer.
+ {
+ ASSERT_EQ(1U, it.NumDirectMethods());
+ const DexFile::MethodId& method_id = raw->GetMethodId(it.GetMemberIndex());
+ const char* name = raw->StringDataByIdx(method_id.name_idx_);
+ ASSERT_STREQ("<init>", name);
+ std::string signature(raw->GetMethodSignature(method_id).ToString());
+ ASSERT_EQ("()V", signature);
+ }
+
+ // Check all virtual methods.
+ struct Result {
+ const char* name;
+ const char* signature;
+ const char* pretty_method;
+ };
+ static const Result results[] = {
+ {
+ "m1",
+ "(IDJLjava/lang/Object;)Ljava/lang/Float;",
+ "java.lang.Float GetMethodSignature.m1(int, double, long, java.lang.Object)"
+ },
+ {
+ "m2",
+ "(ZSC)LGetMethodSignature;",
+ "GetMethodSignature GetMethodSignature.m2(boolean, short, char)"
+ },
+ {
+ "m3",
+ "()V",
+ "void GetMethodSignature.m3()"
+ },
+ {
+ "m4",
+ "(I)V",
+ "void GetMethodSignature.m4(int)"
+ },
+ {
+ "m5",
+ "(II)V",
+ "void GetMethodSignature.m5(int, int)"
+ },
+ {
+ "m6",
+ "(II[[I)V",
+ "void GetMethodSignature.m6(int, int, int[][])"
+ },
+ {
+ "m7",
+ "(II[[ILjava/lang/Object;)V",
+ "void GetMethodSignature.m7(int, int, int[][], java.lang.Object)"
+ },
+ {
+ "m8",
+ "(II[[ILjava/lang/Object;[[Ljava/lang/Object;)V",
+ "void GetMethodSignature.m8(int, int, int[][], java.lang.Object, java.lang.Object[][])"
+ },
+ {
+ "m9",
+ "()I",
+ "int GetMethodSignature.m9()"
+ },
+ {
+ "mA",
+ "()[[I",
+ "int[][] GetMethodSignature.mA()"
+ },
+ {
+ "mB",
+ "()[[Ljava/lang/Object;",
+ "java.lang.Object[][] GetMethodSignature.mB()"
+ },
+ };
+ ASSERT_EQ(arraysize(results), it.NumVirtualMethods());
+ for (const Result& r : results) {
+ it.Next();
+ const DexFile::MethodId& method_id = raw->GetMethodId(it.GetMemberIndex());
+
+ const char* name = raw->StringDataByIdx(method_id.name_idx_);
+ ASSERT_STREQ(r.name, name);
+
+ std::string signature(raw->GetMethodSignature(method_id).ToString());
+ ASSERT_EQ(r.signature, signature);
+
+ std::string plain_method = std::string("GetMethodSignature.") + r.name;
+ ASSERT_EQ(plain_method, raw->PrettyMethod(it.GetMemberIndex(), /* with_signature */ false));
+ ASSERT_EQ(r.pretty_method, raw->PrettyMethod(it.GetMemberIndex(), /* with_signature */ true));
+ }
+}
+
+TEST_F(ArtDexFileLoaderTest, FindStringId) {
+ ScopedObjectAccess soa(Thread::Current());
+ std::unique_ptr<const DexFile> raw(OpenTestDexFile("GetMethodSignature"));
+ ASSERT_TRUE(raw.get() != nullptr);
+ EXPECT_EQ(1U, raw->NumClassDefs());
+
+ const char* strings[] = { "LGetMethodSignature;", "Ljava/lang/Float;", "Ljava/lang/Object;",
+ "D", "I", "J", nullptr };
+ for (size_t i = 0; strings[i] != nullptr; i++) {
+ const char* str = strings[i];
+ const DexFile::StringId* str_id = raw->FindStringId(str);
+ const char* dex_str = raw->GetStringData(*str_id);
+ EXPECT_STREQ(dex_str, str);
+ }
+}
+
+TEST_F(ArtDexFileLoaderTest, FindTypeId) {
+ for (size_t i = 0; i < java_lang_dex_file_->NumTypeIds(); i++) {
+ const char* type_str = java_lang_dex_file_->StringByTypeIdx(dex::TypeIndex(i));
+ const DexFile::StringId* type_str_id = java_lang_dex_file_->FindStringId(type_str);
+ ASSERT_TRUE(type_str_id != nullptr);
+ dex::StringIndex type_str_idx = java_lang_dex_file_->GetIndexForStringId(*type_str_id);
+ const DexFile::TypeId* type_id = java_lang_dex_file_->FindTypeId(type_str_idx);
+ ASSERT_EQ(type_id, java_lang_dex_file_->FindTypeId(type_str));
+ ASSERT_TRUE(type_id != nullptr);
+ EXPECT_EQ(java_lang_dex_file_->GetIndexForTypeId(*type_id).index_, i);
+ }
+}
+
+TEST_F(ArtDexFileLoaderTest, FindProtoId) {
+ for (size_t i = 0; i < java_lang_dex_file_->NumProtoIds(); i++) {
+ const DexFile::ProtoId& to_find = java_lang_dex_file_->GetProtoId(i);
+ const DexFile::TypeList* to_find_tl = java_lang_dex_file_->GetProtoParameters(to_find);
+ std::vector<dex::TypeIndex> to_find_types;
+ if (to_find_tl != nullptr) {
+ for (size_t j = 0; j < to_find_tl->Size(); j++) {
+ to_find_types.push_back(to_find_tl->GetTypeItem(j).type_idx_);
+ }
+ }
+ const DexFile::ProtoId* found =
+ java_lang_dex_file_->FindProtoId(to_find.return_type_idx_, to_find_types);
+ ASSERT_TRUE(found != nullptr);
+ EXPECT_EQ(java_lang_dex_file_->GetIndexForProtoId(*found), i);
+ }
+}
+
+TEST_F(ArtDexFileLoaderTest, FindMethodId) {
+ for (size_t i = 0; i < java_lang_dex_file_->NumMethodIds(); i++) {
+ const DexFile::MethodId& to_find = java_lang_dex_file_->GetMethodId(i);
+ const DexFile::TypeId& klass = java_lang_dex_file_->GetTypeId(to_find.class_idx_);
+ const DexFile::StringId& name = java_lang_dex_file_->GetStringId(to_find.name_idx_);
+ const DexFile::ProtoId& signature = java_lang_dex_file_->GetProtoId(to_find.proto_idx_);
+ const DexFile::MethodId* found = java_lang_dex_file_->FindMethodId(klass, name, signature);
+ ASSERT_TRUE(found != nullptr) << "Didn't find method " << i << ": "
+ << java_lang_dex_file_->StringByTypeIdx(to_find.class_idx_) << "."
+ << java_lang_dex_file_->GetStringData(name)
+ << java_lang_dex_file_->GetMethodSignature(to_find);
+ EXPECT_EQ(java_lang_dex_file_->GetIndexForMethodId(*found), i);
+ }
+}
+
+TEST_F(ArtDexFileLoaderTest, FindFieldId) {
+ for (size_t i = 0; i < java_lang_dex_file_->NumFieldIds(); i++) {
+ const DexFile::FieldId& to_find = java_lang_dex_file_->GetFieldId(i);
+ const DexFile::TypeId& klass = java_lang_dex_file_->GetTypeId(to_find.class_idx_);
+ const DexFile::StringId& name = java_lang_dex_file_->GetStringId(to_find.name_idx_);
+ const DexFile::TypeId& type = java_lang_dex_file_->GetTypeId(to_find.type_idx_);
+ const DexFile::FieldId* found = java_lang_dex_file_->FindFieldId(klass, name, type);
+ ASSERT_TRUE(found != nullptr) << "Didn't find field " << i << ": "
+ << java_lang_dex_file_->StringByTypeIdx(to_find.type_idx_) << " "
+ << java_lang_dex_file_->StringByTypeIdx(to_find.class_idx_) << "."
+ << java_lang_dex_file_->GetStringData(name);
+ EXPECT_EQ(java_lang_dex_file_->GetIndexForFieldId(*found), i);
+ }
+}
+
+TEST_F(ArtDexFileLoaderTest, GetDexCanonicalLocation) {
+ ScratchFile file;
+ UniqueCPtr<const char[]> dex_location_real(realpath(file.GetFilename().c_str(), nullptr));
+ std::string dex_location(dex_location_real.get());
+
+ ASSERT_EQ(dex_location, DexFileLoader::GetDexCanonicalLocation(dex_location.c_str()));
+ std::string multidex_location = DexFileLoader::GetMultiDexLocation(1, dex_location.c_str());
+ ASSERT_EQ(multidex_location, DexFileLoader::GetDexCanonicalLocation(multidex_location.c_str()));
+
+ std::string dex_location_sym = dex_location + "symlink";
+ ASSERT_EQ(0, symlink(dex_location.c_str(), dex_location_sym.c_str()));
+
+ ASSERT_EQ(dex_location, DexFileLoader::GetDexCanonicalLocation(dex_location_sym.c_str()));
+
+ std::string multidex_location_sym = DexFileLoader::GetMultiDexLocation(
+ 1, dex_location_sym.c_str());
+ ASSERT_EQ(multidex_location,
+ DexFileLoader::GetDexCanonicalLocation(multidex_location_sym.c_str()));
+
+ ASSERT_EQ(0, unlink(dex_location_sym.c_str()));
+}
+
+} // namespace art
diff --git a/runtime/dex/base64_test_util.h b/runtime/dex/base64_test_util.h
deleted file mode 100644
index 0657f9fd01..0000000000
--- a/runtime/dex/base64_test_util.h
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ART_RUNTIME_DEX_BASE64_TEST_UTIL_H_
-#define ART_RUNTIME_DEX_BASE64_TEST_UTIL_H_
-
-#include <base/logging.h>
-#include <stdint.h>
-#include <stdlib.h>
-
-#include <memory>
-#include <vector>
-
-namespace art {
-
-static inline uint8_t* DecodeBase64(const char* src, size_t* dst_size) {
- static const uint8_t kBase64Map[256] = {
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63,
- 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255,
- 255, 254, 255, 255, 255, 0, 1, 2, 3, 4, 5, 6,
- 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
- 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255,
- 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
- 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
- 49, 50, 51, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255
- };
-
- CHECK(dst_size != nullptr);
- std::vector<uint8_t> tmp;
- uint32_t t = 0, y = 0;
- int g = 3;
- for (size_t i = 0; src[i] != '\0'; ++i) {
- uint8_t c = kBase64Map[src[i] & 0xFF];
- if (c == 255) continue;
- // the final = symbols are read and used to trim the remaining bytes
- if (c == 254) {
- c = 0;
- // prevent g < 0 which would potentially allow an overflow later
- if (--g < 0) {
- *dst_size = 0;
- return nullptr;
- }
- } else if (g != 3) {
- // we only allow = to be at the end
- *dst_size = 0;
- return nullptr;
- }
- t = (t << 6) | c;
- if (++y == 4) {
- tmp.push_back((t >> 16) & 255);
- if (g > 1) {
- tmp.push_back((t >> 8) & 255);
- }
- if (g > 2) {
- tmp.push_back(t & 255);
- }
- y = t = 0;
- }
- }
- if (y != 0) {
- *dst_size = 0;
- return nullptr;
- }
- std::unique_ptr<uint8_t[]> dst(new uint8_t[tmp.size()]);
- *dst_size = tmp.size();
- std::copy(tmp.begin(), tmp.end(), dst.get());
- return dst.release();
-}
-
-} // namespace art
-
-#endif // ART_RUNTIME_DEX_BASE64_TEST_UTIL_H_
diff --git a/runtime/dex/code_item_accessors-inl.h b/runtime/dex/code_item_accessors-inl.h
deleted file mode 100644
index 9c39935d3b..0000000000
--- a/runtime/dex/code_item_accessors-inl.h
+++ /dev/null
@@ -1,204 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ART_RUNTIME_DEX_CODE_ITEM_ACCESSORS_INL_H_
-#define ART_RUNTIME_DEX_CODE_ITEM_ACCESSORS_INL_H_
-
-#include "code_item_accessors.h"
-
-#include "compact_dex_file.h"
-#include "dex_file-inl.h"
-#include "standard_dex_file.h"
-
-// The no ART version is used by binaries that don't include the whole runtime.
-namespace art {
-
-inline void CodeItemInstructionAccessor::Init(uint32_t insns_size_in_code_units,
- const uint16_t* insns) {
- insns_size_in_code_units_ = insns_size_in_code_units;
- insns_ = insns;
-}
-
-inline void CodeItemInstructionAccessor::Init(const CompactDexFile::CodeItem& code_item) {
- uint32_t insns_size_in_code_units;
- code_item.DecodeFields</*kDecodeOnlyInstructionCount*/ true>(
- &insns_size_in_code_units,
- /*registers_size*/ nullptr,
- /*ins_size*/ nullptr,
- /*outs_size*/ nullptr,
- /*tries_size*/ nullptr);
- Init(insns_size_in_code_units, code_item.insns_);
-}
-
-inline void CodeItemInstructionAccessor::Init(const StandardDexFile::CodeItem& code_item) {
- Init(code_item.insns_size_in_code_units_, code_item.insns_);
-}
-
-inline void CodeItemInstructionAccessor::Init(const DexFile& dex_file,
- const DexFile::CodeItem* code_item) {
- if (code_item != nullptr) {
- DCHECK(dex_file.IsInDataSection(code_item));
- if (dex_file.IsCompactDexFile()) {
- Init(down_cast<const CompactDexFile::CodeItem&>(*code_item));
- } else {
- DCHECK(dex_file.IsStandardDexFile());
- Init(down_cast<const StandardDexFile::CodeItem&>(*code_item));
- }
- }
-}
-
-inline CodeItemInstructionAccessor::CodeItemInstructionAccessor(
- const DexFile& dex_file,
- const DexFile::CodeItem* code_item) {
- Init(dex_file, code_item);
-}
-
-inline DexInstructionIterator CodeItemInstructionAccessor::begin() const {
- return DexInstructionIterator(insns_, 0u);
-}
-
-inline DexInstructionIterator CodeItemInstructionAccessor::end() const {
- return DexInstructionIterator(insns_, insns_size_in_code_units_);
-}
-
-inline IterationRange<DexInstructionIterator> CodeItemInstructionAccessor::InstructionsFrom(
- uint32_t start_dex_pc) const {
- DCHECK_LT(start_dex_pc, InsnsSizeInCodeUnits());
- return {
- DexInstructionIterator(insns_, start_dex_pc),
- DexInstructionIterator(insns_, insns_size_in_code_units_) };
-}
-
-inline void CodeItemDataAccessor::Init(const CompactDexFile::CodeItem& code_item) {
- uint32_t insns_size_in_code_units;
- code_item.DecodeFields</*kDecodeOnlyInstructionCount*/ false>(&insns_size_in_code_units,
- &registers_size_,
- &ins_size_,
- &outs_size_,
- &tries_size_);
- CodeItemInstructionAccessor::Init(insns_size_in_code_units, code_item.insns_);
-}
-
-inline void CodeItemDataAccessor::Init(const StandardDexFile::CodeItem& code_item) {
- CodeItemInstructionAccessor::Init(code_item);
- registers_size_ = code_item.registers_size_;
- ins_size_ = code_item.ins_size_;
- outs_size_ = code_item.outs_size_;
- tries_size_ = code_item.tries_size_;
-}
-
-inline void CodeItemDataAccessor::Init(const DexFile& dex_file,
- const DexFile::CodeItem* code_item) {
- if (code_item != nullptr) {
- if (dex_file.IsCompactDexFile()) {
- CodeItemDataAccessor::Init(down_cast<const CompactDexFile::CodeItem&>(*code_item));
- } else {
- DCHECK(dex_file.IsStandardDexFile());
- CodeItemDataAccessor::Init(down_cast<const StandardDexFile::CodeItem&>(*code_item));
- }
- }
-}
-
-inline CodeItemDataAccessor::CodeItemDataAccessor(const DexFile& dex_file,
- const DexFile::CodeItem* code_item) {
- Init(dex_file, code_item);
-}
-
-inline IterationRange<const DexFile::TryItem*> CodeItemDataAccessor::TryItems() const {
- const DexFile::TryItem* try_items = DexFile::GetTryItems(end(), 0u);
- return {
- try_items,
- try_items + TriesSize() };
-}
-
-inline const uint8_t* CodeItemDataAccessor::GetCatchHandlerData(size_t offset) const {
- return DexFile::GetCatchHandlerData(end(), TriesSize(), offset);
-}
-
-inline const DexFile::TryItem* CodeItemDataAccessor::FindTryItem(uint32_t try_dex_pc) const {
- IterationRange<const DexFile::TryItem*> try_items(TryItems());
- int32_t index = DexFile::FindTryItem(try_items.begin(),
- try_items.end() - try_items.begin(),
- try_dex_pc);
- return index != -1 ? &try_items.begin()[index] : nullptr;
-}
-
-inline const void* CodeItemDataAccessor::CodeItemDataEnd() const {
- const uint8_t* handler_data = GetCatchHandlerData();
-
- if (TriesSize() == 0 || handler_data == nullptr) {
- return &end().Inst();
- }
- // Get the start of the handler data.
- const uint32_t handlers_size = DecodeUnsignedLeb128(&handler_data);
- // Manually read each handler.
- for (uint32_t i = 0; i < handlers_size; ++i) {
- int32_t uleb128_count = DecodeSignedLeb128(&handler_data) * 2;
- if (uleb128_count <= 0) {
- uleb128_count = -uleb128_count + 1;
- }
- for (int32_t j = 0; j < uleb128_count; ++j) {
- DecodeUnsignedLeb128(&handler_data);
- }
- }
- return reinterpret_cast<const void*>(handler_data);
-}
-
-inline void CodeItemDebugInfoAccessor::Init(const DexFile& dex_file,
- const DexFile::CodeItem* code_item,
- uint32_t dex_method_index) {
- if (code_item == nullptr) {
- return;
- }
- dex_file_ = &dex_file;
- if (dex_file.IsCompactDexFile()) {
- Init(down_cast<const CompactDexFile::CodeItem&>(*code_item), dex_method_index);
- } else {
- DCHECK(dex_file.IsStandardDexFile());
- Init(down_cast<const StandardDexFile::CodeItem&>(*code_item));
- }
-}
-
-inline void CodeItemDebugInfoAccessor::Init(const CompactDexFile::CodeItem& code_item,
- uint32_t dex_method_index) {
- debug_info_offset_ = down_cast<const CompactDexFile*>(dex_file_)->GetDebugInfoOffset(
- dex_method_index);
- CodeItemDataAccessor::Init(code_item);
-}
-
-inline void CodeItemDebugInfoAccessor::Init(const StandardDexFile::CodeItem& code_item) {
- debug_info_offset_ = code_item.debug_info_off_;
- CodeItemDataAccessor::Init(code_item);
-}
-
-template<typename NewLocalCallback>
-inline bool CodeItemDebugInfoAccessor::DecodeDebugLocalInfo(bool is_static,
- uint32_t method_idx,
- NewLocalCallback new_local,
- void* context) const {
- return dex_file_->DecodeDebugLocalInfo(RegistersSize(),
- InsSize(),
- InsnsSizeInCodeUnits(),
- DebugInfoOffset(),
- is_static,
- method_idx,
- new_local,
- context);
-}
-
-} // namespace art
-
-#endif // ART_RUNTIME_DEX_CODE_ITEM_ACCESSORS_INL_H_
diff --git a/runtime/dex/code_item_accessors-no_art-inl.h b/runtime/dex/code_item_accessors-no_art-inl.h
deleted file mode 100644
index 8082be3818..0000000000
--- a/runtime/dex/code_item_accessors-no_art-inl.h
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ART_RUNTIME_DEX_CODE_ITEM_ACCESSORS_NO_ART_INL_H_
-#define ART_RUNTIME_DEX_CODE_ITEM_ACCESSORS_NO_ART_INL_H_
-
-// TODO: delete this file once system/core is updated.
-#include "code_item_accessors-inl.h"
-
-#endif // ART_RUNTIME_DEX_CODE_ITEM_ACCESSORS_NO_ART_INL_H_
diff --git a/runtime/dex/code_item_accessors.h b/runtime/dex/code_item_accessors.h
deleted file mode 100644
index beb78f6e4f..0000000000
--- a/runtime/dex/code_item_accessors.h
+++ /dev/null
@@ -1,167 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// TODO: Dex helpers have ART specific APIs, we may want to refactor these for use in dexdump.
-
-#ifndef ART_RUNTIME_DEX_CODE_ITEM_ACCESSORS_H_
-#define ART_RUNTIME_DEX_CODE_ITEM_ACCESSORS_H_
-
-#include "base/mutex.h"
-#include "compact_dex_file.h"
-#include "dex_file.h"
-#include "dex_instruction_iterator.h"
-#include "standard_dex_file.h"
-
-namespace art {
-
-class ArtMethod;
-
-// Abstracts accesses to the instruction fields of code items for CompactDexFile and
-// StandardDexFile.
-class CodeItemInstructionAccessor {
- public:
- ALWAYS_INLINE CodeItemInstructionAccessor(const DexFile& dex_file,
- const DexFile::CodeItem* code_item);
-
- ALWAYS_INLINE explicit CodeItemInstructionAccessor(ArtMethod* method);
-
- ALWAYS_INLINE DexInstructionIterator begin() const;
-
- ALWAYS_INLINE DexInstructionIterator end() const;
-
- IterationRange<DexInstructionIterator> InstructionsFrom(uint32_t start_dex_pc) const;
-
- uint32_t InsnsSizeInCodeUnits() const {
- return insns_size_in_code_units_;
- }
-
- const uint16_t* Insns() const {
- return insns_;
- }
-
- // Return the instruction for a dex pc.
- const Instruction& InstructionAt(uint32_t dex_pc) const {
- DCHECK_LT(dex_pc, InsnsSizeInCodeUnits());
- return *Instruction::At(insns_ + dex_pc);
- }
-
- // Return true if the accessor has a code item.
- bool HasCodeItem() const {
- return Insns() != nullptr;
- }
-
- protected:
- CodeItemInstructionAccessor() = default;
-
- ALWAYS_INLINE void Init(uint32_t insns_size_in_code_units, const uint16_t* insns);
- ALWAYS_INLINE void Init(const CompactDexFile::CodeItem& code_item);
- ALWAYS_INLINE void Init(const StandardDexFile::CodeItem& code_item);
- ALWAYS_INLINE void Init(const DexFile& dex_file, const DexFile::CodeItem* code_item);
-
- private:
- // size of the insns array, in 2 byte code units. 0 if there is no code item.
- uint32_t insns_size_in_code_units_ = 0;
-
- // Pointer to the instructions, null if there is no code item.
- const uint16_t* insns_ = 0;
-};
-
-// Abstracts accesses to code item fields other than debug info for CompactDexFile and
-// StandardDexFile.
-class CodeItemDataAccessor : public CodeItemInstructionAccessor {
- public:
- ALWAYS_INLINE CodeItemDataAccessor(const DexFile& dex_file, const DexFile::CodeItem* code_item);
-
- uint16_t RegistersSize() const {
- return registers_size_;
- }
-
- uint16_t InsSize() const {
- return ins_size_;
- }
-
- uint16_t OutsSize() const {
- return outs_size_;
- }
-
- uint16_t TriesSize() const {
- return tries_size_;
- }
-
- IterationRange<const DexFile::TryItem*> TryItems() const;
-
- const uint8_t* GetCatchHandlerData(size_t offset = 0) const;
-
- const DexFile::TryItem* FindTryItem(uint32_t try_dex_pc) const;
-
- inline const void* CodeItemDataEnd() const;
-
- protected:
- CodeItemDataAccessor() = default;
-
- ALWAYS_INLINE void Init(const CompactDexFile::CodeItem& code_item);
- ALWAYS_INLINE void Init(const StandardDexFile::CodeItem& code_item);
- ALWAYS_INLINE void Init(const DexFile& dex_file, const DexFile::CodeItem* code_item);
-
- private:
- // Fields mirrored from the dex/cdex code item.
- uint16_t registers_size_;
- uint16_t ins_size_;
- uint16_t outs_size_;
- uint16_t tries_size_;
-};
-
-// Abstract accesses to code item data including debug info offset. More heavy weight than the other
-// helpers.
-class CodeItemDebugInfoAccessor : public CodeItemDataAccessor {
- public:
- CodeItemDebugInfoAccessor() = default;
-
- // Initialize with an existing offset.
- ALWAYS_INLINE CodeItemDebugInfoAccessor(const DexFile& dex_file,
- const DexFile::CodeItem* code_item,
- uint32_t dex_method_index) {
- Init(dex_file, code_item, dex_method_index);
- }
-
- ALWAYS_INLINE void Init(const DexFile& dex_file,
- const DexFile::CodeItem* code_item,
- uint32_t dex_method_index);
-
- ALWAYS_INLINE explicit CodeItemDebugInfoAccessor(ArtMethod* method);
-
- uint32_t DebugInfoOffset() const {
- return debug_info_offset_;
- }
-
- template<typename NewLocalCallback>
- bool DecodeDebugLocalInfo(bool is_static,
- uint32_t method_idx,
- NewLocalCallback new_local,
- void* context) const;
-
- protected:
- ALWAYS_INLINE void Init(const CompactDexFile::CodeItem& code_item, uint32_t dex_method_index);
- ALWAYS_INLINE void Init(const StandardDexFile::CodeItem& code_item);
-
- private:
- const DexFile* dex_file_ = nullptr;
- uint32_t debug_info_offset_ = 0u;
-};
-
-} // namespace art
-
-#endif // ART_RUNTIME_DEX_CODE_ITEM_ACCESSORS_H_
diff --git a/runtime/dex/code_item_accessors_test.cc b/runtime/dex/code_item_accessors_test.cc
deleted file mode 100644
index 2bb4dde649..0000000000
--- a/runtime/dex/code_item_accessors_test.cc
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "code_item_accessors-inl.h"
-
-#include <sys/mman.h>
-#include <memory>
-#include <vector>
-
-#include "dex_file_loader.h"
-#include "gtest/gtest.h"
-
-namespace art {
-
-class CodeItemAccessorsTest : public testing::Test {};
-
-std::unique_ptr<const DexFile> CreateFakeDex(bool compact_dex, std::vector<uint8_t>* data) {
- data->resize(kPageSize);
- if (compact_dex) {
- CompactDexFile::Header* header =
- const_cast<CompactDexFile::Header*>(CompactDexFile::Header::At(data->data()));
- CompactDexFile::WriteMagic(header->magic_);
- CompactDexFile::WriteCurrentVersion(header->magic_);
- header->data_off_ = 0;
- header->data_size_ = data->size();
- } else {
- StandardDexFile::WriteMagic(data->data());
- StandardDexFile::WriteCurrentVersion(data->data());
- }
- const DexFileLoader dex_file_loader;
- std::string error_msg;
- std::unique_ptr<const DexFile> dex(dex_file_loader.Open(data->data(),
- data->size(),
- "location",
- /*location_checksum*/ 123,
- /*oat_dex_file*/nullptr,
- /*verify*/false,
- /*verify_checksum*/false,
- &error_msg));
- CHECK(dex != nullptr) << error_msg;
- return dex;
-}
-
-TEST(CodeItemAccessorsTest, TestDexInstructionsAccessor) {
- std::vector<uint8_t> standard_dex_data;
- std::unique_ptr<const DexFile> standard_dex(CreateFakeDex(/*compact_dex*/false,
- &standard_dex_data));
- ASSERT_TRUE(standard_dex != nullptr);
- std::vector<uint8_t> compact_dex_data;
- std::unique_ptr<const DexFile> compact_dex(CreateFakeDex(/*compact_dex*/true,
- &compact_dex_data));
- ASSERT_TRUE(compact_dex != nullptr);
- static constexpr uint16_t kRegisterSize = 2;
- static constexpr uint16_t kInsSize = 1;
- static constexpr uint16_t kOutsSize = 3;
- static constexpr uint16_t kTriesSize = 4;
- // debug_info_off_ is not accessible from the helpers yet.
- static constexpr size_t kInsnsSizeInCodeUnits = 5;
-
- auto verify_code_item = [&](const DexFile* dex,
- const DexFile::CodeItem* item,
- const uint16_t* insns) {
- CodeItemInstructionAccessor insns_accessor(*dex, item);
- EXPECT_TRUE(insns_accessor.HasCodeItem());
- ASSERT_EQ(insns_accessor.InsnsSizeInCodeUnits(), kInsnsSizeInCodeUnits);
- EXPECT_EQ(insns_accessor.Insns(), insns);
-
- CodeItemDataAccessor data_accessor(*dex, item);
- EXPECT_TRUE(data_accessor.HasCodeItem());
- EXPECT_EQ(data_accessor.InsnsSizeInCodeUnits(), kInsnsSizeInCodeUnits);
- EXPECT_EQ(data_accessor.Insns(), insns);
- EXPECT_EQ(data_accessor.RegistersSize(), kRegisterSize);
- EXPECT_EQ(data_accessor.InsSize(), kInsSize);
- EXPECT_EQ(data_accessor.OutsSize(), kOutsSize);
- EXPECT_EQ(data_accessor.TriesSize(), kTriesSize);
- };
-
- StandardDexFile::CodeItem* dex_code_item =
- reinterpret_cast<StandardDexFile::CodeItem*>(const_cast<uint8_t*>(standard_dex->Begin()));
- dex_code_item->registers_size_ = kRegisterSize;
- dex_code_item->ins_size_ = kInsSize;
- dex_code_item->outs_size_ = kOutsSize;
- dex_code_item->tries_size_ = kTriesSize;
- dex_code_item->insns_size_in_code_units_ = kInsnsSizeInCodeUnits;
- verify_code_item(standard_dex.get(), dex_code_item, dex_code_item->insns_);
-
- CompactDexFile::CodeItem* cdex_code_item =
- reinterpret_cast<CompactDexFile::CodeItem*>(const_cast<uint8_t*>(compact_dex->Begin() +
- CompactDexFile::CodeItem::kMaxPreHeaderSize * sizeof(uint16_t)));
- std::vector<uint16_t> preheader;
- cdex_code_item->Create(kRegisterSize,
- kInsSize,
- kOutsSize,
- kTriesSize,
- kInsnsSizeInCodeUnits,
- cdex_code_item->GetPreHeader());
-
- verify_code_item(compact_dex.get(), cdex_code_item, cdex_code_item->insns_);
-}
-
-} // namespace art
diff --git a/runtime/dex/compact_dex_debug_info.cc b/runtime/dex/compact_dex_debug_info.cc
deleted file mode 100644
index 19495ca92c..0000000000
--- a/runtime/dex/compact_dex_debug_info.cc
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "compact_dex_debug_info.h"
-
-#include "compact_dex_utils.h"
-#include "leb128.h"
-
-namespace art {
-
-constexpr size_t CompactDexDebugInfoOffsetTable::kElementsPerIndex;
-
-CompactDexDebugInfoOffsetTable::Accessor::Accessor(const uint8_t* data_begin,
- uint32_t debug_info_base,
- uint32_t debug_info_table_offset)
- : table_(reinterpret_cast<const uint32_t*>(data_begin + debug_info_table_offset)),
- debug_info_base_(debug_info_base),
- data_begin_(data_begin) {}
-
-uint32_t CompactDexDebugInfoOffsetTable::Accessor::GetDebugInfoOffset(uint32_t method_idx) const {
- const uint32_t offset = table_[method_idx / kElementsPerIndex];
- const size_t bit_index = method_idx % kElementsPerIndex;
-
- const uint8_t* block = data_begin_ + offset;
- uint16_t bit_mask = *block;
- ++block;
- bit_mask = (bit_mask << kBitsPerByte) | *block;
- ++block;
- if ((bit_mask & (1 << bit_index)) == 0) {
- // Bit is not set means the offset is 0 for the debug info.
- return 0u;
- }
- // Trim off the bits above the index we want and count how many bits are set. This is how many
- // lebs we need to decode.
- size_t count = POPCOUNT(static_cast<uintptr_t>(bit_mask) << (kBitsPerIntPtrT - 1 - bit_index));
- DCHECK_GT(count, 0u);
- uint32_t current_offset = debug_info_base_;
- do {
- current_offset += DecodeUnsignedLeb128(&block);
- --count;
- } while (count > 0);
- return current_offset;
-}
-
-void CompactDexDebugInfoOffsetTable::Build(const std::vector<uint32_t>& debug_info_offsets,
- std::vector<uint8_t>* out_data,
- uint32_t* out_min_offset,
- uint32_t* out_table_offset) {
- DCHECK(out_data != nullptr);
- DCHECK(out_data->empty());
- // Calculate the base offset and return it.
- *out_min_offset = std::numeric_limits<uint32_t>::max();
- for (const uint32_t offset : debug_info_offsets) {
- if (offset != 0u) {
- *out_min_offset = std::min(*out_min_offset, offset);
- }
- }
- // Write the leb blocks and store the important offsets (each kElementsPerIndex elements).
- size_t block_start = 0;
-
- std::vector<uint32_t> offset_table;
-
- // Write data first then the table.
- while (block_start < debug_info_offsets.size()) {
- // Write the offset of the block for each block.
- offset_table.push_back(out_data->size());
-
- // Block size of up to kElementsPerIndex
- const size_t block_size = std::min(debug_info_offsets.size() - block_start, kElementsPerIndex);
-
- // Calculate bit mask since need to write that first.
- uint16_t bit_mask = 0u;
- for (size_t i = 0; i < block_size; ++i) {
- if (debug_info_offsets[block_start + i] != 0u) {
- bit_mask |= 1 << i;
- }
- }
- // Write bit mask.
- out_data->push_back(static_cast<uint8_t>(bit_mask >> kBitsPerByte));
- out_data->push_back(static_cast<uint8_t>(bit_mask));
-
- // Write debug info offsets relative to the current offset.
- uint32_t current_offset = *out_min_offset;
- for (size_t i = 0; i < block_size; ++i) {
- const uint32_t debug_info_offset = debug_info_offsets[block_start + i];
- if (debug_info_offset != 0u) {
- uint32_t delta = debug_info_offset - current_offset;
- EncodeUnsignedLeb128(out_data, delta);
- current_offset = debug_info_offset;
- }
- }
-
- block_start += block_size;
- }
-
- // Write the offset table.
- AlignmentPadVector(out_data, alignof(uint32_t));
- *out_table_offset = out_data->size();
- out_data->insert(out_data->end(),
- reinterpret_cast<const uint8_t*>(&offset_table[0]),
- reinterpret_cast<const uint8_t*>(&offset_table[0] + offset_table.size()));
-}
-
-} // namespace art
diff --git a/runtime/dex/compact_dex_debug_info.h b/runtime/dex/compact_dex_debug_info.h
deleted file mode 100644
index 1aff75879e..0000000000
--- a/runtime/dex/compact_dex_debug_info.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ART_RUNTIME_DEX_COMPACT_DEX_DEBUG_INFO_H_
-#define ART_RUNTIME_DEX_COMPACT_DEX_DEBUG_INFO_H_
-
-#include <cstdint>
-#include <vector>
-
-namespace art {
-
-// Debug offset table for compact dex, aims to minimize size while still providing reasonable
-// speed (10-20ns average time per lookup on host).
-class CompactDexDebugInfoOffsetTable {
- public:
- // This value is coupled with the leb chunk bitmask. That logic must also be adjusted when the
- // integer is modified.
- static constexpr size_t kElementsPerIndex = 16;
-
- // Leb block format:
- // [uint16_t] 16 bit mask for what method ids actually have a debug info offset for the chunk.
- // [lebs] Up to 16 lebs encoded using leb128, one leb bit. The leb specifies how the offset
- // changes compared to the previous index.
-
- class Accessor {
- public:
- Accessor(const uint8_t* data_begin,
- uint32_t debug_info_base,
- uint32_t debug_info_table_offset);
-
- // Return the debug info for a method index (or 0 if it doesn't have one).
- uint32_t GetDebugInfoOffset(uint32_t method_idx) const;
-
- private:
- const uint32_t* const table_;
- const uint32_t debug_info_base_;
- const uint8_t* const data_begin_;
- };
-
- // Returned offsets are all relative to debug_info_offsets.
- static void Build(const std::vector<uint32_t>& debug_info_offsets,
- std::vector<uint8_t>* out_data,
- uint32_t* out_min_offset,
- uint32_t* out_table_offset);
-
- // 32 bit aligned for the offset table.
- static constexpr size_t kAlignment = sizeof(uint32_t);
-};
-
-} // namespace art
-
-#endif // ART_RUNTIME_DEX_COMPACT_DEX_DEBUG_INFO_H_
diff --git a/runtime/dex/compact_dex_debug_info_test.cc b/runtime/dex/compact_dex_debug_info_test.cc
deleted file mode 100644
index 3267612443..0000000000
--- a/runtime/dex/compact_dex_debug_info_test.cc
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <vector>
-
-#include "base/logging.h"
-#include "dex/compact_dex_debug_info.h"
-#include "gtest/gtest.h"
-
-namespace art {
-
-TEST(CompactDexDebugInfoTest, TestBuildAndAccess) {
- const size_t kDebugInfoMinOffset = 1234567;
- std::vector<uint32_t> offsets = {
- 0, 17, 2, 3, 11, 0, 0, 0, 0, 1, 0, 1552, 100, 122, 44, 1234567, 0, 0,
- std::numeric_limits<uint32_t>::max() - kDebugInfoMinOffset, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12,
- };
- // Add some large offset since the debug info section will never be that close to the beginning
- // of the file.
- for (uint32_t& offset : offsets) {
- if (offset != 0u) {
- offset += kDebugInfoMinOffset;
- }
- }
-
- std::vector<uint8_t> data;
- uint32_t base_offset = 0;
- uint32_t table_offset = 0;
- CompactDexDebugInfoOffsetTable::Build(offsets,
- /*out*/ &data,
- /*out*/ &base_offset,
- /*out*/ &table_offset);
- EXPECT_GE(base_offset, kDebugInfoMinOffset);
- EXPECT_LT(table_offset, data.size());
- ASSERT_GT(data.size(), 0u);
- const size_t before_size = offsets.size() * sizeof(offsets.front());
- EXPECT_LT(data.size(), before_size);
-
- // Note that the accessor requires the data to be aligned. Use memmap to accomplish this.
- std::string error_msg;
- // Leave some extra room since we don't copy the table at the start (for testing).
- constexpr size_t kExtraOffset = 4 * 128;
- std::vector<uint8_t> fake_dex(data.size() + kExtraOffset);
- std::copy(data.begin(), data.end(), fake_dex.data() + kExtraOffset);
-
- CompactDexDebugInfoOffsetTable::Accessor accessor(fake_dex.data() + kExtraOffset,
- base_offset,
- table_offset);
- for (size_t i = 0; i < offsets.size(); ++i) {
- EXPECT_EQ(offsets[i], accessor.GetDebugInfoOffset(i));
- }
-
- // Sort to produce a try and produce a smaller table. This happens because the leb diff is smaller
- // for sorted increasing order.
- std::sort(offsets.begin(), offsets.end());
- std::vector<uint8_t> sorted_data;
- CompactDexDebugInfoOffsetTable::Build(offsets,
- /*out*/ &sorted_data,
- /*out*/ &base_offset,
- /*out*/ &table_offset);
- EXPECT_LT(sorted_data.size(), data.size());
- {
- ScopedLogSeverity sls(LogSeverity::INFO);
- LOG(INFO) << "raw size " << before_size
- << " table size " << data.size()
- << " sorted table size " << sorted_data.size();
- }
-}
-
-} // namespace art
diff --git a/runtime/dex/compact_dex_file.cc b/runtime/dex/compact_dex_file.cc
deleted file mode 100644
index ce289d4d7b..0000000000
--- a/runtime/dex/compact_dex_file.cc
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "compact_dex_file.h"
-
-#include "code_item_accessors-inl.h"
-#include "dex_file-inl.h"
-#include "leb128.h"
-
-namespace art {
-
-constexpr uint8_t CompactDexFile::kDexMagic[kDexMagicSize];
-constexpr uint8_t CompactDexFile::kDexMagicVersion[];
-
-void CompactDexFile::WriteMagic(uint8_t* magic) {
- std::copy_n(kDexMagic, kDexMagicSize, magic);
-}
-
-void CompactDexFile::WriteCurrentVersion(uint8_t* magic) {
- std::copy_n(kDexMagicVersion, kDexVersionLen, magic + kDexMagicSize);
-}
-
-bool CompactDexFile::IsMagicValid(const uint8_t* magic) {
- return (memcmp(magic, kDexMagic, sizeof(kDexMagic)) == 0);
-}
-
-bool CompactDexFile::IsVersionValid(const uint8_t* magic) {
- const uint8_t* version = &magic[sizeof(kDexMagic)];
- return memcmp(version, kDexMagicVersion, kDexVersionLen) == 0;
-}
-
-bool CompactDexFile::IsMagicValid() const {
- return IsMagicValid(header_->magic_);
-}
-
-bool CompactDexFile::IsVersionValid() const {
- return IsVersionValid(header_->magic_);
-}
-
-bool CompactDexFile::SupportsDefaultMethods() const {
- return (GetHeader().GetFeatureFlags() &
- static_cast<uint32_t>(FeatureFlags::kDefaultMethods)) != 0;
-}
-
-uint32_t CompactDexFile::GetCodeItemSize(const DexFile::CodeItem& item) const {
- DCHECK(IsInDataSection(&item));
- return reinterpret_cast<uintptr_t>(CodeItemDataAccessor(*this, &item).CodeItemDataEnd()) -
- reinterpret_cast<uintptr_t>(&item);
-}
-
-
-uint32_t CompactDexFile::CalculateChecksum(const uint8_t* base_begin,
- size_t base_size,
- const uint8_t* data_begin,
- size_t data_size) {
- Header temp_header(*Header::At(base_begin));
- // Zero out fields that are not included in the sum.
- temp_header.checksum_ = 0u;
- temp_header.data_off_ = 0u;
- temp_header.data_size_ = 0u;
- uint32_t checksum = ChecksumMemoryRange(reinterpret_cast<const uint8_t*>(&temp_header),
- sizeof(temp_header));
- // Exclude the header since we already computed it's checksum.
- checksum = (checksum * 31) ^ ChecksumMemoryRange(base_begin + sizeof(temp_header),
- base_size - sizeof(temp_header));
- checksum = (checksum * 31) ^ ChecksumMemoryRange(data_begin, data_size);
- return checksum;
-}
-
-uint32_t CompactDexFile::CalculateChecksum() const {
- return CalculateChecksum(Begin(), Size(), DataBegin(), DataSize());
-}
-
-CompactDexFile::CompactDexFile(const uint8_t* base,
- size_t size,
- const uint8_t* data_begin,
- size_t data_size,
- const std::string& location,
- uint32_t location_checksum,
- const OatDexFile* oat_dex_file,
- DexFileContainer* container)
- : DexFile(base,
- size,
- data_begin,
- data_size,
- location,
- location_checksum,
- oat_dex_file,
- container,
- /*is_compact_dex*/ true),
- debug_info_offsets_(DataBegin() + GetHeader().debug_info_offsets_pos_,
- GetHeader().debug_info_base_,
- GetHeader().debug_info_offsets_table_offset_) {}
-
-} // namespace art
diff --git a/runtime/dex/compact_dex_file.h b/runtime/dex/compact_dex_file.h
deleted file mode 100644
index 31aeb27872..0000000000
--- a/runtime/dex/compact_dex_file.h
+++ /dev/null
@@ -1,291 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ART_RUNTIME_DEX_COMPACT_DEX_FILE_H_
-#define ART_RUNTIME_DEX_COMPACT_DEX_FILE_H_
-
-#include "base/casts.h"
-#include "dex_file.h"
-#include "dex/compact_dex_debug_info.h"
-
-namespace art {
-
-// CompactDex is a currently ART internal dex file format that aims to reduce storage/RAM usage.
-class CompactDexFile : public DexFile {
- public:
- static constexpr uint8_t kDexMagic[kDexMagicSize] = { 'c', 'd', 'e', 'x' };
- static constexpr uint8_t kDexMagicVersion[] = {'0', '0', '1', '\0'};
-
- enum class FeatureFlags : uint32_t {
- kDefaultMethods = 0x1,
- };
-
- class Header : public DexFile::Header {
- public:
- static const Header* At(const void* at) {
- return reinterpret_cast<const Header*>(at);
- }
-
- uint32_t GetFeatureFlags() const {
- return feature_flags_;
- }
-
- uint32_t GetDataOffset() const {
- return data_off_;
- }
-
- uint32_t GetDataSize() const {
- return data_size_;
- }
-
- private:
- uint32_t feature_flags_ = 0u;
-
- // Position in the compact dex file for the debug info table data starts.
- uint32_t debug_info_offsets_pos_ = 0u;
-
- // Offset into the debug info table data where the lookup table is.
- uint32_t debug_info_offsets_table_offset_ = 0u;
-
- // Base offset of where debug info starts in the dex file.
- uint32_t debug_info_base_ = 0u;
-
- friend class CompactDexFile;
- friend class CompactDexWriter;
- };
-
- // Like the standard code item except without a debug info offset. Each code item may have a
- // preheader to encode large methods. In 99% of cases, the preheader is not used. This enables
- // smaller size with a good fast path case in the accessors.
- struct CodeItem : public DexFile::CodeItem {
- static constexpr size_t kAlignment = sizeof(uint16_t);
- // Max preheader size in uint16_ts.
- static constexpr size_t kMaxPreHeaderSize = 6;
-
- private:
- CodeItem() = default;
-
- static constexpr size_t kRegistersSizeShift = 12;
- static constexpr size_t kInsSizeShift = 8;
- static constexpr size_t kOutsSizeShift = 4;
- static constexpr size_t kTriesSizeSizeShift = 0;
- static constexpr uint16_t kFlagPreHeaderRegisterSize = 0x1 << 0;
- static constexpr uint16_t kFlagPreHeaderInsSize = 0x1 << 1;
- static constexpr uint16_t kFlagPreHeaderOutsSize = 0x1 << 2;
- static constexpr uint16_t kFlagPreHeaderTriesSize = 0x1 << 3;
- static constexpr uint16_t kFlagPreHeaderInsnsSize = 0x1 << 4;
- static constexpr size_t kInsnsSizeShift = 5;
- static constexpr size_t kInsnsSizeBits = sizeof(uint16_t) * kBitsPerByte - kInsnsSizeShift;
-
- // Combined preheader flags for fast testing if we need to go slow path.
- static constexpr uint16_t kFlagPreHeaderCombined =
- kFlagPreHeaderRegisterSize |
- kFlagPreHeaderInsSize |
- kFlagPreHeaderOutsSize |
- kFlagPreHeaderTriesSize |
- kFlagPreHeaderInsnsSize;
-
- // Create a code item and associated preheader if required based on field values.
- // Returns the start of the preheader. The preheader buffer must be at least as large as
- // kMaxPreHeaderSize;
- uint16_t* Create(uint16_t registers_size,
- uint16_t ins_size,
- uint16_t outs_size,
- uint16_t tries_size,
- uint32_t insns_size_in_code_units,
- uint16_t* out_preheader) {
- // Dex verification ensures that registers size > ins_size, so we can subtract the registers
- // size accordingly to reduce how often we need to use the preheader.
- DCHECK_GE(registers_size, ins_size);
- registers_size -= ins_size;
- fields_ = (registers_size & 0xF) << kRegistersSizeShift;
- fields_ |= (ins_size & 0xF) << kInsSizeShift;
- fields_ |= (outs_size & 0xF) << kOutsSizeShift;
- fields_ |= (tries_size & 0xF) << kTriesSizeSizeShift;
- registers_size &= ~0xF;
- ins_size &= ~0xF;
- outs_size &= ~0xF;
- tries_size &= ~0xF;
- insns_count_and_flags_ = 0;
- const size_t masked_count = insns_size_in_code_units & ((1 << kInsnsSizeBits) - 1);
- insns_count_and_flags_ |= masked_count << kInsnsSizeShift;
- insns_size_in_code_units -= masked_count;
-
- // Since the preheader case is rare (1% of code items), use a suboptimally large but fast
- // decoding format.
- if (insns_size_in_code_units != 0) {
- insns_count_and_flags_ |= kFlagPreHeaderInsnsSize;
- --out_preheader;
- *out_preheader = static_cast<uint16_t>(insns_size_in_code_units);
- --out_preheader;
- *out_preheader = static_cast<uint16_t>(insns_size_in_code_units >> 16);
- }
- auto preheader_encode = [&](uint16_t size, uint16_t flag) {
- if (size != 0) {
- insns_count_and_flags_ |= flag;
- --out_preheader;
- *out_preheader = size;
- }
- };
- preheader_encode(registers_size, kFlagPreHeaderRegisterSize);
- preheader_encode(ins_size, kFlagPreHeaderInsSize);
- preheader_encode(outs_size, kFlagPreHeaderOutsSize);
- preheader_encode(tries_size, kFlagPreHeaderTriesSize);
- return out_preheader;
- }
-
- ALWAYS_INLINE bool HasPreHeader(uint16_t flag) const {
- return (insns_count_and_flags_ & flag) != 0;
- }
-
- // Return true if the code item has any preheaders.
- ALWAYS_INLINE static bool HasAnyPreHeader(uint16_t insns_count_and_flags) {
- return (insns_count_and_flags & kFlagPreHeaderCombined) != 0;
- }
-
- ALWAYS_INLINE uint16_t* GetPreHeader() {
- return reinterpret_cast<uint16_t*>(this);
- }
-
- ALWAYS_INLINE const uint16_t* GetPreHeader() const {
- return reinterpret_cast<const uint16_t*>(this);
- }
-
- // Decode fields and read the preheader if necessary. If kDecodeOnlyInstructionCount is
- // specified then only the instruction count is decoded.
- template <bool kDecodeOnlyInstructionCount>
- ALWAYS_INLINE void DecodeFields(uint32_t* insns_count,
- uint16_t* registers_size,
- uint16_t* ins_size,
- uint16_t* outs_size,
- uint16_t* tries_size) const {
- *insns_count = insns_count_and_flags_ >> kInsnsSizeShift;
- if (!kDecodeOnlyInstructionCount) {
- const uint16_t fields = fields_;
- *registers_size = (fields >> kRegistersSizeShift) & 0xF;
- *ins_size = (fields >> kInsSizeShift) & 0xF;
- *outs_size = (fields >> kOutsSizeShift) & 0xF;
- *tries_size = (fields >> kTriesSizeSizeShift) & 0xF;
- }
- if (UNLIKELY(HasAnyPreHeader(insns_count_and_flags_))) {
- const uint16_t* preheader = GetPreHeader();
- if (HasPreHeader(kFlagPreHeaderInsnsSize)) {
- --preheader;
- *insns_count += static_cast<uint32_t>(*preheader);
- --preheader;
- *insns_count += static_cast<uint32_t>(*preheader) << 16;
- }
- if (!kDecodeOnlyInstructionCount) {
- if (HasPreHeader(kFlagPreHeaderRegisterSize)) {
- --preheader;
- *registers_size += preheader[0];
- }
- if (HasPreHeader(kFlagPreHeaderInsSize)) {
- --preheader;
- *ins_size += preheader[0];
- }
- if (HasPreHeader(kFlagPreHeaderOutsSize)) {
- --preheader;
- *outs_size += preheader[0];
- }
- if (HasPreHeader(kFlagPreHeaderTriesSize)) {
- --preheader;
- *tries_size += preheader[0];
- }
- }
- }
- if (!kDecodeOnlyInstructionCount) {
- *registers_size += *ins_size;
- }
- }
-
- // Packed code item data, 4 bits each: [registers_size, ins_size, outs_size, tries_size]
- uint16_t fields_;
-
- // 5 bits for if either of the fields required preheader extension, 11 bits for the number of
- // instruction code units.
- uint16_t insns_count_and_flags_;
-
- uint16_t insns_[1]; // actual array of bytecode.
-
- ART_FRIEND_TEST(CodeItemAccessorsTest, TestDexInstructionsAccessor);
- ART_FRIEND_TEST(CompactDexFileTest, CodeItemFields);
- friend class CodeItemDataAccessor;
- friend class CodeItemDebugInfoAccessor;
- friend class CodeItemInstructionAccessor;
- friend class CompactDexFile;
- friend class CompactDexWriter;
- DISALLOW_COPY_AND_ASSIGN(CodeItem);
- };
-
- // Write the compact dex specific magic.
- static void WriteMagic(uint8_t* magic);
-
- // Write the current version, note that the input is the address of the magic.
- static void WriteCurrentVersion(uint8_t* magic);
-
- // Returns true if the byte string points to the magic value.
- static bool IsMagicValid(const uint8_t* magic);
- virtual bool IsMagicValid() const OVERRIDE;
-
- // Returns true if the byte string after the magic is the correct value.
- static bool IsVersionValid(const uint8_t* magic);
- virtual bool IsVersionValid() const OVERRIDE;
-
- // TODO This is completely a guess. We really need to do better. b/72402467
- // We ask for 64 megabytes which should be big enough for any realistic dex file.
- virtual size_t GetDequickenedSize() const OVERRIDE {
- return 64 * MB;
- }
-
- const Header& GetHeader() const {
- return down_cast<const Header&>(DexFile::GetHeader());
- }
-
- virtual bool SupportsDefaultMethods() const OVERRIDE;
-
- uint32_t GetCodeItemSize(const DexFile::CodeItem& item) const OVERRIDE;
-
- uint32_t GetDebugInfoOffset(uint32_t dex_method_index) const {
- return debug_info_offsets_.GetDebugInfoOffset(dex_method_index);
- }
-
- static uint32_t CalculateChecksum(const uint8_t* base_begin,
- size_t base_size,
- const uint8_t* data_begin,
- size_t data_size);
- virtual uint32_t CalculateChecksum() const OVERRIDE;
-
- private:
- CompactDexFile(const uint8_t* base,
- size_t size,
- const uint8_t* data_begin,
- size_t data_size,
- const std::string& location,
- uint32_t location_checksum,
- const OatDexFile* oat_dex_file,
- DexFileContainer* container);
-
- CompactDexDebugInfoOffsetTable::Accessor debug_info_offsets_;
-
- friend class DexFile;
- friend class DexFileLoader;
- DISALLOW_COPY_AND_ASSIGN(CompactDexFile);
-};
-
-} // namespace art
-
-#endif // ART_RUNTIME_DEX_COMPACT_DEX_FILE_H_
diff --git a/runtime/dex/compact_dex_file_test.cc b/runtime/dex/compact_dex_file_test.cc
deleted file mode 100644
index 517c5873ed..0000000000
--- a/runtime/dex/compact_dex_file_test.cc
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-#include "compact_dex_file.h"
-#include "dex_file_loader.h"
-#include "gtest/gtest.h"
-
-namespace art {
-
-TEST(CompactDexFileTest, MagicAndVersion) {
- // Test permutations of valid/invalid headers.
- for (size_t i = 0; i < 2; ++i) {
- for (size_t j = 0; j < 2; ++j) {
- static const size_t len = CompactDexFile::kDexVersionLen + CompactDexFile::kDexMagicSize;
- uint8_t header[len] = {};
- std::fill_n(header, len, 0x99);
- const bool valid_magic = (i & 1) == 0;
- const bool valid_version = (j & 1) == 0;
- if (valid_magic) {
- CompactDexFile::WriteMagic(header);
- }
- if (valid_version) {
- CompactDexFile::WriteCurrentVersion(header);
- }
- EXPECT_EQ(valid_magic, CompactDexFile::IsMagicValid(header));
- EXPECT_EQ(valid_version, CompactDexFile::IsVersionValid(header));
- EXPECT_EQ(valid_magic, DexFileLoader::IsMagicValid(header));
- EXPECT_EQ(valid_magic && valid_version, DexFileLoader::IsVersionAndMagicValid(header));
- }
- }
-}
-
-TEST(CompactDexFileTest, CodeItemFields) {
- auto test_and_write = [&] (uint16_t registers_size,
- uint16_t ins_size,
- uint16_t outs_size,
- uint16_t tries_size,
- uint32_t insns_size_in_code_units) {
- ASSERT_GE(registers_size, ins_size);
- uint16_t buffer[sizeof(CompactDexFile::CodeItem) +
- CompactDexFile::CodeItem::kMaxPreHeaderSize] = {};
- CompactDexFile::CodeItem* code_item = reinterpret_cast<CompactDexFile::CodeItem*>(
- &buffer[CompactDexFile::CodeItem::kMaxPreHeaderSize]);
- const uint16_t* preheader_ptr = code_item->Create(registers_size,
- ins_size,
- outs_size,
- tries_size,
- insns_size_in_code_units,
- code_item->GetPreHeader());
- ASSERT_GT(preheader_ptr, buffer);
-
- uint16_t out_registers_size;
- uint16_t out_ins_size;
- uint16_t out_outs_size;
- uint16_t out_tries_size;
- uint32_t out_insns_size_in_code_units;
- code_item->DecodeFields</*kDecodeOnlyInstructionCount*/false>(&out_insns_size_in_code_units,
- &out_registers_size,
- &out_ins_size,
- &out_outs_size,
- &out_tries_size);
- ASSERT_EQ(registers_size, out_registers_size);
- ASSERT_EQ(ins_size, out_ins_size);
- ASSERT_EQ(outs_size, out_outs_size);
- ASSERT_EQ(tries_size, out_tries_size);
- ASSERT_EQ(insns_size_in_code_units, out_insns_size_in_code_units);
-
- ++out_insns_size_in_code_units; // Force value to change.
- code_item->DecodeFields</*kDecodeOnlyInstructionCount*/true>(&out_insns_size_in_code_units,
- /*registers_size*/ nullptr,
- /*ins_size*/ nullptr,
- /*outs_size*/ nullptr,
- /*tries_size*/ nullptr);
- ASSERT_EQ(insns_size_in_code_units, out_insns_size_in_code_units);
- };
- static constexpr uint32_t kMax32 = std::numeric_limits<uint32_t>::max();
- static constexpr uint16_t kMax16 = std::numeric_limits<uint16_t>::max();
- test_and_write(0, 0, 0, 0, 0);
- test_and_write(kMax16, kMax16, kMax16, kMax16, kMax32);
- test_and_write(kMax16 - 1, kMax16 - 2, kMax16 - 3, kMax16 - 4, kMax32 - 5);
- test_and_write(kMax16 - 4, kMax16 - 5, kMax16 - 3, kMax16 - 2, kMax32 - 1);
- test_and_write(5, 4, 3, 2, 1);
- test_and_write(5, 0, 3, 2, 1);
- test_and_write(kMax16, 0, kMax16 / 2, 1234, kMax32 / 4);
-}
-
-} // namespace art
diff --git a/runtime/dex/compact_dex_level.h b/runtime/dex/compact_dex_level.h
deleted file mode 100644
index de9ca3c783..0000000000
--- a/runtime/dex/compact_dex_level.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ART_RUNTIME_DEX_COMPACT_DEX_LEVEL_H_
-#define ART_RUNTIME_DEX_COMPACT_DEX_LEVEL_H_
-
-#include <string>
-
-#include "base/macros.h"
-#include "dex_file.h"
-
-namespace art {
-
-// Optimization level for compact dex generation.
-enum class CompactDexLevel {
- // Level none means not generated.
- kCompactDexLevelNone,
- // Level fast means optimizations that don't take many resources to perform.
- kCompactDexLevelFast,
-};
-
-#ifndef ART_DEFAULT_COMPACT_DEX_LEVEL
-#error ART_DEFAULT_COMPACT_DEX_LEVEL not specified.
-#else
-#define ART_DEFAULT_COMPACT_DEX_LEVEL_VALUE_fast CompactDexLevel::kCompactDexLevelFast
-#define ART_DEFAULT_COMPACT_DEX_LEVEL_VALUE_none CompactDexLevel::kCompactDexLevelNone
-
-#define ART_DEFAULT_COMPACT_DEX_LEVEL_DEFAULT APPEND_TOKENS_AFTER_EVAL( \
- ART_DEFAULT_COMPACT_DEX_LEVEL_VALUE_, \
- ART_DEFAULT_COMPACT_DEX_LEVEL)
-
-static constexpr CompactDexLevel kDefaultCompactDexLevel = ART_DEFAULT_COMPACT_DEX_LEVEL_DEFAULT;
-#endif
-
-} // namespace art
-
-#endif // ART_RUNTIME_DEX_COMPACT_DEX_LEVEL_H_
diff --git a/runtime/dex/compact_dex_utils.h b/runtime/dex/compact_dex_utils.h
deleted file mode 100644
index 1c7e9514fd..0000000000
--- a/runtime/dex/compact_dex_utils.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ART_RUNTIME_DEX_COMPACT_DEX_UTILS_H_
-#define ART_RUNTIME_DEX_COMPACT_DEX_UTILS_H_
-
-#include <vector>
-
-#include "base/bit_utils.h"
-
-namespace art {
-
-// Add padding to the end of the array until the size is aligned.
-template <typename T, template<typename> class Allocator>
-static inline void AlignmentPadVector(std::vector<T, Allocator<T>>* dest,
- size_t alignment) {
- while (!IsAlignedParam(dest->size(), alignment)) {
- dest->push_back(T());
- }
-}
-
-} // namespace art
-
-#endif // ART_RUNTIME_DEX_COMPACT_DEX_UTILS_H_
diff --git a/runtime/dex/descriptors_names.cc b/runtime/dex/descriptors_names.cc
deleted file mode 100644
index 8124e7256f..0000000000
--- a/runtime/dex/descriptors_names.cc
+++ /dev/null
@@ -1,426 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "descriptors_names.h"
-
-#include "android-base/stringprintf.h"
-#include "android-base/strings.h"
-
-#include "dex/utf-inl.h"
-
-namespace art {
-
-using android::base::StringAppendF;
-using android::base::StringPrintf;
-
-void AppendPrettyDescriptor(const char* descriptor, std::string* result) {
- // Count the number of '['s to get the dimensionality.
- const char* c = descriptor;
- size_t dim = 0;
- while (*c == '[') {
- dim++;
- c++;
- }
-
- // Reference or primitive?
- if (*c == 'L') {
- // "[[La/b/C;" -> "a.b.C[][]".
- c++; // Skip the 'L'.
- } else {
- // "[[B" -> "byte[][]".
- // To make life easier, we make primitives look like unqualified
- // reference types.
- switch (*c) {
- case 'B': c = "byte;"; break;
- case 'C': c = "char;"; break;
- case 'D': c = "double;"; break;
- case 'F': c = "float;"; break;
- case 'I': c = "int;"; break;
- case 'J': c = "long;"; break;
- case 'S': c = "short;"; break;
- case 'Z': c = "boolean;"; break;
- case 'V': c = "void;"; break; // Used when decoding return types.
- default: result->append(descriptor); return;
- }
- }
-
- // At this point, 'c' is a string of the form "fully/qualified/Type;"
- // or "primitive;". Rewrite the type with '.' instead of '/':
- const char* p = c;
- while (*p != ';') {
- char ch = *p++;
- if (ch == '/') {
- ch = '.';
- }
- result->push_back(ch);
- }
- // ...and replace the semicolon with 'dim' "[]" pairs:
- for (size_t i = 0; i < dim; ++i) {
- result->append("[]");
- }
-}
-
-std::string PrettyDescriptor(const char* descriptor) {
- std::string result;
- AppendPrettyDescriptor(descriptor, &result);
- return result;
-}
-
-std::string GetJniShortName(const std::string& class_descriptor, const std::string& method) {
- // Remove the leading 'L' and trailing ';'...
- std::string class_name(class_descriptor);
- CHECK_EQ(class_name[0], 'L') << class_name;
- CHECK_EQ(class_name[class_name.size() - 1], ';') << class_name;
- class_name.erase(0, 1);
- class_name.erase(class_name.size() - 1, 1);
-
- std::string short_name;
- short_name += "Java_";
- short_name += MangleForJni(class_name);
- short_name += "_";
- short_name += MangleForJni(method);
- return short_name;
-}
-
-// See http://java.sun.com/j2se/1.5.0/docs/guide/jni/spec/design.html#wp615 for the full rules.
-std::string MangleForJni(const std::string& s) {
- std::string result;
- size_t char_count = CountModifiedUtf8Chars(s.c_str());
- const char* cp = &s[0];
- for (size_t i = 0; i < char_count; ++i) {
- uint32_t ch = GetUtf16FromUtf8(&cp);
- if ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9')) {
- result.push_back(ch);
- } else if (ch == '.' || ch == '/') {
- result += "_";
- } else if (ch == '_') {
- result += "_1";
- } else if (ch == ';') {
- result += "_2";
- } else if (ch == '[') {
- result += "_3";
- } else {
- const uint16_t leading = GetLeadingUtf16Char(ch);
- const uint32_t trailing = GetTrailingUtf16Char(ch);
-
- StringAppendF(&result, "_0%04x", leading);
- if (trailing != 0) {
- StringAppendF(&result, "_0%04x", trailing);
- }
- }
- }
- return result;
-}
-
-std::string DotToDescriptor(const char* class_name) {
- std::string descriptor(class_name);
- std::replace(descriptor.begin(), descriptor.end(), '.', '/');
- if (descriptor.length() > 0 && descriptor[0] != '[') {
- descriptor = "L" + descriptor + ";";
- }
- return descriptor;
-}
-
-std::string DescriptorToDot(const char* descriptor) {
- size_t length = strlen(descriptor);
- if (length > 1) {
- if (descriptor[0] == 'L' && descriptor[length - 1] == ';') {
- // Descriptors have the leading 'L' and trailing ';' stripped.
- std::string result(descriptor + 1, length - 2);
- std::replace(result.begin(), result.end(), '/', '.');
- return result;
- } else {
- // For arrays the 'L' and ';' remain intact.
- std::string result(descriptor);
- std::replace(result.begin(), result.end(), '/', '.');
- return result;
- }
- }
- // Do nothing for non-class/array descriptors.
- return descriptor;
-}
-
-std::string DescriptorToName(const char* descriptor) {
- size_t length = strlen(descriptor);
- if (descriptor[0] == 'L' && descriptor[length - 1] == ';') {
- std::string result(descriptor + 1, length - 2);
- return result;
- }
- return descriptor;
-}
-
-// Helper for IsValidPartOfMemberNameUtf8(), a bit vector indicating valid low ascii.
-static uint32_t DEX_MEMBER_VALID_LOW_ASCII[4] = {
- 0x00000000, // 00..1f low control characters; nothing valid
- 0x03ff2010, // 20..3f digits and symbols; valid: '0'..'9', '$', '-'
- 0x87fffffe, // 40..5f uppercase etc.; valid: 'A'..'Z', '_'
- 0x07fffffe // 60..7f lowercase etc.; valid: 'a'..'z'
-};
-
-// Helper for IsValidPartOfMemberNameUtf8(); do not call directly.
-static bool IsValidPartOfMemberNameUtf8Slow(const char** pUtf8Ptr) {
- /*
- * It's a multibyte encoded character. Decode it and analyze. We
- * accept anything that isn't (a) an improperly encoded low value,
- * (b) an improper surrogate pair, (c) an encoded '\0', (d) a high
- * control character, or (e) a high space, layout, or special
- * character (U+00a0, U+2000..U+200f, U+2028..U+202f,
- * U+fff0..U+ffff). This is all specified in the dex format
- * document.
- */
-
- const uint32_t pair = GetUtf16FromUtf8(pUtf8Ptr);
- const uint16_t leading = GetLeadingUtf16Char(pair);
-
- // We have a surrogate pair resulting from a valid 4 byte UTF sequence.
- // No further checks are necessary because 4 byte sequences span code
- // points [U+10000, U+1FFFFF], which are valid codepoints in a dex
- // identifier. Furthermore, GetUtf16FromUtf8 guarantees that each of
- // the surrogate halves are valid and well formed in this instance.
- if (GetTrailingUtf16Char(pair) != 0) {
- return true;
- }
-
-
- // We've encountered a one, two or three byte UTF-8 sequence. The
- // three byte UTF-8 sequence could be one half of a surrogate pair.
- switch (leading >> 8) {
- case 0x00:
- // It's only valid if it's above the ISO-8859-1 high space (0xa0).
- return (leading > 0x00a0);
- case 0xd8:
- case 0xd9:
- case 0xda:
- case 0xdb:
- {
- // We found a three byte sequence encoding one half of a surrogate.
- // Look for the other half.
- const uint32_t pair2 = GetUtf16FromUtf8(pUtf8Ptr);
- const uint16_t trailing = GetLeadingUtf16Char(pair2);
-
- return (GetTrailingUtf16Char(pair2) == 0) && (0xdc00 <= trailing && trailing <= 0xdfff);
- }
- case 0xdc:
- case 0xdd:
- case 0xde:
- case 0xdf:
- // It's a trailing surrogate, which is not valid at this point.
- return false;
- case 0x20:
- case 0xff:
- // It's in the range that has spaces, controls, and specials.
- switch (leading & 0xfff8) {
- case 0x2000:
- case 0x2008:
- case 0x2028:
- case 0xfff0:
- case 0xfff8:
- return false;
- }
- return true;
- default:
- return true;
- }
-
- UNREACHABLE();
-}
-
-/* Return whether the pointed-at modified-UTF-8 encoded character is
- * valid as part of a member name, updating the pointer to point past
- * the consumed character. This will consume two encoded UTF-16 code
- * points if the character is encoded as a surrogate pair. Also, if
- * this function returns false, then the given pointer may only have
- * been partially advanced.
- */
-static bool IsValidPartOfMemberNameUtf8(const char** pUtf8Ptr) {
- uint8_t c = (uint8_t) **pUtf8Ptr;
- if (LIKELY(c <= 0x7f)) {
- // It's low-ascii, so check the table.
- uint32_t wordIdx = c >> 5;
- uint32_t bitIdx = c & 0x1f;
- (*pUtf8Ptr)++;
- return (DEX_MEMBER_VALID_LOW_ASCII[wordIdx] & (1 << bitIdx)) != 0;
- }
-
- // It's a multibyte encoded character. Call a non-inline function
- // for the heavy lifting.
- return IsValidPartOfMemberNameUtf8Slow(pUtf8Ptr);
-}
-
-bool IsValidMemberName(const char* s) {
- bool angle_name = false;
-
- switch (*s) {
- case '\0':
- // The empty string is not a valid name.
- return false;
- case '<':
- angle_name = true;
- s++;
- break;
- }
-
- while (true) {
- switch (*s) {
- case '\0':
- return !angle_name;
- case '>':
- return angle_name && s[1] == '\0';
- }
-
- if (!IsValidPartOfMemberNameUtf8(&s)) {
- return false;
- }
- }
-}
-
-enum ClassNameType { kName, kDescriptor };
-template<ClassNameType kType, char kSeparator>
-static bool IsValidClassName(const char* s) {
- int arrayCount = 0;
- while (*s == '[') {
- arrayCount++;
- s++;
- }
-
- if (arrayCount > 255) {
- // Arrays may have no more than 255 dimensions.
- return false;
- }
-
- ClassNameType type = kType;
- if (type != kDescriptor && arrayCount != 0) {
- /*
- * If we're looking at an array of some sort, then it doesn't
- * matter if what is being asked for is a class name; the
- * format looks the same as a type descriptor in that case, so
- * treat it as such.
- */
- type = kDescriptor;
- }
-
- if (type == kDescriptor) {
- /*
- * We are looking for a descriptor. Either validate it as a
- * single-character primitive type, or continue on to check the
- * embedded class name (bracketed by "L" and ";").
- */
- switch (*(s++)) {
- case 'B':
- case 'C':
- case 'D':
- case 'F':
- case 'I':
- case 'J':
- case 'S':
- case 'Z':
- // These are all single-character descriptors for primitive types.
- return (*s == '\0');
- case 'V':
- // Non-array void is valid, but you can't have an array of void.
- return (arrayCount == 0) && (*s == '\0');
- case 'L':
- // Class name: Break out and continue below.
- break;
- default:
- // Oddball descriptor character.
- return false;
- }
- }
-
- /*
- * We just consumed the 'L' that introduces a class name as part
- * of a type descriptor, or we are looking for an unadorned class
- * name.
- */
-
- bool sepOrFirst = true; // first character or just encountered a separator.
- for (;;) {
- uint8_t c = (uint8_t) *s;
- switch (c) {
- case '\0':
- /*
- * Premature end for a type descriptor, but valid for
- * a class name as long as we haven't encountered an
- * empty component (including the degenerate case of
- * the empty string "").
- */
- return (type == kName) && !sepOrFirst;
- case ';':
- /*
- * Invalid character for a class name, but the
- * legitimate end of a type descriptor. In the latter
- * case, make sure that this is the end of the string
- * and that it doesn't end with an empty component
- * (including the degenerate case of "L;").
- */
- return (type == kDescriptor) && !sepOrFirst && (s[1] == '\0');
- case '/':
- case '.':
- if (c != kSeparator) {
- // The wrong separator character.
- return false;
- }
- if (sepOrFirst) {
- // Separator at start or two separators in a row.
- return false;
- }
- sepOrFirst = true;
- s++;
- break;
- default:
- if (!IsValidPartOfMemberNameUtf8(&s)) {
- return false;
- }
- sepOrFirst = false;
- break;
- }
- }
-}
-
-bool IsValidBinaryClassName(const char* s) {
- return IsValidClassName<kName, '.'>(s);
-}
-
-bool IsValidJniClassName(const char* s) {
- return IsValidClassName<kName, '/'>(s);
-}
-
-bool IsValidDescriptor(const char* s) {
- return IsValidClassName<kDescriptor, '/'>(s);
-}
-
-void Split(const std::string& s, char separator, std::vector<std::string>* result) {
- const char* p = s.data();
- const char* end = p + s.size();
- while (p != end) {
- if (*p == separator) {
- ++p;
- } else {
- const char* start = p;
- while (++p != end && *p != separator) {
- // Skip to the next occurrence of the separator.
- }
- result->push_back(std::string(start, p - start));
- }
- }
-}
-
-std::string PrettyDescriptor(Primitive::Type type) {
- return PrettyDescriptor(Primitive::Descriptor(type));
-}
-
-} // namespace art
diff --git a/runtime/dex/descriptors_names.h b/runtime/dex/descriptors_names.h
deleted file mode 100644
index 22e9573556..0000000000
--- a/runtime/dex/descriptors_names.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ART_RUNTIME_DEX_DESCRIPTORS_NAMES_H_
-#define ART_RUNTIME_DEX_DESCRIPTORS_NAMES_H_
-
-#include <string>
-
-#include "primitive.h"
-
-namespace art {
-
-// Used to implement PrettyClass, PrettyField, PrettyMethod, and PrettyTypeOf,
-// one of which is probably more useful to you.
-// Returns a human-readable equivalent of 'descriptor'. So "I" would be "int",
-// "[[I" would be "int[][]", "[Ljava/lang/String;" would be
-// "java.lang.String[]", and so forth.
-void AppendPrettyDescriptor(const char* descriptor, std::string* result);
-std::string PrettyDescriptor(const char* descriptor);
-std::string PrettyDescriptor(Primitive::Type type);
-
-// Performs JNI name mangling as described in section 11.3 "Linking Native Methods"
-// of the JNI spec.
-std::string MangleForJni(const std::string& s);
-
-std::string GetJniShortName(const std::string& class_name, const std::string& method_name);
-
-// Turn "java.lang.String" into "Ljava/lang/String;".
-std::string DotToDescriptor(const char* class_name);
-
-// Turn "Ljava/lang/String;" into "java.lang.String" using the conventions of
-// java.lang.Class.getName().
-std::string DescriptorToDot(const char* descriptor);
-
-// Turn "Ljava/lang/String;" into "java/lang/String" using the opposite conventions of
-// java.lang.Class.getName().
-std::string DescriptorToName(const char* descriptor);
-
-// Tests for whether 's' is a valid class name in the three common forms:
-bool IsValidBinaryClassName(const char* s); // "java.lang.String"
-bool IsValidJniClassName(const char* s); // "java/lang/String"
-bool IsValidDescriptor(const char* s); // "Ljava/lang/String;"
-
-// Returns whether the given string is a valid field or method name,
-// additionally allowing names that begin with '<' and end with '>'.
-bool IsValidMemberName(const char* s);
-
-} // namespace art
-
-#endif // ART_RUNTIME_DEX_DESCRIPTORS_NAMES_H_
diff --git a/runtime/dex/dex_file-inl.h b/runtime/dex/dex_file-inl.h
deleted file mode 100644
index aa53daac35..0000000000
--- a/runtime/dex/dex_file-inl.h
+++ /dev/null
@@ -1,521 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ART_RUNTIME_DEX_DEX_FILE_INL_H_
-#define ART_RUNTIME_DEX_DEX_FILE_INL_H_
-
-#include "base/bit_utils.h"
-#include "base/casts.h"
-#include "base/stringpiece.h"
-#include "compact_dex_file.h"
-#include "dex_file.h"
-#include "invoke_type.h"
-#include "leb128.h"
-#include "standard_dex_file.h"
-
-namespace art {
-
-inline int32_t DexFile::GetStringLength(const StringId& string_id) const {
- const uint8_t* ptr = DataBegin() + string_id.string_data_off_;
- return DecodeUnsignedLeb128(&ptr);
-}
-
-inline const char* DexFile::GetStringDataAndUtf16Length(const StringId& string_id,
- uint32_t* utf16_length) const {
- DCHECK(utf16_length != nullptr) << GetLocation();
- const uint8_t* ptr = DataBegin() + string_id.string_data_off_;
- *utf16_length = DecodeUnsignedLeb128(&ptr);
- return reinterpret_cast<const char*>(ptr);
-}
-
-inline const char* DexFile::GetStringData(const StringId& string_id) const {
- uint32_t ignored;
- return GetStringDataAndUtf16Length(string_id, &ignored);
-}
-
-inline const char* DexFile::StringDataAndUtf16LengthByIdx(dex::StringIndex idx,
- uint32_t* utf16_length) const {
- if (!idx.IsValid()) {
- *utf16_length = 0;
- return nullptr;
- }
- const StringId& string_id = GetStringId(idx);
- return GetStringDataAndUtf16Length(string_id, utf16_length);
-}
-
-inline const char* DexFile::StringDataByIdx(dex::StringIndex idx) const {
- uint32_t unicode_length;
- return StringDataAndUtf16LengthByIdx(idx, &unicode_length);
-}
-
-inline const char* DexFile::StringByTypeIdx(dex::TypeIndex idx, uint32_t* unicode_length) const {
- if (!idx.IsValid()) {
- return nullptr;
- }
- const TypeId& type_id = GetTypeId(idx);
- return StringDataAndUtf16LengthByIdx(type_id.descriptor_idx_, unicode_length);
-}
-
-inline const char* DexFile::StringByTypeIdx(dex::TypeIndex idx) const {
- if (!idx.IsValid()) {
- return nullptr;
- }
- const TypeId& type_id = GetTypeId(idx);
- return StringDataByIdx(type_id.descriptor_idx_);
-}
-
-inline const char* DexFile::GetTypeDescriptor(const TypeId& type_id) const {
- return StringDataByIdx(type_id.descriptor_idx_);
-}
-
-inline const char* DexFile::GetFieldTypeDescriptor(const FieldId& field_id) const {
- const DexFile::TypeId& type_id = GetTypeId(field_id.type_idx_);
- return GetTypeDescriptor(type_id);
-}
-
-inline const char* DexFile::GetFieldName(const FieldId& field_id) const {
- return StringDataByIdx(field_id.name_idx_);
-}
-
-inline const char* DexFile::GetMethodDeclaringClassDescriptor(const MethodId& method_id) const {
- const DexFile::TypeId& type_id = GetTypeId(method_id.class_idx_);
- return GetTypeDescriptor(type_id);
-}
-
-inline const Signature DexFile::GetMethodSignature(const MethodId& method_id) const {
- return Signature(this, GetProtoId(method_id.proto_idx_));
-}
-
-inline const Signature DexFile::GetProtoSignature(const ProtoId& proto_id) const {
- return Signature(this, proto_id);
-}
-
-inline const char* DexFile::GetMethodName(const MethodId& method_id) const {
- return StringDataByIdx(method_id.name_idx_);
-}
-
-inline const char* DexFile::GetMethodShorty(uint32_t idx) const {
- return StringDataByIdx(GetProtoId(GetMethodId(idx).proto_idx_).shorty_idx_);
-}
-
-inline const char* DexFile::GetMethodShorty(const MethodId& method_id) const {
- return StringDataByIdx(GetProtoId(method_id.proto_idx_).shorty_idx_);
-}
-
-inline const char* DexFile::GetMethodShorty(const MethodId& method_id, uint32_t* length) const {
- // Using the UTF16 length is safe here as shorties are guaranteed to be ASCII characters.
- return StringDataAndUtf16LengthByIdx(GetProtoId(method_id.proto_idx_).shorty_idx_, length);
-}
-
-inline const char* DexFile::GetClassDescriptor(const ClassDef& class_def) const {
- return StringByTypeIdx(class_def.class_idx_);
-}
-
-inline const char* DexFile::GetReturnTypeDescriptor(const ProtoId& proto_id) const {
- return StringByTypeIdx(proto_id.return_type_idx_);
-}
-
-inline const char* DexFile::GetShorty(uint32_t proto_idx) const {
- const ProtoId& proto_id = GetProtoId(proto_idx);
- return StringDataByIdx(proto_id.shorty_idx_);
-}
-
-inline const DexFile::TryItem* DexFile::GetTryItems(const DexInstructionIterator& code_item_end,
- uint32_t offset) {
- return reinterpret_cast<const TryItem*>
- (RoundUp(reinterpret_cast<uintptr_t>(&code_item_end.Inst()), TryItem::kAlignment)) + offset;
-}
-
-static inline bool DexFileStringEquals(const DexFile* df1, dex::StringIndex sidx1,
- const DexFile* df2, dex::StringIndex sidx2) {
- uint32_t s1_len; // Note: utf16 length != mutf8 length.
- const char* s1_data = df1->StringDataAndUtf16LengthByIdx(sidx1, &s1_len);
- uint32_t s2_len;
- const char* s2_data = df2->StringDataAndUtf16LengthByIdx(sidx2, &s2_len);
- return (s1_len == s2_len) && (strcmp(s1_data, s2_data) == 0);
-}
-
-inline bool Signature::operator==(const Signature& rhs) const {
- if (dex_file_ == nullptr) {
- return rhs.dex_file_ == nullptr;
- }
- if (rhs.dex_file_ == nullptr) {
- return false;
- }
- if (dex_file_ == rhs.dex_file_) {
- return proto_id_ == rhs.proto_id_;
- }
- uint32_t lhs_shorty_len; // For a shorty utf16 length == mutf8 length.
- const char* lhs_shorty_data = dex_file_->StringDataAndUtf16LengthByIdx(proto_id_->shorty_idx_,
- &lhs_shorty_len);
- StringPiece lhs_shorty(lhs_shorty_data, lhs_shorty_len);
- {
- uint32_t rhs_shorty_len;
- const char* rhs_shorty_data =
- rhs.dex_file_->StringDataAndUtf16LengthByIdx(rhs.proto_id_->shorty_idx_,
- &rhs_shorty_len);
- StringPiece rhs_shorty(rhs_shorty_data, rhs_shorty_len);
- if (lhs_shorty != rhs_shorty) {
- return false; // Shorty mismatch.
- }
- }
- if (lhs_shorty[0] == 'L') {
- const DexFile::TypeId& return_type_id = dex_file_->GetTypeId(proto_id_->return_type_idx_);
- const DexFile::TypeId& rhs_return_type_id =
- rhs.dex_file_->GetTypeId(rhs.proto_id_->return_type_idx_);
- if (!DexFileStringEquals(dex_file_, return_type_id.descriptor_idx_,
- rhs.dex_file_, rhs_return_type_id.descriptor_idx_)) {
- return false; // Return type mismatch.
- }
- }
- if (lhs_shorty.find('L', 1) != StringPiece::npos) {
- const DexFile::TypeList* params = dex_file_->GetProtoParameters(*proto_id_);
- const DexFile::TypeList* rhs_params = rhs.dex_file_->GetProtoParameters(*rhs.proto_id_);
- // We found a reference parameter in the matching shorty, so both lists must be non-empty.
- DCHECK(params != nullptr);
- DCHECK(rhs_params != nullptr);
- uint32_t params_size = params->Size();
- DCHECK_EQ(params_size, rhs_params->Size()); // Parameter list size must match.
- for (uint32_t i = 0; i < params_size; ++i) {
- const DexFile::TypeId& param_id = dex_file_->GetTypeId(params->GetTypeItem(i).type_idx_);
- const DexFile::TypeId& rhs_param_id =
- rhs.dex_file_->GetTypeId(rhs_params->GetTypeItem(i).type_idx_);
- if (!DexFileStringEquals(dex_file_, param_id.descriptor_idx_,
- rhs.dex_file_, rhs_param_id.descriptor_idx_)) {
- return false; // Parameter type mismatch.
- }
- }
- }
- return true;
-}
-
-inline
-InvokeType ClassDataItemIterator::GetMethodInvokeType(const DexFile::ClassDef& class_def) const {
- if (HasNextDirectMethod()) {
- if ((GetRawMemberAccessFlags() & kAccStatic) != 0) {
- return kStatic;
- } else {
- return kDirect;
- }
- } else {
- DCHECK_EQ(GetRawMemberAccessFlags() & kAccStatic, 0U);
- if ((class_def.access_flags_ & kAccInterface) != 0) {
- return kInterface;
- } else if ((GetRawMemberAccessFlags() & kAccConstructor) != 0) {
- return kSuper;
- } else {
- return kVirtual;
- }
- }
-}
-
-template<typename NewLocalCallback, typename IndexToStringData, typename TypeIndexToStringData>
-bool DexFile::DecodeDebugLocalInfo(const uint8_t* stream,
- const std::string& location,
- const char* declaring_class_descriptor,
- const std::vector<const char*>& arg_descriptors,
- const std::string& method_name,
- bool is_static,
- uint16_t registers_size,
- uint16_t ins_size,
- uint16_t insns_size_in_code_units,
- IndexToStringData index_to_string_data,
- TypeIndexToStringData type_index_to_string_data,
- NewLocalCallback new_local_callback,
- void* context) {
- if (stream == nullptr) {
- return false;
- }
- std::vector<LocalInfo> local_in_reg(registers_size);
-
- uint16_t arg_reg = registers_size - ins_size;
- if (!is_static) {
- const char* descriptor = declaring_class_descriptor;
- local_in_reg[arg_reg].name_ = "this";
- local_in_reg[arg_reg].descriptor_ = descriptor;
- local_in_reg[arg_reg].signature_ = nullptr;
- local_in_reg[arg_reg].start_address_ = 0;
- local_in_reg[arg_reg].reg_ = arg_reg;
- local_in_reg[arg_reg].is_live_ = true;
- arg_reg++;
- }
-
- DecodeUnsignedLeb128(&stream); // Line.
- uint32_t parameters_size = DecodeUnsignedLeb128(&stream);
- uint32_t i;
- if (parameters_size != arg_descriptors.size()) {
- LOG(ERROR) << "invalid stream - problem with parameter iterator in " << location
- << " for method " << method_name;
- return false;
- }
- for (i = 0; i < parameters_size && i < arg_descriptors.size(); ++i) {
- if (arg_reg >= registers_size) {
- LOG(ERROR) << "invalid stream - arg reg >= reg size (" << arg_reg
- << " >= " << registers_size << ") in " << location;
- return false;
- }
- uint32_t name_idx = DecodeUnsignedLeb128P1(&stream);
- const char* descriptor = arg_descriptors[i];
- local_in_reg[arg_reg].name_ = index_to_string_data(name_idx);
- local_in_reg[arg_reg].descriptor_ = descriptor;
- local_in_reg[arg_reg].signature_ = nullptr;
- local_in_reg[arg_reg].start_address_ = 0;
- local_in_reg[arg_reg].reg_ = arg_reg;
- local_in_reg[arg_reg].is_live_ = true;
- switch (*descriptor) {
- case 'D':
- case 'J':
- arg_reg += 2;
- break;
- default:
- arg_reg += 1;
- break;
- }
- }
-
- uint32_t address = 0;
- for (;;) {
- uint8_t opcode = *stream++;
- switch (opcode) {
- case DBG_END_SEQUENCE:
- // Emit all variables which are still alive at the end of the method.
- for (uint16_t reg = 0; reg < registers_size; reg++) {
- if (local_in_reg[reg].is_live_) {
- local_in_reg[reg].end_address_ = insns_size_in_code_units;
- new_local_callback(context, local_in_reg[reg]);
- }
- }
- return true;
- case DBG_ADVANCE_PC:
- address += DecodeUnsignedLeb128(&stream);
- break;
- case DBG_ADVANCE_LINE:
- DecodeSignedLeb128(&stream); // Line.
- break;
- case DBG_START_LOCAL:
- case DBG_START_LOCAL_EXTENDED: {
- uint16_t reg = DecodeUnsignedLeb128(&stream);
- if (reg >= registers_size) {
- LOG(ERROR) << "invalid stream - reg >= reg size (" << reg << " >= "
- << registers_size << ") in " << location;
- return false;
- }
-
- uint32_t name_idx = DecodeUnsignedLeb128P1(&stream);
- uint16_t descriptor_idx = DecodeUnsignedLeb128P1(&stream);
- uint32_t signature_idx = dex::kDexNoIndex;
- if (opcode == DBG_START_LOCAL_EXTENDED) {
- signature_idx = DecodeUnsignedLeb128P1(&stream);
- }
-
- // Emit what was previously there, if anything
- if (local_in_reg[reg].is_live_) {
- local_in_reg[reg].end_address_ = address;
- new_local_callback(context, local_in_reg[reg]);
- }
-
- local_in_reg[reg].name_ = index_to_string_data(name_idx);
- local_in_reg[reg].descriptor_ = type_index_to_string_data(descriptor_idx);;
- local_in_reg[reg].signature_ = index_to_string_data(signature_idx);
- local_in_reg[reg].start_address_ = address;
- local_in_reg[reg].reg_ = reg;
- local_in_reg[reg].is_live_ = true;
- break;
- }
- case DBG_END_LOCAL: {
- uint16_t reg = DecodeUnsignedLeb128(&stream);
- if (reg >= registers_size) {
- LOG(ERROR) << "invalid stream - reg >= reg size (" << reg << " >= "
- << registers_size << ") in " << location;
- return false;
- }
- // If the register is live, close it properly. Otherwise, closing an already
- // closed register is sloppy, but harmless if no further action is taken.
- if (local_in_reg[reg].is_live_) {
- local_in_reg[reg].end_address_ = address;
- new_local_callback(context, local_in_reg[reg]);
- local_in_reg[reg].is_live_ = false;
- }
- break;
- }
- case DBG_RESTART_LOCAL: {
- uint16_t reg = DecodeUnsignedLeb128(&stream);
- if (reg >= registers_size) {
- LOG(ERROR) << "invalid stream - reg >= reg size (" << reg << " >= "
- << registers_size << ") in " << location;
- return false;
- }
- // If the register is live, the "restart" is superfluous,
- // and we don't want to mess with the existing start address.
- if (!local_in_reg[reg].is_live_) {
- local_in_reg[reg].start_address_ = address;
- local_in_reg[reg].is_live_ = true;
- }
- break;
- }
- case DBG_SET_PROLOGUE_END:
- case DBG_SET_EPILOGUE_BEGIN:
- break;
- case DBG_SET_FILE:
- DecodeUnsignedLeb128P1(&stream); // name.
- break;
- default:
- address += (opcode - DBG_FIRST_SPECIAL) / DBG_LINE_RANGE;
- break;
- }
- }
-}
-
-template<typename NewLocalCallback>
-bool DexFile::DecodeDebugLocalInfo(uint32_t registers_size,
- uint32_t ins_size,
- uint32_t insns_size_in_code_units,
- uint32_t debug_info_offset,
- bool is_static,
- uint32_t method_idx,
- NewLocalCallback new_local_callback,
- void* context) const {
- const uint8_t* const stream = GetDebugInfoStream(debug_info_offset);
- if (stream == nullptr) {
- return false;
- }
- std::vector<const char*> arg_descriptors;
- DexFileParameterIterator it(*this, GetMethodPrototype(GetMethodId(method_idx)));
- for (; it.HasNext(); it.Next()) {
- arg_descriptors.push_back(it.GetDescriptor());
- }
- return DecodeDebugLocalInfo(stream,
- GetLocation(),
- GetMethodDeclaringClassDescriptor(GetMethodId(method_idx)),
- arg_descriptors,
- this->PrettyMethod(method_idx),
- is_static,
- registers_size,
- ins_size,
- insns_size_in_code_units,
- [this](uint32_t idx) {
- return StringDataByIdx(dex::StringIndex(idx));
- },
- [this](uint32_t idx) {
- return StringByTypeIdx(dex::TypeIndex(
- dchecked_integral_cast<uint16_t>(idx)));
- },
- new_local_callback,
- context);
-}
-
-template<typename DexDebugNewPosition, typename IndexToStringData>
-bool DexFile::DecodeDebugPositionInfo(const uint8_t* stream,
- IndexToStringData index_to_string_data,
- DexDebugNewPosition position_functor,
- void* context) {
- if (stream == nullptr) {
- return false;
- }
-
- PositionInfo entry = PositionInfo();
- entry.line_ = DecodeUnsignedLeb128(&stream);
- uint32_t parameters_size = DecodeUnsignedLeb128(&stream);
- for (uint32_t i = 0; i < parameters_size; ++i) {
- DecodeUnsignedLeb128P1(&stream); // Parameter name.
- }
-
- for (;;) {
- uint8_t opcode = *stream++;
- switch (opcode) {
- case DBG_END_SEQUENCE:
- return true; // end of stream.
- case DBG_ADVANCE_PC:
- entry.address_ += DecodeUnsignedLeb128(&stream);
- break;
- case DBG_ADVANCE_LINE:
- entry.line_ += DecodeSignedLeb128(&stream);
- break;
- case DBG_START_LOCAL:
- DecodeUnsignedLeb128(&stream); // reg.
- DecodeUnsignedLeb128P1(&stream); // name.
- DecodeUnsignedLeb128P1(&stream); // descriptor.
- break;
- case DBG_START_LOCAL_EXTENDED:
- DecodeUnsignedLeb128(&stream); // reg.
- DecodeUnsignedLeb128P1(&stream); // name.
- DecodeUnsignedLeb128P1(&stream); // descriptor.
- DecodeUnsignedLeb128P1(&stream); // signature.
- break;
- case DBG_END_LOCAL:
- case DBG_RESTART_LOCAL:
- DecodeUnsignedLeb128(&stream); // reg.
- break;
- case DBG_SET_PROLOGUE_END:
- entry.prologue_end_ = true;
- break;
- case DBG_SET_EPILOGUE_BEGIN:
- entry.epilogue_begin_ = true;
- break;
- case DBG_SET_FILE: {
- uint32_t name_idx = DecodeUnsignedLeb128P1(&stream);
- entry.source_file_ = index_to_string_data(name_idx);
- break;
- }
- default: {
- int adjopcode = opcode - DBG_FIRST_SPECIAL;
- entry.address_ += adjopcode / DBG_LINE_RANGE;
- entry.line_ += DBG_LINE_BASE + (adjopcode % DBG_LINE_RANGE);
- if (position_functor(context, entry)) {
- return true; // early exit.
- }
- entry.prologue_end_ = false;
- entry.epilogue_begin_ = false;
- break;
- }
- }
- }
-}
-
-template<typename DexDebugNewPosition>
-bool DexFile::DecodeDebugPositionInfo(uint32_t debug_info_offset,
- DexDebugNewPosition position_functor,
- void* context) const {
- return DecodeDebugPositionInfo(GetDebugInfoStream(debug_info_offset),
- [this](uint32_t idx) {
- return StringDataByIdx(dex::StringIndex(idx));
- },
- position_functor,
- context);
-}
-
-inline const CompactDexFile* DexFile::AsCompactDexFile() const {
- DCHECK(IsCompactDexFile());
- return down_cast<const CompactDexFile*>(this);
-}
-
-inline const StandardDexFile* DexFile::AsStandardDexFile() const {
- DCHECK(IsStandardDexFile());
- return down_cast<const StandardDexFile*>(this);
-}
-
-// Get the base of the encoded data for the given DexCode.
-inline const uint8_t* DexFile::GetCatchHandlerData(const DexInstructionIterator& code_item_end,
- uint32_t tries_size,
- uint32_t offset) {
- const uint8_t* handler_data =
- reinterpret_cast<const uint8_t*>(GetTryItems(code_item_end, tries_size));
- return handler_data + offset;
-}
-
-} // namespace art
-
-#endif // ART_RUNTIME_DEX_DEX_FILE_INL_H_
diff --git a/runtime/dex/dex_file.cc b/runtime/dex/dex_file.cc
deleted file mode 100644
index 18eb903551..0000000000
--- a/runtime/dex/dex_file.cc
+++ /dev/null
@@ -1,795 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "dex_file.h"
-
-#include <limits.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <zlib.h>
-
-#include <memory>
-#include <sstream>
-#include <type_traits>
-
-#include "android-base/stringprintf.h"
-
-#include "base/enums.h"
-#include "base/stl_util.h"
-#include "descriptors_names.h"
-#include "dex_file-inl.h"
-#include "leb128.h"
-#include "standard_dex_file.h"
-#include "utf-inl.h"
-
-namespace art {
-
-using android::base::StringPrintf;
-
-static_assert(sizeof(dex::StringIndex) == sizeof(uint32_t), "StringIndex size is wrong");
-static_assert(std::is_trivially_copyable<dex::StringIndex>::value, "StringIndex not trivial");
-static_assert(sizeof(dex::TypeIndex) == sizeof(uint16_t), "TypeIndex size is wrong");
-static_assert(std::is_trivially_copyable<dex::TypeIndex>::value, "TypeIndex not trivial");
-
-uint32_t DexFile::CalculateChecksum() const {
- return CalculateChecksum(Begin(), Size());
-}
-
-uint32_t DexFile::CalculateChecksum(const uint8_t* begin, size_t size) {
- const uint32_t non_sum_bytes = OFFSETOF_MEMBER(DexFile::Header, signature_);
- return ChecksumMemoryRange(begin + non_sum_bytes, size - non_sum_bytes);
-}
-
-uint32_t DexFile::ChecksumMemoryRange(const uint8_t* begin, size_t size) {
- return adler32(adler32(0L, Z_NULL, 0), begin, size);
-}
-
-int DexFile::GetPermissions() const {
- CHECK(container_.get() != nullptr);
- return container_->GetPermissions();
-}
-
-bool DexFile::IsReadOnly() const {
- CHECK(container_.get() != nullptr);
- return container_->IsReadOnly();
-}
-
-bool DexFile::EnableWrite() const {
- CHECK(container_.get() != nullptr);
- return container_->EnableWrite();
-}
-
-bool DexFile::DisableWrite() const {
- CHECK(container_.get() != nullptr);
- return container_->DisableWrite();
-}
-
-DexFile::DexFile(const uint8_t* base,
- size_t size,
- const uint8_t* data_begin,
- size_t data_size,
- const std::string& location,
- uint32_t location_checksum,
- const OatDexFile* oat_dex_file,
- DexFileContainer* container,
- bool is_compact_dex)
- : begin_(base),
- size_(size),
- data_begin_(data_begin),
- data_size_(data_size),
- location_(location),
- location_checksum_(location_checksum),
- header_(reinterpret_cast<const Header*>(base)),
- string_ids_(reinterpret_cast<const StringId*>(base + header_->string_ids_off_)),
- type_ids_(reinterpret_cast<const TypeId*>(base + header_->type_ids_off_)),
- field_ids_(reinterpret_cast<const FieldId*>(base + header_->field_ids_off_)),
- method_ids_(reinterpret_cast<const MethodId*>(base + header_->method_ids_off_)),
- proto_ids_(reinterpret_cast<const ProtoId*>(base + header_->proto_ids_off_)),
- class_defs_(reinterpret_cast<const ClassDef*>(base + header_->class_defs_off_)),
- method_handles_(nullptr),
- num_method_handles_(0),
- call_site_ids_(nullptr),
- num_call_site_ids_(0),
- oat_dex_file_(oat_dex_file),
- container_(container),
- is_compact_dex_(is_compact_dex) {
- CHECK(begin_ != nullptr) << GetLocation();
- CHECK_GT(size_, 0U) << GetLocation();
- // Check base (=header) alignment.
- // Must be 4-byte aligned to avoid undefined behavior when accessing
- // any of the sections via a pointer.
- CHECK_ALIGNED(begin_, alignof(Header));
-
- InitializeSectionsFromMapList();
-}
-
-DexFile::~DexFile() {
- // We don't call DeleteGlobalRef on dex_object_ because we're only called by DestroyJavaVM, and
- // that's only called after DetachCurrentThread, which means there's no JNIEnv. We could
- // re-attach, but cleaning up these global references is not obviously useful. It's not as if
- // the global reference table is otherwise empty!
-}
-
-bool DexFile::Init(std::string* error_msg) {
- if (!CheckMagicAndVersion(error_msg)) {
- return false;
- }
- return true;
-}
-
-bool DexFile::CheckMagicAndVersion(std::string* error_msg) const {
- if (!IsMagicValid()) {
- std::ostringstream oss;
- oss << "Unrecognized magic number in " << GetLocation() << ":"
- << " " << header_->magic_[0]
- << " " << header_->magic_[1]
- << " " << header_->magic_[2]
- << " " << header_->magic_[3];
- *error_msg = oss.str();
- return false;
- }
- if (!IsVersionValid()) {
- std::ostringstream oss;
- oss << "Unrecognized version number in " << GetLocation() << ":"
- << " " << header_->magic_[4]
- << " " << header_->magic_[5]
- << " " << header_->magic_[6]
- << " " << header_->magic_[7];
- *error_msg = oss.str();
- return false;
- }
- return true;
-}
-
-void DexFile::InitializeSectionsFromMapList() {
- const MapList* map_list = reinterpret_cast<const MapList*>(DataBegin() + header_->map_off_);
- if (header_->map_off_ == 0 || header_->map_off_ > DataSize()) {
- // Bad offset. The dex file verifier runs after this method and will reject the file.
- return;
- }
- const size_t count = map_list->size_;
-
- size_t map_limit = header_->map_off_ + count * sizeof(MapItem);
- if (header_->map_off_ >= map_limit || map_limit > DataSize()) {
- // Overflow or out out of bounds. The dex file verifier runs after
- // this method and will reject the file as it is malformed.
- return;
- }
-
- for (size_t i = 0; i < count; ++i) {
- const MapItem& map_item = map_list->list_[i];
- if (map_item.type_ == kDexTypeMethodHandleItem) {
- method_handles_ = reinterpret_cast<const MethodHandleItem*>(Begin() + map_item.offset_);
- num_method_handles_ = map_item.size_;
- } else if (map_item.type_ == kDexTypeCallSiteIdItem) {
- call_site_ids_ = reinterpret_cast<const CallSiteIdItem*>(Begin() + map_item.offset_);
- num_call_site_ids_ = map_item.size_;
- }
- }
-}
-
-uint32_t DexFile::Header::GetVersion() const {
- const char* version = reinterpret_cast<const char*>(&magic_[kDexMagicSize]);
- return atoi(version);
-}
-
-const DexFile::ClassDef* DexFile::FindClassDef(dex::TypeIndex type_idx) const {
- size_t num_class_defs = NumClassDefs();
- // Fast path for rare no class defs case.
- if (num_class_defs == 0) {
- return nullptr;
- }
- for (size_t i = 0; i < num_class_defs; ++i) {
- const ClassDef& class_def = GetClassDef(i);
- if (class_def.class_idx_ == type_idx) {
- return &class_def;
- }
- }
- return nullptr;
-}
-
-uint32_t DexFile::FindCodeItemOffset(const DexFile::ClassDef& class_def,
- uint32_t method_idx) const {
- const uint8_t* class_data = GetClassData(class_def);
- CHECK(class_data != nullptr);
- ClassDataItemIterator it(*this, class_data);
- it.SkipAllFields();
- while (it.HasNextDirectMethod()) {
- if (it.GetMemberIndex() == method_idx) {
- return it.GetMethodCodeItemOffset();
- }
- it.Next();
- }
- while (it.HasNextVirtualMethod()) {
- if (it.GetMemberIndex() == method_idx) {
- return it.GetMethodCodeItemOffset();
- }
- it.Next();
- }
- LOG(FATAL) << "Unable to find method " << method_idx;
- UNREACHABLE();
-}
-
-const DexFile::FieldId* DexFile::FindFieldId(const DexFile::TypeId& declaring_klass,
- const DexFile::StringId& name,
- const DexFile::TypeId& type) const {
- // Binary search MethodIds knowing that they are sorted by class_idx, name_idx then proto_idx
- const dex::TypeIndex class_idx = GetIndexForTypeId(declaring_klass);
- const dex::StringIndex name_idx = GetIndexForStringId(name);
- const dex::TypeIndex type_idx = GetIndexForTypeId(type);
- int32_t lo = 0;
- int32_t hi = NumFieldIds() - 1;
- while (hi >= lo) {
- int32_t mid = (hi + lo) / 2;
- const DexFile::FieldId& field = GetFieldId(mid);
- if (class_idx > field.class_idx_) {
- lo = mid + 1;
- } else if (class_idx < field.class_idx_) {
- hi = mid - 1;
- } else {
- if (name_idx > field.name_idx_) {
- lo = mid + 1;
- } else if (name_idx < field.name_idx_) {
- hi = mid - 1;
- } else {
- if (type_idx > field.type_idx_) {
- lo = mid + 1;
- } else if (type_idx < field.type_idx_) {
- hi = mid - 1;
- } else {
- return &field;
- }
- }
- }
- }
- return nullptr;
-}
-
-const DexFile::MethodId* DexFile::FindMethodId(const DexFile::TypeId& declaring_klass,
- const DexFile::StringId& name,
- const DexFile::ProtoId& signature) const {
- // Binary search MethodIds knowing that they are sorted by class_idx, name_idx then proto_idx
- const dex::TypeIndex class_idx = GetIndexForTypeId(declaring_klass);
- const dex::StringIndex name_idx = GetIndexForStringId(name);
- const uint16_t proto_idx = GetIndexForProtoId(signature);
- int32_t lo = 0;
- int32_t hi = NumMethodIds() - 1;
- while (hi >= lo) {
- int32_t mid = (hi + lo) / 2;
- const DexFile::MethodId& method = GetMethodId(mid);
- if (class_idx > method.class_idx_) {
- lo = mid + 1;
- } else if (class_idx < method.class_idx_) {
- hi = mid - 1;
- } else {
- if (name_idx > method.name_idx_) {
- lo = mid + 1;
- } else if (name_idx < method.name_idx_) {
- hi = mid - 1;
- } else {
- if (proto_idx > method.proto_idx_) {
- lo = mid + 1;
- } else if (proto_idx < method.proto_idx_) {
- hi = mid - 1;
- } else {
- return &method;
- }
- }
- }
- }
- return nullptr;
-}
-
-const DexFile::StringId* DexFile::FindStringId(const char* string) const {
- int32_t lo = 0;
- int32_t hi = NumStringIds() - 1;
- while (hi >= lo) {
- int32_t mid = (hi + lo) / 2;
- const DexFile::StringId& str_id = GetStringId(dex::StringIndex(mid));
- const char* str = GetStringData(str_id);
- int compare = CompareModifiedUtf8ToModifiedUtf8AsUtf16CodePointValues(string, str);
- if (compare > 0) {
- lo = mid + 1;
- } else if (compare < 0) {
- hi = mid - 1;
- } else {
- return &str_id;
- }
- }
- return nullptr;
-}
-
-const DexFile::TypeId* DexFile::FindTypeId(const char* string) const {
- int32_t lo = 0;
- int32_t hi = NumTypeIds() - 1;
- while (hi >= lo) {
- int32_t mid = (hi + lo) / 2;
- const TypeId& type_id = GetTypeId(dex::TypeIndex(mid));
- const DexFile::StringId& str_id = GetStringId(type_id.descriptor_idx_);
- const char* str = GetStringData(str_id);
- int compare = CompareModifiedUtf8ToModifiedUtf8AsUtf16CodePointValues(string, str);
- if (compare > 0) {
- lo = mid + 1;
- } else if (compare < 0) {
- hi = mid - 1;
- } else {
- return &type_id;
- }
- }
- return nullptr;
-}
-
-const DexFile::StringId* DexFile::FindStringId(const uint16_t* string, size_t length) const {
- int32_t lo = 0;
- int32_t hi = NumStringIds() - 1;
- while (hi >= lo) {
- int32_t mid = (hi + lo) / 2;
- const DexFile::StringId& str_id = GetStringId(dex::StringIndex(mid));
- const char* str = GetStringData(str_id);
- int compare = CompareModifiedUtf8ToUtf16AsCodePointValues(str, string, length);
- if (compare > 0) {
- lo = mid + 1;
- } else if (compare < 0) {
- hi = mid - 1;
- } else {
- return &str_id;
- }
- }
- return nullptr;
-}
-
-const DexFile::TypeId* DexFile::FindTypeId(dex::StringIndex string_idx) const {
- int32_t lo = 0;
- int32_t hi = NumTypeIds() - 1;
- while (hi >= lo) {
- int32_t mid = (hi + lo) / 2;
- const TypeId& type_id = GetTypeId(dex::TypeIndex(mid));
- if (string_idx > type_id.descriptor_idx_) {
- lo = mid + 1;
- } else if (string_idx < type_id.descriptor_idx_) {
- hi = mid - 1;
- } else {
- return &type_id;
- }
- }
- return nullptr;
-}
-
-const DexFile::ProtoId* DexFile::FindProtoId(dex::TypeIndex return_type_idx,
- const dex::TypeIndex* signature_type_idxs,
- uint32_t signature_length) const {
- int32_t lo = 0;
- int32_t hi = NumProtoIds() - 1;
- while (hi >= lo) {
- int32_t mid = (hi + lo) / 2;
- const DexFile::ProtoId& proto = GetProtoId(mid);
- int compare = return_type_idx.index_ - proto.return_type_idx_.index_;
- if (compare == 0) {
- DexFileParameterIterator it(*this, proto);
- size_t i = 0;
- while (it.HasNext() && i < signature_length && compare == 0) {
- compare = signature_type_idxs[i].index_ - it.GetTypeIdx().index_;
- it.Next();
- i++;
- }
- if (compare == 0) {
- if (it.HasNext()) {
- compare = -1;
- } else if (i < signature_length) {
- compare = 1;
- }
- }
- }
- if (compare > 0) {
- lo = mid + 1;
- } else if (compare < 0) {
- hi = mid - 1;
- } else {
- return &proto;
- }
- }
- return nullptr;
-}
-
-// Given a signature place the type ids into the given vector
-bool DexFile::CreateTypeList(const StringPiece& signature,
- dex::TypeIndex* return_type_idx,
- std::vector<dex::TypeIndex>* param_type_idxs) const {
- if (signature[0] != '(') {
- return false;
- }
- size_t offset = 1;
- size_t end = signature.size();
- bool process_return = false;
- while (offset < end) {
- size_t start_offset = offset;
- char c = signature[offset];
- offset++;
- if (c == ')') {
- process_return = true;
- continue;
- }
- while (c == '[') { // process array prefix
- if (offset >= end) { // expect some descriptor following [
- return false;
- }
- c = signature[offset];
- offset++;
- }
- if (c == 'L') { // process type descriptors
- do {
- if (offset >= end) { // unexpected early termination of descriptor
- return false;
- }
- c = signature[offset];
- offset++;
- } while (c != ';');
- }
- // TODO: avoid creating a std::string just to get a 0-terminated char array
- std::string descriptor(signature.data() + start_offset, offset - start_offset);
- const DexFile::TypeId* type_id = FindTypeId(descriptor.c_str());
- if (type_id == nullptr) {
- return false;
- }
- dex::TypeIndex type_idx = GetIndexForTypeId(*type_id);
- if (!process_return) {
- param_type_idxs->push_back(type_idx);
- } else {
- *return_type_idx = type_idx;
- return offset == end; // return true if the signature had reached a sensible end
- }
- }
- return false; // failed to correctly parse return type
-}
-
-const Signature DexFile::CreateSignature(const StringPiece& signature) const {
- dex::TypeIndex return_type_idx;
- std::vector<dex::TypeIndex> param_type_indices;
- bool success = CreateTypeList(signature, &return_type_idx, &param_type_indices);
- if (!success) {
- return Signature::NoSignature();
- }
- const ProtoId* proto_id = FindProtoId(return_type_idx, param_type_indices);
- if (proto_id == nullptr) {
- return Signature::NoSignature();
- }
- return Signature(this, *proto_id);
-}
-
-int32_t DexFile::FindTryItem(const TryItem* try_items, uint32_t tries_size, uint32_t address) {
- uint32_t min = 0;
- uint32_t max = tries_size;
- while (min < max) {
- const uint32_t mid = (min + max) / 2;
-
- const art::DexFile::TryItem& ti = try_items[mid];
- const uint32_t start = ti.start_addr_;
- const uint32_t end = start + ti.insn_count_;
-
- if (address < start) {
- max = mid;
- } else if (address >= end) {
- min = mid + 1;
- } else { // We have a winner!
- return mid;
- }
- }
- // No match.
- return -1;
-}
-
-bool DexFile::LineNumForPcCb(void* raw_context, const PositionInfo& entry) {
- LineNumFromPcContext* context = reinterpret_cast<LineNumFromPcContext*>(raw_context);
-
- // We know that this callback will be called in
- // ascending address order, so keep going until we find
- // a match or we've just gone past it.
- if (entry.address_ > context->address_) {
- // The line number from the previous positions callback
- // wil be the final result.
- return true;
- } else {
- context->line_num_ = entry.line_;
- return entry.address_ == context->address_;
- }
-}
-
-// Read a signed integer. "zwidth" is the zero-based byte count.
-int32_t DexFile::ReadSignedInt(const uint8_t* ptr, int zwidth) {
- int32_t val = 0;
- for (int i = zwidth; i >= 0; --i) {
- val = ((uint32_t)val >> 8) | (((int32_t)*ptr++) << 24);
- }
- val >>= (3 - zwidth) * 8;
- return val;
-}
-
-// Read an unsigned integer. "zwidth" is the zero-based byte count,
-// "fill_on_right" indicates which side we want to zero-fill from.
-uint32_t DexFile::ReadUnsignedInt(const uint8_t* ptr, int zwidth, bool fill_on_right) {
- uint32_t val = 0;
- for (int i = zwidth; i >= 0; --i) {
- val = (val >> 8) | (((uint32_t)*ptr++) << 24);
- }
- if (!fill_on_right) {
- val >>= (3 - zwidth) * 8;
- }
- return val;
-}
-
-// Read a signed long. "zwidth" is the zero-based byte count.
-int64_t DexFile::ReadSignedLong(const uint8_t* ptr, int zwidth) {
- int64_t val = 0;
- for (int i = zwidth; i >= 0; --i) {
- val = ((uint64_t)val >> 8) | (((int64_t)*ptr++) << 56);
- }
- val >>= (7 - zwidth) * 8;
- return val;
-}
-
-// Read an unsigned long. "zwidth" is the zero-based byte count,
-// "fill_on_right" indicates which side we want to zero-fill from.
-uint64_t DexFile::ReadUnsignedLong(const uint8_t* ptr, int zwidth, bool fill_on_right) {
- uint64_t val = 0;
- for (int i = zwidth; i >= 0; --i) {
- val = (val >> 8) | (((uint64_t)*ptr++) << 56);
- }
- if (!fill_on_right) {
- val >>= (7 - zwidth) * 8;
- }
- return val;
-}
-
-std::string DexFile::PrettyMethod(uint32_t method_idx, bool with_signature) const {
- if (method_idx >= NumMethodIds()) {
- return StringPrintf("<<invalid-method-idx-%d>>", method_idx);
- }
- const DexFile::MethodId& method_id = GetMethodId(method_idx);
- std::string result;
- const DexFile::ProtoId* proto_id = with_signature ? &GetProtoId(method_id.proto_idx_) : nullptr;
- if (with_signature) {
- AppendPrettyDescriptor(StringByTypeIdx(proto_id->return_type_idx_), &result);
- result += ' ';
- }
- AppendPrettyDescriptor(GetMethodDeclaringClassDescriptor(method_id), &result);
- result += '.';
- result += GetMethodName(method_id);
- if (with_signature) {
- result += '(';
- const DexFile::TypeList* params = GetProtoParameters(*proto_id);
- if (params != nullptr) {
- const char* separator = "";
- for (uint32_t i = 0u, size = params->Size(); i != size; ++i) {
- result += separator;
- separator = ", ";
- AppendPrettyDescriptor(StringByTypeIdx(params->GetTypeItem(i).type_idx_), &result);
- }
- }
- result += ')';
- }
- return result;
-}
-
-std::string DexFile::PrettyField(uint32_t field_idx, bool with_type) const {
- if (field_idx >= NumFieldIds()) {
- return StringPrintf("<<invalid-field-idx-%d>>", field_idx);
- }
- const DexFile::FieldId& field_id = GetFieldId(field_idx);
- std::string result;
- if (with_type) {
- result += GetFieldTypeDescriptor(field_id);
- result += ' ';
- }
- AppendPrettyDescriptor(GetFieldDeclaringClassDescriptor(field_id), &result);
- result += '.';
- result += GetFieldName(field_id);
- return result;
-}
-
-std::string DexFile::PrettyType(dex::TypeIndex type_idx) const {
- if (type_idx.index_ >= NumTypeIds()) {
- return StringPrintf("<<invalid-type-idx-%d>>", type_idx.index_);
- }
- const DexFile::TypeId& type_id = GetTypeId(type_idx);
- return PrettyDescriptor(GetTypeDescriptor(type_id));
-}
-
-// Checks that visibility is as expected. Includes special behavior for M and
-// before to allow runtime and build visibility when expecting runtime.
-std::ostream& operator<<(std::ostream& os, const DexFile& dex_file) {
- os << StringPrintf("[DexFile: %s dex-checksum=%08x location-checksum=%08x %p-%p]",
- dex_file.GetLocation().c_str(),
- dex_file.GetHeader().checksum_, dex_file.GetLocationChecksum(),
- dex_file.Begin(), dex_file.Begin() + dex_file.Size());
- return os;
-}
-
-std::string Signature::ToString() const {
- if (dex_file_ == nullptr) {
- CHECK(proto_id_ == nullptr);
- return "<no signature>";
- }
- const DexFile::TypeList* params = dex_file_->GetProtoParameters(*proto_id_);
- std::string result;
- if (params == nullptr) {
- result += "()";
- } else {
- result += "(";
- for (uint32_t i = 0; i < params->Size(); ++i) {
- result += dex_file_->StringByTypeIdx(params->GetTypeItem(i).type_idx_);
- }
- result += ")";
- }
- result += dex_file_->StringByTypeIdx(proto_id_->return_type_idx_);
- return result;
-}
-
-uint32_t Signature::GetNumberOfParameters() const {
- const DexFile::TypeList* params = dex_file_->GetProtoParameters(*proto_id_);
- return (params != nullptr) ? params->Size() : 0;
-}
-
-bool Signature::IsVoid() const {
- const char* return_type = dex_file_->GetReturnTypeDescriptor(*proto_id_);
- return strcmp(return_type, "V") == 0;
-}
-
-bool Signature::operator==(const StringPiece& rhs) const {
- if (dex_file_ == nullptr) {
- return false;
- }
- StringPiece tail(rhs);
- if (!tail.starts_with("(")) {
- return false; // Invalid signature
- }
- tail.remove_prefix(1); // "(";
- const DexFile::TypeList* params = dex_file_->GetProtoParameters(*proto_id_);
- if (params != nullptr) {
- for (uint32_t i = 0; i < params->Size(); ++i) {
- StringPiece param(dex_file_->StringByTypeIdx(params->GetTypeItem(i).type_idx_));
- if (!tail.starts_with(param)) {
- return false;
- }
- tail.remove_prefix(param.length());
- }
- }
- if (!tail.starts_with(")")) {
- return false;
- }
- tail.remove_prefix(1); // ")";
- return tail == dex_file_->StringByTypeIdx(proto_id_->return_type_idx_);
-}
-
-std::ostream& operator<<(std::ostream& os, const Signature& sig) {
- return os << sig.ToString();
-}
-
-// Decodes the header section from the class data bytes.
-void ClassDataItemIterator::ReadClassDataHeader() {
- CHECK(ptr_pos_ != nullptr);
- header_.static_fields_size_ = DecodeUnsignedLeb128(&ptr_pos_);
- header_.instance_fields_size_ = DecodeUnsignedLeb128(&ptr_pos_);
- header_.direct_methods_size_ = DecodeUnsignedLeb128(&ptr_pos_);
- header_.virtual_methods_size_ = DecodeUnsignedLeb128(&ptr_pos_);
-}
-
-void ClassDataItemIterator::ReadClassDataField() {
- field_.field_idx_delta_ = DecodeUnsignedLeb128(&ptr_pos_);
- field_.access_flags_ = DecodeUnsignedLeb128(&ptr_pos_);
- // The user of the iterator is responsible for checking if there
- // are unordered or duplicate indexes.
-}
-
-void ClassDataItemIterator::ReadClassDataMethod() {
- method_.method_idx_delta_ = DecodeUnsignedLeb128(&ptr_pos_);
- method_.access_flags_ = DecodeUnsignedLeb128(&ptr_pos_);
- method_.code_off_ = DecodeUnsignedLeb128(&ptr_pos_);
- if (last_idx_ != 0 && method_.method_idx_delta_ == 0) {
- LOG(WARNING) << "Duplicate method in " << dex_file_.GetLocation();
- }
-}
-
-EncodedArrayValueIterator::EncodedArrayValueIterator(const DexFile& dex_file,
- const uint8_t* array_data)
- : dex_file_(dex_file),
- array_size_(),
- pos_(-1),
- ptr_(array_data),
- type_(kByte) {
- array_size_ = (ptr_ != nullptr) ? DecodeUnsignedLeb128(&ptr_) : 0;
- if (array_size_ > 0) {
- Next();
- }
-}
-
-void EncodedArrayValueIterator::Next() {
- pos_++;
- if (pos_ >= array_size_) {
- return;
- }
- uint8_t value_type = *ptr_++;
- uint8_t value_arg = value_type >> kEncodedValueArgShift;
- size_t width = value_arg + 1; // assume and correct later
- type_ = static_cast<ValueType>(value_type & kEncodedValueTypeMask);
- switch (type_) {
- case kBoolean:
- jval_.i = (value_arg != 0) ? 1 : 0;
- width = 0;
- break;
- case kByte:
- jval_.i = DexFile::ReadSignedInt(ptr_, value_arg);
- CHECK(IsInt<8>(jval_.i));
- break;
- case kShort:
- jval_.i = DexFile::ReadSignedInt(ptr_, value_arg);
- CHECK(IsInt<16>(jval_.i));
- break;
- case kChar:
- jval_.i = DexFile::ReadUnsignedInt(ptr_, value_arg, false);
- CHECK(IsUint<16>(jval_.i));
- break;
- case kInt:
- jval_.i = DexFile::ReadSignedInt(ptr_, value_arg);
- break;
- case kLong:
- jval_.j = DexFile::ReadSignedLong(ptr_, value_arg);
- break;
- case kFloat:
- jval_.i = DexFile::ReadUnsignedInt(ptr_, value_arg, true);
- break;
- case kDouble:
- jval_.j = DexFile::ReadUnsignedLong(ptr_, value_arg, true);
- break;
- case kString:
- case kType:
- case kMethodType:
- case kMethodHandle:
- jval_.i = DexFile::ReadUnsignedInt(ptr_, value_arg, false);
- break;
- case kField:
- case kMethod:
- case kEnum:
- case kArray:
- case kAnnotation:
- UNIMPLEMENTED(FATAL) << ": type " << type_;
- UNREACHABLE();
- case kNull:
- jval_.l = nullptr;
- width = 0;
- break;
- default:
- LOG(FATAL) << "Unreached";
- UNREACHABLE();
- }
- ptr_ += width;
-}
-
-namespace dex {
-
-std::ostream& operator<<(std::ostream& os, const StringIndex& index) {
- os << "StringIndex[" << index.index_ << "]";
- return os;
-}
-
-std::ostream& operator<<(std::ostream& os, const TypeIndex& index) {
- os << "TypeIndex[" << index.index_ << "]";
- return os;
-}
-
-} // namespace dex
-
-} // namespace art
diff --git a/runtime/dex/dex_file.h b/runtime/dex/dex_file.h
deleted file mode 100644
index cf8c840b59..0000000000
--- a/runtime/dex/dex_file.h
+++ /dev/null
@@ -1,1443 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ART_RUNTIME_DEX_DEX_FILE_H_
-#define ART_RUNTIME_DEX_DEX_FILE_H_
-
-#include <memory>
-#include <string>
-#include <vector>
-
-#include <android-base/logging.h>
-
-#include "base/iteration_range.h"
-#include "base/macros.h"
-#include "base/value_object.h"
-#include "dex_file_types.h"
-#include "dex_instruction_iterator.h"
-#include "globals.h"
-#include "hidden_api_access_flags.h"
-#include "jni.h"
-#include "modifiers.h"
-
-namespace art {
-
-class CompactDexFile;
-enum InvokeType : uint32_t;
-class MemMap;
-class OatDexFile;
-class Signature;
-class StandardDexFile;
-class StringPiece;
-class ZipArchive;
-
-// Some instances of DexFile own the storage referred to by DexFile. Clients who create
-// such management do so by subclassing Container.
-class DexFileContainer {
- public:
- DexFileContainer() { }
- virtual ~DexFileContainer() { }
- virtual int GetPermissions() = 0;
- virtual bool IsReadOnly() = 0;
- virtual bool EnableWrite() = 0;
- virtual bool DisableWrite() = 0;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(DexFileContainer);
-};
-
-// Dex file is the API that exposes native dex files (ordinary dex files) and CompactDex.
-// Originally, the dex file format used by ART was mostly the same as APKs. The only change was
-// quickened opcodes and layout optimizations.
-// Since ART needs to support both native dex files and CompactDex files, the DexFile interface
-// provides an abstraction to facilitate this.
-class DexFile {
- public:
- // Number of bytes in the dex file magic.
- static constexpr size_t kDexMagicSize = 4;
- static constexpr size_t kDexVersionLen = 4;
-
- // First Dex format version enforcing class definition ordering rules.
- static const uint32_t kClassDefinitionOrderEnforcedVersion = 37;
-
- static constexpr size_t kSha1DigestSize = 20;
- static constexpr uint32_t kDexEndianConstant = 0x12345678;
-
- // The value of an invalid index.
- static const uint16_t kDexNoIndex16 = 0xFFFF;
-
- // Raw header_item.
- struct Header {
- uint8_t magic_[8] = {};
- uint32_t checksum_ = 0; // See also location_checksum_
- uint8_t signature_[kSha1DigestSize] = {};
- uint32_t file_size_ = 0; // size of entire file
- uint32_t header_size_ = 0; // offset to start of next section
- uint32_t endian_tag_ = 0;
- uint32_t link_size_ = 0; // unused
- uint32_t link_off_ = 0; // unused
- uint32_t map_off_ = 0; // unused
- uint32_t string_ids_size_ = 0; // number of StringIds
- uint32_t string_ids_off_ = 0; // file offset of StringIds array
- uint32_t type_ids_size_ = 0; // number of TypeIds, we don't support more than 65535
- uint32_t type_ids_off_ = 0; // file offset of TypeIds array
- uint32_t proto_ids_size_ = 0; // number of ProtoIds, we don't support more than 65535
- uint32_t proto_ids_off_ = 0; // file offset of ProtoIds array
- uint32_t field_ids_size_ = 0; // number of FieldIds
- uint32_t field_ids_off_ = 0; // file offset of FieldIds array
- uint32_t method_ids_size_ = 0; // number of MethodIds
- uint32_t method_ids_off_ = 0; // file offset of MethodIds array
- uint32_t class_defs_size_ = 0; // number of ClassDefs
- uint32_t class_defs_off_ = 0; // file offset of ClassDef array
- uint32_t data_size_ = 0; // size of data section
- uint32_t data_off_ = 0; // file offset of data section
-
- // Decode the dex magic version
- uint32_t GetVersion() const;
- };
-
- // Map item type codes.
- enum MapItemType : uint16_t { // private
- kDexTypeHeaderItem = 0x0000,
- kDexTypeStringIdItem = 0x0001,
- kDexTypeTypeIdItem = 0x0002,
- kDexTypeProtoIdItem = 0x0003,
- kDexTypeFieldIdItem = 0x0004,
- kDexTypeMethodIdItem = 0x0005,
- kDexTypeClassDefItem = 0x0006,
- kDexTypeCallSiteIdItem = 0x0007,
- kDexTypeMethodHandleItem = 0x0008,
- kDexTypeMapList = 0x1000,
- kDexTypeTypeList = 0x1001,
- kDexTypeAnnotationSetRefList = 0x1002,
- kDexTypeAnnotationSetItem = 0x1003,
- kDexTypeClassDataItem = 0x2000,
- kDexTypeCodeItem = 0x2001,
- kDexTypeStringDataItem = 0x2002,
- kDexTypeDebugInfoItem = 0x2003,
- kDexTypeAnnotationItem = 0x2004,
- kDexTypeEncodedArrayItem = 0x2005,
- kDexTypeAnnotationsDirectoryItem = 0x2006,
- };
-
- struct MapItem {
- uint16_t type_;
- uint16_t unused_;
- uint32_t size_;
- uint32_t offset_;
- };
-
- struct MapList {
- uint32_t size_;
- MapItem list_[1];
-
- private:
- DISALLOW_COPY_AND_ASSIGN(MapList);
- };
-
- // Raw string_id_item.
- struct StringId {
- uint32_t string_data_off_; // offset in bytes from the base address
-
- private:
- DISALLOW_COPY_AND_ASSIGN(StringId);
- };
-
- // Raw type_id_item.
- struct TypeId {
- dex::StringIndex descriptor_idx_; // index into string_ids
-
- private:
- DISALLOW_COPY_AND_ASSIGN(TypeId);
- };
-
- // Raw field_id_item.
- struct FieldId {
- dex::TypeIndex class_idx_; // index into type_ids_ array for defining class
- dex::TypeIndex type_idx_; // index into type_ids_ array for field type
- dex::StringIndex name_idx_; // index into string_ids_ array for field name
-
- private:
- DISALLOW_COPY_AND_ASSIGN(FieldId);
- };
-
- // Raw proto_id_item.
- struct ProtoId {
- dex::StringIndex shorty_idx_; // index into string_ids array for shorty descriptor
- dex::TypeIndex return_type_idx_; // index into type_ids array for return type
- uint16_t pad_; // padding = 0
- uint32_t parameters_off_; // file offset to type_list for parameter types
-
- private:
- DISALLOW_COPY_AND_ASSIGN(ProtoId);
- };
-
- // Raw method_id_item.
- struct MethodId {
- dex::TypeIndex class_idx_; // index into type_ids_ array for defining class
- uint16_t proto_idx_; // index into proto_ids_ array for method prototype
- dex::StringIndex name_idx_; // index into string_ids_ array for method name
-
- private:
- DISALLOW_COPY_AND_ASSIGN(MethodId);
- };
-
- // Raw class_def_item.
- struct ClassDef {
- dex::TypeIndex class_idx_; // index into type_ids_ array for this class
- uint16_t pad1_; // padding = 0
- uint32_t access_flags_;
- dex::TypeIndex superclass_idx_; // index into type_ids_ array for superclass
- uint16_t pad2_; // padding = 0
- uint32_t interfaces_off_; // file offset to TypeList
- dex::StringIndex source_file_idx_; // index into string_ids_ for source file name
- uint32_t annotations_off_; // file offset to annotations_directory_item
- uint32_t class_data_off_; // file offset to class_data_item
- uint32_t static_values_off_; // file offset to EncodedArray
-
- // Returns the valid access flags, that is, Java modifier bits relevant to the ClassDef type
- // (class or interface). These are all in the lower 16b and do not contain runtime flags.
- uint32_t GetJavaAccessFlags() const {
- // Make sure that none of our runtime-only flags are set.
- static_assert((kAccValidClassFlags & kAccJavaFlagsMask) == kAccValidClassFlags,
- "Valid class flags not a subset of Java flags");
- static_assert((kAccValidInterfaceFlags & kAccJavaFlagsMask) == kAccValidInterfaceFlags,
- "Valid interface flags not a subset of Java flags");
-
- if ((access_flags_ & kAccInterface) != 0) {
- // Interface.
- return access_flags_ & kAccValidInterfaceFlags;
- } else {
- // Class.
- return access_flags_ & kAccValidClassFlags;
- }
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(ClassDef);
- };
-
- // Raw type_item.
- struct TypeItem {
- dex::TypeIndex type_idx_; // index into type_ids section
-
- private:
- DISALLOW_COPY_AND_ASSIGN(TypeItem);
- };
-
- // Raw type_list.
- class TypeList {
- public:
- uint32_t Size() const {
- return size_;
- }
-
- const TypeItem& GetTypeItem(uint32_t idx) const {
- DCHECK_LT(idx, this->size_);
- return this->list_[idx];
- }
-
- // Size in bytes of the part of the list that is common.
- static constexpr size_t GetHeaderSize() {
- return 4U;
- }
-
- // Size in bytes of the whole type list including all the stored elements.
- static constexpr size_t GetListSize(size_t count) {
- return GetHeaderSize() + sizeof(TypeItem) * count;
- }
-
- private:
- uint32_t size_; // size of the list, in entries
- TypeItem list_[1]; // elements of the list
- DISALLOW_COPY_AND_ASSIGN(TypeList);
- };
-
- // MethodHandle Types
- enum class MethodHandleType : uint16_t { // private
- kStaticPut = 0x0000, // a setter for a given static field.
- kStaticGet = 0x0001, // a getter for a given static field.
- kInstancePut = 0x0002, // a setter for a given instance field.
- kInstanceGet = 0x0003, // a getter for a given instance field.
- kInvokeStatic = 0x0004, // an invoker for a given static method.
- kInvokeInstance = 0x0005, // invoke_instance : an invoker for a given instance method. This
- // can be any non-static method on any class (or interface) except
- // for “<init>”.
- kInvokeConstructor = 0x0006, // an invoker for a given constructor.
- kInvokeDirect = 0x0007, // an invoker for a direct (special) method.
- kInvokeInterface = 0x0008, // an invoker for an interface method.
- kLast = kInvokeInterface
- };
-
- // raw method_handle_item
- struct MethodHandleItem {
- uint16_t method_handle_type_;
- uint16_t reserved1_; // Reserved for future use.
- uint16_t field_or_method_idx_; // Field index for accessors, method index otherwise.
- uint16_t reserved2_; // Reserved for future use.
- private:
- DISALLOW_COPY_AND_ASSIGN(MethodHandleItem);
- };
-
- // raw call_site_id_item
- struct CallSiteIdItem {
- uint32_t data_off_; // Offset into data section pointing to encoded array items.
- private:
- DISALLOW_COPY_AND_ASSIGN(CallSiteIdItem);
- };
-
- // Base code_item, compact dex and standard dex have different code item layouts.
- struct CodeItem {
- protected:
- CodeItem() = default;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(CodeItem);
- };
-
- // Raw try_item.
- struct TryItem {
- static constexpr size_t kAlignment = sizeof(uint32_t);
-
- uint32_t start_addr_;
- uint16_t insn_count_;
- uint16_t handler_off_;
-
- private:
- TryItem() = default;
- friend class DexWriter;
- DISALLOW_COPY_AND_ASSIGN(TryItem);
- };
-
- // Annotation constants.
- enum {
- kDexVisibilityBuild = 0x00, /* annotation visibility */
- kDexVisibilityRuntime = 0x01,
- kDexVisibilitySystem = 0x02,
-
- kDexAnnotationByte = 0x00,
- kDexAnnotationShort = 0x02,
- kDexAnnotationChar = 0x03,
- kDexAnnotationInt = 0x04,
- kDexAnnotationLong = 0x06,
- kDexAnnotationFloat = 0x10,
- kDexAnnotationDouble = 0x11,
- kDexAnnotationMethodType = 0x15,
- kDexAnnotationMethodHandle = 0x16,
- kDexAnnotationString = 0x17,
- kDexAnnotationType = 0x18,
- kDexAnnotationField = 0x19,
- kDexAnnotationMethod = 0x1a,
- kDexAnnotationEnum = 0x1b,
- kDexAnnotationArray = 0x1c,
- kDexAnnotationAnnotation = 0x1d,
- kDexAnnotationNull = 0x1e,
- kDexAnnotationBoolean = 0x1f,
-
- kDexAnnotationValueTypeMask = 0x1f, /* low 5 bits */
- kDexAnnotationValueArgShift = 5,
- };
-
- struct AnnotationsDirectoryItem {
- uint32_t class_annotations_off_;
- uint32_t fields_size_;
- uint32_t methods_size_;
- uint32_t parameters_size_;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(AnnotationsDirectoryItem);
- };
-
- struct FieldAnnotationsItem {
- uint32_t field_idx_;
- uint32_t annotations_off_;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(FieldAnnotationsItem);
- };
-
- struct MethodAnnotationsItem {
- uint32_t method_idx_;
- uint32_t annotations_off_;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(MethodAnnotationsItem);
- };
-
- struct ParameterAnnotationsItem {
- uint32_t method_idx_;
- uint32_t annotations_off_;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(ParameterAnnotationsItem);
- };
-
- struct AnnotationSetRefItem {
- uint32_t annotations_off_;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(AnnotationSetRefItem);
- };
-
- struct AnnotationSetRefList {
- uint32_t size_;
- AnnotationSetRefItem list_[1];
-
- private:
- DISALLOW_COPY_AND_ASSIGN(AnnotationSetRefList);
- };
-
- struct AnnotationSetItem {
- uint32_t size_;
- uint32_t entries_[1];
-
- private:
- DISALLOW_COPY_AND_ASSIGN(AnnotationSetItem);
- };
-
- struct AnnotationItem {
- uint8_t visibility_;
- uint8_t annotation_[1];
-
- private:
- DISALLOW_COPY_AND_ASSIGN(AnnotationItem);
- };
-
- enum AnnotationResultStyle { // private
- kAllObjects,
- kPrimitivesOrObjects,
- kAllRaw
- };
-
- struct AnnotationValue;
-
- // Closes a .dex file.
- virtual ~DexFile();
-
- const std::string& GetLocation() const {
- return location_;
- }
-
- // For DexFiles directly from .dex files, this is the checksum from the DexFile::Header.
- // For DexFiles opened from a zip files, this will be the ZipEntry CRC32 of classes.dex.
- uint32_t GetLocationChecksum() const {
- return location_checksum_;
- }
-
- const Header& GetHeader() const {
- DCHECK(header_ != nullptr) << GetLocation();
- return *header_;
- }
-
- // Decode the dex magic version
- uint32_t GetDexVersion() const {
- return GetHeader().GetVersion();
- }
-
- // Returns true if the byte string points to the magic value.
- virtual bool IsMagicValid() const = 0;
-
- // Returns true if the byte string after the magic is the correct value.
- virtual bool IsVersionValid() const = 0;
-
- // Returns true if the dex file supports default methods.
- virtual bool SupportsDefaultMethods() const = 0;
-
- // Returns the maximum size in bytes needed to store an equivalent dex file strictly conforming to
- // the dex file specification. That is the size if we wanted to get rid of all the
- // quickening/compact-dexing/etc.
- //
- // TODO This should really be an exact size! b/72402467
- virtual size_t GetDequickenedSize() const = 0;
-
- // Returns the number of string identifiers in the .dex file.
- size_t NumStringIds() const {
- DCHECK(header_ != nullptr) << GetLocation();
- return header_->string_ids_size_;
- }
-
- // Returns the StringId at the specified index.
- const StringId& GetStringId(dex::StringIndex idx) const {
- DCHECK_LT(idx.index_, NumStringIds()) << GetLocation();
- return string_ids_[idx.index_];
- }
-
- dex::StringIndex GetIndexForStringId(const StringId& string_id) const {
- CHECK_GE(&string_id, string_ids_) << GetLocation();
- CHECK_LT(&string_id, string_ids_ + header_->string_ids_size_) << GetLocation();
- return dex::StringIndex(&string_id - string_ids_);
- }
-
- int32_t GetStringLength(const StringId& string_id) const;
-
- // Returns a pointer to the UTF-8 string data referred to by the given string_id as well as the
- // length of the string when decoded as a UTF-16 string. Note the UTF-16 length is not the same
- // as the string length of the string data.
- const char* GetStringDataAndUtf16Length(const StringId& string_id, uint32_t* utf16_length) const;
-
- const char* GetStringData(const StringId& string_id) const;
-
- // Index version of GetStringDataAndUtf16Length.
- const char* StringDataAndUtf16LengthByIdx(dex::StringIndex idx, uint32_t* utf16_length) const;
-
- const char* StringDataByIdx(dex::StringIndex idx) const;
-
- // Looks up a string id for a given modified utf8 string.
- const StringId* FindStringId(const char* string) const;
-
- const TypeId* FindTypeId(const char* string) const;
-
- // Looks up a string id for a given utf16 string.
- const StringId* FindStringId(const uint16_t* string, size_t length) const;
-
- // Returns the number of type identifiers in the .dex file.
- uint32_t NumTypeIds() const {
- DCHECK(header_ != nullptr) << GetLocation();
- return header_->type_ids_size_;
- }
-
- bool IsTypeIndexValid(dex::TypeIndex idx) const {
- return idx.IsValid() && idx.index_ < NumTypeIds();
- }
-
- // Returns the TypeId at the specified index.
- const TypeId& GetTypeId(dex::TypeIndex idx) const {
- DCHECK_LT(idx.index_, NumTypeIds()) << GetLocation();
- return type_ids_[idx.index_];
- }
-
- dex::TypeIndex GetIndexForTypeId(const TypeId& type_id) const {
- CHECK_GE(&type_id, type_ids_) << GetLocation();
- CHECK_LT(&type_id, type_ids_ + header_->type_ids_size_) << GetLocation();
- size_t result = &type_id - type_ids_;
- DCHECK_LT(result, 65536U) << GetLocation();
- return dex::TypeIndex(static_cast<uint16_t>(result));
- }
-
- // Get the descriptor string associated with a given type index.
- const char* StringByTypeIdx(dex::TypeIndex idx, uint32_t* unicode_length) const;
-
- const char* StringByTypeIdx(dex::TypeIndex idx) const;
-
- // Returns the type descriptor string of a type id.
- const char* GetTypeDescriptor(const TypeId& type_id) const;
-
- // Looks up a type for the given string index
- const TypeId* FindTypeId(dex::StringIndex string_idx) const;
-
- // Returns the number of field identifiers in the .dex file.
- size_t NumFieldIds() const {
- DCHECK(header_ != nullptr) << GetLocation();
- return header_->field_ids_size_;
- }
-
- // Returns the FieldId at the specified index.
- const FieldId& GetFieldId(uint32_t idx) const {
- DCHECK_LT(idx, NumFieldIds()) << GetLocation();
- return field_ids_[idx];
- }
-
- uint32_t GetIndexForFieldId(const FieldId& field_id) const {
- CHECK_GE(&field_id, field_ids_) << GetLocation();
- CHECK_LT(&field_id, field_ids_ + header_->field_ids_size_) << GetLocation();
- return &field_id - field_ids_;
- }
-
- // Looks up a field by its declaring class, name and type
- const FieldId* FindFieldId(const DexFile::TypeId& declaring_klass,
- const DexFile::StringId& name,
- const DexFile::TypeId& type) const;
-
- uint32_t FindCodeItemOffset(const DexFile::ClassDef& class_def,
- uint32_t dex_method_idx) const;
-
- virtual uint32_t GetCodeItemSize(const DexFile::CodeItem& disk_code_item) const = 0;
-
- // Returns the declaring class descriptor string of a field id.
- const char* GetFieldDeclaringClassDescriptor(const FieldId& field_id) const {
- const DexFile::TypeId& type_id = GetTypeId(field_id.class_idx_);
- return GetTypeDescriptor(type_id);
- }
-
- // Returns the class descriptor string of a field id.
- const char* GetFieldTypeDescriptor(const FieldId& field_id) const;
-
- // Returns the name of a field id.
- const char* GetFieldName(const FieldId& field_id) const;
-
- // Returns the number of method identifiers in the .dex file.
- size_t NumMethodIds() const {
- DCHECK(header_ != nullptr) << GetLocation();
- return header_->method_ids_size_;
- }
-
- // Returns the MethodId at the specified index.
- const MethodId& GetMethodId(uint32_t idx) const {
- DCHECK_LT(idx, NumMethodIds()) << GetLocation();
- return method_ids_[idx];
- }
-
- uint32_t GetIndexForMethodId(const MethodId& method_id) const {
- CHECK_GE(&method_id, method_ids_) << GetLocation();
- CHECK_LT(&method_id, method_ids_ + header_->method_ids_size_) << GetLocation();
- return &method_id - method_ids_;
- }
-
- // Looks up a method by its declaring class, name and proto_id
- const MethodId* FindMethodId(const DexFile::TypeId& declaring_klass,
- const DexFile::StringId& name,
- const DexFile::ProtoId& signature) const;
-
- // Returns the declaring class descriptor string of a method id.
- const char* GetMethodDeclaringClassDescriptor(const MethodId& method_id) const;
-
- // Returns the prototype of a method id.
- const ProtoId& GetMethodPrototype(const MethodId& method_id) const {
- return GetProtoId(method_id.proto_idx_);
- }
-
- // Returns a representation of the signature of a method id.
- const Signature GetMethodSignature(const MethodId& method_id) const;
-
- // Returns a representation of the signature of a proto id.
- const Signature GetProtoSignature(const ProtoId& proto_id) const;
-
- // Returns the name of a method id.
- const char* GetMethodName(const MethodId& method_id) const;
-
- // Returns the shorty of a method by its index.
- const char* GetMethodShorty(uint32_t idx) const;
-
- // Returns the shorty of a method id.
- const char* GetMethodShorty(const MethodId& method_id) const;
- const char* GetMethodShorty(const MethodId& method_id, uint32_t* length) const;
-
- // Returns the number of class definitions in the .dex file.
- uint32_t NumClassDefs() const {
- DCHECK(header_ != nullptr) << GetLocation();
- return header_->class_defs_size_;
- }
-
- // Returns the ClassDef at the specified index.
- const ClassDef& GetClassDef(uint16_t idx) const {
- DCHECK_LT(idx, NumClassDefs()) << GetLocation();
- return class_defs_[idx];
- }
-
- uint16_t GetIndexForClassDef(const ClassDef& class_def) const {
- CHECK_GE(&class_def, class_defs_) << GetLocation();
- CHECK_LT(&class_def, class_defs_ + header_->class_defs_size_) << GetLocation();
- return &class_def - class_defs_;
- }
-
- // Returns the class descriptor string of a class definition.
- const char* GetClassDescriptor(const ClassDef& class_def) const;
-
- // Looks up a class definition by its type index.
- const ClassDef* FindClassDef(dex::TypeIndex type_idx) const;
-
- const TypeList* GetInterfacesList(const ClassDef& class_def) const {
- return DataPointer<TypeList>(class_def.interfaces_off_);
- }
-
- uint32_t NumMethodHandles() const {
- return num_method_handles_;
- }
-
- const MethodHandleItem& GetMethodHandle(uint32_t idx) const {
- CHECK_LT(idx, NumMethodHandles());
- return method_handles_[idx];
- }
-
- uint32_t NumCallSiteIds() const {
- return num_call_site_ids_;
- }
-
- const CallSiteIdItem& GetCallSiteId(uint32_t idx) const {
- CHECK_LT(idx, NumCallSiteIds());
- return call_site_ids_[idx];
- }
-
- // Returns a pointer to the raw memory mapped class_data_item
- const uint8_t* GetClassData(const ClassDef& class_def) const {
- return DataPointer<uint8_t>(class_def.class_data_off_);
- }
-
- // Return the code item for a provided offset.
- const CodeItem* GetCodeItem(const uint32_t code_off) const {
- // May be null for native or abstract methods.
- return DataPointer<CodeItem>(code_off);
- }
-
- const char* GetReturnTypeDescriptor(const ProtoId& proto_id) const;
-
- // Returns the number of prototype identifiers in the .dex file.
- size_t NumProtoIds() const {
- DCHECK(header_ != nullptr) << GetLocation();
- return header_->proto_ids_size_;
- }
-
- // Returns the ProtoId at the specified index.
- const ProtoId& GetProtoId(uint16_t idx) const {
- DCHECK_LT(idx, NumProtoIds()) << GetLocation();
- return proto_ids_[idx];
- }
-
- uint16_t GetIndexForProtoId(const ProtoId& proto_id) const {
- CHECK_GE(&proto_id, proto_ids_) << GetLocation();
- CHECK_LT(&proto_id, proto_ids_ + header_->proto_ids_size_) << GetLocation();
- return &proto_id - proto_ids_;
- }
-
- // Looks up a proto id for a given return type and signature type list
- const ProtoId* FindProtoId(dex::TypeIndex return_type_idx,
- const dex::TypeIndex* signature_type_idxs,
- uint32_t signature_length) const;
- const ProtoId* FindProtoId(dex::TypeIndex return_type_idx,
- const std::vector<dex::TypeIndex>& signature_type_idxs) const {
- return FindProtoId(return_type_idx, &signature_type_idxs[0], signature_type_idxs.size());
- }
-
- // Given a signature place the type ids into the given vector, returns true on success
- bool CreateTypeList(const StringPiece& signature,
- dex::TypeIndex* return_type_idx,
- std::vector<dex::TypeIndex>* param_type_idxs) const;
-
- // Create a Signature from the given string signature or return Signature::NoSignature if not
- // possible.
- const Signature CreateSignature(const StringPiece& signature) const;
-
- // Returns the short form method descriptor for the given prototype.
- const char* GetShorty(uint32_t proto_idx) const;
-
- const TypeList* GetProtoParameters(const ProtoId& proto_id) const {
- return DataPointer<TypeList>(proto_id.parameters_off_);
- }
-
- const uint8_t* GetEncodedStaticFieldValuesArray(const ClassDef& class_def) const {
- return DataPointer<uint8_t>(class_def.static_values_off_);
- }
-
- const uint8_t* GetCallSiteEncodedValuesArray(const CallSiteIdItem& call_site_id) const {
- return DataBegin() + call_site_id.data_off_;
- }
-
- static const TryItem* GetTryItems(const DexInstructionIterator& code_item_end, uint32_t offset);
-
- // Get the base of the encoded data for the given DexCode.
- static const uint8_t* GetCatchHandlerData(const DexInstructionIterator& code_item_end,
- uint32_t tries_size,
- uint32_t offset);
-
- // Find which try region is associated with the given address (ie dex pc). Returns -1 if none.
- static int32_t FindTryItem(const TryItem* try_items, uint32_t tries_size, uint32_t address);
-
- // Get the pointer to the start of the debugging data
- const uint8_t* GetDebugInfoStream(uint32_t debug_info_off) const {
- // Check that the offset is in bounds.
- // Note that although the specification says that 0 should be used if there
- // is no debug information, some applications incorrectly use 0xFFFFFFFF.
- return (debug_info_off == 0 || debug_info_off >= data_size_)
- ? nullptr
- : DataBegin() + debug_info_off;
- }
-
- struct PositionInfo {
- PositionInfo() = default;
-
- uint32_t address_ = 0; // In 16-bit code units.
- uint32_t line_ = 0; // Source code line number starting at 1.
- const char* source_file_ = nullptr; // nullptr if the file from ClassDef still applies.
- bool prologue_end_ = false;
- bool epilogue_begin_ = false;
- };
-
- struct LocalInfo {
- LocalInfo() = default;
-
- const char* name_ = nullptr; // E.g., list. It can be nullptr if unknown.
- const char* descriptor_ = nullptr; // E.g., Ljava/util/LinkedList;
- const char* signature_ = nullptr; // E.g., java.util.LinkedList<java.lang.Integer>
- uint32_t start_address_ = 0; // PC location where the local is first defined.
- uint32_t end_address_ = 0; // PC location where the local is no longer defined.
- uint16_t reg_ = 0; // Dex register which stores the values.
- bool is_live_ = false; // Is the local defined and live.
- };
-
- // Callback for "new locals table entry".
- typedef void (*DexDebugNewLocalCb)(void* context, const LocalInfo& entry);
-
- static bool LineNumForPcCb(void* context, const PositionInfo& entry);
-
- const AnnotationsDirectoryItem* GetAnnotationsDirectory(const ClassDef& class_def) const {
- return DataPointer<AnnotationsDirectoryItem>(class_def.annotations_off_);
- }
-
- const AnnotationSetItem* GetClassAnnotationSet(const AnnotationsDirectoryItem* anno_dir) const {
- return DataPointer<AnnotationSetItem>(anno_dir->class_annotations_off_);
- }
-
- const FieldAnnotationsItem* GetFieldAnnotations(const AnnotationsDirectoryItem* anno_dir) const {
- return (anno_dir->fields_size_ == 0)
- ? nullptr
- : reinterpret_cast<const FieldAnnotationsItem*>(&anno_dir[1]);
- }
-
- const MethodAnnotationsItem* GetMethodAnnotations(const AnnotationsDirectoryItem* anno_dir)
- const {
- if (anno_dir->methods_size_ == 0) {
- return nullptr;
- }
- // Skip past the header and field annotations.
- const uint8_t* addr = reinterpret_cast<const uint8_t*>(&anno_dir[1]);
- addr += anno_dir->fields_size_ * sizeof(FieldAnnotationsItem);
- return reinterpret_cast<const MethodAnnotationsItem*>(addr);
- }
-
- const ParameterAnnotationsItem* GetParameterAnnotations(const AnnotationsDirectoryItem* anno_dir)
- const {
- if (anno_dir->parameters_size_ == 0) {
- return nullptr;
- }
- // Skip past the header, field annotations, and method annotations.
- const uint8_t* addr = reinterpret_cast<const uint8_t*>(&anno_dir[1]);
- addr += anno_dir->fields_size_ * sizeof(FieldAnnotationsItem);
- addr += anno_dir->methods_size_ * sizeof(MethodAnnotationsItem);
- return reinterpret_cast<const ParameterAnnotationsItem*>(addr);
- }
-
- const AnnotationSetItem* GetFieldAnnotationSetItem(const FieldAnnotationsItem& anno_item) const {
- return DataPointer<AnnotationSetItem>(anno_item.annotations_off_);
- }
-
- const AnnotationSetItem* GetMethodAnnotationSetItem(const MethodAnnotationsItem& anno_item)
- const {
- return DataPointer<AnnotationSetItem>(anno_item.annotations_off_);
- }
-
- const AnnotationSetRefList* GetParameterAnnotationSetRefList(
- const ParameterAnnotationsItem* anno_item) const {
- return DataPointer<AnnotationSetRefList>(anno_item->annotations_off_);
- }
-
- ALWAYS_INLINE const AnnotationItem* GetAnnotationItemAtOffset(uint32_t offset) const {
- return DataPointer<AnnotationItem>(offset);
- }
-
- const AnnotationItem* GetAnnotationItem(const AnnotationSetItem* set_item, uint32_t index) const {
- DCHECK_LE(index, set_item->size_);
- return GetAnnotationItemAtOffset(set_item->entries_[index]);
- }
-
- const AnnotationSetItem* GetSetRefItemItem(const AnnotationSetRefItem* anno_item) const {
- return DataPointer<AnnotationSetItem>(anno_item->annotations_off_);
- }
-
- // Debug info opcodes and constants
- enum {
- DBG_END_SEQUENCE = 0x00,
- DBG_ADVANCE_PC = 0x01,
- DBG_ADVANCE_LINE = 0x02,
- DBG_START_LOCAL = 0x03,
- DBG_START_LOCAL_EXTENDED = 0x04,
- DBG_END_LOCAL = 0x05,
- DBG_RESTART_LOCAL = 0x06,
- DBG_SET_PROLOGUE_END = 0x07,
- DBG_SET_EPILOGUE_BEGIN = 0x08,
- DBG_SET_FILE = 0x09,
- DBG_FIRST_SPECIAL = 0x0a,
- DBG_LINE_BASE = -4,
- DBG_LINE_RANGE = 15,
- };
-
- struct LineNumFromPcContext {
- LineNumFromPcContext(uint32_t address, uint32_t line_num)
- : address_(address), line_num_(line_num) {}
- uint32_t address_;
- uint32_t line_num_;
- private:
- DISALLOW_COPY_AND_ASSIGN(LineNumFromPcContext);
- };
-
- // Returns false if there is no debugging information or if it cannot be decoded.
- template<typename NewLocalCallback, typename IndexToStringData, typename TypeIndexToStringData>
- static bool DecodeDebugLocalInfo(const uint8_t* stream,
- const std::string& location,
- const char* declaring_class_descriptor,
- const std::vector<const char*>& arg_descriptors,
- const std::string& method_name,
- bool is_static,
- uint16_t registers_size,
- uint16_t ins_size,
- uint16_t insns_size_in_code_units,
- IndexToStringData index_to_string_data,
- TypeIndexToStringData type_index_to_string_data,
- NewLocalCallback new_local,
- void* context);
- template<typename NewLocalCallback>
- bool DecodeDebugLocalInfo(uint32_t registers_size,
- uint32_t ins_size,
- uint32_t insns_size_in_code_units,
- uint32_t debug_info_offset,
- bool is_static,
- uint32_t method_idx,
- NewLocalCallback new_local,
- void* context) const;
-
- // Returns false if there is no debugging information or if it cannot be decoded.
- template<typename DexDebugNewPosition, typename IndexToStringData>
- static bool DecodeDebugPositionInfo(const uint8_t* stream,
- IndexToStringData index_to_string_data,
- DexDebugNewPosition position_functor,
- void* context);
- template<typename DexDebugNewPosition>
- bool DecodeDebugPositionInfo(uint32_t debug_info_offset,
- DexDebugNewPosition position_functor,
- void* context) const;
-
- const char* GetSourceFile(const ClassDef& class_def) const {
- if (!class_def.source_file_idx_.IsValid()) {
- return nullptr;
- } else {
- return StringDataByIdx(class_def.source_file_idx_);
- }
- }
-
- int GetPermissions() const;
-
- bool IsReadOnly() const;
-
- bool EnableWrite() const;
-
- bool DisableWrite() const;
-
- const uint8_t* Begin() const {
- return begin_;
- }
-
- size_t Size() const {
- return size_;
- }
-
- const uint8_t* DataBegin() const {
- return data_begin_;
- }
-
- size_t DataSize() const {
- return data_size_;
- }
-
- template <typename T>
- const T* DataPointer(size_t offset) const {
- DCHECK_LT(offset, DataSize()) << "Offset past end of data section";
- return (offset != 0u) ? reinterpret_cast<const T*>(DataBegin() + offset) : nullptr;
- }
-
- const OatDexFile* GetOatDexFile() const {
- return oat_dex_file_;
- }
-
- // Used by oat writer.
- void SetOatDexFile(OatDexFile* oat_dex_file) const {
- oat_dex_file_ = oat_dex_file;
- }
-
- // Read MapItems and validate/set remaining offsets.
- const DexFile::MapList* GetMapList() const {
- return reinterpret_cast<const DexFile::MapList*>(DataBegin() + header_->map_off_);
- }
-
- // Utility methods for reading integral values from a buffer.
- static int32_t ReadSignedInt(const uint8_t* ptr, int zwidth);
- static uint32_t ReadUnsignedInt(const uint8_t* ptr, int zwidth, bool fill_on_right);
- static int64_t ReadSignedLong(const uint8_t* ptr, int zwidth);
- static uint64_t ReadUnsignedLong(const uint8_t* ptr, int zwidth, bool fill_on_right);
-
- // Recalculates the checksum of the dex file. Does not use the current value in the header.
- virtual uint32_t CalculateChecksum() const;
- static uint32_t CalculateChecksum(const uint8_t* begin, size_t size);
- static uint32_t ChecksumMemoryRange(const uint8_t* begin, size_t size);
-
- // Returns a human-readable form of the method at an index.
- std::string PrettyMethod(uint32_t method_idx, bool with_signature = true) const;
- // Returns a human-readable form of the field at an index.
- std::string PrettyField(uint32_t field_idx, bool with_type = true) const;
- // Returns a human-readable form of the type at an index.
- std::string PrettyType(dex::TypeIndex type_idx) const;
-
- // Not virtual for performance reasons.
- ALWAYS_INLINE bool IsCompactDexFile() const {
- return is_compact_dex_;
- }
- ALWAYS_INLINE bool IsStandardDexFile() const {
- return !is_compact_dex_;
- }
- ALWAYS_INLINE const StandardDexFile* AsStandardDexFile() const;
- ALWAYS_INLINE const CompactDexFile* AsCompactDexFile() const;
-
- bool IsInMainSection(const void* addr) const {
- return Begin() <= addr && addr < Begin() + Size();
- }
-
- bool IsInDataSection(const void* addr) const {
- return DataBegin() <= addr && addr < DataBegin() + DataSize();
- }
-
- DexFileContainer* GetContainer() const {
- return container_.get();
- }
-
- protected:
- // First Dex format version supporting default methods.
- static const uint32_t kDefaultMethodsVersion = 37;
-
- DexFile(const uint8_t* base,
- size_t size,
- const uint8_t* data_begin,
- size_t data_size,
- const std::string& location,
- uint32_t location_checksum,
- const OatDexFile* oat_dex_file,
- DexFileContainer* container,
- bool is_compact_dex);
-
- // Top-level initializer that calls other Init methods.
- bool Init(std::string* error_msg);
-
- // Returns true if the header magic and version numbers are of the expected values.
- bool CheckMagicAndVersion(std::string* error_msg) const;
-
- // Initialize section info for sections only found in map. Returns true on success.
- void InitializeSectionsFromMapList();
-
- // The base address of the memory mapping.
- const uint8_t* const begin_;
-
- // The size of the underlying memory allocation in bytes.
- const size_t size_;
-
- // The base address of the data section (same as Begin() for standard dex).
- const uint8_t* const data_begin_;
-
- // The size of the data section.
- const size_t data_size_;
-
- // Typically the dex file name when available, alternatively some identifying string.
- //
- // The ClassLinker will use this to match DexFiles the boot class
- // path to DexCache::GetLocation when loading from an image.
- const std::string location_;
-
- const uint32_t location_checksum_;
-
- // Points to the header section.
- const Header* const header_;
-
- // Points to the base of the string identifier list.
- const StringId* const string_ids_;
-
- // Points to the base of the type identifier list.
- const TypeId* const type_ids_;
-
- // Points to the base of the field identifier list.
- const FieldId* const field_ids_;
-
- // Points to the base of the method identifier list.
- const MethodId* const method_ids_;
-
- // Points to the base of the prototype identifier list.
- const ProtoId* const proto_ids_;
-
- // Points to the base of the class definition list.
- const ClassDef* const class_defs_;
-
- // Points to the base of the method handles list.
- const MethodHandleItem* method_handles_;
-
- // Number of elements in the method handles list.
- size_t num_method_handles_;
-
- // Points to the base of the call sites id list.
- const CallSiteIdItem* call_site_ids_;
-
- // Number of elements in the call sites list.
- size_t num_call_site_ids_;
-
- // If this dex file was loaded from an oat file, oat_dex_file_ contains a
- // pointer to the OatDexFile it was loaded from. Otherwise oat_dex_file_ is
- // null.
- mutable const OatDexFile* oat_dex_file_;
-
- // Manages the underlying memory allocation.
- std::unique_ptr<DexFileContainer> container_;
-
- // If the dex file is a compact dex file. If false then the dex file is a standard dex file.
- const bool is_compact_dex_;
-
- friend class DexFileLoader;
- friend class DexFileVerifierTest;
- friend class OatWriter;
-};
-
-std::ostream& operator<<(std::ostream& os, const DexFile& dex_file);
-
-// Iterate over a dex file's ProtoId's paramters
-class DexFileParameterIterator {
- public:
- DexFileParameterIterator(const DexFile& dex_file, const DexFile::ProtoId& proto_id)
- : dex_file_(dex_file) {
- type_list_ = dex_file_.GetProtoParameters(proto_id);
- if (type_list_ != nullptr) {
- size_ = type_list_->Size();
- }
- }
- bool HasNext() const { return pos_ < size_; }
- size_t Size() const { return size_; }
- void Next() { ++pos_; }
- dex::TypeIndex GetTypeIdx() {
- return type_list_->GetTypeItem(pos_).type_idx_;
- }
- const char* GetDescriptor() {
- return dex_file_.StringByTypeIdx(dex::TypeIndex(GetTypeIdx()));
- }
- private:
- const DexFile& dex_file_;
- const DexFile::TypeList* type_list_ = nullptr;
- uint32_t size_ = 0;
- uint32_t pos_ = 0;
- DISALLOW_IMPLICIT_CONSTRUCTORS(DexFileParameterIterator);
-};
-
-// Abstract the signature of a method.
-class Signature : public ValueObject {
- public:
- std::string ToString() const;
-
- static Signature NoSignature() {
- return Signature();
- }
-
- bool IsVoid() const;
- uint32_t GetNumberOfParameters() const;
-
- bool operator==(const Signature& rhs) const;
- bool operator!=(const Signature& rhs) const {
- return !(*this == rhs);
- }
-
- bool operator==(const StringPiece& rhs) const;
-
- private:
- Signature(const DexFile* dex, const DexFile::ProtoId& proto) : dex_file_(dex), proto_id_(&proto) {
- }
-
- Signature() = default;
-
- friend class DexFile;
-
- const DexFile* const dex_file_ = nullptr;
- const DexFile::ProtoId* const proto_id_ = nullptr;
-};
-std::ostream& operator<<(std::ostream& os, const Signature& sig);
-
-// Iterate and decode class_data_item
-class ClassDataItemIterator {
- public:
- ClassDataItemIterator(const DexFile& dex_file, const uint8_t* raw_class_data_item)
- : dex_file_(dex_file), pos_(0), ptr_pos_(raw_class_data_item), last_idx_(0) {
- ReadClassDataHeader();
- if (EndOfInstanceFieldsPos() > 0) {
- ReadClassDataField();
- } else if (EndOfVirtualMethodsPos() > 0) {
- ReadClassDataMethod();
- }
- }
- uint32_t NumStaticFields() const {
- return header_.static_fields_size_;
- }
- uint32_t NumInstanceFields() const {
- return header_.instance_fields_size_;
- }
- uint32_t NumDirectMethods() const {
- return header_.direct_methods_size_;
- }
- uint32_t NumVirtualMethods() const {
- return header_.virtual_methods_size_;
- }
- bool IsAtMethod() const {
- return pos_ >= EndOfInstanceFieldsPos();
- }
- bool HasNextStaticField() const {
- return pos_ < EndOfStaticFieldsPos();
- }
- bool HasNextInstanceField() const {
- return pos_ >= EndOfStaticFieldsPos() && pos_ < EndOfInstanceFieldsPos();
- }
- bool HasNextDirectMethod() const {
- return pos_ >= EndOfInstanceFieldsPos() && pos_ < EndOfDirectMethodsPos();
- }
- bool HasNextVirtualMethod() const {
- return pos_ >= EndOfDirectMethodsPos() && pos_ < EndOfVirtualMethodsPos();
- }
- bool HasNextMethod() const {
- const bool result = pos_ >= EndOfInstanceFieldsPos() && pos_ < EndOfVirtualMethodsPos();
- DCHECK_EQ(result, HasNextDirectMethod() || HasNextVirtualMethod());
- return result;
- }
- void SkipStaticFields() {
- while (HasNextStaticField()) {
- Next();
- }
- }
- void SkipInstanceFields() {
- while (HasNextInstanceField()) {
- Next();
- }
- }
- void SkipAllFields() {
- SkipStaticFields();
- SkipInstanceFields();
- }
- void SkipDirectMethods() {
- while (HasNextDirectMethod()) {
- Next();
- }
- }
- void SkipVirtualMethods() {
- while (HasNextVirtualMethod()) {
- Next();
- }
- }
- bool HasNext() const {
- return pos_ < EndOfVirtualMethodsPos();
- }
- inline void Next() {
- pos_++;
- if (pos_ < EndOfStaticFieldsPos()) {
- last_idx_ = GetMemberIndex();
- ReadClassDataField();
- } else if (pos_ == EndOfStaticFieldsPos() && NumInstanceFields() > 0) {
- last_idx_ = 0; // transition to next array, reset last index
- ReadClassDataField();
- } else if (pos_ < EndOfInstanceFieldsPos()) {
- last_idx_ = GetMemberIndex();
- ReadClassDataField();
- } else if (pos_ == EndOfInstanceFieldsPos() && NumDirectMethods() > 0) {
- last_idx_ = 0; // transition to next array, reset last index
- ReadClassDataMethod();
- } else if (pos_ < EndOfDirectMethodsPos()) {
- last_idx_ = GetMemberIndex();
- ReadClassDataMethod();
- } else if (pos_ == EndOfDirectMethodsPos() && NumVirtualMethods() > 0) {
- last_idx_ = 0; // transition to next array, reset last index
- ReadClassDataMethod();
- } else if (pos_ < EndOfVirtualMethodsPos()) {
- last_idx_ = GetMemberIndex();
- ReadClassDataMethod();
- } else {
- DCHECK(!HasNext());
- }
- }
- uint32_t GetMemberIndex() const {
- if (pos_ < EndOfInstanceFieldsPos()) {
- return last_idx_ + field_.field_idx_delta_;
- } else {
- DCHECK_LT(pos_, EndOfVirtualMethodsPos());
- return last_idx_ + method_.method_idx_delta_;
- }
- }
- uint32_t GetRawMemberAccessFlags() const {
- if (pos_ < EndOfInstanceFieldsPos()) {
- return field_.access_flags_;
- } else {
- DCHECK_LT(pos_, EndOfVirtualMethodsPos());
- return method_.access_flags_;
- }
- }
- uint32_t GetFieldAccessFlags() const {
- return GetMemberAccessFlags() & kAccValidFieldFlags;
- }
- uint32_t GetMethodAccessFlags() const {
- return GetMemberAccessFlags() & kAccValidMethodFlags;
- }
- uint32_t GetMemberAccessFlags() const {
- return HiddenApiAccessFlags::RemoveFromDex(GetRawMemberAccessFlags());
- }
- HiddenApiAccessFlags::ApiList DecodeHiddenAccessFlags() const {
- return HiddenApiAccessFlags::DecodeFromDex(GetRawMemberAccessFlags());
- }
- bool MemberIsNative() const {
- return GetRawMemberAccessFlags() & kAccNative;
- }
- bool MemberIsFinal() const {
- return GetRawMemberAccessFlags() & kAccFinal;
- }
- ALWAYS_INLINE InvokeType GetMethodInvokeType(const DexFile::ClassDef& class_def) const;
- const DexFile::CodeItem* GetMethodCodeItem() const {
- return dex_file_.GetCodeItem(method_.code_off_);
- }
- uint32_t GetMethodCodeItemOffset() const {
- return method_.code_off_;
- }
- const uint8_t* DataPointer() const {
- return ptr_pos_;
- }
- const uint8_t* EndDataPointer() const {
- CHECK(!HasNext());
- return ptr_pos_;
- }
-
- private:
- // A dex file's class_data_item is leb128 encoded, this structure holds a decoded form of the
- // header for a class_data_item
- struct ClassDataHeader {
- uint32_t static_fields_size_; // the number of static fields
- uint32_t instance_fields_size_; // the number of instance fields
- uint32_t direct_methods_size_; // the number of direct methods
- uint32_t virtual_methods_size_; // the number of virtual methods
- } header_;
-
- // Read and decode header from a class_data_item stream into header
- void ReadClassDataHeader();
-
- uint32_t EndOfStaticFieldsPos() const {
- return header_.static_fields_size_;
- }
- uint32_t EndOfInstanceFieldsPos() const {
- return EndOfStaticFieldsPos() + header_.instance_fields_size_;
- }
- uint32_t EndOfDirectMethodsPos() const {
- return EndOfInstanceFieldsPos() + header_.direct_methods_size_;
- }
- uint32_t EndOfVirtualMethodsPos() const {
- return EndOfDirectMethodsPos() + header_.virtual_methods_size_;
- }
-
- // A decoded version of the field of a class_data_item
- struct ClassDataField {
- uint32_t field_idx_delta_; // delta of index into the field_ids array for FieldId
- uint32_t access_flags_; // access flags for the field
- ClassDataField() : field_idx_delta_(0), access_flags_(0) {}
-
- private:
- DISALLOW_COPY_AND_ASSIGN(ClassDataField);
- };
- ClassDataField field_;
-
- // Read and decode a field from a class_data_item stream into field
- void ReadClassDataField();
-
- // A decoded version of the method of a class_data_item
- struct ClassDataMethod {
- uint32_t method_idx_delta_; // delta of index into the method_ids array for MethodId
- uint32_t access_flags_;
- uint32_t code_off_;
- ClassDataMethod() : method_idx_delta_(0), access_flags_(0), code_off_(0) {}
-
- private:
- DISALLOW_COPY_AND_ASSIGN(ClassDataMethod);
- };
- ClassDataMethod method_;
-
- // Read and decode a method from a class_data_item stream into method
- void ReadClassDataMethod();
-
- const DexFile& dex_file_;
- size_t pos_; // integral number of items passed
- const uint8_t* ptr_pos_; // pointer into stream of class_data_item
- uint32_t last_idx_; // last read field or method index to apply delta to
- DISALLOW_IMPLICIT_CONSTRUCTORS(ClassDataItemIterator);
-};
-
-class EncodedArrayValueIterator {
- public:
- EncodedArrayValueIterator(const DexFile& dex_file, const uint8_t* array_data);
-
- bool HasNext() const { return pos_ < array_size_; }
-
- void Next();
-
- enum ValueType {
- kByte = 0x00,
- kShort = 0x02,
- kChar = 0x03,
- kInt = 0x04,
- kLong = 0x06,
- kFloat = 0x10,
- kDouble = 0x11,
- kMethodType = 0x15,
- kMethodHandle = 0x16,
- kString = 0x17,
- kType = 0x18,
- kField = 0x19,
- kMethod = 0x1a,
- kEnum = 0x1b,
- kArray = 0x1c,
- kAnnotation = 0x1d,
- kNull = 0x1e,
- kBoolean = 0x1f,
- };
-
- ValueType GetValueType() const { return type_; }
- const jvalue& GetJavaValue() const { return jval_; }
-
- protected:
- static constexpr uint8_t kEncodedValueTypeMask = 0x1f; // 0b11111
- static constexpr uint8_t kEncodedValueArgShift = 5;
-
- const DexFile& dex_file_;
- size_t array_size_; // Size of array.
- size_t pos_; // Current position.
- const uint8_t* ptr_; // Pointer into encoded data array.
- ValueType type_; // Type of current encoded value.
- jvalue jval_; // Value of current encoded value.
-
- private:
- DISALLOW_IMPLICIT_CONSTRUCTORS(EncodedArrayValueIterator);
-};
-std::ostream& operator<<(std::ostream& os, const EncodedArrayValueIterator::ValueType& code);
-
-class EncodedStaticFieldValueIterator : public EncodedArrayValueIterator {
- public:
- EncodedStaticFieldValueIterator(const DexFile& dex_file,
- const DexFile::ClassDef& class_def)
- : EncodedArrayValueIterator(dex_file,
- dex_file.GetEncodedStaticFieldValuesArray(class_def))
- {}
-
- private:
- DISALLOW_IMPLICIT_CONSTRUCTORS(EncodedStaticFieldValueIterator);
-};
-std::ostream& operator<<(std::ostream& os, const EncodedStaticFieldValueIterator::ValueType& code);
-
-class CallSiteArrayValueIterator : public EncodedArrayValueIterator {
- public:
- CallSiteArrayValueIterator(const DexFile& dex_file,
- const DexFile::CallSiteIdItem& call_site_id)
- : EncodedArrayValueIterator(dex_file,
- dex_file.GetCallSiteEncodedValuesArray(call_site_id))
- {}
-
- uint32_t Size() const { return array_size_; }
-
- private:
- DISALLOW_IMPLICIT_CONSTRUCTORS(CallSiteArrayValueIterator);
-};
-std::ostream& operator<<(std::ostream& os, const CallSiteArrayValueIterator::ValueType& code);
-
-} // namespace art
-
-#endif // ART_RUNTIME_DEX_DEX_FILE_H_
diff --git a/runtime/dex/dex_file_annotations.cc b/runtime/dex/dex_file_annotations.cc
index e01890f541..3431bb7efb 100644
--- a/runtime/dex/dex_file_annotations.cc
+++ b/runtime/dex/dex_file_annotations.cc
@@ -23,7 +23,7 @@
#include "art_field-inl.h"
#include "art_method-inl.h"
#include "class_linker-inl.h"
-#include "dex_file-inl.h"
+#include "dex/dex_file-inl.h"
#include "jni_internal.h"
#include "jvalue-inl.h"
#include "mirror/field.h"
diff --git a/runtime/dex/dex_file_annotations.h b/runtime/dex/dex_file_annotations.h
index 26773729c2..d7ebf84b1c 100644
--- a/runtime/dex/dex_file_annotations.h
+++ b/runtime/dex/dex_file_annotations.h
@@ -17,7 +17,7 @@
#ifndef ART_RUNTIME_DEX_DEX_FILE_ANNOTATIONS_H_
#define ART_RUNTIME_DEX_DEX_FILE_ANNOTATIONS_H_
-#include "dex_file.h"
+#include "dex/dex_file.h"
#include "handle.h"
#include "mirror/dex_cache.h"
diff --git a/runtime/dex/dex_file_exception_helpers.cc b/runtime/dex/dex_file_exception_helpers.cc
deleted file mode 100644
index 8e597fd3dd..0000000000
--- a/runtime/dex/dex_file_exception_helpers.cc
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "dex_file_exception_helpers.h"
-
-#include "code_item_accessors-inl.h"
-
-namespace art {
-
-CatchHandlerIterator::CatchHandlerIterator(const CodeItemDataAccessor& accessor, uint32_t address) {
- handler_.address_ = -1;
- int32_t offset = -1;
-
- // Short-circuit the overwhelmingly common cases.
- switch (accessor.TriesSize()) {
- case 0:
- break;
- case 1: {
- const DexFile::TryItem* tries = accessor.TryItems().begin();
- uint32_t start = tries->start_addr_;
- if (address >= start) {
- uint32_t end = start + tries->insn_count_;
- if (address < end) {
- offset = tries->handler_off_;
- }
- }
- break;
- }
- default: {
- const DexFile::TryItem* try_item = accessor.FindTryItem(address);
- offset = try_item != nullptr ? try_item->handler_off_ : -1;
- break;
- }
- }
- Init(accessor, offset);
-}
-
-CatchHandlerIterator::CatchHandlerIterator(const CodeItemDataAccessor& accessor,
- const DexFile::TryItem& try_item) {
- handler_.address_ = -1;
- Init(accessor, try_item.handler_off_);
-}
-
-void CatchHandlerIterator::Init(const CodeItemDataAccessor& accessor, int32_t offset) {
- if (offset >= 0) {
- Init(accessor.GetCatchHandlerData(offset));
- } else {
- // Not found, initialize as empty
- current_data_ = nullptr;
- remaining_count_ = -1;
- catch_all_ = false;
- DCHECK(!HasNext());
- }
-}
-
-void CatchHandlerIterator::Init(const uint8_t* handler_data) {
- current_data_ = handler_data;
- remaining_count_ = DecodeSignedLeb128(&current_data_);
-
- // If remaining_count_ is non-positive, then it is the negative of
- // the number of catch types, and the catches are followed by a
- // catch-all handler.
- if (remaining_count_ <= 0) {
- catch_all_ = true;
- remaining_count_ = -remaining_count_;
- } else {
- catch_all_ = false;
- }
- Next();
-}
-
-void CatchHandlerIterator::Next() {
- if (remaining_count_ > 0) {
- handler_.type_idx_ = dex::TypeIndex(DecodeUnsignedLeb128(&current_data_));
- handler_.address_ = DecodeUnsignedLeb128(&current_data_);
- remaining_count_--;
- return;
- }
-
- if (catch_all_) {
- handler_.type_idx_ = dex::TypeIndex(DexFile::kDexNoIndex16);
- handler_.address_ = DecodeUnsignedLeb128(&current_data_);
- catch_all_ = false;
- return;
- }
-
- // no more handler
- remaining_count_ = -1;
-}
-
-} // namespace art
diff --git a/runtime/dex/dex_file_exception_helpers.h b/runtime/dex/dex_file_exception_helpers.h
deleted file mode 100644
index bd6cb7e747..0000000000
--- a/runtime/dex/dex_file_exception_helpers.h
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ART_RUNTIME_DEX_DEX_FILE_EXCEPTION_HELPERS_H_
-#define ART_RUNTIME_DEX_DEX_FILE_EXCEPTION_HELPERS_H_
-
-#include "dex_file.h"
-
-namespace art {
-
-class CodeItemDataAccessor;
-
-class CatchHandlerIterator {
- public:
- CatchHandlerIterator(const CodeItemDataAccessor& accessor, uint32_t address);
-
- CatchHandlerIterator(const CodeItemDataAccessor& accessor, const DexFile::TryItem& try_item);
-
- explicit CatchHandlerIterator(const uint8_t* handler_data) {
- Init(handler_data);
- }
-
- dex::TypeIndex GetHandlerTypeIndex() const {
- return handler_.type_idx_;
- }
- uint32_t GetHandlerAddress() const {
- return handler_.address_;
- }
- void Next();
- bool HasNext() const {
- return remaining_count_ != -1 || catch_all_;
- }
- // End of this set of catch blocks, convenience method to locate next set of catch blocks
- const uint8_t* EndDataPointer() const {
- CHECK(!HasNext());
- return current_data_;
- }
-
- private:
- void Init(const CodeItemDataAccessor& accessor, int32_t offset);
- void Init(const uint8_t* handler_data);
-
- struct CatchHandlerItem {
- dex::TypeIndex type_idx_; // type index of the caught exception type
- uint32_t address_; // handler address
- } handler_;
- const uint8_t* current_data_; // the current handler in dex file.
- int32_t remaining_count_; // number of handlers not read.
- bool catch_all_; // is there a handler that will catch all exceptions in case
- // that all typed handler does not match.
-};
-
-} // namespace art
-
-#endif // ART_RUNTIME_DEX_DEX_FILE_EXCEPTION_HELPERS_H_
diff --git a/runtime/dex/dex_file_layout.cc b/runtime/dex/dex_file_layout.cc
index 312898d82f..d85d61d56b 100644
--- a/runtime/dex/dex_file_layout.cc
+++ b/runtime/dex/dex_file_layout.cc
@@ -19,8 +19,7 @@
#include <sys/mman.h>
#include "base/file_utils.h"
-#include "descriptors_names.h"
-#include "dex_file.h"
+#include "dex/dex_file.h"
namespace art {
diff --git a/runtime/dex/dex_file_loader.cc b/runtime/dex/dex_file_loader.cc
deleted file mode 100644
index 2c75c5b5d9..0000000000
--- a/runtime/dex/dex_file_loader.cc
+++ /dev/null
@@ -1,501 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "dex_file_loader.h"
-
-#include "android-base/stringprintf.h"
-
-#include "base/stl_util.h"
-#include "compact_dex_file.h"
-#include "dex_file.h"
-#include "dex_file_verifier.h"
-#include "standard_dex_file.h"
-#include "ziparchive/zip_archive.h"
-
-// system/core/zip_archive definitions.
-struct ZipEntry;
-typedef void* ZipArchiveHandle;
-
-namespace art {
-
-namespace {
-
-class VectorContainer : public DexFileContainer {
- public:
- explicit VectorContainer(std::vector<uint8_t>&& vector) : vector_(std::move(vector)) { }
- virtual ~VectorContainer() OVERRIDE { }
-
- int GetPermissions() OVERRIDE {
- return 0;
- }
-
- bool IsReadOnly() OVERRIDE {
- return true;
- }
-
- bool EnableWrite() OVERRIDE {
- return false;
- }
-
- bool DisableWrite() OVERRIDE {
- return false;
- }
-
- private:
- std::vector<uint8_t> vector_;
- DISALLOW_COPY_AND_ASSIGN(VectorContainer);
-};
-
-} // namespace
-
-using android::base::StringPrintf;
-
-class DexZipArchive;
-
-class DexZipEntry {
- public:
- // Extract this entry to memory.
- // Returns null on failure and sets error_msg.
- const std::vector<uint8_t> Extract(std::string* error_msg) {
- std::vector<uint8_t> map(GetUncompressedLength());
- if (map.size() == 0) {
- DCHECK(!error_msg->empty());
- return map;
- }
- const int32_t error = ExtractToMemory(handle_, zip_entry_, map.data(), map.size());
- if (error) {
- *error_msg = std::string(ErrorCodeString(error));
- }
- return map;
- }
-
- virtual ~DexZipEntry() {
- delete zip_entry_;
- }
-
- uint32_t GetUncompressedLength() {
- return zip_entry_->uncompressed_length;
- }
-
- uint32_t GetCrc32() {
- return zip_entry_->crc32;
- }
-
- private:
- DexZipEntry(ZipArchiveHandle handle,
- ::ZipEntry* zip_entry,
- const std::string& entry_name)
- : handle_(handle), zip_entry_(zip_entry), entry_name_(entry_name) {}
-
- ZipArchiveHandle handle_;
- ::ZipEntry* const zip_entry_;
- std::string const entry_name_;
-
- friend class DexZipArchive;
- DISALLOW_COPY_AND_ASSIGN(DexZipEntry);
-};
-
-class DexZipArchive {
- public:
- // return new DexZipArchive instance on success, null on error.
- static DexZipArchive* Open(const uint8_t* base, size_t size, std::string* error_msg) {
- ZipArchiveHandle handle;
- uint8_t* nonconst_base = const_cast<uint8_t*>(base);
- const int32_t error = OpenArchiveFromMemory(nonconst_base, size, "ZipArchiveMemory", &handle);
- if (error) {
- *error_msg = std::string(ErrorCodeString(error));
- CloseArchive(handle);
- return nullptr;
- }
- return new DexZipArchive(handle);
- }
-
- DexZipEntry* Find(const char* name, std::string* error_msg) const {
- DCHECK(name != nullptr);
- // Resist the urge to delete the space. <: is a bigraph sequence.
- std::unique_ptr< ::ZipEntry> zip_entry(new ::ZipEntry);
- const int32_t error = FindEntry(handle_, ZipString(name), zip_entry.get());
- if (error) {
- *error_msg = std::string(ErrorCodeString(error));
- return nullptr;
- }
- return new DexZipEntry(handle_, zip_entry.release(), name);
- }
-
- ~DexZipArchive() {
- CloseArchive(handle_);
- }
-
-
- private:
- explicit DexZipArchive(ZipArchiveHandle handle) : handle_(handle) {}
- ZipArchiveHandle handle_;
-
- friend class DexZipEntry;
- DISALLOW_COPY_AND_ASSIGN(DexZipArchive);
-};
-
-static bool IsZipMagic(uint32_t magic) {
- return (('P' == ((magic >> 0) & 0xff)) &&
- ('K' == ((magic >> 8) & 0xff)));
-}
-
-bool DexFileLoader::IsMagicValid(uint32_t magic) {
- return IsMagicValid(reinterpret_cast<uint8_t*>(&magic));
-}
-
-bool DexFileLoader::IsMagicValid(const uint8_t* magic) {
- return StandardDexFile::IsMagicValid(magic) ||
- CompactDexFile::IsMagicValid(magic);
-}
-
-bool DexFileLoader::IsVersionAndMagicValid(const uint8_t* magic) {
- if (StandardDexFile::IsMagicValid(magic)) {
- return StandardDexFile::IsVersionValid(magic);
- }
- if (CompactDexFile::IsMagicValid(magic)) {
- return CompactDexFile::IsVersionValid(magic);
- }
- return false;
-}
-
-bool DexFileLoader::IsMultiDexLocation(const char* location) {
- return strrchr(location, kMultiDexSeparator) != nullptr;
-}
-
-std::string DexFileLoader::GetMultiDexClassesDexName(size_t index) {
- return (index == 0) ? "classes.dex" : StringPrintf("classes%zu.dex", index + 1);
-}
-
-std::string DexFileLoader::GetMultiDexLocation(size_t index, const char* dex_location) {
- return (index == 0)
- ? dex_location
- : StringPrintf("%s%cclasses%zu.dex", dex_location, kMultiDexSeparator, index + 1);
-}
-
-std::string DexFileLoader::GetDexCanonicalLocation(const char* dex_location) {
- CHECK_NE(dex_location, static_cast<const char*>(nullptr));
- std::string base_location = GetBaseLocation(dex_location);
- const char* suffix = dex_location + base_location.size();
- DCHECK(suffix[0] == 0 || suffix[0] == kMultiDexSeparator);
- UniqueCPtr<const char[]> path(realpath(base_location.c_str(), nullptr));
- if (path != nullptr && path.get() != base_location) {
- return std::string(path.get()) + suffix;
- } else if (suffix[0] == 0) {
- return base_location;
- } else {
- return dex_location;
- }
-}
-
-// All of the implementations here should be independent of the runtime.
-// TODO: implement all the virtual methods.
-
-bool DexFileLoader::GetMultiDexChecksums(const char* filename ATTRIBUTE_UNUSED,
- std::vector<uint32_t>* checksums ATTRIBUTE_UNUSED,
- std::string* error_msg,
- int zip_fd ATTRIBUTE_UNUSED) const {
- *error_msg = "UNIMPLEMENTED";
- return false;
-}
-
-std::unique_ptr<const DexFile> DexFileLoader::Open(const uint8_t* base,
- size_t size,
- const std::string& location,
- uint32_t location_checksum,
- const OatDexFile* oat_dex_file,
- bool verify,
- bool verify_checksum,
- std::string* error_msg) const {
- return OpenCommon(base,
- size,
- /*data_base*/ nullptr,
- /*data_size*/ 0,
- location,
- location_checksum,
- oat_dex_file,
- verify,
- verify_checksum,
- error_msg,
- /*container*/ nullptr,
- /*verify_result*/ nullptr);
-}
-
-std::unique_ptr<const DexFile> DexFileLoader::OpenWithDataSection(
- const uint8_t* base,
- size_t size,
- const uint8_t* data_base,
- size_t data_size,
- const std::string& location,
- uint32_t location_checksum,
- const OatDexFile* oat_dex_file,
- bool verify,
- bool verify_checksum,
- std::string* error_msg) const {
- return OpenCommon(base,
- size,
- data_base,
- data_size,
- location,
- location_checksum,
- oat_dex_file,
- verify,
- verify_checksum,
- error_msg,
- /*container*/ nullptr,
- /*verify_result*/ nullptr);
-}
-
-bool DexFileLoader::OpenAll(
- const uint8_t* base,
- size_t size,
- const std::string& location,
- bool verify,
- bool verify_checksum,
- std::string* error_msg,
- std::vector<std::unique_ptr<const DexFile>>* dex_files) const {
- DCHECK(dex_files != nullptr) << "DexFile::Open: out-param is nullptr";
- uint32_t magic = *reinterpret_cast<const uint32_t*>(base);
- if (IsZipMagic(magic)) {
- std::unique_ptr<DexZipArchive> zip_archive(DexZipArchive::Open(base, size, error_msg));
- if (zip_archive.get() == nullptr) {
- DCHECK(!error_msg->empty());
- return false;
- }
- return OpenAllDexFilesFromZip(*zip_archive.get(),
- location,
- verify,
- verify_checksum,
- error_msg,
- dex_files);
- }
- if (IsMagicValid(magic)) {
- const DexFile::Header* dex_header = reinterpret_cast<const DexFile::Header*>(base);
- std::unique_ptr<const DexFile> dex_file(Open(base,
- size,
- location,
- dex_header->checksum_,
- /*oat_dex_file*/ nullptr,
- verify,
- verify_checksum,
- error_msg));
- if (dex_file.get() != nullptr) {
- dex_files->push_back(std::move(dex_file));
- return true;
- } else {
- return false;
- }
- }
- *error_msg = StringPrintf("Expected valid zip or dex file");
- return false;
-}
-
-std::unique_ptr<DexFile> DexFileLoader::OpenCommon(const uint8_t* base,
- size_t size,
- const uint8_t* data_base,
- size_t data_size,
- const std::string& location,
- uint32_t location_checksum,
- const OatDexFile* oat_dex_file,
- bool verify,
- bool verify_checksum,
- std::string* error_msg,
- DexFileContainer* container,
- VerifyResult* verify_result) {
- if (verify_result != nullptr) {
- *verify_result = VerifyResult::kVerifyNotAttempted;
- }
- std::unique_ptr<DexFile> dex_file;
- if (size >= sizeof(StandardDexFile::Header) && StandardDexFile::IsMagicValid(base)) {
- if (data_size != 0) {
- CHECK_EQ(base, data_base) << "Unsupported for standard dex";
- }
- dex_file.reset(new StandardDexFile(base,
- size,
- location,
- location_checksum,
- oat_dex_file,
- container));
- } else if (size >= sizeof(CompactDexFile::Header) && CompactDexFile::IsMagicValid(base)) {
- if (data_base == nullptr) {
- // TODO: Is there a clean way to support both an explicit data section and reading the one
- // from the header.
- CHECK_EQ(data_size, 0u);
- const CompactDexFile::Header* const header = CompactDexFile::Header::At(base);
- data_base = base + header->data_off_;
- data_size = header->data_size_;
- }
- dex_file.reset(new CompactDexFile(base,
- size,
- data_base,
- data_size,
- location,
- location_checksum,
- oat_dex_file,
- container));
- } else {
- *error_msg = "Invalid or truncated dex file";
- }
- if (dex_file == nullptr) {
- *error_msg = StringPrintf("Failed to open dex file '%s' from memory: %s", location.c_str(),
- error_msg->c_str());
- return nullptr;
- }
- if (!dex_file->Init(error_msg)) {
- dex_file.reset();
- return nullptr;
- }
- if (verify && !DexFileVerifier::Verify(dex_file.get(),
- dex_file->Begin(),
- dex_file->Size(),
- location.c_str(),
- verify_checksum,
- error_msg)) {
- if (verify_result != nullptr) {
- *verify_result = VerifyResult::kVerifyFailed;
- }
- return nullptr;
- }
- if (verify_result != nullptr) {
- *verify_result = VerifyResult::kVerifySucceeded;
- }
- return dex_file;
-}
-
-std::unique_ptr<const DexFile> DexFileLoader::OpenOneDexFileFromZip(
- const DexZipArchive& zip_archive,
- const char* entry_name,
- const std::string& location,
- bool verify,
- bool verify_checksum,
- std::string* error_msg,
- ZipOpenErrorCode* error_code) const {
- CHECK(!location.empty());
- std::unique_ptr<DexZipEntry> zip_entry(zip_archive.Find(entry_name, error_msg));
- if (zip_entry == nullptr) {
- *error_code = ZipOpenErrorCode::kEntryNotFound;
- return nullptr;
- }
- if (zip_entry->GetUncompressedLength() == 0) {
- *error_msg = StringPrintf("Dex file '%s' has zero length", location.c_str());
- *error_code = ZipOpenErrorCode::kDexFileError;
- return nullptr;
- }
-
- std::vector<uint8_t> map(zip_entry->Extract(error_msg));
- if (map.size() == 0) {
- *error_msg = StringPrintf("Failed to extract '%s' from '%s': %s", entry_name, location.c_str(),
- error_msg->c_str());
- *error_code = ZipOpenErrorCode::kExtractToMemoryError;
- return nullptr;
- }
- VerifyResult verify_result;
- std::unique_ptr<const DexFile> dex_file = OpenCommon(map.data(),
- map.size(),
- /*data_base*/ nullptr,
- /*data_size*/ 0u,
- location,
- zip_entry->GetCrc32(),
- /*oat_dex_file*/ nullptr,
- verify,
- verify_checksum,
- error_msg,
- new VectorContainer(std::move(map)),
- &verify_result);
- if (dex_file == nullptr) {
- if (verify_result == VerifyResult::kVerifyNotAttempted) {
- *error_code = ZipOpenErrorCode::kDexFileError;
- } else {
- *error_code = ZipOpenErrorCode::kVerifyError;
- }
- return nullptr;
- }
- if (verify_result != VerifyResult::kVerifySucceeded) {
- *error_code = ZipOpenErrorCode::kVerifyError;
- return nullptr;
- }
- *error_code = ZipOpenErrorCode::kNoError;
- return dex_file;
-}
-
-// Technically we do not have a limitation with respect to the number of dex files that can be in a
-// multidex APK. However, it's bad practice, as each dex file requires its own tables for symbols
-// (types, classes, methods, ...) and dex caches. So warn the user that we open a zip with what
-// seems an excessive number.
-static constexpr size_t kWarnOnManyDexFilesThreshold = 100;
-
-bool DexFileLoader::OpenAllDexFilesFromZip(
- const DexZipArchive& zip_archive,
- const std::string& location,
- bool verify,
- bool verify_checksum,
- std::string* error_msg,
- std::vector<std::unique_ptr<const DexFile>>* dex_files) const {
- DCHECK(dex_files != nullptr) << "DexFile::OpenFromZip: out-param is nullptr";
- ZipOpenErrorCode error_code;
- std::unique_ptr<const DexFile> dex_file(OpenOneDexFileFromZip(zip_archive,
- kClassesDex,
- location,
- verify,
- verify_checksum,
- error_msg,
- &error_code));
- if (dex_file.get() == nullptr) {
- return false;
- } else {
- // Had at least classes.dex.
- dex_files->push_back(std::move(dex_file));
-
- // Now try some more.
-
- // We could try to avoid std::string allocations by working on a char array directly. As we
- // do not expect a lot of iterations, this seems too involved and brittle.
-
- for (size_t i = 1; ; ++i) {
- std::string name = GetMultiDexClassesDexName(i);
- std::string fake_location = GetMultiDexLocation(i, location.c_str());
- std::unique_ptr<const DexFile> next_dex_file(OpenOneDexFileFromZip(zip_archive,
- name.c_str(),
- fake_location,
- verify,
- verify_checksum,
- error_msg,
- &error_code));
- if (next_dex_file.get() == nullptr) {
- if (error_code != ZipOpenErrorCode::kEntryNotFound) {
- LOG(WARNING) << "Zip open failed: " << *error_msg;
- }
- break;
- } else {
- dex_files->push_back(std::move(next_dex_file));
- }
-
- if (i == kWarnOnManyDexFilesThreshold) {
- LOG(WARNING) << location << " has in excess of " << kWarnOnManyDexFilesThreshold
- << " dex files. Please consider coalescing and shrinking the number to "
- " avoid runtime overhead.";
- }
-
- if (i == std::numeric_limits<size_t>::max()) {
- LOG(ERROR) << "Overflow in number of dex files!";
- break;
- }
- }
-
- return true;
- }
-}
-} // namespace art
diff --git a/runtime/dex/dex_file_loader.h b/runtime/dex/dex_file_loader.h
deleted file mode 100644
index 508397cb00..0000000000
--- a/runtime/dex/dex_file_loader.h
+++ /dev/null
@@ -1,198 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ART_RUNTIME_DEX_DEX_FILE_LOADER_H_
-#define ART_RUNTIME_DEX_DEX_FILE_LOADER_H_
-
-#include <cstdint>
-#include <memory>
-#include <string>
-#include <vector>
-
-namespace art {
-
-class DexFile;
-class DexFileContainer;
-class MemMap;
-class OatDexFile;
-
-class DexZipArchive;
-
-// Class that is used to open dex files and deal with corresponding multidex and location logic.
-class DexFileLoader {
- public:
- // name of the DexFile entry within a zip archive
- static constexpr const char* kClassesDex = "classes.dex";
-
- // The separator character in MultiDex locations.
- static constexpr char kMultiDexSeparator = '!';
-
- // Return true if the magic is valid for dex or cdex.
- static bool IsMagicValid(uint32_t magic);
- static bool IsMagicValid(const uint8_t* magic);
-
- // Return true if the corresponding version and magic is valid.
- static bool IsVersionAndMagicValid(const uint8_t* magic);
-
- // Check whether a location denotes a multidex dex file. This is a very simple check: returns
- // whether the string contains the separator character.
- static bool IsMultiDexLocation(const char* location);
-
- // Return the name of the index-th classes.dex in a multidex zip file. This is classes.dex for
- // index == 0, and classes{index + 1}.dex else.
- static std::string GetMultiDexClassesDexName(size_t index);
-
- // Return the (possibly synthetic) dex location for a multidex entry. This is dex_location for
- // index == 0, and dex_location + multi-dex-separator + GetMultiDexClassesDexName(index) else.
- static std::string GetMultiDexLocation(size_t index, const char* dex_location);
-
- // Returns the canonical form of the given dex location.
- //
- // There are different flavors of "dex locations" as follows:
- // the file name of a dex file:
- // The actual file path that the dex file has on disk.
- // dex_location:
- // This acts as a key for the class linker to know which dex file to load.
- // It may correspond to either an old odex file or a particular dex file
- // inside an oat file. In the first case it will also match the file name
- // of the dex file. In the second case (oat) it will include the file name
- // and possibly some multidex annotation to uniquely identify it.
- // canonical_dex_location:
- // the dex_location where it's file name part has been made canonical.
- static std::string GetDexCanonicalLocation(const char* dex_location);
-
- // For normal dex files, location and base location coincide. If a dex file is part of a multidex
- // archive, the base location is the name of the originating jar/apk, stripped of any internal
- // classes*.dex path.
- static std::string GetBaseLocation(const char* location) {
- const char* pos = strrchr(location, kMultiDexSeparator);
- return (pos == nullptr) ? location : std::string(location, pos - location);
- }
-
- static std::string GetBaseLocation(const std::string& location) {
- return GetBaseLocation(location.c_str());
- }
-
- // Returns the '!classes*.dex' part of the dex location. Returns an empty
- // string if there is no multidex suffix for the given location.
- // The kMultiDexSeparator is included in the returned suffix.
- static std::string GetMultiDexSuffix(const std::string& location) {
- size_t pos = location.rfind(kMultiDexSeparator);
- return (pos == std::string::npos) ? std::string() : location.substr(pos);
- }
-
- virtual ~DexFileLoader() { }
-
- // Returns the checksums of a file for comparison with GetLocationChecksum().
- // For .dex files, this is the single header checksum.
- // For zip files, this is the zip entry CRC32 checksum for classes.dex and
- // each additional multidex entry classes2.dex, classes3.dex, etc.
- // If a valid zip_fd is provided the file content will be read directly from
- // the descriptor and `filename` will be used as alias for error logging. If
- // zip_fd is -1, the method will try to open the `filename` and read the
- // content from it.
- // Return true if the checksums could be found, false otherwise.
- virtual bool GetMultiDexChecksums(const char* filename,
- std::vector<uint32_t>* checksums,
- std::string* error_msg,
- int zip_fd = -1) const;
-
- // Opens .dex file, backed by existing memory
- virtual std::unique_ptr<const DexFile> Open(const uint8_t* base,
- size_t size,
- const std::string& location,
- uint32_t location_checksum,
- const OatDexFile* oat_dex_file,
- bool verify,
- bool verify_checksum,
- std::string* error_msg) const;
-
- // Open a dex file with a separate data section.
- virtual std::unique_ptr<const DexFile> OpenWithDataSection(
- const uint8_t* base,
- size_t size,
- const uint8_t* data_base,
- size_t data_size,
- const std::string& location,
- uint32_t location_checksum,
- const OatDexFile* oat_dex_file,
- bool verify,
- bool verify_checksum,
- std::string* error_msg) const;
-
-
- // Opens all .dex files found in the memory map, guessing the container format based on file
- // extension.
- virtual bool OpenAll(const uint8_t* base,
- size_t size,
- const std::string& location,
- bool verify,
- bool verify_checksum,
- std::string* error_msg,
- std::vector<std::unique_ptr<const DexFile>>* dex_files) const;
-
- protected:
- enum class ZipOpenErrorCode {
- kNoError,
- kEntryNotFound,
- kExtractToMemoryError,
- kDexFileError,
- kMakeReadOnlyError,
- kVerifyError
- };
-
- enum class VerifyResult { // private
- kVerifyNotAttempted,
- kVerifySucceeded,
- kVerifyFailed
- };
-
- static std::unique_ptr<DexFile> OpenCommon(const uint8_t* base,
- size_t size,
- const uint8_t* data_base,
- size_t data_size,
- const std::string& location,
- uint32_t location_checksum,
- const OatDexFile* oat_dex_file,
- bool verify,
- bool verify_checksum,
- std::string* error_msg,
- DexFileContainer* container,
- VerifyResult* verify_result);
-
- private:
- // Open all classesXXX.dex files from a zip archive.
- bool OpenAllDexFilesFromZip(const DexZipArchive& zip_archive,
- const std::string& location,
- bool verify,
- bool verify_checksum,
- std::string* error_msg,
- std::vector<std::unique_ptr<const DexFile>>* dex_files) const;
-
- // Opens .dex file from the entry_name in a zip archive. error_code is undefined when non-null
- // return.
- std::unique_ptr<const DexFile> OpenOneDexFileFromZip(const DexZipArchive& zip_archive,
- const char* entry_name,
- const std::string& location,
- bool verify,
- bool verify_checksum,
- std::string* error_msg,
- ZipOpenErrorCode* error_code) const;
-};
-
-} // namespace art
-
-#endif // ART_RUNTIME_DEX_DEX_FILE_LOADER_H_
diff --git a/runtime/dex/dex_file_reference.h b/runtime/dex/dex_file_reference.h
deleted file mode 100644
index 6f882900c6..0000000000
--- a/runtime/dex/dex_file_reference.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ART_RUNTIME_DEX_DEX_FILE_REFERENCE_H_
-#define ART_RUNTIME_DEX_DEX_FILE_REFERENCE_H_
-
-#include <cstdint>
-
-namespace art {
-
-class DexFile;
-
-class DexFileReference {
- public:
- DexFileReference(const DexFile* file, uint32_t idx) : dex_file(file), index(idx) {}
- const DexFile* dex_file;
- uint32_t index;
-
- struct Comparator {
- bool operator()(const DexFileReference& a, const DexFileReference& b) const {
- if (a.dex_file != b.dex_file) {
- return a.dex_file < b.dex_file;
- }
- return a.index < b.index;
- }
- };
-};
-
-// Default comparators, compares the indicies, not the backing data.
-inline bool operator<(const DexFileReference& a, const DexFileReference& b) {
- return DexFileReference::Comparator()(a, b);
-}
-inline bool operator==(const DexFileReference& a, const DexFileReference& b) {
- return a.dex_file == b.dex_file && a.index == b.index;
-}
-
-} // namespace art
-
-#endif // ART_RUNTIME_DEX_DEX_FILE_REFERENCE_H_
diff --git a/runtime/dex/dex_file_test.cc b/runtime/dex/dex_file_test.cc
deleted file mode 100644
index 2bb86672dc..0000000000
--- a/runtime/dex/dex_file_test.cc
+++ /dev/null
@@ -1,749 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "dex_file.h"
-
-#include <sys/mman.h>
-
-#include <memory>
-
-#include "art_dex_file_loader.h"
-#include "base/stl_util.h"
-#include "base/unix_file/fd_file.h"
-#include "base64_test_util.h"
-#include "code_item_accessors-inl.h"
-#include "common_runtime_test.h"
-#include "descriptors_names.h"
-#include "dex_file-inl.h"
-#include "dex_file_loader.h"
-#include "mem_map.h"
-#include "os.h"
-#include "scoped_thread_state_change-inl.h"
-#include "thread-current-inl.h"
-
-namespace art {
-
-class DexFileTest : public CommonRuntimeTest {};
-
-TEST_F(DexFileTest, Open) {
- ScopedObjectAccess soa(Thread::Current());
- std::unique_ptr<const DexFile> dex(OpenTestDexFile("Nested"));
- ASSERT_TRUE(dex.get() != nullptr);
-}
-
-static inline std::vector<uint8_t> DecodeBase64Vec(const char* src) {
- std::vector<uint8_t> res;
- size_t size;
- std::unique_ptr<uint8_t[]> data(DecodeBase64(src, &size));
- res.resize(size);
- memcpy(res.data(), data.get(), size);
- return res;
-}
-
-// Although this is the same content logically as the Nested test dex,
-// the DexFileHeader test is sensitive to subtle changes in the
-// contents due to the checksum etc, so we embed the exact input here.
-//
-// class Nested {
-// class Inner {
-// }
-// }
-static const char kRawDex[] =
- "ZGV4CjAzNQAQedgAe7gM1B/WHsWJ6L7lGAISGC7yjD2IAwAAcAAAAHhWNBIAAAAAAAAAAMQCAAAP"
- "AAAAcAAAAAcAAACsAAAAAgAAAMgAAAABAAAA4AAAAAMAAADoAAAAAgAAAAABAABIAgAAQAEAAK4B"
- "AAC2AQAAvQEAAM0BAADXAQAA+wEAABsCAAA+AgAAUgIAAF8CAABiAgAAZgIAAHMCAAB5AgAAgQIA"
- "AAIAAAADAAAABAAAAAUAAAAGAAAABwAAAAkAAAAJAAAABgAAAAAAAAAKAAAABgAAAKgBAAAAAAEA"
- "DQAAAAAAAQAAAAAAAQAAAAAAAAAFAAAAAAAAAAAAAAAAAAAABQAAAAAAAAAIAAAAiAEAAKsCAAAA"
- "AAAAAQAAAAAAAAAFAAAAAAAAAAgAAACYAQAAuAIAAAAAAAACAAAAlAIAAJoCAAABAAAAowIAAAIA"
- "AgABAAAAiAIAAAYAAABbAQAAcBACAAAADgABAAEAAQAAAI4CAAAEAAAAcBACAAAADgBAAQAAAAAA"
- "AAAAAAAAAAAATAEAAAAAAAAAAAAAAAAAAAEAAAABAAY8aW5pdD4ABUlubmVyAA5MTmVzdGVkJElu"
- "bmVyOwAITE5lc3RlZDsAIkxkYWx2aWsvYW5ub3RhdGlvbi9FbmNsb3NpbmdDbGFzczsAHkxkYWx2"
- "aWsvYW5ub3RhdGlvbi9Jbm5lckNsYXNzOwAhTGRhbHZpay9hbm5vdGF0aW9uL01lbWJlckNsYXNz"
- "ZXM7ABJMamF2YS9sYW5nL09iamVjdDsAC05lc3RlZC5qYXZhAAFWAAJWTAALYWNjZXNzRmxhZ3MA"
- "BG5hbWUABnRoaXMkMAAFdmFsdWUAAgEABw4AAQAHDjwAAgIBDhgBAgMCCwQADBcBAgQBDhwBGAAA"
- "AQEAAJAgAICABNQCAAABAAGAgATwAgAAEAAAAAAAAAABAAAAAAAAAAEAAAAPAAAAcAAAAAIAAAAH"
- "AAAArAAAAAMAAAACAAAAyAAAAAQAAAABAAAA4AAAAAUAAAADAAAA6AAAAAYAAAACAAAAAAEAAAMQ"
- "AAACAAAAQAEAAAEgAAACAAAAVAEAAAYgAAACAAAAiAEAAAEQAAABAAAAqAEAAAIgAAAPAAAArgEA"
- "AAMgAAACAAAAiAIAAAQgAAADAAAAlAIAAAAgAAACAAAAqwIAAAAQAAABAAAAxAIAAA==";
-
-// kRawDex{38,39,40,41} are dex'ed versions of the following Java source :
-//
-// public class Main {
-// public static void main(String[] foo) {
-// }
-// }
-//
-// The dex file was manually edited to change its dex version code to 38
-// or 39, respectively.
-static const char kRawDex38[] =
- "ZGV4CjAzOAC4OovJlJ1089ikzK6asMf/f8qp3Kve5VsgAgAAcAAAAHhWNBIAAAAAAAAAAIwBAAAI"
- "AAAAcAAAAAQAAACQAAAAAgAAAKAAAAAAAAAAAAAAAAMAAAC4AAAAAQAAANAAAAAwAQAA8AAAACIB"
- "AAAqAQAAMgEAAEYBAABRAQAAVAEAAFgBAABtAQAAAQAAAAIAAAAEAAAABgAAAAQAAAACAAAAAAAA"
- "AAUAAAACAAAAHAEAAAAAAAAAAAAAAAABAAcAAAABAAAAAAAAAAAAAAABAAAAAQAAAAAAAAADAAAA"
- "AAAAAH4BAAAAAAAAAQABAAEAAABzAQAABAAAAHAQAgAAAA4AAQABAAAAAAB4AQAAAQAAAA4AAAAB"
- "AAAAAwAGPGluaXQ+AAZMTWFpbjsAEkxqYXZhL2xhbmcvT2JqZWN0OwAJTWFpbi5qYXZhAAFWAAJW"
- "TAATW0xqYXZhL2xhbmcvU3RyaW5nOwAEbWFpbgABAAcOAAMBAAcOAAAAAgAAgYAE8AEBCYgCDAAA"
- "AAAAAAABAAAAAAAAAAEAAAAIAAAAcAAAAAIAAAAEAAAAkAAAAAMAAAACAAAAoAAAAAUAAAADAAAA"
- "uAAAAAYAAAABAAAA0AAAAAEgAAACAAAA8AAAAAEQAAABAAAAHAEAAAIgAAAIAAAAIgEAAAMgAAAC"
- "AAAAcwEAAAAgAAABAAAAfgEAAAAQAAABAAAAjAEAAA==";
-
-static const char kRawDex39[] =
- "ZGV4CjAzOQC4OovJlJ1089ikzK6asMf/f8qp3Kve5VsgAgAAcAAAAHhWNBIAAAAAAAAAAIwBAAAI"
- "AAAAcAAAAAQAAACQAAAAAgAAAKAAAAAAAAAAAAAAAAMAAAC4AAAAAQAAANAAAAAwAQAA8AAAACIB"
- "AAAqAQAAMgEAAEYBAABRAQAAVAEAAFgBAABtAQAAAQAAAAIAAAAEAAAABgAAAAQAAAACAAAAAAAA"
- "AAUAAAACAAAAHAEAAAAAAAAAAAAAAAABAAcAAAABAAAAAAAAAAAAAAABAAAAAQAAAAAAAAADAAAA"
- "AAAAAH4BAAAAAAAAAQABAAEAAABzAQAABAAAAHAQAgAAAA4AAQABAAAAAAB4AQAAAQAAAA4AAAAB"
- "AAAAAwAGPGluaXQ+AAZMTWFpbjsAEkxqYXZhL2xhbmcvT2JqZWN0OwAJTWFpbi5qYXZhAAFWAAJW"
- "TAATW0xqYXZhL2xhbmcvU3RyaW5nOwAEbWFpbgABAAcOAAMBAAcOAAAAAgAAgYAE8AEBCYgCDAAA"
- "AAAAAAABAAAAAAAAAAEAAAAIAAAAcAAAAAIAAAAEAAAAkAAAAAMAAAACAAAAoAAAAAUAAAADAAAA"
- "uAAAAAYAAAABAAAA0AAAAAEgAAACAAAA8AAAAAEQAAABAAAAHAEAAAIgAAAIAAAAIgEAAAMgAAAC"
- "AAAAcwEAAAAgAAABAAAAfgEAAAAQAAABAAAAjAEAAA==";
-
-static const char kRawDex40[] =
- "ZGV4CjA0MAC4OovJlJ1089ikzK6asMf/f8qp3Kve5VsgAgAAcAAAAHhWNBIAAAAAAAAAAIwBAAAI"
- "AAAAcAAAAAQAAACQAAAAAgAAAKAAAAAAAAAAAAAAAAMAAAC4AAAAAQAAANAAAAAwAQAA8AAAACIB"
- "AAAqAQAAMgEAAEYBAABRAQAAVAEAAFgBAABtAQAAAQAAAAIAAAAEAAAABgAAAAQAAAACAAAAAAAA"
- "AAUAAAACAAAAHAEAAAAAAAAAAAAAAAABAAcAAAABAAAAAAAAAAAAAAABAAAAAQAAAAAAAAADAAAA"
- "AAAAAH4BAAAAAAAAAQABAAEAAABzAQAABAAAAHAQAgAAAA4AAQABAAAAAAB4AQAAAQAAAA4AAAAB"
- "AAAAAwAGPGluaXQ+AAZMTWFpbjsAEkxqYXZhL2xhbmcvT2JqZWN0OwAJTWFpbi5qYXZhAAFWAAJW"
- "TAATW0xqYXZhL2xhbmcvU3RyaW5nOwAEbWFpbgABAAcOAAMBAAcOAAAAAgAAgYAE8AEBCYgCDAAA"
- "AAAAAAABAAAAAAAAAAEAAAAIAAAAcAAAAAIAAAAEAAAAkAAAAAMAAAACAAAAoAAAAAUAAAADAAAA"
- "uAAAAAYAAAABAAAA0AAAAAEgAAACAAAA8AAAAAEQAAABAAAAHAEAAAIgAAAIAAAAIgEAAAMgAAAC"
- "AAAAcwEAAAAgAAABAAAAfgEAAAAQAAABAAAAjAEAAA==";
-
-static const char kRawDex41[] =
- "ZGV4CjA0MQC4OovJlJ1089ikzK6asMf/f8qp3Kve5VsgAgAAcAAAAHhWNBIAAAAAAAAAAIwBAAAI"
- "AAAAcAAAAAQAAACQAAAAAgAAAKAAAAAAAAAAAAAAAAMAAAC4AAAAAQAAANAAAAAwAQAA8AAAACIB"
- "AAAqAQAAMgEAAEYBAABRAQAAVAEAAFgBAABtAQAAAQAAAAIAAAAEAAAABgAAAAQAAAACAAAAAAAA"
- "AAUAAAACAAAAHAEAAAAAAAAAAAAAAAABAAcAAAABAAAAAAAAAAAAAAABAAAAAQAAAAAAAAADAAAA"
- "AAAAAH4BAAAAAAAAAQABAAEAAABzAQAABAAAAHAQAgAAAA4AAQABAAAAAAB4AQAAAQAAAA4AAAAB"
- "AAAAAwAGPGluaXQ+AAZMTWFpbjsAEkxqYXZhL2xhbmcvT2JqZWN0OwAJTWFpbi5qYXZhAAFWAAJW"
- "TAATW0xqYXZhL2xhbmcvU3RyaW5nOwAEbWFpbgABAAcOAAMBAAcOAAAAAgAAgYAE8AEBCYgCDAAA"
- "AAAAAAABAAAAAAAAAAEAAAAIAAAAcAAAAAIAAAAEAAAAkAAAAAMAAAACAAAAoAAAAAUAAAADAAAA"
- "uAAAAAYAAAABAAAA0AAAAAEgAAACAAAA8AAAAAEQAAABAAAAHAEAAAIgAAAIAAAAIgEAAAMgAAAC"
- "AAAAcwEAAAAgAAABAAAAfgEAAAAQAAABAAAAjAEAAA==";
-
-static const char kRawDexZeroLength[] =
- "UEsDBAoAAAAAAOhxAkkAAAAAAAAAAAAAAAALABwAY2xhc3Nlcy5kZXhVVAkAA2QNoVdnDaFXdXgL"
- "AAEE5AMBAASIEwAAUEsBAh4DCgAAAAAA6HECSQAAAAAAAAAAAAAAAAsAGAAAAAAAAAAAAKCBAAAA"
- "AGNsYXNzZXMuZGV4VVQFAANkDaFXdXgLAAEE5AMBAASIEwAAUEsFBgAAAAABAAEAUQAAAEUAAAAA"
- "AA==";
-
-static const char kRawZipClassesDexPresent[] =
- "UEsDBBQAAAAIANVRN0ms99lIMQEAACACAAALABwAY2xhc3Nlcy5kZXhVVAkAAwFj5VcUY+VXdXgL"
- "AAEE5AMBAASIEwAAS0mt4DIwtmDYYdV9csrcks83lpxZN2vD8f/1p1beWX3vabQCEwNDAQMDQ0WY"
- "iRADFPQwMjBwMEDEWYB4AhADlTEsYEAAZiDeAcRApQwXgNgAyPgApJWAtBYQGwGxGxAHAnEIEEcA"
- "cS4jRD0T1Fw2KM0ENZMVypZhRLIIqIMdag9CBMFnhtJ1jDA5RrBcMSPE7AIBkIl8UFGgP6Fu4IOa"
- "wczAZpOZl1lix8Dm45uYmWfNIOSTlViWqJ+TmJeu75+UlZpcYs3ACZLSA4kzMIYxMIX5MAhHIykL"
- "LinKzEu3ZmDJBSoDOZiPgRlMgv3T2MDygZGRs4OJB8n9MBoWzrAwmQD1Eyy8WZHCmg0pvBkVIGpA"
- "Yc4oABEHhRuTAsRMUDwwQ9WAwoJBAaIGHE5Q9aB4BgBQSwECHgMUAAAACADVUTdJrPfZSDEBAAAg"
- "AgAACwAYAAAAAAAAAAAAoIEAAAAAY2xhc3Nlcy5kZXhVVAUAAwFj5Vd1eAsAAQTkAwEABIgTAABQ"
- "SwUGAAAAAAEAAQBRAAAAdgEAAAAA";
-
-static const char kRawZipClassesDexAbsent[] =
- "UEsDBBQAAAAIANVRN0ms99lIMQEAACACAAAOABwAbm90Y2xhc3Nlcy5kZXhVVAkAAwFj5VcUY+VX"
- "dXgLAAEE5AMBAASIEwAAS0mt4DIwtmDYYdV9csrcks83lpxZN2vD8f/1p1beWX3vabQCEwNDAQMD"
- "Q0WYiRADFPQwMjBwMEDEWYB4AhADlTEsYEAAZiDeAcRApQwXgNgAyPgApJWAtBYQGwGxGxAHAnEI"
- "EEcAcS4jRD0T1Fw2KM0ENZMVypZhRLIIqIMdag9CBMFnhtJ1jDA5RrBcMSPE7AIBkIl8UFGgP6Fu"
- "4IOawczAZpOZl1lix8Dm45uYmWfNIOSTlViWqJ+TmJeu75+UlZpcYs3ACZLSA4kzMIYxMIX5MAhH"
- "IykLLinKzEu3ZmDJBSoDOZiPgRlMgv3T2MDygZGRs4OJB8n9MBoWzrAwmQD1Eyy8WZHCmg0pvBkV"
- "IGpAYc4oABEHhRuTAsRMUDwwQ9WAwoJBAaIGHE5Q9aB4BgBQSwECHgMUAAAACADVUTdJrPfZSDEB"
- "AAAgAgAADgAYAAAAAAAAAAAAoIEAAAAAbm90Y2xhc3Nlcy5kZXhVVAUAAwFj5Vd1eAsAAQTkAwEA"
- "BIgTAABQSwUGAAAAAAEAAQBUAAAAeQEAAAAA";
-
-static const char kRawZipThreeDexFiles[] =
- "UEsDBBQAAAAIAP1WN0ms99lIMQEAACACAAAMABwAY2xhc3NlczIuZGV4VVQJAAOtbOVXrWzlV3V4"
- "CwABBOQDAQAEiBMAAEtJreAyMLZg2GHVfXLK3JLPN5acWTdrw/H/9adW3ll972m0AhMDQwEDA0NF"
- "mIkQAxT0MDIwcDBAxFmAeAIQA5UxLGBAAGYg3gHEQKUMF4DYAMj4AKSVgLQWEBsBsRsQBwJxCBBH"
- "AHEuI0Q9E9RcNijNBDWTFcqWYUSyCKiDHWoPQgTBZ4bSdYwwOUawXDEjxOwCAZCJfFBRoD+hbuCD"
- "msHMwGaTmZdZYsfA5uObmJlnzSDkk5VYlqifk5iXru+flJWaXGLNwAmS0gOJMzCGMTCF+TAIRyMp"
- "Cy4pysxLt2ZgyQUqAzmYj4EZTIL909jA8oGRkbODiQfJ/TAaFs6wMJkA9RMsvFmRwpoNKbwZFSBq"
- "QGHOKAARB4UbkwLETFA8MEPVgMKCQQGiBhxOUPWgeAYAUEsDBBQAAAAIAABXN0ms99lIMQEAACAC"
- "AAAMABwAY2xhc3NlczMuZGV4VVQJAAOvbOVXr2zlV3V4CwABBOQDAQAEiBMAAEtJreAyMLZg2GHV"
- "fXLK3JLPN5acWTdrw/H/9adW3ll972m0AhMDQwEDA0NFmIkQAxT0MDIwcDBAxFmAeAIQA5UxLGBA"
- "AGYg3gHEQKUMF4DYAMj4AKSVgLQWEBsBsRsQBwJxCBBHAHEuI0Q9E9RcNijNBDWTFcqWYUSyCKiD"
- "HWoPQgTBZ4bSdYwwOUawXDEjxOwCAZCJfFBRoD+hbuCDmsHMwGaTmZdZYsfA5uObmJlnzSDkk5VY"
- "lqifk5iXru+flJWaXGLNwAmS0gOJMzCGMTCF+TAIRyMpCy4pysxLt2ZgyQUqAzmYj4EZTIL909jA"
- "8oGRkbODiQfJ/TAaFs6wMJkA9RMsvFmRwpoNKbwZFSBqQGHOKAARB4UbkwLETFA8MEPVgMKCQQGi"
- "BhxOUPWgeAYAUEsDBBQAAAAIANVRN0ms99lIMQEAACACAAALABwAY2xhc3Nlcy5kZXhVVAkAAwFj"
- "5VetbOVXdXgLAAEE5AMBAASIEwAAS0mt4DIwtmDYYdV9csrcks83lpxZN2vD8f/1p1beWX3vabQC"
- "EwNDAQMDQ0WYiRADFPQwMjBwMEDEWYB4AhADlTEsYEAAZiDeAcRApQwXgNgAyPgApJWAtBYQGwGx"
- "GxAHAnEIEEcAcS4jRD0T1Fw2KM0ENZMVypZhRLIIqIMdag9CBMFnhtJ1jDA5RrBcMSPE7AIBkIl8"
- "UFGgP6Fu4IOawczAZpOZl1lix8Dm45uYmWfNIOSTlViWqJ+TmJeu75+UlZpcYs3ACZLSA4kzMIYx"
- "MIX5MAhHIykLLinKzEu3ZmDJBSoDOZiPgRlMgv3T2MDygZGRs4OJB8n9MBoWzrAwmQD1Eyy8WZHC"
- "mg0pvBkVIGpAYc4oABEHhRuTAsRMUDwwQ9WAwoJBAaIGHE5Q9aB4BgBQSwECHgMUAAAACAD9VjdJ"
- "rPfZSDEBAAAgAgAADAAYAAAAAAAAAAAAoIEAAAAAY2xhc3NlczIuZGV4VVQFAAOtbOVXdXgLAAEE"
- "5AMBAASIEwAAUEsBAh4DFAAAAAgAAFc3Saz32UgxAQAAIAIAAAwAGAAAAAAAAAAAAKCBdwEAAGNs"
- "YXNzZXMzLmRleFVUBQADr2zlV3V4CwABBOQDAQAEiBMAAFBLAQIeAxQAAAAIANVRN0ms99lIMQEA"
- "ACACAAALABgAAAAAAAAAAACgge4CAABjbGFzc2VzLmRleFVUBQADAWPlV3V4CwABBOQDAQAEiBMA"
- "AFBLBQYAAAAAAwADAPUAAABkBAAAAAA=";
-
-static const char kRawDexBadMapOffset[] =
- "ZGV4CjAzNQAZKGSz85r+tXJ1I24FYi+FpQtWbXtelAmoAQAAcAAAAHhWNBIAAAAAAAAAAEAwIBAF"
- "AAAAcAAAAAMAAACEAAAAAQAAAJAAAAAAAAAAAAAAAAIAAACcAAAAAQAAAKwAAADcAAAAzAAAAOQA"
- "AADsAAAA9AAAAPkAAAANAQAAAgAAAAMAAAAEAAAABAAAAAIAAAAAAAAAAAAAAAAAAAABAAAAAAAA"
- "AAAAAAABAAAAAQAAAAAAAAABAAAAAAAAABUBAAAAAAAAAQABAAEAAAAQAQAABAAAAHAQAQAAAA4A"
- "Bjxpbml0PgAGQS5qYXZhAANMQTsAEkxqYXZhL2xhbmcvT2JqZWN0OwABVgABAAcOAAAAAQAAgYAE"
- "zAEACwAAAAAAAAABAAAAAAAAAAEAAAAFAAAAcAAAAAIAAAADAAAAhAAAAAMAAAABAAAAkAAAAAUA"
- "AAACAAAAnAAAAAYAAAABAAAArAAAAAEgAAABAAAAzAAAAAIgAAAFAAAA5AAAAAMgAAABAAAAEAEA"
- "AAAgAAABAAAAFQEAAAAQAAABAAAAIAEAAA==";
-
-static const char kRawDexDebugInfoLocalNullType[] =
- "ZGV4CjAzNQA+Kwj2g6OZMH88OvK9Ey6ycdIsFCt18ED8AQAAcAAAAHhWNBIAAAAAAAAAAHQBAAAI"
- "AAAAcAAAAAQAAACQAAAAAgAAAKAAAAAAAAAAAAAAAAMAAAC4AAAAAQAAANAAAAAMAQAA8AAAABwB"
- "AAAkAQAALAEAAC8BAAA0AQAASAEAAEsBAABOAQAAAgAAAAMAAAAEAAAABQAAAAIAAAAAAAAAAAAA"
- "AAUAAAADAAAAAAAAAAEAAQAAAAAAAQAAAAYAAAACAAEAAAAAAAEAAAABAAAAAgAAAAAAAAABAAAA"
- "AAAAAGMBAAAAAAAAAQABAAEAAABUAQAABAAAAHAQAgAAAA4AAgABAAAAAABZAQAAAgAAABIQDwAG"
- "PGluaXQ+AAZBLmphdmEAAUkAA0xBOwASTGphdmEvbGFuZy9PYmplY3Q7AAFWAAFhAAR0aGlzAAEA"
- "Bw4AAwAHDh4DAAcAAAAAAQEAgYAE8AEBAIgCAAAACwAAAAAAAAABAAAAAAAAAAEAAAAIAAAAcAAA"
- "AAIAAAAEAAAAkAAAAAMAAAACAAAAoAAAAAUAAAADAAAAuAAAAAYAAAABAAAA0AAAAAEgAAACAAAA"
- "8AAAAAIgAAAIAAAAHAEAAAMgAAACAAAAVAEAAAAgAAABAAAAYwEAAAAQAAABAAAAdAEAAA==";
-
-static void DecodeAndWriteDexFile(const char* base64, const char* location) {
- // decode base64
- CHECK(base64 != nullptr);
- std::vector<uint8_t> dex_bytes = DecodeBase64Vec(base64);
- CHECK_NE(dex_bytes.size(), 0u);
-
- // write to provided file
- std::unique_ptr<File> file(OS::CreateEmptyFile(location));
- CHECK(file.get() != nullptr);
- if (!file->WriteFully(dex_bytes.data(), dex_bytes.size())) {
- PLOG(FATAL) << "Failed to write base64 as dex file";
- }
- if (file->FlushCloseOrErase() != 0) {
- PLOG(FATAL) << "Could not flush and close test file.";
- }
-}
-
-static bool OpenDexFilesBase64(const char* base64,
- const char* location,
- std::vector<std::unique_ptr<const DexFile>>* dex_files,
- std::string* error_msg) {
- DecodeAndWriteDexFile(base64, location);
-
- // read dex file(s)
- ScopedObjectAccess soa(Thread::Current());
- static constexpr bool kVerifyChecksum = true;
- std::vector<std::unique_ptr<const DexFile>> tmp;
- const ArtDexFileLoader dex_file_loader;
- bool success = dex_file_loader.Open(
- location, location, /* verify */ true, kVerifyChecksum, error_msg, &tmp);
- if (success) {
- for (std::unique_ptr<const DexFile>& dex_file : tmp) {
- EXPECT_EQ(PROT_READ, dex_file->GetPermissions());
- EXPECT_TRUE(dex_file->IsReadOnly());
- }
- *dex_files = std::move(tmp);
- }
- return success;
-}
-
-static std::unique_ptr<const DexFile> OpenDexFileBase64(const char* base64,
- const char* location) {
- // read dex files.
- std::string error_msg;
- std::vector<std::unique_ptr<const DexFile>> dex_files;
- bool success = OpenDexFilesBase64(base64, location, &dex_files, &error_msg);
- CHECK(success) << error_msg;
- EXPECT_EQ(1U, dex_files.size());
- return std::move(dex_files[0]);
-}
-
-static std::unique_ptr<const DexFile> OpenDexFileInMemoryBase64(const char* base64,
- const char* location,
- uint32_t location_checksum,
- bool expect_success) {
- CHECK(base64 != nullptr);
- std::vector<uint8_t> dex_bytes = DecodeBase64Vec(base64);
- CHECK_NE(dex_bytes.size(), 0u);
-
- std::string error_message;
- std::unique_ptr<MemMap> region(MemMap::MapAnonymous("test-region",
- nullptr,
- dex_bytes.size(),
- PROT_READ | PROT_WRITE,
- /* low_4gb */ false,
- /* reuse */ false,
- &error_message));
- memcpy(region->Begin(), dex_bytes.data(), dex_bytes.size());
- const ArtDexFileLoader dex_file_loader;
- std::unique_ptr<const DexFile> dex_file(dex_file_loader.Open(location,
- location_checksum,
- std::move(region),
- /* verify */ true,
- /* verify_checksum */ true,
- &error_message));
- if (expect_success) {
- CHECK(dex_file != nullptr) << error_message;
- } else {
- CHECK(dex_file == nullptr) << "Expected dex file open to fail.";
- }
- return dex_file;
-}
-
-static void ValidateDexFileHeader(std::unique_ptr<const DexFile> dex_file) {
- static const uint8_t kExpectedDexFileMagic[8] = {
- /* d */ 0x64, /* e */ 0x64, /* x */ 0x78, /* \n */ 0x0d,
- /* 0 */ 0x30, /* 3 */ 0x33, /* 5 */ 0x35, /* \0 */ 0x00
- };
- static const uint8_t kExpectedSha1[DexFile::kSha1DigestSize] = {
- 0x7b, 0xb8, 0x0c, 0xd4, 0x1f, 0xd6, 0x1e, 0xc5,
- 0x89, 0xe8, 0xbe, 0xe5, 0x18, 0x02, 0x12, 0x18,
- 0x2e, 0xf2, 0x8c, 0x3d,
- };
-
- const DexFile::Header& header = dex_file->GetHeader();
- EXPECT_EQ(*kExpectedDexFileMagic, *header.magic_);
- EXPECT_EQ(0x00d87910U, header.checksum_);
- EXPECT_EQ(*kExpectedSha1, *header.signature_);
- EXPECT_EQ(904U, header.file_size_);
- EXPECT_EQ(112U, header.header_size_);
- EXPECT_EQ(0U, header.link_size_);
- EXPECT_EQ(0U, header.link_off_);
- EXPECT_EQ(15U, header.string_ids_size_);
- EXPECT_EQ(112U, header.string_ids_off_);
- EXPECT_EQ(7U, header.type_ids_size_);
- EXPECT_EQ(172U, header.type_ids_off_);
- EXPECT_EQ(2U, header.proto_ids_size_);
- EXPECT_EQ(200U, header.proto_ids_off_);
- EXPECT_EQ(1U, header.field_ids_size_);
- EXPECT_EQ(224U, header.field_ids_off_);
- EXPECT_EQ(3U, header.method_ids_size_);
- EXPECT_EQ(232U, header.method_ids_off_);
- EXPECT_EQ(2U, header.class_defs_size_);
- EXPECT_EQ(256U, header.class_defs_off_);
- EXPECT_EQ(584U, header.data_size_);
- EXPECT_EQ(320U, header.data_off_);
-
- EXPECT_EQ(header.checksum_, dex_file->GetLocationChecksum());
-}
-
-TEST_F(DexFileTest, Header) {
- ScratchFile tmp;
- std::unique_ptr<const DexFile> raw(OpenDexFileBase64(kRawDex, tmp.GetFilename().c_str()));
- ValidateDexFileHeader(std::move(raw));
-}
-
-TEST_F(DexFileTest, HeaderInMemory) {
- ScratchFile tmp;
- std::unique_ptr<const DexFile> raw =
- OpenDexFileInMemoryBase64(kRawDex, tmp.GetFilename().c_str(), 0x00d87910U, true);
- ValidateDexFileHeader(std::move(raw));
-}
-
-TEST_F(DexFileTest, Version38Accepted) {
- ScratchFile tmp;
- std::unique_ptr<const DexFile> raw(OpenDexFileBase64(kRawDex38, tmp.GetFilename().c_str()));
- ASSERT_TRUE(raw.get() != nullptr);
-
- const DexFile::Header& header = raw->GetHeader();
- EXPECT_EQ(38u, header.GetVersion());
-}
-
-TEST_F(DexFileTest, Version39Accepted) {
- ScratchFile tmp;
- std::unique_ptr<const DexFile> raw(OpenDexFileBase64(kRawDex39, tmp.GetFilename().c_str()));
- ASSERT_TRUE(raw.get() != nullptr);
-
- const DexFile::Header& header = raw->GetHeader();
- EXPECT_EQ(39u, header.GetVersion());
-}
-
-TEST_F(DexFileTest, Version40Rejected) {
- ScratchFile tmp;
- const char* location = tmp.GetFilename().c_str();
- DecodeAndWriteDexFile(kRawDex40, location);
-
- ScopedObjectAccess soa(Thread::Current());
- static constexpr bool kVerifyChecksum = true;
- std::string error_msg;
- std::vector<std::unique_ptr<const DexFile>> dex_files;
- const ArtDexFileLoader dex_file_loader;
- ASSERT_FALSE(dex_file_loader.Open(
- location, location, /* verify */ true, kVerifyChecksum, &error_msg, &dex_files));
-}
-
-TEST_F(DexFileTest, Version41Rejected) {
- ScratchFile tmp;
- const char* location = tmp.GetFilename().c_str();
- DecodeAndWriteDexFile(kRawDex41, location);
-
- ScopedObjectAccess soa(Thread::Current());
- static constexpr bool kVerifyChecksum = true;
- std::string error_msg;
- std::vector<std::unique_ptr<const DexFile>> dex_files;
- const ArtDexFileLoader dex_file_loader;
- ASSERT_FALSE(dex_file_loader.Open(
- location, location, /* verify */ true, kVerifyChecksum, &error_msg, &dex_files));
-}
-
-TEST_F(DexFileTest, ZeroLengthDexRejected) {
- ScratchFile tmp;
- const char* location = tmp.GetFilename().c_str();
- DecodeAndWriteDexFile(kRawDexZeroLength, location);
-
- ScopedObjectAccess soa(Thread::Current());
- static constexpr bool kVerifyChecksum = true;
- std::string error_msg;
- std::vector<std::unique_ptr<const DexFile>> dex_files;
- const ArtDexFileLoader dex_file_loader;
- ASSERT_FALSE(dex_file_loader.Open(
- location, location, /* verify */ true, kVerifyChecksum, &error_msg, &dex_files));
-}
-
-TEST_F(DexFileTest, GetLocationChecksum) {
- ScopedObjectAccess soa(Thread::Current());
- std::unique_ptr<const DexFile> raw(OpenTestDexFile("Main"));
- EXPECT_NE(raw->GetHeader().checksum_, raw->GetLocationChecksum());
-}
-
-TEST_F(DexFileTest, GetChecksum) {
- std::vector<uint32_t> checksums;
- ScopedObjectAccess soa(Thread::Current());
- std::string error_msg;
- const ArtDexFileLoader dex_file_loader;
- EXPECT_TRUE(dex_file_loader.GetMultiDexChecksums(GetLibCoreDexFileNames()[0].c_str(),
- &checksums,
- &error_msg))
- << error_msg;
- ASSERT_EQ(1U, checksums.size());
- EXPECT_EQ(java_lang_dex_file_->GetLocationChecksum(), checksums[0]);
-}
-
-TEST_F(DexFileTest, GetMultiDexChecksums) {
- std::string error_msg;
- std::vector<uint32_t> checksums;
- std::string multidex_file = GetTestDexFileName("MultiDex");
- const ArtDexFileLoader dex_file_loader;
- EXPECT_TRUE(dex_file_loader.GetMultiDexChecksums(multidex_file.c_str(),
- &checksums,
- &error_msg)) << error_msg;
-
- std::vector<std::unique_ptr<const DexFile>> dexes = OpenTestDexFiles("MultiDex");
- ASSERT_EQ(2U, dexes.size());
- ASSERT_EQ(2U, checksums.size());
-
- EXPECT_EQ(dexes[0]->GetLocation(), DexFileLoader::GetMultiDexLocation(0, multidex_file.c_str()));
- EXPECT_EQ(dexes[0]->GetLocationChecksum(), checksums[0]);
-
- EXPECT_EQ(dexes[1]->GetLocation(), DexFileLoader::GetMultiDexLocation(1, multidex_file.c_str()));
- EXPECT_EQ(dexes[1]->GetLocationChecksum(), checksums[1]);
-}
-
-TEST_F(DexFileTest, ClassDefs) {
- ScopedObjectAccess soa(Thread::Current());
- std::unique_ptr<const DexFile> raw(OpenTestDexFile("Nested"));
- ASSERT_TRUE(raw.get() != nullptr);
- EXPECT_EQ(3U, raw->NumClassDefs());
-
- const DexFile::ClassDef& c0 = raw->GetClassDef(0);
- EXPECT_STREQ("LNested$1;", raw->GetClassDescriptor(c0));
-
- const DexFile::ClassDef& c1 = raw->GetClassDef(1);
- EXPECT_STREQ("LNested$Inner;", raw->GetClassDescriptor(c1));
-
- const DexFile::ClassDef& c2 = raw->GetClassDef(2);
- EXPECT_STREQ("LNested;", raw->GetClassDescriptor(c2));
-}
-
-TEST_F(DexFileTest, GetMethodSignature) {
- ScopedObjectAccess soa(Thread::Current());
- std::unique_ptr<const DexFile> raw(OpenTestDexFile("GetMethodSignature"));
- ASSERT_TRUE(raw.get() != nullptr);
- EXPECT_EQ(1U, raw->NumClassDefs());
-
- const DexFile::ClassDef& class_def = raw->GetClassDef(0);
- ASSERT_STREQ("LGetMethodSignature;", raw->GetClassDescriptor(class_def));
-
- const uint8_t* class_data = raw->GetClassData(class_def);
- ASSERT_TRUE(class_data != nullptr);
- ClassDataItemIterator it(*raw, class_data);
-
- EXPECT_EQ(1u, it.NumDirectMethods());
-
- // Check the signature for the static initializer.
- {
- ASSERT_EQ(1U, it.NumDirectMethods());
- const DexFile::MethodId& method_id = raw->GetMethodId(it.GetMemberIndex());
- const char* name = raw->StringDataByIdx(method_id.name_idx_);
- ASSERT_STREQ("<init>", name);
- std::string signature(raw->GetMethodSignature(method_id).ToString());
- ASSERT_EQ("()V", signature);
- }
-
- // Check all virtual methods.
- struct Result {
- const char* name;
- const char* signature;
- const char* pretty_method;
- };
- static const Result results[] = {
- {
- "m1",
- "(IDJLjava/lang/Object;)Ljava/lang/Float;",
- "java.lang.Float GetMethodSignature.m1(int, double, long, java.lang.Object)"
- },
- {
- "m2",
- "(ZSC)LGetMethodSignature;",
- "GetMethodSignature GetMethodSignature.m2(boolean, short, char)"
- },
- {
- "m3",
- "()V",
- "void GetMethodSignature.m3()"
- },
- {
- "m4",
- "(I)V",
- "void GetMethodSignature.m4(int)"
- },
- {
- "m5",
- "(II)V",
- "void GetMethodSignature.m5(int, int)"
- },
- {
- "m6",
- "(II[[I)V",
- "void GetMethodSignature.m6(int, int, int[][])"
- },
- {
- "m7",
- "(II[[ILjava/lang/Object;)V",
- "void GetMethodSignature.m7(int, int, int[][], java.lang.Object)"
- },
- {
- "m8",
- "(II[[ILjava/lang/Object;[[Ljava/lang/Object;)V",
- "void GetMethodSignature.m8(int, int, int[][], java.lang.Object, java.lang.Object[][])"
- },
- {
- "m9",
- "()I",
- "int GetMethodSignature.m9()"
- },
- {
- "mA",
- "()[[I",
- "int[][] GetMethodSignature.mA()"
- },
- {
- "mB",
- "()[[Ljava/lang/Object;",
- "java.lang.Object[][] GetMethodSignature.mB()"
- },
- };
- ASSERT_EQ(arraysize(results), it.NumVirtualMethods());
- for (const Result& r : results) {
- it.Next();
- const DexFile::MethodId& method_id = raw->GetMethodId(it.GetMemberIndex());
-
- const char* name = raw->StringDataByIdx(method_id.name_idx_);
- ASSERT_STREQ(r.name, name);
-
- std::string signature(raw->GetMethodSignature(method_id).ToString());
- ASSERT_EQ(r.signature, signature);
-
- std::string plain_method = std::string("GetMethodSignature.") + r.name;
- ASSERT_EQ(plain_method, raw->PrettyMethod(it.GetMemberIndex(), /* with_signature */ false));
- ASSERT_EQ(r.pretty_method, raw->PrettyMethod(it.GetMemberIndex(), /* with_signature */ true));
- }
-}
-
-TEST_F(DexFileTest, FindStringId) {
- ScopedObjectAccess soa(Thread::Current());
- std::unique_ptr<const DexFile> raw(OpenTestDexFile("GetMethodSignature"));
- ASSERT_TRUE(raw.get() != nullptr);
- EXPECT_EQ(1U, raw->NumClassDefs());
-
- const char* strings[] = { "LGetMethodSignature;", "Ljava/lang/Float;", "Ljava/lang/Object;",
- "D", "I", "J", nullptr };
- for (size_t i = 0; strings[i] != nullptr; i++) {
- const char* str = strings[i];
- const DexFile::StringId* str_id = raw->FindStringId(str);
- const char* dex_str = raw->GetStringData(*str_id);
- EXPECT_STREQ(dex_str, str);
- }
-}
-
-TEST_F(DexFileTest, FindTypeId) {
- for (size_t i = 0; i < java_lang_dex_file_->NumTypeIds(); i++) {
- const char* type_str = java_lang_dex_file_->StringByTypeIdx(dex::TypeIndex(i));
- const DexFile::StringId* type_str_id = java_lang_dex_file_->FindStringId(type_str);
- ASSERT_TRUE(type_str_id != nullptr);
- dex::StringIndex type_str_idx = java_lang_dex_file_->GetIndexForStringId(*type_str_id);
- const DexFile::TypeId* type_id = java_lang_dex_file_->FindTypeId(type_str_idx);
- ASSERT_EQ(type_id, java_lang_dex_file_->FindTypeId(type_str));
- ASSERT_TRUE(type_id != nullptr);
- EXPECT_EQ(java_lang_dex_file_->GetIndexForTypeId(*type_id).index_, i);
- }
-}
-
-TEST_F(DexFileTest, FindProtoId) {
- for (size_t i = 0; i < java_lang_dex_file_->NumProtoIds(); i++) {
- const DexFile::ProtoId& to_find = java_lang_dex_file_->GetProtoId(i);
- const DexFile::TypeList* to_find_tl = java_lang_dex_file_->GetProtoParameters(to_find);
- std::vector<dex::TypeIndex> to_find_types;
- if (to_find_tl != nullptr) {
- for (size_t j = 0; j < to_find_tl->Size(); j++) {
- to_find_types.push_back(to_find_tl->GetTypeItem(j).type_idx_);
- }
- }
- const DexFile::ProtoId* found =
- java_lang_dex_file_->FindProtoId(to_find.return_type_idx_, to_find_types);
- ASSERT_TRUE(found != nullptr);
- EXPECT_EQ(java_lang_dex_file_->GetIndexForProtoId(*found), i);
- }
-}
-
-TEST_F(DexFileTest, FindMethodId) {
- for (size_t i = 0; i < java_lang_dex_file_->NumMethodIds(); i++) {
- const DexFile::MethodId& to_find = java_lang_dex_file_->GetMethodId(i);
- const DexFile::TypeId& klass = java_lang_dex_file_->GetTypeId(to_find.class_idx_);
- const DexFile::StringId& name = java_lang_dex_file_->GetStringId(to_find.name_idx_);
- const DexFile::ProtoId& signature = java_lang_dex_file_->GetProtoId(to_find.proto_idx_);
- const DexFile::MethodId* found = java_lang_dex_file_->FindMethodId(klass, name, signature);
- ASSERT_TRUE(found != nullptr) << "Didn't find method " << i << ": "
- << java_lang_dex_file_->StringByTypeIdx(to_find.class_idx_) << "."
- << java_lang_dex_file_->GetStringData(name)
- << java_lang_dex_file_->GetMethodSignature(to_find);
- EXPECT_EQ(java_lang_dex_file_->GetIndexForMethodId(*found), i);
- }
-}
-
-TEST_F(DexFileTest, FindFieldId) {
- for (size_t i = 0; i < java_lang_dex_file_->NumFieldIds(); i++) {
- const DexFile::FieldId& to_find = java_lang_dex_file_->GetFieldId(i);
- const DexFile::TypeId& klass = java_lang_dex_file_->GetTypeId(to_find.class_idx_);
- const DexFile::StringId& name = java_lang_dex_file_->GetStringId(to_find.name_idx_);
- const DexFile::TypeId& type = java_lang_dex_file_->GetTypeId(to_find.type_idx_);
- const DexFile::FieldId* found = java_lang_dex_file_->FindFieldId(klass, name, type);
- ASSERT_TRUE(found != nullptr) << "Didn't find field " << i << ": "
- << java_lang_dex_file_->StringByTypeIdx(to_find.type_idx_) << " "
- << java_lang_dex_file_->StringByTypeIdx(to_find.class_idx_) << "."
- << java_lang_dex_file_->GetStringData(name);
- EXPECT_EQ(java_lang_dex_file_->GetIndexForFieldId(*found), i);
- }
-}
-
-TEST_F(DexFileTest, GetMultiDexClassesDexName) {
- ASSERT_EQ("classes.dex", DexFileLoader::GetMultiDexClassesDexName(0));
- ASSERT_EQ("classes2.dex", DexFileLoader::GetMultiDexClassesDexName(1));
- ASSERT_EQ("classes3.dex", DexFileLoader::GetMultiDexClassesDexName(2));
- ASSERT_EQ("classes100.dex", DexFileLoader::GetMultiDexClassesDexName(99));
-}
-
-TEST_F(DexFileTest, GetMultiDexLocation) {
- std::string dex_location_str = "/system/app/framework.jar";
- const char* dex_location = dex_location_str.c_str();
- ASSERT_EQ("/system/app/framework.jar", DexFileLoader::GetMultiDexLocation(0, dex_location));
- ASSERT_EQ("/system/app/framework.jar!classes2.dex",
- DexFileLoader::GetMultiDexLocation(1, dex_location));
- ASSERT_EQ("/system/app/framework.jar!classes101.dex",
- DexFileLoader::GetMultiDexLocation(100, dex_location));
-}
-
-TEST_F(DexFileTest, GetDexCanonicalLocation) {
- ScratchFile file;
- UniqueCPtr<const char[]> dex_location_real(realpath(file.GetFilename().c_str(), nullptr));
- std::string dex_location(dex_location_real.get());
-
- ASSERT_EQ(dex_location, DexFileLoader::GetDexCanonicalLocation(dex_location.c_str()));
- std::string multidex_location = DexFileLoader::GetMultiDexLocation(1, dex_location.c_str());
- ASSERT_EQ(multidex_location, DexFileLoader::GetDexCanonicalLocation(multidex_location.c_str()));
-
- std::string dex_location_sym = dex_location + "symlink";
- ASSERT_EQ(0, symlink(dex_location.c_str(), dex_location_sym.c_str()));
-
- ASSERT_EQ(dex_location, DexFileLoader::GetDexCanonicalLocation(dex_location_sym.c_str()));
-
- std::string multidex_location_sym = DexFileLoader::GetMultiDexLocation(
- 1, dex_location_sym.c_str());
- ASSERT_EQ(multidex_location,
- DexFileLoader::GetDexCanonicalLocation(multidex_location_sym.c_str()));
-
- ASSERT_EQ(0, unlink(dex_location_sym.c_str()));
-}
-
-TEST(DexFileUtilsTest, GetBaseLocationAndMultiDexSuffix) {
- EXPECT_EQ("/foo/bar/baz.jar", DexFileLoader::GetBaseLocation("/foo/bar/baz.jar"));
- EXPECT_EQ("/foo/bar/baz.jar", DexFileLoader::GetBaseLocation("/foo/bar/baz.jar!classes2.dex"));
- EXPECT_EQ("/foo/bar/baz.jar", DexFileLoader::GetBaseLocation("/foo/bar/baz.jar!classes8.dex"));
- EXPECT_EQ("", DexFileLoader::GetMultiDexSuffix("/foo/bar/baz.jar"));
- EXPECT_EQ("!classes2.dex", DexFileLoader::GetMultiDexSuffix("/foo/bar/baz.jar!classes2.dex"));
- EXPECT_EQ("!classes8.dex", DexFileLoader::GetMultiDexSuffix("/foo/bar/baz.jar!classes8.dex"));
-}
-
-TEST_F(DexFileTest, ZipOpenClassesPresent) {
- ScratchFile tmp;
- std::vector<std::unique_ptr<const DexFile>> dex_files;
- std::string error_msg;
- ASSERT_TRUE(OpenDexFilesBase64(kRawZipClassesDexPresent, tmp.GetFilename().c_str(), &dex_files,
- &error_msg));
- EXPECT_EQ(dex_files.size(), 1u);
-}
-
-TEST_F(DexFileTest, ZipOpenClassesAbsent) {
- ScratchFile tmp;
- std::vector<std::unique_ptr<const DexFile>> dex_files;
- std::string error_msg;
- ASSERT_FALSE(OpenDexFilesBase64(kRawZipClassesDexAbsent, tmp.GetFilename().c_str(), &dex_files,
- &error_msg));
- EXPECT_EQ(dex_files.size(), 0u);
-}
-
-TEST_F(DexFileTest, ZipOpenThreeDexFiles) {
- ScratchFile tmp;
- std::vector<std::unique_ptr<const DexFile>> dex_files;
- std::string error_msg;
- ASSERT_TRUE(OpenDexFilesBase64(kRawZipThreeDexFiles, tmp.GetFilename().c_str(), &dex_files,
- &error_msg));
- EXPECT_EQ(dex_files.size(), 3u);
-}
-
-TEST_F(DexFileTest, OpenDexBadMapOffset) {
- ScratchFile tmp;
- std::unique_ptr<const DexFile> raw =
- OpenDexFileInMemoryBase64(kRawDexBadMapOffset, tmp.GetFilename().c_str(), 0xb3642819U, false);
- EXPECT_EQ(raw, nullptr);
-}
-
-TEST_F(DexFileTest, GetStringWithNoIndex) {
- ScratchFile tmp;
- std::unique_ptr<const DexFile> raw(OpenDexFileBase64(kRawDex, tmp.GetFilename().c_str()));
- dex::TypeIndex idx;
- EXPECT_EQ(raw->StringByTypeIdx(idx), nullptr);
-}
-
-static void Callback(void* context ATTRIBUTE_UNUSED,
- const DexFile::LocalInfo& entry ATTRIBUTE_UNUSED) {
-}
-
-TEST_F(DexFileTest, OpenDexDebugInfoLocalNullType) {
- ScratchFile tmp;
- std::unique_ptr<const DexFile> raw = OpenDexFileInMemoryBase64(
- kRawDexDebugInfoLocalNullType, tmp.GetFilename().c_str(), 0xf25f2b38U, true);
- const DexFile::ClassDef& class_def = raw->GetClassDef(0);
- constexpr uint32_t kMethodIdx = 1;
- const DexFile::CodeItem* code_item = raw->GetCodeItem(raw->FindCodeItemOffset(class_def,
- kMethodIdx));
- CodeItemDebugInfoAccessor accessor(*raw, code_item, kMethodIdx);
- ASSERT_TRUE(accessor.DecodeDebugLocalInfo(true, 1, Callback, nullptr));
-}
-
-} // namespace art
diff --git a/runtime/dex/dex_file_tracking_registrar.cc b/runtime/dex/dex_file_tracking_registrar.cc
deleted file mode 100644
index 78ea9c16cb..0000000000
--- a/runtime/dex/dex_file_tracking_registrar.cc
+++ /dev/null
@@ -1,272 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "dex_file_tracking_registrar.h"
-
-#include <deque>
-#include <tuple>
-
-#include <android-base/logging.h>
-
-// For dex tracking through poisoning. Note: Requires forcing sanitization. This is the reason for
-// the ifdefs and early include.
-#ifdef ART_DEX_FILE_ACCESS_TRACKING
-#ifndef ART_ENABLE_ADDRESS_SANITIZER
-#define ART_ENABLE_ADDRESS_SANITIZER
-#endif
-#endif
-#include "base/memory_tool.h"
-
-#include "code_item_accessors-inl.h"
-#include "dex_file-inl.h"
-
-namespace art {
-namespace dex {
-namespace tracking {
-
-// If true, poison dex files to track accesses.
-static constexpr bool kDexFileAccessTracking =
-#ifdef ART_DEX_FILE_ACCESS_TRACKING
- true;
-#else
- false;
-#endif
-
-// The following are configurations of poisoning certain sections of a Dex File.
-// More will be added
-enum DexTrackingType {
- // Poisons all of a Dex File when set.
- kWholeDexTracking,
- // Poisons all Code Items of a Dex File when set.
- kCodeItemTracking,
- // Poisons all subsections of a Code Item, except the Insns bytecode array
- // section, when set for all Code Items in a Dex File.
- kCodeItemNonInsnsTracking,
- // Poisons all subsections of a Code Item, except the Insns bytecode array
- // section, when set for all Code Items in a Dex File.
- // Additionally unpoisons the entire Code Item when method is a class
- // initializer.
- kCodeItemNonInsnsNoClinitTracking,
- // Poisons the size and offset information along with the first instruction.
- // This is so that accessing multiple instructions while accessing a code item
- // once will not trigger unnecessary accesses.
- kCodeItemStartTracking,
- // Poisons all String Data Items of a Dex Files when set.
- kStringDataItemTracking,
- // Poisons the first byte of the utf16_size value and the first byte of the
- // data section for all String Data Items of a Dex File.
- kStringDataItemStartTracking,
- // Poisons based on a custom tracking system which can be specified in
- // SetDexSections
- kCustomTracking,
-};
-
-// Intended for local changes only.
-// Represents the current configuration being run.
-static constexpr DexTrackingType kCurrentTrackingSystem = kWholeDexTracking;
-
-// Intended for local changes only.
-void DexFileTrackingRegistrar::SetDexSections() {
- if (kDexFileAccessTracking && dex_file_ != nullptr) {
- // Logs the Dex File's location and starting address if tracking is enabled
- LOG(ERROR) << "RegisterDexFile: " << dex_file_->GetLocation() + " @ " << std::hex
- << reinterpret_cast<uintptr_t>(dex_file_->Begin());
- switch (kCurrentTrackingSystem) {
- case kWholeDexTracking:
- SetDexFileRegistration(true);
- break;
- case kCodeItemTracking:
- SetAllCodeItemRegistration(true);
- break;
- case kCodeItemNonInsnsTracking:
- SetAllCodeItemRegistration(true);
- SetAllInsnsRegistration(false);
- break;
- case kCodeItemNonInsnsNoClinitTracking:
- SetAllCodeItemRegistration(true);
- SetAllInsnsRegistration(false);
- SetCodeItemRegistration("<clinit>", false);
- break;
- case kCodeItemStartTracking:
- SetAllCodeItemStartRegistration(true);
- break;
- case kStringDataItemTracking:
- SetAllStringDataRegistration(true);
- break;
- case kStringDataItemStartTracking:
- SetAllStringDataStartRegistration(true);
- break;
- case kCustomTracking:
- // TODO: Add/remove additional calls here to (un)poison sections of
- // dex_file_
- break;
- default:
- break;
- }
- }
-}
-
-void RegisterDexFile(const DexFile* dex_file) {
- DexFileTrackingRegistrar dex_tracking_registrar(dex_file);
- dex_tracking_registrar.SetDexSections();
- dex_tracking_registrar.SetCurrentRanges();
-}
-
-inline void SetRegistrationRange(const void* begin, size_t size, bool should_poison) {
- if (should_poison) {
- MEMORY_TOOL_MAKE_NOACCESS(begin, size);
- } else {
- // Note: MEMORY_TOOL_MAKE_UNDEFINED has the same functionality with Address
- // Sanitizer. The difference has not been tested with Valgrind
- MEMORY_TOOL_MAKE_DEFINED(begin, size);
- }
-}
-
-void DexFileTrackingRegistrar::SetCurrentRanges() {
- // This also empties range_values_ to avoid redundant (un)poisoning upon
- // subsequent calls.
- while (!range_values_.empty()) {
- const std::tuple<const void*, size_t, bool>& current_range = range_values_.front();
- SetRegistrationRange(std::get<0>(current_range),
- std::get<1>(current_range),
- std::get<2>(current_range));
- range_values_.pop_front();
- }
-}
-
-void DexFileTrackingRegistrar::SetDexFileRegistration(bool should_poison) {
- const void* dex_file_begin = reinterpret_cast<const void*>(dex_file_->Begin());
- size_t dex_file_size = dex_file_->Size();
- range_values_.push_back(std::make_tuple(dex_file_begin, dex_file_size, should_poison));
-}
-
-void DexFileTrackingRegistrar::SetAllCodeItemRegistration(bool should_poison) {
- for (size_t classdef_ctr = 0; classdef_ctr < dex_file_->NumClassDefs(); ++classdef_ctr) {
- const DexFile::ClassDef& cd = dex_file_->GetClassDef(classdef_ctr);
- const uint8_t* class_data = dex_file_->GetClassData(cd);
- if (class_data != nullptr) {
- ClassDataItemIterator cdit(*dex_file_, class_data);
- cdit.SkipAllFields();
- while (cdit.HasNextMethod()) {
- const DexFile::CodeItem* code_item = cdit.GetMethodCodeItem();
- if (code_item != nullptr) {
- const void* code_item_begin = reinterpret_cast<const void*>(code_item);
- size_t code_item_size = dex_file_->GetCodeItemSize(*code_item);
- range_values_.push_back(std::make_tuple(code_item_begin, code_item_size, should_poison));
- }
- cdit.Next();
- }
- }
- }
-}
-
-void DexFileTrackingRegistrar::SetAllCodeItemStartRegistration(bool should_poison) {
- for (size_t classdef_ctr = 0; classdef_ctr < dex_file_->NumClassDefs(); ++classdef_ctr) {
- const DexFile::ClassDef& cd = dex_file_->GetClassDef(classdef_ctr);
- const uint8_t* class_data = dex_file_->GetClassData(cd);
- if (class_data != nullptr) {
- ClassDataItemIterator cdit(*dex_file_, class_data);
- cdit.SkipAllFields();
- while (cdit.HasNextMethod()) {
- const DexFile::CodeItem* code_item = cdit.GetMethodCodeItem();
- if (code_item != nullptr) {
- const void* code_item_begin = reinterpret_cast<const void*>(code_item);
- size_t code_item_start = reinterpret_cast<size_t>(code_item);
- CodeItemInstructionAccessor accessor(*dex_file_, code_item);
- size_t code_item_start_end = reinterpret_cast<size_t>(accessor.Insns());
- size_t code_item_start_size = code_item_start_end - code_item_start;
- range_values_.push_back(std::make_tuple(code_item_begin,
- code_item_start_size,
- should_poison));
- }
- cdit.Next();
- }
- }
- }
-}
-
-void DexFileTrackingRegistrar::SetAllInsnsRegistration(bool should_poison) {
- for (size_t classdef_ctr = 0; classdef_ctr < dex_file_->NumClassDefs(); ++classdef_ctr) {
- const DexFile::ClassDef& cd = dex_file_->GetClassDef(classdef_ctr);
- const uint8_t* class_data = dex_file_->GetClassData(cd);
- if (class_data != nullptr) {
- ClassDataItemIterator cdit(*dex_file_, class_data);
- cdit.SkipAllFields();
- while (cdit.HasNextMethod()) {
- const DexFile::CodeItem* code_item = cdit.GetMethodCodeItem();
- if (code_item != nullptr) {
- CodeItemInstructionAccessor accessor(*dex_file_, code_item);
- const void* insns_begin = reinterpret_cast<const void*>(accessor.Insns());
- // Member insns_size_in_code_units_ is in 2-byte units
- size_t insns_size = accessor.InsnsSizeInCodeUnits() * 2;
- range_values_.push_back(std::make_tuple(insns_begin, insns_size, should_poison));
- }
- cdit.Next();
- }
- }
- }
-}
-
-void DexFileTrackingRegistrar::SetCodeItemRegistration(const char* class_name, bool should_poison) {
- for (size_t classdef_ctr = 0; classdef_ctr < dex_file_->NumClassDefs(); ++classdef_ctr) {
- const DexFile::ClassDef& cd = dex_file_->GetClassDef(classdef_ctr);
- const uint8_t* class_data = dex_file_->GetClassData(cd);
- if (class_data != nullptr) {
- ClassDataItemIterator cdit(*dex_file_, class_data);
- cdit.SkipAllFields();
- while (cdit.HasNextMethod()) {
- const DexFile::MethodId& methodid_item = dex_file_->GetMethodId(cdit.GetMemberIndex());
- const char * methodid_name = dex_file_->GetMethodName(methodid_item);
- const DexFile::CodeItem* code_item = cdit.GetMethodCodeItem();
- if (code_item != nullptr && strcmp(methodid_name, class_name) == 0) {
- const void* code_item_begin = reinterpret_cast<const void*>(code_item);
- size_t code_item_size = dex_file_->GetCodeItemSize(*code_item);
- range_values_.push_back(std::make_tuple(code_item_begin, code_item_size, should_poison));
- }
- cdit.Next();
- }
- }
- }
-}
-
-void DexFileTrackingRegistrar::SetAllStringDataStartRegistration(bool should_poison) {
- for (size_t stringid_ctr = 0; stringid_ctr < dex_file_->NumStringIds(); ++stringid_ctr) {
- const DexFile::StringId & string_id = dex_file_->GetStringId(StringIndex(stringid_ctr));
- const void* string_data_begin = reinterpret_cast<const void*>(dex_file_->Begin() + string_id.string_data_off_);
- // Data Section of String Data Item
- const void* string_data_data_begin = reinterpret_cast<const void*>(dex_file_->GetStringData(string_id));
- range_values_.push_back(std::make_tuple(string_data_begin, 1, should_poison));
- range_values_.push_back(std::make_tuple(string_data_data_begin, 1, should_poison));
- }
-}
-
-void DexFileTrackingRegistrar::SetAllStringDataRegistration(bool should_poison) {
- size_t map_offset = dex_file_->GetHeader().map_off_;
- auto map_list = reinterpret_cast<const DexFile::MapList*>(dex_file_->Begin() + map_offset);
- for (size_t map_ctr = 0; map_ctr < map_list->size_; ++map_ctr) {
- const DexFile::MapItem& map_item = map_list->list_[map_ctr];
- if (map_item.type_ == DexFile::kDexTypeStringDataItem) {
- const DexFile::MapItem& next_map_item = map_list->list_[map_ctr + 1];
- const void* string_data_begin = reinterpret_cast<const void*>(dex_file_->Begin() + map_item.offset_);
- size_t string_data_size = next_map_item.offset_ - map_item.offset_;
- range_values_.push_back(std::make_tuple(string_data_begin, string_data_size, should_poison));
- }
- }
-}
-
-} // namespace tracking
-} // namespace dex
-} // namespace art
diff --git a/runtime/dex/dex_file_tracking_registrar.h b/runtime/dex/dex_file_tracking_registrar.h
deleted file mode 100644
index 71b8ed7bde..0000000000
--- a/runtime/dex/dex_file_tracking_registrar.h
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ART_RUNTIME_DEX_DEX_FILE_TRACKING_REGISTRAR_H_
-#define ART_RUNTIME_DEX_DEX_FILE_TRACKING_REGISTRAR_H_
-
-#include <deque>
-#include <tuple>
-
-#include "dex_file.h"
-
-namespace art {
-namespace dex {
-namespace tracking {
-
-// Class for (un)poisoning various sections of Dex Files
-//
-// This class provides the means to log accesses only of sections whose
-// accesses are needed. All accesses are displayed as stack traces in
-// logcat.
-class DexFileTrackingRegistrar {
- public:
- explicit DexFileTrackingRegistrar(const DexFile* const dex_file)
- : dex_file_(dex_file) {
- }
-
- // This function is where the functions below it are called to actually
- // poison sections.
- void SetDexSections();
-
- // Uses data contained inside range_values_ to poison memory through the
- // memory tool.
- void SetCurrentRanges();
-
- private:
- void SetDexFileRegistration(bool should_poison);
-
- // Set of functions concerning Code Items of dex_file_
- void SetAllCodeItemRegistration(bool should_poison);
- // Sets the insns_ section of all code items.
- void SetAllInsnsRegistration(bool should_poison);
- // This function finds the code item of a class based on class name.
- void SetCodeItemRegistration(const char* class_name, bool should_poison);
- // Sets the size and offset information along with first instruction in insns_
- // section of all code items.
- void SetAllCodeItemStartRegistration(bool should_poison);
-
- // Set of functions concerning String Data Items of dex_file_
- void SetAllStringDataRegistration(bool should_poison);
- // Sets the first byte of size value and data section of all string data
- // items.
- void SetAllStringDataStartRegistration(bool should_poison);
-
- // Contains tuples of all ranges of memory that need to be explicitly
- // (un)poisoned by the memory tool.
- std::deque<std::tuple<const void *, size_t, bool>> range_values_;
-
- const DexFile* const dex_file_;
-};
-
-// This function is meant to called externally to use DexfileTrackingRegistrar
-void RegisterDexFile(const DexFile* dex_file);
-
-} // namespace tracking
-} // namespace dex
-} // namespace art
-
-#endif // ART_RUNTIME_DEX_DEX_FILE_TRACKING_REGISTRAR_H_
diff --git a/runtime/dex/dex_file_types.h b/runtime/dex/dex_file_types.h
deleted file mode 100644
index 2c508f9c99..0000000000
--- a/runtime/dex/dex_file_types.h
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ART_RUNTIME_DEX_DEX_FILE_TYPES_H_
-#define ART_RUNTIME_DEX_DEX_FILE_TYPES_H_
-
-#include <limits>
-#include <ostream>
-
-namespace art {
-namespace dex {
-
-constexpr uint32_t kDexNoIndex = 0xFFFFFFFF;
-
-class StringIndex {
- public:
- uint32_t index_;
-
- constexpr StringIndex() : index_(std::numeric_limits<decltype(index_)>::max()) {}
- explicit constexpr StringIndex(uint32_t idx) : index_(idx) {}
-
- bool IsValid() const {
- return index_ != std::numeric_limits<decltype(index_)>::max();
- }
- static StringIndex Invalid() {
- return StringIndex(std::numeric_limits<decltype(index_)>::max());
- }
-
- bool operator==(const StringIndex& other) const {
- return index_ == other.index_;
- }
- bool operator!=(const StringIndex& other) const {
- return index_ != other.index_;
- }
- bool operator<(const StringIndex& other) const {
- return index_ < other.index_;
- }
- bool operator<=(const StringIndex& other) const {
- return index_ <= other.index_;
- }
- bool operator>(const StringIndex& other) const {
- return index_ > other.index_;
- }
- bool operator>=(const StringIndex& other) const {
- return index_ >= other.index_;
- }
-};
-std::ostream& operator<<(std::ostream& os, const StringIndex& index);
-
-class TypeIndex {
- public:
- uint16_t index_;
-
- constexpr TypeIndex() : index_(std::numeric_limits<decltype(index_)>::max()) {}
- explicit constexpr TypeIndex(uint16_t idx) : index_(idx) {}
-
- bool IsValid() const {
- return index_ != std::numeric_limits<decltype(index_)>::max();
- }
- static TypeIndex Invalid() {
- return TypeIndex(std::numeric_limits<decltype(index_)>::max());
- }
-
- bool operator==(const TypeIndex& other) const {
- return index_ == other.index_;
- }
- bool operator!=(const TypeIndex& other) const {
- return index_ != other.index_;
- }
- bool operator<(const TypeIndex& other) const {
- return index_ < other.index_;
- }
- bool operator<=(const TypeIndex& other) const {
- return index_ <= other.index_;
- }
- bool operator>(const TypeIndex& other) const {
- return index_ > other.index_;
- }
- bool operator>=(const TypeIndex& other) const {
- return index_ >= other.index_;
- }
-};
-std::ostream& operator<<(std::ostream& os, const TypeIndex& index);
-
-} // namespace dex
-} // namespace art
-
-namespace std {
-
-template<> struct hash<art::dex::StringIndex> {
- size_t operator()(const art::dex::StringIndex& index) const {
- return hash<uint32_t>()(index.index_);
- }
-};
-
-template<> struct hash<art::dex::TypeIndex> {
- size_t operator()(const art::dex::TypeIndex& index) const {
- return hash<uint16_t>()(index.index_);
- }
-};
-
-} // namespace std
-
-#endif // ART_RUNTIME_DEX_DEX_FILE_TYPES_H_
diff --git a/runtime/dex/dex_file_verifier.cc b/runtime/dex/dex_file_verifier.cc
deleted file mode 100644
index 62667052ad..0000000000
--- a/runtime/dex/dex_file_verifier.cc
+++ /dev/null
@@ -1,3290 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "dex_file_verifier.h"
-
-#include <inttypes.h>
-
-#include <limits>
-#include <memory>
-
-#include "android-base/stringprintf.h"
-
-#include "code_item_accessors-inl.h"
-#include "descriptors_names.h"
-#include "dex_file-inl.h"
-#include "leb128.h"
-#include "modifiers.h"
-#include "utf-inl.h"
-
-namespace art {
-
-using android::base::StringAppendV;
-using android::base::StringPrintf;
-
-static constexpr uint32_t kTypeIdLimit = std::numeric_limits<uint16_t>::max();
-
-static bool IsValidOrNoTypeId(uint16_t low, uint16_t high) {
- return (high == 0) || ((high == 0xffffU) && (low == 0xffffU));
-}
-
-static bool IsValidTypeId(uint16_t low ATTRIBUTE_UNUSED, uint16_t high) {
- return (high == 0);
-}
-
-static uint32_t MapTypeToBitMask(DexFile::MapItemType map_item_type) {
- switch (map_item_type) {
- case DexFile::kDexTypeHeaderItem: return 1 << 0;
- case DexFile::kDexTypeStringIdItem: return 1 << 1;
- case DexFile::kDexTypeTypeIdItem: return 1 << 2;
- case DexFile::kDexTypeProtoIdItem: return 1 << 3;
- case DexFile::kDexTypeFieldIdItem: return 1 << 4;
- case DexFile::kDexTypeMethodIdItem: return 1 << 5;
- case DexFile::kDexTypeClassDefItem: return 1 << 6;
- case DexFile::kDexTypeCallSiteIdItem: return 1 << 7;
- case DexFile::kDexTypeMethodHandleItem: return 1 << 8;
- case DexFile::kDexTypeMapList: return 1 << 9;
- case DexFile::kDexTypeTypeList: return 1 << 10;
- case DexFile::kDexTypeAnnotationSetRefList: return 1 << 11;
- case DexFile::kDexTypeAnnotationSetItem: return 1 << 12;
- case DexFile::kDexTypeClassDataItem: return 1 << 13;
- case DexFile::kDexTypeCodeItem: return 1 << 14;
- case DexFile::kDexTypeStringDataItem: return 1 << 15;
- case DexFile::kDexTypeDebugInfoItem: return 1 << 16;
- case DexFile::kDexTypeAnnotationItem: return 1 << 17;
- case DexFile::kDexTypeEncodedArrayItem: return 1 << 18;
- case DexFile::kDexTypeAnnotationsDirectoryItem: return 1 << 19;
- }
- return 0;
-}
-
-static bool IsDataSectionType(DexFile::MapItemType map_item_type) {
- switch (map_item_type) {
- case DexFile::kDexTypeHeaderItem:
- case DexFile::kDexTypeStringIdItem:
- case DexFile::kDexTypeTypeIdItem:
- case DexFile::kDexTypeProtoIdItem:
- case DexFile::kDexTypeFieldIdItem:
- case DexFile::kDexTypeMethodIdItem:
- case DexFile::kDexTypeClassDefItem:
- return false;
- case DexFile::kDexTypeCallSiteIdItem:
- case DexFile::kDexTypeMethodHandleItem:
- case DexFile::kDexTypeMapList:
- case DexFile::kDexTypeTypeList:
- case DexFile::kDexTypeAnnotationSetRefList:
- case DexFile::kDexTypeAnnotationSetItem:
- case DexFile::kDexTypeClassDataItem:
- case DexFile::kDexTypeCodeItem:
- case DexFile::kDexTypeStringDataItem:
- case DexFile::kDexTypeDebugInfoItem:
- case DexFile::kDexTypeAnnotationItem:
- case DexFile::kDexTypeEncodedArrayItem:
- case DexFile::kDexTypeAnnotationsDirectoryItem:
- return true;
- }
- return true;
-}
-
-const char* DexFileVerifier::CheckLoadStringByIdx(dex::StringIndex idx, const char* error_string) {
- if (UNLIKELY(!CheckIndex(idx.index_, dex_file_->NumStringIds(), error_string))) {
- return nullptr;
- }
- return dex_file_->StringDataByIdx(idx);
-}
-
-// Try to find the name of the method with the given index. We do not want to rely on DexFile
-// infrastructure at this point, so do it all by hand. begin and header correspond to begin_ and
-// header_ of the DexFileVerifier. str will contain the pointer to the method name on success
-// (flagged by the return value), otherwise error_msg will contain an error string.
-static bool FindMethodName(uint32_t method_index,
- const uint8_t* begin,
- const DexFile::Header* header,
- const char** str,
- std::string* error_msg) {
- if (method_index >= header->method_ids_size_) {
- *error_msg = "Method index not available for method flags verification";
- return false;
- }
- uint32_t string_idx =
- (reinterpret_cast<const DexFile::MethodId*>(begin + header->method_ids_off_) +
- method_index)->name_idx_.index_;
- if (string_idx >= header->string_ids_size_) {
- *error_msg = "String index not available for method flags verification";
- return false;
- }
- uint32_t string_off =
- (reinterpret_cast<const DexFile::StringId*>(begin + header->string_ids_off_) + string_idx)->
- string_data_off_;
- if (string_off >= header->file_size_) {
- *error_msg = "String offset out of bounds for method flags verification";
- return false;
- }
- const uint8_t* str_data_ptr = begin + string_off;
- uint32_t dummy;
- if (!DecodeUnsignedLeb128Checked(&str_data_ptr, begin + header->file_size_, &dummy)) {
- *error_msg = "String size out of bounds for method flags verification";
- return false;
- }
- *str = reinterpret_cast<const char*>(str_data_ptr);
- return true;
-}
-
-// Gets constructor flags based on the |method_name|. Returns true if
-// method_name is either <clinit> or <init> and sets
-// |constructor_flags_by_name| appropriately. Otherwise set
-// |constructor_flags_by_name| to zero and returns whether
-// |method_name| is valid.
-bool GetConstructorFlagsForMethodName(const char* method_name,
- uint32_t* constructor_flags_by_name) {
- if (method_name[0] != '<') {
- *constructor_flags_by_name = 0;
- return true;
- }
- if (strcmp(method_name + 1, "clinit>") == 0) {
- *constructor_flags_by_name = kAccStatic | kAccConstructor;
- return true;
- }
- if (strcmp(method_name + 1, "init>") == 0) {
- *constructor_flags_by_name = kAccConstructor;
- return true;
- }
- *constructor_flags_by_name = 0;
- return false;
-}
-
-const char* DexFileVerifier::CheckLoadStringByTypeIdx(dex::TypeIndex type_idx,
- const char* error_string) {
- if (UNLIKELY(!CheckIndex(type_idx.index_, dex_file_->NumTypeIds(), error_string))) {
- return nullptr;
- }
- return CheckLoadStringByIdx(dex_file_->GetTypeId(type_idx).descriptor_idx_, error_string);
-}
-
-const DexFile::FieldId* DexFileVerifier::CheckLoadFieldId(uint32_t idx, const char* error_string) {
- if (UNLIKELY(!CheckIndex(idx, dex_file_->NumFieldIds(), error_string))) {
- return nullptr;
- }
- return &dex_file_->GetFieldId(idx);
-}
-
-const DexFile::MethodId* DexFileVerifier::CheckLoadMethodId(uint32_t idx, const char* err_string) {
- if (UNLIKELY(!CheckIndex(idx, dex_file_->NumMethodIds(), err_string))) {
- return nullptr;
- }
- return &dex_file_->GetMethodId(idx);
-}
-
-const DexFile::ProtoId* DexFileVerifier::CheckLoadProtoId(uint32_t idx, const char* err_string) {
- if (UNLIKELY(!CheckIndex(idx, dex_file_->NumProtoIds(), err_string))) {
- return nullptr;
- }
- return &dex_file_->GetProtoId(idx);
-}
-
-// Helper macro to load string and return false on error.
-#define LOAD_STRING(var, idx, error) \
- const char* (var) = CheckLoadStringByIdx(idx, error); \
- if (UNLIKELY((var) == nullptr)) { \
- return false; \
- }
-
-// Helper macro to load string by type idx and return false on error.
-#define LOAD_STRING_BY_TYPE(var, type_idx, error) \
- const char* (var) = CheckLoadStringByTypeIdx(type_idx, error); \
- if (UNLIKELY((var) == nullptr)) { \
- return false; \
- }
-
-// Helper macro to load method id. Return last parameter on error.
-#define LOAD_METHOD(var, idx, error_string, error_stmt) \
- const DexFile::MethodId* (var) = CheckLoadMethodId(idx, error_string); \
- if (UNLIKELY((var) == nullptr)) { \
- error_stmt; \
- }
-
-// Helper macro to load method id. Return last parameter on error.
-#define LOAD_FIELD(var, idx, fmt, error_stmt) \
- const DexFile::FieldId* (var) = CheckLoadFieldId(idx, fmt); \
- if (UNLIKELY((var) == nullptr)) { \
- error_stmt; \
- }
-
-bool DexFileVerifier::Verify(const DexFile* dex_file,
- const uint8_t* begin,
- size_t size,
- const char* location,
- bool verify_checksum,
- std::string* error_msg) {
- std::unique_ptr<DexFileVerifier> verifier(
- new DexFileVerifier(dex_file, begin, size, location, verify_checksum));
- if (!verifier->Verify()) {
- *error_msg = verifier->FailureReason();
- return false;
- }
- return true;
-}
-
-bool DexFileVerifier::CheckShortyDescriptorMatch(char shorty_char, const char* descriptor,
- bool is_return_type) {
- switch (shorty_char) {
- case 'V':
- if (UNLIKELY(!is_return_type)) {
- ErrorStringPrintf("Invalid use of void");
- return false;
- }
- FALLTHROUGH_INTENDED;
- case 'B':
- case 'C':
- case 'D':
- case 'F':
- case 'I':
- case 'J':
- case 'S':
- case 'Z':
- if (UNLIKELY((descriptor[0] != shorty_char) || (descriptor[1] != '\0'))) {
- ErrorStringPrintf("Shorty vs. primitive type mismatch: '%c', '%s'",
- shorty_char, descriptor);
- return false;
- }
- break;
- case 'L':
- if (UNLIKELY((descriptor[0] != 'L') && (descriptor[0] != '['))) {
- ErrorStringPrintf("Shorty vs. type mismatch: '%c', '%s'", shorty_char, descriptor);
- return false;
- }
- break;
- default:
- ErrorStringPrintf("Bad shorty character: '%c'", shorty_char);
- return false;
- }
- return true;
-}
-
-bool DexFileVerifier::CheckListSize(const void* start, size_t count, size_t elem_size,
- const char* label) {
- // Check that size is not 0.
- CHECK_NE(elem_size, 0U);
-
- const uint8_t* range_start = reinterpret_cast<const uint8_t*>(start);
- const uint8_t* file_start = reinterpret_cast<const uint8_t*>(begin_);
-
- // Check for overflow.
- uintptr_t max = 0 - 1;
- size_t available_bytes_till_end_of_mem = max - reinterpret_cast<uintptr_t>(start);
- size_t max_count = available_bytes_till_end_of_mem / elem_size;
- if (max_count < count) {
- ErrorStringPrintf("Overflow in range for %s: %zx for %zu@%zu", label,
- static_cast<size_t>(range_start - file_start),
- count, elem_size);
- return false;
- }
-
- const uint8_t* range_end = range_start + count * elem_size;
- const uint8_t* file_end = file_start + size_;
- if (UNLIKELY((range_start < file_start) || (range_end > file_end))) {
- // Note: these two tests are enough as we make sure above that there's no overflow.
- ErrorStringPrintf("Bad range for %s: %zx to %zx", label,
- static_cast<size_t>(range_start - file_start),
- static_cast<size_t>(range_end - file_start));
- return false;
- }
- return true;
-}
-
-bool DexFileVerifier::CheckList(size_t element_size, const char* label, const uint8_t* *ptr) {
- // Check that the list is available. The first 4B are the count.
- if (!CheckListSize(*ptr, 1, 4U, label)) {
- return false;
- }
-
- uint32_t count = *reinterpret_cast<const uint32_t*>(*ptr);
- if (count > 0) {
- if (!CheckListSize(*ptr + 4, count, element_size, label)) {
- return false;
- }
- }
-
- *ptr += 4 + count * element_size;
- return true;
-}
-
-bool DexFileVerifier::CheckIndex(uint32_t field, uint32_t limit, const char* label) {
- if (UNLIKELY(field >= limit)) {
- ErrorStringPrintf("Bad index for %s: %x >= %x", label, field, limit);
- return false;
- }
- return true;
-}
-
-bool DexFileVerifier::CheckValidOffsetAndSize(uint32_t offset,
- uint32_t size,
- size_t alignment,
- const char* label) {
- if (size == 0) {
- if (offset != 0) {
- ErrorStringPrintf("Offset(%d) should be zero when size is zero for %s.", offset, label);
- return false;
- }
- }
- if (size_ <= offset) {
- ErrorStringPrintf("Offset(%d) should be within file size(%zu) for %s.", offset, size_, label);
- return false;
- }
- if (alignment != 0 && !IsAlignedParam(offset, alignment)) {
- ErrorStringPrintf("Offset(%d) should be aligned by %zu for %s.", offset, alignment, label);
- return false;
- }
- return true;
-}
-
-bool DexFileVerifier::CheckSizeLimit(uint32_t size, uint32_t limit, const char* label) {
- if (size > limit) {
- ErrorStringPrintf("Size(%u) should not exceed limit(%u) for %s.", size, limit, label);
- return false;
- }
- return true;
-}
-
-bool DexFileVerifier::CheckHeader() {
- // Check file size from the header.
- uint32_t expected_size = header_->file_size_;
- if (size_ != expected_size) {
- ErrorStringPrintf("Bad file size (%zd, expected %u)", size_, expected_size);
- return false;
- }
-
- uint32_t adler_checksum = dex_file_->CalculateChecksum();
- // Compute and verify the checksum in the header.
- if (adler_checksum != header_->checksum_) {
- if (verify_checksum_) {
- ErrorStringPrintf("Bad checksum (%08x, expected %08x)", adler_checksum, header_->checksum_);
- return false;
- } else {
- LOG(WARNING) << StringPrintf(
- "Ignoring bad checksum (%08x, expected %08x)", adler_checksum, header_->checksum_);
- }
- }
-
- // Check the contents of the header.
- if (header_->endian_tag_ != DexFile::kDexEndianConstant) {
- ErrorStringPrintf("Unexpected endian_tag: %x", header_->endian_tag_);
- return false;
- }
-
- const uint32_t expected_header_size = dex_file_->IsCompactDexFile()
- ? sizeof(CompactDexFile::Header)
- : sizeof(StandardDexFile::Header);
-
- if (header_->header_size_ != expected_header_size) {
- ErrorStringPrintf("Bad header size: %ud expected %ud",
- header_->header_size_,
- expected_header_size);
- return false;
- }
-
- // Check that all offsets are inside the file.
- bool result =
- CheckValidOffsetAndSize(header_->link_off_,
- header_->link_size_,
- 0 /* unaligned */,
- "link") &&
- CheckValidOffsetAndSize(header_->map_off_,
- header_->map_off_,
- 4,
- "map") &&
- CheckValidOffsetAndSize(header_->string_ids_off_,
- header_->string_ids_size_,
- 4,
- "string-ids") &&
- CheckValidOffsetAndSize(header_->type_ids_off_,
- header_->type_ids_size_,
- 4,
- "type-ids") &&
- CheckSizeLimit(header_->type_ids_size_, DexFile::kDexNoIndex16, "type-ids") &&
- CheckValidOffsetAndSize(header_->proto_ids_off_,
- header_->proto_ids_size_,
- 4,
- "proto-ids") &&
- CheckSizeLimit(header_->proto_ids_size_, DexFile::kDexNoIndex16, "proto-ids") &&
- CheckValidOffsetAndSize(header_->field_ids_off_,
- header_->field_ids_size_,
- 4,
- "field-ids") &&
- CheckValidOffsetAndSize(header_->method_ids_off_,
- header_->method_ids_size_,
- 4,
- "method-ids") &&
- CheckValidOffsetAndSize(header_->class_defs_off_,
- header_->class_defs_size_,
- 4,
- "class-defs") &&
- CheckValidOffsetAndSize(header_->data_off_,
- header_->data_size_,
- 0, // Unaligned, spec doesn't talk about it, even though size
- // is supposed to be a multiple of 4.
- "data");
- return result;
-}
-
-bool DexFileVerifier::CheckMap() {
- const DexFile::MapList* map = reinterpret_cast<const DexFile::MapList*>(begin_ +
- header_->map_off_);
- // Check that map list content is available.
- if (!CheckListSize(map, 1, sizeof(DexFile::MapList), "maplist content")) {
- return false;
- }
-
- const DexFile::MapItem* item = map->list_;
-
- uint32_t count = map->size_;
- uint32_t last_offset = 0;
- uint32_t last_type = 0;
- uint32_t data_item_count = 0;
- uint32_t data_items_left = header_->data_size_;
- uint32_t used_bits = 0;
-
- // Sanity check the size of the map list.
- if (!CheckListSize(item, count, sizeof(DexFile::MapItem), "map size")) {
- return false;
- }
-
- // Check the items listed in the map.
- for (uint32_t i = 0; i < count; i++) {
- if (UNLIKELY(last_offset >= item->offset_ && i != 0)) {
- ErrorStringPrintf("Out of order map item: %x then %x for type %x last type was %x",
- last_offset,
- item->offset_,
- static_cast<uint32_t>(item->type_),
- last_type);
- return false;
- }
- if (UNLIKELY(item->offset_ >= header_->file_size_)) {
- ErrorStringPrintf("Map item after end of file: %x, size %x",
- item->offset_, header_->file_size_);
- return false;
- }
-
- DexFile::MapItemType item_type = static_cast<DexFile::MapItemType>(item->type_);
- if (IsDataSectionType(item_type)) {
- uint32_t icount = item->size_;
- if (UNLIKELY(icount > data_items_left)) {
- ErrorStringPrintf("Too many items in data section: %ud item_type %zx",
- data_item_count + icount,
- static_cast<size_t>(item_type));
- return false;
- }
- data_items_left -= icount;
- data_item_count += icount;
- }
-
- uint32_t bit = MapTypeToBitMask(item_type);
-
- if (UNLIKELY(bit == 0)) {
- ErrorStringPrintf("Unknown map section type %x", item->type_);
- return false;
- }
-
- if (UNLIKELY((used_bits & bit) != 0)) {
- ErrorStringPrintf("Duplicate map section of type %x", item->type_);
- return false;
- }
-
- used_bits |= bit;
- last_offset = item->offset_;
- last_type = item->type_;
- item++;
- }
-
- // Check for missing sections in the map.
- if (UNLIKELY((used_bits & MapTypeToBitMask(DexFile::kDexTypeHeaderItem)) == 0)) {
- ErrorStringPrintf("Map is missing header entry");
- return false;
- }
- if (UNLIKELY((used_bits & MapTypeToBitMask(DexFile::kDexTypeMapList)) == 0)) {
- ErrorStringPrintf("Map is missing map_list entry");
- return false;
- }
- if (UNLIKELY((used_bits & MapTypeToBitMask(DexFile::kDexTypeStringIdItem)) == 0 &&
- ((header_->string_ids_off_ != 0) || (header_->string_ids_size_ != 0)))) {
- ErrorStringPrintf("Map is missing string_ids entry");
- return false;
- }
- if (UNLIKELY((used_bits & MapTypeToBitMask(DexFile::kDexTypeTypeIdItem)) == 0 &&
- ((header_->type_ids_off_ != 0) || (header_->type_ids_size_ != 0)))) {
- ErrorStringPrintf("Map is missing type_ids entry");
- return false;
- }
- if (UNLIKELY((used_bits & MapTypeToBitMask(DexFile::kDexTypeProtoIdItem)) == 0 &&
- ((header_->proto_ids_off_ != 0) || (header_->proto_ids_size_ != 0)))) {
- ErrorStringPrintf("Map is missing proto_ids entry");
- return false;
- }
- if (UNLIKELY((used_bits & MapTypeToBitMask(DexFile::kDexTypeFieldIdItem)) == 0 &&
- ((header_->field_ids_off_ != 0) || (header_->field_ids_size_ != 0)))) {
- ErrorStringPrintf("Map is missing field_ids entry");
- return false;
- }
- if (UNLIKELY((used_bits & MapTypeToBitMask(DexFile::kDexTypeMethodIdItem)) == 0 &&
- ((header_->method_ids_off_ != 0) || (header_->method_ids_size_ != 0)))) {
- ErrorStringPrintf("Map is missing method_ids entry");
- return false;
- }
- if (UNLIKELY((used_bits & MapTypeToBitMask(DexFile::kDexTypeClassDefItem)) == 0 &&
- ((header_->class_defs_off_ != 0) || (header_->class_defs_size_ != 0)))) {
- ErrorStringPrintf("Map is missing class_defs entry");
- return false;
- }
- return true;
-}
-
-uint32_t DexFileVerifier::ReadUnsignedLittleEndian(uint32_t size) {
- uint32_t result = 0;
- if (LIKELY(CheckListSize(ptr_, size, sizeof(uint8_t), "encoded_value"))) {
- for (uint32_t i = 0; i < size; i++) {
- result |= ((uint32_t) *(ptr_++)) << (i * 8);
- }
- }
- return result;
-}
-
-
-#define DECODE_UNSIGNED_CHECKED_FROM_WITH_ERROR_VALUE(ptr, var, error_value) \
- uint32_t var; \
- if (!DecodeUnsignedLeb128Checked(&(ptr), begin_ + size_, &(var))) { \
- return error_value; \
- }
-
-#define DECODE_UNSIGNED_CHECKED_FROM(ptr, var) \
- uint32_t var; \
- if (!DecodeUnsignedLeb128Checked(&(ptr), begin_ + size_, &(var))) { \
- ErrorStringPrintf("Read out of bounds"); \
- return false; \
- }
-
-#define DECODE_SIGNED_CHECKED_FROM(ptr, var) \
- int32_t var; \
- if (!DecodeSignedLeb128Checked(&(ptr), begin_ + size_, &(var))) { \
- ErrorStringPrintf("Read out of bounds"); \
- return false; \
- }
-
-bool DexFileVerifier::CheckAndGetHandlerOffsets(const DexFile::CodeItem* code_item,
- uint32_t* handler_offsets, uint32_t handlers_size) {
- CodeItemDataAccessor accessor(*dex_file_, code_item);
- const uint8_t* handlers_base = accessor.GetCatchHandlerData();
-
- for (uint32_t i = 0; i < handlers_size; i++) {
- bool catch_all;
- size_t offset = ptr_ - handlers_base;
- DECODE_SIGNED_CHECKED_FROM(ptr_, size);
-
- if (UNLIKELY((size < -65536) || (size > 65536))) {
- ErrorStringPrintf("Invalid exception handler size: %d", size);
- return false;
- }
-
- if (size <= 0) {
- catch_all = true;
- size = -size;
- } else {
- catch_all = false;
- }
-
- handler_offsets[i] = static_cast<uint32_t>(offset);
-
- while (size-- > 0) {
- DECODE_UNSIGNED_CHECKED_FROM(ptr_, type_idx);
- if (!CheckIndex(type_idx, header_->type_ids_size_, "handler type_idx")) {
- return false;
- }
-
- DECODE_UNSIGNED_CHECKED_FROM(ptr_, addr);
- if (UNLIKELY(addr >= accessor.InsnsSizeInCodeUnits())) {
- ErrorStringPrintf("Invalid handler addr: %x", addr);
- return false;
- }
- }
-
- if (catch_all) {
- DECODE_UNSIGNED_CHECKED_FROM(ptr_, addr);
- if (UNLIKELY(addr >= accessor.InsnsSizeInCodeUnits())) {
- ErrorStringPrintf("Invalid handler catch_all_addr: %x", addr);
- return false;
- }
- }
- }
-
- return true;
-}
-
-bool DexFileVerifier::CheckClassDataItemField(uint32_t idx,
- uint32_t access_flags,
- uint32_t class_access_flags,
- dex::TypeIndex class_type_index,
- bool expect_static) {
- // Check for overflow.
- if (!CheckIndex(idx, header_->field_ids_size_, "class_data_item field_idx")) {
- return false;
- }
-
- // Check that it's the right class.
- dex::TypeIndex my_class_index =
- (reinterpret_cast<const DexFile::FieldId*>(begin_ + header_->field_ids_off_) + idx)->
- class_idx_;
- if (class_type_index != my_class_index) {
- ErrorStringPrintf("Field's class index unexpected, %" PRIu16 "vs %" PRIu16,
- my_class_index.index_,
- class_type_index.index_);
- return false;
- }
-
- // Check that it falls into the right class-data list.
- bool is_static = (access_flags & kAccStatic) != 0;
- if (UNLIKELY(is_static != expect_static)) {
- ErrorStringPrintf("Static/instance field not in expected list");
- return false;
- }
-
- // Check field access flags.
- std::string error_msg;
- if (!CheckFieldAccessFlags(idx, access_flags, class_access_flags, &error_msg)) {
- ErrorStringPrintf("%s", error_msg.c_str());
- return false;
- }
-
- return true;
-}
-
-bool DexFileVerifier::CheckClassDataItemMethod(uint32_t idx,
- uint32_t access_flags,
- uint32_t class_access_flags,
- dex::TypeIndex class_type_index,
- uint32_t code_offset,
- std::unordered_set<uint32_t>* direct_method_indexes,
- bool expect_direct) {
- DCHECK(direct_method_indexes != nullptr);
- // Check for overflow.
- if (!CheckIndex(idx, header_->method_ids_size_, "class_data_item method_idx")) {
- return false;
- }
-
- // Check that it's the right class.
- dex::TypeIndex my_class_index =
- (reinterpret_cast<const DexFile::MethodId*>(begin_ + header_->method_ids_off_) + idx)->
- class_idx_;
- if (class_type_index != my_class_index) {
- ErrorStringPrintf("Method's class index unexpected, %" PRIu16 " vs %" PRIu16,
- my_class_index.index_,
- class_type_index.index_);
- return false;
- }
-
- // Check that it's not defined as both direct and virtual.
- if (expect_direct) {
- direct_method_indexes->insert(idx);
- } else if (direct_method_indexes->find(idx) != direct_method_indexes->end()) {
- ErrorStringPrintf("Found virtual method with same index as direct method: %d", idx);
- return false;
- }
-
- std::string error_msg;
- const char* method_name;
- if (!FindMethodName(idx, begin_, header_, &method_name, &error_msg)) {
- ErrorStringPrintf("%s", error_msg.c_str());
- return false;
- }
-
- uint32_t constructor_flags_by_name = 0;
- if (!GetConstructorFlagsForMethodName(method_name, &constructor_flags_by_name)) {
- ErrorStringPrintf("Bad method name: %s", method_name);
- return false;
- }
-
- bool has_code = (code_offset != 0);
- if (!CheckMethodAccessFlags(idx,
- access_flags,
- class_access_flags,
- constructor_flags_by_name,
- has_code,
- expect_direct,
- &error_msg)) {
- ErrorStringPrintf("%s", error_msg.c_str());
- return false;
- }
-
- if (constructor_flags_by_name != 0) {
- if (!CheckConstructorProperties(idx, constructor_flags_by_name)) {
- DCHECK(FailureReasonIsSet());
- return false;
- }
- }
-
- return true;
-}
-
-bool DexFileVerifier::CheckPadding(size_t offset,
- uint32_t aligned_offset,
- DexFile::MapItemType type) {
- if (offset < aligned_offset) {
- if (!CheckListSize(begin_ + offset, aligned_offset - offset, sizeof(uint8_t), "section")) {
- return false;
- }
- while (offset < aligned_offset) {
- if (UNLIKELY(*ptr_ != '\0')) {
- ErrorStringPrintf("Non-zero padding %x before section of type %zu at offset 0x%zx",
- *ptr_,
- static_cast<size_t>(type),
- offset);
- return false;
- }
- ptr_++;
- offset++;
- }
- }
- return true;
-}
-
-bool DexFileVerifier::CheckEncodedValue() {
- if (!CheckListSize(ptr_, 1, sizeof(uint8_t), "encoded_value header")) {
- return false;
- }
-
- uint8_t header_byte = *(ptr_++);
- uint32_t value_type = header_byte & DexFile::kDexAnnotationValueTypeMask;
- uint32_t value_arg = header_byte >> DexFile::kDexAnnotationValueArgShift;
-
- switch (value_type) {
- case DexFile::kDexAnnotationByte:
- if (UNLIKELY(value_arg != 0)) {
- ErrorStringPrintf("Bad encoded_value byte size %x", value_arg);
- return false;
- }
- ptr_++;
- break;
- case DexFile::kDexAnnotationShort:
- case DexFile::kDexAnnotationChar:
- if (UNLIKELY(value_arg > 1)) {
- ErrorStringPrintf("Bad encoded_value char/short size %x", value_arg);
- return false;
- }
- ptr_ += value_arg + 1;
- break;
- case DexFile::kDexAnnotationInt:
- case DexFile::kDexAnnotationFloat:
- if (UNLIKELY(value_arg > 3)) {
- ErrorStringPrintf("Bad encoded_value int/float size %x", value_arg);
- return false;
- }
- ptr_ += value_arg + 1;
- break;
- case DexFile::kDexAnnotationLong:
- case DexFile::kDexAnnotationDouble:
- ptr_ += value_arg + 1;
- break;
- case DexFile::kDexAnnotationString: {
- if (UNLIKELY(value_arg > 3)) {
- ErrorStringPrintf("Bad encoded_value string size %x", value_arg);
- return false;
- }
- uint32_t idx = ReadUnsignedLittleEndian(value_arg + 1);
- if (!CheckIndex(idx, header_->string_ids_size_, "encoded_value string")) {
- return false;
- }
- break;
- }
- case DexFile::kDexAnnotationType: {
- if (UNLIKELY(value_arg > 3)) {
- ErrorStringPrintf("Bad encoded_value type size %x", value_arg);
- return false;
- }
- uint32_t idx = ReadUnsignedLittleEndian(value_arg + 1);
- if (!CheckIndex(idx, header_->type_ids_size_, "encoded_value type")) {
- return false;
- }
- break;
- }
- case DexFile::kDexAnnotationField:
- case DexFile::kDexAnnotationEnum: {
- if (UNLIKELY(value_arg > 3)) {
- ErrorStringPrintf("Bad encoded_value field/enum size %x", value_arg);
- return false;
- }
- uint32_t idx = ReadUnsignedLittleEndian(value_arg + 1);
- if (!CheckIndex(idx, header_->field_ids_size_, "encoded_value field")) {
- return false;
- }
- break;
- }
- case DexFile::kDexAnnotationMethod: {
- if (UNLIKELY(value_arg > 3)) {
- ErrorStringPrintf("Bad encoded_value method size %x", value_arg);
- return false;
- }
- uint32_t idx = ReadUnsignedLittleEndian(value_arg + 1);
- if (!CheckIndex(idx, header_->method_ids_size_, "encoded_value method")) {
- return false;
- }
- break;
- }
- case DexFile::kDexAnnotationArray:
- if (UNLIKELY(value_arg != 0)) {
- ErrorStringPrintf("Bad encoded_value array value_arg %x", value_arg);
- return false;
- }
- if (!CheckEncodedArray()) {
- return false;
- }
- break;
- case DexFile::kDexAnnotationAnnotation:
- if (UNLIKELY(value_arg != 0)) {
- ErrorStringPrintf("Bad encoded_value annotation value_arg %x", value_arg);
- return false;
- }
- if (!CheckEncodedAnnotation()) {
- return false;
- }
- break;
- case DexFile::kDexAnnotationNull:
- if (UNLIKELY(value_arg != 0)) {
- ErrorStringPrintf("Bad encoded_value null value_arg %x", value_arg);
- return false;
- }
- break;
- case DexFile::kDexAnnotationBoolean:
- if (UNLIKELY(value_arg > 1)) {
- ErrorStringPrintf("Bad encoded_value boolean size %x", value_arg);
- return false;
- }
- break;
- case DexFile::kDexAnnotationMethodType: {
- if (UNLIKELY(value_arg > 3)) {
- ErrorStringPrintf("Bad encoded_value method type size %x", value_arg);
- return false;
- }
- uint32_t idx = ReadUnsignedLittleEndian(value_arg + 1);
- if (!CheckIndex(idx, header_->proto_ids_size_, "method_type value")) {
- return false;
- }
- break;
- }
- case DexFile::kDexAnnotationMethodHandle: {
- if (UNLIKELY(value_arg > 3)) {
- ErrorStringPrintf("Bad encoded_value method handle size %x", value_arg);
- return false;
- }
- uint32_t idx = ReadUnsignedLittleEndian(value_arg + 1);
- if (!CheckIndex(idx, dex_file_->NumMethodHandles(), "method_handle value")) {
- return false;
- }
- break;
- }
- default:
- ErrorStringPrintf("Bogus encoded_value value_type %x", value_type);
- return false;
- }
-
- return true;
-}
-
-bool DexFileVerifier::CheckEncodedArray() {
- DECODE_UNSIGNED_CHECKED_FROM(ptr_, size);
-
- while (size--) {
- if (!CheckEncodedValue()) {
- failure_reason_ = StringPrintf("Bad encoded_array value: %s", failure_reason_.c_str());
- return false;
- }
- }
- return true;
-}
-
-bool DexFileVerifier::CheckEncodedAnnotation() {
- DECODE_UNSIGNED_CHECKED_FROM(ptr_, anno_idx);
- if (!CheckIndex(anno_idx, header_->type_ids_size_, "encoded_annotation type_idx")) {
- return false;
- }
-
- DECODE_UNSIGNED_CHECKED_FROM(ptr_, size);
- uint32_t last_idx = 0;
-
- for (uint32_t i = 0; i < size; i++) {
- DECODE_UNSIGNED_CHECKED_FROM(ptr_, idx);
- if (!CheckIndex(idx, header_->string_ids_size_, "annotation_element name_idx")) {
- return false;
- }
-
- if (UNLIKELY(last_idx >= idx && i != 0)) {
- ErrorStringPrintf("Out-of-order annotation_element name_idx: %x then %x",
- last_idx, idx);
- return false;
- }
-
- if (!CheckEncodedValue()) {
- return false;
- }
-
- last_idx = idx;
- }
- return true;
-}
-
-bool DexFileVerifier::FindClassIndexAndDef(uint32_t index,
- bool is_field,
- dex::TypeIndex* class_type_index,
- const DexFile::ClassDef** output_class_def) {
- DCHECK(class_type_index != nullptr);
- DCHECK(output_class_def != nullptr);
-
- // First check if the index is valid.
- if (index >= (is_field ? header_->field_ids_size_ : header_->method_ids_size_)) {
- return false;
- }
-
- // Next get the type index.
- if (is_field) {
- *class_type_index =
- (reinterpret_cast<const DexFile::FieldId*>(begin_ + header_->field_ids_off_) + index)->
- class_idx_;
- } else {
- *class_type_index =
- (reinterpret_cast<const DexFile::MethodId*>(begin_ + header_->method_ids_off_) + index)->
- class_idx_;
- }
-
- // Check if that is valid.
- if (class_type_index->index_ >= header_->type_ids_size_) {
- return false;
- }
-
- // Now search for the class def. This is basically a specialized version of the DexFile code, as
- // we should not trust that this is a valid DexFile just yet.
- const DexFile::ClassDef* class_def_begin =
- reinterpret_cast<const DexFile::ClassDef*>(begin_ + header_->class_defs_off_);
- for (size_t i = 0; i < header_->class_defs_size_; ++i) {
- const DexFile::ClassDef* class_def = class_def_begin + i;
- if (class_def->class_idx_ == *class_type_index) {
- *output_class_def = class_def;
- return true;
- }
- }
-
- // Didn't find the class-def, not defined here...
- return false;
-}
-
-bool DexFileVerifier::CheckOrderAndGetClassDef(bool is_field,
- const char* type_descr,
- uint32_t curr_index,
- uint32_t prev_index,
- bool* have_class,
- dex::TypeIndex* class_type_index,
- const DexFile::ClassDef** class_def) {
- if (curr_index < prev_index) {
- ErrorStringPrintf("out-of-order %s indexes %" PRIu32 " and %" PRIu32,
- type_descr,
- prev_index,
- curr_index);
- return false;
- }
-
- if (!*have_class) {
- *have_class = FindClassIndexAndDef(curr_index, is_field, class_type_index, class_def);
- if (!*have_class) {
- // Should have really found one.
- ErrorStringPrintf("could not find declaring class for %s index %" PRIu32,
- type_descr,
- curr_index);
- return false;
- }
- }
- return true;
-}
-
-bool DexFileVerifier::CheckStaticFieldTypes(const DexFile::ClassDef* class_def) {
- if (class_def == nullptr) {
- return true;
- }
-
- ClassDataItemIterator field_it(*dex_file_, ptr_);
- EncodedStaticFieldValueIterator array_it(*dex_file_, *class_def);
-
- for (; field_it.HasNextStaticField() && array_it.HasNext(); field_it.Next(), array_it.Next()) {
- uint32_t index = field_it.GetMemberIndex();
- const DexFile::TypeId& type_id = dex_file_->GetTypeId(dex_file_->GetFieldId(index).type_idx_);
- const char* field_type_name =
- dex_file_->GetStringData(dex_file_->GetStringId(type_id.descriptor_idx_));
- Primitive::Type field_type = Primitive::GetType(field_type_name[0]);
- EncodedArrayValueIterator::ValueType array_type = array_it.GetValueType();
- // Ensure this matches RuntimeEncodedStaticFieldValueIterator.
- switch (array_type) {
- case EncodedArrayValueIterator::ValueType::kBoolean:
- if (field_type != Primitive::kPrimBoolean) {
- ErrorStringPrintf("unexpected static field initial value type: 'Z' vs '%c'",
- field_type_name[0]);
- return false;
- }
- break;
- case EncodedArrayValueIterator::ValueType::kByte:
- if (field_type != Primitive::kPrimByte) {
- ErrorStringPrintf("unexpected static field initial value type: 'B' vs '%c'",
- field_type_name[0]);
- return false;
- }
- break;
- case EncodedArrayValueIterator::ValueType::kShort:
- if (field_type != Primitive::kPrimShort) {
- ErrorStringPrintf("unexpected static field initial value type: 'S' vs '%c'",
- field_type_name[0]);
- return false;
- }
- break;
- case EncodedArrayValueIterator::ValueType::kChar:
- if (field_type != Primitive::kPrimChar) {
- ErrorStringPrintf("unexpected static field initial value type: 'C' vs '%c'",
- field_type_name[0]);
- return false;
- }
- break;
- case EncodedArrayValueIterator::ValueType::kInt:
- if (field_type != Primitive::kPrimInt) {
- ErrorStringPrintf("unexpected static field initial value type: 'I' vs '%c'",
- field_type_name[0]);
- return false;
- }
- break;
- case EncodedArrayValueIterator::ValueType::kLong:
- if (field_type != Primitive::kPrimLong) {
- ErrorStringPrintf("unexpected static field initial value type: 'J' vs '%c'",
- field_type_name[0]);
- return false;
- }
- break;
- case EncodedArrayValueIterator::ValueType::kFloat:
- if (field_type != Primitive::kPrimFloat) {
- ErrorStringPrintf("unexpected static field initial value type: 'F' vs '%c'",
- field_type_name[0]);
- return false;
- }
- break;
- case EncodedArrayValueIterator::ValueType::kDouble:
- if (field_type != Primitive::kPrimDouble) {
- ErrorStringPrintf("unexpected static field initial value type: 'D' vs '%c'",
- field_type_name[0]);
- return false;
- }
- break;
- case EncodedArrayValueIterator::ValueType::kNull:
- case EncodedArrayValueIterator::ValueType::kString:
- case EncodedArrayValueIterator::ValueType::kType:
- if (field_type != Primitive::kPrimNot) {
- ErrorStringPrintf("unexpected static field initial value type: 'L' vs '%c'",
- field_type_name[0]);
- return false;
- }
- break;
- default:
- ErrorStringPrintf("unexpected static field initial value type: %x", array_type);
- return false;
- }
- }
-
- if (array_it.HasNext()) {
- ErrorStringPrintf("too many static field initial values");
- return false;
- }
- return true;
-}
-
-template <bool kStatic>
-bool DexFileVerifier::CheckIntraClassDataItemFields(ClassDataItemIterator* it,
- bool* have_class,
- dex::TypeIndex* class_type_index,
- const DexFile::ClassDef** class_def) {
- DCHECK(it != nullptr);
- // These calls use the raw access flags to check whether the whole dex field is valid.
- uint32_t prev_index = 0;
- for (; kStatic ? it->HasNextStaticField() : it->HasNextInstanceField(); it->Next()) {
- uint32_t curr_index = it->GetMemberIndex();
- if (!CheckOrderAndGetClassDef(true,
- kStatic ? "static field" : "instance field",
- curr_index,
- prev_index,
- have_class,
- class_type_index,
- class_def)) {
- return false;
- }
- DCHECK(class_def != nullptr);
- if (!CheckClassDataItemField(curr_index,
- it->GetRawMemberAccessFlags(),
- (*class_def)->access_flags_,
- *class_type_index,
- kStatic)) {
- return false;
- }
-
- prev_index = curr_index;
- }
-
- return true;
-}
-
-template <bool kDirect>
-bool DexFileVerifier::CheckIntraClassDataItemMethods(
- ClassDataItemIterator* it,
- std::unordered_set<uint32_t>* direct_method_indexes,
- bool* have_class,
- dex::TypeIndex* class_type_index,
- const DexFile::ClassDef** class_def) {
- uint32_t prev_index = 0;
- for (; kDirect ? it->HasNextDirectMethod() : it->HasNextVirtualMethod(); it->Next()) {
- uint32_t curr_index = it->GetMemberIndex();
- if (!CheckOrderAndGetClassDef(false,
- kDirect ? "direct method" : "virtual method",
- curr_index,
- prev_index,
- have_class,
- class_type_index,
- class_def)) {
- return false;
- }
- DCHECK(class_def != nullptr);
- if (!CheckClassDataItemMethod(curr_index,
- it->GetRawMemberAccessFlags(),
- (*class_def)->access_flags_,
- *class_type_index,
- it->GetMethodCodeItemOffset(),
- direct_method_indexes,
- kDirect)) {
- return false;
- }
-
- prev_index = curr_index;
- }
-
- return true;
-}
-
-bool DexFileVerifier::CheckIntraClassDataItem() {
- ClassDataItemIterator it(*dex_file_, ptr_);
- std::unordered_set<uint32_t> direct_method_indexes;
-
- // This code is complicated by the fact that we don't directly know which class this belongs to.
- // So we need to explicitly search with the first item we find (either field or method), and then,
- // as the lookup is expensive, cache the result.
- bool have_class = false;
- dex::TypeIndex class_type_index;
- const DexFile::ClassDef* class_def = nullptr;
-
- // Check fields.
- if (!CheckIntraClassDataItemFields<true>(&it,
- &have_class,
- &class_type_index,
- &class_def)) {
- return false;
- }
- if (!CheckIntraClassDataItemFields<false>(&it,
- &have_class,
- &class_type_index,
- &class_def)) {
- return false;
- }
-
- // Check methods.
- if (!CheckIntraClassDataItemMethods<true>(&it,
- &direct_method_indexes,
- &have_class,
- &class_type_index,
- &class_def)) {
- return false;
- }
- if (!CheckIntraClassDataItemMethods<false>(&it,
- &direct_method_indexes,
- &have_class,
- &class_type_index,
- &class_def)) {
- return false;
- }
-
- const uint8_t* end_ptr = it.EndDataPointer();
-
- // Check static field types against initial static values in encoded array.
- if (!CheckStaticFieldTypes(class_def)) {
- return false;
- }
-
- ptr_ = end_ptr;
- return true;
-}
-
-bool DexFileVerifier::CheckIntraCodeItem() {
- const DexFile::CodeItem* code_item = reinterpret_cast<const DexFile::CodeItem*>(ptr_);
- if (!CheckListSize(code_item, 1, sizeof(DexFile::CodeItem), "code")) {
- return false;
- }
-
- CodeItemDataAccessor accessor(*dex_file_, code_item);
- if (UNLIKELY(accessor.InsSize() > accessor.RegistersSize())) {
- ErrorStringPrintf("ins_size (%ud) > registers_size (%ud)",
- accessor.InsSize(), accessor.RegistersSize());
- return false;
- }
-
- if (UNLIKELY(accessor.OutsSize() > 5 && accessor.OutsSize() > accessor.RegistersSize())) {
- /*
- * outs_size can be up to 5, even if registers_size is smaller, since the
- * short forms of method invocation allow repetitions of a register multiple
- * times within a single parameter list. However, longer parameter lists
- * need to be represented in-order in the register file.
- */
- ErrorStringPrintf("outs_size (%ud) > registers_size (%ud)",
- accessor.OutsSize(), accessor.RegistersSize());
- return false;
- }
-
- const uint16_t* insns = accessor.Insns();
- uint32_t insns_size = accessor.InsnsSizeInCodeUnits();
- if (!CheckListSize(insns, insns_size, sizeof(uint16_t), "insns size")) {
- return false;
- }
-
- // Grab the end of the insns if there are no try_items.
- uint32_t try_items_size = accessor.TriesSize();
- if (try_items_size == 0) {
- ptr_ = reinterpret_cast<const uint8_t*>(&insns[insns_size]);
- return true;
- }
-
- // try_items are 4-byte aligned. Verify the spacer is 0.
- if (((reinterpret_cast<uintptr_t>(&insns[insns_size]) & 3) != 0) && (insns[insns_size] != 0)) {
- ErrorStringPrintf("Non-zero padding: %x", insns[insns_size]);
- return false;
- }
-
- const DexFile::TryItem* try_items = accessor.TryItems().begin();
- if (!CheckListSize(try_items, try_items_size, sizeof(DexFile::TryItem), "try_items size")) {
- return false;
- }
-
- ptr_ = accessor.GetCatchHandlerData();
- DECODE_UNSIGNED_CHECKED_FROM(ptr_, handlers_size);
-
- if (UNLIKELY((handlers_size == 0) || (handlers_size >= 65536))) {
- ErrorStringPrintf("Invalid handlers_size: %ud", handlers_size);
- return false;
- }
-
- std::unique_ptr<uint32_t[]> handler_offsets(new uint32_t[handlers_size]);
- if (!CheckAndGetHandlerOffsets(code_item, &handler_offsets[0], handlers_size)) {
- return false;
- }
-
- uint32_t last_addr = 0;
- while (try_items_size--) {
- if (UNLIKELY(try_items->start_addr_ < last_addr)) {
- ErrorStringPrintf("Out-of_order try_item with start_addr: %x", try_items->start_addr_);
- return false;
- }
-
- if (UNLIKELY(try_items->start_addr_ >= insns_size)) {
- ErrorStringPrintf("Invalid try_item start_addr: %x", try_items->start_addr_);
- return false;
- }
-
- uint32_t i;
- for (i = 0; i < handlers_size; i++) {
- if (try_items->handler_off_ == handler_offsets[i]) {
- break;
- }
- }
-
- if (UNLIKELY(i == handlers_size)) {
- ErrorStringPrintf("Bogus handler offset: %x", try_items->handler_off_);
- return false;
- }
-
- last_addr = try_items->start_addr_ + try_items->insn_count_;
- if (UNLIKELY(last_addr > insns_size)) {
- ErrorStringPrintf("Invalid try_item insn_count: %x", try_items->insn_count_);
- return false;
- }
-
- try_items++;
- }
-
- return true;
-}
-
-bool DexFileVerifier::CheckIntraStringDataItem() {
- DECODE_UNSIGNED_CHECKED_FROM(ptr_, size);
- const uint8_t* file_end = begin_ + size_;
-
- for (uint32_t i = 0; i < size; i++) {
- CHECK_LT(i, size); // b/15014252 Prevents hitting the impossible case below
- if (UNLIKELY(ptr_ >= file_end)) {
- ErrorStringPrintf("String data would go beyond end-of-file");
- return false;
- }
-
- uint8_t byte = *(ptr_++);
-
- // Switch on the high 4 bits.
- switch (byte >> 4) {
- case 0x00:
- // Special case of bit pattern 0xxx.
- if (UNLIKELY(byte == 0)) {
- CHECK_LT(i, size); // b/15014252 Actually hit this impossible case with clang
- ErrorStringPrintf("String data shorter than indicated utf16_size %x", size);
- return false;
- }
- break;
- case 0x01:
- case 0x02:
- case 0x03:
- case 0x04:
- case 0x05:
- case 0x06:
- case 0x07:
- // No extra checks necessary for bit pattern 0xxx.
- break;
- case 0x08:
- case 0x09:
- case 0x0a:
- case 0x0b:
- case 0x0f:
- // Illegal bit patterns 10xx or 1111.
- // Note: 1111 is valid for normal UTF-8, but not here.
- ErrorStringPrintf("Illegal start byte %x in string data", byte);
- return false;
- case 0x0c:
- case 0x0d: {
- // Bit pattern 110x has an additional byte.
- uint8_t byte2 = *(ptr_++);
- if (UNLIKELY((byte2 & 0xc0) != 0x80)) {
- ErrorStringPrintf("Illegal continuation byte %x in string data", byte2);
- return false;
- }
- uint16_t value = ((byte & 0x1f) << 6) | (byte2 & 0x3f);
- if (UNLIKELY((value != 0) && (value < 0x80))) {
- ErrorStringPrintf("Illegal representation for value %x in string data", value);
- return false;
- }
- break;
- }
- case 0x0e: {
- // Bit pattern 1110 has 2 additional bytes.
- uint8_t byte2 = *(ptr_++);
- if (UNLIKELY((byte2 & 0xc0) != 0x80)) {
- ErrorStringPrintf("Illegal continuation byte %x in string data", byte2);
- return false;
- }
- uint8_t byte3 = *(ptr_++);
- if (UNLIKELY((byte3 & 0xc0) != 0x80)) {
- ErrorStringPrintf("Illegal continuation byte %x in string data", byte3);
- return false;
- }
- uint16_t value = ((byte & 0x0f) << 12) | ((byte2 & 0x3f) << 6) | (byte3 & 0x3f);
- if (UNLIKELY(value < 0x800)) {
- ErrorStringPrintf("Illegal representation for value %x in string data", value);
- return false;
- }
- break;
- }
- }
- }
-
- if (UNLIKELY(*(ptr_++) != '\0')) {
- ErrorStringPrintf("String longer than indicated size %x", size);
- return false;
- }
-
- return true;
-}
-
-bool DexFileVerifier::CheckIntraDebugInfoItem() {
- DECODE_UNSIGNED_CHECKED_FROM(ptr_, dummy);
- DECODE_UNSIGNED_CHECKED_FROM(ptr_, parameters_size);
- if (UNLIKELY(parameters_size > 65536)) {
- ErrorStringPrintf("Invalid parameters_size: %x", parameters_size);
- return false;
- }
-
- for (uint32_t j = 0; j < parameters_size; j++) {
- DECODE_UNSIGNED_CHECKED_FROM(ptr_, parameter_name);
- if (parameter_name != 0) {
- parameter_name--;
- if (!CheckIndex(parameter_name, header_->string_ids_size_, "debug_info_item parameter_name")) {
- return false;
- }
- }
- }
-
- while (true) {
- uint8_t opcode = *(ptr_++);
- switch (opcode) {
- case DexFile::DBG_END_SEQUENCE: {
- return true;
- }
- case DexFile::DBG_ADVANCE_PC: {
- DECODE_UNSIGNED_CHECKED_FROM(ptr_, advance_pc_dummy);
- break;
- }
- case DexFile::DBG_ADVANCE_LINE: {
- DECODE_SIGNED_CHECKED_FROM(ptr_, advance_line_dummy);
- break;
- }
- case DexFile::DBG_START_LOCAL: {
- DECODE_UNSIGNED_CHECKED_FROM(ptr_, reg_num);
- if (UNLIKELY(reg_num >= 65536)) {
- ErrorStringPrintf("Bad reg_num for opcode %x", opcode);
- return false;
- }
- DECODE_UNSIGNED_CHECKED_FROM(ptr_, name_idx);
- if (name_idx != 0) {
- name_idx--;
- if (!CheckIndex(name_idx, header_->string_ids_size_, "DBG_START_LOCAL name_idx")) {
- return false;
- }
- }
- DECODE_UNSIGNED_CHECKED_FROM(ptr_, type_idx);
- if (type_idx != 0) {
- type_idx--;
- if (!CheckIndex(type_idx, header_->type_ids_size_, "DBG_START_LOCAL type_idx")) {
- return false;
- }
- }
- break;
- }
- case DexFile::DBG_END_LOCAL:
- case DexFile::DBG_RESTART_LOCAL: {
- DECODE_UNSIGNED_CHECKED_FROM(ptr_, reg_num);
- if (UNLIKELY(reg_num >= 65536)) {
- ErrorStringPrintf("Bad reg_num for opcode %x", opcode);
- return false;
- }
- break;
- }
- case DexFile::DBG_START_LOCAL_EXTENDED: {
- DECODE_UNSIGNED_CHECKED_FROM(ptr_, reg_num);
- if (UNLIKELY(reg_num >= 65536)) {
- ErrorStringPrintf("Bad reg_num for opcode %x", opcode);
- return false;
- }
- DECODE_UNSIGNED_CHECKED_FROM(ptr_, name_idx);
- if (name_idx != 0) {
- name_idx--;
- if (!CheckIndex(name_idx, header_->string_ids_size_, "DBG_START_LOCAL_EXTENDED name_idx")) {
- return false;
- }
- }
- DECODE_UNSIGNED_CHECKED_FROM(ptr_, type_idx);
- if (type_idx != 0) {
- type_idx--;
- if (!CheckIndex(type_idx, header_->type_ids_size_, "DBG_START_LOCAL_EXTENDED type_idx")) {
- return false;
- }
- }
- DECODE_UNSIGNED_CHECKED_FROM(ptr_, sig_idx);
- if (sig_idx != 0) {
- sig_idx--;
- if (!CheckIndex(sig_idx, header_->string_ids_size_, "DBG_START_LOCAL_EXTENDED sig_idx")) {
- return false;
- }
- }
- break;
- }
- case DexFile::DBG_SET_FILE: {
- DECODE_UNSIGNED_CHECKED_FROM(ptr_, name_idx);
- if (name_idx != 0) {
- name_idx--;
- if (!CheckIndex(name_idx, header_->string_ids_size_, "DBG_SET_FILE name_idx")) {
- return false;
- }
- }
- break;
- }
- }
- }
-}
-
-bool DexFileVerifier::CheckIntraAnnotationItem() {
- if (!CheckListSize(ptr_, 1, sizeof(uint8_t), "annotation visibility")) {
- return false;
- }
-
- // Check visibility
- switch (*(ptr_++)) {
- case DexFile::kDexVisibilityBuild:
- case DexFile::kDexVisibilityRuntime:
- case DexFile::kDexVisibilitySystem:
- break;
- default:
- ErrorStringPrintf("Bad annotation visibility: %x", *ptr_);
- return false;
- }
-
- if (!CheckEncodedAnnotation()) {
- return false;
- }
-
- return true;
-}
-
-bool DexFileVerifier::CheckIntraAnnotationsDirectoryItem() {
- const DexFile::AnnotationsDirectoryItem* item =
- reinterpret_cast<const DexFile::AnnotationsDirectoryItem*>(ptr_);
- if (!CheckListSize(item, 1, sizeof(DexFile::AnnotationsDirectoryItem), "annotations_directory")) {
- return false;
- }
-
- // Field annotations follow immediately after the annotations directory.
- const DexFile::FieldAnnotationsItem* field_item =
- reinterpret_cast<const DexFile::FieldAnnotationsItem*>(item + 1);
- uint32_t field_count = item->fields_size_;
- if (!CheckListSize(field_item, field_count, sizeof(DexFile::FieldAnnotationsItem), "field_annotations list")) {
- return false;
- }
-
- uint32_t last_idx = 0;
- for (uint32_t i = 0; i < field_count; i++) {
- if (UNLIKELY(last_idx >= field_item->field_idx_ && i != 0)) {
- ErrorStringPrintf("Out-of-order field_idx for annotation: %x then %x", last_idx, field_item->field_idx_);
- return false;
- }
- last_idx = field_item->field_idx_;
- field_item++;
- }
-
- // Method annotations follow immediately after field annotations.
- const DexFile::MethodAnnotationsItem* method_item =
- reinterpret_cast<const DexFile::MethodAnnotationsItem*>(field_item);
- uint32_t method_count = item->methods_size_;
- if (!CheckListSize(method_item, method_count, sizeof(DexFile::MethodAnnotationsItem), "method_annotations list")) {
- return false;
- }
-
- last_idx = 0;
- for (uint32_t i = 0; i < method_count; i++) {
- if (UNLIKELY(last_idx >= method_item->method_idx_ && i != 0)) {
- ErrorStringPrintf("Out-of-order method_idx for annotation: %x then %x",
- last_idx, method_item->method_idx_);
- return false;
- }
- last_idx = method_item->method_idx_;
- method_item++;
- }
-
- // Parameter annotations follow immediately after method annotations.
- const DexFile::ParameterAnnotationsItem* parameter_item =
- reinterpret_cast<const DexFile::ParameterAnnotationsItem*>(method_item);
- uint32_t parameter_count = item->parameters_size_;
- if (!CheckListSize(parameter_item, parameter_count, sizeof(DexFile::ParameterAnnotationsItem),
- "parameter_annotations list")) {
- return false;
- }
-
- last_idx = 0;
- for (uint32_t i = 0; i < parameter_count; i++) {
- if (UNLIKELY(last_idx >= parameter_item->method_idx_ && i != 0)) {
- ErrorStringPrintf("Out-of-order method_idx for annotation: %x then %x",
- last_idx, parameter_item->method_idx_);
- return false;
- }
- last_idx = parameter_item->method_idx_;
- parameter_item++;
- }
-
- // Return a pointer to the end of the annotations.
- ptr_ = reinterpret_cast<const uint8_t*>(parameter_item);
- return true;
-}
-
-bool DexFileVerifier::CheckIntraSectionIterate(size_t offset, uint32_t section_count,
- DexFile::MapItemType type) {
- // Get the right alignment mask for the type of section.
- size_t alignment_mask;
- switch (type) {
- case DexFile::kDexTypeClassDataItem:
- case DexFile::kDexTypeStringDataItem:
- case DexFile::kDexTypeDebugInfoItem:
- case DexFile::kDexTypeAnnotationItem:
- case DexFile::kDexTypeEncodedArrayItem:
- alignment_mask = sizeof(uint8_t) - 1;
- break;
- default:
- alignment_mask = sizeof(uint32_t) - 1;
- break;
- }
-
- // Iterate through the items in the section.
- for (uint32_t i = 0; i < section_count; i++) {
- size_t aligned_offset = (offset + alignment_mask) & ~alignment_mask;
-
- // Check the padding between items.
- if (!CheckPadding(offset, aligned_offset, type)) {
- return false;
- }
-
- // Check depending on the section type.
- const uint8_t* start_ptr = ptr_;
- switch (type) {
- case DexFile::kDexTypeStringIdItem: {
- if (!CheckListSize(ptr_, 1, sizeof(DexFile::StringId), "string_ids")) {
- return false;
- }
- ptr_ += sizeof(DexFile::StringId);
- break;
- }
- case DexFile::kDexTypeTypeIdItem: {
- if (!CheckListSize(ptr_, 1, sizeof(DexFile::TypeId), "type_ids")) {
- return false;
- }
- ptr_ += sizeof(DexFile::TypeId);
- break;
- }
- case DexFile::kDexTypeProtoIdItem: {
- if (!CheckListSize(ptr_, 1, sizeof(DexFile::ProtoId), "proto_ids")) {
- return false;
- }
- ptr_ += sizeof(DexFile::ProtoId);
- break;
- }
- case DexFile::kDexTypeFieldIdItem: {
- if (!CheckListSize(ptr_, 1, sizeof(DexFile::FieldId), "field_ids")) {
- return false;
- }
- ptr_ += sizeof(DexFile::FieldId);
- break;
- }
- case DexFile::kDexTypeMethodIdItem: {
- if (!CheckListSize(ptr_, 1, sizeof(DexFile::MethodId), "method_ids")) {
- return false;
- }
- ptr_ += sizeof(DexFile::MethodId);
- break;
- }
- case DexFile::kDexTypeClassDefItem: {
- if (!CheckListSize(ptr_, 1, sizeof(DexFile::ClassDef), "class_defs")) {
- return false;
- }
- ptr_ += sizeof(DexFile::ClassDef);
- break;
- }
- case DexFile::kDexTypeCallSiteIdItem: {
- if (!CheckListSize(ptr_, 1, sizeof(DexFile::CallSiteIdItem), "call_site_ids")) {
- return false;
- }
- ptr_ += sizeof(DexFile::CallSiteIdItem);
- break;
- }
- case DexFile::kDexTypeMethodHandleItem: {
- if (!CheckListSize(ptr_, 1, sizeof(DexFile::MethodHandleItem), "method_handles")) {
- return false;
- }
- ptr_ += sizeof(DexFile::MethodHandleItem);
- break;
- }
- case DexFile::kDexTypeTypeList: {
- if (!CheckList(sizeof(DexFile::TypeItem), "type_list", &ptr_)) {
- return false;
- }
- break;
- }
- case DexFile::kDexTypeAnnotationSetRefList: {
- if (!CheckList(sizeof(DexFile::AnnotationSetRefItem), "annotation_set_ref_list", &ptr_)) {
- return false;
- }
- break;
- }
- case DexFile::kDexTypeAnnotationSetItem: {
- if (!CheckList(sizeof(uint32_t), "annotation_set_item", &ptr_)) {
- return false;
- }
- break;
- }
- case DexFile::kDexTypeClassDataItem: {
- if (!CheckIntraClassDataItem()) {
- return false;
- }
- break;
- }
- case DexFile::kDexTypeCodeItem: {
- if (!CheckIntraCodeItem()) {
- return false;
- }
- break;
- }
- case DexFile::kDexTypeStringDataItem: {
- if (!CheckIntraStringDataItem()) {
- return false;
- }
- break;
- }
- case DexFile::kDexTypeDebugInfoItem: {
- if (!CheckIntraDebugInfoItem()) {
- return false;
- }
- break;
- }
- case DexFile::kDexTypeAnnotationItem: {
- if (!CheckIntraAnnotationItem()) {
- return false;
- }
- break;
- }
- case DexFile::kDexTypeEncodedArrayItem: {
- if (!CheckEncodedArray()) {
- return false;
- }
- break;
- }
- case DexFile::kDexTypeAnnotationsDirectoryItem: {
- if (!CheckIntraAnnotationsDirectoryItem()) {
- return false;
- }
- break;
- }
- case DexFile::kDexTypeHeaderItem:
- case DexFile::kDexTypeMapList:
- break;
- }
-
- if (start_ptr == ptr_) {
- ErrorStringPrintf("Unknown map item type %x", type);
- return false;
- }
-
- if (IsDataSectionType(type)) {
- if (aligned_offset == 0u) {
- ErrorStringPrintf("Item %d offset is 0", i);
- return false;
- }
- DCHECK(offset_to_type_map_.Find(aligned_offset) == offset_to_type_map_.end());
- offset_to_type_map_.Insert(std::pair<uint32_t, uint16_t>(aligned_offset, type));
- }
-
- aligned_offset = ptr_ - begin_;
- if (UNLIKELY(aligned_offset > size_)) {
- ErrorStringPrintf("Item %d at ends out of bounds", i);
- return false;
- }
-
- offset = aligned_offset;
- }
-
- return true;
-}
-
-bool DexFileVerifier::CheckIntraIdSection(size_t offset,
- uint32_t count,
- DexFile::MapItemType type) {
- uint32_t expected_offset;
- uint32_t expected_size;
-
- // Get the expected offset and size from the header.
- switch (type) {
- case DexFile::kDexTypeStringIdItem:
- expected_offset = header_->string_ids_off_;
- expected_size = header_->string_ids_size_;
- break;
- case DexFile::kDexTypeTypeIdItem:
- expected_offset = header_->type_ids_off_;
- expected_size = header_->type_ids_size_;
- break;
- case DexFile::kDexTypeProtoIdItem:
- expected_offset = header_->proto_ids_off_;
- expected_size = header_->proto_ids_size_;
- break;
- case DexFile::kDexTypeFieldIdItem:
- expected_offset = header_->field_ids_off_;
- expected_size = header_->field_ids_size_;
- break;
- case DexFile::kDexTypeMethodIdItem:
- expected_offset = header_->method_ids_off_;
- expected_size = header_->method_ids_size_;
- break;
- case DexFile::kDexTypeClassDefItem:
- expected_offset = header_->class_defs_off_;
- expected_size = header_->class_defs_size_;
- break;
- default:
- ErrorStringPrintf("Bad type for id section: %x", type);
- return false;
- }
-
- // Check that the offset and size are what were expected from the header.
- if (UNLIKELY(offset != expected_offset)) {
- ErrorStringPrintf("Bad offset for section: got %zx, expected %x", offset, expected_offset);
- return false;
- }
- if (UNLIKELY(count != expected_size)) {
- ErrorStringPrintf("Bad size for section: got %x, expected %x", count, expected_size);
- return false;
- }
-
- return CheckIntraSectionIterate(offset, count, type);
-}
-
-bool DexFileVerifier::CheckIntraDataSection(size_t offset,
- uint32_t count,
- DexFile::MapItemType type) {
- size_t data_start = header_->data_off_;
- size_t data_end = data_start + header_->data_size_;
-
- // Sanity check the offset of the section.
- if (UNLIKELY((offset < data_start) || (offset > data_end))) {
- ErrorStringPrintf("Bad offset for data subsection: %zx", offset);
- return false;
- }
-
- if (!CheckIntraSectionIterate(offset, count, type)) {
- return false;
- }
-
- size_t next_offset = ptr_ - begin_;
- if (next_offset > data_end) {
- ErrorStringPrintf("Out-of-bounds end of data subsection: %zu data_off=%u data_size=%u",
- next_offset,
- header_->data_off_,
- header_->data_size_);
- return false;
- }
-
- return true;
-}
-
-bool DexFileVerifier::CheckIntraSection() {
- const DexFile::MapList* map = reinterpret_cast<const DexFile::MapList*>(begin_ + header_->map_off_);
- const DexFile::MapItem* item = map->list_;
- size_t offset = 0;
- uint32_t count = map->size_;
- ptr_ = begin_;
-
- // Check the items listed in the map.
- while (count--) {
- const size_t current_offset = offset;
- uint32_t section_offset = item->offset_;
- uint32_t section_count = item->size_;
- DexFile::MapItemType type = static_cast<DexFile::MapItemType>(item->type_);
-
- // Check for padding and overlap between items.
- if (!CheckPadding(offset, section_offset, type)) {
- return false;
- } else if (UNLIKELY(offset > section_offset)) {
- ErrorStringPrintf("Section overlap or out-of-order map: %zx, %x", offset, section_offset);
- return false;
- }
-
- // Check each item based on its type.
- switch (type) {
- case DexFile::kDexTypeHeaderItem:
- if (UNLIKELY(section_count != 1)) {
- ErrorStringPrintf("Multiple header items");
- return false;
- }
- if (UNLIKELY(section_offset != 0)) {
- ErrorStringPrintf("Header at %x, not at start of file", section_offset);
- return false;
- }
- ptr_ = begin_ + header_->header_size_;
- offset = header_->header_size_;
- break;
- case DexFile::kDexTypeStringIdItem:
- case DexFile::kDexTypeTypeIdItem:
- case DexFile::kDexTypeProtoIdItem:
- case DexFile::kDexTypeFieldIdItem:
- case DexFile::kDexTypeMethodIdItem:
- case DexFile::kDexTypeClassDefItem:
- if (!CheckIntraIdSection(section_offset, section_count, type)) {
- return false;
- }
- offset = ptr_ - begin_;
- break;
- case DexFile::kDexTypeMapList:
- if (UNLIKELY(section_count != 1)) {
- ErrorStringPrintf("Multiple map list items");
- return false;
- }
- if (UNLIKELY(section_offset != header_->map_off_)) {
- ErrorStringPrintf("Map not at header-defined offset: %x, expected %x",
- section_offset, header_->map_off_);
- return false;
- }
- ptr_ += sizeof(uint32_t) + (map->size_ * sizeof(DexFile::MapItem));
- offset = section_offset + sizeof(uint32_t) + (map->size_ * sizeof(DexFile::MapItem));
- break;
- case DexFile::kDexTypeMethodHandleItem:
- case DexFile::kDexTypeCallSiteIdItem:
- CheckIntraSectionIterate(section_offset, section_count, type);
- offset = ptr_ - begin_;
- break;
- case DexFile::kDexTypeTypeList:
- case DexFile::kDexTypeAnnotationSetRefList:
- case DexFile::kDexTypeAnnotationSetItem:
- case DexFile::kDexTypeClassDataItem:
- case DexFile::kDexTypeCodeItem:
- case DexFile::kDexTypeStringDataItem:
- case DexFile::kDexTypeDebugInfoItem:
- case DexFile::kDexTypeAnnotationItem:
- case DexFile::kDexTypeEncodedArrayItem:
- case DexFile::kDexTypeAnnotationsDirectoryItem:
- if (!CheckIntraDataSection(section_offset, section_count, type)) {
- return false;
- }
- offset = ptr_ - begin_;
- break;
- }
-
- if (offset == current_offset) {
- ErrorStringPrintf("Unknown map item type %x", type);
- return false;
- }
-
- item++;
- }
-
- return true;
-}
-
-bool DexFileVerifier::CheckOffsetToTypeMap(size_t offset, uint16_t type) {
- DCHECK_NE(offset, 0u);
- auto it = offset_to_type_map_.Find(offset);
- if (UNLIKELY(it == offset_to_type_map_.end())) {
- ErrorStringPrintf("No data map entry found @ %zx; expected %x", offset, type);
- return false;
- }
- if (UNLIKELY(it->second != type)) {
- ErrorStringPrintf("Unexpected data map entry @ %zx; expected %x, found %x",
- offset, type, it->second);
- return false;
- }
- return true;
-}
-
-dex::TypeIndex DexFileVerifier::FindFirstClassDataDefiner(const uint8_t* ptr, bool* success) {
- ClassDataItemIterator it(*dex_file_, ptr);
- *success = true;
-
- if (it.HasNextStaticField() || it.HasNextInstanceField()) {
- LOAD_FIELD(field, it.GetMemberIndex(), "first_class_data_definer field_id",
- *success = false; return dex::TypeIndex(DexFile::kDexNoIndex16))
- return field->class_idx_;
- }
-
- if (it.HasNextMethod()) {
- LOAD_METHOD(method, it.GetMemberIndex(), "first_class_data_definer method_id",
- *success = false; return dex::TypeIndex(DexFile::kDexNoIndex16))
- return method->class_idx_;
- }
-
- return dex::TypeIndex(DexFile::kDexNoIndex16);
-}
-
-dex::TypeIndex DexFileVerifier::FindFirstAnnotationsDirectoryDefiner(const uint8_t* ptr,
- bool* success) {
- const DexFile::AnnotationsDirectoryItem* item =
- reinterpret_cast<const DexFile::AnnotationsDirectoryItem*>(ptr);
- *success = true;
-
- if (item->fields_size_ != 0) {
- DexFile::FieldAnnotationsItem* field_items = (DexFile::FieldAnnotationsItem*) (item + 1);
- LOAD_FIELD(field, field_items[0].field_idx_, "first_annotations_dir_definer field_id",
- *success = false; return dex::TypeIndex(DexFile::kDexNoIndex16))
- return field->class_idx_;
- }
-
- if (item->methods_size_ != 0) {
- DexFile::MethodAnnotationsItem* method_items = (DexFile::MethodAnnotationsItem*) (item + 1);
- LOAD_METHOD(method, method_items[0].method_idx_, "first_annotations_dir_definer method id",
- *success = false; return dex::TypeIndex(DexFile::kDexNoIndex16))
- return method->class_idx_;
- }
-
- if (item->parameters_size_ != 0) {
- DexFile::ParameterAnnotationsItem* parameter_items = (DexFile::ParameterAnnotationsItem*) (item + 1);
- LOAD_METHOD(method, parameter_items[0].method_idx_, "first_annotations_dir_definer method id",
- *success = false; return dex::TypeIndex(DexFile::kDexNoIndex16))
- return method->class_idx_;
- }
-
- return dex::TypeIndex(DexFile::kDexNoIndex16);
-}
-
-bool DexFileVerifier::CheckInterStringIdItem() {
- const DexFile::StringId* item = reinterpret_cast<const DexFile::StringId*>(ptr_);
-
- // Check the map to make sure it has the right offset->type.
- if (!CheckOffsetToTypeMap(item->string_data_off_, DexFile::kDexTypeStringDataItem)) {
- return false;
- }
-
- // Check ordering between items.
- if (previous_item_ != nullptr) {
- const DexFile::StringId* prev_item = reinterpret_cast<const DexFile::StringId*>(previous_item_);
- const char* prev_str = dex_file_->GetStringData(*prev_item);
- const char* str = dex_file_->GetStringData(*item);
- if (UNLIKELY(CompareModifiedUtf8ToModifiedUtf8AsUtf16CodePointValues(prev_str, str) >= 0)) {
- ErrorStringPrintf("Out-of-order string_ids: '%s' then '%s'", prev_str, str);
- return false;
- }
- }
-
- ptr_ += sizeof(DexFile::StringId);
- return true;
-}
-
-bool DexFileVerifier::CheckInterTypeIdItem() {
- const DexFile::TypeId* item = reinterpret_cast<const DexFile::TypeId*>(ptr_);
-
- LOAD_STRING(descriptor, item->descriptor_idx_, "inter_type_id_item descriptor_idx")
-
- // Check that the descriptor is a valid type.
- if (UNLIKELY(!IsValidDescriptor(descriptor))) {
- ErrorStringPrintf("Invalid type descriptor: '%s'", descriptor);
- return false;
- }
-
- // Check ordering between items.
- if (previous_item_ != nullptr) {
- const DexFile::TypeId* prev_item = reinterpret_cast<const DexFile::TypeId*>(previous_item_);
- if (UNLIKELY(prev_item->descriptor_idx_ >= item->descriptor_idx_)) {
- ErrorStringPrintf("Out-of-order type_ids: %x then %x",
- prev_item->descriptor_idx_.index_,
- item->descriptor_idx_.index_);
- return false;
- }
- }
-
- ptr_ += sizeof(DexFile::TypeId);
- return true;
-}
-
-bool DexFileVerifier::CheckInterProtoIdItem() {
- const DexFile::ProtoId* item = reinterpret_cast<const DexFile::ProtoId*>(ptr_);
-
- LOAD_STRING(shorty, item->shorty_idx_, "inter_proto_id_item shorty_idx")
-
- if (item->parameters_off_ != 0 &&
- !CheckOffsetToTypeMap(item->parameters_off_, DexFile::kDexTypeTypeList)) {
- return false;
- }
-
- // Check that return type is representable as a uint16_t;
- if (UNLIKELY(!IsValidOrNoTypeId(item->return_type_idx_.index_, item->pad_))) {
- ErrorStringPrintf("proto with return type idx outside uint16_t range '%x:%x'",
- item->pad_, item->return_type_idx_.index_);
- return false;
- }
- // Check the return type and advance the shorty.
- LOAD_STRING_BY_TYPE(return_type, item->return_type_idx_, "inter_proto_id_item return_type_idx")
- if (!CheckShortyDescriptorMatch(*shorty, return_type, true)) {
- return false;
- }
- shorty++;
-
- DexFileParameterIterator it(*dex_file_, *item);
- while (it.HasNext() && *shorty != '\0') {
- if (!CheckIndex(it.GetTypeIdx().index_,
- dex_file_->NumTypeIds(),
- "inter_proto_id_item shorty type_idx")) {
- return false;
- }
- const char* descriptor = it.GetDescriptor();
- if (!CheckShortyDescriptorMatch(*shorty, descriptor, false)) {
- return false;
- }
- it.Next();
- shorty++;
- }
- if (UNLIKELY(it.HasNext() || *shorty != '\0')) {
- ErrorStringPrintf("Mismatched length for parameters and shorty");
- return false;
- }
-
- // Check ordering between items. This relies on type_ids being in order.
- if (previous_item_ != nullptr) {
- const DexFile::ProtoId* prev = reinterpret_cast<const DexFile::ProtoId*>(previous_item_);
- if (UNLIKELY(prev->return_type_idx_ > item->return_type_idx_)) {
- ErrorStringPrintf("Out-of-order proto_id return types");
- return false;
- } else if (prev->return_type_idx_ == item->return_type_idx_) {
- DexFileParameterIterator curr_it(*dex_file_, *item);
- DexFileParameterIterator prev_it(*dex_file_, *prev);
-
- while (curr_it.HasNext() && prev_it.HasNext()) {
- dex::TypeIndex prev_idx = prev_it.GetTypeIdx();
- dex::TypeIndex curr_idx = curr_it.GetTypeIdx();
- DCHECK_NE(prev_idx, dex::TypeIndex(DexFile::kDexNoIndex16));
- DCHECK_NE(curr_idx, dex::TypeIndex(DexFile::kDexNoIndex16));
-
- if (prev_idx < curr_idx) {
- break;
- } else if (UNLIKELY(prev_idx > curr_idx)) {
- ErrorStringPrintf("Out-of-order proto_id arguments");
- return false;
- }
-
- prev_it.Next();
- curr_it.Next();
- }
- if (!curr_it.HasNext()) {
- // Either a duplicate ProtoId or a ProtoId with a shorter argument list follows
- // a ProtoId with a longer one. Both cases are forbidden by the specification.
- ErrorStringPrintf("Out-of-order proto_id arguments");
- return false;
- }
- }
- }
-
- ptr_ += sizeof(DexFile::ProtoId);
- return true;
-}
-
-bool DexFileVerifier::CheckInterFieldIdItem() {
- const DexFile::FieldId* item = reinterpret_cast<const DexFile::FieldId*>(ptr_);
-
- // Check that the class descriptor is valid.
- LOAD_STRING_BY_TYPE(class_descriptor, item->class_idx_, "inter_field_id_item class_idx")
- if (UNLIKELY(!IsValidDescriptor(class_descriptor) || class_descriptor[0] != 'L')) {
- ErrorStringPrintf("Invalid descriptor for class_idx: '%s'", class_descriptor);
- return false;
- }
-
- // Check that the type descriptor is a valid field name.
- LOAD_STRING_BY_TYPE(type_descriptor, item->type_idx_, "inter_field_id_item type_idx")
- if (UNLIKELY(!IsValidDescriptor(type_descriptor) || type_descriptor[0] == 'V')) {
- ErrorStringPrintf("Invalid descriptor for type_idx: '%s'", type_descriptor);
- return false;
- }
-
- // Check that the name is valid.
- LOAD_STRING(descriptor, item->name_idx_, "inter_field_id_item name_idx")
- if (UNLIKELY(!IsValidMemberName(descriptor))) {
- ErrorStringPrintf("Invalid field name: '%s'", descriptor);
- return false;
- }
-
- // Check ordering between items. This relies on the other sections being in order.
- if (previous_item_ != nullptr) {
- const DexFile::FieldId* prev_item = reinterpret_cast<const DexFile::FieldId*>(previous_item_);
- if (UNLIKELY(prev_item->class_idx_ > item->class_idx_)) {
- ErrorStringPrintf("Out-of-order field_ids");
- return false;
- } else if (prev_item->class_idx_ == item->class_idx_) {
- if (UNLIKELY(prev_item->name_idx_ > item->name_idx_)) {
- ErrorStringPrintf("Out-of-order field_ids");
- return false;
- } else if (prev_item->name_idx_ == item->name_idx_) {
- if (UNLIKELY(prev_item->type_idx_ >= item->type_idx_)) {
- ErrorStringPrintf("Out-of-order field_ids");
- return false;
- }
- }
- }
- }
-
- ptr_ += sizeof(DexFile::FieldId);
- return true;
-}
-
-bool DexFileVerifier::CheckInterMethodIdItem() {
- const DexFile::MethodId* item = reinterpret_cast<const DexFile::MethodId*>(ptr_);
-
- // Check that the class descriptor is a valid reference name.
- LOAD_STRING_BY_TYPE(class_descriptor, item->class_idx_, "inter_method_id_item class_idx")
- if (UNLIKELY(!IsValidDescriptor(class_descriptor) || (class_descriptor[0] != 'L' &&
- class_descriptor[0] != '['))) {
- ErrorStringPrintf("Invalid descriptor for class_idx: '%s'", class_descriptor);
- return false;
- }
-
- // Check that the name is valid.
- LOAD_STRING(descriptor, item->name_idx_, "inter_method_id_item name_idx")
- if (UNLIKELY(!IsValidMemberName(descriptor))) {
- ErrorStringPrintf("Invalid method name: '%s'", descriptor);
- return false;
- }
-
- // Check that the proto id is valid.
- if (UNLIKELY(!CheckIndex(item->proto_idx_, dex_file_->NumProtoIds(),
- "inter_method_id_item proto_idx"))) {
- return false;
- }
-
- // Check ordering between items. This relies on the other sections being in order.
- if (previous_item_ != nullptr) {
- const DexFile::MethodId* prev_item = reinterpret_cast<const DexFile::MethodId*>(previous_item_);
- if (UNLIKELY(prev_item->class_idx_ > item->class_idx_)) {
- ErrorStringPrintf("Out-of-order method_ids");
- return false;
- } else if (prev_item->class_idx_ == item->class_idx_) {
- if (UNLIKELY(prev_item->name_idx_ > item->name_idx_)) {
- ErrorStringPrintf("Out-of-order method_ids");
- return false;
- } else if (prev_item->name_idx_ == item->name_idx_) {
- if (UNLIKELY(prev_item->proto_idx_ >= item->proto_idx_)) {
- ErrorStringPrintf("Out-of-order method_ids");
- return false;
- }
- }
- }
- }
-
- ptr_ += sizeof(DexFile::MethodId);
- return true;
-}
-
-bool DexFileVerifier::CheckInterClassDefItem() {
- const DexFile::ClassDef* item = reinterpret_cast<const DexFile::ClassDef*>(ptr_);
-
- // Check that class_idx_ is representable as a uint16_t;
- if (UNLIKELY(!IsValidTypeId(item->class_idx_.index_, item->pad1_))) {
- ErrorStringPrintf("class with type idx outside uint16_t range '%x:%x'", item->pad1_,
- item->class_idx_.index_);
- return false;
- }
- // Check that superclass_idx_ is representable as a uint16_t;
- if (UNLIKELY(!IsValidOrNoTypeId(item->superclass_idx_.index_, item->pad2_))) {
- ErrorStringPrintf("class with superclass type idx outside uint16_t range '%x:%x'", item->pad2_,
- item->superclass_idx_.index_);
- return false;
- }
- // Check for duplicate class def.
- if (defined_classes_.find(item->class_idx_) != defined_classes_.end()) {
- ErrorStringPrintf("Redefinition of class with type idx: '%d'", item->class_idx_.index_);
- return false;
- }
- defined_classes_.insert(item->class_idx_);
-
- LOAD_STRING_BY_TYPE(class_descriptor, item->class_idx_, "inter_class_def_item class_idx")
- if (UNLIKELY(!IsValidDescriptor(class_descriptor) || class_descriptor[0] != 'L')) {
- ErrorStringPrintf("Invalid class descriptor: '%s'", class_descriptor);
- return false;
- }
-
- // Only allow non-runtime modifiers.
- if ((item->access_flags_ & ~kAccJavaFlagsMask) != 0) {
- ErrorStringPrintf("Invalid class flags: '%d'", item->access_flags_);
- return false;
- }
-
- if (item->interfaces_off_ != 0 &&
- !CheckOffsetToTypeMap(item->interfaces_off_, DexFile::kDexTypeTypeList)) {
- return false;
- }
- if (item->annotations_off_ != 0 &&
- !CheckOffsetToTypeMap(item->annotations_off_, DexFile::kDexTypeAnnotationsDirectoryItem)) {
- return false;
- }
- if (item->class_data_off_ != 0 &&
- !CheckOffsetToTypeMap(item->class_data_off_, DexFile::kDexTypeClassDataItem)) {
- return false;
- }
- if (item->static_values_off_ != 0 &&
- !CheckOffsetToTypeMap(item->static_values_off_, DexFile::kDexTypeEncodedArrayItem)) {
- return false;
- }
-
- if (item->superclass_idx_.IsValid()) {
- if (header_->GetVersion() >= DexFile::kClassDefinitionOrderEnforcedVersion) {
- // Check that a class does not inherit from itself directly (by having
- // the same type idx as its super class).
- if (UNLIKELY(item->superclass_idx_ == item->class_idx_)) {
- ErrorStringPrintf("Class with same type idx as its superclass: '%d'",
- item->class_idx_.index_);
- return false;
- }
-
- // Check that a class is defined after its super class (if the
- // latter is defined in the same Dex file).
- const DexFile::ClassDef* superclass_def = dex_file_->FindClassDef(item->superclass_idx_);
- if (superclass_def != nullptr) {
- // The superclass is defined in this Dex file.
- if (superclass_def > item) {
- // ClassDef item for super class appearing after the class' ClassDef item.
- ErrorStringPrintf("Invalid class definition ordering:"
- " class with type idx: '%d' defined before"
- " superclass with type idx: '%d'",
- item->class_idx_.index_,
- item->superclass_idx_.index_);
- return false;
- }
- }
- }
-
- LOAD_STRING_BY_TYPE(superclass_descriptor, item->superclass_idx_,
- "inter_class_def_item superclass_idx")
- if (UNLIKELY(!IsValidDescriptor(superclass_descriptor) || superclass_descriptor[0] != 'L')) {
- ErrorStringPrintf("Invalid superclass: '%s'", superclass_descriptor);
- return false;
- }
- }
-
- // Check interfaces.
- const DexFile::TypeList* interfaces = dex_file_->GetInterfacesList(*item);
- if (interfaces != nullptr) {
- uint32_t size = interfaces->Size();
- for (uint32_t i = 0; i < size; i++) {
- if (header_->GetVersion() >= DexFile::kClassDefinitionOrderEnforcedVersion) {
- // Check that a class does not implement itself directly (by having the
- // same type idx as one of its immediate implemented interfaces).
- if (UNLIKELY(interfaces->GetTypeItem(i).type_idx_ == item->class_idx_)) {
- ErrorStringPrintf("Class with same type idx as implemented interface: '%d'",
- item->class_idx_.index_);
- return false;
- }
-
- // Check that a class is defined after the interfaces it implements
- // (if they are defined in the same Dex file).
- const DexFile::ClassDef* interface_def =
- dex_file_->FindClassDef(interfaces->GetTypeItem(i).type_idx_);
- if (interface_def != nullptr) {
- // The interface is defined in this Dex file.
- if (interface_def > item) {
- // ClassDef item for interface appearing after the class' ClassDef item.
- ErrorStringPrintf("Invalid class definition ordering:"
- " class with type idx: '%d' defined before"
- " implemented interface with type idx: '%d'",
- item->class_idx_.index_,
- interfaces->GetTypeItem(i).type_idx_.index_);
- return false;
- }
- }
- }
-
- // Ensure that the interface refers to a class (not an array nor a primitive type).
- LOAD_STRING_BY_TYPE(inf_descriptor, interfaces->GetTypeItem(i).type_idx_,
- "inter_class_def_item interface type_idx")
- if (UNLIKELY(!IsValidDescriptor(inf_descriptor) || inf_descriptor[0] != 'L')) {
- ErrorStringPrintf("Invalid interface: '%s'", inf_descriptor);
- return false;
- }
- }
-
- /*
- * Ensure that there are no duplicates. This is an O(N^2) test, but in
- * practice the number of interfaces implemented by any given class is low.
- */
- for (uint32_t i = 1; i < size; i++) {
- dex::TypeIndex idx1 = interfaces->GetTypeItem(i).type_idx_;
- for (uint32_t j =0; j < i; j++) {
- dex::TypeIndex idx2 = interfaces->GetTypeItem(j).type_idx_;
- if (UNLIKELY(idx1 == idx2)) {
- ErrorStringPrintf("Duplicate interface: '%s'", dex_file_->StringByTypeIdx(idx1));
- return false;
- }
- }
- }
- }
-
- // Check that references in class_data_item are to the right class.
- if (item->class_data_off_ != 0) {
- const uint8_t* data = begin_ + item->class_data_off_;
- bool success;
- dex::TypeIndex data_definer = FindFirstClassDataDefiner(data, &success);
- if (!success) {
- return false;
- }
- if (UNLIKELY((data_definer != item->class_idx_) &&
- (data_definer != dex::TypeIndex(DexFile::kDexNoIndex16)))) {
- ErrorStringPrintf("Invalid class_data_item");
- return false;
- }
- }
-
- // Check that references in annotations_directory_item are to right class.
- if (item->annotations_off_ != 0) {
- // annotations_off_ is supposed to be aligned by 4.
- if (!IsAlignedParam(item->annotations_off_, 4)) {
- ErrorStringPrintf("Invalid annotations_off_, not aligned by 4");
- return false;
- }
- const uint8_t* data = begin_ + item->annotations_off_;
- bool success;
- dex::TypeIndex annotations_definer = FindFirstAnnotationsDirectoryDefiner(data, &success);
- if (!success) {
- return false;
- }
- if (UNLIKELY((annotations_definer != item->class_idx_) &&
- (annotations_definer != dex::TypeIndex(DexFile::kDexNoIndex16)))) {
- ErrorStringPrintf("Invalid annotations_directory_item");
- return false;
- }
- }
-
- ptr_ += sizeof(DexFile::ClassDef);
- return true;
-}
-
-bool DexFileVerifier::CheckInterCallSiteIdItem() {
- const DexFile::CallSiteIdItem* item = reinterpret_cast<const DexFile::CallSiteIdItem*>(ptr_);
-
- // Check call site referenced by item is in encoded array section.
- if (!CheckOffsetToTypeMap(item->data_off_, DexFile::kDexTypeEncodedArrayItem)) {
- ErrorStringPrintf("Invalid offset in CallSideIdItem");
- return false;
- }
-
- CallSiteArrayValueIterator it(*dex_file_, *item);
-
- // Check Method Handle
- if (!it.HasNext() || it.GetValueType() != EncodedArrayValueIterator::ValueType::kMethodHandle) {
- ErrorStringPrintf("CallSiteArray missing method handle");
- return false;
- }
-
- uint32_t handle_index = static_cast<uint32_t>(it.GetJavaValue().i);
- if (handle_index >= dex_file_->NumMethodHandles()) {
- ErrorStringPrintf("CallSite has bad method handle id: %x", handle_index);
- return false;
- }
-
- // Check target method name.
- it.Next();
- if (!it.HasNext() ||
- it.GetValueType() != EncodedArrayValueIterator::ValueType::kString) {
- ErrorStringPrintf("CallSiteArray missing target method name");
- return false;
- }
-
- uint32_t name_index = static_cast<uint32_t>(it.GetJavaValue().i);
- if (name_index >= dex_file_->NumStringIds()) {
- ErrorStringPrintf("CallSite has bad method name id: %x", name_index);
- return false;
- }
-
- // Check method type.
- it.Next();
- if (!it.HasNext() ||
- it.GetValueType() != EncodedArrayValueIterator::ValueType::kMethodType) {
- ErrorStringPrintf("CallSiteArray missing method type");
- return false;
- }
-
- uint32_t proto_index = static_cast<uint32_t>(it.GetJavaValue().i);
- if (proto_index >= dex_file_->NumProtoIds()) {
- ErrorStringPrintf("CallSite has bad method type: %x", proto_index);
- return false;
- }
-
- ptr_ += sizeof(DexFile::CallSiteIdItem);
- return true;
-}
-
-bool DexFileVerifier::CheckInterMethodHandleItem() {
- const DexFile::MethodHandleItem* item = reinterpret_cast<const DexFile::MethodHandleItem*>(ptr_);
-
- DexFile::MethodHandleType method_handle_type =
- static_cast<DexFile::MethodHandleType>(item->method_handle_type_);
- if (method_handle_type > DexFile::MethodHandleType::kLast) {
- ErrorStringPrintf("Bad method handle type %x", item->method_handle_type_);
- return false;
- }
-
- uint32_t index = item->field_or_method_idx_;
- switch (method_handle_type) {
- case DexFile::MethodHandleType::kStaticPut:
- case DexFile::MethodHandleType::kStaticGet:
- case DexFile::MethodHandleType::kInstancePut:
- case DexFile::MethodHandleType::kInstanceGet: {
- LOAD_FIELD(field, index, "method_handle_item field_idx", return false);
- break;
- }
- case DexFile::MethodHandleType::kInvokeStatic:
- case DexFile::MethodHandleType::kInvokeInstance:
- case DexFile::MethodHandleType::kInvokeConstructor:
- case DexFile::MethodHandleType::kInvokeDirect:
- case DexFile::MethodHandleType::kInvokeInterface: {
- LOAD_METHOD(method, index, "method_handle_item method_idx", return false);
- break;
- }
- }
-
- ptr_ += sizeof(DexFile::MethodHandleItem);
- return true;
-}
-
-bool DexFileVerifier::CheckInterAnnotationSetRefList() {
- const DexFile::AnnotationSetRefList* list =
- reinterpret_cast<const DexFile::AnnotationSetRefList*>(ptr_);
- const DexFile::AnnotationSetRefItem* item = list->list_;
- uint32_t count = list->size_;
-
- while (count--) {
- if (item->annotations_off_ != 0 &&
- !CheckOffsetToTypeMap(item->annotations_off_, DexFile::kDexTypeAnnotationSetItem)) {
- return false;
- }
- item++;
- }
-
- ptr_ = reinterpret_cast<const uint8_t*>(item);
- return true;
-}
-
-bool DexFileVerifier::CheckInterAnnotationSetItem() {
- const DexFile::AnnotationSetItem* set = reinterpret_cast<const DexFile::AnnotationSetItem*>(ptr_);
- const uint32_t* offsets = set->entries_;
- uint32_t count = set->size_;
- uint32_t last_idx = 0;
-
- for (uint32_t i = 0; i < count; i++) {
- if (*offsets != 0 && !CheckOffsetToTypeMap(*offsets, DexFile::kDexTypeAnnotationItem)) {
- return false;
- }
-
- // Get the annotation from the offset and the type index for the annotation.
- const DexFile::AnnotationItem* annotation =
- reinterpret_cast<const DexFile::AnnotationItem*>(begin_ + *offsets);
- const uint8_t* data = annotation->annotation_;
- DECODE_UNSIGNED_CHECKED_FROM(data, idx);
-
- if (UNLIKELY(last_idx >= idx && i != 0)) {
- ErrorStringPrintf("Out-of-order entry types: %x then %x", last_idx, idx);
- return false;
- }
-
- last_idx = idx;
- offsets++;
- }
-
- ptr_ = reinterpret_cast<const uint8_t*>(offsets);
- return true;
-}
-
-bool DexFileVerifier::CheckInterClassDataItem() {
- ClassDataItemIterator it(*dex_file_, ptr_);
- bool success;
- dex::TypeIndex defining_class = FindFirstClassDataDefiner(ptr_, &success);
- if (!success) {
- return false;
- }
-
- for (; it.HasNextStaticField() || it.HasNextInstanceField(); it.Next()) {
- LOAD_FIELD(field, it.GetMemberIndex(), "inter_class_data_item field_id", return false)
- if (UNLIKELY(field->class_idx_ != defining_class)) {
- ErrorStringPrintf("Mismatched defining class for class_data_item field");
- return false;
- }
- }
- for (; it.HasNextMethod(); it.Next()) {
- uint32_t code_off = it.GetMethodCodeItemOffset();
- if (code_off != 0 && !CheckOffsetToTypeMap(code_off, DexFile::kDexTypeCodeItem)) {
- return false;
- }
- LOAD_METHOD(method, it.GetMemberIndex(), "inter_class_data_item method_id", return false)
- if (UNLIKELY(method->class_idx_ != defining_class)) {
- ErrorStringPrintf("Mismatched defining class for class_data_item method");
- return false;
- }
- }
-
- ptr_ = it.EndDataPointer();
- return true;
-}
-
-bool DexFileVerifier::CheckInterAnnotationsDirectoryItem() {
- const DexFile::AnnotationsDirectoryItem* item =
- reinterpret_cast<const DexFile::AnnotationsDirectoryItem*>(ptr_);
- bool success;
- dex::TypeIndex defining_class = FindFirstAnnotationsDirectoryDefiner(ptr_, &success);
- if (!success) {
- return false;
- }
-
- if (item->class_annotations_off_ != 0 &&
- !CheckOffsetToTypeMap(item->class_annotations_off_, DexFile::kDexTypeAnnotationSetItem)) {
- return false;
- }
-
- // Field annotations follow immediately after the annotations directory.
- const DexFile::FieldAnnotationsItem* field_item =
- reinterpret_cast<const DexFile::FieldAnnotationsItem*>(item + 1);
- uint32_t field_count = item->fields_size_;
- for (uint32_t i = 0; i < field_count; i++) {
- LOAD_FIELD(field, field_item->field_idx_, "inter_annotations_directory_item field_id",
- return false)
- if (UNLIKELY(field->class_idx_ != defining_class)) {
- ErrorStringPrintf("Mismatched defining class for field_annotation");
- return false;
- }
- if (!CheckOffsetToTypeMap(field_item->annotations_off_, DexFile::kDexTypeAnnotationSetItem)) {
- return false;
- }
- field_item++;
- }
-
- // Method annotations follow immediately after field annotations.
- const DexFile::MethodAnnotationsItem* method_item =
- reinterpret_cast<const DexFile::MethodAnnotationsItem*>(field_item);
- uint32_t method_count = item->methods_size_;
- for (uint32_t i = 0; i < method_count; i++) {
- LOAD_METHOD(method, method_item->method_idx_, "inter_annotations_directory_item method_id",
- return false)
- if (UNLIKELY(method->class_idx_ != defining_class)) {
- ErrorStringPrintf("Mismatched defining class for method_annotation");
- return false;
- }
- if (!CheckOffsetToTypeMap(method_item->annotations_off_, DexFile::kDexTypeAnnotationSetItem)) {
- return false;
- }
- method_item++;
- }
-
- // Parameter annotations follow immediately after method annotations.
- const DexFile::ParameterAnnotationsItem* parameter_item =
- reinterpret_cast<const DexFile::ParameterAnnotationsItem*>(method_item);
- uint32_t parameter_count = item->parameters_size_;
- for (uint32_t i = 0; i < parameter_count; i++) {
- LOAD_METHOD(parameter_method, parameter_item->method_idx_,
- "inter_annotations_directory_item parameter method_id", return false)
- if (UNLIKELY(parameter_method->class_idx_ != defining_class)) {
- ErrorStringPrintf("Mismatched defining class for parameter_annotation");
- return false;
- }
- if (!CheckOffsetToTypeMap(parameter_item->annotations_off_,
- DexFile::kDexTypeAnnotationSetRefList)) {
- return false;
- }
- parameter_item++;
- }
-
- ptr_ = reinterpret_cast<const uint8_t*>(parameter_item);
- return true;
-}
-
-bool DexFileVerifier::CheckInterSectionIterate(size_t offset,
- uint32_t count,
- DexFile::MapItemType type) {
- // Get the right alignment mask for the type of section.
- size_t alignment_mask;
- switch (type) {
- case DexFile::kDexTypeClassDataItem:
- alignment_mask = sizeof(uint8_t) - 1;
- break;
- default:
- alignment_mask = sizeof(uint32_t) - 1;
- break;
- }
-
- // Iterate through the items in the section.
- previous_item_ = nullptr;
- for (uint32_t i = 0; i < count; i++) {
- uint32_t new_offset = (offset + alignment_mask) & ~alignment_mask;
- ptr_ = begin_ + new_offset;
- const uint8_t* prev_ptr = ptr_;
-
- if (MapTypeToBitMask(type) == 0) {
- ErrorStringPrintf("Unknown map item type %x", type);
- return false;
- }
-
- // Check depending on the section type.
- switch (type) {
- case DexFile::kDexTypeHeaderItem:
- case DexFile::kDexTypeMapList:
- case DexFile::kDexTypeTypeList:
- case DexFile::kDexTypeCodeItem:
- case DexFile::kDexTypeStringDataItem:
- case DexFile::kDexTypeDebugInfoItem:
- case DexFile::kDexTypeAnnotationItem:
- case DexFile::kDexTypeEncodedArrayItem:
- break;
- case DexFile::kDexTypeStringIdItem: {
- if (!CheckInterStringIdItem()) {
- return false;
- }
- break;
- }
- case DexFile::kDexTypeTypeIdItem: {
- if (!CheckInterTypeIdItem()) {
- return false;
- }
- break;
- }
- case DexFile::kDexTypeProtoIdItem: {
- if (!CheckInterProtoIdItem()) {
- return false;
- }
- break;
- }
- case DexFile::kDexTypeFieldIdItem: {
- if (!CheckInterFieldIdItem()) {
- return false;
- }
- break;
- }
- case DexFile::kDexTypeMethodIdItem: {
- if (!CheckInterMethodIdItem()) {
- return false;
- }
- break;
- }
- case DexFile::kDexTypeClassDefItem: {
- // There shouldn't be more class definitions than type ids allow.
- // This check should be redundant, since there are checks that the
- // class_idx_ is within range and that there is only one definition
- // for a given type id.
- if (i > kTypeIdLimit) {
- ErrorStringPrintf("Too many class definition items");
- return false;
- }
- if (!CheckInterClassDefItem()) {
- return false;
- }
- break;
- }
- case DexFile::kDexTypeCallSiteIdItem: {
- if (!CheckInterCallSiteIdItem()) {
- return false;
- }
- break;
- }
- case DexFile::kDexTypeMethodHandleItem: {
- if (!CheckInterMethodHandleItem()) {
- return false;
- }
- break;
- }
- case DexFile::kDexTypeAnnotationSetRefList: {
- if (!CheckInterAnnotationSetRefList()) {
- return false;
- }
- break;
- }
- case DexFile::kDexTypeAnnotationSetItem: {
- if (!CheckInterAnnotationSetItem()) {
- return false;
- }
- break;
- }
- case DexFile::kDexTypeClassDataItem: {
- // There shouldn't be more class data than type ids allow.
- // This check should be redundant, since there are checks that the
- // class_idx_ is within range and that there is only one definition
- // for a given type id.
- if (i > kTypeIdLimit) {
- ErrorStringPrintf("Too many class data items");
- return false;
- }
- if (!CheckInterClassDataItem()) {
- return false;
- }
- break;
- }
- case DexFile::kDexTypeAnnotationsDirectoryItem: {
- if (!CheckInterAnnotationsDirectoryItem()) {
- return false;
- }
- break;
- }
- }
-
- previous_item_ = prev_ptr;
- offset = ptr_ - begin_;
- }
-
- return true;
-}
-
-bool DexFileVerifier::CheckInterSection() {
- const DexFile::MapList* map = reinterpret_cast<const DexFile::MapList*>(begin_ + header_->map_off_);
- const DexFile::MapItem* item = map->list_;
- uint32_t count = map->size_;
-
- // Cross check the items listed in the map.
- while (count--) {
- uint32_t section_offset = item->offset_;
- uint32_t section_count = item->size_;
- DexFile::MapItemType type = static_cast<DexFile::MapItemType>(item->type_);
- bool found = false;
-
- switch (type) {
- case DexFile::kDexTypeHeaderItem:
- case DexFile::kDexTypeMapList:
- case DexFile::kDexTypeTypeList:
- case DexFile::kDexTypeCodeItem:
- case DexFile::kDexTypeStringDataItem:
- case DexFile::kDexTypeDebugInfoItem:
- case DexFile::kDexTypeAnnotationItem:
- case DexFile::kDexTypeEncodedArrayItem:
- found = true;
- break;
- case DexFile::kDexTypeStringIdItem:
- case DexFile::kDexTypeTypeIdItem:
- case DexFile::kDexTypeProtoIdItem:
- case DexFile::kDexTypeFieldIdItem:
- case DexFile::kDexTypeMethodIdItem:
- case DexFile::kDexTypeClassDefItem:
- case DexFile::kDexTypeCallSiteIdItem:
- case DexFile::kDexTypeMethodHandleItem:
- case DexFile::kDexTypeAnnotationSetRefList:
- case DexFile::kDexTypeAnnotationSetItem:
- case DexFile::kDexTypeClassDataItem:
- case DexFile::kDexTypeAnnotationsDirectoryItem: {
- if (!CheckInterSectionIterate(section_offset, section_count, type)) {
- return false;
- }
- found = true;
- break;
- }
- }
-
- if (!found) {
- ErrorStringPrintf("Unknown map item type %x", item->type_);
- return false;
- }
-
- item++;
- }
-
- return true;
-}
-
-bool DexFileVerifier::Verify() {
- // Check the header.
- if (!CheckHeader()) {
- return false;
- }
-
- // Check the map section.
- if (!CheckMap()) {
- return false;
- }
-
- // Check structure within remaining sections.
- if (!CheckIntraSection()) {
- return false;
- }
-
- // Check references from one section to another.
- if (!CheckInterSection()) {
- return false;
- }
-
- return true;
-}
-
-void DexFileVerifier::ErrorStringPrintf(const char* fmt, ...) {
- va_list ap;
- va_start(ap, fmt);
- DCHECK(failure_reason_.empty()) << failure_reason_;
- failure_reason_ = StringPrintf("Failure to verify dex file '%s': ", location_);
- StringAppendV(&failure_reason_, fmt, ap);
- va_end(ap);
-}
-
-// Fields and methods may have only one of public/protected/private.
-static bool CheckAtMostOneOfPublicProtectedPrivate(uint32_t flags) {
- size_t count = (((flags & kAccPublic) == 0) ? 0 : 1) +
- (((flags & kAccProtected) == 0) ? 0 : 1) +
- (((flags & kAccPrivate) == 0) ? 0 : 1);
- return count <= 1;
-}
-
-// Helper functions to retrieve names from the dex file. We do not want to rely on DexFile
-// functionality, as we're still verifying the dex file. begin and header correspond to the
-// underscored variants in the DexFileVerifier.
-
-static std::string GetStringOrError(const uint8_t* const begin,
- const DexFile::Header* const header,
- dex::StringIndex string_idx) {
- // The `string_idx` is not guaranteed to be valid yet.
- if (header->string_ids_size_ <= string_idx.index_) {
- return "(error)";
- }
-
- const DexFile::StringId* string_id =
- reinterpret_cast<const DexFile::StringId*>(begin + header->string_ids_off_)
- + string_idx.index_;
-
- // Assume that the data is OK at this point. String data has been checked at this point.
-
- const uint8_t* ptr = begin + string_id->string_data_off_;
- uint32_t dummy;
- if (!DecodeUnsignedLeb128Checked(&ptr, begin + header->file_size_, &dummy)) {
- return "(error)";
- }
- return reinterpret_cast<const char*>(ptr);
-}
-
-static std::string GetClassOrError(const uint8_t* const begin,
- const DexFile::Header* const header,
- dex::TypeIndex class_idx) {
- // The `class_idx` is either `FieldId::class_idx_` or `MethodId::class_idx_` and
- // it has already been checked in `DexFileVerifier::CheckClassDataItemField()`
- // or `DexFileVerifier::CheckClassDataItemMethod()`, respectively, to match
- // a valid defining class.
- CHECK_LT(class_idx.index_, header->type_ids_size_);
-
- const DexFile::TypeId* type_id =
- reinterpret_cast<const DexFile::TypeId*>(begin + header->type_ids_off_) + class_idx.index_;
-
- // Assume that the data is OK at this point. Type id offsets have been checked at this point.
-
- return GetStringOrError(begin, header, type_id->descriptor_idx_);
-}
-
-static std::string GetFieldDescriptionOrError(const uint8_t* const begin,
- const DexFile::Header* const header,
- uint32_t idx) {
- // The `idx` has already been checked in `DexFileVerifier::CheckClassDataItemField()`.
- CHECK_LT(idx, header->field_ids_size_);
-
- const DexFile::FieldId* field_id =
- reinterpret_cast<const DexFile::FieldId*>(begin + header->field_ids_off_) + idx;
-
- // Assume that the data is OK at this point. Field id offsets have been checked at this point.
-
- std::string class_name = GetClassOrError(begin, header, field_id->class_idx_);
- std::string field_name = GetStringOrError(begin, header, field_id->name_idx_);
-
- return class_name + "." + field_name;
-}
-
-static std::string GetMethodDescriptionOrError(const uint8_t* const begin,
- const DexFile::Header* const header,
- uint32_t idx) {
- // The `idx` has already been checked in `DexFileVerifier::CheckClassDataItemMethod()`.
- CHECK_LT(idx, header->method_ids_size_);
-
- const DexFile::MethodId* method_id =
- reinterpret_cast<const DexFile::MethodId*>(begin + header->method_ids_off_) + idx;
-
- // Assume that the data is OK at this point. Method id offsets have been checked at this point.
-
- std::string class_name = GetClassOrError(begin, header, method_id->class_idx_);
- std::string method_name = GetStringOrError(begin, header, method_id->name_idx_);
-
- return class_name + "." + method_name;
-}
-
-bool DexFileVerifier::CheckFieldAccessFlags(uint32_t idx,
- uint32_t field_access_flags,
- uint32_t class_access_flags,
- std::string* error_msg) {
- // Generally sort out >16-bit flags.
- if ((field_access_flags & ~kAccJavaFlagsMask) != 0) {
- *error_msg = StringPrintf("Bad field access_flags for %s: %x(%s)",
- GetFieldDescriptionOrError(begin_, header_, idx).c_str(),
- field_access_flags,
- PrettyJavaAccessFlags(field_access_flags).c_str());
- return false;
- }
-
- // Flags allowed on fields, in general. Other lower-16-bit flags are to be ignored.
- constexpr uint32_t kFieldAccessFlags = kAccPublic |
- kAccPrivate |
- kAccProtected |
- kAccStatic |
- kAccFinal |
- kAccVolatile |
- kAccTransient |
- kAccSynthetic |
- kAccEnum;
-
- // Fields may have only one of public/protected/final.
- if (!CheckAtMostOneOfPublicProtectedPrivate(field_access_flags)) {
- *error_msg = StringPrintf("Field may have only one of public/protected/private, %s: %x(%s)",
- GetFieldDescriptionOrError(begin_, header_, idx).c_str(),
- field_access_flags,
- PrettyJavaAccessFlags(field_access_flags).c_str());
- return false;
- }
-
- // Interfaces have a pretty restricted list.
- if ((class_access_flags & kAccInterface) != 0) {
- // Interface fields must be public final static.
- constexpr uint32_t kPublicFinalStatic = kAccPublic | kAccFinal | kAccStatic;
- if ((field_access_flags & kPublicFinalStatic) != kPublicFinalStatic) {
- *error_msg = StringPrintf("Interface field is not public final static, %s: %x(%s)",
- GetFieldDescriptionOrError(begin_, header_, idx).c_str(),
- field_access_flags,
- PrettyJavaAccessFlags(field_access_flags).c_str());
- if (dex_file_->SupportsDefaultMethods()) {
- return false;
- } else {
- // Allow in older versions, but warn.
- LOG(WARNING) << "This dex file is invalid and will be rejected in the future. Error is: "
- << *error_msg;
- }
- }
- // Interface fields may be synthetic, but may not have other flags.
- constexpr uint32_t kDisallowed = ~(kPublicFinalStatic | kAccSynthetic);
- if ((field_access_flags & kFieldAccessFlags & kDisallowed) != 0) {
- *error_msg = StringPrintf("Interface field has disallowed flag, %s: %x(%s)",
- GetFieldDescriptionOrError(begin_, header_, idx).c_str(),
- field_access_flags,
- PrettyJavaAccessFlags(field_access_flags).c_str());
- if (dex_file_->SupportsDefaultMethods()) {
- return false;
- } else {
- // Allow in older versions, but warn.
- LOG(WARNING) << "This dex file is invalid and will be rejected in the future. Error is: "
- << *error_msg;
- }
- }
- return true;
- }
-
- // Volatile fields may not be final.
- constexpr uint32_t kVolatileFinal = kAccVolatile | kAccFinal;
- if ((field_access_flags & kVolatileFinal) == kVolatileFinal) {
- *error_msg = StringPrintf("Fields may not be volatile and final: %s",
- GetFieldDescriptionOrError(begin_, header_, idx).c_str());
- return false;
- }
-
- return true;
-}
-
-bool DexFileVerifier::CheckMethodAccessFlags(uint32_t method_index,
- uint32_t method_access_flags,
- uint32_t class_access_flags,
- uint32_t constructor_flags_by_name,
- bool has_code,
- bool expect_direct,
- std::string* error_msg) {
- // Generally sort out >16-bit flags, except dex knows Constructor and DeclaredSynchronized.
- constexpr uint32_t kAllMethodFlags =
- kAccJavaFlagsMask | kAccConstructor | kAccDeclaredSynchronized;
- if ((method_access_flags & ~kAllMethodFlags) != 0) {
- *error_msg = StringPrintf("Bad method access_flags for %s: %x",
- GetMethodDescriptionOrError(begin_, header_, method_index).c_str(),
- method_access_flags);
- return false;
- }
-
- // Flags allowed on fields, in general. Other lower-16-bit flags are to be ignored.
- constexpr uint32_t kMethodAccessFlags = kAccPublic |
- kAccPrivate |
- kAccProtected |
- kAccStatic |
- kAccFinal |
- kAccSynthetic |
- kAccSynchronized |
- kAccBridge |
- kAccVarargs |
- kAccNative |
- kAccAbstract |
- kAccStrict;
-
- // Methods may have only one of public/protected/final.
- if (!CheckAtMostOneOfPublicProtectedPrivate(method_access_flags)) {
- *error_msg = StringPrintf("Method may have only one of public/protected/private, %s: %x",
- GetMethodDescriptionOrError(begin_, header_, method_index).c_str(),
- method_access_flags);
- return false;
- }
-
- constexpr uint32_t kConstructorFlags = kAccStatic | kAccConstructor;
- const bool is_constructor_by_name = (constructor_flags_by_name & kConstructorFlags) != 0;
- const bool is_clinit_by_name = constructor_flags_by_name == kConstructorFlags;
-
- // Only methods named "<clinit>" or "<init>" may be marked constructor. Note: we cannot enforce
- // the reverse for backwards compatibility reasons.
- if (((method_access_flags & kAccConstructor) != 0) && !is_constructor_by_name) {
- *error_msg =
- StringPrintf("Method %" PRIu32 "(%s) is marked constructor, but doesn't match name",
- method_index,
- GetMethodDescriptionOrError(begin_, header_, method_index).c_str());
- return false;
- }
-
- if (is_constructor_by_name) {
- // Check that the static constructor (= static initializer) is named "<clinit>" and that the
- // instance constructor is called "<init>".
- bool is_static = (method_access_flags & kAccStatic) != 0;
- if (is_static ^ is_clinit_by_name) {
- *error_msg = StringPrintf("Constructor %" PRIu32 "(%s) is not flagged correctly wrt/ static.",
- method_index,
- GetMethodDescriptionOrError(begin_, header_, method_index).c_str());
- if (dex_file_->SupportsDefaultMethods()) {
- return false;
- } else {
- // Allow in older versions, but warn.
- LOG(WARNING) << "This dex file is invalid and will be rejected in the future. Error is: "
- << *error_msg;
- }
- }
- }
-
- // Check that static and private methods, as well as constructors, are in the direct methods list,
- // and other methods in the virtual methods list.
- bool is_direct = ((method_access_flags & (kAccStatic | kAccPrivate)) != 0) ||
- is_constructor_by_name;
- if (is_direct != expect_direct) {
- *error_msg = StringPrintf("Direct/virtual method %" PRIu32 "(%s) not in expected list %d",
- method_index,
- GetMethodDescriptionOrError(begin_, header_, method_index).c_str(),
- expect_direct);
- return false;
- }
-
- // From here on out it is easier to mask out the bits we're supposed to ignore.
- method_access_flags &= kMethodAccessFlags;
-
- // Interfaces are special.
- if ((class_access_flags & kAccInterface) != 0) {
- // Non-static interface methods must be public or private.
- uint32_t desired_flags = (kAccPublic | kAccStatic);
- if (dex_file_->SupportsDefaultMethods()) {
- desired_flags |= kAccPrivate;
- }
- if ((method_access_flags & desired_flags) == 0) {
- *error_msg = StringPrintf("Interface virtual method %" PRIu32 "(%s) is not public",
- method_index,
- GetMethodDescriptionOrError(begin_, header_, method_index).c_str());
- if (dex_file_->SupportsDefaultMethods()) {
- return false;
- } else {
- // Allow in older versions, but warn.
- LOG(WARNING) << "This dex file is invalid and will be rejected in the future. Error is: "
- << *error_msg;
- }
- }
- }
-
- // If there aren't any instructions, make sure that's expected.
- if (!has_code) {
- // Only native or abstract methods may not have code.
- if ((method_access_flags & (kAccNative | kAccAbstract)) == 0) {
- *error_msg = StringPrintf("Method %" PRIu32 "(%s) has no code, but is not marked native or "
- "abstract",
- method_index,
- GetMethodDescriptionOrError(begin_, header_, method_index).c_str());
- return false;
- }
- // Constructors must always have code.
- if (is_constructor_by_name) {
- *error_msg = StringPrintf("Constructor %u(%s) must not be abstract or native",
- method_index,
- GetMethodDescriptionOrError(begin_, header_, method_index).c_str());
- if (dex_file_->SupportsDefaultMethods()) {
- return false;
- } else {
- // Allow in older versions, but warn.
- LOG(WARNING) << "This dex file is invalid and will be rejected in the future. Error is: "
- << *error_msg;
- }
- }
- if ((method_access_flags & kAccAbstract) != 0) {
- // Abstract methods are not allowed to have the following flags.
- constexpr uint32_t kForbidden =
- kAccPrivate | kAccStatic | kAccFinal | kAccNative | kAccStrict | kAccSynchronized;
- if ((method_access_flags & kForbidden) != 0) {
- *error_msg = StringPrintf("Abstract method %" PRIu32 "(%s) has disallowed access flags %x",
- method_index,
- GetMethodDescriptionOrError(begin_, header_, method_index).c_str(),
- method_access_flags);
- return false;
- }
- // Abstract methods should be in an abstract class or interface.
- if ((class_access_flags & (kAccInterface | kAccAbstract)) == 0) {
- LOG(WARNING) << "Method " << GetMethodDescriptionOrError(begin_, header_, method_index)
- << " is abstract, but the declaring class is neither abstract nor an "
- << "interface in dex file "
- << dex_file_->GetLocation();
- }
- }
- // Interfaces are special.
- if ((class_access_flags & kAccInterface) != 0) {
- // Interface methods without code must be abstract.
- if ((method_access_flags & (kAccPublic | kAccAbstract)) != (kAccPublic | kAccAbstract)) {
- *error_msg = StringPrintf("Interface method %" PRIu32 "(%s) is not public and abstract",
- method_index,
- GetMethodDescriptionOrError(begin_, header_, method_index).c_str());
- if (dex_file_->SupportsDefaultMethods()) {
- return false;
- } else {
- // Allow in older versions, but warn.
- LOG(WARNING) << "This dex file is invalid and will be rejected in the future. Error is: "
- << *error_msg;
- }
- }
- // At this point, we know the method is public and abstract. This means that all the checks
- // for invalid combinations above applies. In addition, interface methods must not be
- // protected. This is caught by the check for only-one-of-public-protected-private.
- }
- return true;
- }
-
- // When there's code, the method must not be native or abstract.
- if ((method_access_flags & (kAccNative | kAccAbstract)) != 0) {
- *error_msg = StringPrintf("Method %" PRIu32 "(%s) has code, but is marked native or abstract",
- method_index,
- GetMethodDescriptionOrError(begin_, header_, method_index).c_str());
- return false;
- }
-
- // Instance constructors must not be synchronized and a few other flags.
- if (constructor_flags_by_name == kAccConstructor) {
- static constexpr uint32_t kInitAllowed =
- kAccPrivate | kAccProtected | kAccPublic | kAccStrict | kAccVarargs | kAccSynthetic;
- if ((method_access_flags & ~kInitAllowed) != 0) {
- *error_msg = StringPrintf("Constructor %" PRIu32 "(%s) flagged inappropriately %x",
- method_index,
- GetMethodDescriptionOrError(begin_, header_, method_index).c_str(),
- method_access_flags);
- return false;
- }
- }
-
- return true;
-}
-
-bool DexFileVerifier::CheckConstructorProperties(
- uint32_t method_index,
- uint32_t constructor_flags) {
- DCHECK(constructor_flags == kAccConstructor ||
- constructor_flags == (kAccConstructor | kAccStatic));
-
- // Check signature matches expectations.
- const DexFile::MethodId* const method_id = CheckLoadMethodId(method_index,
- "Bad <init>/<clinit> method id");
- if (method_id == nullptr) {
- return false;
- }
-
- // Check the ProtoId for the corresponding method.
- //
- // TODO(oth): the error message here is to satisfy the MethodId test
- // in the DexFileVerifierTest. The test is checking that the error
- // contains this string if the index is out of range.
- const DexFile::ProtoId* const proto_id = CheckLoadProtoId(method_id->proto_idx_,
- "inter_method_id_item proto_idx");
- if (proto_id == nullptr) {
- return false;
- }
-
- Signature signature = dex_file_->GetMethodSignature(*method_id);
- if (constructor_flags == (kAccStatic | kAccConstructor)) {
- if (!signature.IsVoid() || signature.GetNumberOfParameters() != 0) {
- ErrorStringPrintf("<clinit> must have descriptor ()V");
- return false;
- }
- } else if (!signature.IsVoid()) {
- ErrorStringPrintf("Constructor %u(%s) must be void",
- method_index,
- GetMethodDescriptionOrError(begin_, header_, method_index).c_str());
- return false;
- }
-
- return true;
-}
-
-} // namespace art
diff --git a/runtime/dex/dex_file_verifier.h b/runtime/dex/dex_file_verifier.h
deleted file mode 100644
index 6cb5d4c629..0000000000
--- a/runtime/dex/dex_file_verifier.h
+++ /dev/null
@@ -1,257 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ART_RUNTIME_DEX_DEX_FILE_VERIFIER_H_
-#define ART_RUNTIME_DEX_DEX_FILE_VERIFIER_H_
-
-#include <unordered_set>
-
-#include "base/allocator.h"
-#include "base/hash_map.h"
-#include "dex_file.h"
-#include "dex_file_types.h"
-#include "safe_map.h"
-
-namespace art {
-
-class DexFileVerifier {
- public:
- static bool Verify(const DexFile* dex_file,
- const uint8_t* begin,
- size_t size,
- const char* location,
- bool verify_checksum,
- std::string* error_msg);
-
- const std::string& FailureReason() const {
- return failure_reason_;
- }
-
- private:
- DexFileVerifier(const DexFile* dex_file,
- const uint8_t* begin,
- size_t size,
- const char* location,
- bool verify_checksum)
- : dex_file_(dex_file),
- begin_(begin),
- size_(size),
- location_(location),
- verify_checksum_(verify_checksum),
- header_(&dex_file->GetHeader()),
- ptr_(nullptr),
- previous_item_(nullptr) {
- }
-
- bool Verify();
-
- bool CheckShortyDescriptorMatch(char shorty_char, const char* descriptor, bool is_return_type);
- bool CheckListSize(const void* start, size_t count, size_t element_size, const char* label);
- // Check a list. The head is assumed to be at *ptr, and elements to be of size element_size. If
- // successful, the ptr will be moved forward the amount covered by the list.
- bool CheckList(size_t element_size, const char* label, const uint8_t* *ptr);
- // Checks whether the offset is zero (when size is zero) or that the offset falls within the area
- // claimed by the file.
- bool CheckValidOffsetAndSize(uint32_t offset, uint32_t size, size_t alignment, const char* label);
- // Checks whether the size is less than the limit.
- bool CheckSizeLimit(uint32_t size, uint32_t limit, const char* label);
- bool CheckIndex(uint32_t field, uint32_t limit, const char* label);
-
- bool CheckHeader();
- bool CheckMap();
-
- uint32_t ReadUnsignedLittleEndian(uint32_t size);
- bool CheckAndGetHandlerOffsets(const DexFile::CodeItem* code_item,
- uint32_t* handler_offsets, uint32_t handlers_size);
- bool CheckClassDataItemField(uint32_t idx,
- uint32_t access_flags,
- uint32_t class_access_flags,
- dex::TypeIndex class_type_index,
- bool expect_static);
- bool CheckClassDataItemMethod(uint32_t idx,
- uint32_t access_flags,
- uint32_t class_access_flags,
- dex::TypeIndex class_type_index,
- uint32_t code_offset,
- std::unordered_set<uint32_t>* direct_method_indexes,
- bool expect_direct);
- bool CheckOrderAndGetClassDef(bool is_field,
- const char* type_descr,
- uint32_t curr_index,
- uint32_t prev_index,
- bool* have_class,
- dex::TypeIndex* class_type_index,
- const DexFile::ClassDef** class_def);
- bool CheckStaticFieldTypes(const DexFile::ClassDef* class_def);
-
- bool CheckPadding(size_t offset, uint32_t aligned_offset, DexFile::MapItemType type);
- bool CheckEncodedValue();
- bool CheckEncodedArray();
- bool CheckEncodedAnnotation();
-
- bool CheckIntraClassDataItem();
- // Check all fields of the given type from the given iterator. Load the class data from the first
- // field, if necessary (and return it), or use the given values.
- template <bool kStatic>
- bool CheckIntraClassDataItemFields(ClassDataItemIterator* it,
- bool* have_class,
- dex::TypeIndex* class_type_index,
- const DexFile::ClassDef** class_def);
- // Check all methods of the given type from the given iterator. Load the class data from the first
- // method, if necessary (and return it), or use the given values.
- template <bool kDirect>
- bool CheckIntraClassDataItemMethods(ClassDataItemIterator* it,
- std::unordered_set<uint32_t>* direct_method_indexes,
- bool* have_class,
- dex::TypeIndex* class_type_index,
- const DexFile::ClassDef** class_def);
-
- bool CheckIntraCodeItem();
- bool CheckIntraStringDataItem();
- bool CheckIntraDebugInfoItem();
- bool CheckIntraAnnotationItem();
- bool CheckIntraAnnotationsDirectoryItem();
-
- bool CheckIntraSectionIterate(size_t offset, uint32_t count, DexFile::MapItemType type);
- bool CheckIntraIdSection(size_t offset, uint32_t count, DexFile::MapItemType type);
- bool CheckIntraDataSection(size_t offset, uint32_t count, DexFile::MapItemType type);
- bool CheckIntraSection();
-
- bool CheckOffsetToTypeMap(size_t offset, uint16_t type);
-
- // Note: as sometimes kDexNoIndex16, being 0xFFFF, is a valid return value, we need an
- // additional out parameter to signal any errors loading an index.
- dex::TypeIndex FindFirstClassDataDefiner(const uint8_t* ptr, bool* success);
- dex::TypeIndex FindFirstAnnotationsDirectoryDefiner(const uint8_t* ptr, bool* success);
-
- bool CheckInterStringIdItem();
- bool CheckInterTypeIdItem();
- bool CheckInterProtoIdItem();
- bool CheckInterFieldIdItem();
- bool CheckInterMethodIdItem();
- bool CheckInterClassDefItem();
- bool CheckInterCallSiteIdItem();
- bool CheckInterMethodHandleItem();
- bool CheckInterAnnotationSetRefList();
- bool CheckInterAnnotationSetItem();
- bool CheckInterClassDataItem();
- bool CheckInterAnnotationsDirectoryItem();
-
- bool CheckInterSectionIterate(size_t offset, uint32_t count, DexFile::MapItemType type);
- bool CheckInterSection();
-
- // Load a string by (type) index. Checks whether the index is in bounds, printing the error if
- // not. If there is an error, null is returned.
- const char* CheckLoadStringByIdx(dex::StringIndex idx, const char* error_fmt);
- const char* CheckLoadStringByTypeIdx(dex::TypeIndex type_idx, const char* error_fmt);
-
- // Load a field/method/proto Id by index. Checks whether the index is in bounds, printing the
- // error if not. If there is an error, null is returned.
- const DexFile::FieldId* CheckLoadFieldId(uint32_t idx, const char* error_fmt);
- const DexFile::MethodId* CheckLoadMethodId(uint32_t idx, const char* error_fmt);
- const DexFile::ProtoId* CheckLoadProtoId(uint32_t idx, const char* error_fmt);
-
- void ErrorStringPrintf(const char* fmt, ...)
- __attribute__((__format__(__printf__, 2, 3))) COLD_ATTR;
- bool FailureReasonIsSet() const { return failure_reason_.size() != 0; }
-
- // Retrieve class index and class def from the given member. index is the member index, which is
- // taken as either a field or a method index (as designated by is_field). The result, if the
- // member and declaring class could be found, is stored in class_type_index and class_def.
- // This is an expensive lookup, as we have to find the class def by type index, which is a
- // linear search. The output values should thus be cached by the caller.
- bool FindClassIndexAndDef(uint32_t index,
- bool is_field,
- dex::TypeIndex* class_type_index,
- const DexFile::ClassDef** output_class_def);
-
- // Check validity of the given access flags, interpreted for a field in the context of a class
- // with the given second access flags.
- bool CheckFieldAccessFlags(uint32_t idx,
- uint32_t field_access_flags,
- uint32_t class_access_flags,
- std::string* error_message);
-
- // Check validity of the given method and access flags, in the context of a class with the given
- // second access flags.
- bool CheckMethodAccessFlags(uint32_t method_index,
- uint32_t method_access_flags,
- uint32_t class_access_flags,
- uint32_t constructor_flags_by_name,
- bool has_code,
- bool expect_direct,
- std::string* error_message);
-
- // Check validity of given method if it's a constructor or class initializer.
- bool CheckConstructorProperties(uint32_t method_index, uint32_t constructor_flags);
-
- const DexFile* const dex_file_;
- const uint8_t* const begin_;
- const size_t size_;
- const char* const location_;
- const bool verify_checksum_;
- const DexFile::Header* const header_;
-
- struct OffsetTypeMapEmptyFn {
- // Make a hash map slot empty by making the offset 0. Offset 0 is a valid dex file offset that
- // is in the offset of the dex file header. However, we only store data section items in the
- // map, and these are after the header.
- void MakeEmpty(std::pair<uint32_t, uint16_t>& pair) const {
- pair.first = 0u;
- }
- // Check if a hash map slot is empty.
- bool IsEmpty(const std::pair<uint32_t, uint16_t>& pair) const {
- return pair.first == 0;
- }
- };
- struct OffsetTypeMapHashCompareFn {
- // Hash function for offset.
- size_t operator()(const uint32_t key) const {
- return key;
- }
- // std::equal function for offset.
- bool operator()(const uint32_t a, const uint32_t b) const {
- return a == b;
- }
- };
- // Map from offset to dex file type, HashMap for performance reasons.
- template<class Key,
- class T,
- class EmptyFn,
- AllocatorTag kTag,
- class Hash = std::hash<Key>,
- class Pred = std::equal_to<Key>>
- using AllocationTrackingHashMap = HashMap<
- Key, T, EmptyFn, Hash, Pred, TrackingAllocator<std::pair<Key, T>, kTag>>;
-
- AllocationTrackingHashMap<uint32_t,
- uint16_t,
- OffsetTypeMapEmptyFn,
- kAllocatorTagDexFileVerifier,
- OffsetTypeMapHashCompareFn,
- OffsetTypeMapHashCompareFn> offset_to_type_map_;
- const uint8_t* ptr_;
- const void* previous_item_;
-
- std::string failure_reason_;
-
- // Set of type ids for which there are ClassDef elements in the dex file.
- std::unordered_set<decltype(DexFile::ClassDef::class_idx_)> defined_classes_;
-};
-
-} // namespace art
-
-#endif // ART_RUNTIME_DEX_DEX_FILE_VERIFIER_H_
diff --git a/runtime/dex/dex_file_verifier_test.cc b/runtime/dex/dex_file_verifier_test.cc
deleted file mode 100644
index 1cd4b2c07b..0000000000
--- a/runtime/dex/dex_file_verifier_test.cc
+++ /dev/null
@@ -1,2186 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "dex_file_verifier.h"
-
-#include <zlib.h>
-
-#include <functional>
-#include <memory>
-
-#include "base/bit_utils.h"
-#include "base/macros.h"
-#include "base64_test_util.h"
-#include "descriptors_names.h"
-#include "dex_file-inl.h"
-#include "dex_file_loader.h"
-#include "dex_file_types.h"
-#include "gtest/gtest.h"
-#include "leb128.h"
-#include "standard_dex_file.h"
-
-namespace art {
-
-static constexpr char kLocationString[] = "dex_file_location";
-
-// Make the Dex file version 37.
-static void MakeDexVersion37(DexFile* dex_file) {
- size_t offset = OFFSETOF_MEMBER(DexFile::Header, magic_) + 6;
- CHECK_EQ(*(dex_file->Begin() + offset), '5');
- *(const_cast<uint8_t*>(dex_file->Begin()) + offset) = '7';
-}
-
-static void FixUpChecksum(uint8_t* dex_file) {
- DexFile::Header* header = reinterpret_cast<DexFile::Header*>(dex_file);
- uint32_t expected_size = header->file_size_;
- uint32_t adler_checksum = adler32(0L, Z_NULL, 0);
- const uint32_t non_sum = sizeof(DexFile::Header::magic_) + sizeof(DexFile::Header::checksum_);
- const uint8_t* non_sum_ptr = dex_file + non_sum;
- adler_checksum = adler32(adler_checksum, non_sum_ptr, expected_size - non_sum);
- header->checksum_ = adler_checksum;
-}
-
-class DexFileVerifierTest : public testing::Test {
- protected:
- DexFile* GetDexFile(const uint8_t* dex_bytes, size_t length) {
- return new StandardDexFile(dex_bytes, length, "tmp", 0, nullptr, nullptr);
- }
-
- void VerifyModification(const char* dex_file_base64_content,
- const char* location,
- const std::function<void(DexFile*)>& f,
- const char* expected_error) {
- size_t length;
- std::unique_ptr<uint8_t[]> dex_bytes(DecodeBase64(dex_file_base64_content, &length));
- CHECK(dex_bytes != nullptr);
- // Note: `dex_file` will be destroyed before `dex_bytes`.
- std::unique_ptr<DexFile> dex_file(GetDexFile(dex_bytes.get(), length));
- f(dex_file.get());
- FixUpChecksum(const_cast<uint8_t*>(dex_file->Begin()));
-
- static constexpr bool kVerifyChecksum = true;
- std::string error_msg;
- bool success = DexFileVerifier::Verify(dex_file.get(),
- dex_file->Begin(),
- dex_file->Size(),
- location,
- kVerifyChecksum,
- &error_msg);
- if (expected_error == nullptr) {
- EXPECT_TRUE(success) << error_msg;
- } else {
- EXPECT_FALSE(success) << "Expected " << expected_error;
- if (!success) {
- EXPECT_NE(error_msg.find(expected_error), std::string::npos) << error_msg;
- }
- }
- }
-};
-
-static std::unique_ptr<const DexFile> OpenDexFileBase64(const char* base64,
- const char* location,
- std::string* error_msg) {
- // decode base64
- CHECK(base64 != nullptr);
- size_t length;
- std::unique_ptr<uint8_t[]> dex_bytes(DecodeBase64(base64, &length));
- CHECK(dex_bytes.get() != nullptr);
-
- // read dex
- std::vector<std::unique_ptr<const DexFile>> tmp;
- const DexFileLoader dex_file_loader;
- bool success = dex_file_loader.OpenAll(dex_bytes.get(),
- length,
- location,
- /* verify */ true,
- /* verify_checksum */ true,
- error_msg,
- &tmp);
- CHECK(success) << *error_msg;
- EXPECT_EQ(1U, tmp.size());
- std::unique_ptr<const DexFile> dex_file = std::move(tmp[0]);
- return dex_file;
-}
-
-// To generate a base64 encoded Dex file (such as kGoodTestDex, below)
-// from Smali files, use:
-//
-// smali assemble -o classes.dex class1.smali [class2.smali ...]
-// base64 classes.dex >classes.dex.base64
-
-// For reference.
-static const char kGoodTestDex[] =
- "ZGV4CjAzNQDrVbyVkxX1HljTznNf95AglkUAhQuFtmKkAgAAcAAAAHhWNBIAAAAAAAAAAAQCAAAN"
- "AAAAcAAAAAYAAACkAAAAAgAAALwAAAABAAAA1AAAAAQAAADcAAAAAQAAAPwAAACIAQAAHAEAAFoB"
- "AABiAQAAagEAAIEBAACVAQAAqQEAAL0BAADDAQAAzgEAANEBAADVAQAA2gEAAN8BAAABAAAAAgAA"
- "AAMAAAAEAAAABQAAAAgAAAAIAAAABQAAAAAAAAAJAAAABQAAAFQBAAAEAAEACwAAAAAAAAAAAAAA"
- "AAAAAAoAAAABAAEADAAAAAIAAAAAAAAAAAAAAAEAAAACAAAAAAAAAAcAAAAAAAAA8wEAAAAAAAAB"
- "AAEAAQAAAOgBAAAEAAAAcBADAAAADgACAAAAAgAAAO0BAAAIAAAAYgAAABoBBgBuIAIAEAAOAAEA"
- "AAADAAY8aW5pdD4ABkxUZXN0OwAVTGphdmEvaW8vUHJpbnRTdHJlYW07ABJMamF2YS9sYW5nL09i"
- "amVjdDsAEkxqYXZhL2xhbmcvU3RyaW5nOwASTGphdmEvbGFuZy9TeXN0ZW07AARUZXN0AAlUZXN0"
- "LmphdmEAAVYAAlZMAANmb28AA291dAAHcHJpbnRsbgABAAcOAAMABw54AAAAAgAAgYAEnAIBCbQC"
- "AAAADQAAAAAAAAABAAAAAAAAAAEAAAANAAAAcAAAAAIAAAAGAAAApAAAAAMAAAACAAAAvAAAAAQA"
- "AAABAAAA1AAAAAUAAAAEAAAA3AAAAAYAAAABAAAA/AAAAAEgAAACAAAAHAEAAAEQAAABAAAAVAEA"
- "AAIgAAANAAAAWgEAAAMgAAACAAAA6AEAAAAgAAABAAAA8wEAAAAQAAABAAAABAIAAA==";
-
-TEST_F(DexFileVerifierTest, GoodDex) {
- std::string error_msg;
- std::unique_ptr<const DexFile> raw(OpenDexFileBase64(kGoodTestDex,
- kLocationString,
- &error_msg));
- ASSERT_TRUE(raw.get() != nullptr) << error_msg;
-}
-
-TEST_F(DexFileVerifierTest, MethodId) {
- // Class idx error.
- VerifyModification(
- kGoodTestDex,
- "method_id_class_idx",
- [](DexFile* dex_file) {
- DexFile::MethodId* method_id = const_cast<DexFile::MethodId*>(&dex_file->GetMethodId(0));
- method_id->class_idx_ = dex::TypeIndex(0xFF);
- },
- "could not find declaring class for direct method index 0");
-
- // Proto idx error.
- VerifyModification(
- kGoodTestDex,
- "method_id_proto_idx",
- [](DexFile* dex_file) {
- DexFile::MethodId* method_id = const_cast<DexFile::MethodId*>(&dex_file->GetMethodId(0));
- method_id->proto_idx_ = 0xFF;
- },
- "inter_method_id_item proto_idx");
-
- // Name idx error.
- VerifyModification(
- kGoodTestDex,
- "method_id_name_idx",
- [](DexFile* dex_file) {
- DexFile::MethodId* method_id = const_cast<DexFile::MethodId*>(&dex_file->GetMethodId(0));
- method_id->name_idx_ = dex::StringIndex(0xFF);
- },
- "String index not available for method flags verification");
-}
-
-// Method flags test class generated from the following smali code. The declared-synchronized
-// flags are there to enforce a 3-byte uLEB128 encoding so we don't have to relayout
-// the code, but we need to remove them before doing tests.
-//
-// .class public LMethodFlags;
-// .super Ljava/lang/Object;
-//
-// .method public static constructor <clinit>()V
-// .registers 1
-// return-void
-// .end method
-//
-// .method public constructor <init>()V
-// .registers 1
-// return-void
-// .end method
-//
-// .method private declared-synchronized foo()V
-// .registers 1
-// return-void
-// .end method
-//
-// .method public declared-synchronized bar()V
-// .registers 1
-// return-void
-// .end method
-
-static const char kMethodFlagsTestDex[] =
- "ZGV4CjAzNQCyOQrJaDBwiIWv5MIuYKXhxlLLsQcx5SwgAgAAcAAAAHhWNBIAAAAAAAAAAJgBAAAH"
- "AAAAcAAAAAMAAACMAAAAAQAAAJgAAAAAAAAAAAAAAAQAAACkAAAAAQAAAMQAAAA8AQAA5AAAAOQA"
- "AADuAAAA9gAAAAUBAAAZAQAAHAEAACEBAAACAAAAAwAAAAQAAAAEAAAAAgAAAAAAAAAAAAAAAAAA"
- "AAAAAAABAAAAAAAAAAUAAAAAAAAABgAAAAAAAAABAAAAAQAAAAAAAAD/////AAAAAHoBAAAAAAAA"
- "CDxjbGluaXQ+AAY8aW5pdD4ADUxNZXRob2RGbGFnczsAEkxqYXZhL2xhbmcvT2JqZWN0OwABVgAD"
- "YmFyAANmb28AAAAAAAAAAQAAAAAAAAAAAAAAAQAAAA4AAAABAAEAAAAAAAAAAAABAAAADgAAAAEA"
- "AQAAAAAAAAAAAAEAAAAOAAAAAQABAAAAAAAAAAAAAQAAAA4AAAADAQCJgASsAgGBgATAAgKCgAjU"
- "AgKBgAjoAgAACwAAAAAAAAABAAAAAAAAAAEAAAAHAAAAcAAAAAIAAAADAAAAjAAAAAMAAAABAAAA"
- "mAAAAAUAAAAEAAAApAAAAAYAAAABAAAAxAAAAAIgAAAHAAAA5AAAAAMQAAABAAAAKAEAAAEgAAAE"
- "AAAALAEAAAAgAAABAAAAegEAAAAQAAABAAAAmAEAAA==";
-
-// Find the method data for the first method with the given name (from class 0). Note: the pointer
-// is to the access flags, so that the caller doesn't have to handle the leb128-encoded method-index
-// delta.
-static const uint8_t* FindMethodData(const DexFile* dex_file,
- const char* name,
- /*out*/ uint32_t* method_idx = nullptr) {
- const DexFile::ClassDef& class_def = dex_file->GetClassDef(0);
- const uint8_t* class_data = dex_file->GetClassData(class_def);
-
- ClassDataItemIterator it(*dex_file, class_data);
-
- const uint8_t* trailing = class_data;
- // Need to manually decode the four entries. DataPointer() doesn't work for this, as the first
- // element has already been loaded into the iterator.
- DecodeUnsignedLeb128(&trailing);
- DecodeUnsignedLeb128(&trailing);
- DecodeUnsignedLeb128(&trailing);
- DecodeUnsignedLeb128(&trailing);
-
- // Skip all fields.
- while (it.HasNextStaticField() || it.HasNextInstanceField()) {
- trailing = it.DataPointer();
- it.Next();
- }
-
- while (it.HasNextMethod()) {
- uint32_t method_index = it.GetMemberIndex();
- dex::StringIndex name_index = dex_file->GetMethodId(method_index).name_idx_;
- const DexFile::StringId& string_id = dex_file->GetStringId(name_index);
- const char* str = dex_file->GetStringData(string_id);
- if (strcmp(name, str) == 0) {
- if (method_idx != nullptr) {
- *method_idx = method_index;
- }
- DecodeUnsignedLeb128(&trailing);
- return trailing;
- }
-
- trailing = it.DataPointer();
- it.Next();
- }
-
- return nullptr;
-}
-
-// Set the method flags to the given value.
-static void SetMethodFlags(DexFile* dex_file, const char* method, uint32_t mask) {
- uint8_t* method_flags_ptr = const_cast<uint8_t*>(FindMethodData(dex_file, method));
- CHECK(method_flags_ptr != nullptr) << method;
-
- // Unroll this, as we only have three bytes, anyways.
- uint8_t base1 = static_cast<uint8_t>(mask & 0x7F);
- *(method_flags_ptr++) = (base1 | 0x80);
- mask >>= 7;
-
- uint8_t base2 = static_cast<uint8_t>(mask & 0x7F);
- *(method_flags_ptr++) = (base2 | 0x80);
- mask >>= 7;
-
- uint8_t base3 = static_cast<uint8_t>(mask & 0x7F);
- *method_flags_ptr = base3;
-}
-
-static uint32_t GetMethodFlags(DexFile* dex_file, const char* method) {
- const uint8_t* method_flags_ptr = const_cast<uint8_t*>(FindMethodData(dex_file, method));
- CHECK(method_flags_ptr != nullptr) << method;
- return DecodeUnsignedLeb128(&method_flags_ptr);
-}
-
-// Apply the given mask to method flags.
-static void ApplyMaskToMethodFlags(DexFile* dex_file, const char* method, uint32_t mask) {
- uint32_t value = GetMethodFlags(dex_file, method);
- value &= mask;
- SetMethodFlags(dex_file, method, value);
-}
-
-// Apply the given mask to method flags.
-static void OrMaskToMethodFlags(DexFile* dex_file, const char* method, uint32_t mask) {
- uint32_t value = GetMethodFlags(dex_file, method);
- value |= mask;
- SetMethodFlags(dex_file, method, value);
-}
-
-// Set code_off to 0 for the method.
-static void RemoveCode(DexFile* dex_file, const char* method) {
- const uint8_t* ptr = FindMethodData(dex_file, method);
- // Next is flags, pass.
- DecodeUnsignedLeb128(&ptr);
-
- // Figure out how many bytes the code_off is.
- const uint8_t* tmp = ptr;
- DecodeUnsignedLeb128(&tmp);
- size_t bytes = tmp - ptr;
-
- uint8_t* mod = const_cast<uint8_t*>(ptr);
- for (size_t i = 1; i < bytes; ++i) {
- *(mod++) = 0x80;
- }
- *mod = 0x00;
-}
-
-TEST_F(DexFileVerifierTest, MethodAccessFlagsBase) {
- // Check that it's OK when the wrong declared-synchronized flag is removed from "foo."
- VerifyModification(
- kMethodFlagsTestDex,
- "method_flags_ok",
- [](DexFile* dex_file) {
- ApplyMaskToMethodFlags(dex_file, "foo", ~kAccDeclaredSynchronized);
- ApplyMaskToMethodFlags(dex_file, "bar", ~kAccDeclaredSynchronized);
- },
- nullptr);
-}
-
-TEST_F(DexFileVerifierTest, MethodAccessFlagsConstructors) {
- // Make sure we still accept constructors without their flags.
- VerifyModification(
- kMethodFlagsTestDex,
- "method_flags_missing_constructor_tag_ok",
- [](DexFile* dex_file) {
- ApplyMaskToMethodFlags(dex_file, "foo", ~kAccDeclaredSynchronized);
- ApplyMaskToMethodFlags(dex_file, "bar", ~kAccDeclaredSynchronized);
-
- ApplyMaskToMethodFlags(dex_file, "<init>", ~kAccConstructor);
- ApplyMaskToMethodFlags(dex_file, "<clinit>", ~kAccConstructor);
- },
- nullptr);
-
- constexpr const char* kConstructors[] = { "<clinit>", "<init>"};
- for (size_t i = 0; i < 2; ++i) {
- // Constructor with code marked native.
- VerifyModification(
- kMethodFlagsTestDex,
- "method_flags_constructor_native",
- [&](DexFile* dex_file) {
- ApplyMaskToMethodFlags(dex_file, "foo", ~kAccDeclaredSynchronized);
- ApplyMaskToMethodFlags(dex_file, "bar", ~kAccDeclaredSynchronized);
-
- OrMaskToMethodFlags(dex_file, kConstructors[i], kAccNative);
- },
- "has code, but is marked native or abstract");
- // Constructor with code marked abstract.
- VerifyModification(
- kMethodFlagsTestDex,
- "method_flags_constructor_abstract",
- [&](DexFile* dex_file) {
- ApplyMaskToMethodFlags(dex_file, "foo", ~kAccDeclaredSynchronized);
- ApplyMaskToMethodFlags(dex_file, "bar", ~kAccDeclaredSynchronized);
-
- OrMaskToMethodFlags(dex_file, kConstructors[i], kAccAbstract);
- },
- "has code, but is marked native or abstract");
- // Constructor as-is without code.
- VerifyModification(
- kMethodFlagsTestDex,
- "method_flags_constructor_nocode",
- [&](DexFile* dex_file) {
- ApplyMaskToMethodFlags(dex_file, "foo", ~kAccDeclaredSynchronized);
- ApplyMaskToMethodFlags(dex_file, "bar", ~kAccDeclaredSynchronized);
-
- RemoveCode(dex_file, kConstructors[i]);
- },
- "has no code, but is not marked native or abstract");
- // Constructor without code marked native.
- VerifyModification(
- kMethodFlagsTestDex,
- "method_flags_constructor_native_nocode",
- [&](DexFile* dex_file) {
- MakeDexVersion37(dex_file);
- ApplyMaskToMethodFlags(dex_file, "foo", ~kAccDeclaredSynchronized);
- ApplyMaskToMethodFlags(dex_file, "bar", ~kAccDeclaredSynchronized);
-
- OrMaskToMethodFlags(dex_file, kConstructors[i], kAccNative);
- RemoveCode(dex_file, kConstructors[i]);
- },
- "must not be abstract or native");
- // Constructor without code marked abstract.
- VerifyModification(
- kMethodFlagsTestDex,
- "method_flags_constructor_abstract_nocode",
- [&](DexFile* dex_file) {
- MakeDexVersion37(dex_file);
- ApplyMaskToMethodFlags(dex_file, "foo", ~kAccDeclaredSynchronized);
- ApplyMaskToMethodFlags(dex_file, "bar", ~kAccDeclaredSynchronized);
-
- OrMaskToMethodFlags(dex_file, kConstructors[i], kAccAbstract);
- RemoveCode(dex_file, kConstructors[i]);
- },
- "must not be abstract or native");
- }
- // <init> may only have (modulo ignored):
- // kAccPrivate | kAccProtected | kAccPublic | kAccStrict | kAccVarargs | kAccSynthetic
- static constexpr uint32_t kInitAllowed[] = {
- 0,
- kAccPrivate,
- kAccProtected,
- kAccPublic,
- kAccStrict,
- kAccVarargs,
- kAccSynthetic
- };
- for (size_t i = 0; i < arraysize(kInitAllowed); ++i) {
- VerifyModification(
- kMethodFlagsTestDex,
- "init_allowed_flags",
- [&](DexFile* dex_file) {
- ApplyMaskToMethodFlags(dex_file, "foo", ~kAccDeclaredSynchronized);
- ApplyMaskToMethodFlags(dex_file, "bar", ~kAccDeclaredSynchronized);
-
- ApplyMaskToMethodFlags(dex_file, "<init>", ~kAccPublic);
- OrMaskToMethodFlags(dex_file, "<init>", kInitAllowed[i]);
- },
- nullptr);
- }
- // Only one of public-private-protected.
- for (size_t i = 1; i < 8; ++i) {
- if (POPCOUNT(i) < 2) {
- continue;
- }
- // Technically the flags match, but just be defensive here.
- uint32_t mask = ((i & 1) != 0 ? kAccPrivate : 0) |
- ((i & 2) != 0 ? kAccProtected : 0) |
- ((i & 4) != 0 ? kAccPublic : 0);
- VerifyModification(
- kMethodFlagsTestDex,
- "init_one_of_ppp",
- [&](DexFile* dex_file) {
- ApplyMaskToMethodFlags(dex_file, "foo", ~kAccDeclaredSynchronized);
- ApplyMaskToMethodFlags(dex_file, "bar", ~kAccDeclaredSynchronized);
-
- ApplyMaskToMethodFlags(dex_file, "<init>", ~kAccPublic);
- OrMaskToMethodFlags(dex_file, "<init>", mask);
- },
- "Method may have only one of public/protected/private");
- }
- // <init> doesn't allow
- // kAccStatic | kAccFinal | kAccSynchronized | kAccBridge
- // Need to handle static separately as it has its own error message.
- VerifyModification(
- kMethodFlagsTestDex,
- "init_not_allowed_flags",
- [&](DexFile* dex_file) {
- MakeDexVersion37(dex_file);
- ApplyMaskToMethodFlags(dex_file, "foo", ~kAccDeclaredSynchronized);
- ApplyMaskToMethodFlags(dex_file, "bar", ~kAccDeclaredSynchronized);
-
- ApplyMaskToMethodFlags(dex_file, "<init>", ~kAccPublic);
- OrMaskToMethodFlags(dex_file, "<init>", kAccStatic);
- },
- "Constructor 1(LMethodFlags;.<init>) is not flagged correctly wrt/ static");
- static constexpr uint32_t kInitNotAllowed[] = {
- kAccFinal,
- kAccSynchronized,
- kAccBridge
- };
- for (size_t i = 0; i < arraysize(kInitNotAllowed); ++i) {
- VerifyModification(
- kMethodFlagsTestDex,
- "init_not_allowed_flags",
- [&](DexFile* dex_file) {
- ApplyMaskToMethodFlags(dex_file, "foo", ~kAccDeclaredSynchronized);
- ApplyMaskToMethodFlags(dex_file, "bar", ~kAccDeclaredSynchronized);
-
- ApplyMaskToMethodFlags(dex_file, "<init>", ~kAccPublic);
- OrMaskToMethodFlags(dex_file, "<init>", kInitNotAllowed[i]);
- },
- "Constructor 1(LMethodFlags;.<init>) flagged inappropriately");
- }
-}
-
-TEST_F(DexFileVerifierTest, MethodAccessFlagsMethods) {
- constexpr const char* kMethods[] = { "foo", "bar"};
- for (size_t i = 0; i < arraysize(kMethods); ++i) {
- // Make sure we reject non-constructors marked as constructors.
- VerifyModification(
- kMethodFlagsTestDex,
- "method_flags_non_constructor",
- [&](DexFile* dex_file) {
- ApplyMaskToMethodFlags(dex_file, "foo", ~kAccDeclaredSynchronized);
- ApplyMaskToMethodFlags(dex_file, "bar", ~kAccDeclaredSynchronized);
-
- OrMaskToMethodFlags(dex_file, kMethods[i], kAccConstructor);
- },
- "is marked constructor, but doesn't match name");
-
- VerifyModification(
- kMethodFlagsTestDex,
- "method_flags_native_with_code",
- [&](DexFile* dex_file) {
- ApplyMaskToMethodFlags(dex_file, "foo", ~kAccDeclaredSynchronized);
- ApplyMaskToMethodFlags(dex_file, "bar", ~kAccDeclaredSynchronized);
-
- OrMaskToMethodFlags(dex_file, kMethods[i], kAccNative);
- },
- "has code, but is marked native or abstract");
-
- VerifyModification(
- kMethodFlagsTestDex,
- "method_flags_abstract_with_code",
- [&](DexFile* dex_file) {
- ApplyMaskToMethodFlags(dex_file, "foo", ~kAccDeclaredSynchronized);
- ApplyMaskToMethodFlags(dex_file, "bar", ~kAccDeclaredSynchronized);
-
- OrMaskToMethodFlags(dex_file, kMethods[i], kAccAbstract);
- },
- "has code, but is marked native or abstract");
-
- VerifyModification(
- kMethodFlagsTestDex,
- "method_flags_non_abstract_native_no_code",
- [&](DexFile* dex_file) {
- ApplyMaskToMethodFlags(dex_file, "foo", ~kAccDeclaredSynchronized);
- ApplyMaskToMethodFlags(dex_file, "bar", ~kAccDeclaredSynchronized);
-
- RemoveCode(dex_file, kMethods[i]);
- },
- "has no code, but is not marked native or abstract");
-
- // Abstract methods may not have the following flags.
- constexpr uint32_t kAbstractDisallowed[] = {
- kAccPrivate,
- kAccStatic,
- kAccFinal,
- kAccNative,
- kAccStrict,
- kAccSynchronized,
- };
- for (size_t j = 0; j < arraysize(kAbstractDisallowed); ++j) {
- VerifyModification(
- kMethodFlagsTestDex,
- "method_flags_abstract_and_disallowed_no_code",
- [&](DexFile* dex_file) {
- ApplyMaskToMethodFlags(dex_file, "foo", ~kAccDeclaredSynchronized);
- ApplyMaskToMethodFlags(dex_file, "bar", ~kAccDeclaredSynchronized);
-
- RemoveCode(dex_file, kMethods[i]);
-
- // Can't check private and static with foo, as it's in the virtual list and gives a
- // different error.
- if (((GetMethodFlags(dex_file, kMethods[i]) & kAccPublic) != 0) &&
- ((kAbstractDisallowed[j] & (kAccPrivate | kAccStatic)) != 0)) {
- // Use another breaking flag.
- OrMaskToMethodFlags(dex_file, kMethods[i], kAccAbstract | kAccFinal);
- } else {
- OrMaskToMethodFlags(dex_file, kMethods[i], kAccAbstract | kAbstractDisallowed[j]);
- }
- },
- "has disallowed access flags");
- }
-
- // Only one of public-private-protected.
- for (size_t j = 1; j < 8; ++j) {
- if (POPCOUNT(j) < 2) {
- continue;
- }
- // Technically the flags match, but just be defensive here.
- uint32_t mask = ((j & 1) != 0 ? kAccPrivate : 0) |
- ((j & 2) != 0 ? kAccProtected : 0) |
- ((j & 4) != 0 ? kAccPublic : 0);
- VerifyModification(
- kMethodFlagsTestDex,
- "method_flags_one_of_ppp",
- [&](DexFile* dex_file) {
- ApplyMaskToMethodFlags(dex_file, "foo", ~kAccDeclaredSynchronized);
- ApplyMaskToMethodFlags(dex_file, "bar", ~kAccDeclaredSynchronized);
-
- ApplyMaskToMethodFlags(dex_file, kMethods[i], ~kAccPublic);
- OrMaskToMethodFlags(dex_file, kMethods[i], mask);
- },
- "Method may have only one of public/protected/private");
- }
- }
-}
-
-TEST_F(DexFileVerifierTest, MethodAccessFlagsIgnoredOK) {
- constexpr const char* kMethods[] = { "<clinit>", "<init>", "foo", "bar"};
- for (size_t i = 0; i < arraysize(kMethods); ++i) {
- // All interesting method flags, other flags are to be ignored.
- constexpr uint32_t kAllMethodFlags =
- kAccPublic |
- kAccPrivate |
- kAccProtected |
- kAccStatic |
- kAccFinal |
- kAccSynchronized |
- kAccBridge |
- kAccVarargs |
- kAccNative |
- kAccAbstract |
- kAccStrict |
- kAccSynthetic;
- constexpr uint32_t kIgnoredMask = ~kAllMethodFlags & 0xFFFF;
- VerifyModification(
- kMethodFlagsTestDex,
- "method_flags_ignored",
- [&](DexFile* dex_file) {
- ApplyMaskToMethodFlags(dex_file, "foo", ~kAccDeclaredSynchronized);
- ApplyMaskToMethodFlags(dex_file, "bar", ~kAccDeclaredSynchronized);
-
- OrMaskToMethodFlags(dex_file, kMethods[i], kIgnoredMask);
- },
- nullptr);
- }
-}
-
-TEST_F(DexFileVerifierTest, B28552165) {
- // Regression test for bad error string retrieval in different situations.
- // Using invalid access flags to trigger the error.
- VerifyModification(
- kMethodFlagsTestDex,
- "b28552165",
- [](DexFile* dex_file) {
- OrMaskToMethodFlags(dex_file, "foo", kAccPublic | kAccProtected);
- },
- "Method may have only one of public/protected/private, LMethodFlags;.foo");
-}
-
-// Set of dex files for interface method tests. As it's not as easy to mutate method names, it's
-// just easier to break up bad cases.
-
-// Standard interface. Use declared-synchronized again for 3B encoding.
-//
-// .class public interface LInterfaceMethodFlags;
-// .super Ljava/lang/Object;
-//
-// .method public static constructor <clinit>()V
-// .registers 1
-// return-void
-// .end method
-//
-// .method public abstract declared-synchronized foo()V
-// .end method
-static const char kMethodFlagsInterface[] =
- "ZGV4CjAzNQCOM0odZ5bws1d9GSmumXaK5iE/7XxFpOm8AQAAcAAAAHhWNBIAAAAAAAAAADQBAAAF"
- "AAAAcAAAAAMAAACEAAAAAQAAAJAAAAAAAAAAAAAAAAIAAACcAAAAAQAAAKwAAADwAAAAzAAAAMwA"
- "AADWAAAA7gAAAAIBAAAFAQAAAQAAAAIAAAADAAAAAwAAAAIAAAAAAAAAAAAAAAAAAAAAAAAABAAA"
- "AAAAAAABAgAAAQAAAAAAAAD/////AAAAACIBAAAAAAAACDxjbGluaXQ+ABZMSW50ZXJmYWNlTWV0"
- "aG9kRmxhZ3M7ABJMamF2YS9sYW5nL09iamVjdDsAAVYAA2ZvbwAAAAAAAAABAAAAAAAAAAAAAAAB"
- "AAAADgAAAAEBAImABJACAYGICAAAAAALAAAAAAAAAAEAAAAAAAAAAQAAAAUAAABwAAAAAgAAAAMA"
- "AACEAAAAAwAAAAEAAACQAAAABQAAAAIAAACcAAAABgAAAAEAAACsAAAAAiAAAAUAAADMAAAAAxAA"
- "AAEAAAAMAQAAASAAAAEAAAAQAQAAACAAAAEAAAAiAQAAABAAAAEAAAA0AQAA";
-
-// To simplify generation of interesting "sub-states" of src_value, allow a "simple" mask to apply
-// to a src_value, such that mask bit 0 applies to the lowest set bit in src_value, and so on.
-static uint32_t ApplyMaskShifted(uint32_t src_value, uint32_t mask) {
- uint32_t result = 0;
- uint32_t mask_index = 0;
- while (src_value != 0) {
- uint32_t index = CTZ(src_value);
- if (((src_value & (1 << index)) != 0) &&
- ((mask & (1 << mask_index)) != 0)) {
- result |= (1 << index);
- }
- src_value &= ~(1 << index);
- mask_index++;
- }
- return result;
-}
-
-TEST_F(DexFileVerifierTest, MethodAccessFlagsInterfaces) {
- VerifyModification(
- kMethodFlagsInterface,
- "method_flags_interface_ok",
- [](DexFile* dex_file) {
- ApplyMaskToMethodFlags(dex_file, "foo", ~kAccDeclaredSynchronized);
- },
- nullptr);
- VerifyModification(
- kMethodFlagsInterface,
- "method_flags_interface_ok37",
- [](DexFile* dex_file) {
- MakeDexVersion37(dex_file);
- ApplyMaskToMethodFlags(dex_file, "foo", ~kAccDeclaredSynchronized);
- },
- nullptr);
-
- VerifyModification(
- kMethodFlagsInterface,
- "method_flags_interface_non_public",
- [](DexFile* dex_file) {
- ApplyMaskToMethodFlags(dex_file, "foo", ~kAccDeclaredSynchronized);
-
- ApplyMaskToMethodFlags(dex_file, "foo", ~kAccPublic);
- },
- nullptr); // Should be allowed in older dex versions for backwards compatibility.
- VerifyModification(
- kMethodFlagsInterface,
- "method_flags_interface_non_public",
- [](DexFile* dex_file) {
- MakeDexVersion37(dex_file);
- ApplyMaskToMethodFlags(dex_file, "foo", ~kAccDeclaredSynchronized);
-
- ApplyMaskToMethodFlags(dex_file, "foo", ~kAccPublic);
- },
- "Interface virtual method 1(LInterfaceMethodFlags;.foo) is not public");
-
- VerifyModification(
- kMethodFlagsInterface,
- "method_flags_interface_non_abstract",
- [](DexFile* dex_file) {
- ApplyMaskToMethodFlags(dex_file, "foo", ~kAccDeclaredSynchronized);
-
- ApplyMaskToMethodFlags(dex_file, "foo", ~kAccAbstract);
- },
- "Method 1(LInterfaceMethodFlags;.foo) has no code, but is not marked native or abstract");
-
- VerifyModification(
- kMethodFlagsInterface,
- "method_flags_interface_static",
- [](DexFile* dex_file) {
- ApplyMaskToMethodFlags(dex_file, "foo", ~kAccDeclaredSynchronized);
-
- OrMaskToMethodFlags(dex_file, "foo", kAccStatic);
- },
- "Direct/virtual method 1(LInterfaceMethodFlags;.foo) not in expected list 0");
- VerifyModification(
- kMethodFlagsInterface,
- "method_flags_interface_private",
- [](DexFile* dex_file) {
- ApplyMaskToMethodFlags(dex_file, "foo", ~kAccDeclaredSynchronized);
-
- ApplyMaskToMethodFlags(dex_file, "foo", ~kAccPublic);
- OrMaskToMethodFlags(dex_file, "foo", kAccPrivate);
- },
- "Direct/virtual method 1(LInterfaceMethodFlags;.foo) not in expected list 0");
-
- VerifyModification(
- kMethodFlagsInterface,
- "method_flags_interface_non_public",
- [](DexFile* dex_file) {
- ApplyMaskToMethodFlags(dex_file, "foo", ~kAccDeclaredSynchronized);
-
- ApplyMaskToMethodFlags(dex_file, "foo", ~kAccPublic);
- },
- nullptr); // Should be allowed in older dex versions for backwards compatibility.
- VerifyModification(
- kMethodFlagsInterface,
- "method_flags_interface_non_public",
- [](DexFile* dex_file) {
- MakeDexVersion37(dex_file);
- ApplyMaskToMethodFlags(dex_file, "foo", ~kAccDeclaredSynchronized);
-
- ApplyMaskToMethodFlags(dex_file, "foo", ~kAccPublic);
- },
- "Interface virtual method 1(LInterfaceMethodFlags;.foo) is not public");
-
- VerifyModification(
- kMethodFlagsInterface,
- "method_flags_interface_protected",
- [](DexFile* dex_file) {
- ApplyMaskToMethodFlags(dex_file, "foo", ~kAccDeclaredSynchronized);
-
- ApplyMaskToMethodFlags(dex_file, "foo", ~kAccPublic);
- OrMaskToMethodFlags(dex_file, "foo", kAccProtected);
- },
- nullptr); // Should be allowed in older dex versions for backwards compatibility.
- VerifyModification(
- kMethodFlagsInterface,
- "method_flags_interface_protected",
- [](DexFile* dex_file) {
- MakeDexVersion37(dex_file);
- ApplyMaskToMethodFlags(dex_file, "foo", ~kAccDeclaredSynchronized);
-
- ApplyMaskToMethodFlags(dex_file, "foo", ~kAccPublic);
- OrMaskToMethodFlags(dex_file, "foo", kAccProtected);
- },
- "Interface virtual method 1(LInterfaceMethodFlags;.foo) is not public");
-
- constexpr uint32_t kAllMethodFlags =
- kAccPublic |
- kAccPrivate |
- kAccProtected |
- kAccStatic |
- kAccFinal |
- kAccSynchronized |
- kAccBridge |
- kAccVarargs |
- kAccNative |
- kAccAbstract |
- kAccStrict |
- kAccSynthetic;
- constexpr uint32_t kInterfaceMethodFlags =
- kAccPublic | kAccAbstract | kAccVarargs | kAccBridge | kAccSynthetic;
- constexpr uint32_t kInterfaceDisallowed = kAllMethodFlags &
- ~kInterfaceMethodFlags &
- // Already tested, needed to be separate.
- ~kAccStatic &
- ~kAccPrivate &
- ~kAccProtected;
- static_assert(kInterfaceDisallowed != 0, "There should be disallowed flags.");
-
- uint32_t bits = POPCOUNT(kInterfaceDisallowed);
- for (uint32_t i = 1; i < (1u << bits); ++i) {
- VerifyModification(
- kMethodFlagsInterface,
- "method_flags_interface_non_abstract",
- [&](DexFile* dex_file) {
- ApplyMaskToMethodFlags(dex_file, "foo", ~kAccDeclaredSynchronized);
-
- uint32_t mask = ApplyMaskShifted(kInterfaceDisallowed, i);
- if ((mask & kAccProtected) != 0) {
- mask &= ~kAccProtected;
- ApplyMaskToMethodFlags(dex_file, "foo", ~kAccPublic);
- }
- OrMaskToMethodFlags(dex_file, "foo", mask);
- },
- "Abstract method 1(LInterfaceMethodFlags;.foo) has disallowed access flags");
- }
-}
-
-///////////////////////////////////////////////////////////////////
-
-// Field flags.
-
-// Find the method data for the first method with the given name (from class 0). Note: the pointer
-// is to the access flags, so that the caller doesn't have to handle the leb128-encoded method-index
-// delta.
-static const uint8_t* FindFieldData(const DexFile* dex_file, const char* name) {
- const DexFile::ClassDef& class_def = dex_file->GetClassDef(0);
- const uint8_t* class_data = dex_file->GetClassData(class_def);
-
- ClassDataItemIterator it(*dex_file, class_data);
-
- const uint8_t* trailing = class_data;
- // Need to manually decode the four entries. DataPointer() doesn't work for this, as the first
- // element has already been loaded into the iterator.
- DecodeUnsignedLeb128(&trailing);
- DecodeUnsignedLeb128(&trailing);
- DecodeUnsignedLeb128(&trailing);
- DecodeUnsignedLeb128(&trailing);
-
- while (it.HasNextStaticField() || it.HasNextInstanceField()) {
- uint32_t field_index = it.GetMemberIndex();
- dex::StringIndex name_index = dex_file->GetFieldId(field_index).name_idx_;
- const DexFile::StringId& string_id = dex_file->GetStringId(name_index);
- const char* str = dex_file->GetStringData(string_id);
- if (strcmp(name, str) == 0) {
- DecodeUnsignedLeb128(&trailing);
- return trailing;
- }
-
- trailing = it.DataPointer();
- it.Next();
- }
-
- return nullptr;
-}
-
-// Set the method flags to the given value.
-static void SetFieldFlags(DexFile* dex_file, const char* field, uint32_t mask) {
- uint8_t* field_flags_ptr = const_cast<uint8_t*>(FindFieldData(dex_file, field));
- CHECK(field_flags_ptr != nullptr) << field;
-
- // Unroll this, as we only have three bytes, anyways.
- uint8_t base1 = static_cast<uint8_t>(mask & 0x7F);
- *(field_flags_ptr++) = (base1 | 0x80);
- mask >>= 7;
-
- uint8_t base2 = static_cast<uint8_t>(mask & 0x7F);
- *(field_flags_ptr++) = (base2 | 0x80);
- mask >>= 7;
-
- uint8_t base3 = static_cast<uint8_t>(mask & 0x7F);
- *field_flags_ptr = base3;
-}
-
-static uint32_t GetFieldFlags(DexFile* dex_file, const char* field) {
- const uint8_t* field_flags_ptr = const_cast<uint8_t*>(FindFieldData(dex_file, field));
- CHECK(field_flags_ptr != nullptr) << field;
- return DecodeUnsignedLeb128(&field_flags_ptr);
-}
-
-// Apply the given mask to method flags.
-static void ApplyMaskToFieldFlags(DexFile* dex_file, const char* field, uint32_t mask) {
- uint32_t value = GetFieldFlags(dex_file, field);
- value &= mask;
- SetFieldFlags(dex_file, field, value);
-}
-
-// Apply the given mask to method flags.
-static void OrMaskToFieldFlags(DexFile* dex_file, const char* field, uint32_t mask) {
- uint32_t value = GetFieldFlags(dex_file, field);
- value |= mask;
- SetFieldFlags(dex_file, field, value);
-}
-
-// Standard class. Use declared-synchronized again for 3B encoding.
-//
-// .class public LFieldFlags;
-// .super Ljava/lang/Object;
-//
-// .field declared-synchronized public foo:I
-//
-// .field declared-synchronized public static bar:I
-
-static const char kFieldFlagsTestDex[] =
- "ZGV4CjAzNQBtLw7hydbfv4TdXidZyzAB70W7w3vnYJRwAQAAcAAAAHhWNBIAAAAAAAAAAAABAAAF"
- "AAAAcAAAAAMAAACEAAAAAAAAAAAAAAACAAAAkAAAAAAAAAAAAAAAAQAAAKAAAACwAAAAwAAAAMAA"
- "AADDAAAA0QAAAOUAAADqAAAAAAAAAAEAAAACAAAAAQAAAAMAAAABAAAABAAAAAEAAAABAAAAAgAA"
- "AAAAAAD/////AAAAAPQAAAAAAAAAAUkADExGaWVsZEZsYWdzOwASTGphdmEvbGFuZy9PYmplY3Q7"
- "AANiYXIAA2ZvbwAAAAAAAAEBAAAAiYAIAYGACAkAAAAAAAAAAQAAAAAAAAABAAAABQAAAHAAAAAC"
- "AAAAAwAAAIQAAAAEAAAAAgAAAJAAAAAGAAAAAQAAAKAAAAACIAAABQAAAMAAAAADEAAAAQAAAPAA"
- "AAAAIAAAAQAAAPQAAAAAEAAAAQAAAAABAAA=";
-
-TEST_F(DexFileVerifierTest, FieldAccessFlagsBase) {
- // Check that it's OK when the wrong declared-synchronized flag is removed from "foo."
- VerifyModification(
- kFieldFlagsTestDex,
- "field_flags_ok",
- [](DexFile* dex_file) {
- ApplyMaskToFieldFlags(dex_file, "foo", ~kAccDeclaredSynchronized);
- ApplyMaskToFieldFlags(dex_file, "bar", ~kAccDeclaredSynchronized);
- },
- nullptr);
-}
-
-TEST_F(DexFileVerifierTest, FieldAccessFlagsWrongList) {
- // Mark the field so that it should appear in the opposite list (instance vs static).
- VerifyModification(
- kFieldFlagsTestDex,
- "field_flags_wrong_list",
- [](DexFile* dex_file) {
- ApplyMaskToFieldFlags(dex_file, "foo", ~kAccDeclaredSynchronized);
- ApplyMaskToFieldFlags(dex_file, "bar", ~kAccDeclaredSynchronized);
-
- OrMaskToFieldFlags(dex_file, "foo", kAccStatic);
- },
- "Static/instance field not in expected list");
- VerifyModification(
- kFieldFlagsTestDex,
- "field_flags_wrong_list",
- [](DexFile* dex_file) {
- ApplyMaskToFieldFlags(dex_file, "foo", ~kAccDeclaredSynchronized);
- ApplyMaskToFieldFlags(dex_file, "bar", ~kAccDeclaredSynchronized);
-
- ApplyMaskToFieldFlags(dex_file, "bar", ~kAccStatic);
- },
- "Static/instance field not in expected list");
-}
-
-TEST_F(DexFileVerifierTest, FieldAccessFlagsPPP) {
- static const char* kFields[] = { "foo", "bar" };
- for (size_t i = 0; i < arraysize(kFields); ++i) {
- // Should be OK to remove public.
- VerifyModification(
- kFieldFlagsTestDex,
- "field_flags_non_public",
- [&](DexFile* dex_file) {
- ApplyMaskToFieldFlags(dex_file, "foo", ~kAccDeclaredSynchronized);
- ApplyMaskToFieldFlags(dex_file, "bar", ~kAccDeclaredSynchronized);
-
- ApplyMaskToFieldFlags(dex_file, kFields[i], ~kAccPublic);
- },
- nullptr);
- constexpr uint32_t kAccFlags = kAccPublic | kAccPrivate | kAccProtected;
- uint32_t bits = POPCOUNT(kAccFlags);
- for (uint32_t j = 1; j < (1u << bits); ++j) {
- if (POPCOUNT(j) < 2) {
- continue;
- }
- VerifyModification(
- kFieldFlagsTestDex,
- "field_flags_ppp",
- [&](DexFile* dex_file) {
- ApplyMaskToFieldFlags(dex_file, "foo", ~kAccDeclaredSynchronized);
- ApplyMaskToFieldFlags(dex_file, "bar", ~kAccDeclaredSynchronized);
-
- ApplyMaskToFieldFlags(dex_file, kFields[i], ~kAccPublic);
- uint32_t mask = ApplyMaskShifted(kAccFlags, j);
- OrMaskToFieldFlags(dex_file, kFields[i], mask);
- },
- "Field may have only one of public/protected/private");
- }
- }
-}
-
-TEST_F(DexFileVerifierTest, FieldAccessFlagsIgnoredOK) {
- constexpr const char* kFields[] = { "foo", "bar"};
- for (size_t i = 0; i < arraysize(kFields); ++i) {
- // All interesting method flags, other flags are to be ignored.
- constexpr uint32_t kAllFieldFlags =
- kAccPublic |
- kAccPrivate |
- kAccProtected |
- kAccStatic |
- kAccFinal |
- kAccVolatile |
- kAccTransient |
- kAccSynthetic |
- kAccEnum;
- constexpr uint32_t kIgnoredMask = ~kAllFieldFlags & 0xFFFF;
- VerifyModification(
- kFieldFlagsTestDex,
- "field_flags_ignored",
- [&](DexFile* dex_file) {
- ApplyMaskToFieldFlags(dex_file, "foo", ~kAccDeclaredSynchronized);
- ApplyMaskToFieldFlags(dex_file, "bar", ~kAccDeclaredSynchronized);
-
- OrMaskToFieldFlags(dex_file, kFields[i], kIgnoredMask);
- },
- nullptr);
- }
-}
-
-TEST_F(DexFileVerifierTest, FieldAccessFlagsVolatileFinal) {
- constexpr const char* kFields[] = { "foo", "bar"};
- for (size_t i = 0; i < arraysize(kFields); ++i) {
- VerifyModification(
- kFieldFlagsTestDex,
- "field_flags_final_and_volatile",
- [&](DexFile* dex_file) {
- ApplyMaskToFieldFlags(dex_file, "foo", ~kAccDeclaredSynchronized);
- ApplyMaskToFieldFlags(dex_file, "bar", ~kAccDeclaredSynchronized);
-
- OrMaskToFieldFlags(dex_file, kFields[i], kAccVolatile | kAccFinal);
- },
- "Fields may not be volatile and final");
- }
-}
-
-// Standard interface. Needs to be separate from class as interfaces do not allow instance fields.
-// Use declared-synchronized again for 3B encoding.
-//
-// .class public interface LInterfaceFieldFlags;
-// .super Ljava/lang/Object;
-//
-// .field declared-synchronized public static final foo:I
-
-static const char kFieldFlagsInterfaceTestDex[] =
- "ZGV4CjAzNQCVMHfEimR1zZPk6hl6O9GPAYqkl3u0umFkAQAAcAAAAHhWNBIAAAAAAAAAAPQAAAAE"
- "AAAAcAAAAAMAAACAAAAAAAAAAAAAAAABAAAAjAAAAAAAAAAAAAAAAQAAAJQAAACwAAAAtAAAALQA"
- "AAC3AAAAzgAAAOIAAAAAAAAAAQAAAAIAAAABAAAAAwAAAAEAAAABAgAAAgAAAAAAAAD/////AAAA"
- "AOwAAAAAAAAAAUkAFUxJbnRlcmZhY2VGaWVsZEZsYWdzOwASTGphdmEvbGFuZy9PYmplY3Q7AANm"
- "b28AAAAAAAABAAAAAJmACAkAAAAAAAAAAQAAAAAAAAABAAAABAAAAHAAAAACAAAAAwAAAIAAAAAE"
- "AAAAAQAAAIwAAAAGAAAAAQAAAJQAAAACIAAABAAAALQAAAADEAAAAQAAAOgAAAAAIAAAAQAAAOwA"
- "AAAAEAAAAQAAAPQAAAA=";
-
-TEST_F(DexFileVerifierTest, FieldAccessFlagsInterface) {
- VerifyModification(
- kFieldFlagsInterfaceTestDex,
- "field_flags_interface",
- [](DexFile* dex_file) {
- ApplyMaskToFieldFlags(dex_file, "foo", ~kAccDeclaredSynchronized);
- },
- nullptr);
- VerifyModification(
- kFieldFlagsInterfaceTestDex,
- "field_flags_interface",
- [](DexFile* dex_file) {
- MakeDexVersion37(dex_file);
- ApplyMaskToFieldFlags(dex_file, "foo", ~kAccDeclaredSynchronized);
- },
- nullptr);
-
- VerifyModification(
- kFieldFlagsInterfaceTestDex,
- "field_flags_interface_non_public",
- [](DexFile* dex_file) {
- ApplyMaskToFieldFlags(dex_file, "foo", ~kAccDeclaredSynchronized);
-
- ApplyMaskToFieldFlags(dex_file, "foo", ~kAccPublic);
- },
- nullptr); // Should be allowed in older dex versions for backwards compatibility.
- VerifyModification(
- kFieldFlagsInterfaceTestDex,
- "field_flags_interface_non_public",
- [](DexFile* dex_file) {
- MakeDexVersion37(dex_file);
- ApplyMaskToFieldFlags(dex_file, "foo", ~kAccDeclaredSynchronized);
-
- ApplyMaskToFieldFlags(dex_file, "foo", ~kAccPublic);
- },
- "Interface field is not public final static");
-
- VerifyModification(
- kFieldFlagsInterfaceTestDex,
- "field_flags_interface_non_final",
- [](DexFile* dex_file) {
- ApplyMaskToFieldFlags(dex_file, "foo", ~kAccDeclaredSynchronized);
-
- ApplyMaskToFieldFlags(dex_file, "foo", ~kAccFinal);
- },
- nullptr); // Should be allowed in older dex versions for backwards compatibility.
- VerifyModification(
- kFieldFlagsInterfaceTestDex,
- "field_flags_interface_non_final",
- [](DexFile* dex_file) {
- MakeDexVersion37(dex_file);
- ApplyMaskToFieldFlags(dex_file, "foo", ~kAccDeclaredSynchronized);
-
- ApplyMaskToFieldFlags(dex_file, "foo", ~kAccFinal);
- },
- "Interface field is not public final static");
-
- VerifyModification(
- kFieldFlagsInterfaceTestDex,
- "field_flags_interface_protected",
- [](DexFile* dex_file) {
- ApplyMaskToFieldFlags(dex_file, "foo", ~kAccDeclaredSynchronized);
-
- ApplyMaskToFieldFlags(dex_file, "foo", ~kAccPublic);
- OrMaskToFieldFlags(dex_file, "foo", kAccProtected);
- },
- nullptr); // Should be allowed in older dex versions for backwards compatibility.
- VerifyModification(
- kFieldFlagsInterfaceTestDex,
- "field_flags_interface_protected",
- [](DexFile* dex_file) {
- MakeDexVersion37(dex_file);
- ApplyMaskToFieldFlags(dex_file, "foo", ~kAccDeclaredSynchronized);
-
- ApplyMaskToFieldFlags(dex_file, "foo", ~kAccPublic);
- OrMaskToFieldFlags(dex_file, "foo", kAccProtected);
- },
- "Interface field is not public final static");
-
- VerifyModification(
- kFieldFlagsInterfaceTestDex,
- "field_flags_interface_private",
- [](DexFile* dex_file) {
- ApplyMaskToFieldFlags(dex_file, "foo", ~kAccDeclaredSynchronized);
-
- ApplyMaskToFieldFlags(dex_file, "foo", ~kAccPublic);
- OrMaskToFieldFlags(dex_file, "foo", kAccPrivate);
- },
- nullptr); // Should be allowed in older dex versions for backwards compatibility.
- VerifyModification(
- kFieldFlagsInterfaceTestDex,
- "field_flags_interface_private",
- [](DexFile* dex_file) {
- MakeDexVersion37(dex_file);
- ApplyMaskToFieldFlags(dex_file, "foo", ~kAccDeclaredSynchronized);
-
- ApplyMaskToFieldFlags(dex_file, "foo", ~kAccPublic);
- OrMaskToFieldFlags(dex_file, "foo", kAccPrivate);
- },
- "Interface field is not public final static");
-
- VerifyModification(
- kFieldFlagsInterfaceTestDex,
- "field_flags_interface_synthetic",
- [](DexFile* dex_file) {
- ApplyMaskToFieldFlags(dex_file, "foo", ~kAccDeclaredSynchronized);
-
- OrMaskToFieldFlags(dex_file, "foo", kAccSynthetic);
- },
- nullptr);
-
- constexpr uint32_t kAllFieldFlags =
- kAccPublic |
- kAccPrivate |
- kAccProtected |
- kAccStatic |
- kAccFinal |
- kAccVolatile |
- kAccTransient |
- kAccSynthetic |
- kAccEnum;
- constexpr uint32_t kInterfaceFieldFlags = kAccPublic | kAccStatic | kAccFinal | kAccSynthetic;
- constexpr uint32_t kInterfaceDisallowed = kAllFieldFlags &
- ~kInterfaceFieldFlags &
- ~kAccProtected &
- ~kAccPrivate;
- static_assert(kInterfaceDisallowed != 0, "There should be disallowed flags.");
-
- uint32_t bits = POPCOUNT(kInterfaceDisallowed);
- for (uint32_t i = 1; i < (1u << bits); ++i) {
- VerifyModification(
- kFieldFlagsInterfaceTestDex,
- "field_flags_interface_disallowed",
- [&](DexFile* dex_file) {
- ApplyMaskToFieldFlags(dex_file, "foo", ~kAccDeclaredSynchronized);
-
- uint32_t mask = ApplyMaskShifted(kInterfaceDisallowed, i);
- if ((mask & kAccProtected) != 0) {
- mask &= ~kAccProtected;
- ApplyMaskToFieldFlags(dex_file, "foo", ~kAccPublic);
- }
- OrMaskToFieldFlags(dex_file, "foo", mask);
- },
- nullptr); // Should be allowed in older dex versions for backwards compatibility.
- VerifyModification(
- kFieldFlagsInterfaceTestDex,
- "field_flags_interface_disallowed",
- [&](DexFile* dex_file) {
- MakeDexVersion37(dex_file);
- ApplyMaskToFieldFlags(dex_file, "foo", ~kAccDeclaredSynchronized);
-
- uint32_t mask = ApplyMaskShifted(kInterfaceDisallowed, i);
- if ((mask & kAccProtected) != 0) {
- mask &= ~kAccProtected;
- ApplyMaskToFieldFlags(dex_file, "foo", ~kAccPublic);
- }
- OrMaskToFieldFlags(dex_file, "foo", mask);
- },
- "Interface field has disallowed flag");
- }
-}
-
-// Standard bad interface. Needs to be separate from class as interfaces do not allow instance
-// fields. Use declared-synchronized again for 3B encoding.
-//
-// .class public interface LInterfaceFieldFlags;
-// .super Ljava/lang/Object;
-//
-// .field declared-synchronized public final foo:I
-
-static const char kFieldFlagsInterfaceBadTestDex[] =
- "ZGV4CjAzNQByMUnqYKHBkUpvvNp+9CnZ2VyDkKnRN6VkAQAAcAAAAHhWNBIAAAAAAAAAAPQAAAAE"
- "AAAAcAAAAAMAAACAAAAAAAAAAAAAAAABAAAAjAAAAAAAAAAAAAAAAQAAAJQAAACwAAAAtAAAALQA"
- "AAC3AAAAzgAAAOIAAAAAAAAAAQAAAAIAAAABAAAAAwAAAAEAAAABAgAAAgAAAAAAAAD/////AAAA"
- "AOwAAAAAAAAAAUkAFUxJbnRlcmZhY2VGaWVsZEZsYWdzOwASTGphdmEvbGFuZy9PYmplY3Q7AANm"
- "b28AAAAAAAAAAQAAAJGACAkAAAAAAAAAAQAAAAAAAAABAAAABAAAAHAAAAACAAAAAwAAAIAAAAAE"
- "AAAAAQAAAIwAAAAGAAAAAQAAAJQAAAACIAAABAAAALQAAAADEAAAAQAAAOgAAAAAIAAAAQAAAOwA"
- "AAAAEAAAAQAAAPQAAAA=";
-
-TEST_F(DexFileVerifierTest, FieldAccessFlagsInterfaceNonStatic) {
- VerifyModification(
- kFieldFlagsInterfaceBadTestDex,
- "field_flags_interface_non_static",
- [](DexFile* dex_file) {
- ApplyMaskToFieldFlags(dex_file, "foo", ~kAccDeclaredSynchronized);
- },
- nullptr); // Should be allowed in older dex versions for backwards compatibility.
- VerifyModification(
- kFieldFlagsInterfaceBadTestDex,
- "field_flags_interface_non_static",
- [](DexFile* dex_file) {
- MakeDexVersion37(dex_file);
- ApplyMaskToFieldFlags(dex_file, "foo", ~kAccDeclaredSynchronized);
- },
- "Interface field is not public final static");
-}
-
-// Generated from:
-//
-// .class public LTest;
-// .super Ljava/lang/Object;
-// .source "Test.java"
-//
-// .method public constructor <init>()V
-// .registers 1
-//
-// .prologue
-// .line 1
-// invoke-direct {p0}, Ljava/lang/Object;-><init>()V
-//
-// return-void
-// .end method
-//
-// .method public static main()V
-// .registers 2
-//
-// const-string v0, "a"
-// const-string v0, "b"
-// const-string v0, "c"
-// const-string v0, "d"
-// const-string v0, "e"
-// const-string v0, "f"
-// const-string v0, "g"
-// const-string v0, "h"
-// const-string v0, "i"
-// const-string v0, "j"
-// const-string v0, "k"
-//
-// .local v1, "local_var":Ljava/lang/String;
-// const-string v1, "test"
-// .end method
-
-static const char kDebugInfoTestDex[] =
- "ZGV4CjAzNQCHRkHix2eIMQgvLD/0VGrlllZLo0Rb6VyUAgAAcAAAAHhWNBIAAAAAAAAAAAwCAAAU"
- "AAAAcAAAAAQAAADAAAAAAQAAANAAAAAAAAAAAAAAAAMAAADcAAAAAQAAAPQAAACAAQAAFAEAABQB"
- "AAAcAQAAJAEAADgBAABMAQAAVwEAAFoBAABdAQAAYAEAAGMBAABmAQAAaQEAAGwBAABvAQAAcgEA"
- "AHUBAAB4AQAAewEAAIYBAACMAQAAAQAAAAIAAAADAAAABQAAAAUAAAADAAAAAAAAAAAAAAAAAAAA"
- "AAAAABIAAAABAAAAAAAAAAAAAAABAAAAAQAAAAAAAAAEAAAAAAAAAPwBAAAAAAAABjxpbml0PgAG"
- "TFRlc3Q7ABJMamF2YS9sYW5nL09iamVjdDsAEkxqYXZhL2xhbmcvU3RyaW5nOwAJVGVzdC5qYXZh"
- "AAFWAAFhAAFiAAFjAAFkAAFlAAFmAAFnAAFoAAFpAAFqAAFrAAlsb2NhbF92YXIABG1haW4ABHRl"
- "c3QAAAABAAcOAAAAARYDARIDAAAAAQABAAEAAACUAQAABAAAAHAQAgAAAA4AAgAAAAAAAACZAQAA"
- "GAAAABoABgAaAAcAGgAIABoACQAaAAoAGgALABoADAAaAA0AGgAOABoADwAaABAAGgETAAAAAgAA"
- "gYAEpAMBCbwDAAALAAAAAAAAAAEAAAAAAAAAAQAAABQAAABwAAAAAgAAAAQAAADAAAAAAwAAAAEA"
- "AADQAAAABQAAAAMAAADcAAAABgAAAAEAAAD0AAAAAiAAABQAAAAUAQAAAyAAAAIAAACUAQAAASAA"
- "AAIAAACkAQAAACAAAAEAAAD8AQAAABAAAAEAAAAMAgAA";
-
-TEST_F(DexFileVerifierTest, DebugInfoTypeIdxTest) {
- {
- // The input dex file should be good before modification.
- std::string error_msg;
- std::unique_ptr<const DexFile> raw(OpenDexFileBase64(kDebugInfoTestDex,
- kLocationString,
- &error_msg));
- ASSERT_TRUE(raw.get() != nullptr) << error_msg;
- }
-
- // Modify the debug information entry.
- VerifyModification(
- kDebugInfoTestDex,
- "debug_start_type_idx",
- [](DexFile* dex_file) {
- *(const_cast<uint8_t*>(dex_file->Begin()) + 416) = 0x14U;
- },
- "DBG_START_LOCAL type_idx");
-}
-
-TEST_F(DexFileVerifierTest, SectionAlignment) {
- {
- // The input dex file should be good before modification. Any file is fine, as long as it
- // uses all sections.
- std::string error_msg;
- std::unique_ptr<const DexFile> raw(OpenDexFileBase64(kGoodTestDex,
- kLocationString,
- &error_msg));
- ASSERT_TRUE(raw.get() != nullptr) << error_msg;
- }
-
- // Modify all section offsets to be unaligned.
- constexpr size_t kSections = 7;
- for (size_t i = 0; i < kSections; ++i) {
- VerifyModification(
- kGoodTestDex,
- "section_align",
- [&](DexFile* dex_file) {
- DexFile::Header* header = const_cast<DexFile::Header*>(
- reinterpret_cast<const DexFile::Header*>(dex_file->Begin()));
- uint32_t* off_ptr;
- switch (i) {
- case 0:
- off_ptr = &header->map_off_;
- break;
- case 1:
- off_ptr = &header->string_ids_off_;
- break;
- case 2:
- off_ptr = &header->type_ids_off_;
- break;
- case 3:
- off_ptr = &header->proto_ids_off_;
- break;
- case 4:
- off_ptr = &header->field_ids_off_;
- break;
- case 5:
- off_ptr = &header->method_ids_off_;
- break;
- case 6:
- off_ptr = &header->class_defs_off_;
- break;
-
- static_assert(kSections == 7, "kSections is wrong");
- default:
- LOG(FATAL) << "Unexpected section";
- UNREACHABLE();
- }
- ASSERT_TRUE(off_ptr != nullptr);
- ASSERT_NE(*off_ptr, 0U) << i; // Should already contain a value (in use).
- (*off_ptr)++; // Add one, which should misalign it (all the sections
- // above are aligned by 4).
- },
- "should be aligned by 4 for");
- }
-}
-
-// Generated from
-//
-// .class LOverloading;
-//
-// .super Ljava/lang/Object;
-//
-// .method public static foo()V
-// .registers 1
-// return-void
-// .end method
-//
-// .method public static foo(I)V
-// .registers 1
-// return-void
-// .end method
-static const char kProtoOrderingTestDex[] =
- "ZGV4CjAzNQA1L+ABE6voQ9Lr4Ci//efB53oGnDr5PinsAQAAcAAAAHhWNBIAAAAAAAAAAFgBAAAG"
- "AAAAcAAAAAQAAACIAAAAAgAAAJgAAAAAAAAAAAAAAAIAAACwAAAAAQAAAMAAAAAMAQAA4AAAAOAA"
- "AADjAAAA8gAAAAYBAAAJAQAADQEAAAAAAAABAAAAAgAAAAMAAAADAAAAAwAAAAAAAAAEAAAAAwAA"
- "ABQBAAABAAAABQAAAAEAAQAFAAAAAQAAAAAAAAACAAAAAAAAAP////8AAAAASgEAAAAAAAABSQAN"
- "TE92ZXJsb2FkaW5nOwASTGphdmEvbGFuZy9PYmplY3Q7AAFWAAJWSQADZm9vAAAAAQAAAAAAAAAA"
- "AAAAAAAAAAEAAAAAAAAAAAAAAAEAAAAOAAAAAQABAAAAAAAAAAAAAQAAAA4AAAACAAAJpAIBCbgC"
- "AAAMAAAAAAAAAAEAAAAAAAAAAQAAAAYAAABwAAAAAgAAAAQAAACIAAAAAwAAAAIAAACYAAAABQAA"
- "AAIAAACwAAAABgAAAAEAAADAAAAAAiAAAAYAAADgAAAAARAAAAEAAAAUAQAAAxAAAAIAAAAcAQAA"
- "ASAAAAIAAAAkAQAAACAAAAEAAABKAQAAABAAAAEAAABYAQAA";
-
-TEST_F(DexFileVerifierTest, ProtoOrdering) {
- {
- // The input dex file should be good before modification.
- std::string error_msg;
- std::unique_ptr<const DexFile> raw(OpenDexFileBase64(kProtoOrderingTestDex,
- kLocationString,
- &error_msg));
- ASSERT_TRUE(raw.get() != nullptr) << error_msg;
- }
-
- // Modify the order of the ProtoIds for two overloads of "foo" with the
- // same return type and one having longer parameter list than the other.
- for (size_t i = 0; i != 2; ++i) {
- VerifyModification(
- kProtoOrderingTestDex,
- "proto_ordering",
- [i](DexFile* dex_file) {
- uint32_t method_idx;
- const uint8_t* data = FindMethodData(dex_file, "foo", &method_idx);
- CHECK(data != nullptr);
- // There should be 2 methods called "foo".
- CHECK_LT(method_idx + 1u, dex_file->NumMethodIds());
- CHECK_EQ(dex_file->GetMethodId(method_idx).name_idx_,
- dex_file->GetMethodId(method_idx + 1).name_idx_);
- CHECK_EQ(dex_file->GetMethodId(method_idx).proto_idx_ + 1u,
- dex_file->GetMethodId(method_idx + 1).proto_idx_);
- // Their return types should be the same.
- uint32_t proto1_idx = dex_file->GetMethodId(method_idx).proto_idx_;
- const DexFile::ProtoId& proto1 = dex_file->GetProtoId(proto1_idx);
- const DexFile::ProtoId& proto2 = dex_file->GetProtoId(proto1_idx + 1u);
- CHECK_EQ(proto1.return_type_idx_, proto2.return_type_idx_);
- // And the first should not have any parameters while the second should have some.
- CHECK(!DexFileParameterIterator(*dex_file, proto1).HasNext());
- CHECK(DexFileParameterIterator(*dex_file, proto2).HasNext());
- if (i == 0) {
- // Swap the proto parameters and shorties to break the ordering.
- std::swap(const_cast<uint32_t&>(proto1.parameters_off_),
- const_cast<uint32_t&>(proto2.parameters_off_));
- std::swap(const_cast<dex::StringIndex&>(proto1.shorty_idx_),
- const_cast<dex::StringIndex&>(proto2.shorty_idx_));
- } else {
- // Copy the proto parameters and shorty to create duplicate proto id.
- const_cast<uint32_t&>(proto1.parameters_off_) = proto2.parameters_off_;
- const_cast<dex::StringIndex&>(proto1.shorty_idx_) = proto2.shorty_idx_;
- }
- },
- "Out-of-order proto_id arguments");
- }
-}
-
-// To generate a base64 encoded Dex file version 037 from Smali files, use:
-//
-// smali assemble --api 24 -o classes.dex class1.smali [class2.smali ...]
-// base64 classes.dex >classes.dex.base64
-
-// Dex file version 037 generated from:
-//
-// .class public LB28685551;
-// .super LB28685551;
-
-static const char kClassExtendsItselfTestDex[] =
- "ZGV4CjAzNwDeGbgRg1kb6swszpcTWrrOAALB++F4OPT0AAAAcAAAAHhWNBIAAAAAAAAAAKgAAAAB"
- "AAAAcAAAAAEAAAB0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAHgAAABcAAAAmAAAAJgA"
- "AAAAAAAAAAAAAAEAAAAAAAAAAAAAAP////8AAAAAAAAAAAAAAAALTEIyODY4NTU1MTsAAAAABgAA"
- "AAAAAAABAAAAAAAAAAEAAAABAAAAcAAAAAIAAAABAAAAdAAAAAYAAAABAAAAeAAAAAIgAAABAAAA"
- "mAAAAAAQAAABAAAAqAAAAA==";
-
-TEST_F(DexFileVerifierTest, ClassExtendsItself) {
- VerifyModification(
- kClassExtendsItselfTestDex,
- "class_extends_itself",
- [](DexFile* dex_file ATTRIBUTE_UNUSED) { /* empty */ },
- "Class with same type idx as its superclass: '0'");
-}
-
-// Dex file version 037 generated from:
-//
-// .class public LFoo;
-// .super LBar;
-//
-// and:
-//
-// .class public LBar;
-// .super LFoo;
-
-static const char kClassesExtendOneAnotherTestDex[] =
- "ZGV4CjAzNwBXHSrwpDMwRBkg+L+JeQCuFNRLhQ86duEcAQAAcAAAAHhWNBIAAAAAAAAAANAAAAAC"
- "AAAAcAAAAAIAAAB4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAIAAAABcAAAAwAAAAMAA"
- "AADHAAAAAAAAAAEAAAABAAAAAQAAAAAAAAAAAAAA/////wAAAAAAAAAAAAAAAAAAAAABAAAAAQAA"
- "AAAAAAD/////AAAAAAAAAAAAAAAABUxCYXI7AAVMRm9vOwAAAAYAAAAAAAAAAQAAAAAAAAABAAAA"
- "AgAAAHAAAAACAAAAAgAAAHgAAAAGAAAAAgAAAIAAAAACIAAAAgAAAMAAAAAAEAAAAQAAANAAAAA=";
-
-TEST_F(DexFileVerifierTest, ClassesExtendOneAnother) {
- VerifyModification(
- kClassesExtendOneAnotherTestDex,
- "classes_extend_one_another",
- [](DexFile* dex_file ATTRIBUTE_UNUSED) { /* empty */ },
- "Invalid class definition ordering: class with type idx: '1' defined before"
- " superclass with type idx: '0'");
-}
-
-// Dex file version 037 generated from:
-//
-// .class public LAll;
-// .super LYour;
-//
-// and:
-//
-// .class public LYour;
-// .super LBase;
-//
-// and:
-//
-// .class public LBase;
-// .super LAll;
-
-static const char kCircularClassInheritanceTestDex[] =
- "ZGV4CjAzNwBMJxgP0SJz6oLXnKfl+J7lSEORLRwF5LNMAQAAcAAAAHhWNBIAAAAAAAAAAAABAAAD"
- "AAAAcAAAAAMAAAB8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAAIgAAABkAAAA6AAAAOgA"
- "AADvAAAA9wAAAAAAAAABAAAAAgAAAAEAAAABAAAAAAAAAAAAAAD/////AAAAAAAAAAAAAAAAAgAA"
- "AAEAAAABAAAAAAAAAP////8AAAAAAAAAAAAAAAAAAAAAAQAAAAIAAAAAAAAA/////wAAAAAAAAAA"
- "AAAAAAVMQWxsOwAGTEJhc2U7AAZMWW91cjsAAAYAAAAAAAAAAQAAAAAAAAABAAAAAwAAAHAAAAAC"
- "AAAAAwAAAHwAAAAGAAAAAwAAAIgAAAACIAAAAwAAAOgAAAAAEAAAAQAAAAABAAA=";
-
-TEST_F(DexFileVerifierTest, CircularClassInheritance) {
- VerifyModification(
- kCircularClassInheritanceTestDex,
- "circular_class_inheritance",
- [](DexFile* dex_file ATTRIBUTE_UNUSED) { /* empty */ },
- "Invalid class definition ordering: class with type idx: '1' defined before"
- " superclass with type idx: '0'");
-}
-
-// Dex file version 037 generated from:
-//
-// .class public abstract interface LInterfaceImplementsItself;
-// .super Ljava/lang/Object;
-// .implements LInterfaceImplementsItself;
-
-static const char kInterfaceImplementsItselfTestDex[] =
- "ZGV4CjAzNwCKKrjatp8XbXl5S/bEVJnqaBhjZkQY4440AQAAcAAAAHhWNBIAAAAAAAAAANwAAAAC"
- "AAAAcAAAAAIAAAB4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAIAAAACUAAAAoAAAAKAA"
- "AAC9AAAAAAAAAAEAAAAAAAAAAQYAAAEAAADUAAAA/////wAAAAAAAAAAAAAAABtMSW50ZXJmYWNl"
- "SW1wbGVtZW50c0l0c2VsZjsAEkxqYXZhL2xhbmcvT2JqZWN0OwAAAAABAAAAAAAAAAcAAAAAAAAA"
- "AQAAAAAAAAABAAAAAgAAAHAAAAACAAAAAgAAAHgAAAAGAAAAAQAAAIAAAAACIAAAAgAAAKAAAAAB"
- "EAAAAQAAANQAAAAAEAAAAQAAANwAAAA=";
-
-TEST_F(DexFileVerifierTest, InterfaceImplementsItself) {
- VerifyModification(
- kInterfaceImplementsItselfTestDex,
- "interface_implements_itself",
- [](DexFile* dex_file ATTRIBUTE_UNUSED) { /* empty */ },
- "Class with same type idx as implemented interface: '0'");
-}
-
-// Dex file version 037 generated from:
-//
-// .class public abstract interface LPing;
-// .super Ljava/lang/Object;
-// .implements LPong;
-//
-// and:
-//
-// .class public abstract interface LPong;
-// .super Ljava/lang/Object;
-// .implements LPing;
-
-static const char kInterfacesImplementOneAnotherTestDex[] =
- "ZGV4CjAzNwD0Kk9sxlYdg3Dy1Cff0gQCuJAQfEP6ohZUAQAAcAAAAHhWNBIAAAAAAAAAAPwAAAAD"
- "AAAAcAAAAAMAAAB8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAIgAAACMAAAAyAAAAMgA"
- "AADQAAAA2AAAAAAAAAABAAAAAgAAAAEAAAABBgAAAgAAAOwAAAD/////AAAAAAAAAAAAAAAAAAAA"
- "AAEGAAACAAAA9AAAAP////8AAAAAAAAAAAAAAAAGTFBpbmc7AAZMUG9uZzsAEkxqYXZhL2xhbmcv"
- "T2JqZWN0OwABAAAAAAAAAAEAAAABAAAABwAAAAAAAAABAAAAAAAAAAEAAAADAAAAcAAAAAIAAAAD"
- "AAAAfAAAAAYAAAACAAAAiAAAAAIgAAADAAAAyAAAAAEQAAACAAAA7AAAAAAQAAABAAAA/AAAAA==";
-
-TEST_F(DexFileVerifierTest, InterfacesImplementOneAnother) {
- VerifyModification(
- kInterfacesImplementOneAnotherTestDex,
- "interfaces_implement_one_another",
- [](DexFile* dex_file ATTRIBUTE_UNUSED) { /* empty */ },
- "Invalid class definition ordering: class with type idx: '1' defined before"
- " implemented interface with type idx: '0'");
-}
-
-// Dex file version 037 generated from:
-//
-// .class public abstract interface LA;
-// .super Ljava/lang/Object;
-// .implements LB;
-//
-// and:
-//
-// .class public abstract interface LB;
-// .super Ljava/lang/Object;
-// .implements LC;
-//
-// and:
-//
-// .class public abstract interface LC;
-// .super Ljava/lang/Object;
-// .implements LA;
-
-static const char kCircularInterfaceImplementationTestDex[] =
- "ZGV4CjAzNwCzKmD5Fol6XAU6ichYHcUTIP7Z7MdTcEmEAQAAcAAAAHhWNBIAAAAAAAAAACwBAAAE"
- "AAAAcAAAAAQAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAAJAAAACUAAAA8AAAAPAA"
- "AAD1AAAA+gAAAP8AAAAAAAAAAQAAAAIAAAADAAAAAgAAAAEGAAADAAAAHAEAAP////8AAAAAAAAA"
- "AAAAAAABAAAAAQYAAAMAAAAUAQAA/////wAAAAAAAAAAAAAAAAAAAAABBgAAAwAAACQBAAD/////"
- "AAAAAAAAAAAAAAAAA0xBOwADTEI7AANMQzsAEkxqYXZhL2xhbmcvT2JqZWN0OwAAAQAAAAIAAAAB"
- "AAAAAAAAAAEAAAABAAAABwAAAAAAAAABAAAAAAAAAAEAAAAEAAAAcAAAAAIAAAAEAAAAgAAAAAYA"
- "AAADAAAAkAAAAAIgAAAEAAAA8AAAAAEQAAADAAAAFAEAAAAQAAABAAAALAEAAA==";
-
-TEST_F(DexFileVerifierTest, CircularInterfaceImplementation) {
- VerifyModification(
- kCircularInterfaceImplementationTestDex,
- "circular_interface_implementation",
- [](DexFile* dex_file ATTRIBUTE_UNUSED) { /* empty */ },
- "Invalid class definition ordering: class with type idx: '2' defined before"
- " implemented interface with type idx: '0'");
-}
-
-TEST_F(DexFileVerifierTest, Checksum) {
- size_t length;
- std::unique_ptr<uint8_t[]> dex_bytes(DecodeBase64(kGoodTestDex, &length));
- CHECK(dex_bytes != nullptr);
- // Note: `dex_file` will be destroyed before `dex_bytes`.
- std::unique_ptr<DexFile> dex_file(GetDexFile(dex_bytes.get(), length));
- std::string error_msg;
-
- // Good checksum: all pass.
- EXPECT_TRUE(DexFileVerifier::Verify(dex_file.get(),
- dex_file->Begin(),
- dex_file->Size(),
- "good checksum, no verify",
- /*verify_checksum*/ false,
- &error_msg));
- EXPECT_TRUE(DexFileVerifier::Verify(dex_file.get(),
- dex_file->Begin(),
- dex_file->Size(),
- "good checksum, verify",
- /*verify_checksum*/ true,
- &error_msg));
-
- // Bad checksum: !verify_checksum passes verify_checksum fails.
- DexFile::Header* header = reinterpret_cast<DexFile::Header*>(
- const_cast<uint8_t*>(dex_file->Begin()));
- header->checksum_ = 0;
- EXPECT_TRUE(DexFileVerifier::Verify(dex_file.get(),
- dex_file->Begin(),
- dex_file->Size(),
- "bad checksum, no verify",
- /*verify_checksum*/ false,
- &error_msg));
- EXPECT_FALSE(DexFileVerifier::Verify(dex_file.get(),
- dex_file->Begin(),
- dex_file->Size(),
- "bad checksum, verify",
- /*verify_checksum*/ true,
- &error_msg));
- EXPECT_NE(error_msg.find("Bad checksum"), std::string::npos) << error_msg;
-}
-
-TEST_F(DexFileVerifierTest, BadStaticMethodName) {
- // Generated DEX file version (037) from:
- //
- // .class public LBadName;
- // .super Ljava/lang/Object;
- //
- // .method public static <bad_name> (II)V
- // .registers 2
- // .prologue
- // return-void
- // .end method
- //
- // .method public constructor <init>()V
- // .registers 1
- // .prologue
- // .line 1
- // invoke-direct {p0}, Ljava/lang/Object;-><init>()V
- // return-void
- // .end method
- //
- static const char kDexBase64[] =
- "ZGV4CjAzNwC2NYlwyxEc/h6hv+hMeUVQPtiX6MQBcfgwAgAAcAAAAHhWNBIAAAAAAAAAAJABAAAI"
- "AAAAcAAAAAQAAACQAAAAAgAAAKAAAAAAAAAAAAAAAAMAAAC4AAAAAQAAANAAAABAAQAA8AAAAPAA"
- "AAD8AAAABAEAABIBAAAVAQAAIAEAADQBAAA3AQAAAwAAAAQAAAAFAAAABgAAAAYAAAADAAAAAAAA"
- "AAcAAAADAAAAPAEAAAEAAQAAAAAAAQAAAAEAAAACAAAAAQAAAAEAAAABAAAAAgAAAAAAAAACAAAA"
- "AAAAAIABAAAAAAAACjxiYWRfbmFtZT4ABjxpbml0PgAMQmFkTmFtZS5qYXZhAAFJAAlMQmFkTmFt"
- "ZTsAEkxqYXZhL2xhbmcvT2JqZWN0OwABVgADVklJAAIAAAAAAAAAAAAAAAACAAAHAAEABw4AAAIA"
- "AgAAAAAASAEAAAEAAAAOAAAAAQABAAEAAABOAQAABAAAAHAQAgAAAA4AAAACAAAJ1AIBgYAE6AIA"
- "AA0AAAAAAAAAAQAAAAAAAAABAAAACAAAAHAAAAACAAAABAAAAJAAAAADAAAAAgAAAKAAAAAFAAAA"
- "AwAAALgAAAAGAAAAAQAAANAAAAACIAAACAAAAPAAAAABEAAAAQAAADwBAAADEAAAAQAAAEQBAAAD"
- "IAAAAgAAAEgBAAABIAAAAgAAAFQBAAAAIAAAAQAAAIABAAAAEAAAAQAAAJABAAA=";
-
- size_t length;
- std::unique_ptr<uint8_t[]> dex_bytes(DecodeBase64(kDexBase64, &length));
- CHECK(dex_bytes != nullptr);
- // Note: `dex_file` will be destroyed before `dex_bytes`.
- std::unique_ptr<DexFile> dex_file(GetDexFile(dex_bytes.get(), length));
- std::string error_msg;
- EXPECT_FALSE(DexFileVerifier::Verify(dex_file.get(),
- dex_file->Begin(),
- dex_file->Size(),
- "bad static method name",
- /*verify_checksum*/ true,
- &error_msg));
-}
-
-TEST_F(DexFileVerifierTest, BadVirtualMethodName) {
- // Generated DEX file version (037) from:
- //
- // .class public LBadVirtualName;
- // .super Ljava/lang/Object;
- //
- // .method public <bad_name> (II)V
- // .registers 2
- // return-void
- // .end method
- //
- // .method public constructor <init>()V
- // .registers 1
- // invoke-direct {p0}, Ljava/lang/Object;-><init>()V
- // return-void
- // .end method
- //
- static const char kDexBase64[] =
- "ZGV4CjAzNwDcPC8B2E7kYTZmeHX2u2IqrpWV9EXBHpE8AgAAcAAAAHhWNBIAAAAAAAAAAJwBAAAI"
- "AAAAcAAAAAQAAACQAAAAAgAAAKAAAAAAAAAAAAAAAAMAAAC4AAAAAQAAANAAAABMAQAA8AAAAPAA"
- "AAD8AAAABAEAABkBAAAcAQAALgEAAEIBAABFAQAAAwAAAAQAAAAFAAAABgAAAAYAAAADAAAAAAAA"
- "AAcAAAADAAAATAEAAAEAAQAAAAAAAQAAAAEAAAACAAAAAQAAAAEAAAABAAAAAgAAAAAAAAACAAAA"
- "AAAAAI4BAAAAAAAACjxiYWRfbmFtZT4ABjxpbml0PgATQmFkVmlydHVhbE5hbWUuamF2YQABSQAQ"
- "TEJhZFZpcnR1YWxOYW1lOwASTGphdmEvbGFuZy9PYmplY3Q7AAFWAANWSUkAAAACAAAAAAAAAAAA"
- "AAABAAcOAAACAAAHAAABAAEAAQAAAFgBAAAEAAAAcBACAAAADgADAAMAAAAAAF0BAAABAAAADgAA"
- "AAEBAYGABOQCAAH8Ag0AAAAAAAAAAQAAAAAAAAABAAAACAAAAHAAAAACAAAABAAAAJAAAAADAAAA"
- "AgAAAKAAAAAFAAAAAwAAALgAAAAGAAAAAQAAANAAAAACIAAACAAAAPAAAAABEAAAAQAAAEwBAAAD"
- "EAAAAQAAAFQBAAADIAAAAgAAAFgBAAABIAAAAgAAAGQBAAAAIAAAAQAAAI4BAAAAEAAAAQAAAJwB"
- "AAA=";
-
- size_t length;
- std::unique_ptr<uint8_t[]> dex_bytes(DecodeBase64(kDexBase64, &length));
- CHECK(dex_bytes != nullptr);
- // Note: `dex_file` will be destroyed before `dex_bytes`.
- std::unique_ptr<DexFile> dex_file(GetDexFile(dex_bytes.get(), length));
- std::string error_msg;
- EXPECT_FALSE(DexFileVerifier::Verify(dex_file.get(),
- dex_file->Begin(),
- dex_file->Size(),
- "bad virtual method name",
- /*verify_checksum*/ true,
- &error_msg));
-}
-
-TEST_F(DexFileVerifierTest, BadClinitSignature) {
- // Generated DEX file version (037) from:
- //
- // .class public LOneClinitBadSig;
- // .super Ljava/lang/Object;
- //
- // .method public static constructor <clinit>(II)V
- // .registers 2
- // return-void
- // .end method
- //
- // .method public constructor <init>()V
- // .registers 1
- // invoke-direct {p0}, Ljava/lang/Object;-><init>()V
- // return-void
- // .end method
- //
- static const char kDexBase64[] =
- "ZGV4CjAzNwBNOwTbfJmWq5eMOlxUY4EICGiEGJMVg8RAAgAAcAAAAHhWNBIAAAAAAAAAAKABAAAI"
- "AAAAcAAAAAQAAACQAAAAAgAAAKAAAAAAAAAAAAAAAAMAAAC4AAAAAQAAANAAAABQAQAA8AAAAPAA"
- "AAD6AAAAAgEAAAUBAAAYAQAALAEAAEIBAABFAQAAAgAAAAMAAAAEAAAABgAAAAYAAAADAAAAAAAA"
- "AAcAAAADAAAATAEAAAEAAQAAAAAAAQAAAAEAAAACAAAAAQAAAAEAAAABAAAAAgAAAAAAAAAFAAAA"
- "AAAAAJABAAAAAAAACDxjbGluaXQ+AAY8aW5pdD4AAUkAEUxPbmVDbGluaXRCYWRTaWc7ABJMamF2"
- "YS9sYW5nL09iamVjdDsAFE9uZUNsaW5pdEJhZFNpZy5qYXZhAAFWAANWSUkAAAACAAAAAAAAAAAA"
- "AAAAAgAABwABAAcOAAACAAIAAAAAAFgBAAABAAAADgAAAAEAAQABAAAAXgEAAAQAAABwEAIAAAAO"
- "AAAAAgAAiYAE5AIBgYAE+AINAAAAAAAAAAEAAAAAAAAAAQAAAAgAAABwAAAAAgAAAAQAAACQAAAA"
- "AwAAAAIAAACgAAAABQAAAAMAAAC4AAAABgAAAAEAAADQAAAAAiAAAAgAAADwAAAAARAAAAEAAABM"
- "AQAAAxAAAAEAAABUAQAAAyAAAAIAAABYAQAAASAAAAIAAABkAQAAACAAAAEAAACQAQAAABAAAAEA"
- "AACgAQAA";
-
- size_t length;
- std::unique_ptr<uint8_t[]> dex_bytes(DecodeBase64(kDexBase64, &length));
- CHECK(dex_bytes != nullptr);
- // Note: `dex_file` will be destroyed before `dex_bytes`.
- std::unique_ptr<DexFile> dex_file(GetDexFile(dex_bytes.get(), length));
- std::string error_msg;
- EXPECT_FALSE(DexFileVerifier::Verify(dex_file.get(),
- dex_file->Begin(),
- dex_file->Size(),
- "bad clinit signature",
- /*verify_checksum*/ true,
- &error_msg));
-}
-
-TEST_F(DexFileVerifierTest, BadClinitSignatureAgain) {
- // Generated DEX file version (037) from:
- //
- // .class public LOneClinitBadSigAgain;
- // .super Ljava/lang/Object;
- //
- // .method public static constructor <clinit>()I
- // .registers 1
- // const/4 v0, 1
- // return v0
- // .end method
- //
- // .method public constructor <init>()V
- // .registers 1
- // invoke-direct {p0}, Ljava/lang/Object;-><init>()V
- // return-void
- // .end method
- //
- static const char kDexBase64[] =
- "ZGV4CjAzNwBfPcPu5NVwKUqZIu/YR8xqVlVD5UzTk0gEAgAAcAAAAHhWNBIAAAAAAAAAAIgBAAAH"
- "AAAAcAAAAAQAAACMAAAAAgAAAJwAAAAAAAAAAAAAAAMAAAC0AAAAAQAAAMwAAAAYAQAA7AAAAOwA"
- "AAD2AAAA/gAAAAEBAAAZAQAALQEAAEgBAAACAAAAAwAAAAQAAAAGAAAAAgAAAAAAAAAAAAAABgAA"
- "AAMAAAAAAAAAAQAAAAAAAAABAAEAAQAAAAIAAQABAAAAAQAAAAEAAAACAAAAAAAAAAUAAAAAAAAA"
- "eAEAAAAAAAAIPGNsaW5pdD4ABjxpbml0PgABSQAWTE9uZUNsaW5pdEJhZFNpZ0FnYWluOwASTGph"
- "dmEvbGFuZy9PYmplY3Q7ABlPbmVDbGluaXRCYWRTaWdBZ2Fpbi5qYXZhAAFWAAABAAAAAAAAAAAA"
- "AAACAAAAEhAPAAEAAQABAAAAAAAAAAQAAABwEAIAAAAOAAAAAgAAiYAEzAIBgYAE4AIKAAAAAAAA"
- "AAEAAAAAAAAAAQAAAAcAAABwAAAAAgAAAAQAAACMAAAAAwAAAAIAAACcAAAABQAAAAMAAAC0AAAA"
- "BgAAAAEAAADMAAAAAiAAAAcAAADsAAAAASAAAAIAAABMAQAAACAAAAEAAAB4AQAAABAAAAEAAACI"
- "AQAA";
-
- size_t length;
- std::unique_ptr<uint8_t[]> dex_bytes(DecodeBase64(kDexBase64, &length));
- CHECK(dex_bytes != nullptr);
- // Note: `dex_file` will be destroyed before `dex_bytes`.
- std::unique_ptr<DexFile> dex_file(GetDexFile(dex_bytes.get(), length));
- std::string error_msg;
- EXPECT_FALSE(DexFileVerifier::Verify(dex_file.get(),
- dex_file->Begin(),
- dex_file->Size(),
- "bad clinit signature",
- /*verify_checksum*/ true,
- &error_msg));
-}
-
-TEST_F(DexFileVerifierTest, BadInitSignature) {
- // Generated DEX file version (037) from:
- //
- // .class public LBadInitSig;
- // .super Ljava/lang/Object;
- //
- // .method public constructor <init>()I
- // .registers 1
- // invoke-direct {p0}, Ljava/lang/Object;-><init>()V
- // const v0, 1
- // return v0
- // .end method
- //
- static const char kDexBase64[] =
- "ZGV4CjAzNwCdMdeh1KoHWamF2Prq32LF39YZ78fV7q+wAQAAcAAAAHhWNBIAAAAAAAAAADQBAAAF"
- "AAAAcAAAAAQAAACEAAAAAgAAAJQAAAAAAAAAAAAAAAIAAACsAAAAAQAAALwAAADUAAAA3AAAANwA"
- "AADkAAAA5wAAAPUAAAAJAQAAAQAAAAIAAAADAAAABAAAAAEAAAAAAAAAAAAAAAQAAAADAAAAAAAA"
- "AAEAAAAAAAAAAgABAAAAAAABAAAAAQAAAAIAAAAAAAAA/////wAAAAAqAQAAAAAAAAY8aW5pdD4A"
- "AUkADExCYWRJbml0U2lnOwASTGphdmEvbGFuZy9PYmplY3Q7AAFWAAEAAQABAAAAAAAAAAcAAABw"
- "EAEAAAAUAAEAAAAPAAAAAQAAgYAEjAIKAAAAAAAAAAEAAAAAAAAAAQAAAAUAAABwAAAAAgAAAAQA"
- "AACEAAAAAwAAAAIAAACUAAAABQAAAAIAAACsAAAABgAAAAEAAAC8AAAAAiAAAAUAAADcAAAAASAA"
- "AAEAAAAMAQAAACAAAAEAAAAqAQAAABAAAAEAAAA0AQAA";
-
- size_t length;
- std::unique_ptr<uint8_t[]> dex_bytes(DecodeBase64(kDexBase64, &length));
- CHECK(dex_bytes != nullptr);
- // Note: `dex_file` will be destroyed before `dex_bytes`.
- std::unique_ptr<DexFile> dex_file(GetDexFile(dex_bytes.get(), length));
- std::string error_msg;
- EXPECT_FALSE(DexFileVerifier::Verify(dex_file.get(),
- dex_file->Begin(),
- dex_file->Size(),
- "bad init signature",
- /*verify_checksum*/ true,
- &error_msg));
-}
-
-static const char* kInvokeCustomDexFiles[] = {
- // TODO(oth): Revisit this test when we have smali / dx support.
- // https://cs.corp.google.com/android/toolchain/jack/jack-tests/tests/com/android/jack/java7/invokecustom/test001/Tests.java
- "ZGV4CjAzOAAEj12s/acmmdGuDL92SWSBh6iLBjxgomWkCAAAcAAAAHhWNBIAAAAAAAAAALwHAAAx"
- "AAAAcAAAABYAAAA0AQAACQAAAIwBAAADAAAA+AEAAAsAAAAQAgAAAQAAAHACAAAMBgAAmAIAAMID"
- "AADKAwAAzQMAANIDAADhAwAA5AMAAOoDAAAfBAAAUgQAAIMEAAC4BAAA1AQAAOsEAAD+BAAAEgUA"
- "ACYFAAA6BQAAUQUAAG4FAACTBQAAtAUAAN0FAAD/BQAAHgYAADgGAABKBgAAVgYAAFkGAABdBgAA"
- "YgYAAGYGAAB7BgAAgAYAAI8GAACdBgAAtAYAAMMGAADSBgAA3gYAAPIGAAD4BgAABgcAAA4HAAAU"
- "BwAAGgcAAB8HAAAoBwAANAcAADoHAAABAAAABgAAAAcAAAAIAAAACQAAAAoAAAALAAAADAAAAA0A"
- "AAAOAAAADwAAABAAAAARAAAAEgAAABMAAAAUAAAAFQAAABYAAAAXAAAAGAAAABoAAAAeAAAAAgAA"
- "AAAAAACMAwAABQAAAAwAAACUAwAABQAAAA4AAACgAwAABAAAAA8AAAAAAAAAGgAAABQAAAAAAAAA"
- "GwAAABQAAACsAwAAHAAAABQAAACMAwAAHQAAABQAAAC0AwAAHQAAABQAAAC8AwAAAwADAAMAAAAE"
- "AAwAJAAAAAoABgAsAAAABAAEAAAAAAAEAAAAHwAAAAQAAQAoAAAABAAIACoAAAAEAAQALwAAAAYA"
- "BQAtAAAACAAEAAAAAAANAAcAAAAAAA8AAgAlAAAAEAADACkAAAASAAYAIQAAAJYHAACWBwAABAAA"
- "AAEAAAAIAAAAAAAAABkAAABkAwAAnQcAAAAAAAAEAAAAAgAAAAEAAABjBwAAAQAAAIsHAAACAAAA"
- "iwcAAJMHAAABAAEAAQAAAEEHAAAEAAAAcBAGAAAADgADAAIAAAAAAEYHAAADAAAAkAABAg8AAAAF"
- "AAMABAAAAE0HAAAQAAAAcQAJAAAADAAcAQQAbkAIABBDDAAiAQ0AcCAHAAEAEQEEAAEAAgAAAFYH"
- "AAAMAAAAYgACABIhEjL8IAAAIQAKAW4gBQAQAA4AAwABAAIAAABdBwAACwAAABIgEjH8IAEAEAAK"
- "ABJRcSAKAAEADgAAAAAAAAAAAAAAAwAAAAAAAAABAAAAmAIAAAIAAACgAgAABAAAAKgCAAACAAAA"
- "AAAAAAMAAAAPAAkAEQAAAAMAAAAHAAkAEQAAAAEAAAAAAAAAAQAAAA4AAAABAAAAFQAGPGluaXQ+"
- "AAFJAANJSUkADUlOVk9LRV9TVEFUSUMAAUwABExMTEwAM0xjb20vYW5kcm9pZC9qYWNrL2Fubm90"
- "YXRpb25zL0NhbGxlZEJ5SW52b2tlQ3VzdG9tOwAxTGNvbS9hbmRyb2lkL2phY2svYW5ub3RhdGlv"
- "bnMvTGlua2VyTWV0aG9kSGFuZGxlOwAvTGNvbS9hbmRyb2lkL2phY2svYW5ub3RhdGlvbnMvTWV0"
- "aG9kSGFuZGxlS2luZDsAM0xjb20vYW5kcm9pZC9qYWNrL2phdmE3L2ludm9rZWN1c3RvbS90ZXN0"
- "MDAxL1Rlc3RzOwAaTGRhbHZpay9hbm5vdGF0aW9uL1Rocm93czsAFUxqYXZhL2lvL1ByaW50U3Ry"
- "ZWFtOwARTGphdmEvbGFuZy9DbGFzczsAEkxqYXZhL2xhbmcvT2JqZWN0OwASTGphdmEvbGFuZy9T"
- "dHJpbmc7ABJMamF2YS9sYW5nL1N5c3RlbTsAFUxqYXZhL2xhbmcvVGhyb3dhYmxlOwAbTGphdmEv"
- "bGFuZy9pbnZva2UvQ2FsbFNpdGU7ACNMamF2YS9sYW5nL2ludm9rZS9Db25zdGFudENhbGxTaXRl"
- "OwAfTGphdmEvbGFuZy9pbnZva2UvTWV0aG9kSGFuZGxlOwAnTGphdmEvbGFuZy9pbnZva2UvTWV0"
- "aG9kSGFuZGxlcyRMb29rdXA7ACBMamF2YS9sYW5nL2ludm9rZS9NZXRob2RIYW5kbGVzOwAdTGph"
- "dmEvbGFuZy9pbnZva2UvTWV0aG9kVHlwZTsAGExqdW5pdC9mcmFtZXdvcmsvQXNzZXJ0OwAQTG9y"
- "Zy9qdW5pdC9UZXN0OwAKVGVzdHMuamF2YQABVgACVkkAA1ZJSQACVkwAE1tMamF2YS9sYW5nL1N0"
- "cmluZzsAA2FkZAANYXJndW1lbnRUeXBlcwAMYXNzZXJ0RXF1YWxzABVlbWl0dGVyOiBqYWNrLTQu"
- "MC1lbmcADWVuY2xvc2luZ1R5cGUADWZpZWxkQ2FsbFNpdGUACmZpbmRTdGF0aWMAEmludm9rZU1l"
- "dGhvZEhhbmRsZQAEa2luZAAMbGlua2VyTWV0aG9kAAZsb29rdXAABG1haW4ABG5hbWUAA291dAAH"
- "cHJpbnRsbgAKcmV0dXJuVHlwZQAEdGVzdAAFdmFsdWUAIgAHDgAvAgAABw4ANQMAAAAHDqUAPwEA"
- "Bw60ADsABw6lAAABBCAcAhgAGAAmHAEdAgQgHAMYDxgJGBEjGAQnGwArFygrFx8uGAACBQEwHAEY"
- "CwETAAMWABcfFQABAAQBAQkAgYAEtAUBCswFAQrkBQEJlAYEAbwGAAAAEwAAAAAAAAABAAAAAAAA"
- "AAEAAAAxAAAAcAAAAAIAAAAWAAAANAEAAAMAAAAJAAAAjAEAAAQAAAADAAAA+AEAAAUAAAALAAAA"
- "EAIAAAcAAAACAAAAaAIAAAYAAAABAAAAcAIAAAgAAAABAAAAkAIAAAMQAAADAAAAmAIAAAEgAAAF"
- "AAAAtAIAAAYgAAABAAAAZAMAAAEQAAAGAAAAjAMAAAIgAAAxAAAAwgMAAAMgAAAFAAAAQQcAAAQg"
- "AAADAAAAYwcAAAUgAAABAAAAlgcAAAAgAAABAAAAnQcAAAAQAAABAAAAvAcAAA==",
- // https://cs.corp.google.com/android/toolchain/jack/jack-tests/tests/com/android/jack/java7/invokecustom/test002/Tests.java
- "ZGV4CjAzOAAzq3aGAwKhT4QQj4lqNfZJAO8Tm24uTyNICQAAcAAAAHhWNBIAAAAAAAAAAGAIAAA2"
- "AAAAcAAAABgAAABIAQAACQAAAKgBAAAEAAAAFAIAAA0AAAA0AgAAAQAAAKQCAAB8BgAAzAIAACYE"
- "AAAwBAAAOAQAAEQEAABHBAAATAQAAE8EAABVBAAAigQAALwEAADtBAAAIgUAAD4FAABVBQAAaAUA"
- "AH0FAACRBQAApQUAALkFAADQBQAA7QUAABIGAAAzBgAAXAYAAH4GAACdBgAAtwYAAMkGAADPBgAA"
- "2wYAAN4GAADiBgAA5wYAAOsGAAD/BgAAFAcAABkHAAAoBwAANgcAAE0HAABcBwAAawcAAH4HAACK"
- "BwAAkAcAAJgHAACeBwAAqgcAALAHAAC1BwAAxgcAAM8HAADbBwAA4QcAAAMAAAAHAAAACAAAAAkA"
- "AAAKAAAACwAAAAwAAAANAAAADgAAAA8AAAAQAAAAEQAAABIAAAATAAAAFAAAABUAAAAWAAAAFwAA"
- "ABgAAAAZAAAAGgAAAB0AAAAhAAAAIgAAAAQAAAAAAAAA8AMAAAYAAAAPAAAA+AMAAAUAAAAQAAAA"
- "AAAAAAYAAAASAAAABAQAAB0AAAAVAAAAAAAAAB4AAAAVAAAAEAQAAB8AAAAVAAAA8AMAACAAAAAV"
- "AAAAGAQAACAAAAAVAAAAIAQAAAMAAwACAAAABAANACgAAAAIAAcAGwAAAAsABgAwAAAABAAEAAAA"
- "AAAEAAQAAQAAAAQAAAAjAAAABAAIAC0AAAAEAAQANAAAAAYABQAyAAAACQAEAAEAAAAMAAQAMQAA"
- "AA4ABwABAAAAEAABACoAAAARAAIALAAAABIAAwAuAAAAEwAGACUAAAA4CAAAOAgAAAQAAAABAAAA"
- "CQAAAAAAAAAcAAAA0AMAAD8IAAAAAAAAAQAAAAEAAAABAAAADggAAAIAAAAtCAAANQgAAAgAAAAE"
- "AAEA6AcAACoAAABxAAoAAAAMABwBBAAbAiMAAABiAwIAYgQCABIVI1UWAGIGAgASB00GBQdxMAsA"
- "QwUMA25ACQAQMgwAIgEOAHAgCAABAGkBAQAOAA0AbhAHAAAAKPsAAAAAJAABAAEBDCUBAAEAAQAA"
- "APUHAAAEAAAAcBAGAAAADgADAAIAAAAAAPoHAAADAAAAkAABAg8AAAAEAAEAAgAAAAEIAAAMAAAA"
- "YgADABIhEjL8IAAAIQAKAW4gBQAQAA4AAwABAAIAAAAICAAACwAAABIgEjH8IAEAEAAKABJRcSAM"
- "AAEADgAAAAAAAAAAAAAAAgAAAAAAAAACAAAAzAIAAAQAAADUAgAAAgAAAAAAAAADAAAABwAKABIA"
- "AAADAAAABwAHABYAAAABAAAAAAAAAAEAAAAPAAAAAQAAABcACDxjbGluaXQ+AAY8aW5pdD4ACkdF"
- "VF9TVEFUSUMAAUkAA0lJSQABTAAETExMTAAzTGNvbS9hbmRyb2lkL2phY2svYW5ub3RhdGlvbnMv"
- "Q2FsbGVkQnlJbnZva2VDdXN0b207ADBMY29tL2FuZHJvaWQvamFjay9hbm5vdGF0aW9ucy9MaW5r"
- "ZXJGaWVsZEhhbmRsZTsAL0xjb20vYW5kcm9pZC9qYWNrL2Fubm90YXRpb25zL01ldGhvZEhhbmRs"
- "ZUtpbmQ7ADNMY29tL2FuZHJvaWQvamFjay9qYXZhNy9pbnZva2VjdXN0b20vdGVzdDAwMi9UZXN0"
- "czsAGkxkYWx2aWsvYW5ub3RhdGlvbi9UaHJvd3M7ABVMamF2YS9pby9QcmludFN0cmVhbTsAEUxq"
- "YXZhL2xhbmcvQ2xhc3M7ABNMamF2YS9sYW5nL0ludGVnZXI7ABJMamF2YS9sYW5nL09iamVjdDsA"
- "EkxqYXZhL2xhbmcvU3RyaW5nOwASTGphdmEvbGFuZy9TeXN0ZW07ABVMamF2YS9sYW5nL1Rocm93"
- "YWJsZTsAG0xqYXZhL2xhbmcvaW52b2tlL0NhbGxTaXRlOwAjTGphdmEvbGFuZy9pbnZva2UvQ29u"
- "c3RhbnRDYWxsU2l0ZTsAH0xqYXZhL2xhbmcvaW52b2tlL01ldGhvZEhhbmRsZTsAJ0xqYXZhL2xh"
- "bmcvaW52b2tlL01ldGhvZEhhbmRsZXMkTG9va3VwOwAgTGphdmEvbGFuZy9pbnZva2UvTWV0aG9k"
- "SGFuZGxlczsAHUxqYXZhL2xhbmcvaW52b2tlL01ldGhvZFR5cGU7ABhManVuaXQvZnJhbWV3b3Jr"
- "L0Fzc2VydDsAEExvcmcvanVuaXQvVGVzdDsABFRZUEUAClRlc3RzLmphdmEAAVYAAlZJAANWSUkA"
- "AlZMABJbTGphdmEvbGFuZy9DbGFzczsAE1tMamF2YS9sYW5nL1N0cmluZzsAA2FkZAANYXJndW1l"
- "bnRUeXBlcwAMYXNzZXJ0RXF1YWxzABVlbWl0dGVyOiBqYWNrLTQuMC1lbmcADWVuY2xvc2luZ1R5"
- "cGUADWZpZWxkQ2FsbFNpdGUAEWZpZWxkTWV0aG9kSGFuZGxlAApmaW5kU3RhdGljAARraW5kAAZs"
- "b29rdXAABG1haW4ACm1ldGhvZFR5cGUABG5hbWUAA291dAAPcHJpbnRTdGFja1RyYWNlAAdwcmlu"
- "dGxuAApyZXR1cm5UeXBlAAR0ZXN0AAV2YWx1ZQAoAAcOAR0PAnh3Jh4AIQAHDgA2AgAABw4APwEA"
- "Bw60ADsABw6lAAABBCQcAhgAGAApHAEdAgMnGAQrGwAvFygvFyMzGAACBQE1HAEYDAEUAAMWABcj"
- "FQABAAQBAQkAiIAE4AUBgYAE0AYBCugGAQmABwQBqAcAAAATAAAAAAAAAAEAAAAAAAAAAQAAADYA"
- "AABwAAAAAgAAABgAAABIAQAAAwAAAAkAAACoAQAABAAAAAQAAAAUAgAABQAAAA0AAAA0AgAABwAA"
- "AAIAAACcAgAABgAAAAEAAACkAgAACAAAAAEAAADEAgAAAxAAAAIAAADMAgAAASAAAAUAAADgAgAA"
- "BiAAAAEAAADQAwAAARAAAAYAAADwAwAAAiAAADYAAAAmBAAAAyAAAAUAAADoBwAABCAAAAMAAAAO"
- "CAAABSAAAAEAAAA4CAAAACAAAAEAAAA/CAAAABAAAAEAAABgCAAA",
- // https://cs.corp.google.com/android/toolchain/jack/jack-tests/tests/com/android/jack/java7/invokecustom/test003/Tests.java
- "ZGV4CjAzOABjnhkFatj30/7cHTCJsfr7vAjz9/p+Y+TcCAAAcAAAAHhWNBIAAAAAAAAAAPQHAAAx"
- "AAAAcAAAABYAAAA0AQAACQAAAIwBAAADAAAA+AEAAAsAAAAQAgAAAQAAAHACAABEBgAAmAIAAOoD"
- "AADyAwAA9QMAAP4DAAANBAAAEAQAABYEAABLBAAAfgQAAK8EAADkBAAAAAUAABcFAAAqBQAAPgUA"
- "AFIFAABmBQAAfQUAAJoFAAC/BQAA4AUAAAkGAAArBgAASgYAAGQGAAB2BgAAggYAAIUGAACJBgAA"
- "jgYAAJIGAACnBgAArAYAALsGAADJBgAA4AYAAO8GAAD+BgAACgcAAB4HAAAkBwAAMgcAADoHAABA"
- "BwAARgcAAEsHAABUBwAAYAcAAGYHAAABAAAABgAAAAcAAAAIAAAACQAAAAoAAAALAAAADAAAAA0A"
- "AAAOAAAADwAAABAAAAARAAAAEgAAABMAAAAUAAAAFQAAABYAAAAXAAAAGAAAABoAAAAeAAAAAgAA"
- "AAAAAACkAwAABQAAAAwAAAC0AwAABQAAAA4AAADAAwAABAAAAA8AAAAAAAAAGgAAABQAAAAAAAAA"
- "GwAAABQAAADMAwAAHAAAABQAAADUAwAAHQAAABQAAADcAwAAHQAAABQAAADkAwAAAwADAAMAAAAE"
- "AAwAJAAAAAoABgAsAAAABAAEAAAAAAAEAAAAHwAAAAQAAQAoAAAABAAIACoAAAAEAAQALwAAAAYA"
- "BQAtAAAACAAEAAAAAAANAAcAAAAAAA8AAgAlAAAAEAADACkAAAASAAYAIQAAAM4HAADOBwAABAAA"
- "AAEAAAAIAAAAAAAAABkAAAB8AwAA1QcAAAAAAAAEAAAAAgAAAAEAAACTBwAAAQAAAMMHAAACAAAA"
- "wwcAAMsHAAABAAEAAQAAAG0HAAAEAAAAcBAGAAAADgAHAAYAAAAAAHIHAAAHAAAAkAABArAwsECw"
- "ULBgDwAAAAUAAwAEAAAAfQcAABAAAABxAAkAAAAMABwBBABuQAgAEEMMACIBDQBwIAcAAQARAQgA"
- "AQACAAAAhgcAABAAAABiBgIAEhASIRIyEkMSVBJl/QYAAAAACgBuIAUABgAOAAcAAQACAAAAjQcA"
- "ABAAAAASEBIhEjISQxJUEmX9BgEAAAAKABMBFQBxIAoAAQAOAAAAAAAAAAAAAwAAAAAAAAABAAAA"
- "mAIAAAIAAACgAgAABAAAAKgCAAAGAAAAAAAAAAAAAAAAAAAAAwAAAA8ACQARAAAAAwAAAAcACQAR"
- "AAAAAQAAAAAAAAACAAAAAAAAAAEAAAAOAAAAAQAAABUABjxpbml0PgABSQAHSUlJSUlJSQANSU5W"
- "T0tFX1NUQVRJQwABTAAETExMTAAzTGNvbS9hbmRyb2lkL2phY2svYW5ub3RhdGlvbnMvQ2FsbGVk"
- "QnlJbnZva2VDdXN0b207ADFMY29tL2FuZHJvaWQvamFjay9hbm5vdGF0aW9ucy9MaW5rZXJNZXRo"
- "b2RIYW5kbGU7AC9MY29tL2FuZHJvaWQvamFjay9hbm5vdGF0aW9ucy9NZXRob2RIYW5kbGVLaW5k"
- "OwAzTGNvbS9hbmRyb2lkL2phY2svamF2YTcvaW52b2tlY3VzdG9tL3Rlc3QwMDMvVGVzdHM7ABpM"
- "ZGFsdmlrL2Fubm90YXRpb24vVGhyb3dzOwAVTGphdmEvaW8vUHJpbnRTdHJlYW07ABFMamF2YS9s"
- "YW5nL0NsYXNzOwASTGphdmEvbGFuZy9PYmplY3Q7ABJMamF2YS9sYW5nL1N0cmluZzsAEkxqYXZh"
- "L2xhbmcvU3lzdGVtOwAVTGphdmEvbGFuZy9UaHJvd2FibGU7ABtMamF2YS9sYW5nL2ludm9rZS9D"
- "YWxsU2l0ZTsAI0xqYXZhL2xhbmcvaW52b2tlL0NvbnN0YW50Q2FsbFNpdGU7AB9MamF2YS9sYW5n"
- "L2ludm9rZS9NZXRob2RIYW5kbGU7ACdMamF2YS9sYW5nL2ludm9rZS9NZXRob2RIYW5kbGVzJExv"
- "b2t1cDsAIExqYXZhL2xhbmcvaW52b2tlL01ldGhvZEhhbmRsZXM7AB1MamF2YS9sYW5nL2ludm9r"
- "ZS9NZXRob2RUeXBlOwAYTGp1bml0L2ZyYW1ld29yay9Bc3NlcnQ7ABBMb3JnL2p1bml0L1Rlc3Q7"
- "AApUZXN0cy5qYXZhAAFWAAJWSQADVklJAAJWTAATW0xqYXZhL2xhbmcvU3RyaW5nOwADYWRkAA1h"
- "cmd1bWVudFR5cGVzAAxhc3NlcnRFcXVhbHMAFWVtaXR0ZXI6IGphY2stNC4wLWVuZwANZW5jbG9z"
- "aW5nVHlwZQANZmllbGRDYWxsU2l0ZQAKZmluZFN0YXRpYwASaW52b2tlTWV0aG9kSGFuZGxlAARr"
- "aW5kAAxsaW5rZXJNZXRob2QABmxvb2t1cAAEbWFpbgAEbmFtZQADb3V0AAdwcmludGxuAApyZXR1"
- "cm5UeXBlAAR0ZXN0AAV2YWx1ZQAiAAcOAC8GAAAAAAAABw4ANQMAAAAHDqUAPwEABw7wADsABw7w"
- "AAABBCAcBhgAGAAYABgAGAAYACYcAR0CBCAcAxgPGAkYESMYBCcbACsXKCsXHy4YAAIFATAcARgL"
- "ARMAAxYAFx8VAAEABAEBCQCBgAS0BQEKzAUBCuwFAQmcBgQBzAYAAAATAAAAAAAAAAEAAAAAAAAA"
- "AQAAADEAAABwAAAAAgAAABYAAAA0AQAAAwAAAAkAAACMAQAABAAAAAMAAAD4AQAABQAAAAsAAAAQ"
- "AgAABwAAAAIAAABoAgAABgAAAAEAAABwAgAACAAAAAEAAACQAgAAAxAAAAMAAACYAgAAASAAAAUA"
- "AAC0AgAABiAAAAEAAAB8AwAAARAAAAcAAACkAwAAAiAAADEAAADqAwAAAyAAAAUAAABtBwAABCAA"
- "AAMAAACTBwAABSAAAAEAAADOBwAAACAAAAEAAADVBwAAABAAAAEAAAD0BwAA",
- // https://cs.corp.google.com/android/toolchain/jack/jack-tests/tests/com/android/jack/java7/invokecustom/test004/Tests.java
- "ZGV4CjAzOABvUVfbV74qWbSOEsgKP+EzahlNQLW2/8TMDAAAcAAAAHhWNBIAAAAAAAAAAOQLAABS"
- "AAAAcAAAAB8AAAC4AQAAEAAAADQCAAADAAAA9AIAABIAAAAMAwAAAQAAAKQDAAAACQAAzAMAANYF"
- "AADZBQAA4QUAAOkFAADsBQAA7wUAAPIFAAD1BQAA/AUAAP8FAAAEBgAAEwYAABYGAAAZBgAAHwYA"
- "AC8GAABkBgAAjQYAAMAGAADxBgAAJgcAAEUHAABhBwAAeAcAAIoHAACdBwAAsQcAAMUHAADZBwAA"
- "8AcAAA0IAAAyCAAAUwgAAHwIAACeCAAAvQgAANcIAADpCAAA7AgAAPgIAAD7CAAAAAkAAAYJAAAM"
- "CQAAEAkAABUJAAAaCQAAHgkAACMJAAAnCQAAKgkAADMJAABICQAATQkAAFwJAABqCQAAdgkAAIQJ"
- "AACPCQAAmgkAAKYJAACzCQAAygkAANkJAADoCQAA9AkAAAAKAAAKCgAAHgoAACQKAAAyCgAAPQoA"
- "AEUKAABLCgAAYgoAAGgKAABtCgAAdgoAAIIKAACOCgAAmwoAAKEKAAADAAAABAAAAAUAAAAGAAAA"
- "CAAAAAsAAAAPAAAAEAAAABEAAAASAAAAEwAAABQAAAAVAAAAFgAAABgAAAAZAAAAGgAAABsAAAAc"
- "AAAAHQAAAB4AAAAfAAAAIAAAACEAAAAiAAAAIwAAACQAAAAlAAAAJwAAADEAAAAzAAAACQAAAAQA"
- "AABMBQAADgAAABMAAABUBQAADQAAABUAAAB0BQAADAAAABYAAAAAAAAAJwAAABwAAAAAAAAAKAAA"
- "ABwAAACABQAAKQAAABwAAACIBQAAKgAAABwAAACUBQAAKwAAABwAAACgBQAALAAAABwAAABMBQAA"
- "LQAAABwAAACoBQAALwAAABwAAACwBQAALwAAABwAAAC4BQAALgAAABwAAADABQAAMAAAABwAAADI"
- "BQAALgAAABwAAADQBQAACQAJAAoAAAAKABMAPwAAABEADQBLAAAACgAEAAIAAAAKAAAANAAAAAoA"
- "AQBFAAAACgAPAEgAAAAKAAQAUAAAAA0ACABMAAAADwAEAAIAAAAUAA0AAgAAABYAAgBAAAAAFwAD"
- "AEcAAAAZAAUANgAAABkABgA2AAAAGQAHADYAAAAZAAkANgAAABkACgA2AAAAGQALADYAAAAZAAwA"
- "NgAAABkADgA3AAAAnQsAAJ0LAAAKAAAAAQAAAA8AAAAAAAAAJgAAACQFAADGCwAAAAAAAAQAAAAC"
- "AAAAAQAAAN4KAAACAAAAegsAAJILAAACAAAAkgsAAJoLAAABAAEAAQAAAKgKAAAEAAAAcBAGAAAA"
- "DgADAAIAAAAAAK0KAAADAAAAkAABAg8AAAAYAA8ABgAAALQKAABTAAAAcRARAAwAEhJxIA0A0gAT"
- "AmEAcSAKAOIAEwIABHEgDQDyABISAgAQAHEgDQACABICFAOamTFBAgARAHEwDAADAhYGAAAYApqZ"
- "mZmZmQFABQQSAHcGCwACABsCBwAAAAgAFABxIBAAAgAcAgoACAAVAHEgDwACABcCFc1bBwUAFgBx"
- "QA4AMhBxAAkAAAAMAhwDCgBuQAgAMroMAiIDFABwIAcAIwARAwAABAABAAIAAADRCgAADAAAAGIA"
- "AgASIRIy/CAAACEACgFuIAUAEAAOAAMAAQACAAAA2AoAAAsAAAASIBIx/CABABAACgASUXEgDQAB"
- "AA4AAAAAAAAAAAAAAAMAAAAAAAAAAQAAAMwDAAACAAAA1AMAAAQAAADgAwAAAgAAAAQABAANAAAA"
- "FgAQABgAHQAAAAEAGwAEAAMAAgAQAA4ABQAAAAMAAAAOABAAGAAAAAIAAAABAAEAAwAAAAIAAgAC"
- "AAAAAwAAAAMAAwADAAAAAQAAAAQAAAACAAAABQAFAAIAAAAPAA8AAgAAABAAEAABAAAAFQAAAAEA"
- "AAAdAAAAAQAAAB4AASgABjwqPjtKKQAGPGluaXQ+AAFCAAFDAAFEAAFGAAVIZWxsbwABSQADSUlJ"
- "AA1JTlZPS0VfU1RBVElDAAFKAAFMAARMTExMAA5MTExMWkJDU0lGRExMSgAzTGNvbS9hbmRyb2lk"
- "L2phY2svYW5ub3RhdGlvbnMvQ2FsbGVkQnlJbnZva2VDdXN0b207ACdMY29tL2FuZHJvaWQvamFj"
- "ay9hbm5vdGF0aW9ucy9Db25zdGFudDsAMUxjb20vYW5kcm9pZC9qYWNrL2Fubm90YXRpb25zL0xp"
- "bmtlck1ldGhvZEhhbmRsZTsAL0xjb20vYW5kcm9pZC9qYWNrL2Fubm90YXRpb25zL01ldGhvZEhh"
- "bmRsZUtpbmQ7ADNMY29tL2FuZHJvaWQvamFjay9qYXZhNy9pbnZva2VjdXN0b20vdGVzdDAwNC9U"
- "ZXN0czsAHUxkYWx2aWsvYW5ub3RhdGlvbi9TaWduYXR1cmU7ABpMZGFsdmlrL2Fubm90YXRpb24v"
- "VGhyb3dzOwAVTGphdmEvaW8vUHJpbnRTdHJlYW07ABBMamF2YS9sYW5nL0NsYXNzABFMamF2YS9s"
- "YW5nL0NsYXNzOwASTGphdmEvbGFuZy9PYmplY3Q7ABJMamF2YS9sYW5nL1N0cmluZzsAEkxqYXZh"
- "L2xhbmcvU3lzdGVtOwAVTGphdmEvbGFuZy9UaHJvd2FibGU7ABtMamF2YS9sYW5nL2ludm9rZS9D"
- "YWxsU2l0ZTsAI0xqYXZhL2xhbmcvaW52b2tlL0NvbnN0YW50Q2FsbFNpdGU7AB9MamF2YS9sYW5n"
- "L2ludm9rZS9NZXRob2RIYW5kbGU7ACdMamF2YS9sYW5nL2ludm9rZS9NZXRob2RIYW5kbGVzJExv"
- "b2t1cDsAIExqYXZhL2xhbmcvaW52b2tlL01ldGhvZEhhbmRsZXM7AB1MamF2YS9sYW5nL2ludm9r"
- "ZS9NZXRob2RUeXBlOwAYTGp1bml0L2ZyYW1ld29yay9Bc3NlcnQ7ABBMb3JnL2p1bml0L1Rlc3Q7"
- "AAFTAApUZXN0cy5qYXZhAAFWAANWQ0MABFZEREQABFZGRkYAAlZJAANWSUkAA1ZKSgACVkwAA1ZM"
- "TAACVloAAVoAB1pCQ1NJRkQAE1tMamF2YS9sYW5nL1N0cmluZzsAA2FkZAANYXJndW1lbnRUeXBl"
- "cwAMYXNzZXJ0RXF1YWxzAAphc3NlcnRUcnVlAAxib29sZWFuVmFsdWUACWJ5dGVWYWx1ZQAJY2hh"
- "clZhbHVlAApjbGFzc1ZhbHVlAAtkb3VibGVWYWx1ZQAVZW1pdHRlcjogamFjay00LjAtZW5nAA1l"
- "bmNsb3NpbmdUeXBlAA1maWVsZENhbGxTaXRlAApmaW5kU3RhdGljAApmbG9hdFZhbHVlAAhpbnRW"
- "YWx1ZQASaW52b2tlTWV0aG9kSGFuZGxlAARraW5kAAxsaW5rZXJNZXRob2QACWxvbmdWYWx1ZQAG"
- "bG9va3VwAARtYWluABVtZXRob2RIYW5kbGVFeHRyYUFyZ3MABG5hbWUAA291dAAHcHJpbnRsbgAK"
- "cmV0dXJuVHlwZQAKc2hvcnRWYWx1ZQALc3RyaW5nVmFsdWUABHRlc3QABXZhbHVlACMABw4ANwIA"
- "AAcOAD4NAAAAAAAAAAAAAAAAAAcOPEtaWmmWw4d4h6UAUgEABw60AE4ABw6lAAAGBTUcAhgEGARD"
- "HAEdCAQ1HA0YFhgQGBgYHRgAGAEYGxgEGAMYAhgQGA4YBT4YCkQbAEoXRUkcCh0HATgcAT8dBwE5"
- "HAEAAR0HATocAQNhHQcBThwBIgAEHQcBQhwBBAEdBwFBHAFwmpkxQR0HATwcAfGamZmZmZkBQB0H"
- "AU8cARcHHQcBOxwBGAodBwFGHAFmFc1bB0oXNE0YBAILAVEcCRcAFyAXGhciFzIXGhcXFwEXHQIM"
- "AVEcARgSARoADRYAFzQVAAQBBAEEYSQABAQBcJqZMUHxmpmZmZmZAUAXBxgKZhXNWwcBAAQBAQkA"
- "gYAE7AcBCoQIAQqcCAEJ1AkEAfwJAAATAAAAAAAAAAEAAAAAAAAAAQAAAFIAAABwAAAAAgAAAB8A"
- "AAC4AQAAAwAAABAAAAA0AgAABAAAAAMAAAD0AgAABQAAABIAAAAMAwAABwAAAAIAAACcAwAABgAA"
- "AAEAAACkAwAACAAAAAEAAADEAwAAAxAAAAMAAADMAwAAASAAAAUAAADsAwAABiAAAAEAAAAkBQAA"
- "ARAAAA0AAABMBQAAAiAAAFIAAADWBQAAAyAAAAUAAACoCgAABCAAAAQAAADeCgAABSAAAAEAAACd"
- "CwAAACAAAAEAAADGCwAAABAAAAEAAADkCwAA"
-};
-
-TEST_F(DexFileVerifierTest, InvokeCustomDexSamples) {
- for (size_t i = 0; i < arraysize(kInvokeCustomDexFiles); ++i) {
- size_t length;
- std::unique_ptr<uint8_t[]> dex_bytes(DecodeBase64(kInvokeCustomDexFiles[i], &length));
- CHECK(dex_bytes != nullptr);
- // Note: `dex_file` will be destroyed before `dex_bytes`.
- std::unique_ptr<DexFile> dex_file(GetDexFile(dex_bytes.get(), length));
- std::string error_msg;
- EXPECT_TRUE(DexFileVerifier::Verify(dex_file.get(),
- dex_file->Begin(),
- dex_file->Size(),
- "good checksum, verify",
- /*verify_checksum*/ true,
- &error_msg));
- // TODO(oth): Test corruptions (b/35308502)
- }
-}
-
-TEST_F(DexFileVerifierTest, BadStaticFieldInitialValuesArray) {
- // Generated DEX file version (037) from:
- //
- // .class public LBadStaticFieldInitialValuesArray;
- // .super Ljava/lang/Object;
- //
- // # static fields
- // .field static final c:C = 'c'
- // .field static final i:I = 0x1
- // .field static final s:Ljava/lang/String; = "s"
- //
- // # direct methods
- // .method public constructor <init>()V
- // .registers 1
- // invoke-direct {p0}, Ljava/lang/Object;-><init>()V
- // return-void
- // .end method
- //
- // Output file was hex edited so that static field "i" has string typing in initial values array.
- static const char kDexBase64[] =
- "ZGV4CjAzNQBrMi4cCPcMvvXNRw0uI6RRubwMPwgEYXIsAgAAcAAAAHhWNBIAAAAAAAAAAIwBAAAL"
- "AAAAcAAAAAYAAACcAAAAAQAAALQAAAADAAAAwAAAAAIAAADYAAAAAQAAAOgAAAAkAQAACAEAACAB"
- "AAAoAQAAMAEAADMBAAA2AQAAOwEAAE8BAABjAQAAZgEAAGkBAABsAQAAAgAAAAMAAAAEAAAABQAA"
- "AAYAAAAHAAAABwAAAAUAAAAAAAAAAgAAAAgAAAACAAEACQAAAAIABAAKAAAAAgAAAAAAAAADAAAA"
- "AAAAAAIAAAABAAAAAwAAAAAAAAABAAAAAAAAAHsBAAB0AQAAAQABAAEAAABvAQAABAAAAHAQAQAA"
- "AA4ABjxpbml0PgAGQS5qYXZhAAFDAAFJAANMQTsAEkxqYXZhL2xhbmcvT2JqZWN0OwASTGphdmEv"
- "bGFuZy9TdHJpbmc7AAFWAAFjAAFpAAFzAAEABw4AAwNjFwoXCgMAAQAAGAEYARgAgYAEiAIADQAA"
- "AAAAAAABAAAAAAAAAAEAAAALAAAAcAAAAAIAAAAGAAAAnAAAAAMAAAABAAAAtAAAAAQAAAADAAAA"
- "wAAAAAUAAAACAAAA2AAAAAYAAAABAAAA6AAAAAEgAAABAAAACAEAAAIgAAALAAAAIAEAAAMgAAAB"
- "AAAAbwEAAAUgAAABAAAAdAEAAAAgAAABAAAAewEAAAAQAAABAAAAjAEAAA==";
-
- size_t length;
- std::unique_ptr<uint8_t[]> dex_bytes(DecodeBase64(kDexBase64, &length));
- CHECK(dex_bytes != nullptr);
- // Note: `dex_file` will be destroyed before `dex_bytes`.
- std::unique_ptr<DexFile> dex_file(GetDexFile(dex_bytes.get(), length));
- std::string error_msg;
- EXPECT_FALSE(DexFileVerifier::Verify(dex_file.get(),
- dex_file->Begin(),
- dex_file->Size(),
- "bad static field initial values array",
- /*verify_checksum*/ true,
- &error_msg));
-}
-
-TEST_F(DexFileVerifierTest, GoodStaticFieldInitialValuesArray) {
- // Generated DEX file version (037) from:
- //
- // .class public LGoodStaticFieldInitialValuesArray;
- // .super Ljava/lang/Object;
- //
- // # static fields
- // .field static final b:B = 0x1t
- // .field static final c:C = 'c'
- // .field static final d:D = 0.6
- // .field static final f:F = 0.5f
- // .field static final i:I = 0x3
- // .field static final j:J = 0x4L
- // .field static final l1:Ljava/lang/String;
- // .field static final l2:Ljava/lang/String; = "s"
- // .field static final l3:Ljava/lang/Class; = Ljava/lang/String;
- // .field static final s:S = 0x2s
- // .field static final z:Z = true
- //
- // # direct methods
- // .method public constructor <init>()V
- // .registers 1
- // invoke-direct {p0}, Ljava/lang/Object;-><init>()V
- // return-void
- // .end method
- static const char kDexBase64[] =
- "ZGV4CjAzNQAwWxLbdhFa1NGiFWjsy5fhUCHxe5QHtPY8AwAAcAAAAHhWNBIAAAAAAAAAAJwCAAAZ"
- "AAAAcAAAAA0AAADUAAAAAQAAAAgBAAALAAAAFAEAAAIAAABsAQAAAQAAAHwBAACgAQAAnAEAAJwB"
- "AACkAQAApwEAAKoBAACtAQAAsAEAALMBAAC2AQAA2wEAAO4BAAACAgAAFgIAABkCAAAcAgAAHwIA"
- "ACICAAAlAgAAKAIAACsCAAAuAgAAMQIAADUCAAA5AgAAPQIAAEACAAABAAAAAgAAAAMAAAAEAAAA"
- "BQAAAAYAAAAHAAAACAAAAAkAAAAKAAAACwAAAAwAAAANAAAADAAAAAsAAAAAAAAABgAAAA4AAAAG"
- "AAEADwAAAAYAAgAQAAAABgADABEAAAAGAAQAEgAAAAYABQATAAAABgAJABQAAAAGAAkAFQAAAAYA"
- "BwAWAAAABgAKABcAAAAGAAwAGAAAAAYAAAAAAAAACAAAAAAAAAAGAAAAAQAAAAgAAAAAAAAA////"
- "/wAAAAB8AgAARAIAAAY8aW5pdD4AAUIAAUMAAUQAAUYAAUkAAUoAI0xHb29kU3RhdGljRmllbGRJ"
- "bml0aWFsVmFsdWVzQXJyYXk7ABFMamF2YS9sYW5nL0NsYXNzOwASTGphdmEvbGFuZy9PYmplY3Q7"
- "ABJMamF2YS9sYW5nL1N0cmluZzsAAVMAAVYAAVoAAWIAAWMAAWQAAWYAAWkAAWoAAmwxAAJsMgAC"
- "bDMAAXMAAXoAAAsAAQNj8TMzMzMzM+M/ED8EAwYEHhcXGAkCAj8AAAAAAQABAAEAAAAAAAAABAAA"
- "AHAQAQAAAA4ACwABAAAYARgBGAEYARgBGAEYARgBGAEYARgAgYAE5AQNAAAAAAAAAAEAAAAAAAAA"
- "AQAAABkAAABwAAAAAgAAAA0AAADUAAAAAwAAAAEAAAAIAQAABAAAAAsAAAAUAQAABQAAAAIAAABs"
- "AQAABgAAAAEAAAB8AQAAAiAAABkAAACcAQAABSAAAAEAAABEAgAAAxAAAAEAAABgAgAAASAAAAEA"
- "AABkAgAAACAAAAEAAAB8AgAAABAAAAEAAACcAgAA";
-
- size_t length;
- std::unique_ptr<uint8_t[]> dex_bytes(DecodeBase64(kDexBase64, &length));
- CHECK(dex_bytes != nullptr);
- // Note: `dex_file` will be destroyed before `dex_bytes`.
- std::unique_ptr<DexFile> dex_file(GetDexFile(dex_bytes.get(), length));
- std::string error_msg;
- EXPECT_TRUE(DexFileVerifier::Verify(dex_file.get(),
- dex_file->Begin(),
- dex_file->Size(),
- "good static field initial values array",
- /*verify_checksum*/ true,
- &error_msg));
-}
-
-} // namespace art
diff --git a/runtime/dex/dex_instruction-inl.h b/runtime/dex/dex_instruction-inl.h
deleted file mode 100644
index a6b8414e62..0000000000
--- a/runtime/dex/dex_instruction-inl.h
+++ /dev/null
@@ -1,558 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ART_RUNTIME_DEX_DEX_INSTRUCTION_INL_H_
-#define ART_RUNTIME_DEX_DEX_INSTRUCTION_INL_H_
-
-#include "dex_instruction.h"
-
-namespace art {
-
-//------------------------------------------------------------------------------
-// VRegA
-//------------------------------------------------------------------------------
-inline bool Instruction::HasVRegA() const {
- switch (FormatOf(Opcode())) {
- case k10t: return true;
- case k10x: return true;
- case k11n: return true;
- case k11x: return true;
- case k12x: return true;
- case k20t: return true;
- case k21c: return true;
- case k21h: return true;
- case k21s: return true;
- case k21t: return true;
- case k22b: return true;
- case k22c: return true;
- case k22s: return true;
- case k22t: return true;
- case k22x: return true;
- case k23x: return true;
- case k30t: return true;
- case k31c: return true;
- case k31i: return true;
- case k31t: return true;
- case k32x: return true;
- case k35c: return true;
- case k3rc: return true;
- case k45cc: return true;
- case k4rcc: return true;
- case k51l: return true;
- default: return false;
- }
-}
-
-inline int32_t Instruction::VRegA() const {
- switch (FormatOf(Opcode())) {
- case k10t: return VRegA_10t();
- case k10x: return VRegA_10x();
- case k11n: return VRegA_11n();
- case k11x: return VRegA_11x();
- case k12x: return VRegA_12x();
- case k20t: return VRegA_20t();
- case k21c: return VRegA_21c();
- case k21h: return VRegA_21h();
- case k21s: return VRegA_21s();
- case k21t: return VRegA_21t();
- case k22b: return VRegA_22b();
- case k22c: return VRegA_22c();
- case k22s: return VRegA_22s();
- case k22t: return VRegA_22t();
- case k22x: return VRegA_22x();
- case k23x: return VRegA_23x();
- case k30t: return VRegA_30t();
- case k31c: return VRegA_31c();
- case k31i: return VRegA_31i();
- case k31t: return VRegA_31t();
- case k32x: return VRegA_32x();
- case k35c: return VRegA_35c();
- case k3rc: return VRegA_3rc();
- case k45cc: return VRegA_45cc();
- case k4rcc: return VRegA_4rcc();
- case k51l: return VRegA_51l();
- default:
- LOG(FATAL) << "Tried to access vA of instruction " << Name() << " which has no A operand.";
- exit(EXIT_FAILURE);
- }
-}
-
-inline int8_t Instruction::VRegA_10t(uint16_t inst_data) const {
- DCHECK_EQ(FormatOf(Opcode()), k10t);
- return static_cast<int8_t>(InstAA(inst_data));
-}
-
-inline uint8_t Instruction::VRegA_10x(uint16_t inst_data) const {
- DCHECK_EQ(FormatOf(Opcode()), k10x);
- return InstAA(inst_data);
-}
-
-inline uint4_t Instruction::VRegA_11n(uint16_t inst_data) const {
- DCHECK_EQ(FormatOf(Opcode()), k11n);
- return InstA(inst_data);
-}
-
-inline uint8_t Instruction::VRegA_11x(uint16_t inst_data) const {
- DCHECK_EQ(FormatOf(Opcode()), k11x);
- return InstAA(inst_data);
-}
-
-inline uint4_t Instruction::VRegA_12x(uint16_t inst_data) const {
- DCHECK_EQ(FormatOf(Opcode()), k12x);
- return InstA(inst_data);
-}
-
-inline int16_t Instruction::VRegA_20t() const {
- DCHECK_EQ(FormatOf(Opcode()), k20t);
- return static_cast<int16_t>(Fetch16(1));
-}
-
-inline uint8_t Instruction::VRegA_21c(uint16_t inst_data) const {
- DCHECK_EQ(FormatOf(Opcode()), k21c);
- return InstAA(inst_data);
-}
-
-inline uint8_t Instruction::VRegA_21h(uint16_t inst_data) const {
- DCHECK_EQ(FormatOf(Opcode()), k21h);
- return InstAA(inst_data);
-}
-
-inline uint8_t Instruction::VRegA_21s(uint16_t inst_data) const {
- DCHECK_EQ(FormatOf(Opcode()), k21s);
- return InstAA(inst_data);
-}
-
-inline uint8_t Instruction::VRegA_21t(uint16_t inst_data) const {
- DCHECK_EQ(FormatOf(Opcode()), k21t);
- return InstAA(inst_data);
-}
-
-inline uint8_t Instruction::VRegA_22b(uint16_t inst_data) const {
- DCHECK_EQ(FormatOf(Opcode()), k22b);
- return InstAA(inst_data);
-}
-
-inline uint4_t Instruction::VRegA_22c(uint16_t inst_data) const {
- DCHECK_EQ(FormatOf(Opcode()), k22c);
- return InstA(inst_data);
-}
-
-inline uint4_t Instruction::VRegA_22s(uint16_t inst_data) const {
- DCHECK_EQ(FormatOf(Opcode()), k22s);
- return InstA(inst_data);
-}
-
-inline uint4_t Instruction::VRegA_22t(uint16_t inst_data) const {
- DCHECK_EQ(FormatOf(Opcode()), k22t);
- return InstA(inst_data);
-}
-
-inline uint8_t Instruction::VRegA_22x(uint16_t inst_data) const {
- DCHECK_EQ(FormatOf(Opcode()), k22x);
- return InstAA(inst_data);
-}
-
-inline uint8_t Instruction::VRegA_23x(uint16_t inst_data) const {
- DCHECK_EQ(FormatOf(Opcode()), k23x);
- return InstAA(inst_data);
-}
-
-inline int32_t Instruction::VRegA_30t() const {
- DCHECK_EQ(FormatOf(Opcode()), k30t);
- return static_cast<int32_t>(Fetch32(1));
-}
-
-inline uint8_t Instruction::VRegA_31c(uint16_t inst_data) const {
- DCHECK_EQ(FormatOf(Opcode()), k31c);
- return InstAA(inst_data);
-}
-
-inline uint8_t Instruction::VRegA_31i(uint16_t inst_data) const {
- DCHECK_EQ(FormatOf(Opcode()), k31i);
- return InstAA(inst_data);
-}
-
-inline uint8_t Instruction::VRegA_31t(uint16_t inst_data) const {
- DCHECK_EQ(FormatOf(Opcode()), k31t);
- return InstAA(inst_data);
-}
-
-inline uint16_t Instruction::VRegA_32x() const {
- DCHECK_EQ(FormatOf(Opcode()), k32x);
- return Fetch16(1);
-}
-
-inline uint4_t Instruction::VRegA_35c(uint16_t inst_data) const {
- DCHECK_EQ(FormatOf(Opcode()), k35c);
- return InstB(inst_data); // This is labeled A in the spec.
-}
-
-inline uint8_t Instruction::VRegA_3rc(uint16_t inst_data) const {
- DCHECK_EQ(FormatOf(Opcode()), k3rc);
- return InstAA(inst_data);
-}
-
-inline uint8_t Instruction::VRegA_51l(uint16_t inst_data) const {
- DCHECK_EQ(FormatOf(Opcode()), k51l);
- return InstAA(inst_data);
-}
-
-inline uint4_t Instruction::VRegA_45cc(uint16_t inst_data) const {
- DCHECK_EQ(FormatOf(Opcode()), k45cc);
- return InstB(inst_data); // This is labeled A in the spec.
-}
-
-inline uint8_t Instruction::VRegA_4rcc(uint16_t inst_data) const {
- DCHECK_EQ(FormatOf(Opcode()), k4rcc);
- return InstAA(inst_data);
-}
-
-//------------------------------------------------------------------------------
-// VRegB
-//------------------------------------------------------------------------------
-inline bool Instruction::HasVRegB() const {
- switch (FormatOf(Opcode())) {
- case k11n: return true;
- case k12x: return true;
- case k21c: return true;
- case k21h: return true;
- case k21s: return true;
- case k21t: return true;
- case k22b: return true;
- case k22c: return true;
- case k22s: return true;
- case k22t: return true;
- case k22x: return true;
- case k23x: return true;
- case k31c: return true;
- case k31i: return true;
- case k31t: return true;
- case k32x: return true;
- case k35c: return true;
- case k3rc: return true;
- case k45cc: return true;
- case k4rcc: return true;
- case k51l: return true;
- default: return false;
- }
-}
-
-inline bool Instruction::HasWideVRegB() const {
- return FormatOf(Opcode()) == k51l;
-}
-
-inline int32_t Instruction::VRegB() const {
- switch (FormatOf(Opcode())) {
- case k11n: return VRegB_11n();
- case k12x: return VRegB_12x();
- case k21c: return VRegB_21c();
- case k21h: return VRegB_21h();
- case k21s: return VRegB_21s();
- case k21t: return VRegB_21t();
- case k22b: return VRegB_22b();
- case k22c: return VRegB_22c();
- case k22s: return VRegB_22s();
- case k22t: return VRegB_22t();
- case k22x: return VRegB_22x();
- case k23x: return VRegB_23x();
- case k31c: return VRegB_31c();
- case k31i: return VRegB_31i();
- case k31t: return VRegB_31t();
- case k32x: return VRegB_32x();
- case k35c: return VRegB_35c();
- case k3rc: return VRegB_3rc();
- case k45cc: return VRegB_45cc();
- case k4rcc: return VRegB_4rcc();
- case k51l: return VRegB_51l();
- default:
- LOG(FATAL) << "Tried to access vB of instruction " << Name() << " which has no B operand.";
- exit(EXIT_FAILURE);
- }
-}
-
-inline uint64_t Instruction::WideVRegB() const {
- return VRegB_51l();
-}
-
-inline int4_t Instruction::VRegB_11n(uint16_t inst_data) const {
- DCHECK_EQ(FormatOf(Opcode()), k11n);
- return static_cast<int4_t>((InstB(inst_data) << 28) >> 28);
-}
-
-inline uint4_t Instruction::VRegB_12x(uint16_t inst_data) const {
- DCHECK_EQ(FormatOf(Opcode()), k12x);
- return InstB(inst_data);
-}
-
-inline uint16_t Instruction::VRegB_21c() const {
- DCHECK_EQ(FormatOf(Opcode()), k21c);
- return Fetch16(1);
-}
-
-inline uint16_t Instruction::VRegB_21h() const {
- DCHECK_EQ(FormatOf(Opcode()), k21h);
- return Fetch16(1);
-}
-
-inline int16_t Instruction::VRegB_21s() const {
- DCHECK_EQ(FormatOf(Opcode()), k21s);
- return static_cast<int16_t>(Fetch16(1));
-}
-
-inline int16_t Instruction::VRegB_21t() const {
- DCHECK_EQ(FormatOf(Opcode()), k21t);
- return static_cast<int16_t>(Fetch16(1));
-}
-
-inline uint8_t Instruction::VRegB_22b() const {
- DCHECK_EQ(FormatOf(Opcode()), k22b);
- return static_cast<uint8_t>(Fetch16(1) & 0xff);
-}
-
-inline uint4_t Instruction::VRegB_22c(uint16_t inst_data) const {
- DCHECK_EQ(FormatOf(Opcode()), k22c);
- return InstB(inst_data);
-}
-
-inline uint4_t Instruction::VRegB_22s(uint16_t inst_data) const {
- DCHECK_EQ(FormatOf(Opcode()), k22s);
- return InstB(inst_data);
-}
-
-inline uint4_t Instruction::VRegB_22t(uint16_t inst_data) const {
- DCHECK_EQ(FormatOf(Opcode()), k22t);
- return InstB(inst_data);
-}
-
-inline uint16_t Instruction::VRegB_22x() const {
- DCHECK_EQ(FormatOf(Opcode()), k22x);
- return Fetch16(1);
-}
-
-inline uint8_t Instruction::VRegB_23x() const {
- DCHECK_EQ(FormatOf(Opcode()), k23x);
- return static_cast<uint8_t>(Fetch16(1) & 0xff);
-}
-
-inline uint32_t Instruction::VRegB_31c() const {
- DCHECK_EQ(FormatOf(Opcode()), k31c);
- return Fetch32(1);
-}
-
-inline int32_t Instruction::VRegB_31i() const {
- DCHECK_EQ(FormatOf(Opcode()), k31i);
- return static_cast<int32_t>(Fetch32(1));
-}
-
-inline int32_t Instruction::VRegB_31t() const {
- DCHECK_EQ(FormatOf(Opcode()), k31t);
- return static_cast<int32_t>(Fetch32(1));
-}
-
-inline uint16_t Instruction::VRegB_32x() const {
- DCHECK_EQ(FormatOf(Opcode()), k32x);
- return Fetch16(2);
-}
-
-inline uint16_t Instruction::VRegB_35c() const {
- DCHECK_EQ(FormatOf(Opcode()), k35c);
- return Fetch16(1);
-}
-
-inline uint16_t Instruction::VRegB_3rc() const {
- DCHECK_EQ(FormatOf(Opcode()), k3rc);
- return Fetch16(1);
-}
-
-inline uint16_t Instruction::VRegB_45cc() const {
- DCHECK_EQ(FormatOf(Opcode()), k45cc);
- return Fetch16(1);
-}
-
-inline uint16_t Instruction::VRegB_4rcc() const {
- DCHECK_EQ(FormatOf(Opcode()), k4rcc);
- return Fetch16(1);
-}
-
-inline uint64_t Instruction::VRegB_51l() const {
- DCHECK_EQ(FormatOf(Opcode()), k51l);
- uint64_t vB_wide = Fetch32(1) | ((uint64_t) Fetch32(3) << 32);
- return vB_wide;
-}
-
-//------------------------------------------------------------------------------
-// VRegC
-//------------------------------------------------------------------------------
-inline bool Instruction::HasVRegC() const {
- switch (FormatOf(Opcode())) {
- case k22b: return true;
- case k22c: return true;
- case k22s: return true;
- case k22t: return true;
- case k23x: return true;
- case k35c: return true;
- case k3rc: return true;
- case k45cc: return true;
- case k4rcc: return true;
- default: return false;
- }
-}
-
-inline int32_t Instruction::VRegC() const {
- switch (FormatOf(Opcode())) {
- case k22b: return VRegC_22b();
- case k22c: return VRegC_22c();
- case k22s: return VRegC_22s();
- case k22t: return VRegC_22t();
- case k23x: return VRegC_23x();
- case k35c: return VRegC_35c();
- case k3rc: return VRegC_3rc();
- case k45cc: return VRegC_45cc();
- case k4rcc: return VRegC_4rcc();
- default:
- LOG(FATAL) << "Tried to access vC of instruction " << Name() << " which has no C operand.";
- exit(EXIT_FAILURE);
- }
-}
-
-inline int8_t Instruction::VRegC_22b() const {
- DCHECK_EQ(FormatOf(Opcode()), k22b);
- return static_cast<int8_t>(Fetch16(1) >> 8);
-}
-
-inline uint16_t Instruction::VRegC_22c() const {
- DCHECK_EQ(FormatOf(Opcode()), k22c);
- return Fetch16(1);
-}
-
-inline int16_t Instruction::VRegC_22s() const {
- DCHECK_EQ(FormatOf(Opcode()), k22s);
- return static_cast<int16_t>(Fetch16(1));
-}
-
-inline int16_t Instruction::VRegC_22t() const {
- DCHECK_EQ(FormatOf(Opcode()), k22t);
- return static_cast<int16_t>(Fetch16(1));
-}
-
-inline uint8_t Instruction::VRegC_23x() const {
- DCHECK_EQ(FormatOf(Opcode()), k23x);
- return static_cast<uint8_t>(Fetch16(1) >> 8);
-}
-
-inline uint4_t Instruction::VRegC_35c() const {
- DCHECK_EQ(FormatOf(Opcode()), k35c);
- return static_cast<uint4_t>(Fetch16(2) & 0x0f);
-}
-
-inline uint16_t Instruction::VRegC_3rc() const {
- DCHECK_EQ(FormatOf(Opcode()), k3rc);
- return Fetch16(2);
-}
-
-inline uint4_t Instruction::VRegC_45cc() const {
- DCHECK_EQ(FormatOf(Opcode()), k45cc);
- return static_cast<uint4_t>(Fetch16(2) & 0x0f);
-}
-
-inline uint16_t Instruction::VRegC_4rcc() const {
- DCHECK_EQ(FormatOf(Opcode()), k4rcc);
- return Fetch16(2);
-}
-
-//------------------------------------------------------------------------------
-// VRegH
-//------------------------------------------------------------------------------
-inline bool Instruction::HasVRegH() const {
- switch (FormatOf(Opcode())) {
- case k45cc: return true;
- case k4rcc: return true;
- default : return false;
- }
-}
-
-inline int32_t Instruction::VRegH() const {
- switch (FormatOf(Opcode())) {
- case k45cc: return VRegH_45cc();
- case k4rcc: return VRegH_4rcc();
- default :
- LOG(FATAL) << "Tried to access vH of instruction " << Name() << " which has no H operand.";
- exit(EXIT_FAILURE);
- }
-}
-
-inline uint16_t Instruction::VRegH_45cc() const {
- DCHECK_EQ(FormatOf(Opcode()), k45cc);
- return Fetch16(3);
-}
-
-inline uint16_t Instruction::VRegH_4rcc() const {
- DCHECK_EQ(FormatOf(Opcode()), k4rcc);
- return Fetch16(3);
-}
-
-inline bool Instruction::HasVarArgs() const {
- return (FormatOf(Opcode()) == k35c) || (FormatOf(Opcode()) == k45cc);
-}
-
-inline void Instruction::GetVarArgs(uint32_t arg[kMaxVarArgRegs], uint16_t inst_data) const {
- DCHECK(HasVarArgs());
-
- /*
- * Note that the fields mentioned in the spec don't appear in
- * their "usual" positions here compared to most formats. This
- * was done so that the field names for the argument count and
- * reference index match between this format and the corresponding
- * range formats (3rc and friends).
- *
- * Bottom line: The argument count is always in vA, and the
- * method constant (or equivalent) is always in vB.
- */
- uint16_t regList = Fetch16(2);
- uint4_t count = InstB(inst_data); // This is labeled A in the spec.
- DCHECK_LE(count, 5U) << "Invalid arg count in 35c (" << count << ")";
-
- /*
- * Copy the argument registers into the arg[] array, and
- * also copy the first argument (if any) into vC. (The
- * DecodedInstruction structure doesn't have separate
- * fields for {vD, vE, vF, vG}, so there's no need to make
- * copies of those.) Note that cases 5..2 fall through.
- */
- switch (count) {
- case 5:
- arg[4] = InstA(inst_data);
- FALLTHROUGH_INTENDED;
- case 4:
- arg[3] = (regList >> 12) & 0x0f;
- FALLTHROUGH_INTENDED;
- case 3:
- arg[2] = (regList >> 8) & 0x0f;
- FALLTHROUGH_INTENDED;
- case 2:
- arg[1] = (regList >> 4) & 0x0f;
- FALLTHROUGH_INTENDED;
- case 1:
- arg[0] = regList & 0x0f;
- break;
- default: // case 0
- break; // Valid, but no need to do anything.
- }
-}
-
-} // namespace art
-
-#endif // ART_RUNTIME_DEX_DEX_INSTRUCTION_INL_H_
diff --git a/runtime/dex/dex_instruction.cc b/runtime/dex/dex_instruction.cc
deleted file mode 100644
index b84791ffae..0000000000
--- a/runtime/dex/dex_instruction.cc
+++ /dev/null
@@ -1,561 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "dex_instruction-inl.h"
-
-#include <inttypes.h>
-
-#include <iomanip>
-#include <sstream>
-
-#include "android-base/stringprintf.h"
-
-#include "dex_file-inl.h"
-#include "utf.h"
-
-namespace art {
-
-using android::base::StringPrintf;
-
-const char* const Instruction::kInstructionNames[] = {
-#define INSTRUCTION_NAME(o, c, pname, f, i, a, e, v) pname,
-#include "dex_instruction_list.h"
- DEX_INSTRUCTION_LIST(INSTRUCTION_NAME)
-#undef DEX_INSTRUCTION_LIST
-#undef INSTRUCTION_NAME
-};
-
-static_assert(sizeof(Instruction::InstructionDescriptor) == 8u, "Unexpected descriptor size");
-
-static constexpr int8_t InstructionSizeInCodeUnitsByOpcode(Instruction::Code opcode,
- Instruction::Format format) {
- if (opcode == Instruction::Code::NOP) {
- return -1;
- } else if ((format >= Instruction::Format::k10x) && (format <= Instruction::Format::k10t)) {
- return 1;
- } else if ((format >= Instruction::Format::k20t) && (format <= Instruction::Format::k22c)) {
- return 2;
- } else if ((format >= Instruction::Format::k32x) && (format <= Instruction::Format::k3rc)) {
- return 3;
- } else if ((format >= Instruction::Format::k45cc) && (format <= Instruction::Format::k4rcc)) {
- return 4;
- } else if (format == Instruction::Format::k51l) {
- return 5;
- } else {
- return -1;
- }
-}
-
-Instruction::InstructionDescriptor const Instruction::kInstructionDescriptors[] = {
-#define INSTRUCTION_DESCR(opcode, c, p, format, index, flags, eflags, vflags) \
- { vflags, \
- format, \
- index, \
- flags, \
- InstructionSizeInCodeUnitsByOpcode((c), (format)), \
- },
-#include "dex_instruction_list.h"
- DEX_INSTRUCTION_LIST(INSTRUCTION_DESCR)
-#undef DEX_INSTRUCTION_LIST
-#undef INSTRUCTION_DESCR
-};
-
-int32_t Instruction::GetTargetOffset() const {
- switch (FormatOf(Opcode())) {
- // Cases for conditional branches follow.
- case k22t: return VRegC_22t();
- case k21t: return VRegB_21t();
- // Cases for unconditional branches follow.
- case k10t: return VRegA_10t();
- case k20t: return VRegA_20t();
- case k30t: return VRegA_30t();
- default: LOG(FATAL) << "Tried to access the branch offset of an instruction " << Name() <<
- " which does not have a target operand.";
- }
- return 0;
-}
-
-bool Instruction::CanFlowThrough() const {
- const uint16_t* insns = reinterpret_cast<const uint16_t*>(this);
- uint16_t insn = *insns;
- Code opcode = static_cast<Code>(insn & 0xFF);
- return FlagsOf(opcode) & Instruction::kContinue;
-}
-
-size_t Instruction::SizeInCodeUnitsComplexOpcode() const {
- const uint16_t* insns = reinterpret_cast<const uint16_t*>(this);
- // Handle special NOP encoded variable length sequences.
- switch (*insns) {
- case kPackedSwitchSignature:
- return (4 + insns[1] * 2);
- case kSparseSwitchSignature:
- return (2 + insns[1] * 4);
- case kArrayDataSignature: {
- uint16_t element_size = insns[1];
- uint32_t length = insns[2] | (((uint32_t)insns[3]) << 16);
- // The plus 1 is to round up for odd size and width.
- return (4 + (element_size * length + 1) / 2);
- }
- default:
- if ((*insns & 0xFF) == 0) {
- return 1; // NOP.
- } else {
- LOG(FATAL) << "Unreachable: " << DumpString(nullptr);
- UNREACHABLE();
- }
- }
-}
-
-size_t Instruction::CodeUnitsRequiredForSizeOfComplexOpcode() const {
- const uint16_t* insns = reinterpret_cast<const uint16_t*>(this);
- // Handle special NOP encoded variable length sequences.
- switch (*insns) {
- case kPackedSwitchSignature:
- FALLTHROUGH_INTENDED;
- case kSparseSwitchSignature:
- return 2;
- case kArrayDataSignature:
- return 4;
- default:
- if ((*insns & 0xFF) == 0) {
- return 1; // NOP.
- } else {
- LOG(FATAL) << "Unreachable: " << DumpString(nullptr);
- UNREACHABLE();
- }
- }
-}
-
-std::string Instruction::DumpHex(size_t code_units) const {
- size_t inst_length = SizeInCodeUnits();
- if (inst_length > code_units) {
- inst_length = code_units;
- }
- std::ostringstream os;
- const uint16_t* insn = reinterpret_cast<const uint16_t*>(this);
- for (size_t i = 0; i < inst_length; i++) {
- os << StringPrintf("0x%04x", insn[i]) << " ";
- }
- for (size_t i = inst_length; i < code_units; i++) {
- os << " ";
- }
- return os.str();
-}
-
-std::string Instruction::DumpHexLE(size_t instr_code_units) const {
- size_t inst_length = SizeInCodeUnits();
- if (inst_length > instr_code_units) {
- inst_length = instr_code_units;
- }
- std::ostringstream os;
- const uint16_t* insn = reinterpret_cast<const uint16_t*>(this);
- for (size_t i = 0; i < inst_length; i++) {
- os << StringPrintf("%02x%02x", static_cast<uint8_t>(insn[i] & 0x00FF),
- static_cast<uint8_t>((insn[i] & 0xFF00) >> 8)) << " ";
- }
- for (size_t i = inst_length; i < instr_code_units; i++) {
- os << " ";
- }
- return os.str();
-}
-
-std::string Instruction::DumpString(const DexFile* file) const {
- std::ostringstream os;
- const char* opcode = kInstructionNames[Opcode()];
- switch (FormatOf(Opcode())) {
- case k10x: os << opcode; break;
- case k12x: os << StringPrintf("%s v%d, v%d", opcode, VRegA_12x(), VRegB_12x()); break;
- case k11n: os << StringPrintf("%s v%d, #%+d", opcode, VRegA_11n(), VRegB_11n()); break;
- case k11x: os << StringPrintf("%s v%d", opcode, VRegA_11x()); break;
- case k10t: os << StringPrintf("%s %+d", opcode, VRegA_10t()); break;
- case k20t: os << StringPrintf("%s %+d", opcode, VRegA_20t()); break;
- case k22x: os << StringPrintf("%s v%d, v%d", opcode, VRegA_22x(), VRegB_22x()); break;
- case k21t: os << StringPrintf("%s v%d, %+d", opcode, VRegA_21t(), VRegB_21t()); break;
- case k21s: os << StringPrintf("%s v%d, #%+d", opcode, VRegA_21s(), VRegB_21s()); break;
- case k21h: {
- // op vAA, #+BBBB0000[00000000]
- if (Opcode() == CONST_HIGH16) {
- uint32_t value = VRegB_21h() << 16;
- os << StringPrintf("%s v%d, #int %+d // 0x%x", opcode, VRegA_21h(), value, value);
- } else {
- uint64_t value = static_cast<uint64_t>(VRegB_21h()) << 48;
- os << StringPrintf("%s v%d, #long %+" PRId64 " // 0x%" PRIx64, opcode, VRegA_21h(),
- value, value);
- }
- }
- break;
- case k21c: {
- switch (Opcode()) {
- case CONST_STRING:
- if (file != nullptr) {
- uint32_t string_idx = VRegB_21c();
- if (string_idx < file->NumStringIds()) {
- os << StringPrintf(
- "const-string v%d, %s // string@%d",
- VRegA_21c(),
- PrintableString(file->StringDataByIdx(dex::StringIndex(string_idx))).c_str(),
- string_idx);
- } else {
- os << StringPrintf("const-string v%d, <<invalid-string-idx-%d>> // string@%d",
- VRegA_21c(),
- string_idx,
- string_idx);
- }
- break;
- }
- FALLTHROUGH_INTENDED;
- case CHECK_CAST:
- case CONST_CLASS:
- case NEW_INSTANCE:
- if (file != nullptr) {
- dex::TypeIndex type_idx(VRegB_21c());
- os << opcode << " v" << static_cast<int>(VRegA_21c()) << ", "
- << file->PrettyType(type_idx) << " // type@" << type_idx;
- break;
- }
- FALLTHROUGH_INTENDED;
- case SGET:
- case SGET_WIDE:
- case SGET_OBJECT:
- case SGET_BOOLEAN:
- case SGET_BYTE:
- case SGET_CHAR:
- case SGET_SHORT:
- if (file != nullptr) {
- uint32_t field_idx = VRegB_21c();
- os << opcode << " v" << static_cast<int>(VRegA_21c()) << ", " << file->PrettyField(field_idx, true)
- << " // field@" << field_idx;
- break;
- }
- FALLTHROUGH_INTENDED;
- case SPUT:
- case SPUT_WIDE:
- case SPUT_OBJECT:
- case SPUT_BOOLEAN:
- case SPUT_BYTE:
- case SPUT_CHAR:
- case SPUT_SHORT:
- if (file != nullptr) {
- uint32_t field_idx = VRegB_21c();
- os << opcode << " v" << static_cast<int>(VRegA_21c()) << ", " << file->PrettyField(field_idx, true)
- << " // field@" << field_idx;
- break;
- }
- FALLTHROUGH_INTENDED;
- default:
- os << StringPrintf("%s v%d, thing@%d", opcode, VRegA_21c(), VRegB_21c());
- break;
- }
- break;
- }
- case k23x: os << StringPrintf("%s v%d, v%d, v%d", opcode, VRegA_23x(), VRegB_23x(), VRegC_23x()); break;
- case k22b: os << StringPrintf("%s v%d, v%d, #%+d", opcode, VRegA_22b(), VRegB_22b(), VRegC_22b()); break;
- case k22t: os << StringPrintf("%s v%d, v%d, %+d", opcode, VRegA_22t(), VRegB_22t(), VRegC_22t()); break;
- case k22s: os << StringPrintf("%s v%d, v%d, #%+d", opcode, VRegA_22s(), VRegB_22s(), VRegC_22s()); break;
- case k22c: {
- switch (Opcode()) {
- case IGET:
- case IGET_WIDE:
- case IGET_OBJECT:
- case IGET_BOOLEAN:
- case IGET_BYTE:
- case IGET_CHAR:
- case IGET_SHORT:
- if (file != nullptr) {
- uint32_t field_idx = VRegC_22c();
- os << opcode << " v" << static_cast<int>(VRegA_22c()) << ", v" << static_cast<int>(VRegB_22c()) << ", "
- << file->PrettyField(field_idx, true) << " // field@" << field_idx;
- break;
- }
- FALLTHROUGH_INTENDED;
- case IGET_QUICK:
- case IGET_OBJECT_QUICK:
- if (file != nullptr) {
- uint32_t field_idx = VRegC_22c();
- os << opcode << " v" << static_cast<int>(VRegA_22c()) << ", v" << static_cast<int>(VRegB_22c()) << ", "
- << "// offset@" << field_idx;
- break;
- }
- FALLTHROUGH_INTENDED;
- case IPUT:
- case IPUT_WIDE:
- case IPUT_OBJECT:
- case IPUT_BOOLEAN:
- case IPUT_BYTE:
- case IPUT_CHAR:
- case IPUT_SHORT:
- if (file != nullptr) {
- uint32_t field_idx = VRegC_22c();
- os << opcode << " v" << static_cast<int>(VRegA_22c()) << ", v" << static_cast<int>(VRegB_22c()) << ", "
- << file->PrettyField(field_idx, true) << " // field@" << field_idx;
- break;
- }
- FALLTHROUGH_INTENDED;
- case IPUT_QUICK:
- case IPUT_OBJECT_QUICK:
- if (file != nullptr) {
- uint32_t field_idx = VRegC_22c();
- os << opcode << " v" << static_cast<int>(VRegA_22c()) << ", v" << static_cast<int>(VRegB_22c()) << ", "
- << "// offset@" << field_idx;
- break;
- }
- FALLTHROUGH_INTENDED;
- case INSTANCE_OF:
- if (file != nullptr) {
- dex::TypeIndex type_idx(VRegC_22c());
- os << opcode << " v" << static_cast<int>(VRegA_22c()) << ", v"
- << static_cast<int>(VRegB_22c()) << ", " << file->PrettyType(type_idx)
- << " // type@" << type_idx.index_;
- break;
- }
- FALLTHROUGH_INTENDED;
- case NEW_ARRAY:
- if (file != nullptr) {
- dex::TypeIndex type_idx(VRegC_22c());
- os << opcode << " v" << static_cast<int>(VRegA_22c()) << ", v"
- << static_cast<int>(VRegB_22c()) << ", " << file->PrettyType(type_idx)
- << " // type@" << type_idx.index_;
- break;
- }
- FALLTHROUGH_INTENDED;
- default:
- os << StringPrintf("%s v%d, v%d, thing@%d", opcode, VRegA_22c(), VRegB_22c(), VRegC_22c());
- break;
- }
- break;
- }
- case k32x: os << StringPrintf("%s v%d, v%d", opcode, VRegA_32x(), VRegB_32x()); break;
- case k30t: os << StringPrintf("%s %+d", opcode, VRegA_30t()); break;
- case k31t: os << StringPrintf("%s v%d, %+d", opcode, VRegA_31t(), VRegB_31t()); break;
- case k31i: os << StringPrintf("%s v%d, #%+d", opcode, VRegA_31i(), VRegB_31i()); break;
- case k31c:
- if (Opcode() == CONST_STRING_JUMBO) {
- uint32_t string_idx = VRegB_31c();
- if (file != nullptr) {
- if (string_idx < file->NumStringIds()) {
- os << StringPrintf(
- "%s v%d, %s // string@%d",
- opcode,
- VRegA_31c(),
- PrintableString(file->StringDataByIdx(dex::StringIndex(string_idx))).c_str(),
- string_idx);
- } else {
- os << StringPrintf("%s v%d, <<invalid-string-idx-%d>> // string@%d",
- opcode,
- VRegA_31c(),
- string_idx,
- string_idx);
- }
- } else {
- os << StringPrintf("%s v%d, string@%d", opcode, VRegA_31c(), string_idx);
- }
- } else {
- os << StringPrintf("%s v%d, thing@%d", opcode, VRegA_31c(), VRegB_31c()); break;
- }
- break;
- case k35c: {
- uint32_t arg[kMaxVarArgRegs];
- GetVarArgs(arg);
- auto DumpArgs = [&](size_t count) {
- for (size_t i = 0; i < count; ++i) {
- if (i != 0) {
- os << ", ";
- }
- os << "v" << arg[i];
- }
- };
- switch (Opcode()) {
- case FILLED_NEW_ARRAY:
- {
- os << opcode << " {";
- DumpArgs(VRegA_35c());
- os << "}, type@" << VRegB_35c();
- }
- break;
-
- case INVOKE_VIRTUAL:
- case INVOKE_SUPER:
- case INVOKE_DIRECT:
- case INVOKE_STATIC:
- case INVOKE_INTERFACE:
- if (file != nullptr) {
- os << opcode << " {";
- uint32_t method_idx = VRegB_35c();
- DumpArgs(VRegA_35c());
- os << "}, " << file->PrettyMethod(method_idx) << " // method@" << method_idx;
- break;
- }
- FALLTHROUGH_INTENDED;
- case INVOKE_VIRTUAL_QUICK:
- if (file != nullptr) {
- os << opcode << " {";
- uint32_t method_idx = VRegB_35c();
- DumpArgs(VRegA_35c());
- os << "}, // vtable@" << method_idx;
- break;
- }
- FALLTHROUGH_INTENDED;
- case INVOKE_CUSTOM:
- if (file != nullptr) {
- os << opcode << " {";
- uint32_t call_site_idx = VRegB_35c();
- DumpArgs(VRegA_35c());
- os << "}, // call_site@" << call_site_idx;
- break;
- }
- FALLTHROUGH_INTENDED;
- default:
- os << opcode << " {";
- DumpArgs(VRegA_35c());
- os << "}, thing@" << VRegB_35c();
- break;
- }
- break;
- }
- case k3rc: {
- uint16_t first_reg = VRegC_3rc();
- uint16_t last_reg = VRegC_3rc() + VRegA_3rc() - 1;
- switch (Opcode()) {
- case INVOKE_VIRTUAL_RANGE:
- case INVOKE_SUPER_RANGE:
- case INVOKE_DIRECT_RANGE:
- case INVOKE_STATIC_RANGE:
- case INVOKE_INTERFACE_RANGE:
- if (file != nullptr) {
- uint32_t method_idx = VRegB_3rc();
- os << StringPrintf("%s, {v%d .. v%d}, ", opcode, first_reg, last_reg)
- << file->PrettyMethod(method_idx) << " // method@" << method_idx;
- break;
- }
- FALLTHROUGH_INTENDED;
- case INVOKE_VIRTUAL_RANGE_QUICK:
- if (file != nullptr) {
- uint32_t method_idx = VRegB_3rc();
- os << StringPrintf("%s, {v%d .. v%d}, ", opcode, first_reg, last_reg)
- << "// vtable@" << method_idx;
- break;
- }
- FALLTHROUGH_INTENDED;
- case INVOKE_CUSTOM_RANGE:
- if (file != nullptr) {
- uint32_t call_site_idx = VRegB_3rc();
- os << StringPrintf("%s, {v%d .. v%d}, ", opcode, first_reg, last_reg)
- << "// call_site@" << call_site_idx;
- break;
- }
- FALLTHROUGH_INTENDED;
- default:
- os << StringPrintf("%s, {v%d .. v%d}, ", opcode, first_reg, last_reg)
- << "thing@" << VRegB_3rc();
- break;
- }
- break;
- }
- case k45cc: {
- uint32_t arg[kMaxVarArgRegs];
- GetVarArgs(arg);
- uint32_t method_idx = VRegB_45cc();
- uint32_t proto_idx = VRegH_45cc();
- os << opcode << " {";
- for (int i = 0; i < VRegA_45cc(); ++i) {
- if (i != 0) {
- os << ", ";
- }
- os << "v" << arg[i];
- }
- os << "}";
- if (file != nullptr) {
- os << ", " << file->PrettyMethod(method_idx) << ", " << file->GetShorty(proto_idx)
- << " // ";
- } else {
- os << ", ";
- }
- os << "method@" << method_idx << ", proto@" << proto_idx;
- break;
- }
- case k4rcc:
- switch (Opcode()) {
- case INVOKE_POLYMORPHIC_RANGE: {
- if (file != nullptr) {
- uint32_t method_idx = VRegB_4rcc();
- uint32_t proto_idx = VRegH_4rcc();
- os << opcode << ", {v" << VRegC_4rcc() << " .. v" << (VRegC_4rcc() + VRegA_4rcc())
- << "}, " << file->PrettyMethod(method_idx) << ", " << file->GetShorty(proto_idx)
- << " // method@" << method_idx << ", proto@" << proto_idx;
- break;
- }
- }
- FALLTHROUGH_INTENDED;
- default: {
- uint32_t method_idx = VRegB_4rcc();
- uint32_t proto_idx = VRegH_4rcc();
- os << opcode << ", {v" << VRegC_4rcc() << " .. v" << (VRegC_4rcc() + VRegA_4rcc())
- << "}, method@" << method_idx << ", proto@" << proto_idx;
- }
- }
- break;
- case k51l: os << StringPrintf("%s v%d, #%+" PRId64, opcode, VRegA_51l(), VRegB_51l()); break;
- }
- return os.str();
-}
-
-// Add some checks that ensure the flags make sense. We need a subclass to be in the context of
-// Instruction. Otherwise the flags from the instruction list don't work.
-struct InstructionStaticAsserts : private Instruction {
- #define IMPLIES(a, b) (!(a) || (b))
-
- #define VAR_ARGS_CHECK(o, c, pname, f, i, a, e, v) \
- static_assert(IMPLIES((f) == k35c || (f) == k45cc, \
- ((v) & (kVerifyVarArg | kVerifyVarArgNonZero)) != 0), \
- "Missing var-arg verification");
- #include "dex_instruction_list.h"
- DEX_INSTRUCTION_LIST(VAR_ARGS_CHECK)
- #undef DEX_INSTRUCTION_LIST
- #undef VAR_ARGS_CHECK
-
- #define VAR_ARGS_RANGE_CHECK(o, c, pname, f, i, a, e, v) \
- static_assert(IMPLIES((f) == k3rc || (f) == k4rcc, \
- ((v) & (kVerifyVarArgRange | kVerifyVarArgRangeNonZero)) != 0), \
- "Missing var-arg verification");
- #include "dex_instruction_list.h"
- DEX_INSTRUCTION_LIST(VAR_ARGS_RANGE_CHECK)
- #undef DEX_INSTRUCTION_LIST
- #undef VAR_ARGS_RANGE_CHECK
-
- #define EXPERIMENTAL_CHECK(o, c, pname, f, i, a, e, v) \
- static_assert(kHaveExperimentalInstructions || (((a) & kExperimental) == 0), \
- "Unexpected experimental instruction.");
- #include "dex_instruction_list.h"
- DEX_INSTRUCTION_LIST(EXPERIMENTAL_CHECK)
- #undef DEX_INSTRUCTION_LIST
- #undef EXPERIMENTAL_CHECK
-};
-
-std::ostream& operator<<(std::ostream& os, const Instruction::Code& code) {
- return os << Instruction::Name(code);
-}
-
-uint32_t RangeInstructionOperands::GetOperand(size_t operand_index) const {
- DCHECK_LT(operand_index, GetNumberOfOperands());
- return first_operand_ + operand_index;
-}
-
-uint32_t VarArgsInstructionOperands::GetOperand(size_t operand_index) const {
- DCHECK_LT(operand_index, GetNumberOfOperands());
- return operands_[operand_index];
-}
-
-} // namespace art
diff --git a/runtime/dex/dex_instruction.h b/runtime/dex/dex_instruction.h
deleted file mode 100644
index 8b1a5ce670..0000000000
--- a/runtime/dex/dex_instruction.h
+++ /dev/null
@@ -1,742 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ART_RUNTIME_DEX_DEX_INSTRUCTION_H_
-#define ART_RUNTIME_DEX_DEX_INSTRUCTION_H_
-
-#include <android-base/logging.h>
-
-#include "base/macros.h"
-#include "globals.h"
-
-typedef uint8_t uint4_t;
-typedef int8_t int4_t;
-
-namespace art {
-
-class DexFile;
-
-enum {
- kNumPackedOpcodes = 0x100
-};
-
-class Instruction {
- public:
- // NOP-encoded switch-statement signatures.
- enum Signatures {
- kPackedSwitchSignature = 0x0100,
- kSparseSwitchSignature = 0x0200,
- kArrayDataSignature = 0x0300,
- };
-
- struct PACKED(4) PackedSwitchPayload {
- const uint16_t ident;
- const uint16_t case_count;
- const int32_t first_key;
- const int32_t targets[];
-
- private:
- DISALLOW_COPY_AND_ASSIGN(PackedSwitchPayload);
- };
-
- struct PACKED(4) SparseSwitchPayload {
- const uint16_t ident;
- const uint16_t case_count;
- const int32_t keys_and_targets[];
-
- public:
- const int32_t* GetKeys() const {
- return keys_and_targets;
- }
-
- const int32_t* GetTargets() const {
- return keys_and_targets + case_count;
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(SparseSwitchPayload);
- };
-
- struct PACKED(4) ArrayDataPayload {
- const uint16_t ident;
- const uint16_t element_width;
- const uint32_t element_count;
- const uint8_t data[];
-
- private:
- DISALLOW_COPY_AND_ASSIGN(ArrayDataPayload);
- };
-
- enum Code { // private marker to avoid generate-operator-out.py from processing.
-#define INSTRUCTION_ENUM(opcode, cname, p, f, i, a, e, v) cname = (opcode),
-#include "dex_instruction_list.h"
- DEX_INSTRUCTION_LIST(INSTRUCTION_ENUM)
-#undef DEX_INSTRUCTION_LIST
-#undef INSTRUCTION_ENUM
- RSUB_INT_LIT16 = RSUB_INT,
- };
-
- enum Format : uint8_t {
- k10x, // op
- k12x, // op vA, vB
- k11n, // op vA, #+B
- k11x, // op vAA
- k10t, // op +AA
- k20t, // op +AAAA
- k22x, // op vAA, vBBBB
- k21t, // op vAA, +BBBB
- k21s, // op vAA, #+BBBB
- k21h, // op vAA, #+BBBB00000[00000000]
- k21c, // op vAA, thing@BBBB
- k23x, // op vAA, vBB, vCC
- k22b, // op vAA, vBB, #+CC
- k22t, // op vA, vB, +CCCC
- k22s, // op vA, vB, #+CCCC
- k22c, // op vA, vB, thing@CCCC
- k32x, // op vAAAA, vBBBB
- k30t, // op +AAAAAAAA
- k31t, // op vAA, +BBBBBBBB
- k31i, // op vAA, #+BBBBBBBB
- k31c, // op vAA, thing@BBBBBBBB
- k35c, // op {vC, vD, vE, vF, vG}, thing@BBBB (B: count, A: vG)
- k3rc, // op {vCCCC .. v(CCCC+AA-1)}, meth@BBBB
-
- // op {vC, vD, vE, vF, vG}, meth@BBBB, proto@HHHH (A: count)
- // format: AG op BBBB FEDC HHHH
- k45cc,
-
- // op {VCCCC .. v(CCCC+AA-1)}, meth@BBBB, proto@HHHH (AA: count)
- // format: AA op BBBB CCCC HHHH
- k4rcc, // op {VCCCC .. v(CCCC+AA-1)}, meth@BBBB, proto@HHHH (AA: count)
-
- k51l, // op vAA, #+BBBBBBBBBBBBBBBB
- };
-
- enum IndexType : uint8_t {
- kIndexUnknown = 0,
- kIndexNone, // has no index
- kIndexTypeRef, // type reference index
- kIndexStringRef, // string reference index
- kIndexMethodRef, // method reference index
- kIndexFieldRef, // field reference index
- kIndexFieldOffset, // field offset (for static linked fields)
- kIndexVtableOffset, // vtable offset (for static linked methods)
- kIndexMethodAndProtoRef, // method and a proto reference index (for invoke-polymorphic)
- kIndexCallSiteRef, // call site reference index
- kIndexMethodHandleRef, // constant method handle reference index
- kIndexProtoRef, // prototype reference index
- };
-
- enum Flags : uint8_t {
- kBranch = 0x01, // conditional or unconditional branch
- kContinue = 0x02, // flow can continue to next statement
- kSwitch = 0x04, // switch statement
- kThrow = 0x08, // could cause an exception to be thrown
- kReturn = 0x10, // returns, no additional statements
- kInvoke = 0x20, // a flavor of invoke
- kUnconditional = 0x40, // unconditional branch
- kExperimental = 0x80, // is an experimental opcode
- };
-
- // Old flags. Keeping them around in case we might need them again some day.
- enum ExtendedFlags : uint32_t {
- kAdd = 0x0000080, // addition
- kSubtract = 0x0000100, // subtract
- kMultiply = 0x0000200, // multiply
- kDivide = 0x0000400, // division
- kRemainder = 0x0000800, // remainder
- kAnd = 0x0001000, // and
- kOr = 0x0002000, // or
- kXor = 0x0004000, // xor
- kShl = 0x0008000, // shl
- kShr = 0x0010000, // shr
- kUshr = 0x0020000, // ushr
- kCast = 0x0040000, // cast
- kStore = 0x0080000, // store opcode
- kLoad = 0x0100000, // load opcode
- kClobber = 0x0200000, // clobbers memory in a big way (not just a write)
- kRegCFieldOrConstant = 0x0400000, // is the third virtual register a field or literal constant (vC)
- kRegBFieldOrConstant = 0x0800000, // is the second virtual register a field or literal constant (vB)
- };
-
- enum VerifyFlag : uint32_t {
- kVerifyNone = 0x0000000,
- kVerifyRegA = 0x0000001,
- kVerifyRegAWide = 0x0000002,
- kVerifyRegB = 0x0000004,
- kVerifyRegBField = 0x0000008,
- kVerifyRegBMethod = 0x0000010,
- kVerifyRegBNewInstance = 0x0000020,
- kVerifyRegBString = 0x0000040,
- kVerifyRegBType = 0x0000080,
- kVerifyRegBWide = 0x0000100,
- kVerifyRegC = 0x0000200,
- kVerifyRegCField = 0x0000400,
- kVerifyRegCNewArray = 0x0000800,
- kVerifyRegCType = 0x0001000,
- kVerifyRegCWide = 0x0002000,
- kVerifyArrayData = 0x0004000,
- kVerifyBranchTarget = 0x0008000,
- kVerifySwitchTargets = 0x0010000,
- kVerifyVarArg = 0x0020000,
- kVerifyVarArgNonZero = 0x0040000,
- kVerifyVarArgRange = 0x0080000,
- kVerifyVarArgRangeNonZero = 0x0100000,
- kVerifyRuntimeOnly = 0x0200000,
- kVerifyError = 0x0400000,
- kVerifyRegHPrototype = 0x0800000,
- kVerifyRegBCallSite = 0x1000000,
- kVerifyRegBMethodHandle = 0x2000000,
- kVerifyRegBPrototype = 0x4000000,
- };
-
- // Collect the enums in a struct for better locality.
- struct InstructionDescriptor {
- uint32_t verify_flags; // Set of VerifyFlag.
- Format format;
- IndexType index_type;
- uint8_t flags; // Set of Flags.
- int8_t size_in_code_units;
- };
-
- static constexpr uint32_t kMaxVarArgRegs = 5;
-
- static constexpr bool kHaveExperimentalInstructions = false;
-
- // Returns the size (in 2 byte code units) of this instruction.
- size_t SizeInCodeUnits() const {
- int8_t result = kInstructionDescriptors[Opcode()].size_in_code_units;
- if (UNLIKELY(result < 0)) {
- return SizeInCodeUnitsComplexOpcode();
- } else {
- return static_cast<size_t>(result);
- }
- }
-
- // Code units required to calculate the size of the instruction.
- size_t CodeUnitsRequiredForSizeComputation() const {
- const int8_t result = kInstructionDescriptors[Opcode()].size_in_code_units;
- return UNLIKELY(result < 0) ? CodeUnitsRequiredForSizeOfComplexOpcode() : 1;
- }
-
- // Reads an instruction out of the stream at the specified address.
- static const Instruction* At(const uint16_t* code) {
- DCHECK(code != nullptr);
- return reinterpret_cast<const Instruction*>(code);
- }
-
- // Reads an instruction out of the stream from the current address plus an offset.
- const Instruction* RelativeAt(int32_t offset) const WARN_UNUSED {
- return At(reinterpret_cast<const uint16_t*>(this) + offset);
- }
-
- // Returns a pointer to the next instruction in the stream.
- const Instruction* Next() const {
- return RelativeAt(SizeInCodeUnits());
- }
-
- // Returns a pointer to the instruction after this 1xx instruction in the stream.
- const Instruction* Next_1xx() const {
- DCHECK(FormatOf(Opcode()) >= k10x && FormatOf(Opcode()) <= k10t);
- return RelativeAt(1);
- }
-
- // Returns a pointer to the instruction after this 2xx instruction in the stream.
- const Instruction* Next_2xx() const {
- DCHECK(FormatOf(Opcode()) >= k20t && FormatOf(Opcode()) <= k22c);
- return RelativeAt(2);
- }
-
- // Returns a pointer to the instruction after this 3xx instruction in the stream.
- const Instruction* Next_3xx() const {
- DCHECK(FormatOf(Opcode()) >= k32x && FormatOf(Opcode()) <= k3rc);
- return RelativeAt(3);
- }
-
- // Returns a pointer to the instruction after this 4xx instruction in the stream.
- const Instruction* Next_4xx() const {
- DCHECK(FormatOf(Opcode()) >= k45cc && FormatOf(Opcode()) <= k4rcc);
- return RelativeAt(4);
- }
-
- // Returns a pointer to the instruction after this 51l instruction in the stream.
- const Instruction* Next_51l() const {
- DCHECK(FormatOf(Opcode()) == k51l);
- return RelativeAt(5);
- }
-
- // Returns the name of this instruction's opcode.
- const char* Name() const {
- return Instruction::Name(Opcode());
- }
-
- // Returns the name of the given opcode.
- static const char* Name(Code opcode) {
- return kInstructionNames[opcode];
- }
-
- // VRegA
- bool HasVRegA() const;
- ALWAYS_INLINE int32_t VRegA() const;
-
- int8_t VRegA_10t() const {
- return VRegA_10t(Fetch16(0));
- }
- uint8_t VRegA_10x() const {
- return VRegA_10x(Fetch16(0));
- }
- uint4_t VRegA_11n() const {
- return VRegA_11n(Fetch16(0));
- }
- uint8_t VRegA_11x() const {
- return VRegA_11x(Fetch16(0));
- }
- uint4_t VRegA_12x() const {
- return VRegA_12x(Fetch16(0));
- }
- int16_t VRegA_20t() const;
- uint8_t VRegA_21c() const {
- return VRegA_21c(Fetch16(0));
- }
- uint8_t VRegA_21h() const {
- return VRegA_21h(Fetch16(0));
- }
- uint8_t VRegA_21s() const {
- return VRegA_21s(Fetch16(0));
- }
- uint8_t VRegA_21t() const {
- return VRegA_21t(Fetch16(0));
- }
- uint8_t VRegA_22b() const {
- return VRegA_22b(Fetch16(0));
- }
- uint4_t VRegA_22c() const {
- return VRegA_22c(Fetch16(0));
- }
- uint4_t VRegA_22s() const {
- return VRegA_22s(Fetch16(0));
- }
- uint4_t VRegA_22t() const {
- return VRegA_22t(Fetch16(0));
- }
- uint8_t VRegA_22x() const {
- return VRegA_22x(Fetch16(0));
- }
- uint8_t VRegA_23x() const {
- return VRegA_23x(Fetch16(0));
- }
- int32_t VRegA_30t() const;
- uint8_t VRegA_31c() const {
- return VRegA_31c(Fetch16(0));
- }
- uint8_t VRegA_31i() const {
- return VRegA_31i(Fetch16(0));
- }
- uint8_t VRegA_31t() const {
- return VRegA_31t(Fetch16(0));
- }
- uint16_t VRegA_32x() const;
- uint4_t VRegA_35c() const {
- return VRegA_35c(Fetch16(0));
- }
- uint8_t VRegA_3rc() const {
- return VRegA_3rc(Fetch16(0));
- }
- uint8_t VRegA_51l() const {
- return VRegA_51l(Fetch16(0));
- }
- uint4_t VRegA_45cc() const {
- return VRegA_45cc(Fetch16(0));
- }
- uint8_t VRegA_4rcc() const {
- return VRegA_4rcc(Fetch16(0));
- }
-
- // The following methods return the vA operand for various instruction formats. The "inst_data"
- // parameter holds the first 16 bits of instruction which the returned value is decoded from.
- int8_t VRegA_10t(uint16_t inst_data) const;
- uint8_t VRegA_10x(uint16_t inst_data) const;
- uint4_t VRegA_11n(uint16_t inst_data) const;
- uint8_t VRegA_11x(uint16_t inst_data) const;
- uint4_t VRegA_12x(uint16_t inst_data) const;
- uint8_t VRegA_21c(uint16_t inst_data) const;
- uint8_t VRegA_21h(uint16_t inst_data) const;
- uint8_t VRegA_21s(uint16_t inst_data) const;
- uint8_t VRegA_21t(uint16_t inst_data) const;
- uint8_t VRegA_22b(uint16_t inst_data) const;
- uint4_t VRegA_22c(uint16_t inst_data) const;
- uint4_t VRegA_22s(uint16_t inst_data) const;
- uint4_t VRegA_22t(uint16_t inst_data) const;
- uint8_t VRegA_22x(uint16_t inst_data) const;
- uint8_t VRegA_23x(uint16_t inst_data) const;
- uint8_t VRegA_31c(uint16_t inst_data) const;
- uint8_t VRegA_31i(uint16_t inst_data) const;
- uint8_t VRegA_31t(uint16_t inst_data) const;
- uint4_t VRegA_35c(uint16_t inst_data) const;
- uint8_t VRegA_3rc(uint16_t inst_data) const;
- uint8_t VRegA_51l(uint16_t inst_data) const;
- uint4_t VRegA_45cc(uint16_t inst_data) const;
- uint8_t VRegA_4rcc(uint16_t inst_data) const;
-
- // VRegB
- bool HasVRegB() const;
- int32_t VRegB() const;
-
- bool HasWideVRegB() const;
- uint64_t WideVRegB() const;
-
- int4_t VRegB_11n() const {
- return VRegB_11n(Fetch16(0));
- }
- uint4_t VRegB_12x() const {
- return VRegB_12x(Fetch16(0));
- }
- uint16_t VRegB_21c() const;
- uint16_t VRegB_21h() const;
- int16_t VRegB_21s() const;
- int16_t VRegB_21t() const;
- uint8_t VRegB_22b() const;
- uint4_t VRegB_22c() const {
- return VRegB_22c(Fetch16(0));
- }
- uint4_t VRegB_22s() const {
- return VRegB_22s(Fetch16(0));
- }
- uint4_t VRegB_22t() const {
- return VRegB_22t(Fetch16(0));
- }
- uint16_t VRegB_22x() const;
- uint8_t VRegB_23x() const;
- uint32_t VRegB_31c() const;
- int32_t VRegB_31i() const;
- int32_t VRegB_31t() const;
- uint16_t VRegB_32x() const;
- uint16_t VRegB_35c() const;
- uint16_t VRegB_3rc() const;
- uint64_t VRegB_51l() const; // vB_wide
- uint16_t VRegB_45cc() const;
- uint16_t VRegB_4rcc() const;
-
- // The following methods return the vB operand for all instruction formats where it is encoded in
- // the first 16 bits of instruction. The "inst_data" parameter holds these 16 bits. The returned
- // value is decoded from it.
- int4_t VRegB_11n(uint16_t inst_data) const;
- uint4_t VRegB_12x(uint16_t inst_data) const;
- uint4_t VRegB_22c(uint16_t inst_data) const;
- uint4_t VRegB_22s(uint16_t inst_data) const;
- uint4_t VRegB_22t(uint16_t inst_data) const;
-
- // VRegC
- bool HasVRegC() const;
- int32_t VRegC() const;
-
- int8_t VRegC_22b() const;
- uint16_t VRegC_22c() const;
- int16_t VRegC_22s() const;
- int16_t VRegC_22t() const;
- uint8_t VRegC_23x() const;
- uint4_t VRegC_35c() const;
- uint16_t VRegC_3rc() const;
- uint4_t VRegC_45cc() const;
- uint16_t VRegC_4rcc() const;
-
-
- // VRegH
- bool HasVRegH() const;
- int32_t VRegH() const;
- uint16_t VRegH_45cc() const;
- uint16_t VRegH_4rcc() const;
-
- // Fills the given array with the 'arg' array of the instruction.
- bool HasVarArgs() const;
- void GetVarArgs(uint32_t args[kMaxVarArgRegs], uint16_t inst_data) const;
- void GetVarArgs(uint32_t args[kMaxVarArgRegs]) const {
- return GetVarArgs(args, Fetch16(0));
- }
-
- // Returns the opcode field of the instruction. The given "inst_data" parameter must be the first
- // 16 bits of instruction.
- Code Opcode(uint16_t inst_data) const {
- DCHECK_EQ(inst_data, Fetch16(0));
- return static_cast<Code>(inst_data & 0xFF);
- }
-
- // Returns the opcode field of the instruction from the first 16 bits of instruction.
- Code Opcode() const {
- return Opcode(Fetch16(0));
- }
-
- void SetOpcode(Code opcode) {
- DCHECK_LT(static_cast<uint16_t>(opcode), 256u);
- uint16_t* insns = reinterpret_cast<uint16_t*>(this);
- insns[0] = (insns[0] & 0xff00) | static_cast<uint16_t>(opcode);
- }
-
- void SetVRegA_10x(uint8_t val) {
- DCHECK(FormatOf(Opcode()) == k10x);
- uint16_t* insns = reinterpret_cast<uint16_t*>(this);
- insns[0] = (val << 8) | (insns[0] & 0x00ff);
- }
-
- void SetVRegB_3rc(uint16_t val) {
- DCHECK(FormatOf(Opcode()) == k3rc);
- uint16_t* insns = reinterpret_cast<uint16_t*>(this);
- insns[1] = val;
- }
-
- void SetVRegB_35c(uint16_t val) {
- DCHECK(FormatOf(Opcode()) == k35c);
- uint16_t* insns = reinterpret_cast<uint16_t*>(this);
- insns[1] = val;
- }
-
- void SetVRegC_22c(uint16_t val) {
- DCHECK(FormatOf(Opcode()) == k22c);
- uint16_t* insns = reinterpret_cast<uint16_t*>(this);
- insns[1] = val;
- }
-
- void SetVRegA_21c(uint8_t val) {
- DCHECK(FormatOf(Opcode()) == k21c);
- uint16_t* insns = reinterpret_cast<uint16_t*>(this);
- insns[0] = (val << 8) | (insns[0] & 0x00ff);
- }
-
- void SetVRegB_21c(uint16_t val) {
- DCHECK(FormatOf(Opcode()) == k21c);
- uint16_t* insns = reinterpret_cast<uint16_t*>(this);
- insns[1] = val;
- }
-
- // Returns the format of the given opcode.
- static Format FormatOf(Code opcode) {
- return kInstructionDescriptors[opcode].format;
- }
-
- // Returns the index type of the given opcode.
- static IndexType IndexTypeOf(Code opcode) {
- return kInstructionDescriptors[opcode].index_type;
- }
-
- // Returns the flags for the given opcode.
- static uint8_t FlagsOf(Code opcode) {
- return kInstructionDescriptors[opcode].flags;
- }
-
- // Return the verify flags for the given opcode.
- static uint32_t VerifyFlagsOf(Code opcode) {
- return kInstructionDescriptors[opcode].verify_flags;
- }
-
- // Returns true if this instruction is a branch.
- bool IsBranch() const {
- return (kInstructionDescriptors[Opcode()].flags & kBranch) != 0;
- }
-
- // Returns true if this instruction is a unconditional branch.
- bool IsUnconditional() const {
- return (kInstructionDescriptors[Opcode()].flags & kUnconditional) != 0;
- }
-
- // Returns the branch offset if this instruction is a branch.
- int32_t GetTargetOffset() const;
-
- // Returns true if the instruction allows control flow to go to the following instruction.
- bool CanFlowThrough() const;
-
- // Returns true if the instruction is a quickened instruction.
- bool IsQuickened() const {
- return (kInstructionDescriptors[Opcode()].index_type == kIndexFieldOffset) ||
- (kInstructionDescriptors[Opcode()].index_type == kIndexVtableOffset);
- }
-
- // Returns true if this instruction is a switch.
- bool IsSwitch() const {
- return (kInstructionDescriptors[Opcode()].flags & kSwitch) != 0;
- }
-
- // Returns true if this instruction can throw.
- bool IsThrow() const {
- return (kInstructionDescriptors[Opcode()].flags & kThrow) != 0;
- }
-
- // Determine if the instruction is any of 'return' instructions.
- bool IsReturn() const {
- return (kInstructionDescriptors[Opcode()].flags & kReturn) != 0;
- }
-
- // Determine if this instruction ends execution of its basic block.
- bool IsBasicBlockEnd() const {
- return IsBranch() || IsReturn() || Opcode() == THROW;
- }
-
- // Determine if this instruction is an invoke.
- bool IsInvoke() const {
- return (kInstructionDescriptors[Opcode()].flags & kInvoke) != 0;
- }
-
- // Determine if this instruction is experimental.
- bool IsExperimental() const {
- return (kInstructionDescriptors[Opcode()].flags & kExperimental) != 0;
- }
-
- int GetVerifyTypeArgumentA() const {
- return (kInstructionDescriptors[Opcode()].verify_flags & (kVerifyRegA | kVerifyRegAWide));
- }
-
- int GetVerifyTypeArgumentB() const {
- return (kInstructionDescriptors[Opcode()].verify_flags & (kVerifyRegB | kVerifyRegBField |
- kVerifyRegBMethod | kVerifyRegBNewInstance | kVerifyRegBString | kVerifyRegBType |
- kVerifyRegBWide));
- }
-
- int GetVerifyTypeArgumentC() const {
- return (kInstructionDescriptors[Opcode()].verify_flags & (kVerifyRegC | kVerifyRegCField |
- kVerifyRegCNewArray | kVerifyRegCType | kVerifyRegCWide));
- }
-
- int GetVerifyTypeArgumentH() const {
- return (kInstructionDescriptors[Opcode()].verify_flags & kVerifyRegHPrototype);
- }
-
- int GetVerifyExtraFlags() const {
- return (kInstructionDescriptors[Opcode()].verify_flags & (kVerifyArrayData |
- kVerifyBranchTarget | kVerifySwitchTargets | kVerifyVarArg | kVerifyVarArgNonZero |
- kVerifyVarArgRange | kVerifyVarArgRangeNonZero | kVerifyError));
- }
-
- bool GetVerifyIsRuntimeOnly() const {
- return (kInstructionDescriptors[Opcode()].verify_flags & kVerifyRuntimeOnly) != 0;
- }
-
- // Get the dex PC of this instruction as a offset in code units from the beginning of insns.
- uint32_t GetDexPc(const uint16_t* insns) const {
- return (reinterpret_cast<const uint16_t*>(this) - insns);
- }
-
- // Dump decoded version of instruction
- std::string DumpString(const DexFile*) const;
-
- // Dump code_units worth of this instruction, padding to code_units for shorter instructions
- std::string DumpHex(size_t code_units) const;
-
- // Little-endian dump code_units worth of this instruction, padding to code_units for
- // shorter instructions
- std::string DumpHexLE(size_t instr_code_units) const;
-
- uint16_t Fetch16(size_t offset) const {
- const uint16_t* insns = reinterpret_cast<const uint16_t*>(this);
- return insns[offset];
- }
-
- private:
- size_t SizeInCodeUnitsComplexOpcode() const;
-
- // Return how many code unit words are required to compute the size of the opcode.
- size_t CodeUnitsRequiredForSizeOfComplexOpcode() const;
-
- uint32_t Fetch32(size_t offset) const {
- return (Fetch16(offset) | ((uint32_t) Fetch16(offset + 1) << 16));
- }
-
- uint4_t InstA() const {
- return InstA(Fetch16(0));
- }
-
- uint4_t InstB() const {
- return InstB(Fetch16(0));
- }
-
- uint8_t InstAA() const {
- return InstAA(Fetch16(0));
- }
-
- uint4_t InstA(uint16_t inst_data) const {
- DCHECK_EQ(inst_data, Fetch16(0));
- return static_cast<uint4_t>((inst_data >> 8) & 0x0f);
- }
-
- uint4_t InstB(uint16_t inst_data) const {
- DCHECK_EQ(inst_data, Fetch16(0));
- return static_cast<uint4_t>(inst_data >> 12);
- }
-
- uint8_t InstAA(uint16_t inst_data) const {
- DCHECK_EQ(inst_data, Fetch16(0));
- return static_cast<uint8_t>(inst_data >> 8);
- }
-
- static const char* const kInstructionNames[];
-
- static const InstructionDescriptor kInstructionDescriptors[];
-
- DISALLOW_IMPLICIT_CONSTRUCTORS(Instruction);
-};
-std::ostream& operator<<(std::ostream& os, const Instruction::Code& code);
-std::ostream& operator<<(std::ostream& os, const Instruction::Format& format);
-std::ostream& operator<<(std::ostream& os, const Instruction::Flags& flags);
-std::ostream& operator<<(std::ostream& os, const Instruction::VerifyFlag& vflags);
-
-// Base class for accessing instruction operands. Unifies operand
-// access for instructions that have range and varargs forms
-// (e.g. invoke-polymoprhic/range and invoke-polymorphic).
-class InstructionOperands {
- public:
- explicit InstructionOperands(size_t num_operands) : num_operands_(num_operands) {}
- virtual ~InstructionOperands() {}
- virtual uint32_t GetOperand(size_t index) const = 0;
- size_t GetNumberOfOperands() const { return num_operands_; }
-
- private:
- size_t num_operands_;
-
- DISALLOW_IMPLICIT_CONSTRUCTORS(InstructionOperands);
-};
-
-// Class for accessing operands for instructions with a range format
-// (e.g. 3rc and 4rcc).
-class RangeInstructionOperands FINAL : public InstructionOperands {
- public:
- RangeInstructionOperands(uint32_t first_operand, size_t num_operands)
- : InstructionOperands(num_operands), first_operand_(first_operand) {}
- ~RangeInstructionOperands() {}
- uint32_t GetOperand(size_t operand_index) const OVERRIDE;
-
- private:
- const uint32_t first_operand_;
-
- DISALLOW_IMPLICIT_CONSTRUCTORS(RangeInstructionOperands);
-};
-
-// Class for accessing operands for instructions with a variable
-// number of arguments format (e.g. 35c and 45cc).
-class VarArgsInstructionOperands FINAL : public InstructionOperands {
- public:
- VarArgsInstructionOperands(const uint32_t (&operands)[Instruction::kMaxVarArgRegs],
- size_t num_operands)
- : InstructionOperands(num_operands), operands_(operands) {}
- ~VarArgsInstructionOperands() {}
- uint32_t GetOperand(size_t operand_index) const OVERRIDE;
-
- private:
- const uint32_t (&operands_)[Instruction::kMaxVarArgRegs];
-
- DISALLOW_IMPLICIT_CONSTRUCTORS(VarArgsInstructionOperands);
-};
-
-} // namespace art
-
-#endif // ART_RUNTIME_DEX_DEX_INSTRUCTION_H_
diff --git a/runtime/dex/dex_instruction_iterator.h b/runtime/dex/dex_instruction_iterator.h
deleted file mode 100644
index c1b3118f85..0000000000
--- a/runtime/dex/dex_instruction_iterator.h
+++ /dev/null
@@ -1,237 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ART_RUNTIME_DEX_DEX_INSTRUCTION_ITERATOR_H_
-#define ART_RUNTIME_DEX_DEX_INSTRUCTION_ITERATOR_H_
-
-#include <iterator>
-
-#include <android-base/logging.h>
-
-#include "base/macros.h"
-#include "dex_instruction.h"
-
-namespace art {
-
-class DexInstructionPcPair {
- public:
- ALWAYS_INLINE const Instruction& Inst() const {
- return *Instruction::At(instructions_ + DexPc());
- }
-
- ALWAYS_INLINE const Instruction* operator->() const {
- return &Inst();
- }
-
- ALWAYS_INLINE uint32_t DexPc() const {
- return dex_pc_;
- }
-
- ALWAYS_INLINE const uint16_t* Instructions() const {
- return instructions_;
- }
-
- protected:
- explicit DexInstructionPcPair(const uint16_t* instructions, uint32_t dex_pc)
- : instructions_(instructions), dex_pc_(dex_pc) {}
-
- const uint16_t* instructions_ = nullptr;
- uint32_t dex_pc_ = 0;
-
- friend class DexInstructionIteratorBase;
- friend class DexInstructionIterator;
- friend class SafeDexInstructionIterator;
-};
-
-// Base helper class to prevent duplicated comparators.
-class DexInstructionIteratorBase : public
- std::iterator<std::forward_iterator_tag, DexInstructionPcPair> {
- public:
- using value_type = std::iterator<std::forward_iterator_tag, DexInstructionPcPair>::value_type;
- using difference_type = std::iterator<std::forward_iterator_tag, value_type>::difference_type;
-
- DexInstructionIteratorBase() = default;
- explicit DexInstructionIteratorBase(const Instruction* inst, uint32_t dex_pc)
- : data_(reinterpret_cast<const uint16_t*>(inst), dex_pc) {}
-
- const Instruction& Inst() const {
- return data_.Inst();
- }
-
- // Return the dex pc for an iterator compared to the code item begin.
- ALWAYS_INLINE uint32_t DexPc() const {
- return data_.DexPc();
- }
-
- // Instructions from the start of the code item.
- ALWAYS_INLINE const uint16_t* Instructions() const {
- return data_.Instructions();
- }
-
- protected:
- DexInstructionPcPair data_;
-};
-
-static ALWAYS_INLINE inline bool operator==(const DexInstructionIteratorBase& lhs,
- const DexInstructionIteratorBase& rhs) {
- DCHECK_EQ(lhs.Instructions(), rhs.Instructions()) << "Comparing different code items.";
- return lhs.DexPc() == rhs.DexPc();
-}
-
-static inline bool operator!=(const DexInstructionIteratorBase& lhs,
- const DexInstructionIteratorBase& rhs) {
- return !(lhs == rhs);
-}
-
-static inline bool operator<(const DexInstructionIteratorBase& lhs,
- const DexInstructionIteratorBase& rhs) {
- DCHECK_EQ(lhs.Instructions(), rhs.Instructions()) << "Comparing different code items.";
- return lhs.DexPc() < rhs.DexPc();
-}
-
-static inline bool operator>(const DexInstructionIteratorBase& lhs,
- const DexInstructionIteratorBase& rhs) {
- return rhs < lhs;
-}
-
-static inline bool operator<=(const DexInstructionIteratorBase& lhs,
- const DexInstructionIteratorBase& rhs) {
- return !(rhs < lhs);
-}
-
-static inline bool operator>=(const DexInstructionIteratorBase& lhs,
- const DexInstructionIteratorBase& rhs) {
- return !(lhs < rhs);
-}
-
-// A helper class for a code_item's instructions using range based for loop syntax.
-class DexInstructionIterator : public DexInstructionIteratorBase {
- public:
- using DexInstructionIteratorBase::DexInstructionIteratorBase;
-
- explicit DexInstructionIterator(const uint16_t* inst, uint32_t dex_pc)
- : DexInstructionIteratorBase(Instruction::At(inst), dex_pc) {}
-
- explicit DexInstructionIterator(const DexInstructionPcPair& pair)
- : DexInstructionIterator(pair.Instructions(), pair.DexPc()) {}
-
- // Value after modification.
- DexInstructionIterator& operator++() {
- data_.dex_pc_ += Inst().SizeInCodeUnits();
- return *this;
- }
-
- // Value before modification.
- DexInstructionIterator operator++(int) {
- DexInstructionIterator temp = *this;
- ++*this;
- return temp;
- }
-
- const value_type& operator*() const {
- return data_;
- }
-
- const Instruction* operator->() const {
- return &data_.Inst();
- }
-
- // Return the dex pc for the iterator.
- ALWAYS_INLINE uint32_t DexPc() const {
- return data_.DexPc();
- }
-};
-
-// A safe version of DexInstructionIterator that is guaranteed to not go past the end of the code
-// item.
-class SafeDexInstructionIterator : public DexInstructionIteratorBase {
- public:
- explicit SafeDexInstructionIterator(const DexInstructionIteratorBase& start,
- const DexInstructionIteratorBase& end)
- : DexInstructionIteratorBase(&start.Inst(), start.DexPc())
- , num_code_units_(end.DexPc()) {
- DCHECK_EQ(start.Instructions(), end.Instructions())
- << "start and end must be in the same code item.";
- }
-
- // Value after modification, does not read past the end of the allowed region. May increment past
- // the end of the code item though.
- SafeDexInstructionIterator& operator++() {
- AssertValid();
- const size_t size_code_units = Inst().CodeUnitsRequiredForSizeComputation();
- const size_t available = NumCodeUnits() - DexPc();
- if (UNLIKELY(size_code_units > available)) {
- error_state_ = true;
- return *this;
- }
- const size_t instruction_code_units = Inst().SizeInCodeUnits();
- if (UNLIKELY(instruction_code_units > available)) {
- error_state_ = true;
- return *this;
- }
- data_.dex_pc_ += instruction_code_units;
- return *this;
- }
-
- // Value before modification.
- SafeDexInstructionIterator operator++(int) {
- SafeDexInstructionIterator temp = *this;
- ++*this;
- return temp;
- }
-
- const value_type& operator*() const {
- AssertValid();
- return data_;
- }
-
- const Instruction* operator->() const {
- AssertValid();
- return &data_.Inst();
- }
-
- // Return the current instruction of the iterator.
- ALWAYS_INLINE const Instruction& Inst() const {
- return data_.Inst();
- }
-
- const uint16_t* Instructions() const {
- return data_.Instructions();
- }
-
- // Returns true if the iterator is in an error state. This occurs when an instruction couldn't
- // have its size computed without reading past the end iterator.
- bool IsErrorState() const {
- return error_state_;
- }
-
- private:
- ALWAYS_INLINE void AssertValid() const {
- DCHECK(!IsErrorState());
- DCHECK_LT(DexPc(), NumCodeUnits());
- }
-
- ALWAYS_INLINE uint32_t NumCodeUnits() const {
- return num_code_units_;
- }
-
- const uint32_t num_code_units_ = 0;
- bool error_state_ = false;
-};
-
-} // namespace art
-
-#endif // ART_RUNTIME_DEX_DEX_INSTRUCTION_ITERATOR_H_
diff --git a/runtime/dex/dex_instruction_list.h b/runtime/dex/dex_instruction_list.h
deleted file mode 100644
index aa63fadb66..0000000000
--- a/runtime/dex/dex_instruction_list.h
+++ /dev/null
@@ -1,308 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ART_RUNTIME_DEX_DEX_INSTRUCTION_LIST_H_
-#define ART_RUNTIME_DEX_DEX_INSTRUCTION_LIST_H_
-
-// V(opcode, instruction_code, name, format, index, flags, extended_flags, verifier_flags);
-#define DEX_INSTRUCTION_LIST(V) \
- V(0x00, NOP, "nop", k10x, kIndexNone, kContinue, 0, kVerifyNone) \
- V(0x01, MOVE, "move", k12x, kIndexNone, kContinue, 0, kVerifyRegA | kVerifyRegB) \
- V(0x02, MOVE_FROM16, "move/from16", k22x, kIndexNone, kContinue, 0, kVerifyRegA | kVerifyRegB) \
- V(0x03, MOVE_16, "move/16", k32x, kIndexNone, kContinue, 0, kVerifyRegA | kVerifyRegB) \
- V(0x04, MOVE_WIDE, "move-wide", k12x, kIndexNone, kContinue, 0, kVerifyRegAWide | kVerifyRegBWide) \
- V(0x05, MOVE_WIDE_FROM16, "move-wide/from16", k22x, kIndexNone, kContinue, 0, kVerifyRegAWide | kVerifyRegBWide) \
- V(0x06, MOVE_WIDE_16, "move-wide/16", k32x, kIndexNone, kContinue, 0, kVerifyRegAWide | kVerifyRegBWide) \
- V(0x07, MOVE_OBJECT, "move-object", k12x, kIndexNone, kContinue, 0, kVerifyRegA | kVerifyRegB) \
- V(0x08, MOVE_OBJECT_FROM16, "move-object/from16", k22x, kIndexNone, kContinue, 0, kVerifyRegA | kVerifyRegB) \
- V(0x09, MOVE_OBJECT_16, "move-object/16", k32x, kIndexNone, kContinue, 0, kVerifyRegA | kVerifyRegB) \
- V(0x0A, MOVE_RESULT, "move-result", k11x, kIndexNone, kContinue, 0, kVerifyRegA) \
- V(0x0B, MOVE_RESULT_WIDE, "move-result-wide", k11x, kIndexNone, kContinue, 0, kVerifyRegAWide) \
- V(0x0C, MOVE_RESULT_OBJECT, "move-result-object", k11x, kIndexNone, kContinue, 0, kVerifyRegA) \
- V(0x0D, MOVE_EXCEPTION, "move-exception", k11x, kIndexNone, kContinue, 0, kVerifyRegA) \
- V(0x0E, RETURN_VOID, "return-void", k10x, kIndexNone, kReturn, 0, kVerifyNone) \
- V(0x0F, RETURN, "return", k11x, kIndexNone, kReturn, 0, kVerifyRegA) \
- V(0x10, RETURN_WIDE, "return-wide", k11x, kIndexNone, kReturn, 0, kVerifyRegAWide) \
- V(0x11, RETURN_OBJECT, "return-object", k11x, kIndexNone, kReturn, 0, kVerifyRegA) \
- V(0x12, CONST_4, "const/4", k11n, kIndexNone, kContinue, kRegBFieldOrConstant, kVerifyRegA) \
- V(0x13, CONST_16, "const/16", k21s, kIndexNone, kContinue, kRegBFieldOrConstant, kVerifyRegA) \
- V(0x14, CONST, "const", k31i, kIndexNone, kContinue, kRegBFieldOrConstant, kVerifyRegA) \
- V(0x15, CONST_HIGH16, "const/high16", k21h, kIndexNone, kContinue, kRegBFieldOrConstant, kVerifyRegA) \
- V(0x16, CONST_WIDE_16, "const-wide/16", k21s, kIndexNone, kContinue, kRegBFieldOrConstant, kVerifyRegAWide) \
- V(0x17, CONST_WIDE_32, "const-wide/32", k31i, kIndexNone, kContinue, kRegBFieldOrConstant, kVerifyRegAWide) \
- V(0x18, CONST_WIDE, "const-wide", k51l, kIndexNone, kContinue, kRegBFieldOrConstant, kVerifyRegAWide) \
- V(0x19, CONST_WIDE_HIGH16, "const-wide/high16", k21h, kIndexNone, kContinue, kRegBFieldOrConstant, kVerifyRegAWide) \
- V(0x1A, CONST_STRING, "const-string", k21c, kIndexStringRef, kContinue | kThrow, 0, kVerifyRegA | kVerifyRegBString) \
- V(0x1B, CONST_STRING_JUMBO, "const-string/jumbo", k31c, kIndexStringRef, kContinue | kThrow, 0, kVerifyRegA | kVerifyRegBString) \
- V(0x1C, CONST_CLASS, "const-class", k21c, kIndexTypeRef, kContinue | kThrow, 0, kVerifyRegA | kVerifyRegBType) \
- V(0x1D, MONITOR_ENTER, "monitor-enter", k11x, kIndexNone, kContinue | kThrow, kClobber, kVerifyRegA) \
- V(0x1E, MONITOR_EXIT, "monitor-exit", k11x, kIndexNone, kContinue | kThrow, kClobber, kVerifyRegA) \
- V(0x1F, CHECK_CAST, "check-cast", k21c, kIndexTypeRef, kContinue | kThrow, 0, kVerifyRegA | kVerifyRegBType) \
- V(0x20, INSTANCE_OF, "instance-of", k22c, kIndexTypeRef, kContinue | kThrow, 0, kVerifyRegA | kVerifyRegB | kVerifyRegCType) \
- V(0x21, ARRAY_LENGTH, "array-length", k12x, kIndexNone, kContinue | kThrow, 0, kVerifyRegA | kVerifyRegB) \
- V(0x22, NEW_INSTANCE, "new-instance", k21c, kIndexTypeRef, kContinue | kThrow, kClobber, kVerifyRegA | kVerifyRegBNewInstance) \
- V(0x23, NEW_ARRAY, "new-array", k22c, kIndexTypeRef, kContinue | kThrow, kClobber, kVerifyRegA | kVerifyRegB | kVerifyRegCNewArray) \
- V(0x24, FILLED_NEW_ARRAY, "filled-new-array", k35c, kIndexTypeRef, kContinue | kThrow, kClobber, kVerifyRegBType | kVerifyVarArg) \
- V(0x25, FILLED_NEW_ARRAY_RANGE, "filled-new-array/range", k3rc, kIndexTypeRef, kContinue | kThrow, kClobber, kVerifyRegBType | kVerifyVarArgRange) \
- V(0x26, FILL_ARRAY_DATA, "fill-array-data", k31t, kIndexNone, kContinue | kThrow, kClobber, kVerifyRegA | kVerifyArrayData) \
- V(0x27, THROW, "throw", k11x, kIndexNone, kThrow, 0, kVerifyRegA) \
- V(0x28, GOTO, "goto", k10t, kIndexNone, kBranch | kUnconditional, 0, kVerifyBranchTarget) \
- V(0x29, GOTO_16, "goto/16", k20t, kIndexNone, kBranch | kUnconditional, 0, kVerifyBranchTarget) \
- V(0x2A, GOTO_32, "goto/32", k30t, kIndexNone, kBranch | kUnconditional, 0, kVerifyBranchTarget) \
- V(0x2B, PACKED_SWITCH, "packed-switch", k31t, kIndexNone, kContinue | kSwitch, 0, kVerifyRegA | kVerifySwitchTargets) \
- V(0x2C, SPARSE_SWITCH, "sparse-switch", k31t, kIndexNone, kContinue | kSwitch, 0, kVerifyRegA | kVerifySwitchTargets) \
- V(0x2D, CMPL_FLOAT, "cmpl-float", k23x, kIndexNone, kContinue, 0, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
- V(0x2E, CMPG_FLOAT, "cmpg-float", k23x, kIndexNone, kContinue, 0, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
- V(0x2F, CMPL_DOUBLE, "cmpl-double", k23x, kIndexNone, kContinue, 0, kVerifyRegA | kVerifyRegBWide | kVerifyRegCWide) \
- V(0x30, CMPG_DOUBLE, "cmpg-double", k23x, kIndexNone, kContinue, 0, kVerifyRegA | kVerifyRegBWide | kVerifyRegCWide) \
- V(0x31, CMP_LONG, "cmp-long", k23x, kIndexNone, kContinue, 0, kVerifyRegA | kVerifyRegBWide | kVerifyRegCWide) \
- V(0x32, IF_EQ, "if-eq", k22t, kIndexNone, kContinue | kBranch, 0, kVerifyRegA | kVerifyRegB | kVerifyBranchTarget) \
- V(0x33, IF_NE, "if-ne", k22t, kIndexNone, kContinue | kBranch, 0, kVerifyRegA | kVerifyRegB | kVerifyBranchTarget) \
- V(0x34, IF_LT, "if-lt", k22t, kIndexNone, kContinue | kBranch, 0, kVerifyRegA | kVerifyRegB | kVerifyBranchTarget) \
- V(0x35, IF_GE, "if-ge", k22t, kIndexNone, kContinue | kBranch, 0, kVerifyRegA | kVerifyRegB | kVerifyBranchTarget) \
- V(0x36, IF_GT, "if-gt", k22t, kIndexNone, kContinue | kBranch, 0, kVerifyRegA | kVerifyRegB | kVerifyBranchTarget) \
- V(0x37, IF_LE, "if-le", k22t, kIndexNone, kContinue | kBranch, 0, kVerifyRegA | kVerifyRegB | kVerifyBranchTarget) \
- V(0x38, IF_EQZ, "if-eqz", k21t, kIndexNone, kContinue | kBranch, 0, kVerifyRegA | kVerifyBranchTarget) \
- V(0x39, IF_NEZ, "if-nez", k21t, kIndexNone, kContinue | kBranch, 0, kVerifyRegA | kVerifyBranchTarget) \
- V(0x3A, IF_LTZ, "if-ltz", k21t, kIndexNone, kContinue | kBranch, 0, kVerifyRegA | kVerifyBranchTarget) \
- V(0x3B, IF_GEZ, "if-gez", k21t, kIndexNone, kContinue | kBranch, 0, kVerifyRegA | kVerifyBranchTarget) \
- V(0x3C, IF_GTZ, "if-gtz", k21t, kIndexNone, kContinue | kBranch, 0, kVerifyRegA | kVerifyBranchTarget) \
- V(0x3D, IF_LEZ, "if-lez", k21t, kIndexNone, kContinue | kBranch, 0, kVerifyRegA | kVerifyBranchTarget) \
- V(0x3E, UNUSED_3E, "unused-3e", k10x, kIndexUnknown, 0, 0, kVerifyError) \
- V(0x3F, UNUSED_3F, "unused-3f", k10x, kIndexUnknown, 0, 0, kVerifyError) \
- V(0x40, UNUSED_40, "unused-40", k10x, kIndexUnknown, 0, 0, kVerifyError) \
- V(0x41, UNUSED_41, "unused-41", k10x, kIndexUnknown, 0, 0, kVerifyError) \
- V(0x42, UNUSED_42, "unused-42", k10x, kIndexUnknown, 0, 0, kVerifyError) \
- V(0x43, UNUSED_43, "unused-43", k10x, kIndexUnknown, 0, 0, kVerifyError) \
- V(0x44, AGET, "aget", k23x, kIndexNone, kContinue | kThrow, kLoad, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
- V(0x45, AGET_WIDE, "aget-wide", k23x, kIndexNone, kContinue | kThrow, kLoad, kVerifyRegAWide | kVerifyRegB | kVerifyRegC) \
- V(0x46, AGET_OBJECT, "aget-object", k23x, kIndexNone, kContinue | kThrow, kLoad, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
- V(0x47, AGET_BOOLEAN, "aget-boolean", k23x, kIndexNone, kContinue | kThrow, kLoad, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
- V(0x48, AGET_BYTE, "aget-byte", k23x, kIndexNone, kContinue | kThrow, kLoad, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
- V(0x49, AGET_CHAR, "aget-char", k23x, kIndexNone, kContinue | kThrow, kLoad, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
- V(0x4A, AGET_SHORT, "aget-short", k23x, kIndexNone, kContinue | kThrow, kLoad, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
- V(0x4B, APUT, "aput", k23x, kIndexNone, kContinue | kThrow, kStore, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
- V(0x4C, APUT_WIDE, "aput-wide", k23x, kIndexNone, kContinue | kThrow, kStore, kVerifyRegAWide | kVerifyRegB | kVerifyRegC) \
- V(0x4D, APUT_OBJECT, "aput-object", k23x, kIndexNone, kContinue | kThrow, kStore, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
- V(0x4E, APUT_BOOLEAN, "aput-boolean", k23x, kIndexNone, kContinue | kThrow, kStore, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
- V(0x4F, APUT_BYTE, "aput-byte", k23x, kIndexNone, kContinue | kThrow, kStore, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
- V(0x50, APUT_CHAR, "aput-char", k23x, kIndexNone, kContinue | kThrow, kStore, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
- V(0x51, APUT_SHORT, "aput-short", k23x, kIndexNone, kContinue | kThrow, kStore, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
- V(0x52, IGET, "iget", k22c, kIndexFieldRef, kContinue | kThrow, kLoad | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \
- V(0x53, IGET_WIDE, "iget-wide", k22c, kIndexFieldRef, kContinue | kThrow, kLoad | kRegCFieldOrConstant, kVerifyRegAWide | kVerifyRegB | kVerifyRegCField) \
- V(0x54, IGET_OBJECT, "iget-object", k22c, kIndexFieldRef, kContinue | kThrow, kLoad | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \
- V(0x55, IGET_BOOLEAN, "iget-boolean", k22c, kIndexFieldRef, kContinue | kThrow, kLoad | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \
- V(0x56, IGET_BYTE, "iget-byte", k22c, kIndexFieldRef, kContinue | kThrow, kLoad | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \
- V(0x57, IGET_CHAR, "iget-char", k22c, kIndexFieldRef, kContinue | kThrow, kLoad | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \
- V(0x58, IGET_SHORT, "iget-short", k22c, kIndexFieldRef, kContinue | kThrow, kLoad | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \
- V(0x59, IPUT, "iput", k22c, kIndexFieldRef, kContinue | kThrow, kStore | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \
- V(0x5A, IPUT_WIDE, "iput-wide", k22c, kIndexFieldRef, kContinue | kThrow, kStore | kRegCFieldOrConstant, kVerifyRegAWide | kVerifyRegB | kVerifyRegCField) \
- V(0x5B, IPUT_OBJECT, "iput-object", k22c, kIndexFieldRef, kContinue | kThrow, kStore | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \
- V(0x5C, IPUT_BOOLEAN, "iput-boolean", k22c, kIndexFieldRef, kContinue | kThrow, kStore | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \
- V(0x5D, IPUT_BYTE, "iput-byte", k22c, kIndexFieldRef, kContinue | kThrow, kStore | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \
- V(0x5E, IPUT_CHAR, "iput-char", k22c, kIndexFieldRef, kContinue | kThrow, kStore | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \
- V(0x5F, IPUT_SHORT, "iput-short", k22c, kIndexFieldRef, kContinue | kThrow, kStore | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRegCField) \
- V(0x60, SGET, "sget", k21c, kIndexFieldRef, kContinue | kThrow, kLoad | kRegBFieldOrConstant, kVerifyRegA | kVerifyRegBField) \
- V(0x61, SGET_WIDE, "sget-wide", k21c, kIndexFieldRef, kContinue | kThrow, kLoad | kRegBFieldOrConstant, kVerifyRegAWide | kVerifyRegBField) \
- V(0x62, SGET_OBJECT, "sget-object", k21c, kIndexFieldRef, kContinue | kThrow, kLoad | kRegBFieldOrConstant, kVerifyRegA | kVerifyRegBField) \
- V(0x63, SGET_BOOLEAN, "sget-boolean", k21c, kIndexFieldRef, kContinue | kThrow, kLoad | kRegBFieldOrConstant, kVerifyRegA | kVerifyRegBField) \
- V(0x64, SGET_BYTE, "sget-byte", k21c, kIndexFieldRef, kContinue | kThrow, kLoad | kRegBFieldOrConstant, kVerifyRegA | kVerifyRegBField) \
- V(0x65, SGET_CHAR, "sget-char", k21c, kIndexFieldRef, kContinue | kThrow, kLoad | kRegBFieldOrConstant, kVerifyRegA | kVerifyRegBField) \
- V(0x66, SGET_SHORT, "sget-short", k21c, kIndexFieldRef, kContinue | kThrow, kLoad | kRegBFieldOrConstant, kVerifyRegA | kVerifyRegBField) \
- V(0x67, SPUT, "sput", k21c, kIndexFieldRef, kContinue | kThrow, kStore | kRegBFieldOrConstant, kVerifyRegA | kVerifyRegBField) \
- V(0x68, SPUT_WIDE, "sput-wide", k21c, kIndexFieldRef, kContinue | kThrow, kStore | kRegBFieldOrConstant, kVerifyRegAWide | kVerifyRegBField) \
- V(0x69, SPUT_OBJECT, "sput-object", k21c, kIndexFieldRef, kContinue | kThrow, kStore | kRegBFieldOrConstant, kVerifyRegA | kVerifyRegBField) \
- V(0x6A, SPUT_BOOLEAN, "sput-boolean", k21c, kIndexFieldRef, kContinue | kThrow, kStore | kRegBFieldOrConstant, kVerifyRegA | kVerifyRegBField) \
- V(0x6B, SPUT_BYTE, "sput-byte", k21c, kIndexFieldRef, kContinue | kThrow, kStore | kRegBFieldOrConstant, kVerifyRegA | kVerifyRegBField) \
- V(0x6C, SPUT_CHAR, "sput-char", k21c, kIndexFieldRef, kContinue | kThrow, kStore | kRegBFieldOrConstant, kVerifyRegA | kVerifyRegBField) \
- V(0x6D, SPUT_SHORT, "sput-short", k21c, kIndexFieldRef, kContinue | kThrow, kStore | kRegBFieldOrConstant, kVerifyRegA | kVerifyRegBField) \
- V(0x6E, INVOKE_VIRTUAL, "invoke-virtual", k35c, kIndexMethodRef, kContinue | kThrow | kInvoke, 0, kVerifyRegBMethod | kVerifyVarArgNonZero) \
- V(0x6F, INVOKE_SUPER, "invoke-super", k35c, kIndexMethodRef, kContinue | kThrow | kInvoke, 0, kVerifyRegBMethod | kVerifyVarArgNonZero) \
- V(0x70, INVOKE_DIRECT, "invoke-direct", k35c, kIndexMethodRef, kContinue | kThrow | kInvoke, 0, kVerifyRegBMethod | kVerifyVarArgNonZero) \
- V(0x71, INVOKE_STATIC, "invoke-static", k35c, kIndexMethodRef, kContinue | kThrow | kInvoke, 0, kVerifyRegBMethod | kVerifyVarArg) \
- V(0x72, INVOKE_INTERFACE, "invoke-interface", k35c, kIndexMethodRef, kContinue | kThrow | kInvoke, 0, kVerifyRegBMethod | kVerifyVarArgNonZero) \
- V(0x73, RETURN_VOID_NO_BARRIER, "return-void-no-barrier", k10x, kIndexNone, kReturn, 0, kVerifyNone) \
- V(0x74, INVOKE_VIRTUAL_RANGE, "invoke-virtual/range", k3rc, kIndexMethodRef, kContinue | kThrow | kInvoke, 0, kVerifyRegBMethod | kVerifyVarArgRangeNonZero) \
- V(0x75, INVOKE_SUPER_RANGE, "invoke-super/range", k3rc, kIndexMethodRef, kContinue | kThrow | kInvoke, 0, kVerifyRegBMethod | kVerifyVarArgRangeNonZero) \
- V(0x76, INVOKE_DIRECT_RANGE, "invoke-direct/range", k3rc, kIndexMethodRef, kContinue | kThrow | kInvoke, 0, kVerifyRegBMethod | kVerifyVarArgRangeNonZero) \
- V(0x77, INVOKE_STATIC_RANGE, "invoke-static/range", k3rc, kIndexMethodRef, kContinue | kThrow | kInvoke, 0, kVerifyRegBMethod | kVerifyVarArgRange) \
- V(0x78, INVOKE_INTERFACE_RANGE, "invoke-interface/range", k3rc, kIndexMethodRef, kContinue | kThrow | kInvoke, 0, kVerifyRegBMethod | kVerifyVarArgRangeNonZero) \
- V(0x79, UNUSED_79, "unused-79", k10x, kIndexUnknown, 0, 0, kVerifyError) \
- V(0x7A, UNUSED_7A, "unused-7a", k10x, kIndexUnknown, 0, 0, kVerifyError) \
- V(0x7B, NEG_INT, "neg-int", k12x, kIndexNone, kContinue, 0, kVerifyRegA | kVerifyRegB) \
- V(0x7C, NOT_INT, "not-int", k12x, kIndexNone, kContinue, 0, kVerifyRegA | kVerifyRegB) \
- V(0x7D, NEG_LONG, "neg-long", k12x, kIndexNone, kContinue, 0, kVerifyRegAWide | kVerifyRegBWide) \
- V(0x7E, NOT_LONG, "not-long", k12x, kIndexNone, kContinue, 0, kVerifyRegAWide | kVerifyRegBWide) \
- V(0x7F, NEG_FLOAT, "neg-float", k12x, kIndexNone, kContinue, 0, kVerifyRegA | kVerifyRegB) \
- V(0x80, NEG_DOUBLE, "neg-double", k12x, kIndexNone, kContinue, 0, kVerifyRegAWide | kVerifyRegBWide) \
- V(0x81, INT_TO_LONG, "int-to-long", k12x, kIndexNone, kContinue, kCast, kVerifyRegAWide | kVerifyRegB) \
- V(0x82, INT_TO_FLOAT, "int-to-float", k12x, kIndexNone, kContinue, kCast, kVerifyRegA | kVerifyRegB) \
- V(0x83, INT_TO_DOUBLE, "int-to-double", k12x, kIndexNone, kContinue, kCast, kVerifyRegAWide | kVerifyRegB) \
- V(0x84, LONG_TO_INT, "long-to-int", k12x, kIndexNone, kContinue, kCast, kVerifyRegA | kVerifyRegBWide) \
- V(0x85, LONG_TO_FLOAT, "long-to-float", k12x, kIndexNone, kContinue, kCast, kVerifyRegA | kVerifyRegBWide) \
- V(0x86, LONG_TO_DOUBLE, "long-to-double", k12x, kIndexNone, kContinue, kCast, kVerifyRegAWide | kVerifyRegBWide) \
- V(0x87, FLOAT_TO_INT, "float-to-int", k12x, kIndexNone, kContinue, kCast, kVerifyRegA | kVerifyRegB) \
- V(0x88, FLOAT_TO_LONG, "float-to-long", k12x, kIndexNone, kContinue, kCast, kVerifyRegAWide | kVerifyRegB) \
- V(0x89, FLOAT_TO_DOUBLE, "float-to-double", k12x, kIndexNone, kContinue, kCast, kVerifyRegAWide | kVerifyRegB) \
- V(0x8A, DOUBLE_TO_INT, "double-to-int", k12x, kIndexNone, kContinue, kCast, kVerifyRegA | kVerifyRegBWide) \
- V(0x8B, DOUBLE_TO_LONG, "double-to-long", k12x, kIndexNone, kContinue, kCast, kVerifyRegAWide | kVerifyRegBWide) \
- V(0x8C, DOUBLE_TO_FLOAT, "double-to-float", k12x, kIndexNone, kContinue, kCast, kVerifyRegA | kVerifyRegBWide) \
- V(0x8D, INT_TO_BYTE, "int-to-byte", k12x, kIndexNone, kContinue, kCast, kVerifyRegA | kVerifyRegB) \
- V(0x8E, INT_TO_CHAR, "int-to-char", k12x, kIndexNone, kContinue, kCast, kVerifyRegA | kVerifyRegB) \
- V(0x8F, INT_TO_SHORT, "int-to-short", k12x, kIndexNone, kContinue, kCast, kVerifyRegA | kVerifyRegB) \
- V(0x90, ADD_INT, "add-int", k23x, kIndexNone, kContinue, kAdd, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
- V(0x91, SUB_INT, "sub-int", k23x, kIndexNone, kContinue, kSubtract, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
- V(0x92, MUL_INT, "mul-int", k23x, kIndexNone, kContinue, kMultiply, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
- V(0x93, DIV_INT, "div-int", k23x, kIndexNone, kContinue | kThrow, kDivide, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
- V(0x94, REM_INT, "rem-int", k23x, kIndexNone, kContinue | kThrow, kRemainder, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
- V(0x95, AND_INT, "and-int", k23x, kIndexNone, kContinue, kAnd, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
- V(0x96, OR_INT, "or-int", k23x, kIndexNone, kContinue, kOr, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
- V(0x97, XOR_INT, "xor-int", k23x, kIndexNone, kContinue, kXor, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
- V(0x98, SHL_INT, "shl-int", k23x, kIndexNone, kContinue, kShl, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
- V(0x99, SHR_INT, "shr-int", k23x, kIndexNone, kContinue, kShr, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
- V(0x9A, USHR_INT, "ushr-int", k23x, kIndexNone, kContinue, kUshr, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
- V(0x9B, ADD_LONG, "add-long", k23x, kIndexNone, kContinue, kAdd, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \
- V(0x9C, SUB_LONG, "sub-long", k23x, kIndexNone, kContinue, kSubtract, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \
- V(0x9D, MUL_LONG, "mul-long", k23x, kIndexNone, kContinue, kMultiply, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \
- V(0x9E, DIV_LONG, "div-long", k23x, kIndexNone, kContinue | kThrow, kDivide, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \
- V(0x9F, REM_LONG, "rem-long", k23x, kIndexNone, kContinue | kThrow, kRemainder, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \
- V(0xA0, AND_LONG, "and-long", k23x, kIndexNone, kContinue, kAnd, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \
- V(0xA1, OR_LONG, "or-long", k23x, kIndexNone, kContinue, kOr, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \
- V(0xA2, XOR_LONG, "xor-long", k23x, kIndexNone, kContinue, kXor, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \
- V(0xA3, SHL_LONG, "shl-long", k23x, kIndexNone, kContinue, kShl, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegC) \
- V(0xA4, SHR_LONG, "shr-long", k23x, kIndexNone, kContinue, kShr, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegC) \
- V(0xA5, USHR_LONG, "ushr-long", k23x, kIndexNone, kContinue, kUshr, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegC) \
- V(0xA6, ADD_FLOAT, "add-float", k23x, kIndexNone, kContinue, kAdd, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
- V(0xA7, SUB_FLOAT, "sub-float", k23x, kIndexNone, kContinue, kSubtract, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
- V(0xA8, MUL_FLOAT, "mul-float", k23x, kIndexNone, kContinue, kMultiply, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
- V(0xA9, DIV_FLOAT, "div-float", k23x, kIndexNone, kContinue, kDivide, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
- V(0xAA, REM_FLOAT, "rem-float", k23x, kIndexNone, kContinue, kRemainder, kVerifyRegA | kVerifyRegB | kVerifyRegC) \
- V(0xAB, ADD_DOUBLE, "add-double", k23x, kIndexNone, kContinue, kAdd, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \
- V(0xAC, SUB_DOUBLE, "sub-double", k23x, kIndexNone, kContinue, kSubtract, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \
- V(0xAD, MUL_DOUBLE, "mul-double", k23x, kIndexNone, kContinue, kMultiply, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \
- V(0xAE, DIV_DOUBLE, "div-double", k23x, kIndexNone, kContinue, kDivide, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \
- V(0xAF, REM_DOUBLE, "rem-double", k23x, kIndexNone, kContinue, kRemainder, kVerifyRegAWide | kVerifyRegBWide | kVerifyRegCWide) \
- V(0xB0, ADD_INT_2ADDR, "add-int/2addr", k12x, kIndexNone, kContinue, kAdd, kVerifyRegA | kVerifyRegB) \
- V(0xB1, SUB_INT_2ADDR, "sub-int/2addr", k12x, kIndexNone, kContinue, kSubtract, kVerifyRegA | kVerifyRegB) \
- V(0xB2, MUL_INT_2ADDR, "mul-int/2addr", k12x, kIndexNone, kContinue, kMultiply, kVerifyRegA | kVerifyRegB) \
- V(0xB3, DIV_INT_2ADDR, "div-int/2addr", k12x, kIndexNone, kContinue | kThrow, kDivide, kVerifyRegA | kVerifyRegB) \
- V(0xB4, REM_INT_2ADDR, "rem-int/2addr", k12x, kIndexNone, kContinue | kThrow, kRemainder, kVerifyRegA | kVerifyRegB) \
- V(0xB5, AND_INT_2ADDR, "and-int/2addr", k12x, kIndexNone, kContinue, kAnd, kVerifyRegA | kVerifyRegB) \
- V(0xB6, OR_INT_2ADDR, "or-int/2addr", k12x, kIndexNone, kContinue, kOr, kVerifyRegA | kVerifyRegB) \
- V(0xB7, XOR_INT_2ADDR, "xor-int/2addr", k12x, kIndexNone, kContinue, kXor, kVerifyRegA | kVerifyRegB) \
- V(0xB8, SHL_INT_2ADDR, "shl-int/2addr", k12x, kIndexNone, kContinue, kShl, kVerifyRegA | kVerifyRegB) \
- V(0xB9, SHR_INT_2ADDR, "shr-int/2addr", k12x, kIndexNone, kContinue, kShr, kVerifyRegA | kVerifyRegB) \
- V(0xBA, USHR_INT_2ADDR, "ushr-int/2addr", k12x, kIndexNone, kContinue, kUshr, kVerifyRegA | kVerifyRegB) \
- V(0xBB, ADD_LONG_2ADDR, "add-long/2addr", k12x, kIndexNone, kContinue, kAdd, kVerifyRegAWide | kVerifyRegBWide) \
- V(0xBC, SUB_LONG_2ADDR, "sub-long/2addr", k12x, kIndexNone, kContinue, kSubtract, kVerifyRegAWide | kVerifyRegBWide) \
- V(0xBD, MUL_LONG_2ADDR, "mul-long/2addr", k12x, kIndexNone, kContinue, kMultiply, kVerifyRegAWide | kVerifyRegBWide) \
- V(0xBE, DIV_LONG_2ADDR, "div-long/2addr", k12x, kIndexNone, kContinue | kThrow, kDivide, kVerifyRegAWide | kVerifyRegBWide) \
- V(0xBF, REM_LONG_2ADDR, "rem-long/2addr", k12x, kIndexNone, kContinue | kThrow, kRemainder, kVerifyRegAWide | kVerifyRegBWide) \
- V(0xC0, AND_LONG_2ADDR, "and-long/2addr", k12x, kIndexNone, kContinue, kAnd, kVerifyRegAWide | kVerifyRegBWide) \
- V(0xC1, OR_LONG_2ADDR, "or-long/2addr", k12x, kIndexNone, kContinue, kOr, kVerifyRegAWide | kVerifyRegBWide) \
- V(0xC2, XOR_LONG_2ADDR, "xor-long/2addr", k12x, kIndexNone, kContinue, kXor, kVerifyRegAWide | kVerifyRegBWide) \
- V(0xC3, SHL_LONG_2ADDR, "shl-long/2addr", k12x, kIndexNone, kContinue, kShl, kVerifyRegAWide | kVerifyRegB) \
- V(0xC4, SHR_LONG_2ADDR, "shr-long/2addr", k12x, kIndexNone, kContinue, kShr, kVerifyRegAWide | kVerifyRegB) \
- V(0xC5, USHR_LONG_2ADDR, "ushr-long/2addr", k12x, kIndexNone, kContinue, kUshr, kVerifyRegAWide | kVerifyRegB) \
- V(0xC6, ADD_FLOAT_2ADDR, "add-float/2addr", k12x, kIndexNone, kContinue, kAdd, kVerifyRegA | kVerifyRegB) \
- V(0xC7, SUB_FLOAT_2ADDR, "sub-float/2addr", k12x, kIndexNone, kContinue, kSubtract, kVerifyRegA | kVerifyRegB) \
- V(0xC8, MUL_FLOAT_2ADDR, "mul-float/2addr", k12x, kIndexNone, kContinue, kMultiply, kVerifyRegA | kVerifyRegB) \
- V(0xC9, DIV_FLOAT_2ADDR, "div-float/2addr", k12x, kIndexNone, kContinue, kDivide, kVerifyRegA | kVerifyRegB) \
- V(0xCA, REM_FLOAT_2ADDR, "rem-float/2addr", k12x, kIndexNone, kContinue, kRemainder, kVerifyRegA | kVerifyRegB) \
- V(0xCB, ADD_DOUBLE_2ADDR, "add-double/2addr", k12x, kIndexNone, kContinue, kAdd, kVerifyRegAWide | kVerifyRegBWide) \
- V(0xCC, SUB_DOUBLE_2ADDR, "sub-double/2addr", k12x, kIndexNone, kContinue, kSubtract, kVerifyRegAWide | kVerifyRegBWide) \
- V(0xCD, MUL_DOUBLE_2ADDR, "mul-double/2addr", k12x, kIndexNone, kContinue, kMultiply, kVerifyRegAWide | kVerifyRegBWide) \
- V(0xCE, DIV_DOUBLE_2ADDR, "div-double/2addr", k12x, kIndexNone, kContinue, kDivide, kVerifyRegAWide | kVerifyRegBWide) \
- V(0xCF, REM_DOUBLE_2ADDR, "rem-double/2addr", k12x, kIndexNone, kContinue, kRemainder, kVerifyRegAWide | kVerifyRegBWide) \
- V(0xD0, ADD_INT_LIT16, "add-int/lit16", k22s, kIndexNone, kContinue, kAdd | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \
- V(0xD1, RSUB_INT, "rsub-int", k22s, kIndexNone, kContinue, kSubtract | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \
- V(0xD2, MUL_INT_LIT16, "mul-int/lit16", k22s, kIndexNone, kContinue, kMultiply | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \
- V(0xD3, DIV_INT_LIT16, "div-int/lit16", k22s, kIndexNone, kContinue | kThrow, kDivide | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \
- V(0xD4, REM_INT_LIT16, "rem-int/lit16", k22s, kIndexNone, kContinue | kThrow, kRemainder | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \
- V(0xD5, AND_INT_LIT16, "and-int/lit16", k22s, kIndexNone, kContinue, kAnd | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \
- V(0xD6, OR_INT_LIT16, "or-int/lit16", k22s, kIndexNone, kContinue, kOr | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \
- V(0xD7, XOR_INT_LIT16, "xor-int/lit16", k22s, kIndexNone, kContinue, kXor | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \
- V(0xD8, ADD_INT_LIT8, "add-int/lit8", k22b, kIndexNone, kContinue, kAdd | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \
- V(0xD9, RSUB_INT_LIT8, "rsub-int/lit8", k22b, kIndexNone, kContinue, kSubtract | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \
- V(0xDA, MUL_INT_LIT8, "mul-int/lit8", k22b, kIndexNone, kContinue, kMultiply | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \
- V(0xDB, DIV_INT_LIT8, "div-int/lit8", k22b, kIndexNone, kContinue | kThrow, kDivide | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \
- V(0xDC, REM_INT_LIT8, "rem-int/lit8", k22b, kIndexNone, kContinue | kThrow, kRemainder | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \
- V(0xDD, AND_INT_LIT8, "and-int/lit8", k22b, kIndexNone, kContinue, kAnd | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \
- V(0xDE, OR_INT_LIT8, "or-int/lit8", k22b, kIndexNone, kContinue, kOr | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \
- V(0xDF, XOR_INT_LIT8, "xor-int/lit8", k22b, kIndexNone, kContinue, kXor | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \
- V(0xE0, SHL_INT_LIT8, "shl-int/lit8", k22b, kIndexNone, kContinue, kShl | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \
- V(0xE1, SHR_INT_LIT8, "shr-int/lit8", k22b, kIndexNone, kContinue, kShr | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \
- V(0xE2, USHR_INT_LIT8, "ushr-int/lit8", k22b, kIndexNone, kContinue, kUshr | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB) \
- V(0xE3, IGET_QUICK, "iget-quick", k22c, kIndexFieldOffset, kContinue | kThrow, kLoad | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRuntimeOnly) \
- V(0xE4, IGET_WIDE_QUICK, "iget-wide-quick", k22c, kIndexFieldOffset, kContinue | kThrow, kLoad | kRegCFieldOrConstant, kVerifyRegAWide | kVerifyRegB | kVerifyRuntimeOnly) \
- V(0xE5, IGET_OBJECT_QUICK, "iget-object-quick", k22c, kIndexFieldOffset, kContinue | kThrow, kLoad | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRuntimeOnly) \
- V(0xE6, IPUT_QUICK, "iput-quick", k22c, kIndexFieldOffset, kContinue | kThrow, kStore | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRuntimeOnly) \
- V(0xE7, IPUT_WIDE_QUICK, "iput-wide-quick", k22c, kIndexFieldOffset, kContinue | kThrow, kStore | kRegCFieldOrConstant, kVerifyRegAWide | kVerifyRegB | kVerifyRuntimeOnly) \
- V(0xE8, IPUT_OBJECT_QUICK, "iput-object-quick", k22c, kIndexFieldOffset, kContinue | kThrow, kStore | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRuntimeOnly) \
- V(0xE9, INVOKE_VIRTUAL_QUICK, "invoke-virtual-quick", k35c, kIndexVtableOffset, kContinue | kThrow | kInvoke, 0, kVerifyVarArgNonZero | kVerifyRuntimeOnly) \
- V(0xEA, INVOKE_VIRTUAL_RANGE_QUICK, "invoke-virtual/range-quick", k3rc, kIndexVtableOffset, kContinue | kThrow | kInvoke, 0, kVerifyVarArgRangeNonZero | kVerifyRuntimeOnly) \
- V(0xEB, IPUT_BOOLEAN_QUICK, "iput-boolean-quick", k22c, kIndexFieldOffset, kContinue | kThrow, kStore | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRuntimeOnly) \
- V(0xEC, IPUT_BYTE_QUICK, "iput-byte-quick", k22c, kIndexFieldOffset, kContinue | kThrow, kStore | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRuntimeOnly) \
- V(0xED, IPUT_CHAR_QUICK, "iput-char-quick", k22c, kIndexFieldOffset, kContinue | kThrow, kStore | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRuntimeOnly) \
- V(0xEE, IPUT_SHORT_QUICK, "iput-short-quick", k22c, kIndexFieldOffset, kContinue | kThrow, kStore | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRuntimeOnly) \
- V(0xEF, IGET_BOOLEAN_QUICK, "iget-boolean-quick", k22c, kIndexFieldOffset, kContinue | kThrow, kLoad | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRuntimeOnly) \
- V(0xF0, IGET_BYTE_QUICK, "iget-byte-quick", k22c, kIndexFieldOffset, kContinue | kThrow, kLoad | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRuntimeOnly) \
- V(0xF1, IGET_CHAR_QUICK, "iget-char-quick", k22c, kIndexFieldOffset, kContinue | kThrow, kLoad | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRuntimeOnly) \
- V(0xF2, IGET_SHORT_QUICK, "iget-short-quick", k22c, kIndexFieldOffset, kContinue | kThrow, kLoad | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRuntimeOnly) \
- V(0xF3, UNUSED_F3, "unused-f3", k10x, kIndexUnknown, 0, 0, kVerifyError) \
- V(0xF4, UNUSED_F4, "unused-f4", k10x, kIndexUnknown, 0, 0, kVerifyError) \
- V(0xF5, UNUSED_F5, "unused-f5", k10x, kIndexUnknown, 0, 0, kVerifyError) \
- V(0xF6, UNUSED_F6, "unused-f6", k10x, kIndexUnknown, 0, 0, kVerifyError) \
- V(0xF7, UNUSED_F7, "unused-f7", k10x, kIndexUnknown, 0, 0, kVerifyError) \
- V(0xF8, UNUSED_F8, "unused-f8", k10x, kIndexUnknown, 0, 0, kVerifyError) \
- V(0xF9, UNUSED_F9, "unused-f9", k10x, kIndexUnknown, 0, 0, kVerifyError) \
- V(0xFA, INVOKE_POLYMORPHIC, "invoke-polymorphic", k45cc, kIndexMethodAndProtoRef, kContinue | kThrow | kInvoke, 0, kVerifyRegBMethod | kVerifyVarArgNonZero | kVerifyRegHPrototype) \
- V(0xFB, INVOKE_POLYMORPHIC_RANGE, "invoke-polymorphic/range", k4rcc, kIndexMethodAndProtoRef, kContinue | kThrow | kInvoke, 0, kVerifyRegBMethod | kVerifyVarArgRangeNonZero | kVerifyRegHPrototype) \
- V(0xFC, INVOKE_CUSTOM, "invoke-custom", k35c, kIndexCallSiteRef, kContinue | kThrow, 0, kVerifyRegBCallSite | kVerifyVarArg) \
- V(0xFD, INVOKE_CUSTOM_RANGE, "invoke-custom/range", k3rc, kIndexCallSiteRef, kContinue | kThrow, 0, kVerifyRegBCallSite | kVerifyVarArgRange) \
- V(0xFE, CONST_METHOD_HANDLE, "const-method-handle", k21c, kIndexMethodHandleRef, kContinue | kThrow, 0, kVerifyRegA | kVerifyRegBMethodHandle) \
- V(0xFF, CONST_METHOD_TYPE, "const-method-type", k21c, kIndexProtoRef, kContinue | kThrow, 0, kVerifyRegA | kVerifyRegBPrototype)
-
-#define DEX_INSTRUCTION_FORMAT_LIST(V) \
- V(k10x) \
- V(k12x) \
- V(k11n) \
- V(k11x) \
- V(k10t) \
- V(k20t) \
- V(k22x) \
- V(k21t) \
- V(k21s) \
- V(k21h) \
- V(k21c) \
- V(k23x) \
- V(k22b) \
- V(k22t) \
- V(k22s) \
- V(k22c) \
- V(k32x) \
- V(k30t) \
- V(k31t) \
- V(k31i) \
- V(k31c) \
- V(k35c) \
- V(k3rc) \
- V(k45cc) \
- V(k4rcc) \
- V(k51l)
-
-#endif // ART_RUNTIME_DEX_DEX_INSTRUCTION_LIST_H_
-#undef ART_RUNTIME_DEX_DEX_INSTRUCTION_LIST_H_ // the guard in this file is just for cpplint
diff --git a/runtime/dex/dex_instruction_test.cc b/runtime/dex/dex_instruction_test.cc
deleted file mode 100644
index c944085b9e..0000000000
--- a/runtime/dex/dex_instruction_test.cc
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "dex_instruction-inl.h"
-#include "dex_instruction_iterator.h"
-#include "gtest/gtest.h"
-
-namespace art {
-
-TEST(StaticGetters, PropertiesOfNopTest) {
- Instruction::Code nop = Instruction::NOP;
- EXPECT_STREQ("nop", Instruction::Name(nop));
- EXPECT_EQ(Instruction::k10x, Instruction::FormatOf(nop));
- EXPECT_EQ(Instruction::kIndexNone, Instruction::IndexTypeOf(nop));
- EXPECT_EQ(Instruction::kContinue, Instruction::FlagsOf(nop));
- EXPECT_EQ(Instruction::kVerifyNone, Instruction::VerifyFlagsOf(nop));
-}
-
-static void Build45cc(uint8_t num_args, uint16_t method_idx, uint16_t proto_idx,
- uint16_t arg_regs, uint16_t* out) {
- // A = num argument registers
- // B = method_idx
- // C - G = argument registers
- // H = proto_idx
- //
- // op = 0xFA
- //
- // format:
- // AG op BBBB FEDC HHHH
- out[0] = 0;
- out[0] |= (num_args << 12);
- out[0] |= 0x00FA;
-
- out[1] = method_idx;
- out[2] = arg_regs;
- out[3] = proto_idx;
-}
-
-static void Build4rcc(uint16_t num_args, uint16_t method_idx, uint16_t proto_idx,
- uint16_t arg_regs_start, uint16_t* out) {
- // A = num argument registers
- // B = method_idx
- // C = first argument register
- // H = proto_idx
- //
- // op = 0xFB
- //
- // format:
- // AA op BBBB CCCC HHHH
- out[0] = 0;
- out[0] |= (num_args << 8);
- out[0] |= 0x00FB;
-
- out[1] = method_idx;
- out[2] = arg_regs_start;
- out[3] = proto_idx;
-}
-
-TEST(Instruction, PropertiesOf45cc) {
- uint16_t instruction[4];
- Build45cc(4u /* num_vregs */, 16u /* method_idx */, 32u /* proto_idx */,
- 0xcafe /* arg_regs */, instruction);
-
- DexInstructionIterator ins(instruction, /*dex_pc*/ 0u);
- ASSERT_EQ(4u, ins->SizeInCodeUnits());
-
- ASSERT_TRUE(ins->HasVRegA());
- ASSERT_EQ(4, ins->VRegA());
- ASSERT_EQ(4u, ins->VRegA_45cc());
- ASSERT_EQ(4u, ins->VRegA_45cc(instruction[0]));
-
- ASSERT_TRUE(ins->HasVRegB());
- ASSERT_EQ(16, ins->VRegB());
- ASSERT_EQ(16u, ins->VRegB_45cc());
-
- ASSERT_TRUE(ins->HasVRegC());
- ASSERT_EQ(0xe, ins->VRegC());
- ASSERT_EQ(0xe, ins->VRegC_45cc());
-
- ASSERT_TRUE(ins->HasVRegH());
- ASSERT_EQ(32, ins->VRegH());
- ASSERT_EQ(32, ins->VRegH_45cc());
-
- ASSERT_TRUE(ins->HasVarArgs());
-
- uint32_t arg_regs[Instruction::kMaxVarArgRegs];
- ins->GetVarArgs(arg_regs);
- ASSERT_EQ(0xeu, arg_regs[0]);
- ASSERT_EQ(0xfu, arg_regs[1]);
- ASSERT_EQ(0xau, arg_regs[2]);
- ASSERT_EQ(0xcu, arg_regs[3]);
-}
-
-TEST(Instruction, PropertiesOf4rcc) {
- uint16_t instruction[4];
- Build4rcc(4u /* num_vregs */, 16u /* method_idx */, 32u /* proto_idx */,
- 0xcafe /* arg_regs */, instruction);
-
- DexInstructionIterator ins(instruction, /*dex_pc*/ 0u);
- ASSERT_EQ(4u, ins->SizeInCodeUnits());
-
- ASSERT_TRUE(ins->HasVRegA());
- ASSERT_EQ(4, ins->VRegA());
- ASSERT_EQ(4u, ins->VRegA_4rcc());
- ASSERT_EQ(4u, ins->VRegA_4rcc(instruction[0]));
-
- ASSERT_TRUE(ins->HasVRegB());
- ASSERT_EQ(16, ins->VRegB());
- ASSERT_EQ(16u, ins->VRegB_4rcc());
-
- ASSERT_TRUE(ins->HasVRegC());
- ASSERT_EQ(0xcafe, ins->VRegC());
- ASSERT_EQ(0xcafe, ins->VRegC_4rcc());
-
- ASSERT_TRUE(ins->HasVRegH());
- ASSERT_EQ(32, ins->VRegH());
- ASSERT_EQ(32, ins->VRegH_4rcc());
-
- ASSERT_FALSE(ins->HasVarArgs());
-}
-
-static void Build35c(uint16_t* out,
- Instruction::Code code,
- uint16_t method_idx,
- std::vector<uint16_t> args) {
- out[0] = 0;
- out[0] |= (args.size() << 12);
- out[0] |= static_cast<uint16_t>(code);
- out[1] = method_idx;
- size_t i = 0;
- out[2] = 0;
- for (; i < 4 && i < args.size(); ++i) {
- out[2] |= args[i] << (i * 4);
- }
- if (args.size() == 5) {
- out[0] |= args[4] << 8;
- }
-}
-
-static std::string DumpInst35c(Instruction::Code code,
- uint16_t method_idx,
- std::vector<uint16_t> args) {
- uint16_t inst[6] = {};
- Build35c(inst, code, method_idx, args);
- return Instruction::At(inst)->DumpString(nullptr);
-}
-
-TEST(Instruction, DumpString) {
- EXPECT_EQ(DumpInst35c(Instruction::FILLED_NEW_ARRAY, 1234, {3, 2}),
- "filled-new-array {v3, v2}, type@1234");
- EXPECT_EQ(DumpInst35c(Instruction::INVOKE_VIRTUAL, 1234, {3, 2, 1, 5, 6}),
- "invoke-virtual {v3, v2, v1, v5, v6}, thing@1234");
- EXPECT_EQ(DumpInst35c(Instruction::INVOKE_VIRTUAL_QUICK, 1234, {3, 2, 1, 5}),
- "invoke-virtual-quick {v3, v2, v1, v5}, thing@1234");
- EXPECT_EQ(DumpInst35c(Instruction::INVOKE_CUSTOM, 1234, {3, 2, 1}),
- "invoke-custom {v3, v2, v1}, thing@1234");
-}
-
-} // namespace art
diff --git a/runtime/dex/dex_instruction_utils.h b/runtime/dex/dex_instruction_utils.h
deleted file mode 100644
index 27501927e7..0000000000
--- a/runtime/dex/dex_instruction_utils.h
+++ /dev/null
@@ -1,219 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ART_RUNTIME_DEX_DEX_INSTRUCTION_UTILS_H_
-#define ART_RUNTIME_DEX_DEX_INSTRUCTION_UTILS_H_
-
-#include "dex_instruction.h"
-
-namespace art {
-
-// Dex invoke type corresponds to the ordering of INVOKE instructions;
-// this order is the same for range and non-range invokes.
-enum DexInvokeType : uint8_t {
- kDexInvokeVirtual = 0, // invoke-virtual, invoke-virtual-range
- kDexInvokeSuper, // invoke-super, invoke-super-range
- kDexInvokeDirect, // invoke-direct, invoke-direct-range
- kDexInvokeStatic, // invoke-static, invoke-static-range
- kDexInvokeInterface, // invoke-interface, invoke-interface-range
- kDexInvokeTypeCount
-};
-
-// Dex instruction memory access types correspond to the ordering of GET/PUT instructions;
-// this order is the same for IGET, IPUT, SGET, SPUT, AGET and APUT.
-enum DexMemAccessType : uint8_t {
- kDexMemAccessWord = 0, // op 0; int or float, the actual type is not encoded.
- kDexMemAccessWide, // op_WIDE 1; long or double, the actual type is not encoded.
- kDexMemAccessObject, // op_OBJECT 2; the actual reference type is not encoded.
- kDexMemAccessBoolean, // op_BOOLEAN 3
- kDexMemAccessByte, // op_BYTE 4
- kDexMemAccessChar, // op_CHAR 5
- kDexMemAccessShort, // op_SHORT 6
- kDexMemAccessTypeCount
-};
-
-std::ostream& operator<<(std::ostream& os, const DexMemAccessType& type);
-
-// NOTE: The following functions disregard quickened instructions.
-
-// By "direct" const we mean to exclude const-string and const-class
-// which load data from somewhere else, i.e. indirectly.
-constexpr bool IsInstructionDirectConst(Instruction::Code opcode) {
- return Instruction::CONST_4 <= opcode && opcode <= Instruction::CONST_WIDE_HIGH16;
-}
-
-constexpr bool IsInstructionConstWide(Instruction::Code opcode) {
- return Instruction::CONST_WIDE_16 <= opcode && opcode <= Instruction::CONST_WIDE_HIGH16;
-}
-
-constexpr bool IsInstructionReturn(Instruction::Code opcode) {
- return Instruction::RETURN_VOID <= opcode && opcode <= Instruction::RETURN_OBJECT;
-}
-
-constexpr bool IsInstructionInvoke(Instruction::Code opcode) {
- return Instruction::INVOKE_VIRTUAL <= opcode && opcode <= Instruction::INVOKE_INTERFACE_RANGE &&
- opcode != Instruction::RETURN_VOID_NO_BARRIER;
-}
-
-constexpr bool IsInstructionQuickInvoke(Instruction::Code opcode) {
- return opcode == Instruction::INVOKE_VIRTUAL_QUICK ||
- opcode == Instruction::INVOKE_VIRTUAL_RANGE_QUICK;
-}
-
-constexpr bool IsInstructionInvokeStatic(Instruction::Code opcode) {
- return opcode == Instruction::INVOKE_STATIC || opcode == Instruction::INVOKE_STATIC_RANGE;
-}
-
-constexpr bool IsInstructionGoto(Instruction::Code opcode) {
- return Instruction::GOTO <= opcode && opcode <= Instruction::GOTO_32;
-}
-
-constexpr bool IsInstructionIfCc(Instruction::Code opcode) {
- return Instruction::IF_EQ <= opcode && opcode <= Instruction::IF_LE;
-}
-
-constexpr bool IsInstructionIfCcZ(Instruction::Code opcode) {
- return Instruction::IF_EQZ <= opcode && opcode <= Instruction::IF_LEZ;
-}
-
-constexpr bool IsInstructionIGet(Instruction::Code code) {
- return Instruction::IGET <= code && code <= Instruction::IGET_SHORT;
-}
-
-constexpr bool IsInstructionIPut(Instruction::Code code) {
- return Instruction::IPUT <= code && code <= Instruction::IPUT_SHORT;
-}
-
-constexpr bool IsInstructionSGet(Instruction::Code code) {
- return Instruction::SGET <= code && code <= Instruction::SGET_SHORT;
-}
-
-constexpr bool IsInstructionSPut(Instruction::Code code) {
- return Instruction::SPUT <= code && code <= Instruction::SPUT_SHORT;
-}
-
-constexpr bool IsInstructionAGet(Instruction::Code code) {
- return Instruction::AGET <= code && code <= Instruction::AGET_SHORT;
-}
-
-constexpr bool IsInstructionAPut(Instruction::Code code) {
- return Instruction::APUT <= code && code <= Instruction::APUT_SHORT;
-}
-
-constexpr bool IsInstructionIGetOrIPut(Instruction::Code code) {
- return Instruction::IGET <= code && code <= Instruction::IPUT_SHORT;
-}
-
-constexpr bool IsInstructionIGetQuickOrIPutQuick(Instruction::Code code) {
- return (code >= Instruction::IGET_QUICK && code <= Instruction::IPUT_OBJECT_QUICK) ||
- (code >= Instruction::IPUT_BOOLEAN_QUICK && code <= Instruction::IGET_SHORT_QUICK);
-}
-
-constexpr bool IsInstructionSGetOrSPut(Instruction::Code code) {
- return Instruction::SGET <= code && code <= Instruction::SPUT_SHORT;
-}
-
-constexpr bool IsInstructionAGetOrAPut(Instruction::Code code) {
- return Instruction::AGET <= code && code <= Instruction::APUT_SHORT;
-}
-
-constexpr bool IsInstructionBinOp2Addr(Instruction::Code code) {
- return Instruction::ADD_INT_2ADDR <= code && code <= Instruction::REM_DOUBLE_2ADDR;
-}
-
-constexpr bool IsInvokeInstructionRange(Instruction::Code opcode) {
- DCHECK(IsInstructionInvoke(opcode));
- return opcode >= Instruction::INVOKE_VIRTUAL_RANGE;
-}
-
-constexpr DexInvokeType InvokeInstructionType(Instruction::Code opcode) {
- DCHECK(IsInstructionInvoke(opcode));
- return static_cast<DexInvokeType>(IsInvokeInstructionRange(opcode)
- ? (opcode - Instruction::INVOKE_VIRTUAL_RANGE)
- : (opcode - Instruction::INVOKE_VIRTUAL));
-}
-
-constexpr DexMemAccessType IGetMemAccessType(Instruction::Code code) {
- DCHECK(IsInstructionIGet(code));
- return static_cast<DexMemAccessType>(code - Instruction::IGET);
-}
-
-constexpr DexMemAccessType IPutMemAccessType(Instruction::Code code) {
- DCHECK(IsInstructionIPut(code));
- return static_cast<DexMemAccessType>(code - Instruction::IPUT);
-}
-
-constexpr DexMemAccessType SGetMemAccessType(Instruction::Code code) {
- DCHECK(IsInstructionSGet(code));
- return static_cast<DexMemAccessType>(code - Instruction::SGET);
-}
-
-constexpr DexMemAccessType SPutMemAccessType(Instruction::Code code) {
- DCHECK(IsInstructionSPut(code));
- return static_cast<DexMemAccessType>(code - Instruction::SPUT);
-}
-
-constexpr DexMemAccessType AGetMemAccessType(Instruction::Code code) {
- DCHECK(IsInstructionAGet(code));
- return static_cast<DexMemAccessType>(code - Instruction::AGET);
-}
-
-constexpr DexMemAccessType APutMemAccessType(Instruction::Code code) {
- DCHECK(IsInstructionAPut(code));
- return static_cast<DexMemAccessType>(code - Instruction::APUT);
-}
-
-constexpr DexMemAccessType IGetOrIPutMemAccessType(Instruction::Code code) {
- DCHECK(IsInstructionIGetOrIPut(code));
- return (code >= Instruction::IPUT) ? IPutMemAccessType(code) : IGetMemAccessType(code);
-}
-
-inline DexMemAccessType IGetQuickOrIPutQuickMemAccessType(Instruction::Code code) {
- DCHECK(IsInstructionIGetQuickOrIPutQuick(code));
- switch (code) {
- case Instruction::IGET_QUICK: case Instruction::IPUT_QUICK:
- return kDexMemAccessWord;
- case Instruction::IGET_WIDE_QUICK: case Instruction::IPUT_WIDE_QUICK:
- return kDexMemAccessWide;
- case Instruction::IGET_OBJECT_QUICK: case Instruction::IPUT_OBJECT_QUICK:
- return kDexMemAccessObject;
- case Instruction::IGET_BOOLEAN_QUICK: case Instruction::IPUT_BOOLEAN_QUICK:
- return kDexMemAccessBoolean;
- case Instruction::IGET_BYTE_QUICK: case Instruction::IPUT_BYTE_QUICK:
- return kDexMemAccessByte;
- case Instruction::IGET_CHAR_QUICK: case Instruction::IPUT_CHAR_QUICK:
- return kDexMemAccessChar;
- case Instruction::IGET_SHORT_QUICK: case Instruction::IPUT_SHORT_QUICK:
- return kDexMemAccessShort;
- default:
- LOG(FATAL) << code;
- UNREACHABLE();
- }
-}
-
-constexpr DexMemAccessType SGetOrSPutMemAccessType(Instruction::Code code) {
- DCHECK(IsInstructionSGetOrSPut(code));
- return (code >= Instruction::SPUT) ? SPutMemAccessType(code) : SGetMemAccessType(code);
-}
-
-constexpr DexMemAccessType AGetOrAPutMemAccessType(Instruction::Code code) {
- DCHECK(IsInstructionAGetOrAPut(code));
- return (code >= Instruction::APUT) ? APutMemAccessType(code) : AGetMemAccessType(code);
-}
-
-} // namespace art
-
-#endif // ART_RUNTIME_DEX_DEX_INSTRUCTION_UTILS_H_
diff --git a/runtime/dex/invoke_type.h b/runtime/dex/invoke_type.h
deleted file mode 100644
index 726d269a3e..0000000000
--- a/runtime/dex/invoke_type.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ART_RUNTIME_DEX_INVOKE_TYPE_H_
-#define ART_RUNTIME_DEX_INVOKE_TYPE_H_
-
-#include <iosfwd>
-
-namespace art {
-
-enum InvokeType : uint32_t {
- kStatic, // <<static>>
- kDirect, // <<direct>>
- kVirtual, // <<virtual>>
- kSuper, // <<super>>
- kInterface, // <<interface>>
- kPolymorphic, // <<polymorphic>>
- kMaxInvokeType = kPolymorphic
-};
-
-std::ostream& operator<<(std::ostream& os, const InvokeType& rhs);
-
-} // namespace art
-
-#endif // ART_RUNTIME_DEX_INVOKE_TYPE_H_
diff --git a/runtime/dex/modifiers.cc b/runtime/dex/modifiers.cc
deleted file mode 100644
index 30daefb172..0000000000
--- a/runtime/dex/modifiers.cc
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <string>
-
-#include "modifiers.h"
-
-namespace art {
-
-std::string PrettyJavaAccessFlags(uint32_t access_flags) {
- std::string result;
- if ((access_flags & kAccPublic) != 0) {
- result += "public ";
- }
- if ((access_flags & kAccProtected) != 0) {
- result += "protected ";
- }
- if ((access_flags & kAccPrivate) != 0) {
- result += "private ";
- }
- if ((access_flags & kAccFinal) != 0) {
- result += "final ";
- }
- if ((access_flags & kAccStatic) != 0) {
- result += "static ";
- }
- if ((access_flags & kAccAbstract) != 0) {
- result += "abstract ";
- }
- if ((access_flags & kAccInterface) != 0) {
- result += "interface ";
- }
- if ((access_flags & kAccTransient) != 0) {
- result += "transient ";
- }
- if ((access_flags & kAccVolatile) != 0) {
- result += "volatile ";
- }
- if ((access_flags & kAccSynchronized) != 0) {
- result += "synchronized ";
- }
- return result;
-}
-
-} // namespace art
diff --git a/runtime/dex/modifiers.h b/runtime/dex/modifiers.h
deleted file mode 100644
index 2998f602d4..0000000000
--- a/runtime/dex/modifiers.h
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ART_RUNTIME_DEX_MODIFIERS_H_
-#define ART_RUNTIME_DEX_MODIFIERS_H_
-
-#include <stdint.h>
-
-namespace art {
-
-static constexpr uint32_t kAccPublic = 0x0001; // class, field, method, ic
-static constexpr uint32_t kAccPrivate = 0x0002; // field, method, ic
-static constexpr uint32_t kAccProtected = 0x0004; // field, method, ic
-static constexpr uint32_t kAccStatic = 0x0008; // field, method, ic
-static constexpr uint32_t kAccFinal = 0x0010; // class, field, method, ic
-static constexpr uint32_t kAccSynchronized = 0x0020; // method (only allowed on natives)
-static constexpr uint32_t kAccSuper = 0x0020; // class (not used in dex)
-static constexpr uint32_t kAccVolatile = 0x0040; // field
-static constexpr uint32_t kAccBridge = 0x0040; // method (1.5)
-static constexpr uint32_t kAccTransient = 0x0080; // field
-static constexpr uint32_t kAccVarargs = 0x0080; // method (1.5)
-static constexpr uint32_t kAccNative = 0x0100; // method
-static constexpr uint32_t kAccInterface = 0x0200; // class, ic
-static constexpr uint32_t kAccAbstract = 0x0400; // class, method, ic
-static constexpr uint32_t kAccStrict = 0x0800; // method
-static constexpr uint32_t kAccSynthetic = 0x1000; // class, field, method, ic
-static constexpr uint32_t kAccAnnotation = 0x2000; // class, ic (1.5)
-static constexpr uint32_t kAccEnum = 0x4000; // class, field, ic (1.5)
-
-static constexpr uint32_t kAccJavaFlagsMask = 0xffff; // bits set from Java sources (low 16)
-
-// The following flags are used to insert hidden API access flags into boot
-// class path dex files. They are decoded by DexFile::ClassDataItemIterator and
-// removed from the access flags before used by the runtime.
-static constexpr uint32_t kAccDexHiddenBit = 0x00000020; // field, method (not native)
-static constexpr uint32_t kAccDexHiddenBitNative = 0x00000200; // method (native)
-
-static constexpr uint32_t kAccConstructor = 0x00010000; // method (dex only) <(cl)init>
-static constexpr uint32_t kAccDeclaredSynchronized = 0x00020000; // method (dex only)
-static constexpr uint32_t kAccClassIsProxy = 0x00040000; // class (dex only)
-// Set to indicate that the ArtMethod is obsolete and has a different DexCache + DexFile from its
-// declaring class. This flag may only be applied to methods.
-static constexpr uint32_t kAccObsoleteMethod = 0x00040000; // method (runtime)
-// Used by a method to denote that its execution does not need to go through slow path interpreter.
-static constexpr uint32_t kAccSkipAccessChecks = 0x00080000; // method (runtime, not native)
-// Used by a class to denote that the verifier has attempted to check it at least once.
-static constexpr uint32_t kAccVerificationAttempted = 0x00080000; // class (runtime)
-// This is set by the class linker during LinkInterfaceMethods. It is used by a method to represent
-// that it was copied from its declaring class into another class. All methods marked kAccMiranda
-// and kAccDefaultConflict will have this bit set. Any kAccDefault method contained in the methods_
-// array of a concrete class will also have this bit set.
-static constexpr uint32_t kAccCopied = 0x00100000; // method (runtime)
-static constexpr uint32_t kAccMiranda = 0x00200000; // method (runtime, not native)
-static constexpr uint32_t kAccDefault = 0x00400000; // method (runtime)
-// Native method flags are set when linking the methods based on the presence of the
-// @dalvik.annotation.optimization.{Fast,Critical}Native annotations with build visibility.
-// Reuse the values of kAccSkipAccessChecks and kAccMiranda which are not used for native methods.
-static constexpr uint32_t kAccFastNative = 0x00080000; // method (runtime; native only)
-static constexpr uint32_t kAccCriticalNative = 0x00200000; // method (runtime; native only)
-
-// Set by the JIT when clearing profiling infos to denote that a method was previously warm.
-static constexpr uint32_t kAccPreviouslyWarm = 0x00800000; // method (runtime)
-
-// This is set by the class linker during LinkInterfaceMethods. Prior to that point we do not know
-// if any particular method needs to be a default conflict. Used to figure out at runtime if
-// invoking this method will throw an exception.
-static constexpr uint32_t kAccDefaultConflict = 0x01000000; // method (runtime)
-
-// Set by the verifier for a method we do not want the compiler to compile.
-static constexpr uint32_t kAccCompileDontBother = 0x02000000; // method (runtime)
-
-// Set by the verifier for a method that could not be verified to follow structured locking.
-static constexpr uint32_t kAccMustCountLocks = 0x04000000; // method (runtime)
-
-// Set by the class linker for a method that has only one implementation for a
-// virtual call.
-static constexpr uint32_t kAccSingleImplementation = 0x08000000; // method (runtime)
-
-static constexpr uint32_t kAccHiddenApiBits = 0x30000000; // field, method
-
-// Not currently used, except for intrinsic methods where these bits
-// are part of the intrinsic ordinal.
-static constexpr uint32_t kAccMayBeUnusedBits = 0x40000000;
-
-// Set by the compiler driver when compiling boot classes with instrinsic methods.
-static constexpr uint32_t kAccIntrinsic = 0x80000000; // method (runtime)
-
-// Special runtime-only flags.
-// Interface and all its super-interfaces with default methods have been recursively initialized.
-static constexpr uint32_t kAccRecursivelyInitialized = 0x20000000;
-// Interface declares some default method.
-static constexpr uint32_t kAccHasDefaultMethod = 0x40000000;
-// class/ancestor overrides finalize()
-static constexpr uint32_t kAccClassIsFinalizable = 0x80000000;
-
-// Continuous sequence of bits used to hold the ordinal of an intrinsic method. Flags
-// which overlap are not valid when kAccIntrinsic is set.
-static constexpr uint32_t kAccIntrinsicBits = kAccMayBeUnusedBits | kAccHiddenApiBits |
- kAccSingleImplementation | kAccMustCountLocks | kAccCompileDontBother | kAccDefaultConflict |
- kAccPreviouslyWarm;
-
-// Valid (meaningful) bits for a field.
-static constexpr uint32_t kAccValidFieldFlags = kAccPublic | kAccPrivate | kAccProtected |
- kAccStatic | kAccFinal | kAccVolatile | kAccTransient | kAccSynthetic | kAccEnum;
-
-// Valid (meaningful) bits for a method.
-static constexpr uint32_t kAccValidMethodFlags = kAccPublic | kAccPrivate | kAccProtected |
- kAccStatic | kAccFinal | kAccSynchronized | kAccBridge | kAccVarargs | kAccNative |
- kAccAbstract | kAccStrict | kAccSynthetic | kAccConstructor | kAccDeclaredSynchronized;
-static_assert(((kAccIntrinsic | kAccIntrinsicBits) & kAccValidMethodFlags) == 0,
- "Intrinsic bits and valid dex file method access flags must not overlap.");
-
-// Valid (meaningful) bits for a class (not interface).
-// Note 1. These are positive bits. Other bits may have to be zero.
-// Note 2. Inner classes can expose more access flags to Java programs. That is handled by libcore.
-static constexpr uint32_t kAccValidClassFlags = kAccPublic | kAccFinal | kAccSuper |
- kAccAbstract | kAccSynthetic | kAccEnum;
-
-// Valid (meaningful) bits for an interface.
-// Note 1. Annotations are interfaces.
-// Note 2. These are positive bits. Other bits may have to be zero.
-// Note 3. Inner classes can expose more access flags to Java programs. That is handled by libcore.
-static constexpr uint32_t kAccValidInterfaceFlags = kAccPublic | kAccInterface |
- kAccAbstract | kAccSynthetic | kAccAnnotation;
-
-static constexpr uint32_t kAccVisibilityFlags = kAccPublic | kAccPrivate | kAccProtected;
-
-// Returns a human-readable version of the Java part of the access flags, e.g., "private static "
-// (note the trailing whitespace).
-std::string PrettyJavaAccessFlags(uint32_t access_flags);
-
-} // namespace art
-
-#endif // ART_RUNTIME_DEX_MODIFIERS_H_
-
diff --git a/runtime/dex/standard_dex_file.cc b/runtime/dex/standard_dex_file.cc
deleted file mode 100644
index f7317eb997..0000000000
--- a/runtime/dex/standard_dex_file.cc
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "standard_dex_file.h"
-
-#include "base/casts.h"
-#include "code_item_accessors-inl.h"
-#include "dex_file-inl.h"
-#include "leb128.h"
-
-namespace art {
-
-const uint8_t StandardDexFile::kDexMagic[] = { 'd', 'e', 'x', '\n' };
-const uint8_t StandardDexFile::kDexMagicVersions[StandardDexFile::kNumDexVersions]
- [StandardDexFile::kDexVersionLen] = {
- {'0', '3', '5', '\0'},
- // Dex version 036 skipped because of an old dalvik bug on some versions of android where dex
- // files with that version number would erroneously be accepted and run.
- {'0', '3', '7', '\0'},
- // Dex version 038: Android "O" and beyond.
- {'0', '3', '8', '\0'},
- // Dex verion 039: Beyond Android "O".
- {'0', '3', '9', '\0'},
-};
-
-void StandardDexFile::WriteMagic(uint8_t* magic) {
- std::copy_n(kDexMagic, kDexMagicSize, magic);
-}
-
-void StandardDexFile::WriteCurrentVersion(uint8_t* magic) {
- std::copy_n(kDexMagicVersions[StandardDexFile::kDexVersionLen - 1],
- kDexVersionLen,
- magic + kDexMagicSize);
-}
-
-bool StandardDexFile::IsMagicValid(const uint8_t* magic) {
- return (memcmp(magic, kDexMagic, sizeof(kDexMagic)) == 0);
-}
-
-bool StandardDexFile::IsVersionValid(const uint8_t* magic) {
- const uint8_t* version = &magic[sizeof(kDexMagic)];
- for (uint32_t i = 0; i < kNumDexVersions; i++) {
- if (memcmp(version, kDexMagicVersions[i], kDexVersionLen) == 0) {
- return true;
- }
- }
- return false;
-}
-
-bool StandardDexFile::IsMagicValid() const {
- return IsMagicValid(header_->magic_);
-}
-
-bool StandardDexFile::IsVersionValid() const {
- return IsVersionValid(header_->magic_);
-}
-
-bool StandardDexFile::SupportsDefaultMethods() const {
- return GetDexVersion() >= DexFile::kDefaultMethodsVersion;
-}
-
-uint32_t StandardDexFile::GetCodeItemSize(const DexFile::CodeItem& item) const {
- DCHECK(IsInDataSection(&item));
- return reinterpret_cast<uintptr_t>(CodeItemDataAccessor(*this, &item).CodeItemDataEnd()) -
- reinterpret_cast<uintptr_t>(&item);
-}
-
-} // namespace art
diff --git a/runtime/dex/standard_dex_file.h b/runtime/dex/standard_dex_file.h
deleted file mode 100644
index e0e9f2f11c..0000000000
--- a/runtime/dex/standard_dex_file.h
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ART_RUNTIME_DEX_STANDARD_DEX_FILE_H_
-#define ART_RUNTIME_DEX_STANDARD_DEX_FILE_H_
-
-#include <iosfwd>
-
-#include "dex_file.h"
-
-namespace art {
-
-class OatDexFile;
-
-// Standard dex file. This is the format that is packaged in APKs and produced by tools.
-class StandardDexFile : public DexFile {
- public:
- class Header : public DexFile::Header {
- // Same for now.
- };
-
- struct CodeItem : public DexFile::CodeItem {
- static constexpr size_t kAlignment = 4;
-
- private:
- CodeItem() = default;
-
- uint16_t registers_size_; // the number of registers used by this code
- // (locals + parameters)
- uint16_t ins_size_; // the number of words of incoming arguments to the method
- // that this code is for
- uint16_t outs_size_; // the number of words of outgoing argument space required
- // by this code for method invocation
- uint16_t tries_size_; // the number of try_items for this instance. If non-zero,
- // then these appear as the tries array just after the
- // insns in this instance.
- uint32_t debug_info_off_; // Holds file offset to debug info stream.
-
- uint32_t insns_size_in_code_units_; // size of the insns array, in 2 byte code units
- uint16_t insns_[1]; // actual array of bytecode.
-
- ART_FRIEND_TEST(CodeItemAccessorsTest, TestDexInstructionsAccessor);
- friend class CodeItemDataAccessor;
- friend class CodeItemDebugInfoAccessor;
- friend class CodeItemInstructionAccessor;
- friend class DexWriter;
- friend class StandardDexFile;
- DISALLOW_COPY_AND_ASSIGN(CodeItem);
- };
-
- // Write the standard dex specific magic.
- static void WriteMagic(uint8_t* magic);
-
- // Write the current version, note that the input is the address of the magic.
- static void WriteCurrentVersion(uint8_t* magic);
-
- static const uint8_t kDexMagic[kDexMagicSize];
- static constexpr size_t kNumDexVersions = 4;
- static const uint8_t kDexMagicVersions[kNumDexVersions][kDexVersionLen];
-
- // Returns true if the byte string points to the magic value.
- static bool IsMagicValid(const uint8_t* magic);
- virtual bool IsMagicValid() const OVERRIDE;
-
- // Returns true if the byte string after the magic is the correct value.
- static bool IsVersionValid(const uint8_t* magic);
- virtual bool IsVersionValid() const OVERRIDE;
-
- virtual bool SupportsDefaultMethods() const OVERRIDE;
-
- uint32_t GetCodeItemSize(const DexFile::CodeItem& item) const OVERRIDE;
-
- virtual size_t GetDequickenedSize() const OVERRIDE {
- return Size();
- }
-
- private:
- StandardDexFile(const uint8_t* base,
- size_t size,
- const std::string& location,
- uint32_t location_checksum,
- const OatDexFile* oat_dex_file,
- DexFileContainer* container)
- : DexFile(base,
- size,
- /*data_begin*/ base,
- /*data_size*/ size,
- location,
- location_checksum,
- oat_dex_file,
- container,
- /*is_compact_dex*/ false) {}
-
- friend class DexFileLoader;
- friend class DexFileVerifierTest;
-
- ART_FRIEND_TEST(ClassLinkerTest, RegisterDexFileName); // for constructor
- friend class OptimizingUnitTestHelper; // for constructor
-
- DISALLOW_COPY_AND_ASSIGN(StandardDexFile);
-};
-
-} // namespace art
-
-#endif // ART_RUNTIME_DEX_STANDARD_DEX_FILE_H_
diff --git a/runtime/dex/utf-inl.h b/runtime/dex/utf-inl.h
deleted file mode 100644
index 4f626a8580..0000000000
--- a/runtime/dex/utf-inl.h
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ART_RUNTIME_DEX_UTF_INL_H_
-#define ART_RUNTIME_DEX_UTF_INL_H_
-
-#include "utf.h"
-
-namespace art {
-
-inline uint16_t GetTrailingUtf16Char(uint32_t maybe_pair) {
- return static_cast<uint16_t>(maybe_pair >> 16);
-}
-
-inline uint16_t GetLeadingUtf16Char(uint32_t maybe_pair) {
- return static_cast<uint16_t>(maybe_pair & 0x0000FFFF);
-}
-
-inline uint32_t GetUtf16FromUtf8(const char** utf8_data_in) {
- const uint8_t one = *(*utf8_data_in)++;
- if ((one & 0x80) == 0) {
- // one-byte encoding
- return one;
- }
-
- const uint8_t two = *(*utf8_data_in)++;
- if ((one & 0x20) == 0) {
- // two-byte encoding
- return ((one & 0x1f) << 6) | (two & 0x3f);
- }
-
- const uint8_t three = *(*utf8_data_in)++;
- if ((one & 0x10) == 0) {
- return ((one & 0x0f) << 12) | ((two & 0x3f) << 6) | (three & 0x3f);
- }
-
- // Four byte encodings need special handling. We'll have
- // to convert them into a surrogate pair.
- const uint8_t four = *(*utf8_data_in)++;
-
- // Since this is a 4 byte UTF-8 sequence, it will lie between
- // U+10000 and U+1FFFFF.
- //
- // TODO: What do we do about values in (U+10FFFF, U+1FFFFF) ? The
- // spec says they're invalid but nobody appears to check for them.
- const uint32_t code_point = ((one & 0x0f) << 18) | ((two & 0x3f) << 12)
- | ((three & 0x3f) << 6) | (four & 0x3f);
-
- uint32_t surrogate_pair = 0;
- // Step two: Write out the high (leading) surrogate to the bottom 16 bits
- // of the of the 32 bit type.
- surrogate_pair |= ((code_point >> 10) + 0xd7c0) & 0xffff;
- // Step three : Write out the low (trailing) surrogate to the top 16 bits.
- surrogate_pair |= ((code_point & 0x03ff) + 0xdc00) << 16;
-
- return surrogate_pair;
-}
-
-inline int CompareModifiedUtf8ToModifiedUtf8AsUtf16CodePointValues(const char* utf8_1,
- const char* utf8_2) {
- uint32_t c1, c2;
- do {
- c1 = *utf8_1;
- c2 = *utf8_2;
- // Did we reach a terminating character?
- if (c1 == 0) {
- return (c2 == 0) ? 0 : -1;
- } else if (c2 == 0) {
- return 1;
- }
-
- c1 = GetUtf16FromUtf8(&utf8_1);
- c2 = GetUtf16FromUtf8(&utf8_2);
- } while (c1 == c2);
-
- const uint32_t leading_surrogate_diff = GetLeadingUtf16Char(c1) - GetLeadingUtf16Char(c2);
- if (leading_surrogate_diff != 0) {
- return static_cast<int>(leading_surrogate_diff);
- }
-
- return GetTrailingUtf16Char(c1) - GetTrailingUtf16Char(c2);
-}
-
-} // namespace art
-
-#endif // ART_RUNTIME_DEX_UTF_INL_H_
diff --git a/runtime/dex/utf.cc b/runtime/dex/utf.cc
deleted file mode 100644
index 772a610140..0000000000
--- a/runtime/dex/utf.cc
+++ /dev/null
@@ -1,321 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "utf.h"
-
-#include <android-base/logging.h>
-#include <android-base/stringprintf.h>
-#include <android-base/strings.h>
-
-#include "base/casts.h"
-#include "utf-inl.h"
-
-namespace art {
-
-using android::base::StringAppendF;
-using android::base::StringPrintf;
-
-// This is used only from debugger and test code.
-size_t CountModifiedUtf8Chars(const char* utf8) {
- return CountModifiedUtf8Chars(utf8, strlen(utf8));
-}
-
-/*
- * This does not validate UTF8 rules (nor did older code). But it gets the right answer
- * for valid UTF-8 and that's fine because it's used only to size a buffer for later
- * conversion.
- *
- * Modified UTF-8 consists of a series of bytes up to 21 bit Unicode code points as follows:
- * U+0001 - U+007F 0xxxxxxx
- * U+0080 - U+07FF 110xxxxx 10xxxxxx
- * U+0800 - U+FFFF 1110xxxx 10xxxxxx 10xxxxxx
- * U+10000 - U+1FFFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
- *
- * U+0000 is encoded using the 2nd form to avoid nulls inside strings (this differs from
- * standard UTF-8).
- * The four byte encoding converts to two utf16 characters.
- */
-size_t CountModifiedUtf8Chars(const char* utf8, size_t byte_count) {
- DCHECK_LE(byte_count, strlen(utf8));
- size_t len = 0;
- const char* end = utf8 + byte_count;
- for (; utf8 < end; ++utf8) {
- int ic = *utf8;
- len++;
- if (LIKELY((ic & 0x80) == 0)) {
- // One-byte encoding.
- continue;
- }
- // Two- or three-byte encoding.
- utf8++;
- if ((ic & 0x20) == 0) {
- // Two-byte encoding.
- continue;
- }
- utf8++;
- if ((ic & 0x10) == 0) {
- // Three-byte encoding.
- continue;
- }
-
- // Four-byte encoding: needs to be converted into a surrogate
- // pair.
- utf8++;
- len++;
- }
- return len;
-}
-
-// This is used only from debugger and test code.
-void ConvertModifiedUtf8ToUtf16(uint16_t* utf16_data_out, const char* utf8_data_in) {
- while (*utf8_data_in != '\0') {
- const uint32_t ch = GetUtf16FromUtf8(&utf8_data_in);
- const uint16_t leading = GetLeadingUtf16Char(ch);
- const uint16_t trailing = GetTrailingUtf16Char(ch);
-
- *utf16_data_out++ = leading;
- if (trailing != 0) {
- *utf16_data_out++ = trailing;
- }
- }
-}
-
-void ConvertModifiedUtf8ToUtf16(uint16_t* utf16_data_out, size_t out_chars,
- const char* utf8_data_in, size_t in_bytes) {
- const char *in_start = utf8_data_in;
- const char *in_end = utf8_data_in + in_bytes;
- uint16_t *out_p = utf16_data_out;
-
- if (LIKELY(out_chars == in_bytes)) {
- // Common case where all characters are ASCII.
- for (const char *p = in_start; p < in_end;) {
- // Safe even if char is signed because ASCII characters always have
- // the high bit cleared.
- *out_p++ = dchecked_integral_cast<uint16_t>(*p++);
- }
- return;
- }
-
- // String contains non-ASCII characters.
- for (const char *p = in_start; p < in_end;) {
- const uint32_t ch = GetUtf16FromUtf8(&p);
- const uint16_t leading = GetLeadingUtf16Char(ch);
- const uint16_t trailing = GetTrailingUtf16Char(ch);
-
- *out_p++ = leading;
- if (trailing != 0) {
- *out_p++ = trailing;
- }
- }
-}
-
-void ConvertUtf16ToModifiedUtf8(char* utf8_out, size_t byte_count,
- const uint16_t* utf16_in, size_t char_count) {
- if (LIKELY(byte_count == char_count)) {
- // Common case where all characters are ASCII.
- const uint16_t *utf16_end = utf16_in + char_count;
- for (const uint16_t *p = utf16_in; p < utf16_end;) {
- *utf8_out++ = dchecked_integral_cast<char>(*p++);
- }
- return;
- }
-
- // String contains non-ASCII characters.
- while (char_count--) {
- const uint16_t ch = *utf16_in++;
- if (ch > 0 && ch <= 0x7f) {
- *utf8_out++ = ch;
- } else {
- // Char_count == 0 here implies we've encountered an unpaired
- // surrogate and we have no choice but to encode it as 3-byte UTF
- // sequence. Note that unpaired surrogates can occur as a part of
- // "normal" operation.
- if ((ch >= 0xd800 && ch <= 0xdbff) && (char_count > 0)) {
- const uint16_t ch2 = *utf16_in;
-
- // Check if the other half of the pair is within the expected
- // range. If it isn't, we will have to emit both "halves" as
- // separate 3 byte sequences.
- if (ch2 >= 0xdc00 && ch2 <= 0xdfff) {
- utf16_in++;
- char_count--;
- const uint32_t code_point = (ch << 10) + ch2 - 0x035fdc00;
- *utf8_out++ = (code_point >> 18) | 0xf0;
- *utf8_out++ = ((code_point >> 12) & 0x3f) | 0x80;
- *utf8_out++ = ((code_point >> 6) & 0x3f) | 0x80;
- *utf8_out++ = (code_point & 0x3f) | 0x80;
- continue;
- }
- }
-
- if (ch > 0x07ff) {
- // Three byte encoding.
- *utf8_out++ = (ch >> 12) | 0xe0;
- *utf8_out++ = ((ch >> 6) & 0x3f) | 0x80;
- *utf8_out++ = (ch & 0x3f) | 0x80;
- } else /*(ch > 0x7f || ch == 0)*/ {
- // Two byte encoding.
- *utf8_out++ = (ch >> 6) | 0xc0;
- *utf8_out++ = (ch & 0x3f) | 0x80;
- }
- }
- }
-}
-
-int32_t ComputeUtf16HashFromModifiedUtf8(const char* utf8, size_t utf16_length) {
- uint32_t hash = 0;
- while (utf16_length != 0u) {
- const uint32_t pair = GetUtf16FromUtf8(&utf8);
- const uint16_t first = GetLeadingUtf16Char(pair);
- hash = hash * 31 + first;
- --utf16_length;
- const uint16_t second = GetTrailingUtf16Char(pair);
- if (second != 0) {
- hash = hash * 31 + second;
- DCHECK_NE(utf16_length, 0u);
- --utf16_length;
- }
- }
- return static_cast<int32_t>(hash);
-}
-
-uint32_t ComputeModifiedUtf8Hash(const char* chars) {
- uint32_t hash = 0;
- while (*chars != '\0') {
- hash = hash * 31 + *chars++;
- }
- return static_cast<int32_t>(hash);
-}
-
-int CompareModifiedUtf8ToUtf16AsCodePointValues(const char* utf8, const uint16_t* utf16,
- size_t utf16_length) {
- for (;;) {
- if (*utf8 == '\0') {
- return (utf16_length == 0) ? 0 : -1;
- } else if (utf16_length == 0) {
- return 1;
- }
-
- const uint32_t pair = GetUtf16FromUtf8(&utf8);
-
- // First compare the leading utf16 char.
- const uint16_t lhs = GetLeadingUtf16Char(pair);
- const uint16_t rhs = *utf16++;
- --utf16_length;
- if (lhs != rhs) {
- return lhs > rhs ? 1 : -1;
- }
-
- // Then compare the trailing utf16 char. First check if there
- // are any characters left to consume.
- const uint16_t lhs2 = GetTrailingUtf16Char(pair);
- if (lhs2 != 0) {
- if (utf16_length == 0) {
- return 1;
- }
-
- const uint16_t rhs2 = *utf16++;
- --utf16_length;
- if (lhs2 != rhs2) {
- return lhs2 > rhs2 ? 1 : -1;
- }
- }
- }
-}
-
-size_t CountUtf8Bytes(const uint16_t* chars, size_t char_count) {
- size_t result = 0;
- const uint16_t *end = chars + char_count;
- while (chars < end) {
- const uint16_t ch = *chars++;
- if (LIKELY(ch != 0 && ch < 0x80)) {
- result++;
- continue;
- }
- if (ch < 0x800) {
- result += 2;
- continue;
- }
- if (ch >= 0xd800 && ch < 0xdc00) {
- if (chars < end) {
- const uint16_t ch2 = *chars;
- // If we find a properly paired surrogate, we emit it as a 4 byte
- // UTF sequence. If we find an unpaired leading or trailing surrogate,
- // we emit it as a 3 byte sequence like would have done earlier.
- if (ch2 >= 0xdc00 && ch2 < 0xe000) {
- chars++;
- result += 4;
- continue;
- }
- }
- }
- result += 3;
- }
- return result;
-}
-
-static inline constexpr bool NeedsEscaping(uint16_t ch) {
- return (ch < ' ' || ch > '~');
-}
-
-std::string PrintableChar(uint16_t ch) {
- std::string result;
- result += '\'';
- if (NeedsEscaping(ch)) {
- StringAppendF(&result, "\\u%04x", ch);
- } else {
- result += static_cast<std::string::value_type>(ch);
- }
- result += '\'';
- return result;
-}
-
-std::string PrintableString(const char* utf) {
- std::string result;
- result += '"';
- const char* p = utf;
- size_t char_count = CountModifiedUtf8Chars(p);
- for (size_t i = 0; i < char_count; ++i) {
- uint32_t ch = GetUtf16FromUtf8(&p);
- if (ch == '\\') {
- result += "\\\\";
- } else if (ch == '\n') {
- result += "\\n";
- } else if (ch == '\r') {
- result += "\\r";
- } else if (ch == '\t') {
- result += "\\t";
- } else {
- const uint16_t leading = GetLeadingUtf16Char(ch);
-
- if (NeedsEscaping(leading)) {
- StringAppendF(&result, "\\u%04x", leading);
- } else {
- result += static_cast<std::string::value_type>(leading);
- }
-
- const uint32_t trailing = GetTrailingUtf16Char(ch);
- if (trailing != 0) {
- // All high surrogates will need escaping.
- StringAppendF(&result, "\\u%04x", trailing);
- }
- }
- }
- result += '"';
- return result;
-}
-
-} // namespace art
diff --git a/runtime/dex/utf.h b/runtime/dex/utf.h
deleted file mode 100644
index 4adfc4af8c..0000000000
--- a/runtime/dex/utf.h
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ART_RUNTIME_DEX_UTF_H_
-#define ART_RUNTIME_DEX_UTF_H_
-
-#include "base/macros.h"
-
-#include <stddef.h>
-#include <stdint.h>
-
-#include <string>
-
-/*
- * All UTF-8 in art is actually modified UTF-8. Mostly, this distinction
- * doesn't matter.
- *
- * See http://en.wikipedia.org/wiki/UTF-8#Modified_UTF-8 for the details.
- */
-namespace art {
-
-/*
- * Returns the number of UTF-16 characters in the given modified UTF-8 string.
- */
-size_t CountModifiedUtf8Chars(const char* utf8);
-size_t CountModifiedUtf8Chars(const char* utf8, size_t byte_count);
-
-/*
- * Returns the number of modified UTF-8 bytes needed to represent the given
- * UTF-16 string.
- */
-size_t CountUtf8Bytes(const uint16_t* chars, size_t char_count);
-
-/*
- * Convert from Modified UTF-8 to UTF-16.
- */
-void ConvertModifiedUtf8ToUtf16(uint16_t* utf16_out, const char* utf8_in);
-void ConvertModifiedUtf8ToUtf16(uint16_t* utf16_out, size_t out_chars,
- const char* utf8_in, size_t in_bytes);
-
-/*
- * Compare two modified UTF-8 strings as UTF-16 code point values in a non-locale sensitive manner
- */
-ALWAYS_INLINE int CompareModifiedUtf8ToModifiedUtf8AsUtf16CodePointValues(const char* utf8_1,
- const char* utf8_2);
-
-/*
- * Compare a null-terminated modified UTF-8 string with a UTF-16 string (not null-terminated)
- * as code point values in a non-locale sensitive manner.
- */
-int CompareModifiedUtf8ToUtf16AsCodePointValues(const char* utf8, const uint16_t* utf16,
- size_t utf16_length);
-
-/*
- * Convert from UTF-16 to Modified UTF-8. Note that the output is _not_
- * NUL-terminated. You probably need to call CountUtf8Bytes before calling
- * this anyway, so if you want a NUL-terminated string, you know where to
- * put the NUL byte.
- */
-void ConvertUtf16ToModifiedUtf8(char* utf8_out, size_t byte_count,
- const uint16_t* utf16_in, size_t char_count);
-
-/*
- * The java.lang.String hashCode() algorithm.
- */
-template<typename MemoryType>
-int32_t ComputeUtf16Hash(const MemoryType* chars, size_t char_count) {
- uint32_t hash = 0;
- while (char_count--) {
- hash = hash * 31 + *chars++;
- }
- return static_cast<int32_t>(hash);
-}
-
-int32_t ComputeUtf16HashFromModifiedUtf8(const char* utf8, size_t utf16_length);
-
-// Compute a hash code of a modified UTF-8 string. Not the standard java hash since it returns a
-// uint32_t and hashes individual chars instead of codepoint words.
-uint32_t ComputeModifiedUtf8Hash(const char* chars);
-
-/*
- * Retrieve the next UTF-16 character or surrogate pair from a UTF-8 string.
- * single byte, 2-byte and 3-byte UTF-8 sequences result in a single UTF-16
- * character (possibly one half of a surrogate) whereas 4-byte UTF-8 sequences
- * result in a surrogate pair. Use GetLeadingUtf16Char and GetTrailingUtf16Char
- * to process the return value of this function.
- *
- * Advances "*utf8_data_in" to the start of the next character.
- *
- * WARNING: If a string is corrupted by dropping a '\0' in the middle
- * of a multi byte sequence, you can end up overrunning the buffer with
- * reads (and possibly with the writes if the length was computed and
- * cached before the damage). For performance reasons, this function
- * assumes that the string being parsed is known to be valid (e.g., by
- * already being verified). Most strings we process here are coming
- * out of dex files or other internal translations, so the only real
- * risk comes from the JNI NewStringUTF call.
- */
-uint32_t GetUtf16FromUtf8(const char** utf8_data_in);
-
-/**
- * Gets the leading UTF-16 character from a surrogate pair, or the sole
- * UTF-16 character from the return value of GetUtf16FromUtf8.
- */
-ALWAYS_INLINE uint16_t GetLeadingUtf16Char(uint32_t maybe_pair);
-
-/**
- * Gets the trailing UTF-16 character from a surrogate pair, or 0 otherwise
- * from the return value of GetUtf16FromUtf8.
- */
-ALWAYS_INLINE uint16_t GetTrailingUtf16Char(uint32_t maybe_pair);
-
-// Returns a printable (escaped) version of a character.
-std::string PrintableChar(uint16_t ch);
-
-// Returns an ASCII string corresponding to the given UTF-8 string.
-// Java escapes are used for non-ASCII characters.
-std::string PrintableString(const char* utf8);
-
-} // namespace art
-
-#endif // ART_RUNTIME_DEX_UTF_H_
diff --git a/runtime/dex/utf_test.cc b/runtime/dex/utf_test.cc
deleted file mode 100644
index d2f22d16ef..0000000000
--- a/runtime/dex/utf_test.cc
+++ /dev/null
@@ -1,381 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "utf.h"
-
-#include <map>
-#include <vector>
-
-#include "gtest/gtest.h"
-#include "utf-inl.h"
-
-namespace art {
-
-class UtfTest : public testing::Test {};
-
-TEST_F(UtfTest, GetLeadingUtf16Char) {
- EXPECT_EQ(0xffff, GetLeadingUtf16Char(0xeeeeffff));
-}
-
-TEST_F(UtfTest, GetTrailingUtf16Char) {
- EXPECT_EQ(0xffff, GetTrailingUtf16Char(0xffffeeee));
- EXPECT_EQ(0, GetTrailingUtf16Char(0x0000aaaa));
-}
-
-#define EXPECT_ARRAY_POSITION(expected, end, start) \
- EXPECT_EQ(static_cast<uintptr_t>(expected), \
- reinterpret_cast<uintptr_t>(end) - reinterpret_cast<uintptr_t>(start));
-
-// A test string containing one, two, three and four byte UTF-8 sequences.
-static const uint8_t kAllSequences[] = {
- 0x24,
- 0xc2, 0xa2,
- 0xe2, 0x82, 0xac,
- 0xf0, 0x9f, 0x8f, 0xa0,
- 0x00
-};
-
-// A test string that contains a UTF-8 encoding of a surrogate pair
-// (code point = U+10400).
-static const uint8_t kSurrogateEncoding[] = {
- 0xed, 0xa0, 0x81,
- 0xed, 0xb0, 0x80,
- 0x00
-};
-
-TEST_F(UtfTest, GetUtf16FromUtf8) {
- const char* const start = reinterpret_cast<const char*>(kAllSequences);
- const char* ptr = start;
- uint32_t pair = 0;
-
- // Single byte sequence.
- pair = GetUtf16FromUtf8(&ptr);
- EXPECT_EQ(0x24, GetLeadingUtf16Char(pair));
- EXPECT_EQ(0, GetTrailingUtf16Char(pair));
- EXPECT_ARRAY_POSITION(1, ptr, start);
-
- // Two byte sequence.
- pair = GetUtf16FromUtf8(&ptr);
- EXPECT_EQ(0xa2, GetLeadingUtf16Char(pair));
- EXPECT_EQ(0, GetTrailingUtf16Char(pair));
- EXPECT_ARRAY_POSITION(3, ptr, start);
-
- // Three byte sequence.
- pair = GetUtf16FromUtf8(&ptr);
- EXPECT_EQ(0x20ac, GetLeadingUtf16Char(pair));
- EXPECT_EQ(0, GetTrailingUtf16Char(pair));
- EXPECT_ARRAY_POSITION(6, ptr, start);
-
- // Four byte sequence
- pair = GetUtf16FromUtf8(&ptr);
- EXPECT_EQ(0xd83c, GetLeadingUtf16Char(pair));
- EXPECT_EQ(0xdfe0, GetTrailingUtf16Char(pair));
- EXPECT_ARRAY_POSITION(10, ptr, start);
-
- // Null terminator.
- pair = GetUtf16FromUtf8(&ptr);
- EXPECT_EQ(0, GetLeadingUtf16Char(pair));
- EXPECT_EQ(0, GetTrailingUtf16Char(pair));
- EXPECT_ARRAY_POSITION(11, ptr, start);
-}
-
-TEST_F(UtfTest, GetUtf16FromUtf8_SurrogatesPassThrough) {
- const char* const start = reinterpret_cast<const char *>(kSurrogateEncoding);
- const char* ptr = start;
- uint32_t pair = 0;
-
- pair = GetUtf16FromUtf8(&ptr);
- EXPECT_EQ(0xd801, GetLeadingUtf16Char(pair));
- EXPECT_EQ(0, GetTrailingUtf16Char(pair));
- EXPECT_ARRAY_POSITION(3, ptr, start);
-
- pair = GetUtf16FromUtf8(&ptr);
- EXPECT_EQ(0xdc00, GetLeadingUtf16Char(pair));
- EXPECT_EQ(0, GetTrailingUtf16Char(pair));
- EXPECT_ARRAY_POSITION(6, ptr, start);
-}
-
-TEST_F(UtfTest, CountModifiedUtf8Chars) {
- EXPECT_EQ(5u, CountModifiedUtf8Chars(reinterpret_cast<const char *>(kAllSequences)));
- EXPECT_EQ(2u, CountModifiedUtf8Chars(reinterpret_cast<const char *>(kSurrogateEncoding)));
-}
-
-static void AssertConversion(const std::vector<uint16_t>& input,
- const std::vector<uint8_t>& expected) {
- ASSERT_EQ(expected.size(), CountUtf8Bytes(&input[0], input.size()));
-
- std::vector<uint8_t> output(expected.size());
- ConvertUtf16ToModifiedUtf8(reinterpret_cast<char*>(&output[0]), expected.size(),
- &input[0], input.size());
- EXPECT_EQ(expected, output);
-}
-
-TEST_F(UtfTest, CountAndConvertUtf8Bytes) {
- // Surrogate pairs will be converted into 4 byte sequences.
- AssertConversion({ 0xd801, 0xdc00 }, { 0xf0, 0x90, 0x90, 0x80 });
-
- // Three byte encodings that are below & above the leading surrogate
- // range respectively.
- AssertConversion({ 0xdef0 }, { 0xed, 0xbb, 0xb0 });
- AssertConversion({ 0xdcff }, { 0xed, 0xb3, 0xbf });
- // Two byte encoding.
- AssertConversion({ 0x0101 }, { 0xc4, 0x81 });
-
- // Two byte special case : 0 must use an overlong encoding.
- AssertConversion({ 0x0101, 0x0000 }, { 0xc4, 0x81, 0xc0, 0x80 });
-
- // One byte encoding.
- AssertConversion({ 'h', 'e', 'l', 'l', 'o' }, { 0x68, 0x65, 0x6c, 0x6c, 0x6f });
-
- AssertConversion({
- 0xd802, 0xdc02, // Surrogate pair.
- 0xdef0, 0xdcff, // Three byte encodings.
- 0x0101, 0x0000, // Two byte encodings.
- 'p' , 'p' // One byte encoding.
- }, {
- 0xf0, 0x90, 0xa0, 0x82,
- 0xed, 0xbb, 0xb0, 0xed, 0xb3, 0xbf,
- 0xc4, 0x81, 0xc0, 0x80,
- 0x70, 0x70
- });
-}
-
-TEST_F(UtfTest, CountAndConvertUtf8Bytes_UnpairedSurrogate) {
- // Unpaired trailing surrogate at the end of input.
- AssertConversion({ 'h', 'e', 0xd801 }, { 'h', 'e', 0xed, 0xa0, 0x81 });
- // Unpaired (or incorrectly paired) surrogates in the middle of the input.
- const std::map<std::vector<uint16_t>, std::vector<uint8_t>> prefixes {
- {{ 'h' }, { 'h' }},
- {{ 0 }, { 0xc0, 0x80 }},
- {{ 0x81 }, { 0xc2, 0x81 }},
- {{ 0x801 }, { 0xe0, 0xa0, 0x81 }},
- };
- const std::map<std::vector<uint16_t>, std::vector<uint8_t>> suffixes {
- {{ 'e' }, { 'e' }},
- {{ 0 }, { 0xc0, 0x80 }},
- {{ 0x7ff }, { 0xdf, 0xbf }},
- {{ 0xffff }, { 0xef, 0xbf, 0xbf }},
- };
- const std::map<std::vector<uint16_t>, std::vector<uint8_t>> tests {
- {{ 0xd801 }, { 0xed, 0xa0, 0x81 }},
- {{ 0xdc00 }, { 0xed, 0xb0, 0x80 }},
- {{ 0xd801, 0xd801 }, { 0xed, 0xa0, 0x81, 0xed, 0xa0, 0x81 }},
- {{ 0xdc00, 0xdc00 }, { 0xed, 0xb0, 0x80, 0xed, 0xb0, 0x80 }},
- };
- for (const auto& prefix : prefixes) {
- const std::vector<uint16_t>& prefix_in = prefix.first;
- const std::vector<uint8_t>& prefix_out = prefix.second;
- for (const auto& test : tests) {
- const std::vector<uint16_t>& test_in = test.first;
- const std::vector<uint8_t>& test_out = test.second;
- for (const auto& suffix : suffixes) {
- const std::vector<uint16_t>& suffix_in = suffix.first;
- const std::vector<uint8_t>& suffix_out = suffix.second;
- std::vector<uint16_t> in = prefix_in;
- in.insert(in.end(), test_in.begin(), test_in.end());
- in.insert(in.end(), suffix_in.begin(), suffix_in.end());
- std::vector<uint8_t> out = prefix_out;
- out.insert(out.end(), test_out.begin(), test_out.end());
- out.insert(out.end(), suffix_out.begin(), suffix_out.end());
- AssertConversion(in, out);
- }
- }
- }
-}
-
-// Old versions of functions, here to compare answers with optimized versions.
-
-size_t CountModifiedUtf8Chars_reference(const char* utf8) {
- size_t len = 0;
- int ic;
- while ((ic = *utf8++) != '\0') {
- len++;
- if ((ic & 0x80) == 0) {
- // one-byte encoding
- continue;
- }
- // two- or three-byte encoding
- utf8++;
- if ((ic & 0x20) == 0) {
- // two-byte encoding
- continue;
- }
- utf8++;
- if ((ic & 0x10) == 0) {
- // three-byte encoding
- continue;
- }
-
- // four-byte encoding: needs to be converted into a surrogate
- // pair.
- utf8++;
- len++;
- }
- return len;
-}
-
-static size_t CountUtf8Bytes_reference(const uint16_t* chars, size_t char_count) {
- size_t result = 0;
- while (char_count--) {
- const uint16_t ch = *chars++;
- if (ch > 0 && ch <= 0x7f) {
- ++result;
- } else if (ch >= 0xd800 && ch <= 0xdbff) {
- if (char_count > 0) {
- const uint16_t ch2 = *chars;
- // If we find a properly paired surrogate, we emit it as a 4 byte
- // UTF sequence. If we find an unpaired leading or trailing surrogate,
- // we emit it as a 3 byte sequence like would have done earlier.
- if (ch2 >= 0xdc00 && ch2 <= 0xdfff) {
- chars++;
- char_count--;
-
- result += 4;
- } else {
- result += 3;
- }
- } else {
- // This implies we found an unpaired trailing surrogate at the end
- // of a string.
- result += 3;
- }
- } else if (ch > 0x7ff) {
- result += 3;
- } else {
- result += 2;
- }
- }
- return result;
-}
-
-static void ConvertUtf16ToModifiedUtf8_reference(char* utf8_out, const uint16_t* utf16_in,
- size_t char_count) {
- while (char_count--) {
- const uint16_t ch = *utf16_in++;
- if (ch > 0 && ch <= 0x7f) {
- *utf8_out++ = ch;
- } else {
- // Char_count == 0 here implies we've encountered an unpaired
- // surrogate and we have no choice but to encode it as 3-byte UTF
- // sequence. Note that unpaired surrogates can occur as a part of
- // "normal" operation.
- if ((ch >= 0xd800 && ch <= 0xdbff) && (char_count > 0)) {
- const uint16_t ch2 = *utf16_in;
-
- // Check if the other half of the pair is within the expected
- // range. If it isn't, we will have to emit both "halves" as
- // separate 3 byte sequences.
- if (ch2 >= 0xdc00 && ch2 <= 0xdfff) {
- utf16_in++;
- char_count--;
- const uint32_t code_point = (ch << 10) + ch2 - 0x035fdc00;
- *utf8_out++ = (code_point >> 18) | 0xf0;
- *utf8_out++ = ((code_point >> 12) & 0x3f) | 0x80;
- *utf8_out++ = ((code_point >> 6) & 0x3f) | 0x80;
- *utf8_out++ = (code_point & 0x3f) | 0x80;
- continue;
- }
- }
-
- if (ch > 0x07ff) {
- // Three byte encoding.
- *utf8_out++ = (ch >> 12) | 0xe0;
- *utf8_out++ = ((ch >> 6) & 0x3f) | 0x80;
- *utf8_out++ = (ch & 0x3f) | 0x80;
- } else /*(ch > 0x7f || ch == 0)*/ {
- // Two byte encoding.
- *utf8_out++ = (ch >> 6) | 0xc0;
- *utf8_out++ = (ch & 0x3f) | 0x80;
- }
- }
- }
-}
-
-// Exhaustive test of converting a single code point to UTF-16, then UTF-8, and back again.
-
-static void codePointToSurrogatePair(uint32_t code_point, uint16_t &first, uint16_t &second) {
- first = (code_point >> 10) + 0xd7c0;
- second = (code_point & 0x03ff) + 0xdc00;
-}
-
-static void testConversions(uint16_t *buf, int char_count) {
- char bytes_test[8] = { 0 }, bytes_reference[8] = { 0 };
- uint16_t out_buf_test[4] = { 0 }, out_buf_reference[4] = { 0 };
- int byte_count_test, byte_count_reference;
- int char_count_test, char_count_reference;
-
- // Calculate the number of utf-8 bytes for the utf-16 chars.
- byte_count_reference = CountUtf8Bytes_reference(buf, char_count);
- byte_count_test = CountUtf8Bytes(buf, char_count);
- EXPECT_EQ(byte_count_reference, byte_count_test);
-
- // Convert the utf-16 string to utf-8 bytes.
- ConvertUtf16ToModifiedUtf8_reference(bytes_reference, buf, char_count);
- ConvertUtf16ToModifiedUtf8(bytes_test, byte_count_test, buf, char_count);
- for (int i = 0; i < byte_count_test; ++i) {
- EXPECT_EQ(bytes_reference[i], bytes_test[i]);
- }
-
- // Calculate the number of utf-16 chars from the utf-8 bytes.
- bytes_reference[byte_count_reference] = 0; // Reference function needs null termination.
- char_count_reference = CountModifiedUtf8Chars_reference(bytes_reference);
- char_count_test = CountModifiedUtf8Chars(bytes_test, byte_count_test);
- EXPECT_EQ(char_count, char_count_reference);
- EXPECT_EQ(char_count, char_count_test);
-
- // Convert the utf-8 bytes back to utf-16 chars.
- // Does not need copied _reference version of the function because the original
- // function with the old API is retained for debug/testing code.
- ConvertModifiedUtf8ToUtf16(out_buf_reference, bytes_reference);
- ConvertModifiedUtf8ToUtf16(out_buf_test, char_count_test, bytes_test, byte_count_test);
- for (int i = 0; i < char_count_test; ++i) {
- EXPECT_EQ(buf[i], out_buf_reference[i]);
- EXPECT_EQ(buf[i], out_buf_test[i]);
- }
-}
-
-TEST_F(UtfTest, ExhaustiveBidirectionalCodePointCheck) {
- for (int codePoint = 0; codePoint <= 0x10ffff; ++codePoint) {
- uint16_t buf[4] = { 0 };
- if (codePoint <= 0xffff) {
- if (codePoint >= 0xd800 && codePoint <= 0xdfff) {
- // According to the Unicode standard, no character will ever
- // be assigned to these code points, and they cannot be encoded
- // into either utf-16 or utf-8.
- continue;
- }
- buf[0] = 'h';
- buf[1] = codePoint;
- buf[2] = 'e';
- testConversions(buf, 2);
- testConversions(buf, 3);
- testConversions(buf + 1, 1);
- testConversions(buf + 1, 2);
- } else {
- buf[0] = 'h';
- codePointToSurrogatePair(codePoint, buf[1], buf[2]);
- buf[3] = 'e';
- testConversions(buf, 2);
- testConversions(buf, 3);
- testConversions(buf, 4);
- testConversions(buf + 1, 1);
- testConversions(buf + 1, 2);
- testConversions(buf + 1, 3);
- }
- }
-}
-
-} // namespace art