blob: d078d6f4386821ad85fe89eb06ed82e693001e43 [file] [log] [blame]
Nicolas Geoffray01b70e82016-11-17 10:58:36 +00001/*
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
Andreas Gampe57943812017-12-06 21:39:13 -080019#include <android-base/logging.h>
20
21#include "base/macros.h"
Nicolas Geoffray01b70e82016-11-17 10:58:36 +000022#include "base/mutex.h"
David Sehr312f3b22018-03-19 08:39:26 -070023#include "dex/bytecode_utils.h"
David Sehr9e734c72018-01-04 17:56:19 -080024#include "dex/code_item_accessors-inl.h"
25#include "dex/dex_file-inl.h"
26#include "dex/dex_instruction-inl.h"
Mathieu Chartierde4b08f2017-07-10 14:13:41 -070027#include "quicken_info.h"
Nicolas Geoffray01b70e82016-11-17 10:58:36 +000028
29namespace art {
30namespace optimizer {
31
32class DexDecompiler {
33 public:
Mathieu Chartier6238c832018-01-04 09:55:13 -080034 DexDecompiler(const DexFile& dex_file,
Andreas Gampe3f1dcd32018-12-28 09:39:56 -080035 const dex::CodeItem& code_item,
Nicolas Geoffrayb1677e22016-12-16 16:23:16 +000036 const ArrayRef<const uint8_t>& quickened_info,
37 bool decompile_return_instruction)
Mathieu Chartier698ebbc2018-01-05 11:00:42 -080038 : code_item_accessor_(dex_file, &code_item),
Mathieu Chartier210531f2018-01-12 10:15:51 -080039 quicken_info_(quickened_info),
Nicolas Geoffrayb1677e22016-12-16 16:23:16 +000040 decompile_return_instruction_(decompile_return_instruction) {}
Nicolas Geoffray01b70e82016-11-17 10:58:36 +000041
42 bool Decompile();
43
44 private:
Mathieu Chartierde4b08f2017-07-10 14:13:41 -070045 void DecompileInstanceFieldAccess(Instruction* inst, Instruction::Code new_opcode) {
46 uint16_t index = NextIndex();
Nicolas Geoffray01b70e82016-11-17 10:58:36 +000047 inst->SetOpcode(new_opcode);
48 inst->SetVRegC_22c(index);
49 }
50
Mathieu Chartierde4b08f2017-07-10 14:13:41 -070051 void DecompileInvokeVirtual(Instruction* inst, Instruction::Code new_opcode, bool is_range) {
52 const uint16_t index = NextIndex();
Nicolas Geoffray01b70e82016-11-17 10:58:36 +000053 inst->SetOpcode(new_opcode);
54 if (is_range) {
55 inst->SetVRegB_3rc(index);
56 } else {
57 inst->SetVRegB_35c(index);
58 }
59 }
60
Mathieu Chartierde4b08f2017-07-10 14:13:41 -070061 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.
Nicolas Geoffray01b70e82016-11-17 10:58:36 +000065 return;
66 }
Mathieu Chartierde4b08f2017-07-10 14:13:41 -070067 const uint16_t type_index = NextIndex();
Nicolas Geoffray01b70e82016-11-17 10:58:36 +000068 inst->SetOpcode(Instruction::CHECK_CAST);
69 inst->SetVRegA_21c(reference_index);
70 inst->SetVRegB_21c(type_index);
71 }
72
Mathieu Chartierde4b08f2017-07-10 14:13:41 -070073 uint16_t NextIndex() {
Mathieu Chartier210531f2018-01-12 10:15:51 -080074 DCHECK_LT(quicken_index_, quicken_info_.NumIndices());
Mathieu Chartierde4b08f2017-07-10 14:13:41 -070075 const uint16_t ret = quicken_info_.GetData(quicken_index_);
76 quicken_index_++;
77 return ret;
Nicolas Geoffray01b70e82016-11-17 10:58:36 +000078 }
79
Mathieu Chartier73f21d42018-01-02 14:26:50 -080080 const CodeItemInstructionAccessor code_item_accessor_;
Mathieu Chartierde4b08f2017-07-10 14:13:41 -070081 const QuickenInfoTable quicken_info_;
Nicolas Geoffrayb1677e22016-12-16 16:23:16 +000082 const bool decompile_return_instruction_;
Nicolas Geoffray01b70e82016-11-17 10:58:36 +000083
Mathieu Chartierde4b08f2017-07-10 14:13:41 -070084 size_t quicken_index_ = 0u;
85
Nicolas Geoffray01b70e82016-11-17 10:58:36 +000086 DISALLOW_COPY_AND_ASSIGN(DexDecompiler);
87};
88
89bool 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.
Mathieu Chartier73f21d42018-01-02 14:26:50 -080094 for (const DexInstructionPcPair& pair : code_item_accessor_) {
Mathieu Chartier0021feb2017-11-07 00:08:52 -080095 Instruction* inst = const_cast<Instruction*>(&pair.Inst());
Nicolas Geoffray01b70e82016-11-17 10:58:36 +000096
97 switch (inst->Opcode()) {
98 case Instruction::RETURN_VOID_NO_BARRIER:
Nicolas Geoffrayb1677e22016-12-16 16:23:16 +000099 if (decompile_return_instruction_) {
100 inst->SetOpcode(Instruction::RETURN_VOID);
101 }
Nicolas Geoffray01b70e82016-11-17 10:58:36 +0000102 break;
103
104 case Instruction::NOP:
Mathieu Chartier210531f2018-01-12 10:15:51 -0800105 if (quicken_info_.NumIndices() > 0) {
Nicolas Geoffraya55e2682017-07-13 09:22:59 +0100106 // 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.
Mathieu Chartier36f549e2017-07-12 21:43:37 -0700109 DecompileNop(inst);
110 }
Nicolas Geoffray01b70e82016-11-17 10:58:36 +0000111 break;
112
113 case Instruction::IGET_QUICK:
Mathieu Chartierde4b08f2017-07-10 14:13:41 -0700114 DecompileInstanceFieldAccess(inst, Instruction::IGET);
Nicolas Geoffray01b70e82016-11-17 10:58:36 +0000115 break;
116
117 case Instruction::IGET_WIDE_QUICK:
Mathieu Chartierde4b08f2017-07-10 14:13:41 -0700118 DecompileInstanceFieldAccess(inst, Instruction::IGET_WIDE);
Nicolas Geoffray01b70e82016-11-17 10:58:36 +0000119 break;
120
121 case Instruction::IGET_OBJECT_QUICK:
Mathieu Chartierde4b08f2017-07-10 14:13:41 -0700122 DecompileInstanceFieldAccess(inst, Instruction::IGET_OBJECT);
Nicolas Geoffray01b70e82016-11-17 10:58:36 +0000123 break;
124
125 case Instruction::IGET_BOOLEAN_QUICK:
Mathieu Chartierde4b08f2017-07-10 14:13:41 -0700126 DecompileInstanceFieldAccess(inst, Instruction::IGET_BOOLEAN);
Nicolas Geoffray01b70e82016-11-17 10:58:36 +0000127 break;
128
129 case Instruction::IGET_BYTE_QUICK:
Mathieu Chartierde4b08f2017-07-10 14:13:41 -0700130 DecompileInstanceFieldAccess(inst, Instruction::IGET_BYTE);
Nicolas Geoffray01b70e82016-11-17 10:58:36 +0000131 break;
132
133 case Instruction::IGET_CHAR_QUICK:
Mathieu Chartierde4b08f2017-07-10 14:13:41 -0700134 DecompileInstanceFieldAccess(inst, Instruction::IGET_CHAR);
Nicolas Geoffray01b70e82016-11-17 10:58:36 +0000135 break;
136
137 case Instruction::IGET_SHORT_QUICK:
Mathieu Chartierde4b08f2017-07-10 14:13:41 -0700138 DecompileInstanceFieldAccess(inst, Instruction::IGET_SHORT);
Nicolas Geoffray01b70e82016-11-17 10:58:36 +0000139 break;
140
141 case Instruction::IPUT_QUICK:
Mathieu Chartierde4b08f2017-07-10 14:13:41 -0700142 DecompileInstanceFieldAccess(inst, Instruction::IPUT);
Nicolas Geoffray01b70e82016-11-17 10:58:36 +0000143 break;
144
145 case Instruction::IPUT_BOOLEAN_QUICK:
Mathieu Chartierde4b08f2017-07-10 14:13:41 -0700146 DecompileInstanceFieldAccess(inst, Instruction::IPUT_BOOLEAN);
Nicolas Geoffray01b70e82016-11-17 10:58:36 +0000147 break;
148
149 case Instruction::IPUT_BYTE_QUICK:
Mathieu Chartierde4b08f2017-07-10 14:13:41 -0700150 DecompileInstanceFieldAccess(inst, Instruction::IPUT_BYTE);
Nicolas Geoffray01b70e82016-11-17 10:58:36 +0000151 break;
152
153 case Instruction::IPUT_CHAR_QUICK:
Mathieu Chartierde4b08f2017-07-10 14:13:41 -0700154 DecompileInstanceFieldAccess(inst, Instruction::IPUT_CHAR);
Nicolas Geoffray01b70e82016-11-17 10:58:36 +0000155 break;
156
157 case Instruction::IPUT_SHORT_QUICK:
Mathieu Chartierde4b08f2017-07-10 14:13:41 -0700158 DecompileInstanceFieldAccess(inst, Instruction::IPUT_SHORT);
Nicolas Geoffray01b70e82016-11-17 10:58:36 +0000159 break;
160
161 case Instruction::IPUT_WIDE_QUICK:
Mathieu Chartierde4b08f2017-07-10 14:13:41 -0700162 DecompileInstanceFieldAccess(inst, Instruction::IPUT_WIDE);
Nicolas Geoffray01b70e82016-11-17 10:58:36 +0000163 break;
164
165 case Instruction::IPUT_OBJECT_QUICK:
Mathieu Chartierde4b08f2017-07-10 14:13:41 -0700166 DecompileInstanceFieldAccess(inst, Instruction::IPUT_OBJECT);
Nicolas Geoffray01b70e82016-11-17 10:58:36 +0000167 break;
168
169 case Instruction::INVOKE_VIRTUAL_QUICK:
Mathieu Chartierde4b08f2017-07-10 14:13:41 -0700170 DecompileInvokeVirtual(inst, Instruction::INVOKE_VIRTUAL, false);
Nicolas Geoffray01b70e82016-11-17 10:58:36 +0000171 break;
172
173 case Instruction::INVOKE_VIRTUAL_RANGE_QUICK:
Mathieu Chartierde4b08f2017-07-10 14:13:41 -0700174 DecompileInvokeVirtual(inst, Instruction::INVOKE_VIRTUAL_RANGE, true);
Nicolas Geoffray01b70e82016-11-17 10:58:36 +0000175 break;
176
177 default:
178 break;
179 }
180 }
181
Mathieu Chartier210531f2018-01-12 10:15:51 -0800182 if (quicken_index_ != quicken_info_.NumIndices()) {
Mathieu Chartierde4b08f2017-07-10 14:13:41 -0700183 if (quicken_index_ == 0) {
Nicolas Geoffray095d6a62017-04-27 16:08:50 +0100184 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."
Mathieu Chartierde4b08f2017-07-10 14:13:41 -0700188 << " Actual: " << std::hex << quicken_index_
Mathieu Chartier210531f2018-01-12 10:15:51 -0800189 << " Expected: " << quicken_info_.NumIndices();
Nicolas Geoffray095d6a62017-04-27 16:08:50 +0100190 }
Nicolas Geoffray01b70e82016-11-17 10:58:36 +0000191 }
192
193 return true;
194}
195
Mathieu Chartier6238c832018-01-04 09:55:13 -0800196bool ArtDecompileDEX(const DexFile& dex_file,
Andreas Gampe3f1dcd32018-12-28 09:39:56 -0800197 const dex::CodeItem& code_item,
Nicolas Geoffrayb1677e22016-12-16 16:23:16 +0000198 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 }
Mathieu Chartier73f21d42018-01-02 14:26:50 -0800203 DexDecompiler decompiler(dex_file, code_item, quickened_info, decompile_return_instruction);
Nicolas Geoffray01b70e82016-11-17 10:58:36 +0000204 return decompiler.Decompile();
205}
206
207} // namespace optimizer
208} // namespace art