| OLD | NEW |
| 1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include <assert.h> | 5 #include <assert.h> |
| 6 #include <stdarg.h> | 6 #include <stdarg.h> |
| 7 #include <stdio.h> | 7 #include <stdio.h> |
| 8 | 8 |
| 9 #include "src/v8.h" | 9 #include "src/v8.h" |
| 10 | 10 |
| (...skipping 228 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 239 } | 239 } |
| 240 } | 240 } |
| 241 | 241 |
| 242 | 242 |
| 243 // The IA32 disassembler implementation. | 243 // The IA32 disassembler implementation. |
| 244 class DisassemblerIA32 { | 244 class DisassemblerIA32 { |
| 245 public: | 245 public: |
| 246 DisassemblerIA32(const NameConverter& converter, | 246 DisassemblerIA32(const NameConverter& converter, |
| 247 bool abort_on_unimplemented = true) | 247 bool abort_on_unimplemented = true) |
| 248 : converter_(converter), | 248 : converter_(converter), |
| 249 vex_byte0_(0), |
| 250 vex_byte1_(0), |
| 251 vex_byte2_(0), |
| 249 instruction_table_(InstructionTable::get_instance()), | 252 instruction_table_(InstructionTable::get_instance()), |
| 250 tmp_buffer_pos_(0), | 253 tmp_buffer_pos_(0), |
| 251 abort_on_unimplemented_(abort_on_unimplemented) { | 254 abort_on_unimplemented_(abort_on_unimplemented) { |
| 252 tmp_buffer_[0] = '\0'; | 255 tmp_buffer_[0] = '\0'; |
| 253 } | 256 } |
| 254 | 257 |
| 255 virtual ~DisassemblerIA32() {} | 258 virtual ~DisassemblerIA32() {} |
| 256 | 259 |
| 257 // Writes one disassembled instruction into 'buffer' (0-terminated). | 260 // Writes one disassembled instruction into 'buffer' (0-terminated). |
| 258 // Returns the length of the disassembled machine instruction in bytes. | 261 // Returns the length of the disassembled machine instruction in bytes. |
| 259 int InstructionDecode(v8::internal::Vector<char> buffer, byte* instruction); | 262 int InstructionDecode(v8::internal::Vector<char> buffer, byte* instruction); |
| 260 | 263 |
| 261 private: | 264 private: |
| 262 const NameConverter& converter_; | 265 const NameConverter& converter_; |
| 266 byte vex_byte0_; // 0xc4 or 0xc5 |
| 267 byte vex_byte1_; |
| 268 byte vex_byte2_; // only for 3 bytes vex prefix |
| 263 InstructionTable* instruction_table_; | 269 InstructionTable* instruction_table_; |
| 264 v8::internal::EmbeddedVector<char, 128> tmp_buffer_; | 270 v8::internal::EmbeddedVector<char, 128> tmp_buffer_; |
| 265 unsigned int tmp_buffer_pos_; | 271 unsigned int tmp_buffer_pos_; |
| 266 bool abort_on_unimplemented_; | 272 bool abort_on_unimplemented_; |
| 267 | 273 |
| 268 enum { | 274 enum { |
| 269 eax = 0, | 275 eax = 0, |
| 270 ecx = 1, | 276 ecx = 1, |
| 271 edx = 2, | 277 edx = 2, |
| 272 ebx = 3, | 278 ebx = 3, |
| 273 esp = 4, | 279 esp = 4, |
| 274 ebp = 5, | 280 ebp = 5, |
| 275 esi = 6, | 281 esi = 6, |
| 276 edi = 7 | 282 edi = 7 |
| 277 }; | 283 }; |
| 278 | 284 |
| 279 | 285 |
| 280 enum ShiftOpcodeExtension { | 286 enum ShiftOpcodeExtension { |
| 281 kROL = 0, | 287 kROL = 0, |
| 282 kROR = 1, | 288 kROR = 1, |
| 283 kRCL = 2, | 289 kRCL = 2, |
| 284 kRCR = 3, | 290 kRCR = 3, |
| 285 kSHL = 4, | 291 kSHL = 4, |
| 286 KSHR = 5, | 292 KSHR = 5, |
| 287 kSAR = 7 | 293 kSAR = 7 |
| 288 }; | 294 }; |
| 289 | 295 |
| 296 bool vex_128() { |
| 297 DCHECK(vex_byte0_ == 0xc4 || vex_byte0_ == 0xc5); |
| 298 byte checked = vex_byte0_ == 0xc4 ? vex_byte2_ : vex_byte1_; |
| 299 return (checked & 4) != 1; |
| 300 } |
| 301 |
| 302 bool vex_66() { |
| 303 DCHECK(vex_byte0_ == 0xc4 || vex_byte0_ == 0xc5); |
| 304 byte checked = vex_byte0_ == 0xc4 ? vex_byte2_ : vex_byte1_; |
| 305 return (checked & 3) == 1; |
| 306 } |
| 307 |
| 308 bool vex_f3() { |
| 309 DCHECK(vex_byte0_ == 0xc4 || vex_byte0_ == 0xc5); |
| 310 byte checked = vex_byte0_ == 0xc4 ? vex_byte2_ : vex_byte1_; |
| 311 return (checked & 3) == 2; |
| 312 } |
| 313 |
| 314 bool vex_f2() { |
| 315 DCHECK(vex_byte0_ == 0xc4 || vex_byte0_ == 0xc5); |
| 316 byte checked = vex_byte0_ == 0xc4 ? vex_byte2_ : vex_byte1_; |
| 317 return (checked & 3) == 3; |
| 318 } |
| 319 |
| 320 bool vex_w() { |
| 321 if (vex_byte0_ == 0xc5) return false; |
| 322 return (vex_byte2_ & 0x80) == 1; |
| 323 } |
| 324 |
| 325 bool vex_0f() { |
| 326 if (vex_byte0_ == 0xc5) return true; |
| 327 return (vex_byte1_ & 3) == 1; |
| 328 } |
| 329 |
| 330 bool vex_0f38() { |
| 331 if (vex_byte0_ == 0xc5) return false; |
| 332 return (vex_byte1_ & 3) == 2; |
| 333 } |
| 334 |
| 335 bool vex_0f3a() { |
| 336 if (vex_byte0_ == 0xc5) return false; |
| 337 return (vex_byte1_ & 3) == 3; |
| 338 } |
| 339 |
| 340 int vex_vreg() { |
| 341 DCHECK(vex_byte0_ == 0xc4 || vex_byte0_ == 0xc5); |
| 342 byte checked = vex_byte0_ == 0xc4 ? vex_byte2_ : vex_byte1_; |
| 343 return ~(checked >> 3) & 0xf; |
| 344 } |
| 345 |
| 346 char float_size_code() { return "sd"[vex_w()]; } |
| 290 | 347 |
| 291 const char* NameOfCPURegister(int reg) const { | 348 const char* NameOfCPURegister(int reg) const { |
| 292 return converter_.NameOfCPURegister(reg); | 349 return converter_.NameOfCPURegister(reg); |
| 293 } | 350 } |
| 294 | 351 |
| 295 | 352 |
| 296 const char* NameOfByteCPURegister(int reg) const { | 353 const char* NameOfByteCPURegister(int reg) const { |
| 297 return converter_.NameOfByteCPURegister(reg); | 354 return converter_.NameOfByteCPURegister(reg); |
| 298 } | 355 } |
| 299 | 356 |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 333 int F7Instruction(byte* data); | 390 int F7Instruction(byte* data); |
| 334 int D1D3C1Instruction(byte* data); | 391 int D1D3C1Instruction(byte* data); |
| 335 int JumpShort(byte* data); | 392 int JumpShort(byte* data); |
| 336 int JumpConditional(byte* data, const char* comment); | 393 int JumpConditional(byte* data, const char* comment); |
| 337 int JumpConditionalShort(byte* data, const char* comment); | 394 int JumpConditionalShort(byte* data, const char* comment); |
| 338 int SetCC(byte* data); | 395 int SetCC(byte* data); |
| 339 int CMov(byte* data); | 396 int CMov(byte* data); |
| 340 int FPUInstruction(byte* data); | 397 int FPUInstruction(byte* data); |
| 341 int MemoryFPUInstruction(int escape_opcode, int regop, byte* modrm_start); | 398 int MemoryFPUInstruction(int escape_opcode, int regop, byte* modrm_start); |
| 342 int RegisterFPUInstruction(int escape_opcode, byte modrm_byte); | 399 int RegisterFPUInstruction(int escape_opcode, byte modrm_byte); |
| 400 int AVXInstruction(byte* data); |
| 343 void AppendToBuffer(const char* format, ...); | 401 void AppendToBuffer(const char* format, ...); |
| 344 | 402 |
| 345 | 403 |
| 346 void UnimplementedInstruction() { | 404 void UnimplementedInstruction() { |
| 347 if (abort_on_unimplemented_) { | 405 if (abort_on_unimplemented_) { |
| 348 UNIMPLEMENTED(); | 406 UNIMPLEMENTED(); |
| 349 } else { | 407 } else { |
| 350 AppendToBuffer("'Unimplemented Instruction'"); | 408 AppendToBuffer("'Unimplemented Instruction'"); |
| 351 } | 409 } |
| 352 } | 410 } |
| (...skipping 319 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 672 // Returns number of bytes used, including *data. | 730 // Returns number of bytes used, including *data. |
| 673 int DisassemblerIA32::CMov(byte* data) { | 731 int DisassemblerIA32::CMov(byte* data) { |
| 674 DCHECK_EQ(0x0F, *data); | 732 DCHECK_EQ(0x0F, *data); |
| 675 byte cond = *(data + 1) & 0x0F; | 733 byte cond = *(data + 1) & 0x0F; |
| 676 const char* mnem = conditional_move_mnem[cond]; | 734 const char* mnem = conditional_move_mnem[cond]; |
| 677 int op_size = PrintOperands(mnem, REG_OPER_OP_ORDER, data + 2); | 735 int op_size = PrintOperands(mnem, REG_OPER_OP_ORDER, data + 2); |
| 678 return 2 + op_size; // includes 0x0F | 736 return 2 + op_size; // includes 0x0F |
| 679 } | 737 } |
| 680 | 738 |
| 681 | 739 |
| 740 int DisassemblerIA32::AVXInstruction(byte* data) { |
| 741 byte opcode = *data; |
| 742 byte* current = data + 1; |
| 743 if (vex_f2() && vex_0f()) { |
| 744 int mod, regop, rm, vvvv = vex_vreg(); |
| 745 get_modrm(*current, &mod, ®op, &rm); |
| 746 switch (opcode) { |
| 747 case 0x58: |
| 748 AppendToBuffer("vaddsd %s,%s,", NameOfXMMRegister(regop), |
| 749 NameOfXMMRegister(vvvv)); |
| 750 current += PrintRightXMMOperand(current); |
| 751 break; |
| 752 case 0x59: |
| 753 AppendToBuffer("vmulsd %s,%s,", NameOfXMMRegister(regop), |
| 754 NameOfXMMRegister(vvvv)); |
| 755 current += PrintRightXMMOperand(current); |
| 756 break; |
| 757 case 0x5c: |
| 758 AppendToBuffer("vsubsd %s,%s,", NameOfXMMRegister(regop), |
| 759 NameOfXMMRegister(vvvv)); |
| 760 current += PrintRightXMMOperand(current); |
| 761 break; |
| 762 case 0x5e: |
| 763 AppendToBuffer("vdivsd %s,%s,", NameOfXMMRegister(regop), |
| 764 NameOfXMMRegister(vvvv)); |
| 765 current += PrintRightXMMOperand(current); |
| 766 break; |
| 767 default: |
| 768 UnimplementedInstruction(); |
| 769 } |
| 770 } else { |
| 771 UnimplementedInstruction(); |
| 772 } |
| 773 |
| 774 return static_cast<int>(current - data); |
| 775 } |
| 776 |
| 777 |
| 682 // Returns number of bytes used, including *data. | 778 // Returns number of bytes used, including *data. |
| 683 int DisassemblerIA32::FPUInstruction(byte* data) { | 779 int DisassemblerIA32::FPUInstruction(byte* data) { |
| 684 byte escape_opcode = *data; | 780 byte escape_opcode = *data; |
| 685 DCHECK_EQ(0xD8, escape_opcode & 0xF8); | 781 DCHECK_EQ(0xD8, escape_opcode & 0xF8); |
| 686 byte modrm_byte = *(data+1); | 782 byte modrm_byte = *(data+1); |
| 687 | 783 |
| 688 if (modrm_byte >= 0xC0) { | 784 if (modrm_byte >= 0xC0) { |
| 689 return RegisterFPUInstruction(escape_opcode, modrm_byte); | 785 return RegisterFPUInstruction(escape_opcode, modrm_byte); |
| 690 } else { | 786 } else { |
| 691 return MemoryFPUInstruction(escape_opcode, modrm_byte, data+1); | 787 return MemoryFPUInstruction(escape_opcode, modrm_byte, data+1); |
| (...skipping 204 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 896 byte* data = instr; | 992 byte* data = instr; |
| 897 // Check for hints. | 993 // Check for hints. |
| 898 const char* branch_hint = NULL; | 994 const char* branch_hint = NULL; |
| 899 // We use these two prefixes only with branch prediction | 995 // We use these two prefixes only with branch prediction |
| 900 if (*data == 0x3E /*ds*/) { | 996 if (*data == 0x3E /*ds*/) { |
| 901 branch_hint = "predicted taken"; | 997 branch_hint = "predicted taken"; |
| 902 data++; | 998 data++; |
| 903 } else if (*data == 0x2E /*cs*/) { | 999 } else if (*data == 0x2E /*cs*/) { |
| 904 branch_hint = "predicted not taken"; | 1000 branch_hint = "predicted not taken"; |
| 905 data++; | 1001 data++; |
| 1002 } else if (*data == 0xC4 && *(data + 1) >= 0xc0) { |
| 1003 vex_byte0_ = *data; |
| 1004 vex_byte1_ = *(data + 1); |
| 1005 vex_byte2_ = *(data + 2); |
| 1006 data += 3; |
| 1007 } else if (*data == 0xC5 && *(data + 1) >= 0xc0) { |
| 1008 vex_byte0_ = *data; |
| 1009 vex_byte1_ = *(data + 1); |
| 1010 data += 2; |
| 906 } | 1011 } |
| 1012 |
| 907 bool processed = true; // Will be set to false if the current instruction | 1013 bool processed = true; // Will be set to false if the current instruction |
| 908 // is not in 'instructions' table. | 1014 // is not in 'instructions' table. |
| 909 const InstructionDesc& idesc = instruction_table_->Get(*data); | 1015 // Decode AVX instructions. |
| 910 switch (idesc.type) { | 1016 if (vex_byte0_ != 0) { |
| 911 case ZERO_OPERANDS_INSTR: | 1017 data += AVXInstruction(data); |
| 912 AppendToBuffer(idesc.mnem); | 1018 } else { |
| 913 data++; | 1019 const InstructionDesc& idesc = instruction_table_->Get(*data); |
| 914 break; | 1020 switch (idesc.type) { |
| 1021 case ZERO_OPERANDS_INSTR: |
| 1022 AppendToBuffer(idesc.mnem); |
| 1023 data++; |
| 1024 break; |
| 915 | 1025 |
| 916 case TWO_OPERANDS_INSTR: | 1026 case TWO_OPERANDS_INSTR: |
| 917 data++; | 1027 data++; |
| 918 data += PrintOperands(idesc.mnem, idesc.op_order_, data); | 1028 data += PrintOperands(idesc.mnem, idesc.op_order_, data); |
| 919 break; | 1029 break; |
| 920 | 1030 |
| 921 case JUMP_CONDITIONAL_SHORT_INSTR: | 1031 case JUMP_CONDITIONAL_SHORT_INSTR: |
| 922 data += JumpConditionalShort(data, branch_hint); | 1032 data += JumpConditionalShort(data, branch_hint); |
| 923 break; | 1033 break; |
| 924 | 1034 |
| 925 case REGISTER_INSTR: | 1035 case REGISTER_INSTR: |
| 926 AppendToBuffer("%s %s", idesc.mnem, NameOfCPURegister(*data & 0x07)); | 1036 AppendToBuffer("%s %s", idesc.mnem, NameOfCPURegister(*data & 0x07)); |
| 927 data++; | 1037 data++; |
| 928 break; | 1038 break; |
| 929 | 1039 |
| 930 case MOVE_REG_INSTR: { | 1040 case MOVE_REG_INSTR: { |
| 931 byte* addr = reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data+1)); | 1041 byte* addr = |
| 932 AppendToBuffer("mov %s,%s", | 1042 reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data + 1)); |
| 933 NameOfCPURegister(*data & 0x07), | 1043 AppendToBuffer("mov %s,%s", NameOfCPURegister(*data & 0x07), |
| 934 NameOfAddress(addr)); | 1044 NameOfAddress(addr)); |
| 935 data += 5; | 1045 data += 5; |
| 936 break; | 1046 break; |
| 1047 } |
| 1048 |
| 1049 case CALL_JUMP_INSTR: { |
| 1050 byte* addr = data + *reinterpret_cast<int32_t*>(data + 1) + 5; |
| 1051 AppendToBuffer("%s %s", idesc.mnem, NameOfAddress(addr)); |
| 1052 data += 5; |
| 1053 break; |
| 1054 } |
| 1055 |
| 1056 case SHORT_IMMEDIATE_INSTR: { |
| 1057 byte* addr = |
| 1058 reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data + 1)); |
| 1059 AppendToBuffer("%s eax,%s", idesc.mnem, NameOfAddress(addr)); |
| 1060 data += 5; |
| 1061 break; |
| 1062 } |
| 1063 |
| 1064 case BYTE_IMMEDIATE_INSTR: { |
| 1065 AppendToBuffer("%s al,0x%x", idesc.mnem, data[1]); |
| 1066 data += 2; |
| 1067 break; |
| 1068 } |
| 1069 |
| 1070 case NO_INSTR: |
| 1071 processed = false; |
| 1072 break; |
| 1073 |
| 1074 default: |
| 1075 UNIMPLEMENTED(); // This type is not implemented. |
| 937 } | 1076 } |
| 938 | |
| 939 case CALL_JUMP_INSTR: { | |
| 940 byte* addr = data + *reinterpret_cast<int32_t*>(data+1) + 5; | |
| 941 AppendToBuffer("%s %s", idesc.mnem, NameOfAddress(addr)); | |
| 942 data += 5; | |
| 943 break; | |
| 944 } | |
| 945 | |
| 946 case SHORT_IMMEDIATE_INSTR: { | |
| 947 byte* addr = reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data+1)); | |
| 948 AppendToBuffer("%s eax,%s", idesc.mnem, NameOfAddress(addr)); | |
| 949 data += 5; | |
| 950 break; | |
| 951 } | |
| 952 | |
| 953 case BYTE_IMMEDIATE_INSTR: { | |
| 954 AppendToBuffer("%s al,0x%x", idesc.mnem, data[1]); | |
| 955 data += 2; | |
| 956 break; | |
| 957 } | |
| 958 | |
| 959 case NO_INSTR: | |
| 960 processed = false; | |
| 961 break; | |
| 962 | |
| 963 default: | |
| 964 UNIMPLEMENTED(); // This type is not implemented. | |
| 965 } | 1077 } |
| 966 //---------------------------- | 1078 //---------------------------- |
| 967 if (!processed) { | 1079 if (!processed) { |
| 968 switch (*data) { | 1080 switch (*data) { |
| 969 case 0xC2: | 1081 case 0xC2: |
| 970 AppendToBuffer("ret 0x%x", *reinterpret_cast<uint16_t*>(data+1)); | 1082 AppendToBuffer("ret 0x%x", *reinterpret_cast<uint16_t*>(data+1)); |
| 971 data += 3; | 1083 data += 3; |
| 972 break; | 1084 break; |
| 973 | 1085 |
| 974 case 0x6B: { | 1086 case 0x6B: { |
| (...skipping 804 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1779 fprintf(f, " "); | 1891 fprintf(f, " "); |
| 1780 } | 1892 } |
| 1781 fprintf(f, " %s\n", buffer.start()); | 1893 fprintf(f, " %s\n", buffer.start()); |
| 1782 } | 1894 } |
| 1783 } | 1895 } |
| 1784 | 1896 |
| 1785 | 1897 |
| 1786 } // namespace disasm | 1898 } // namespace disasm |
| 1787 | 1899 |
| 1788 #endif // V8_TARGET_ARCH_IA32 | 1900 #endif // V8_TARGET_ARCH_IA32 |
| OLD | NEW |