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