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