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