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 |