1 /* 2 * Copyright (C) 2011 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_instruction-inl.h" 18 19 #include <inttypes.h> 20 21 #include <iomanip> 22 23 #include "base/stringprintf.h" 24 #include "dex_file-inl.h" 25 #include "utils.h" 26 27 namespace art { 28 29 const char* const Instruction::kInstructionNames[] = { 30 #define INSTRUCTION_NAME(o, c, pname, f, r, i, a, v) pname, 31 #include "dex_instruction_list.h" 32 DEX_INSTRUCTION_LIST(INSTRUCTION_NAME) 33 #undef DEX_INSTRUCTION_LIST 34 #undef INSTRUCTION_NAME 35 }; 36 37 Instruction::Format const Instruction::kInstructionFormats[] = { 38 #define INSTRUCTION_FORMAT(o, c, p, format, r, i, a, v) format, 39 #include "dex_instruction_list.h" 40 DEX_INSTRUCTION_LIST(INSTRUCTION_FORMAT) 41 #undef DEX_INSTRUCTION_LIST 42 #undef INSTRUCTION_FORMAT 43 }; 44 45 int const Instruction::kInstructionFlags[] = { 46 #define INSTRUCTION_FLAGS(o, c, p, f, r, i, flags, v) flags, 47 #include "dex_instruction_list.h" 48 DEX_INSTRUCTION_LIST(INSTRUCTION_FLAGS) 49 #undef DEX_INSTRUCTION_LIST 50 #undef INSTRUCTION_FLAGS 51 }; 52 53 int const Instruction::kInstructionVerifyFlags[] = { 54 #define INSTRUCTION_VERIFY_FLAGS(o, c, p, f, r, i, a, vflags) vflags, 55 #include "dex_instruction_list.h" 56 DEX_INSTRUCTION_LIST(INSTRUCTION_VERIFY_FLAGS) 57 #undef DEX_INSTRUCTION_LIST 58 #undef INSTRUCTION_VERIFY_FLAGS 59 }; 60 61 int const Instruction::kInstructionSizeInCodeUnits[] = { 62 #define INSTRUCTION_SIZE(opcode, c, p, format, r, i, a, v) \ 63 ((opcode == NOP) ? -1 : \ 64 ((format >= k10x) && (format <= k10t)) ? 1 : \ 65 ((format >= k20t) && (format <= k22c)) ? 2 : \ 66 ((format >= k32x) && (format <= k3rc)) ? 3 : \ 67 (format == k51l) ? 5 : -1), 68 #include "dex_instruction_list.h" 69 DEX_INSTRUCTION_LIST(INSTRUCTION_SIZE) 70 #undef DEX_INSTRUCTION_LIST 71 #undef INSTRUCTION_SIZE 72 }; 73 74 int32_t Instruction::GetTargetOffset() const { 75 switch (FormatOf(Opcode())) { 76 // Cases for conditional branches follow. 77 case k22t: return VRegC_22t(); 78 case k21t: return VRegB_21t(); 79 // Cases for unconditional branches follow. 80 case k10t: return VRegA_10t(); 81 case k20t: return VRegA_20t(); 82 case k30t: return VRegA_30t(); 83 default: LOG(FATAL) << "Tried to access the branch offset of an instruction " << Name() << 84 " which does not have a target operand."; 85 } 86 return 0; 87 } 88 89 bool Instruction::CanFlowThrough() const { 90 const uint16_t* insns = reinterpret_cast<const uint16_t*>(this); 91 uint16_t insn = *insns; 92 Code opcode = static_cast<Code>(insn & 0xFF); 93 return FlagsOf(opcode) & Instruction::kContinue; 94 } 95 96 size_t Instruction::SizeInCodeUnitsComplexOpcode() const { 97 const uint16_t* insns = reinterpret_cast<const uint16_t*>(this); 98 // Handle special NOP encoded variable length sequences. 99 switch (*insns) { 100 case kPackedSwitchSignature: 101 return (4 + insns[1] * 2); 102 case kSparseSwitchSignature: 103 return (2 + insns[1] * 4); 104 case kArrayDataSignature: { 105 uint16_t element_size = insns[1]; 106 uint32_t length = insns[2] | (((uint32_t)insns[3]) << 16); 107 // The plus 1 is to round up for odd size and width. 108 return (4 + (element_size * length + 1) / 2); 109 } 110 default: 111 if ((*insns & 0xFF) == 0) { 112 return 1; // NOP. 113 } else { 114 LOG(FATAL) << "Unreachable: " << DumpString(NULL); 115 return 0; 116 } 117 } 118 } 119 120 std::string Instruction::DumpHex(size_t code_units) const { 121 size_t inst_length = SizeInCodeUnits(); 122 if (inst_length > code_units) { 123 inst_length = code_units; 124 } 125 std::ostringstream os; 126 const uint16_t* insn = reinterpret_cast<const uint16_t*>(this); 127 for (size_t i = 0; i < inst_length; i++) { 128 os << StringPrintf("0x%04x", insn[i]) << " "; 129 } 130 for (size_t i = inst_length; i < code_units; i++) { 131 os << " "; 132 } 133 return os.str(); 134 } 135 136 std::string Instruction::DumpString(const DexFile* file) const { 137 std::ostringstream os; 138 const char* opcode = kInstructionNames[Opcode()]; 139 switch (FormatOf(Opcode())) { 140 case k10x: os << opcode; break; 141 case k12x: os << StringPrintf("%s v%d, v%d", opcode, VRegA_12x(), VRegB_12x()); break; 142 case k11n: os << StringPrintf("%s v%d, #%+d", opcode, VRegA_11n(), VRegB_11n()); break; 143 case k11x: os << StringPrintf("%s v%d", opcode, VRegA_11x()); break; 144 case k10t: os << StringPrintf("%s %+d", opcode, VRegA_10t()); break; 145 case k20t: os << StringPrintf("%s %+d", opcode, VRegA_20t()); break; 146 case k22x: os << StringPrintf("%s v%d, v%d", opcode, VRegA_22x(), VRegB_22x()); break; 147 case k21t: os << StringPrintf("%s v%d, %+d", opcode, VRegA_21t(), VRegB_21t()); break; 148 case k21s: os << StringPrintf("%s v%d, #%+d", opcode, VRegA_21s(), VRegB_21s()); break; 149 case k21h: { 150 // op vAA, #+BBBB0000[00000000] 151 if (Opcode() == CONST_HIGH16) { 152 uint32_t value = VRegB_21h() << 16; 153 os << StringPrintf("%s v%d, #int %+d // 0x%x", opcode, VRegA_21h(), value, value); 154 } else { 155 uint64_t value = static_cast<uint64_t>(VRegB_21h()) << 48; 156 os << StringPrintf("%s v%d, #long %+" PRId64 " // 0x%" PRIx64, opcode, VRegA_21h(), 157 value, value); 158 } 159 } 160 break; 161 case k21c: { 162 switch (Opcode()) { 163 case CONST_STRING: 164 if (file != NULL) { 165 uint32_t string_idx = VRegB_21c(); 166 os << StringPrintf("const-string v%d, %s // string@%d", VRegA_21c(), 167 PrintableString(file->StringDataByIdx(string_idx)).c_str(), string_idx); 168 break; 169 } // else fall-through 170 case CHECK_CAST: 171 case CONST_CLASS: 172 case NEW_INSTANCE: 173 if (file != NULL) { 174 uint32_t type_idx = VRegB_21c(); 175 os << opcode << " v" << static_cast<int>(VRegA_21c()) << ", " << PrettyType(type_idx, *file) 176 << " // type@" << type_idx; 177 break; 178 } // else fall-through 179 case SGET: 180 case SGET_WIDE: 181 case SGET_OBJECT: 182 case SGET_BOOLEAN: 183 case SGET_BYTE: 184 case SGET_CHAR: 185 case SGET_SHORT: 186 if (file != NULL) { 187 uint32_t field_idx = VRegB_21c(); 188 os << opcode << " v" << static_cast<int>(VRegA_21c()) << ", " << PrettyField(field_idx, *file, true) 189 << " // field@" << field_idx; 190 break; 191 } // else fall-through 192 case SPUT: 193 case SPUT_WIDE: 194 case SPUT_OBJECT: 195 case SPUT_BOOLEAN: 196 case SPUT_BYTE: 197 case SPUT_CHAR: 198 case SPUT_SHORT: 199 if (file != NULL) { 200 uint32_t field_idx = VRegB_21c(); 201 os << opcode << " v" << static_cast<int>(VRegA_21c()) << ", " << PrettyField(field_idx, *file, true) 202 << " // field@" << field_idx; 203 break; 204 } // else fall-through 205 default: 206 os << StringPrintf("%s v%d, thing@%d", opcode, VRegA_21c(), VRegB_21c()); 207 break; 208 } 209 break; 210 } 211 case k23x: os << StringPrintf("%s v%d, v%d, v%d", opcode, VRegA_23x(), VRegB_23x(), VRegC_23x()); break; 212 case k22b: os << StringPrintf("%s v%d, v%d, #%+d", opcode, VRegA_22b(), VRegB_22b(), VRegC_22b()); break; 213 case k22t: os << StringPrintf("%s v%d, v%d, %+d", opcode, VRegA_22t(), VRegB_22t(), VRegC_22t()); break; 214 case k22s: os << StringPrintf("%s v%d, v%d, #%+d", opcode, VRegA_22s(), VRegB_22s(), VRegC_22s()); break; 215 case k22c: { 216 switch (Opcode()) { 217 case IGET: 218 case IGET_WIDE: 219 case IGET_OBJECT: 220 case IGET_BOOLEAN: 221 case IGET_BYTE: 222 case IGET_CHAR: 223 case IGET_SHORT: 224 if (file != NULL) { 225 uint32_t field_idx = VRegC_22c(); 226 os << opcode << " v" << static_cast<int>(VRegA_22c()) << ", v" << static_cast<int>(VRegB_22c()) << ", " 227 << PrettyField(field_idx, *file, true) << " // field@" << field_idx; 228 break; 229 } // else fall-through 230 case IGET_QUICK: 231 case IGET_OBJECT_QUICK: 232 if (file != NULL) { 233 uint32_t field_idx = VRegC_22c(); 234 os << opcode << " v" << static_cast<int>(VRegA_22c()) << ", v" << static_cast<int>(VRegB_22c()) << ", " 235 << "// offset@" << field_idx; 236 break; 237 } // else fall-through 238 case IPUT: 239 case IPUT_WIDE: 240 case IPUT_OBJECT: 241 case IPUT_BOOLEAN: 242 case IPUT_BYTE: 243 case IPUT_CHAR: 244 case IPUT_SHORT: 245 if (file != NULL) { 246 uint32_t field_idx = VRegC_22c(); 247 os << opcode << " v" << static_cast<int>(VRegA_22c()) << ", v" << static_cast<int>(VRegB_22c()) << ", " 248 << PrettyField(field_idx, *file, true) << " // field@" << field_idx; 249 break; 250 } // else fall-through 251 case IPUT_QUICK: 252 case IPUT_OBJECT_QUICK: 253 if (file != NULL) { 254 uint32_t field_idx = VRegC_22c(); 255 os << opcode << " v" << static_cast<int>(VRegA_22c()) << ", v" << static_cast<int>(VRegB_22c()) << ", " 256 << "// offset@" << field_idx; 257 break; 258 } // else fall-through 259 case INSTANCE_OF: 260 if (file != NULL) { 261 uint32_t type_idx = VRegC_22c(); 262 os << opcode << " v" << static_cast<int>(VRegA_22c()) << ", v" << static_cast<int>(VRegB_22c()) << ", " 263 << PrettyType(type_idx, *file) << " // type@" << type_idx; 264 break; 265 } 266 case NEW_ARRAY: 267 if (file != NULL) { 268 uint32_t type_idx = VRegC_22c(); 269 os << opcode << " v" << static_cast<int>(VRegA_22c()) << ", v" << static_cast<int>(VRegB_22c()) << ", " 270 << PrettyType(type_idx, *file) << " // type@" << type_idx; 271 break; 272 } // else fall-through 273 default: 274 os << StringPrintf("%s v%d, v%d, thing@%d", opcode, VRegA_22c(), VRegB_22c(), VRegC_22c()); 275 break; 276 } 277 break; 278 } 279 case k32x: os << StringPrintf("%s v%d, v%d", opcode, VRegA_32x(), VRegB_32x()); break; 280 case k30t: os << StringPrintf("%s %+d", opcode, VRegA_30t()); break; 281 case k31t: os << StringPrintf("%s v%d, %+d", opcode, VRegA_31t(), VRegB_31t()); break; 282 case k31i: os << StringPrintf("%s v%d, #%+d", opcode, VRegA_31i(), VRegB_31i()); break; 283 case k31c: 284 if (Opcode() == CONST_STRING_JUMBO) { 285 uint32_t string_idx = VRegB_31c(); 286 if (file != NULL) { 287 os << StringPrintf("%s v%d, %s // string@%d", opcode, VRegA_31c(), 288 PrintableString(file->StringDataByIdx(string_idx)).c_str(), 289 string_idx); 290 } else { 291 os << StringPrintf("%s v%d, string@%d", opcode, VRegA_31c(), string_idx); 292 } 293 } else { 294 os << StringPrintf("%s v%d, thing@%d", opcode, VRegA_31c(), VRegB_31c()); break; 295 } 296 break; 297 case k35c: { 298 uint32_t arg[5]; 299 GetVarArgs(arg); 300 switch (Opcode()) { 301 case FILLED_NEW_ARRAY: 302 { 303 const int32_t a = VRegA_35c(); 304 os << opcode << " {"; 305 for (int i = 0; i < a; ++i) { 306 if (i > 0) { 307 os << ", "; 308 } 309 os << "v" << arg[i]; 310 } 311 os << "}, type@" << VRegB_35c(); 312 } 313 break; 314 315 case INVOKE_VIRTUAL: 316 case INVOKE_SUPER: 317 case INVOKE_DIRECT: 318 case INVOKE_STATIC: 319 case INVOKE_INTERFACE: 320 if (file != NULL) { 321 os << opcode << " {"; 322 uint32_t method_idx = VRegB_35c(); 323 for (size_t i = 0; i < VRegA_35c(); ++i) { 324 if (i != 0) { 325 os << ", "; 326 } 327 os << "v" << arg[i]; 328 } 329 os << "}, " << PrettyMethod(method_idx, *file) << " // method@" << method_idx; 330 break; 331 } // else fall-through 332 case INVOKE_VIRTUAL_QUICK: 333 if (file != NULL) { 334 os << opcode << " {"; 335 uint32_t method_idx = VRegB_35c(); 336 for (size_t i = 0; i < VRegA_35c(); ++i) { 337 if (i != 0) { 338 os << ", "; 339 } 340 os << "v" << arg[i]; 341 } 342 os << "}, // vtable@" << method_idx; 343 break; 344 } // else fall-through 345 default: 346 os << opcode << " {v" << arg[0] << ", v" << arg[1] << ", v" << arg[2] 347 << ", v" << arg[3] << ", v" << arg[4] << "}, thing@" << VRegB_35c(); 348 break; 349 } 350 break; 351 } 352 case k3rc: { 353 switch (Opcode()) { 354 case INVOKE_VIRTUAL_RANGE: 355 case INVOKE_SUPER_RANGE: 356 case INVOKE_DIRECT_RANGE: 357 case INVOKE_STATIC_RANGE: 358 case INVOKE_INTERFACE_RANGE: 359 if (file != NULL) { 360 uint32_t method_idx = VRegB_3rc(); 361 os << StringPrintf("%s, {v%d .. v%d}, ", opcode, VRegC_3rc(), (VRegC_3rc() + VRegA_3rc() - 1)) 362 << PrettyMethod(method_idx, *file) << " // method@" << method_idx; 363 break; 364 } // else fall-through 365 case INVOKE_VIRTUAL_RANGE_QUICK: 366 if (file != NULL) { 367 uint32_t method_idx = VRegB_3rc(); 368 os << StringPrintf("%s, {v%d .. v%d}, ", opcode, VRegC_3rc(), (VRegC_3rc() + VRegA_3rc() - 1)) 369 << "// vtable@" << method_idx; 370 break; 371 } // else fall-through 372 default: 373 os << StringPrintf("%s, {v%d .. v%d}, thing@%d", opcode, VRegC_3rc(), 374 (VRegC_3rc() + VRegA_3rc() - 1), VRegB_3rc()); 375 break; 376 } 377 break; 378 } 379 case k51l: os << StringPrintf("%s v%d, #%+" PRId64, opcode, VRegA_51l(), VRegB_51l()); break; 380 default: os << " unknown format (" << DumpHex(5) << ")"; break; 381 } 382 return os.str(); 383 } 384 385 std::ostream& operator<<(std::ostream& os, const Instruction::Code& code) { 386 return os << Instruction::Name(code); 387 } 388 389 } // namespace art 390