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 "utils.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 std::string Instruction::DumpHex(size_t code_units) const { 123 size_t inst_length = SizeInCodeUnits(); 124 if (inst_length > code_units) { 125 inst_length = code_units; 126 } 127 std::ostringstream os; 128 const uint16_t* insn = reinterpret_cast<const uint16_t*>(this); 129 for (size_t i = 0; i < inst_length; i++) { 130 os << StringPrintf("0x%04x", insn[i]) << " "; 131 } 132 for (size_t i = inst_length; i < code_units; i++) { 133 os << " "; 134 } 135 return os.str(); 136 } 137 138 std::string Instruction::DumpHexLE(size_t instr_code_units) const { 139 size_t inst_length = SizeInCodeUnits(); 140 if (inst_length > instr_code_units) { 141 inst_length = instr_code_units; 142 } 143 std::ostringstream os; 144 const uint16_t* insn = reinterpret_cast<const uint16_t*>(this); 145 for (size_t i = 0; i < inst_length; i++) { 146 os << StringPrintf("%02x%02x", static_cast<uint8_t>(insn[i] & 0x00FF), 147 static_cast<uint8_t>((insn[i] & 0xFF00) >> 8)) << " "; 148 } 149 for (size_t i = inst_length; i < instr_code_units; i++) { 150 os << " "; 151 } 152 return os.str(); 153 } 154 155 std::string Instruction::DumpString(const DexFile* file) const { 156 std::ostringstream os; 157 const char* opcode = kInstructionNames[Opcode()]; 158 switch (FormatOf(Opcode())) { 159 case k10x: os << opcode; break; 160 case k12x: os << StringPrintf("%s v%d, v%d", opcode, VRegA_12x(), VRegB_12x()); break; 161 case k11n: os << StringPrintf("%s v%d, #%+d", opcode, VRegA_11n(), VRegB_11n()); break; 162 case k11x: os << StringPrintf("%s v%d", opcode, VRegA_11x()); break; 163 case k10t: os << StringPrintf("%s %+d", opcode, VRegA_10t()); break; 164 case k20t: os << StringPrintf("%s %+d", opcode, VRegA_20t()); break; 165 case k22x: os << StringPrintf("%s v%d, v%d", opcode, VRegA_22x(), VRegB_22x()); break; 166 case k21t: os << StringPrintf("%s v%d, %+d", opcode, VRegA_21t(), VRegB_21t()); break; 167 case k21s: os << StringPrintf("%s v%d, #%+d", opcode, VRegA_21s(), VRegB_21s()); break; 168 case k21h: { 169 // op vAA, #+BBBB0000[00000000] 170 if (Opcode() == CONST_HIGH16) { 171 uint32_t value = VRegB_21h() << 16; 172 os << StringPrintf("%s v%d, #int %+d // 0x%x", opcode, VRegA_21h(), value, value); 173 } else { 174 uint64_t value = static_cast<uint64_t>(VRegB_21h()) << 48; 175 os << StringPrintf("%s v%d, #long %+" PRId64 " // 0x%" PRIx64, opcode, VRegA_21h(), 176 value, value); 177 } 178 } 179 break; 180 case k21c: { 181 switch (Opcode()) { 182 case CONST_STRING: 183 if (file != nullptr) { 184 uint32_t string_idx = VRegB_21c(); 185 if (string_idx < file->NumStringIds()) { 186 os << StringPrintf( 187 "const-string v%d, %s // string@%d", 188 VRegA_21c(), 189 PrintableString(file->StringDataByIdx(dex::StringIndex(string_idx))).c_str(), 190 string_idx); 191 } else { 192 os << StringPrintf("const-string v%d, <<invalid-string-idx-%d>> // string@%d", 193 VRegA_21c(), 194 string_idx, 195 string_idx); 196 } 197 break; 198 } 199 FALLTHROUGH_INTENDED; 200 case CHECK_CAST: 201 case CONST_CLASS: 202 case NEW_INSTANCE: 203 if (file != nullptr) { 204 dex::TypeIndex type_idx(VRegB_21c()); 205 os << opcode << " v" << static_cast<int>(VRegA_21c()) << ", " 206 << file->PrettyType(type_idx) << " // type@" << type_idx; 207 break; 208 } 209 FALLTHROUGH_INTENDED; 210 case SGET: 211 case SGET_WIDE: 212 case SGET_OBJECT: 213 case SGET_BOOLEAN: 214 case SGET_BYTE: 215 case SGET_CHAR: 216 case SGET_SHORT: 217 if (file != nullptr) { 218 uint32_t field_idx = VRegB_21c(); 219 os << opcode << " v" << static_cast<int>(VRegA_21c()) << ", " << file->PrettyField(field_idx, true) 220 << " // field@" << field_idx; 221 break; 222 } 223 FALLTHROUGH_INTENDED; 224 case SPUT: 225 case SPUT_WIDE: 226 case SPUT_OBJECT: 227 case SPUT_BOOLEAN: 228 case SPUT_BYTE: 229 case SPUT_CHAR: 230 case SPUT_SHORT: 231 if (file != nullptr) { 232 uint32_t field_idx = VRegB_21c(); 233 os << opcode << " v" << static_cast<int>(VRegA_21c()) << ", " << file->PrettyField(field_idx, true) 234 << " // field@" << field_idx; 235 break; 236 } 237 FALLTHROUGH_INTENDED; 238 default: 239 os << StringPrintf("%s v%d, thing@%d", opcode, VRegA_21c(), VRegB_21c()); 240 break; 241 } 242 break; 243 } 244 case k23x: os << StringPrintf("%s v%d, v%d, v%d", opcode, VRegA_23x(), VRegB_23x(), VRegC_23x()); break; 245 case k22b: os << StringPrintf("%s v%d, v%d, #%+d", opcode, VRegA_22b(), VRegB_22b(), VRegC_22b()); break; 246 case k22t: os << StringPrintf("%s v%d, v%d, %+d", opcode, VRegA_22t(), VRegB_22t(), VRegC_22t()); break; 247 case k22s: os << StringPrintf("%s v%d, v%d, #%+d", opcode, VRegA_22s(), VRegB_22s(), VRegC_22s()); break; 248 case k22c: { 249 switch (Opcode()) { 250 case IGET: 251 case IGET_WIDE: 252 case IGET_OBJECT: 253 case IGET_BOOLEAN: 254 case IGET_BYTE: 255 case IGET_CHAR: 256 case IGET_SHORT: 257 if (file != nullptr) { 258 uint32_t field_idx = VRegC_22c(); 259 os << opcode << " v" << static_cast<int>(VRegA_22c()) << ", v" << static_cast<int>(VRegB_22c()) << ", " 260 << file->PrettyField(field_idx, true) << " // field@" << field_idx; 261 break; 262 } 263 FALLTHROUGH_INTENDED; 264 case IGET_QUICK: 265 case IGET_OBJECT_QUICK: 266 if (file != nullptr) { 267 uint32_t field_idx = VRegC_22c(); 268 os << opcode << " v" << static_cast<int>(VRegA_22c()) << ", v" << static_cast<int>(VRegB_22c()) << ", " 269 << "// offset@" << field_idx; 270 break; 271 } 272 FALLTHROUGH_INTENDED; 273 case IPUT: 274 case IPUT_WIDE: 275 case IPUT_OBJECT: 276 case IPUT_BOOLEAN: 277 case IPUT_BYTE: 278 case IPUT_CHAR: 279 case IPUT_SHORT: 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 << file->PrettyField(field_idx, true) << " // field@" << field_idx; 284 break; 285 } 286 FALLTHROUGH_INTENDED; 287 case IPUT_QUICK: 288 case IPUT_OBJECT_QUICK: 289 if (file != nullptr) { 290 uint32_t field_idx = VRegC_22c(); 291 os << opcode << " v" << static_cast<int>(VRegA_22c()) << ", v" << static_cast<int>(VRegB_22c()) << ", " 292 << "// offset@" << field_idx; 293 break; 294 } 295 FALLTHROUGH_INTENDED; 296 case INSTANCE_OF: 297 if (file != nullptr) { 298 dex::TypeIndex type_idx(VRegC_22c()); 299 os << opcode << " v" << static_cast<int>(VRegA_22c()) << ", v" 300 << static_cast<int>(VRegB_22c()) << ", " << file->PrettyType(type_idx) 301 << " // type@" << type_idx.index_; 302 break; 303 } 304 FALLTHROUGH_INTENDED; 305 case NEW_ARRAY: 306 if (file != nullptr) { 307 dex::TypeIndex type_idx(VRegC_22c()); 308 os << opcode << " v" << static_cast<int>(VRegA_22c()) << ", v" 309 << static_cast<int>(VRegB_22c()) << ", " << file->PrettyType(type_idx) 310 << " // type@" << type_idx.index_; 311 break; 312 } 313 FALLTHROUGH_INTENDED; 314 default: 315 os << StringPrintf("%s v%d, v%d, thing@%d", opcode, VRegA_22c(), VRegB_22c(), VRegC_22c()); 316 break; 317 } 318 break; 319 } 320 case k32x: os << StringPrintf("%s v%d, v%d", opcode, VRegA_32x(), VRegB_32x()); break; 321 case k30t: os << StringPrintf("%s %+d", opcode, VRegA_30t()); break; 322 case k31t: os << StringPrintf("%s v%d, %+d", opcode, VRegA_31t(), VRegB_31t()); break; 323 case k31i: os << StringPrintf("%s v%d, #%+d", opcode, VRegA_31i(), VRegB_31i()); break; 324 case k31c: 325 if (Opcode() == CONST_STRING_JUMBO) { 326 uint32_t string_idx = VRegB_31c(); 327 if (file != nullptr) { 328 if (string_idx < file->NumStringIds()) { 329 os << StringPrintf( 330 "%s v%d, %s // string@%d", 331 opcode, 332 VRegA_31c(), 333 PrintableString(file->StringDataByIdx(dex::StringIndex(string_idx))).c_str(), 334 string_idx); 335 } else { 336 os << StringPrintf("%s v%d, <<invalid-string-idx-%d>> // string@%d", 337 opcode, 338 VRegA_31c(), 339 string_idx, 340 string_idx); 341 } 342 } else { 343 os << StringPrintf("%s v%d, string@%d", opcode, VRegA_31c(), string_idx); 344 } 345 } else { 346 os << StringPrintf("%s v%d, thing@%d", opcode, VRegA_31c(), VRegB_31c()); break; 347 } 348 break; 349 case k35c: { 350 uint32_t arg[kMaxVarArgRegs]; 351 GetVarArgs(arg); 352 switch (Opcode()) { 353 case FILLED_NEW_ARRAY: 354 { 355 const int32_t a = VRegA_35c(); 356 os << opcode << " {"; 357 for (int i = 0; i < a; ++i) { 358 if (i > 0) { 359 os << ", "; 360 } 361 os << "v" << arg[i]; 362 } 363 os << "}, type@" << VRegB_35c(); 364 } 365 break; 366 367 case INVOKE_VIRTUAL: 368 case INVOKE_SUPER: 369 case INVOKE_DIRECT: 370 case INVOKE_STATIC: 371 case INVOKE_INTERFACE: 372 if (file != nullptr) { 373 os << opcode << " {"; 374 uint32_t method_idx = VRegB_35c(); 375 for (size_t i = 0; i < VRegA_35c(); ++i) { 376 if (i != 0) { 377 os << ", "; 378 } 379 os << "v" << arg[i]; 380 } 381 os << "}, " << file->PrettyMethod(method_idx) << " // method@" << method_idx; 382 break; 383 } 384 FALLTHROUGH_INTENDED; 385 case INVOKE_VIRTUAL_QUICK: 386 if (file != nullptr) { 387 os << opcode << " {"; 388 uint32_t method_idx = VRegB_35c(); 389 for (size_t i = 0; i < VRegA_35c(); ++i) { 390 if (i != 0) { 391 os << ", "; 392 } 393 os << "v" << arg[i]; 394 } 395 os << "}, // vtable@" << method_idx; 396 break; 397 } 398 FALLTHROUGH_INTENDED; 399 case INVOKE_CUSTOM: 400 if (file != nullptr) { 401 os << opcode << " {"; 402 uint32_t call_site_idx = VRegB_35c(); 403 for (size_t i = 0; i < VRegA_35c(); ++i) { 404 if (i != 0) { 405 os << ", "; 406 } 407 os << "v" << arg[i]; 408 } 409 os << "}, // call_site@" << call_site_idx; 410 break; 411 } 412 FALLTHROUGH_INTENDED; 413 default: 414 os << opcode << " {v" << arg[0] << ", v" << arg[1] << ", v" << arg[2] 415 << ", v" << arg[3] << ", v" << arg[4] << "}, thing@" << VRegB_35c(); 416 break; 417 } 418 break; 419 } 420 case k3rc: { 421 uint16_t first_reg = VRegC_3rc(); 422 uint16_t last_reg = VRegC_3rc() + VRegA_3rc() - 1; 423 switch (Opcode()) { 424 case INVOKE_VIRTUAL_RANGE: 425 case INVOKE_SUPER_RANGE: 426 case INVOKE_DIRECT_RANGE: 427 case INVOKE_STATIC_RANGE: 428 case INVOKE_INTERFACE_RANGE: 429 if (file != nullptr) { 430 uint32_t method_idx = VRegB_3rc(); 431 os << StringPrintf("%s, {v%d .. v%d}, ", opcode, first_reg, last_reg) 432 << file->PrettyMethod(method_idx) << " // method@" << method_idx; 433 break; 434 } 435 FALLTHROUGH_INTENDED; 436 case INVOKE_VIRTUAL_RANGE_QUICK: 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 << "// vtable@" << method_idx; 441 break; 442 } 443 FALLTHROUGH_INTENDED; 444 case INVOKE_CUSTOM_RANGE: 445 if (file != nullptr) { 446 uint32_t call_site_idx = VRegB_3rc(); 447 os << StringPrintf("%s, {v%d .. v%d}, ", opcode, first_reg, last_reg) 448 << "// call_site@" << call_site_idx; 449 break; 450 } 451 FALLTHROUGH_INTENDED; 452 default: 453 os << StringPrintf("%s, {v%d .. v%d}, ", opcode, first_reg, last_reg) 454 << "thing@" << VRegB_3rc(); 455 break; 456 } 457 break; 458 } 459 case k45cc: { 460 uint32_t arg[kMaxVarArgRegs]; 461 GetVarArgs(arg); 462 uint32_t method_idx = VRegB_45cc(); 463 uint32_t proto_idx = VRegH_45cc(); 464 os << opcode << " {"; 465 for (int i = 0; i < VRegA_45cc(); ++i) { 466 if (i != 0) { 467 os << ", "; 468 } 469 os << "v" << arg[i]; 470 } 471 os << "}"; 472 if (file != nullptr) { 473 os << ", " << file->PrettyMethod(method_idx) << ", " << file->GetShorty(proto_idx) 474 << " // "; 475 } else { 476 os << ", "; 477 } 478 os << "method@" << method_idx << ", proto@" << proto_idx; 479 break; 480 } 481 case k4rcc: 482 switch (Opcode()) { 483 case INVOKE_POLYMORPHIC_RANGE: { 484 if (file != nullptr) { 485 uint32_t method_idx = VRegB_4rcc(); 486 uint32_t proto_idx = VRegH_4rcc(); 487 os << opcode << ", {v" << VRegC_4rcc() << " .. v" << (VRegC_4rcc() + VRegA_4rcc()) 488 << "}, " << file->PrettyMethod(method_idx) << ", " << file->GetShorty(proto_idx) 489 << " // method@" << method_idx << ", proto@" << proto_idx; 490 break; 491 } 492 } 493 FALLTHROUGH_INTENDED; 494 default: { 495 uint32_t method_idx = VRegB_4rcc(); 496 uint32_t proto_idx = VRegH_4rcc(); 497 os << opcode << ", {v" << VRegC_4rcc() << " .. v" << (VRegC_4rcc() + VRegA_4rcc()) 498 << "}, method@" << method_idx << ", proto@" << proto_idx; 499 } 500 } 501 break; 502 case k51l: os << StringPrintf("%s v%d, #%+" PRId64, opcode, VRegA_51l(), VRegB_51l()); break; 503 } 504 return os.str(); 505 } 506 507 // Add some checks that ensure the flags make sense. We need a subclass to be in the context of 508 // Instruction. Otherwise the flags from the instruction list don't work. 509 struct InstructionStaticAsserts : private Instruction { 510 #define IMPLIES(a, b) (!(a) || (b)) 511 512 #define VAR_ARGS_CHECK(o, c, pname, f, i, a, e, v) \ 513 static_assert(IMPLIES((f) == k35c || (f) == k45cc, \ 514 ((v) & (kVerifyVarArg | kVerifyVarArgNonZero)) != 0), \ 515 "Missing var-arg verification"); 516 #include "dex_instruction_list.h" 517 DEX_INSTRUCTION_LIST(VAR_ARGS_CHECK) 518 #undef DEX_INSTRUCTION_LIST 519 #undef VAR_ARGS_CHECK 520 521 #define VAR_ARGS_RANGE_CHECK(o, c, pname, f, i, a, e, v) \ 522 static_assert(IMPLIES((f) == k3rc || (f) == k4rcc, \ 523 ((v) & (kVerifyVarArgRange | kVerifyVarArgRangeNonZero)) != 0), \ 524 "Missing var-arg verification"); 525 #include "dex_instruction_list.h" 526 DEX_INSTRUCTION_LIST(VAR_ARGS_RANGE_CHECK) 527 #undef DEX_INSTRUCTION_LIST 528 #undef VAR_ARGS_RANGE_CHECK 529 530 #define EXPERIMENTAL_CHECK(o, c, pname, f, i, a, e, v) \ 531 static_assert(kHaveExperimentalInstructions || (((a) & kExperimental) == 0), \ 532 "Unexpected experimental instruction."); 533 #include "dex_instruction_list.h" 534 DEX_INSTRUCTION_LIST(EXPERIMENTAL_CHECK) 535 #undef DEX_INSTRUCTION_LIST 536 #undef EXPERIMENTAL_CHECK 537 }; 538 539 std::ostream& operator<<(std::ostream& os, const Instruction::Code& code) { 540 return os << Instruction::Name(code); 541 } 542 543 } // namespace art 544