1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "dex_to_dex_decompiler.h"
18 
19 #include "class_linker.h"
20 #include "compiler/common_compiler_test.h"
21 #include "compiler/compiled_method.h"
22 #include "compiler/driver/compiler_options.h"
23 #include "compiler/driver/compiler_driver.h"
24 #include "compiler_callbacks.h"
25 #include "dex_file.h"
26 #include "handle_scope-inl.h"
27 #include "verifier/method_verifier-inl.h"
28 #include "mirror/class_loader.h"
29 #include "runtime.h"
30 #include "thread.h"
31 #include "scoped_thread_state_change-inl.h"
32 
33 namespace art {
34 
35 class DexToDexDecompilerTest : public CommonCompilerTest {
36  public:
CompileAll(jobject class_loader)37   void CompileAll(jobject class_loader) REQUIRES(!Locks::mutator_lock_) {
38     TimingLogger timings("CompilerDriverTest::CompileAll", false, false);
39     TimingLogger::ScopedTiming t(__FUNCTION__, &timings);
40     compiler_options_->boot_image_ = false;
41     compiler_options_->SetCompilerFilter(CompilerFilter::kQuicken);
42     compiler_driver_->CompileAll(class_loader,
43                                  GetDexFiles(class_loader),
44                                  /* verifier_deps */ nullptr,
45                                  &timings);
46   }
47 
RunTest(const char * dex_name)48   void RunTest(const char* dex_name) {
49     Thread* self = Thread::Current();
50     // First load the original dex file.
51     jobject original_class_loader;
52     {
53       ScopedObjectAccess soa(self);
54       original_class_loader = LoadDex(dex_name);
55     }
56     const DexFile* original_dex_file = GetDexFiles(original_class_loader)[0];
57 
58     // Load the dex file again and make it writable to quicken them.
59     jobject class_loader;
60     const DexFile* updated_dex_file = nullptr;
61     {
62       ScopedObjectAccess soa(self);
63       class_loader = LoadDex(dex_name);
64       updated_dex_file = GetDexFiles(class_loader)[0];
65       Runtime::Current()->GetClassLinker()->RegisterDexFile(
66           *updated_dex_file, soa.Decode<mirror::ClassLoader>(class_loader).Ptr());
67     }
68     // The dex files should be identical.
69     int cmp = memcmp(original_dex_file->Begin(),
70                      updated_dex_file->Begin(),
71                      updated_dex_file->Size());
72     ASSERT_EQ(0, cmp);
73 
74     updated_dex_file->EnableWrite();
75     CompileAll(class_loader);
76     // The dex files should be different after quickening.
77     cmp = memcmp(original_dex_file->Begin(), updated_dex_file->Begin(), updated_dex_file->Size());
78     ASSERT_NE(0, cmp);
79 
80     // Unquicken the dex file.
81     for (uint32_t i = 0; i < updated_dex_file->NumClassDefs(); ++i) {
82       const DexFile::ClassDef& class_def = updated_dex_file->GetClassDef(i);
83       const uint8_t* class_data = updated_dex_file->GetClassData(class_def);
84       if (class_data == nullptr) {
85         continue;
86       }
87       ClassDataItemIterator it(*updated_dex_file, class_data);
88       // Skip fields
89       while (it.HasNextStaticField()) {
90         it.Next();
91       }
92       while (it.HasNextInstanceField()) {
93         it.Next();
94       }
95 
96       // Unquicken each method.
97       while (it.HasNextDirectMethod()) {
98         uint32_t method_idx = it.GetMemberIndex();
99         CompiledMethod* compiled_method =
100             compiler_driver_->GetCompiledMethod(MethodReference(updated_dex_file, method_idx));
101         ArrayRef<const uint8_t> table;
102         if (compiled_method != nullptr) {
103           table = compiled_method->GetVmapTable();
104         }
105         optimizer::ArtDecompileDEX(
106             *it.GetMethodCodeItem(), table, /* decompile_return_instruction */ true);
107         it.Next();
108       }
109       while (it.HasNextVirtualMethod()) {
110         uint32_t method_idx = it.GetMemberIndex();
111         CompiledMethod* compiled_method =
112             compiler_driver_->GetCompiledMethod(MethodReference(updated_dex_file, method_idx));
113         ArrayRef<const uint8_t> table;
114         if (compiled_method != nullptr) {
115           table = compiled_method->GetVmapTable();
116         }
117         optimizer::ArtDecompileDEX(
118             *it.GetMethodCodeItem(), table, /* decompile_return_instruction */ true);
119         it.Next();
120       }
121       DCHECK(!it.HasNext());
122     }
123 
124     // Make sure after unquickening we go back to the same contents as the original dex file.
125     cmp = memcmp(original_dex_file->Begin(), updated_dex_file->Begin(), updated_dex_file->Size());
126     ASSERT_EQ(0, cmp);
127   }
128 };
129 
TEST_F(DexToDexDecompilerTest,VerifierDeps)130 TEST_F(DexToDexDecompilerTest, VerifierDeps) {
131   RunTest("VerifierDeps");
132 }
133 
TEST_F(DexToDexDecompilerTest,DexToDexDecompiler)134 TEST_F(DexToDexDecompilerTest, DexToDexDecompiler) {
135   RunTest("DexToDexDecompiler");
136 }
137 
138 }  // namespace art
139