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: 34 DexDecompiler(const DexFile& dex_file, 35 const DexFile::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: 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 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 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 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 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 return false; 191 } 192 } 193 194 return true; 195 } 196 197 bool ArtDecompileDEX(const DexFile& dex_file, 198 const DexFile::CodeItem& code_item, 199 const ArrayRef<const uint8_t>& quickened_info, 200 bool decompile_return_instruction) { 201 if (quickened_info.size() == 0 && !decompile_return_instruction) { 202 return true; 203 } 204 DexDecompiler decompiler(dex_file, code_item, quickened_info, decompile_return_instruction); 205 return decompiler.Decompile(); 206 } 207 208 } // namespace optimizer 209 } // namespace art 210