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