| OLD | NEW |
| 1 // Copyright 2009 the V8 project authors. All rights reserved. | 1 // Copyright 2009 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 235 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 246 assert(id->type == NO_INSTR); // Information already entered | 246 assert(id->type == NO_INSTR); // Information already entered |
| 247 id->mnem = NULL; // Computed depending on condition code. | 247 id->mnem = NULL; // Computed depending on condition code. |
| 248 id->type = JUMP_CONDITIONAL_SHORT_INSTR; | 248 id->type = JUMP_CONDITIONAL_SHORT_INSTR; |
| 249 } | 249 } |
| 250 } | 250 } |
| 251 | 251 |
| 252 | 252 |
| 253 static InstructionTable instruction_table; | 253 static InstructionTable instruction_table; |
| 254 | 254 |
| 255 | 255 |
| 256 // The X64 disassembler implementation. | 256 //------------------------------------------------------------------------------ |
| 257 // DisassemblerX64 implementation. |
| 258 |
| 257 enum UnimplementedOpcodeAction { | 259 enum UnimplementedOpcodeAction { |
| 258 CONTINUE_ON_UNIMPLEMENTED_OPCODE, | 260 CONTINUE_ON_UNIMPLEMENTED_OPCODE, |
| 259 ABORT_ON_UNIMPLEMENTED_OPCODE | 261 ABORT_ON_UNIMPLEMENTED_OPCODE |
| 260 }; | 262 }; |
| 261 | 263 |
| 262 | 264 // A new DisassemblerX64 object is created to disassemble each instruction. |
| 265 // The object can only disassemble a single instruction. |
| 263 class DisassemblerX64 { | 266 class DisassemblerX64 { |
| 264 public: | 267 public: |
| 265 DisassemblerX64(const NameConverter& converter, | 268 DisassemblerX64(const NameConverter& converter, |
| 266 UnimplementedOpcodeAction unimplemented_action = | 269 UnimplementedOpcodeAction unimplemented_action = |
| 267 ABORT_ON_UNIMPLEMENTED_OPCODE) | 270 ABORT_ON_UNIMPLEMENTED_OPCODE) |
| 268 : converter_(converter), | 271 : converter_(converter), |
| 269 tmp_buffer_pos_(0), | 272 tmp_buffer_pos_(0), |
| 270 abort_on_unimplemented_( | 273 abort_on_unimplemented_( |
| 271 unimplemented_action == ABORT_ON_UNIMPLEMENTED_OPCODE), | 274 unimplemented_action == ABORT_ON_UNIMPLEMENTED_OPCODE), |
| 272 rex_(0), | 275 rex_(0), |
| 273 operand_size_(0), | 276 operand_size_(0), |
| 277 group_1_prefix_(0), |
| 274 byte_size_operand_(false) { | 278 byte_size_operand_(false) { |
| 275 tmp_buffer_[0] = '\0'; | 279 tmp_buffer_[0] = '\0'; |
| 276 } | 280 } |
| 277 | 281 |
| 278 virtual ~DisassemblerX64() { | 282 virtual ~DisassemblerX64() { |
| 279 } | 283 } |
| 280 | 284 |
| 281 // Writes one disassembled instruction into 'buffer' (0-terminated). | 285 // Writes one disassembled instruction into 'buffer' (0-terminated). |
| 282 // Returns the length of the disassembled machine instruction in bytes. | 286 // Returns the length of the disassembled machine instruction in bytes. |
| 283 int InstructionDecode(v8::internal::Vector<char> buffer, byte* instruction); | 287 int InstructionDecode(v8::internal::Vector<char> buffer, byte* instruction); |
| 284 | 288 |
| 285 private: | 289 private: |
| 286 enum OperandSize { | 290 enum OperandSize { |
| 287 BYTE_SIZE = 0, | 291 BYTE_SIZE = 0, |
| 288 WORD_SIZE = 1, | 292 WORD_SIZE = 1, |
| 289 DOUBLEWORD_SIZE = 2, | 293 DOUBLEWORD_SIZE = 2, |
| 290 QUADWORD_SIZE = 3 | 294 QUADWORD_SIZE = 3 |
| 291 }; | 295 }; |
| 292 | 296 |
| 293 const NameConverter& converter_; | 297 const NameConverter& converter_; |
| 294 v8::internal::EmbeddedVector<char, 128> tmp_buffer_; | 298 v8::internal::EmbeddedVector<char, 128> tmp_buffer_; |
| 295 unsigned int tmp_buffer_pos_; | 299 unsigned int tmp_buffer_pos_; |
| 296 bool abort_on_unimplemented_; | 300 bool abort_on_unimplemented_; |
| 297 // Prefixes parsed | 301 // Prefixes parsed |
| 298 byte rex_; | 302 byte rex_; |
| 299 byte operand_size_; | 303 byte operand_size_; // 0x66 or (if no group 3 prefix is present) 0x0. |
| 304 byte group_1_prefix_; // 0xF2, 0xF3, or (if no group 1 prefix is present) 0. |
| 300 // Byte size operand override. | 305 // Byte size operand override. |
| 301 bool byte_size_operand_; | 306 bool byte_size_operand_; |
| 302 | 307 |
| 303 void setOperandSizePrefix(byte prefix) { | |
| 304 ASSERT_EQ(0x66, prefix); | |
| 305 operand_size_ = prefix; | |
| 306 } | |
| 307 | |
| 308 void setRex(byte rex) { | 308 void setRex(byte rex) { |
| 309 ASSERT_EQ(0x40, rex & 0xF0); | 309 ASSERT_EQ(0x40, rex & 0xF0); |
| 310 rex_ = rex; | 310 rex_ = rex; |
| 311 } | 311 } |
| 312 | 312 |
| 313 bool rex() { return rex_ != 0; } | 313 bool rex() { return rex_ != 0; } |
| 314 | 314 |
| 315 bool rex_b() { return (rex_ & 0x01) != 0; } | 315 bool rex_b() { return (rex_ & 0x01) != 0; } |
| 316 | 316 |
| 317 // Actual number of base register given the low bits and the rex.b state. | 317 // Actual number of base register given the low bits and the rex.b state. |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 373 | 373 |
| 374 int PrintRightOperandHelper(byte* modrmp, | 374 int PrintRightOperandHelper(byte* modrmp, |
| 375 RegisterNameMapping register_name); | 375 RegisterNameMapping register_name); |
| 376 int PrintRightOperand(byte* modrmp); | 376 int PrintRightOperand(byte* modrmp); |
| 377 int PrintRightByteOperand(byte* modrmp); | 377 int PrintRightByteOperand(byte* modrmp); |
| 378 int PrintOperands(const char* mnem, | 378 int PrintOperands(const char* mnem, |
| 379 OperandType op_order, | 379 OperandType op_order, |
| 380 byte* data); | 380 byte* data); |
| 381 int PrintImmediate(byte* data, OperandSize size); | 381 int PrintImmediate(byte* data, OperandSize size); |
| 382 int PrintImmediateOp(byte* data); | 382 int PrintImmediateOp(byte* data); |
| 383 const char* TwoByteMnemonic(byte opcode); |
| 384 int TwoByteOpcodeInstruction(byte* data); |
| 383 int F7Instruction(byte* data); | 385 int F7Instruction(byte* data); |
| 384 int ShiftInstruction(byte* data); | 386 int ShiftInstruction(byte* data); |
| 385 int JumpShort(byte* data); | 387 int JumpShort(byte* data); |
| 386 int JumpConditional(byte* data); | 388 int JumpConditional(byte* data); |
| 387 int JumpConditionalShort(byte* data); | 389 int JumpConditionalShort(byte* data); |
| 388 int SetCC(byte* data); | 390 int SetCC(byte* data); |
| 389 int FPUInstruction(byte* data); | 391 int FPUInstruction(byte* data); |
| 390 void AppendToBuffer(const char* format, ...); | 392 void AppendToBuffer(const char* format, ...); |
| 391 | 393 |
| 392 void UnimplementedInstruction() { | 394 void UnimplementedInstruction() { |
| 393 if (abort_on_unimplemented_) { | 395 if (abort_on_unimplemented_) { |
| 394 UNIMPLEMENTED(); | 396 CHECK(false); |
| 395 } else { | 397 } else { |
| 396 AppendToBuffer("'Unimplemented Instruction'"); | 398 AppendToBuffer("'Unimplemented Instruction'"); |
| 397 } | 399 } |
| 398 } | 400 } |
| 399 }; | 401 }; |
| 400 | 402 |
| 401 | 403 |
| 402 void DisassemblerX64::AppendToBuffer(const char* format, ...) { | 404 void DisassemblerX64::AppendToBuffer(const char* format, ...) { |
| 403 v8::internal::Vector<char> buf = tmp_buffer_ + tmp_buffer_pos_; | 405 v8::internal::Vector<char> buf = tmp_buffer_ + tmp_buffer_pos_; |
| 404 va_list args; | 406 va_list args; |
| (...skipping 524 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 929 return 2; | 931 return 2; |
| 930 } else if (b1 == 0xDA && b2 == 0xE9) { | 932 } else if (b1 == 0xDA && b2 == 0xE9) { |
| 931 const char* mnem = "fucompp"; | 933 const char* mnem = "fucompp"; |
| 932 AppendToBuffer("%s", mnem); | 934 AppendToBuffer("%s", mnem); |
| 933 return 2; | 935 return 2; |
| 934 } | 936 } |
| 935 AppendToBuffer("Unknown FP instruction"); | 937 AppendToBuffer("Unknown FP instruction"); |
| 936 return 2; | 938 return 2; |
| 937 } | 939 } |
| 938 | 940 |
| 939 // Mnemonics for instructions 0xF0 byte. | 941 |
| 942 // Handle all two-byte opcodes, which start with 0x0F. |
| 943 // These instructions may be affected by an 0x66, 0xF2, or 0xF3 prefix. |
| 944 // We do not use any three-byte opcodes, which start with 0x0F38 or 0x0F3A. |
| 945 int DisassemblerX64::TwoByteOpcodeInstruction(byte* data) { |
| 946 byte opcode = *(data + 1); |
| 947 byte* current = data + 2; |
| 948 // At return, "current" points to the start of the next instruction. |
| 949 const char* mnemonic = TwoByteMnemonic(opcode); |
| 950 if (opcode == 0x1F) { |
| 951 // NOP |
| 952 int mod, regop, rm; |
| 953 get_modrm(*current, &mod, ®op, &rm); |
| 954 current++; |
| 955 if (regop == 4) { // SIB byte present. |
| 956 current++; |
| 957 } |
| 958 if (mod == 1) { // Byte displacement. |
| 959 current += 1; |
| 960 } else if (mod == 2) { // 32-bit displacement. |
| 961 current += 4; |
| 962 } // else no immediate displacement. |
| 963 AppendToBuffer("nop"); |
| 964 |
| 965 } else if (opcode == 0xA2 || opcode == 0x31) { |
| 966 // RDTSC or CPUID |
| 967 AppendToBuffer("%s", mnemonic); |
| 968 |
| 969 } else if ((opcode & 0xF0) == 0x80) { |
| 970 // Jcc: Conditional jump (branch). |
| 971 current = data + JumpConditional(data); |
| 972 |
| 973 } else if (opcode == 0xBE || opcode == 0xBF || opcode == 0xB6 || |
| 974 opcode == 0xB7 || opcode == 0xAF) { |
| 975 // Size-extending moves, IMUL. |
| 976 current += PrintOperands(mnemonic, REG_OPER_OP_ORDER, current); |
| 977 |
| 978 } else if ((opcode & 0xF0) == 0x90) { |
| 979 // SETcc: Set byte on condition. Needs pointer to beginning of instruction. |
| 980 current = data + SetCC(data); |
| 981 |
| 982 } else if (opcode == 0xAB || opcode == 0xA5 || opcode == 0xAD) { |
| 983 // SHLD, SHRD (double-precision shift), BTS (bit set). |
| 984 AppendToBuffer("%s ", mnemonic); |
| 985 int mod, regop, rm; |
| 986 get_modrm(*current, &mod, ®op, &rm); |
| 987 current += PrintRightOperand(current); |
| 988 if (opcode == 0xAB) { |
| 989 AppendToBuffer(",%s", NameOfCPURegister(regop)); |
| 990 } else { |
| 991 AppendToBuffer(",%s,cl", NameOfCPURegister(regop)); |
| 992 } |
| 993 } else if (group_1_prefix_ == 0xF2) { |
| 994 // Beginning of instructions with prefix 0xF2. |
| 995 |
| 996 if (opcode == 0x11 || opcode == 0x10) { |
| 997 // MOVSD: Move scalar double-precision fp to/from/between XMM registers. |
| 998 AppendToBuffer("movsd "); |
| 999 int mod, regop, rm; |
| 1000 get_modrm(*current, &mod, ®op, &rm); |
| 1001 if (opcode == 0x11) { |
| 1002 current += PrintRightOperand(current); |
| 1003 AppendToBuffer(",%s", NameOfXMMRegister(regop)); |
| 1004 } else { |
| 1005 AppendToBuffer("%s,", NameOfXMMRegister(regop)); |
| 1006 current += PrintRightOperand(current); |
| 1007 } |
| 1008 } else if (opcode == 0x2A) { |
| 1009 // CVTSI2SD: integer to XMM double conversion. |
| 1010 int mod, regop, rm; |
| 1011 get_modrm(*current, &mod, ®op, &rm); |
| 1012 AppendToBuffer("%s %s,", mnemonic, NameOfXMMRegister(regop)); |
| 1013 data += PrintRightOperand(data); |
| 1014 } else if ((opcode & 0xF8) == 0x58) { |
| 1015 // XMM arithmetic. Mnemonic was retrieved at the start of this function. |
| 1016 int mod, regop, rm; |
| 1017 get_modrm(*current, &mod, ®op, &rm); |
| 1018 AppendToBuffer("%s %s,%s", mnemonic, NameOfXMMRegister(regop), |
| 1019 NameOfXMMRegister(rm)); |
| 1020 } else { |
| 1021 UnimplementedInstruction(); |
| 1022 } |
| 1023 } else if (opcode == 0x2C && group_1_prefix_ == 0xF3) { |
| 1024 // Instruction with prefix 0xF3. |
| 1025 |
| 1026 // CVTTSS2SI: Convert scalar single-precision FP to dword integer. |
| 1027 // Assert that mod is not 3, so source is memory, not an XMM register. |
| 1028 ASSERT((*current & 0xC0) != 0xC0); |
| 1029 current += PrintOperands("cvttss2si", REG_OPER_OP_ORDER, current); |
| 1030 } else { |
| 1031 UnimplementedInstruction(); |
| 1032 } |
| 1033 return current - data; |
| 1034 } |
| 1035 |
| 1036 |
| 1037 // Mnemonics for two-byte opcode instructions starting with 0x0F. |
| 1038 // The argument is the second byte of the two-byte opcode. |
| 940 // Returns NULL if the instruction is not handled here. | 1039 // Returns NULL if the instruction is not handled here. |
| 941 static const char* F0Mnem(byte f0byte) { | 1040 const char* DisassemblerX64::TwoByteMnemonic(byte opcode) { |
| 942 switch (f0byte) { | 1041 switch (opcode) { |
| 943 case 0x1F: | 1042 case 0x1F: |
| 944 return "nop"; | 1043 return "nop"; |
| 1044 case 0x2A: // F2 prefix. |
| 1045 return "cvtsi2sd"; |
| 945 case 0x31: | 1046 case 0x31: |
| 946 return "rdtsc"; | 1047 return "rdtsc"; |
| 1048 case 0x58: // F2 prefix. |
| 1049 return "addsd"; |
| 1050 case 0x59: // F2 prefix. |
| 1051 return "mulsd"; |
| 1052 case 0x5C: // F2 prefix. |
| 1053 return "subsd"; |
| 1054 case 0x5E: // F2 prefix. |
| 1055 return "divsd"; |
| 947 case 0xA2: | 1056 case 0xA2: |
| 948 return "cpuid"; | 1057 return "cpuid"; |
| 1058 case 0xA5: |
| 1059 return "shld"; |
| 1060 case 0xAB: |
| 1061 return "bts"; |
| 1062 case 0xAD: |
| 1063 return "shrd"; |
| 1064 case 0xAF: |
| 1065 return "imul"; |
| 1066 case 0xB6: |
| 1067 return "movzxb"; |
| 1068 case 0xB7: |
| 1069 return "movzxw"; |
| 949 case 0xBE: | 1070 case 0xBE: |
| 950 return "movsxb"; | 1071 return "movsxb"; |
| 951 case 0xBF: | 1072 case 0xBF: |
| 952 return "movsxw"; | 1073 return "movsxw"; |
| 953 case 0xB6: | |
| 954 return "movzxb"; | |
| 955 case 0xB7: | |
| 956 return "movzxw"; | |
| 957 case 0xAF: | |
| 958 return "imul"; | |
| 959 case 0xA5: | |
| 960 return "shld"; | |
| 961 case 0xAD: | |
| 962 return "shrd"; | |
| 963 case 0xAB: | |
| 964 return "bts"; | |
| 965 default: | 1074 default: |
| 966 return NULL; | 1075 return NULL; |
| 967 } | 1076 } |
| 968 } | 1077 } |
| 969 | 1078 |
| 970 // Disassembled instruction '*instr' and writes it into 'out_buffer'. | 1079 |
| 1080 // Disassembles the instruction at instr, and writes it into out_buffer. |
| 971 int DisassemblerX64::InstructionDecode(v8::internal::Vector<char> out_buffer, | 1081 int DisassemblerX64::InstructionDecode(v8::internal::Vector<char> out_buffer, |
| 972 byte* instr) { | 1082 byte* instr) { |
| 973 tmp_buffer_pos_ = 0; // starting to write as position 0 | 1083 tmp_buffer_pos_ = 0; // starting to write as position 0 |
| 974 byte* data = instr; | 1084 byte* data = instr; |
| 975 bool processed = true; // Will be set to false if the current instruction | 1085 bool processed = true; // Will be set to false if the current instruction |
| 976 // is not in 'instructions' table. | 1086 // is not in 'instructions' table. |
| 977 byte current; | 1087 byte current; |
| 978 | 1088 |
| 979 // Scan for prefixes. | 1089 // Scan for prefixes. |
| 980 while (true) { | 1090 while (true) { |
| 981 current = *data; | 1091 current = *data; |
| 982 if (current == 0x66) { | 1092 if (current == 0x66) { // Group 3 prefix. |
| 983 // If the sequence is 66 0f, it's not a prefix, but a SSE escape. | 1093 operand_size_ = current; |
| 984 if (*(data + 1) == 0x0F) break; | 1094 } else if ((current & 0xF0) == 0x40) { // REX prefix. |
| 985 data++; | |
| 986 } else if ((current & 0xF0) == 0x40) { | |
| 987 setRex(current); | 1095 setRex(current); |
| 988 if (rex_w()) AppendToBuffer("REX.W "); | 1096 if (rex_w()) AppendToBuffer("REX.W "); |
| 989 data++; | 1097 } else if ((current & 0xFE) == 0xF2) { // Group 1 prefix. |
| 990 } else { | 1098 group_1_prefix_ = current; |
| 1099 } else { // Not a prefix - an opcode. |
| 991 break; | 1100 break; |
| 992 } | 1101 } |
| 1102 data++; |
| 993 } | 1103 } |
| 994 | 1104 |
| 995 const InstructionDesc& idesc = instruction_table.Get(current); | 1105 const InstructionDesc& idesc = instruction_table.Get(current); |
| 996 byte_size_operand_ = idesc.byte_size_operation; | 1106 byte_size_operand_ = idesc.byte_size_operation; |
| 997 switch (idesc.type) { | 1107 switch (idesc.type) { |
| 998 case ZERO_OPERANDS_INSTR: | 1108 case ZERO_OPERANDS_INSTR: |
| 999 AppendToBuffer(idesc.mnem); | 1109 AppendToBuffer(idesc.mnem); |
| 1000 data++; | 1110 data++; |
| 1001 break; | 1111 break; |
| 1002 | 1112 |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1101 } | 1211 } |
| 1102 data += 3; | 1212 data += 3; |
| 1103 break; | 1213 break; |
| 1104 } | 1214 } |
| 1105 | 1215 |
| 1106 case 0x81: // fall through | 1216 case 0x81: // fall through |
| 1107 case 0x83: // 0x81 with sign extension bit set | 1217 case 0x83: // 0x81 with sign extension bit set |
| 1108 data += PrintImmediateOp(data); | 1218 data += PrintImmediateOp(data); |
| 1109 break; | 1219 break; |
| 1110 | 1220 |
| 1111 case 0x0F: { | 1221 case 0x0F: |
| 1112 byte f0byte = *(data + 1); | 1222 data += TwoByteOpcodeInstruction(data); |
| 1113 const char* f0mnem = F0Mnem(f0byte); | |
| 1114 if (f0byte == 0x1F) { | |
| 1115 data += 1; | |
| 1116 byte modrm = *data; | |
| 1117 data += 1; | |
| 1118 if (((modrm >> 3) & 7) == 4) { | |
| 1119 // SIB byte present. | |
| 1120 data += 1; | |
| 1121 } | |
| 1122 int mod = modrm >> 6; | |
| 1123 if (mod == 1) { | |
| 1124 // Byte displacement. | |
| 1125 data += 1; | |
| 1126 } else if (mod == 2) { | |
| 1127 // 32-bit displacement. | |
| 1128 data += 4; | |
| 1129 } | |
| 1130 AppendToBuffer("nop"); | |
| 1131 } else if (f0byte == 0xA2 || f0byte == 0x31) { | |
| 1132 AppendToBuffer("%s", f0mnem); | |
| 1133 data += 2; | |
| 1134 } else if ((f0byte & 0xF0) == 0x80) { | |
| 1135 data += JumpConditional(data); | |
| 1136 } else if (f0byte == 0xBE || f0byte == 0xBF || f0byte == 0xB6 || f0byte | |
| 1137 == 0xB7 || f0byte == 0xAF) { | |
| 1138 data += 2; | |
| 1139 data += PrintOperands(f0mnem, REG_OPER_OP_ORDER, data); | |
| 1140 } else if ((f0byte & 0xF0) == 0x90) { | |
| 1141 data += SetCC(data); | |
| 1142 } else { | |
| 1143 data += 2; | |
| 1144 if (f0byte == 0xAB || f0byte == 0xA5 || f0byte == 0xAD) { | |
| 1145 // shrd, shld, bts | |
| 1146 AppendToBuffer("%s ", f0mnem); | |
| 1147 int mod, regop, rm; | |
| 1148 get_modrm(*data, &mod, ®op, &rm); | |
| 1149 data += PrintRightOperand(data); | |
| 1150 if (f0byte == 0xAB) { | |
| 1151 AppendToBuffer(",%s", NameOfCPURegister(regop)); | |
| 1152 } else { | |
| 1153 AppendToBuffer(",%s,cl", NameOfCPURegister(regop)); | |
| 1154 } | |
| 1155 } else { | |
| 1156 UnimplementedInstruction(); | |
| 1157 } | |
| 1158 } | |
| 1159 } | |
| 1160 break; | 1223 break; |
| 1161 | 1224 |
| 1162 case 0x8F: { | 1225 case 0x8F: { |
| 1163 data++; | 1226 data++; |
| 1164 int mod, regop, rm; | 1227 int mod, regop, rm; |
| 1165 get_modrm(*data, &mod, ®op, &rm); | 1228 get_modrm(*data, &mod, ®op, &rm); |
| 1166 if (regop == 0) { | 1229 if (regop == 0) { |
| 1167 AppendToBuffer("pop "); | 1230 AppendToBuffer("pop "); |
| 1168 data += PrintRightOperand(data); | 1231 data += PrintRightOperand(data); |
| 1169 } | 1232 } |
| (...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1296 value = *reinterpret_cast<uint32_t*>(data + 1); | 1359 value = *reinterpret_cast<uint32_t*>(data + 1); |
| 1297 data += 5; | 1360 data += 5; |
| 1298 break; | 1361 break; |
| 1299 case QUADWORD_SIZE: | 1362 case QUADWORD_SIZE: |
| 1300 value = *reinterpret_cast<int32_t*>(data + 1); | 1363 value = *reinterpret_cast<int32_t*>(data + 1); |
| 1301 data += 5; | 1364 data += 5; |
| 1302 break; | 1365 break; |
| 1303 default: | 1366 default: |
| 1304 UNREACHABLE(); | 1367 UNREACHABLE(); |
| 1305 } | 1368 } |
| 1306 break; | |
| 1307 AppendToBuffer("test%c rax,0x%"V8_PTR_PREFIX"ux", | 1369 AppendToBuffer("test%c rax,0x%"V8_PTR_PREFIX"ux", |
| 1308 operand_size_code(), | 1370 operand_size_code(), |
| 1309 value); | 1371 value); |
| 1372 break; |
| 1310 } | 1373 } |
| 1311 case 0xD1: // fall through | 1374 case 0xD1: // fall through |
| 1312 case 0xD3: // fall through | 1375 case 0xD3: // fall through |
| 1313 case 0xC1: | 1376 case 0xC1: |
| 1314 data += ShiftInstruction(data); | 1377 data += ShiftInstruction(data); |
| 1315 break; | 1378 break; |
| 1316 case 0xD0: // fall through | 1379 case 0xD0: // fall through |
| 1317 case 0xD2: // fall through | 1380 case 0xD2: // fall through |
| 1318 case 0xC0: | 1381 case 0xC0: |
| 1319 byte_size_operand_ = true; | 1382 byte_size_operand_ = true; |
| 1320 data += ShiftInstruction(data); | 1383 data += ShiftInstruction(data); |
| 1321 break; | 1384 break; |
| 1322 | 1385 |
| 1323 case 0xD9: // fall through | 1386 case 0xD9: // fall through |
| 1324 case 0xDA: // fall through | 1387 case 0xDA: // fall through |
| 1325 case 0xDB: // fall through | 1388 case 0xDB: // fall through |
| 1326 case 0xDC: // fall through | 1389 case 0xDC: // fall through |
| 1327 case 0xDD: // fall through | 1390 case 0xDD: // fall through |
| 1328 case 0xDE: // fall through | 1391 case 0xDE: // fall through |
| 1329 case 0xDF: | 1392 case 0xDF: |
| 1330 data += FPUInstruction(data); | 1393 data += FPUInstruction(data); |
| 1331 break; | 1394 break; |
| 1332 | 1395 |
| 1333 case 0xEB: | 1396 case 0xEB: |
| 1334 data += JumpShort(data); | 1397 data += JumpShort(data); |
| 1335 break; | 1398 break; |
| 1336 | 1399 |
| 1337 case 0xF2: | |
| 1338 if (*(data + 1) == 0x0F) { | |
| 1339 byte b2 = *(data + 2); | |
| 1340 if (b2 == 0x11) { | |
| 1341 AppendToBuffer("movsd "); | |
| 1342 data += 3; | |
| 1343 int mod, regop, rm; | |
| 1344 get_modrm(*data, &mod, ®op, &rm); | |
| 1345 data += PrintRightOperand(data); | |
| 1346 AppendToBuffer(",%s", NameOfXMMRegister(regop)); | |
| 1347 } else if (b2 == 0x10) { | |
| 1348 data += 3; | |
| 1349 int mod, regop, rm; | |
| 1350 get_modrm(*data, &mod, ®op, &rm); | |
| 1351 AppendToBuffer("movsd %s,", NameOfXMMRegister(regop)); | |
| 1352 data += PrintRightOperand(data); | |
| 1353 } else { | |
| 1354 const char* mnem = "?"; | |
| 1355 switch (b2) { | |
| 1356 case 0x2A: | |
| 1357 mnem = "cvtsi2sd"; | |
| 1358 break; | |
| 1359 case 0x58: | |
| 1360 mnem = "addsd"; | |
| 1361 break; | |
| 1362 case 0x59: | |
| 1363 mnem = "mulsd"; | |
| 1364 break; | |
| 1365 case 0x5C: | |
| 1366 mnem = "subsd"; | |
| 1367 break; | |
| 1368 case 0x5E: | |
| 1369 mnem = "divsd"; | |
| 1370 break; | |
| 1371 } | |
| 1372 data += 3; | |
| 1373 int mod, regop, rm; | |
| 1374 get_modrm(*data, &mod, ®op, &rm); | |
| 1375 if (b2 == 0x2A) { | |
| 1376 AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop)); | |
| 1377 data += PrintRightOperand(data); | |
| 1378 } else { | |
| 1379 AppendToBuffer("%s %s,%s", mnem, NameOfXMMRegister(regop), | |
| 1380 NameOfXMMRegister(rm)); | |
| 1381 data++; | |
| 1382 } | |
| 1383 } | |
| 1384 } else { | |
| 1385 UnimplementedInstruction(); | |
| 1386 } | |
| 1387 break; | |
| 1388 | |
| 1389 case 0xF3: | |
| 1390 if (*(data + 1) == 0x0F) { | |
| 1391 if (*(data + 2) == 0x2C) { | |
| 1392 data += 3; | |
| 1393 data += PrintOperands("cvttss2si", REG_OPER_OP_ORDER, data); | |
| 1394 } else { | |
| 1395 UnimplementedInstruction(); | |
| 1396 data += 1; | |
| 1397 } | |
| 1398 } else { | |
| 1399 UnimplementedInstruction(); | |
| 1400 data += 1; | |
| 1401 } | |
| 1402 break; | |
| 1403 | |
| 1404 case 0xF7: | 1400 case 0xF7: |
| 1405 data += F7Instruction(data); | 1401 data += F7Instruction(data); |
| 1406 break; | 1402 break; |
| 1407 | 1403 |
| 1408 default: | 1404 default: |
| 1409 UnimplementedInstruction(); | 1405 UnimplementedInstruction(); |
| 1410 data += 1; | 1406 data += 1; |
| 1411 } | 1407 } |
| 1412 } // !processed | 1408 } // !processed |
| 1413 | 1409 |
| (...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1528 fprintf(f, "%02x", *bp); | 1524 fprintf(f, "%02x", *bp); |
| 1529 } | 1525 } |
| 1530 for (int i = 6 - (pc - prev_pc); i >= 0; i--) { | 1526 for (int i = 6 - (pc - prev_pc); i >= 0; i--) { |
| 1531 fprintf(f, " "); | 1527 fprintf(f, " "); |
| 1532 } | 1528 } |
| 1533 fprintf(f, " %s\n", buffer.start()); | 1529 fprintf(f, " %s\n", buffer.start()); |
| 1534 } | 1530 } |
| 1535 } | 1531 } |
| 1536 | 1532 |
| 1537 } // namespace disasm | 1533 } // namespace disasm |
| OLD | NEW |