• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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