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 "base/logging.h"
20 #include "base/mutex.h"
21 #include "bytecode_utils.h"
22 #include "dex_file-inl.h"
23 #include "dex_instruction-inl.h"
24 #include "quicken_info.h"
25
26 namespace art {
27 namespace optimizer {
28
29 class DexDecompiler {
30 public:
DexDecompiler(const DexFile::CodeItem & code_item,const ArrayRef<const uint8_t> & quickened_info,bool decompile_return_instruction)31 DexDecompiler(const DexFile::CodeItem& code_item,
32 const ArrayRef<const uint8_t>& quickened_info,
33 bool decompile_return_instruction)
34 : code_item_(code_item),
35 quicken_info_(quickened_info.data()),
36 quicken_info_number_of_indices_(QuickenInfoTable::NumberOfIndices(quickened_info.size())),
37 decompile_return_instruction_(decompile_return_instruction) {}
38
39 bool Decompile();
40
41 private:
DecompileInstanceFieldAccess(Instruction * inst,Instruction::Code new_opcode)42 void DecompileInstanceFieldAccess(Instruction* inst, Instruction::Code new_opcode) {
43 uint16_t index = NextIndex();
44 inst->SetOpcode(new_opcode);
45 inst->SetVRegC_22c(index);
46 }
47
DecompileInvokeVirtual(Instruction * inst,Instruction::Code new_opcode,bool is_range)48 void DecompileInvokeVirtual(Instruction* inst, Instruction::Code new_opcode, bool is_range) {
49 const uint16_t index = NextIndex();
50 inst->SetOpcode(new_opcode);
51 if (is_range) {
52 inst->SetVRegB_3rc(index);
53 } else {
54 inst->SetVRegB_35c(index);
55 }
56 }
57
DecompileNop(Instruction * inst)58 void DecompileNop(Instruction* inst) {
59 const uint16_t reference_index = NextIndex();
60 if (reference_index == DexFile::kDexNoIndex16) {
61 // This means it was a normal nop and not a check-cast.
62 return;
63 }
64 const uint16_t type_index = NextIndex();
65 inst->SetOpcode(Instruction::CHECK_CAST);
66 inst->SetVRegA_21c(reference_index);
67 inst->SetVRegB_21c(type_index);
68 }
69
NextIndex()70 uint16_t NextIndex() {
71 DCHECK_LT(quicken_index_, quicken_info_number_of_indices_);
72 const uint16_t ret = quicken_info_.GetData(quicken_index_);
73 quicken_index_++;
74 return ret;
75 }
76
77 const DexFile::CodeItem& code_item_;
78 const QuickenInfoTable quicken_info_;
79 const size_t quicken_info_number_of_indices_;
80 const bool decompile_return_instruction_;
81
82 size_t quicken_index_ = 0u;
83
84 DISALLOW_COPY_AND_ASSIGN(DexDecompiler);
85 };
86
Decompile()87 bool DexDecompiler::Decompile() {
88 // We need to iterate over the code item, and not over the quickening data,
89 // because the RETURN_VOID quickening is not encoded in the quickening data. Because
90 // unquickening is a rare need and not performance sensitive, it is not worth the
91 // added storage to also add the RETURN_VOID quickening in the quickened data.
92 for (CodeItemIterator it(code_item_); !it.Done(); it.Advance()) {
93 Instruction* inst = const_cast<Instruction*>(&it.CurrentInstruction());
94
95 switch (inst->Opcode()) {
96 case Instruction::RETURN_VOID_NO_BARRIER:
97 if (decompile_return_instruction_) {
98 inst->SetOpcode(Instruction::RETURN_VOID);
99 }
100 break;
101
102 case Instruction::NOP:
103 if (quicken_info_number_of_indices_ > 0) {
104 // Only try to decompile NOP if there are more than 0 indices. Not having
105 // any index happens when we unquicken a code item that only has
106 // RETURN_VOID_NO_BARRIER as quickened instruction.
107 DecompileNop(inst);
108 }
109 break;
110
111 case Instruction::IGET_QUICK:
112 DecompileInstanceFieldAccess(inst, Instruction::IGET);
113 break;
114
115 case Instruction::IGET_WIDE_QUICK:
116 DecompileInstanceFieldAccess(inst, Instruction::IGET_WIDE);
117 break;
118
119 case Instruction::IGET_OBJECT_QUICK:
120 DecompileInstanceFieldAccess(inst, Instruction::IGET_OBJECT);
121 break;
122
123 case Instruction::IGET_BOOLEAN_QUICK:
124 DecompileInstanceFieldAccess(inst, Instruction::IGET_BOOLEAN);
125 break;
126
127 case Instruction::IGET_BYTE_QUICK:
128 DecompileInstanceFieldAccess(inst, Instruction::IGET_BYTE);
129 break;
130
131 case Instruction::IGET_CHAR_QUICK:
132 DecompileInstanceFieldAccess(inst, Instruction::IGET_CHAR);
133 break;
134
135 case Instruction::IGET_SHORT_QUICK:
136 DecompileInstanceFieldAccess(inst, Instruction::IGET_SHORT);
137 break;
138
139 case Instruction::IPUT_QUICK:
140 DecompileInstanceFieldAccess(inst, Instruction::IPUT);
141 break;
142
143 case Instruction::IPUT_BOOLEAN_QUICK:
144 DecompileInstanceFieldAccess(inst, Instruction::IPUT_BOOLEAN);
145 break;
146
147 case Instruction::IPUT_BYTE_QUICK:
148 DecompileInstanceFieldAccess(inst, Instruction::IPUT_BYTE);
149 break;
150
151 case Instruction::IPUT_CHAR_QUICK:
152 DecompileInstanceFieldAccess(inst, Instruction::IPUT_CHAR);
153 break;
154
155 case Instruction::IPUT_SHORT_QUICK:
156 DecompileInstanceFieldAccess(inst, Instruction::IPUT_SHORT);
157 break;
158
159 case Instruction::IPUT_WIDE_QUICK:
160 DecompileInstanceFieldAccess(inst, Instruction::IPUT_WIDE);
161 break;
162
163 case Instruction::IPUT_OBJECT_QUICK:
164 DecompileInstanceFieldAccess(inst, Instruction::IPUT_OBJECT);
165 break;
166
167 case Instruction::INVOKE_VIRTUAL_QUICK:
168 DecompileInvokeVirtual(inst, Instruction::INVOKE_VIRTUAL, false);
169 break;
170
171 case Instruction::INVOKE_VIRTUAL_RANGE_QUICK:
172 DecompileInvokeVirtual(inst, Instruction::INVOKE_VIRTUAL_RANGE, true);
173 break;
174
175 default:
176 break;
177 }
178 }
179
180 if (quicken_index_ != quicken_info_number_of_indices_) {
181 if (quicken_index_ == 0) {
182 LOG(WARNING) << "Failed to use any value in quickening info,"
183 << " potentially due to duplicate methods.";
184 } else {
185 LOG(FATAL) << "Failed to use all values in quickening info."
186 << " Actual: " << std::hex << quicken_index_
187 << " Expected: " << quicken_info_number_of_indices_;
188 return false;
189 }
190 }
191
192 return true;
193 }
194
ArtDecompileDEX(const DexFile::CodeItem & code_item,const ArrayRef<const uint8_t> & quickened_info,bool decompile_return_instruction)195 bool ArtDecompileDEX(const DexFile::CodeItem& code_item,
196 const ArrayRef<const uint8_t>& quickened_info,
197 bool decompile_return_instruction) {
198 if (quickened_info.size() == 0 && !decompile_return_instruction) {
199 return true;
200 }
201 DexDecompiler decompiler(code_item, quickened_info, decompile_return_instruction);
202 return decompiler.Decompile();
203 }
204
205 } // namespace optimizer
206 } // namespace art
207