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 "android-base/stringprintf.h" 25 26 #include "dex_file-inl.h" 27 #include "utf.h" 28 29 namespace art { 30 31 using android::base::StringPrintf; 32 33 const char* const Instruction::kInstructionNames[] = { 34 #define INSTRUCTION_NAME(o, c, pname, f, i, a, e, v) pname, 35 #include "dex_instruction_list.h" 36 DEX_INSTRUCTION_LIST(INSTRUCTION_NAME) 37 #undef DEX_INSTRUCTION_LIST 38 #undef INSTRUCTION_NAME 39 }; 40 41 static_assert(sizeof(Instruction::InstructionDescriptor) == 8u, "Unexpected descriptor size"); 42 43 static constexpr int8_t InstructionSizeInCodeUnitsByOpcode(Instruction::Code opcode, 44 Instruction::Format format) { 45 if (opcode == Instruction::Code::NOP) { 46 return -1; 47 } else if ((format >= Instruction::Format::k10x) && (format <= Instruction::Format::k10t)) { 48 return 1; 49 } else if ((format >= Instruction::Format::k20t) && (format <= Instruction::Format::k22c)) { 50 return 2; 51 } else if ((format >= Instruction::Format::k32x) && (format <= Instruction::Format::k3rc)) { 52 return 3; 53 } else if ((format >= Instruction::Format::k45cc) && (format <= Instruction::Format::k4rcc)) { 54 return 4; 55 } else if (format == Instruction::Format::k51l) { 56 return 5; 57 } else { 58 return -1; 59 } 60 } 61 62 Instruction::InstructionDescriptor const Instruction::kInstructionDescriptors[] = { 63 #define INSTRUCTION_DESCR(opcode, c, p, format, index, flags, eflags, vflags) \ 64 { vflags, \ 65 format, \ 66 index, \ 67 flags, \ 68 InstructionSizeInCodeUnitsByOpcode((c), (format)), \ 69 }, 70 #include "dex_instruction_list.h" 71 DEX_INSTRUCTION_LIST(INSTRUCTION_DESCR) 72 #undef DEX_INSTRUCTION_LIST 73 #undef INSTRUCTION_DESCR 74 }; 75 76 int32_t Instruction::GetTargetOffset() const { 77 switch (FormatOf(Opcode())) { 78 // Cases for conditional branches follow. 79 case k22t: return VRegC_22t(); 80 case k21t: return VRegB_21t(); 81 // Cases for unconditional branches follow. 82 case k10t: return VRegA_10t(); 83 case k20t: return VRegA_20t(); 84 case k30t: return VRegA_30t(); 85 default: LOG(FATAL) << "Tried to access the branch offset of an instruction " << Name() << 86 " which does not have a target operand."; 87 } 88 return 0; 89 } 90 91 bool Instruction::CanFlowThrough() const { 92 const uint16_t* insns = reinterpret_cast<const uint16_t*>(this); 93 uint16_t insn = *insns; 94 Code opcode = static_cast<Code>(insn & 0xFF); 95 return FlagsOf(opcode) & Instruction::kContinue; 96 } 97 98 size_t Instruction::SizeInCodeUnitsComplexOpcode() const { 99 const uint16_t* insns = reinterpret_cast<const uint16_t*>(this); 100 // Handle special NOP encoded variable length sequences. 101 switch (*insns) { 102 case kPackedSwitchSignature: 103 return (4 + insns[1] * 2); 104 case kSparseSwitchSignature: 105 return (2 + insns[1] * 4); 106 case kArrayDataSignature: { 107 uint16_t element_size = insns[1]; 108 uint32_t length = insns[2] | (((uint32_t)insns[3]) << 16); 109 // The plus 1 is to round up for odd size and width. 110 return (4 + (element_size * length + 1) / 2); 111 } 112 default: 113 if ((*insns & 0xFF) == 0) { 114 return 1; // NOP. 115 } else { 116 LOG(FATAL) << "Unreachable: " << DumpString(nullptr); 117 UNREACHABLE(); 118 } 119 } 120 } 121 122 size_t Instruction::CodeUnitsRequiredForSizeOfComplexOpcode() const { 123 const uint16_t* insns = reinterpret_cast<const uint16_t*>(this); 124 // Handle special NOP encoded variable length sequences. 125 switch (*insns) { 126 case kPackedSwitchSignature: 127 FALLTHROUGH_INTENDED; 128 case kSparseSwitchSignature: 129 return 2; 130 case kArrayDataSignature: 131 return 4; 132 default: 133 if ((*insns & 0xFF) == 0) { 134 return 1; // NOP. 135 } else { 136 LOG(FATAL) << "Unreachable: " << DumpString(nullptr); 137 UNREACHABLE(); 138 } 139 } 140 } 141 142 std::string Instruction::DumpHex(size_t code_units) const { 143 size_t inst_length = SizeInCodeUnits(); 144 if (inst_length > code_units) { 145 inst_length = code_units; 146 } 147 std::ostringstream os; 148 const uint16_t* insn = reinterpret_cast<const uint16_t*>(this); 149 for (size_t i = 0; i < inst_length; i++) { 150 os << StringPrintf("0x%04x", insn[i]) << " "; 151 } 152 for (size_t i = inst_length; i < code_units; i++) { 153 os << " "; 154 } 155 return os.str(); 156 } 157 158 std::string Instruction::DumpHexLE(size_t instr_code_units) const { 159 size_t inst_length = SizeInCodeUnits(); 160 if (inst_length > instr_code_units) { 161 inst_length = instr_code_units; 162 } 163 std::ostringstream os; 164 const uint16_t* insn = reinterpret_cast<const uint16_t*>(this); 165 for (size_t i = 0; i < inst_length; i++) { 166 os << StringPrintf("%02x%02x", static_cast<uint8_t>(insn[i] & 0x00FF), 167 static_cast<uint8_t>((insn[i] & 0xFF00) >> 8)) << " "; 168 } 169 for (size_t i = inst_length; i < instr_code_units; i++) { 170 os << " "; 171 } 172 return os.str(); 173 } 174 175 std::string Instruction::DumpString(const DexFile* file) const { 176 std::ostringstream os; 177 const char* opcode = kInstructionNames[Opcode()]; 178 switch (FormatOf(Opcode())) { 179 case k10x: os << opcode; break; 180 case k12x: os << StringPrintf("%s v%d, v%d", opcode, VRegA_12x(), VRegB_12x()); break; 181 case k11n: os << StringPrintf("%s v%d, #%+d", opcode, VRegA_11n(), VRegB_11n()); break; 182 case k11x: os << StringPrintf("%s v%d", opcode, VRegA_11x()); break; 183 case k10t: os << StringPrintf("%s %+d", opcode, VRegA_10t()); break; 184 case k20t: os << StringPrintf("%s %+d", opcode, VRegA_20t()); break; 185 case k22x: os << StringPrintf("%s v%d, v%d", opcode, VRegA_22x(), VRegB_22x()); break; 186 case k21t: os << StringPrintf("%s v%d, %+d", opcode, VRegA_21t(), VRegB_21t()); break; 187 case k21s: os << StringPrintf("%s v%d, #%+d", opcode, VRegA_21s(), VRegB_21s()); break; 188 case k21h: { 189 // op vAA, #+BBBB0000[00000000] 190 if (Opcode() == CONST_HIGH16) { 191 uint32_t value = VRegB_21h() << 16; 192 os << StringPrintf("%s v%d, #int %+d // 0x%x", opcode, VRegA_21h(), value, value); 193 } else { 194 uint64_t value = static_cast<uint64_t>(VRegB_21h()) << 48; 195 os << StringPrintf("%s v%d, #long %+" PRId64 " // 0x%" PRIx64, opcode, VRegA_21h(), 196 value, value); 197 } 198 } 199 break; 200 case k21c: { 201 switch (Opcode()) { 202 case CONST_STRING: 203 if (file != nullptr) { 204 uint32_t string_idx = VRegB_21c(); 205 if (string_idx < file->NumStringIds()) { 206 os << StringPrintf( 207 "const-string v%d, %s // string@%d", 208 VRegA_21c(), 209 PrintableString(file->StringDataByIdx(dex::StringIndex(string_idx))).c_str(), 210 string_idx); 211 } else { 212 os << StringPrintf("const-string v%d, <<invalid-string-idx-%d>> // string@%d", 213 VRegA_21c(), 214 string_idx, 215 string_idx); 216 } 217 break; 218 } 219 FALLTHROUGH_INTENDED; 220 case CHECK_CAST: 221 case CONST_CLASS: 222 case NEW_INSTANCE: 223 if (file != nullptr) { 224 dex::TypeIndex type_idx(VRegB_21c()); 225 os << opcode << " v" << static_cast<int>(VRegA_21c()) << ", " 226 << file->PrettyType(type_idx) << " // type@" << type_idx; 227 break; 228 } 229 FALLTHROUGH_INTENDED; 230 case SGET: 231 case SGET_WIDE: 232 case SGET_OBJECT: 233 case SGET_BOOLEAN: 234 case SGET_BYTE: 235 case SGET_CHAR: 236 case SGET_SHORT: 237 if (file != nullptr) { 238 uint32_t field_idx = VRegB_21c(); 239 os << opcode << " v" << static_cast<int>(VRegA_21c()) << ", " << file->PrettyField(field_idx, true) 240 << " // field@" << field_idx; 241 break; 242 } 243 FALLTHROUGH_INTENDED; 244 case SPUT: 245 case SPUT_WIDE: 246 case SPUT_OBJECT: 247 case SPUT_BOOLEAN: 248 case SPUT_BYTE: 249 case SPUT_CHAR: 250 case SPUT_SHORT: 251 if (file != nullptr) { 252 uint32_t field_idx = VRegB_21c(); 253 os << opcode << " v" << static_cast<int>(VRegA_21c()) << ", " << file->PrettyField(field_idx, true) 254 << " // field@" << field_idx; 255 break; 256 } 257 FALLTHROUGH_INTENDED; 258 default: 259 os << StringPrintf("%s v%d, thing@%d", opcode, VRegA_21c(), VRegB_21c()); 260 break; 261 } 262 break; 263 } 264 case k23x: os << StringPrintf("%s v%d, v%d, v%d", opcode, VRegA_23x(), VRegB_23x(), VRegC_23x()); break; 265 case k22b: os << StringPrintf("%s v%d, v%d, #%+d", opcode, VRegA_22b(), VRegB_22b(), VRegC_22b()); break; 266 case k22t: os << StringPrintf("%s v%d, v%d, %+d", opcode, VRegA_22t(), VRegB_22t(), VRegC_22t()); break; 267 case k22s: os << StringPrintf("%s v%d, v%d, #%+d", opcode, VRegA_22s(), VRegB_22s(), VRegC_22s()); break; 268 case k22c: { 269 switch (Opcode()) { 270 case IGET: 271 case IGET_WIDE: 272 case IGET_OBJECT: 273 case IGET_BOOLEAN: 274 case IGET_BYTE: 275 case IGET_CHAR: 276 case IGET_SHORT: 277 if (file != nullptr) { 278 uint32_t field_idx = VRegC_22c(); 279 os << opcode << " v" << static_cast<int>(VRegA_22c()) << ", v" << static_cast<int>(VRegB_22c()) << ", " 280 << file->PrettyField(field_idx, true) << " // field@" << field_idx; 281 break; 282 } 283 FALLTHROUGH_INTENDED; 284 case IGET_QUICK: 285 case IGET_OBJECT_QUICK: 286 if (file != nullptr) { 287 uint32_t field_idx = VRegC_22c(); 288 os << opcode << " v" << static_cast<int>(VRegA_22c()) << ", v" << static_cast<int>(VRegB_22c()) << ", " 289 << "// offset@" << field_idx; 290 break; 291 } 292 FALLTHROUGH_INTENDED; 293 case IPUT: 294 case IPUT_WIDE: 295 case IPUT_OBJECT: 296 case IPUT_BOOLEAN: 297 case IPUT_BYTE: 298 case IPUT_CHAR: 299 case IPUT_SHORT: 300 if (file != nullptr) { 301 uint32_t field_idx = VRegC_22c(); 302 os << opcode << " v" << static_cast<int>(VRegA_22c()) << ", v" << static_cast<int>(VRegB_22c()) << ", " 303 << file->PrettyField(field_idx, true) << " // field@" << field_idx; 304 break; 305 } 306 FALLTHROUGH_INTENDED; 307 case IPUT_QUICK: 308 case IPUT_OBJECT_QUICK: 309 if (file != nullptr) { 310 uint32_t field_idx = VRegC_22c(); 311 os << opcode << " v" << static_cast<int>(VRegA_22c()) << ", v" << static_cast<int>(VRegB_22c()) << ", " 312 << "// offset@" << field_idx; 313 break; 314 } 315 FALLTHROUGH_INTENDED; 316 case INSTANCE_OF: 317 if (file != nullptr) { 318 dex::TypeIndex type_idx(VRegC_22c()); 319 os << opcode << " v" << static_cast<int>(VRegA_22c()) << ", v" 320 << static_cast<int>(VRegB_22c()) << ", " << file->PrettyType(type_idx) 321 << " // type@" << type_idx.index_; 322 break; 323 } 324 FALLTHROUGH_INTENDED; 325 case NEW_ARRAY: 326 if (file != nullptr) { 327 dex::TypeIndex type_idx(VRegC_22c()); 328 os << opcode << " v" << static_cast<int>(VRegA_22c()) << ", v" 329 << static_cast<int>(VRegB_22c()) << ", " << file->PrettyType(type_idx) 330 << " // type@" << type_idx.index_; 331 break; 332 } 333 FALLTHROUGH_INTENDED; 334 default: 335 os << StringPrintf("%s v%d, v%d, thing@%d", opcode, VRegA_22c(), VRegB_22c(), VRegC_22c()); 336 break; 337 } 338 break; 339 } 340 case k32x: os << StringPrintf("%s v%d, v%d", opcode, VRegA_32x(), VRegB_32x()); break; 341 case k30t: os << StringPrintf("%s %+d", opcode, VRegA_30t()); break; 342 case k31t: os << StringPrintf("%s v%d, %+d", opcode, VRegA_31t(), VRegB_31t()); break; 343 case k31i: os << StringPrintf("%s v%d, #%+d", opcode, VRegA_31i(), VRegB_31i()); break; 344 case k31c: 345 if (Opcode() == CONST_STRING_JUMBO) { 346 uint32_t string_idx = VRegB_31c(); 347 if (file != nullptr) { 348 if (string_idx < file->NumStringIds()) { 349 os << StringPrintf( 350 "%s v%d, %s // string@%d", 351 opcode, 352 VRegA_31c(), 353 PrintableString(file->StringDataByIdx(dex::StringIndex(string_idx))).c_str(), 354 string_idx); 355 } else { 356 os << StringPrintf("%s v%d, <<invalid-string-idx-%d>> // string@%d", 357 opcode, 358 VRegA_31c(), 359 string_idx, 360 string_idx); 361 } 362 } else { 363 os << StringPrintf("%s v%d, string@%d", opcode, VRegA_31c(), string_idx); 364 } 365 } else { 366 os << StringPrintf("%s v%d, thing@%d", opcode, VRegA_31c(), VRegB_31c()); break; 367 } 368 break; 369 case k35c: { 370 uint32_t arg[kMaxVarArgRegs]; 371 GetVarArgs(arg); 372 auto DumpArgs = [&](size_t count) { 373 for (size_t i = 0; i < count; ++i) { 374 if (i != 0) { 375 os << ", "; 376 } 377 os << "v" << arg[i]; 378 } 379 }; 380 switch (Opcode()) { 381 case FILLED_NEW_ARRAY: 382 { 383 os << opcode << " {"; 384 DumpArgs(VRegA_35c()); 385 os << "}, type@" << VRegB_35c(); 386 } 387 break; 388 389 case INVOKE_VIRTUAL: 390 case INVOKE_SUPER: 391 case INVOKE_DIRECT: 392 case INVOKE_STATIC: 393 case INVOKE_INTERFACE: 394 if (file != nullptr) { 395 os << opcode << " {"; 396 uint32_t method_idx = VRegB_35c(); 397 DumpArgs(VRegA_35c()); 398 os << "}, " << file->PrettyMethod(method_idx) << " // method@" << method_idx; 399 break; 400 } 401 FALLTHROUGH_INTENDED; 402 case INVOKE_VIRTUAL_QUICK: 403 if (file != nullptr) { 404 os << opcode << " {"; 405 uint32_t method_idx = VRegB_35c(); 406 DumpArgs(VRegA_35c()); 407 os << "}, // vtable@" << method_idx; 408 break; 409 } 410 FALLTHROUGH_INTENDED; 411 case INVOKE_CUSTOM: 412 if (file != nullptr) { 413 os << opcode << " {"; 414 uint32_t call_site_idx = VRegB_35c(); 415 DumpArgs(VRegA_35c()); 416 os << "}, // call_site@" << call_site_idx; 417 break; 418 } 419 FALLTHROUGH_INTENDED; 420 default: 421 os << opcode << " {"; 422 DumpArgs(VRegA_35c()); 423 os << "}, thing@" << VRegB_35c(); 424 break; 425 } 426 break; 427 } 428 case k3rc: { 429 uint16_t first_reg = VRegC_3rc(); 430 uint16_t last_reg = VRegC_3rc() + VRegA_3rc() - 1; 431 switch (Opcode()) { 432 case INVOKE_VIRTUAL_RANGE: 433 case INVOKE_SUPER_RANGE: 434 case INVOKE_DIRECT_RANGE: 435 case INVOKE_STATIC_RANGE: 436 case INVOKE_INTERFACE_RANGE: 437 if (file != nullptr) { 438 uint32_t method_idx = VRegB_3rc(); 439 os << StringPrintf("%s, {v%d .. v%d}, ", opcode, first_reg, last_reg) 440 << file->PrettyMethod(method_idx) << " // method@" << method_idx; 441 break; 442 } 443 FALLTHROUGH_INTENDED; 444 case INVOKE_VIRTUAL_RANGE_QUICK: 445 if (file != nullptr) { 446 uint32_t method_idx = VRegB_3rc(); 447 os << StringPrintf("%s, {v%d .. v%d}, ", opcode, first_reg, last_reg) 448 << "// vtable@" << method_idx; 449 break; 450 } 451 FALLTHROUGH_INTENDED; 452 case INVOKE_CUSTOM_RANGE: 453 if (file != nullptr) { 454 uint32_t call_site_idx = VRegB_3rc(); 455 os << StringPrintf("%s, {v%d .. v%d}, ", opcode, first_reg, last_reg) 456 << "// call_site@" << call_site_idx; 457 break; 458 } 459 FALLTHROUGH_INTENDED; 460 default: 461 os << StringPrintf("%s, {v%d .. v%d}, ", opcode, first_reg, last_reg) 462 << "thing@" << VRegB_3rc(); 463 break; 464 } 465 break; 466 } 467 case k45cc: { 468 uint32_t arg[kMaxVarArgRegs]; 469 GetVarArgs(arg); 470 uint32_t method_idx = VRegB_45cc(); 471 uint32_t proto_idx = VRegH_45cc(); 472 os << opcode << " {"; 473 for (int i = 0; i < VRegA_45cc(); ++i) { 474 if (i != 0) { 475 os << ", "; 476 } 477 os << "v" << arg[i]; 478 } 479 os << "}"; 480 if (file != nullptr) { 481 os << ", " << file->PrettyMethod(method_idx) << ", " << file->GetShorty(proto_idx) 482 << " // "; 483 } else { 484 os << ", "; 485 } 486 os << "method@" << method_idx << ", proto@" << proto_idx; 487 break; 488 } 489 case k4rcc: 490 switch (Opcode()) { 491 case INVOKE_POLYMORPHIC_RANGE: { 492 if (file != nullptr) { 493 uint32_t method_idx = VRegB_4rcc(); 494 uint32_t proto_idx = VRegH_4rcc(); 495 os << opcode << ", {v" << VRegC_4rcc() << " .. v" << (VRegC_4rcc() + VRegA_4rcc()) 496 << "}, " << file->PrettyMethod(method_idx) << ", " << file->GetShorty(proto_idx) 497 << " // method@" << method_idx << ", proto@" << proto_idx; 498 break; 499 } 500 } 501 FALLTHROUGH_INTENDED; 502 default: { 503 uint32_t method_idx = VRegB_4rcc(); 504 uint32_t proto_idx = VRegH_4rcc(); 505 os << opcode << ", {v" << VRegC_4rcc() << " .. v" << (VRegC_4rcc() + VRegA_4rcc()) 506 << "}, method@" << method_idx << ", proto@" << proto_idx; 507 } 508 } 509 break; 510 case k51l: os << StringPrintf("%s v%d, #%+" PRId64, opcode, VRegA_51l(), VRegB_51l()); break; 511 } 512 return os.str(); 513 } 514 515 // Add some checks that ensure the flags make sense. We need a subclass to be in the context of 516 // Instruction. Otherwise the flags from the instruction list don't work. 517 struct InstructionStaticAsserts : private Instruction { 518 #define IMPLIES(a, b) (!(a) || (b)) 519 520 #define VAR_ARGS_CHECK(o, c, pname, f, i, a, e, v) \ 521 static_assert(IMPLIES((f) == k35c || (f) == k45cc, \ 522 ((v) & (kVerifyVarArg | kVerifyVarArgNonZero)) != 0), \ 523 "Missing var-arg verification"); 524 #include "dex_instruction_list.h" 525 DEX_INSTRUCTION_LIST(VAR_ARGS_CHECK) 526 #undef DEX_INSTRUCTION_LIST 527 #undef VAR_ARGS_CHECK 528 529 #define VAR_ARGS_RANGE_CHECK(o, c, pname, f, i, a, e, v) \ 530 static_assert(IMPLIES((f) == k3rc || (f) == k4rcc, \ 531 ((v) & (kVerifyVarArgRange | kVerifyVarArgRangeNonZero)) != 0), \ 532 "Missing var-arg verification"); 533 #include "dex_instruction_list.h" 534 DEX_INSTRUCTION_LIST(VAR_ARGS_RANGE_CHECK) 535 #undef DEX_INSTRUCTION_LIST 536 #undef VAR_ARGS_RANGE_CHECK 537 538 #define EXPERIMENTAL_CHECK(o, c, pname, f, i, a, e, v) \ 539 static_assert(kHaveExperimentalInstructions || (((a) & kExperimental) == 0), \ 540 "Unexpected experimental instruction."); 541 #include "dex_instruction_list.h" 542 DEX_INSTRUCTION_LIST(EXPERIMENTAL_CHECK) 543 #undef DEX_INSTRUCTION_LIST 544 #undef EXPERIMENTAL_CHECK 545 }; 546 547 std::ostream& operator<<(std::ostream& os, const Instruction::Code& code) { 548 return os << Instruction::Name(code); 549 } 550 551 uint32_t RangeInstructionOperands::GetOperand(size_t operand_index) const { 552 DCHECK_LT(operand_index, GetNumberOfOperands()); 553 return first_operand_ + operand_index; 554 } 555 556 uint32_t VarArgsInstructionOperands::GetOperand(size_t operand_index) const { 557 DCHECK_LT(operand_index, GetNumberOfOperands()); 558 return operands_[operand_index]; 559 } 560 561 uint32_t NoReceiverInstructionOperands::GetOperand(size_t operand_index) const { 562 DCHECK_LT(GetNumberOfOperands(), inner_->GetNumberOfOperands()); 563 // The receiver is the first operand and since we're skipping it, we need to 564 // add 1 to the operand_index. 565 return inner_->GetOperand(operand_index + 1); 566 } 567 568 } // namespace art 569