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