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