| 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 16 matching lines...) Expand all Loading... |
| 27 | 27 |
| 28 #include <assert.h> | 28 #include <assert.h> |
| 29 #include <stdio.h> | 29 #include <stdio.h> |
| 30 #include <stdarg.h> | 30 #include <stdarg.h> |
| 31 | 31 |
| 32 #include "v8.h" | 32 #include "v8.h" |
| 33 #include "disasm.h" | 33 #include "disasm.h" |
| 34 | 34 |
| 35 namespace disasm { | 35 namespace disasm { |
| 36 | 36 |
| 37 enum OperandOrder { | 37 enum OperandType { |
| 38 UNSET_OP_ORDER = 0, REG_OPER_OP_ORDER, OPER_REG_OP_ORDER | 38 UNSET_OP_ORDER = 0, |
| 39 // Operand size decides between 16, 32 and 64 bit operands. |
| 40 REG_OPER_OP_ORDER = 1, // Register destination, operand source. |
| 41 OPER_REG_OP_ORDER = 2, // Operand destination, register source. |
| 42 // Fixed 8-bit operands. |
| 43 BYTE_SIZE_OPERAND_FLAG = 4, |
| 44 BYTE_REG_OPER_OP_ORDER = REG_OPER_OP_ORDER | BYTE_SIZE_OPERAND_FLAG, |
| 45 BYTE_OPER_REG_OP_ORDER = OPER_REG_OP_ORDER | BYTE_SIZE_OPERAND_FLAG |
| 39 }; | 46 }; |
| 40 | 47 |
| 41 //------------------------------------------------------------------ | 48 //------------------------------------------------------------------ |
| 42 // Tables | 49 // Tables |
| 43 //------------------------------------------------------------------ | 50 //------------------------------------------------------------------ |
| 44 struct ByteMnemonic { | 51 struct ByteMnemonic { |
| 45 int b; // -1 terminates, otherwise must be in range (0..255) | 52 int b; // -1 terminates, otherwise must be in range (0..255) |
| 46 OperandOrder op_order_; | 53 OperandType op_order_; |
| 47 const char* mnem; | 54 const char* mnem; |
| 48 }; | 55 }; |
| 49 | 56 |
| 50 | 57 |
| 51 static ByteMnemonic two_operands_instr[] = { | 58 static ByteMnemonic two_operands_instr[] = { |
| 52 { 0x03, REG_OPER_OP_ORDER, "add" }, | 59 { 0x00, BYTE_OPER_REG_OP_ORDER, "add" }, |
| 53 { 0x21, OPER_REG_OP_ORDER, "and" }, | 60 { 0x01, OPER_REG_OP_ORDER, "add" }, |
| 54 { 0x23, REG_OPER_OP_ORDER, "and" }, | 61 { 0x02, BYTE_REG_OPER_OP_ORDER, "add" }, |
| 55 { 0x3B, REG_OPER_OP_ORDER, "cmp" }, | 62 { 0x03, REG_OPER_OP_ORDER, "add" }, |
| 56 { 0x8D, REG_OPER_OP_ORDER, "lea" }, | 63 { 0x08, BYTE_OPER_REG_OP_ORDER, "or" }, |
| 57 { 0x09, OPER_REG_OP_ORDER, "or" }, | 64 { 0x09, OPER_REG_OP_ORDER, "or" }, |
| 58 { 0x0B, REG_OPER_OP_ORDER, "or" }, | 65 { 0x0A, BYTE_REG_OPER_OP_ORDER, "or" }, |
| 59 { 0x1B, REG_OPER_OP_ORDER, "sbb" }, | 66 { 0x0B, REG_OPER_OP_ORDER, "or" }, |
| 60 { 0x29, OPER_REG_OP_ORDER, "sub" }, | 67 { 0x10, BYTE_OPER_REG_OP_ORDER, "adc" }, |
| 61 { 0x2B, REG_OPER_OP_ORDER, "sub" }, | 68 { 0x11, OPER_REG_OP_ORDER, "adc" }, |
| 62 { 0x85, REG_OPER_OP_ORDER, "test" }, | 69 { 0x12, BYTE_REG_OPER_OP_ORDER, "adc" }, |
| 63 { 0x31, OPER_REG_OP_ORDER, "xor" }, | 70 { 0x13, REG_OPER_OP_ORDER, "adc" }, |
| 64 { 0x33, REG_OPER_OP_ORDER, "xor" }, | 71 { 0x18, BYTE_OPER_REG_OP_ORDER, "sbb" }, |
| 65 { 0x87, REG_OPER_OP_ORDER, "xchg" }, | 72 { 0x19, OPER_REG_OP_ORDER, "sbb" }, |
| 66 { 0x8A, REG_OPER_OP_ORDER, "movb" }, | 73 { 0x1A, BYTE_REG_OPER_OP_ORDER, "sbb" }, |
| 67 { 0x8B, REG_OPER_OP_ORDER, "mov" }, | 74 { 0x1B, REG_OPER_OP_ORDER, "sbb" }, |
| 75 { 0x20, BYTE_OPER_REG_OP_ORDER, "and" }, |
| 76 { 0x21, OPER_REG_OP_ORDER, "and" }, |
| 77 { 0x22, BYTE_REG_OPER_OP_ORDER, "and" }, |
| 78 { 0x23, REG_OPER_OP_ORDER, "and" }, |
| 79 { 0x28, BYTE_OPER_REG_OP_ORDER, "sub" }, |
| 80 { 0x29, OPER_REG_OP_ORDER, "sub" }, |
| 81 { 0x2A, BYTE_REG_OPER_OP_ORDER, "sub" }, |
| 82 { 0x2B, REG_OPER_OP_ORDER, "sub" }, |
| 83 { 0x30, BYTE_OPER_REG_OP_ORDER, "xor" }, |
| 84 { 0x31, OPER_REG_OP_ORDER, "xor" }, |
| 85 { 0x32, BYTE_REG_OPER_OP_ORDER, "xor" }, |
| 86 { 0x33, REG_OPER_OP_ORDER, "xor" }, |
| 87 { 0x38, BYTE_OPER_REG_OP_ORDER, "cmp" }, |
| 88 { 0x39, OPER_REG_OP_ORDER, "cmp" }, |
| 89 { 0x3A, BYTE_REG_OPER_OP_ORDER, "cmp" }, |
| 90 { 0x3B, REG_OPER_OP_ORDER, "cmp" }, |
| 91 { 0x8D, REG_OPER_OP_ORDER, "lea" }, |
| 92 { 0x84, BYTE_REG_OPER_OP_ORDER, "test" }, |
| 93 { 0x85, REG_OPER_OP_ORDER, "test" }, |
| 94 { 0x86, BYTE_REG_OPER_OP_ORDER, "xchg" }, |
| 95 { 0x87, REG_OPER_OP_ORDER, "xchg" }, |
| 96 { 0x88, BYTE_OPER_REG_OP_ORDER, "mov" }, |
| 97 { 0x89, OPER_REG_OP_ORDER, "mov" }, |
| 98 { 0x8A, BYTE_REG_OPER_OP_ORDER, "mov" }, |
| 99 { 0x8B, REG_OPER_OP_ORDER, "mov" }, |
| 68 { -1, UNSET_OP_ORDER, "" } | 100 { -1, UNSET_OP_ORDER, "" } |
| 69 }; | 101 }; |
| 70 | 102 |
| 71 | 103 |
| 72 static ByteMnemonic zero_operands_instr[] = { | 104 static ByteMnemonic zero_operands_instr[] = { |
| 73 { 0xC3, UNSET_OP_ORDER, "ret" }, | 105 { 0xC3, UNSET_OP_ORDER, "ret" }, |
| 74 { 0xC9, UNSET_OP_ORDER, "leave" }, | 106 { 0xC9, UNSET_OP_ORDER, "leave" }, |
| 75 { 0x90, UNSET_OP_ORDER, "nop" }, | 107 { 0x90, UNSET_OP_ORDER, "nop" }, |
| 76 { 0xF4, UNSET_OP_ORDER, "hlt" }, | 108 { 0xF4, UNSET_OP_ORDER, "hlt" }, |
| 77 { 0xCC, UNSET_OP_ORDER, "int3" }, | 109 { 0xCC, UNSET_OP_ORDER, "int3" }, |
| (...skipping 12 matching lines...) Expand all Loading... |
| 90 { 0xE8, UNSET_OP_ORDER, "call" }, | 122 { 0xE8, UNSET_OP_ORDER, "call" }, |
| 91 { 0xE9, UNSET_OP_ORDER, "jmp" }, | 123 { 0xE9, UNSET_OP_ORDER, "jmp" }, |
| 92 { -1, UNSET_OP_ORDER, "" } | 124 { -1, UNSET_OP_ORDER, "" } |
| 93 }; | 125 }; |
| 94 | 126 |
| 95 | 127 |
| 96 static ByteMnemonic short_immediate_instr[] = { | 128 static ByteMnemonic short_immediate_instr[] = { |
| 97 { 0x05, UNSET_OP_ORDER, "add" }, | 129 { 0x05, UNSET_OP_ORDER, "add" }, |
| 98 { 0x0D, UNSET_OP_ORDER, "or" }, | 130 { 0x0D, UNSET_OP_ORDER, "or" }, |
| 99 { 0x15, UNSET_OP_ORDER, "adc" }, | 131 { 0x15, UNSET_OP_ORDER, "adc" }, |
| 132 { 0x1D, UNSET_OP_ORDER, "sbb" }, |
| 100 { 0x25, UNSET_OP_ORDER, "and" }, | 133 { 0x25, UNSET_OP_ORDER, "and" }, |
| 101 { 0x2D, UNSET_OP_ORDER, "sub" }, | 134 { 0x2D, UNSET_OP_ORDER, "sub" }, |
| 102 { 0x35, UNSET_OP_ORDER, "xor" }, | 135 { 0x35, UNSET_OP_ORDER, "xor" }, |
| 103 { 0x3D, UNSET_OP_ORDER, "cmp" }, | 136 { 0x3D, UNSET_OP_ORDER, "cmp" }, |
| 104 { -1, UNSET_OP_ORDER, "" } | 137 { -1, UNSET_OP_ORDER, "" } |
| 105 }; | 138 }; |
| 106 | 139 |
| 107 | 140 |
| 108 static const char* conditional_code_suffix[] = { | 141 static const char* conditional_code_suffix[] = { |
| 109 "o", "no", "c", "nc", "z", "nz", "a", "na", | 142 "o", "no", "c", "nc", "z", "nz", "a", "na", |
| (...skipping 10 matching lines...) Expand all Loading... |
| 120 PUSHPOP_INSTR, // Has implicit 64-bit operand size. | 153 PUSHPOP_INSTR, // Has implicit 64-bit operand size. |
| 121 MOVE_REG_INSTR, | 154 MOVE_REG_INSTR, |
| 122 CALL_JUMP_INSTR, | 155 CALL_JUMP_INSTR, |
| 123 SHORT_IMMEDIATE_INSTR | 156 SHORT_IMMEDIATE_INSTR |
| 124 }; | 157 }; |
| 125 | 158 |
| 126 | 159 |
| 127 struct InstructionDesc { | 160 struct InstructionDesc { |
| 128 const char* mnem; | 161 const char* mnem; |
| 129 InstructionType type; | 162 InstructionType type; |
| 130 OperandOrder op_order_; | 163 OperandType op_order_; |
| 164 bool byte_size_operation; // Fixed 8-bit operation. |
| 131 }; | 165 }; |
| 132 | 166 |
| 133 | 167 |
| 134 class InstructionTable { | 168 class InstructionTable { |
| 135 public: | 169 public: |
| 136 InstructionTable(); | 170 InstructionTable(); |
| 137 const InstructionDesc& Get(byte x) const { | 171 const InstructionDesc& Get(byte x) const { |
| 138 return instructions_[x]; | 172 return instructions_[x]; |
| 139 } | 173 } |
| 140 | 174 |
| 141 private: | 175 private: |
| 142 InstructionDesc instructions_[256]; | 176 InstructionDesc instructions_[256]; |
| 143 void Clear(); | 177 void Clear(); |
| 144 void Init(); | 178 void Init(); |
| 145 void CopyTable(ByteMnemonic bm[], InstructionType type); | 179 void CopyTable(ByteMnemonic bm[], InstructionType type); |
| 146 void SetTableRange(InstructionType type, byte start, byte end, | 180 void SetTableRange(InstructionType type, byte start, byte end, bool byte_size, |
| 147 const char* mnem); | 181 const char* mnem); |
| 148 void AddJumpConditionalShort(); | 182 void AddJumpConditionalShort(); |
| 149 }; | 183 }; |
| 150 | 184 |
| 151 | 185 |
| 152 InstructionTable::InstructionTable() { | 186 InstructionTable::InstructionTable() { |
| 153 Clear(); | 187 Clear(); |
| 154 Init(); | 188 Init(); |
| 155 } | 189 } |
| 156 | 190 |
| 157 | 191 |
| 158 void InstructionTable::Clear() { | 192 void InstructionTable::Clear() { |
| 159 for (int i = 0; i < 256; i++) { | 193 for (int i = 0; i < 256; i++) { |
| 160 instructions_[i].mnem = ""; | 194 instructions_[i].mnem = "(bad)"; |
| 161 instructions_[i].type = NO_INSTR; | 195 instructions_[i].type = NO_INSTR; |
| 162 instructions_[i].op_order_ = UNSET_OP_ORDER; | 196 instructions_[i].op_order_ = UNSET_OP_ORDER; |
| 197 instructions_[i].byte_size_operation = false; |
| 163 } | 198 } |
| 164 } | 199 } |
| 165 | 200 |
| 166 | 201 |
| 167 void InstructionTable::Init() { | 202 void InstructionTable::Init() { |
| 168 CopyTable(two_operands_instr, TWO_OPERANDS_INSTR); | 203 CopyTable(two_operands_instr, TWO_OPERANDS_INSTR); |
| 169 CopyTable(zero_operands_instr, ZERO_OPERANDS_INSTR); | 204 CopyTable(zero_operands_instr, ZERO_OPERANDS_INSTR); |
| 170 CopyTable(call_jump_instr, CALL_JUMP_INSTR); | 205 CopyTable(call_jump_instr, CALL_JUMP_INSTR); |
| 171 CopyTable(short_immediate_instr, SHORT_IMMEDIATE_INSTR); | 206 CopyTable(short_immediate_instr, SHORT_IMMEDIATE_INSTR); |
| 172 AddJumpConditionalShort(); | 207 AddJumpConditionalShort(); |
| 173 SetTableRange(PUSHPOP_INSTR, 0x50, 0x57, "push"); | 208 SetTableRange(PUSHPOP_INSTR, 0x50, 0x57, false, "push"); |
| 174 SetTableRange(PUSHPOP_INSTR, 0x58, 0x5F, "pop"); | 209 SetTableRange(PUSHPOP_INSTR, 0x58, 0x5F, false, "pop"); |
| 175 SetTableRange(MOVE_REG_INSTR, 0xB8, 0xBF, "mov"); | 210 SetTableRange(MOVE_REG_INSTR, 0xB8, 0xBF, false, "mov"); |
| 176 } | 211 } |
| 177 | 212 |
| 178 | 213 |
| 179 void InstructionTable::CopyTable(ByteMnemonic bm[], InstructionType type) { | 214 void InstructionTable::CopyTable(ByteMnemonic bm[], InstructionType type) { |
| 180 for (int i = 0; bm[i].b >= 0; i++) { | 215 for (int i = 0; bm[i].b >= 0; i++) { |
| 181 InstructionDesc* id = &instructions_[bm[i].b]; | 216 InstructionDesc* id = &instructions_[bm[i].b]; |
| 182 id->mnem = bm[i].mnem; | 217 id->mnem = bm[i].mnem; |
| 183 id->op_order_ = bm[i].op_order_; | 218 OperandType op_order = bm[i].op_order_; |
| 184 assert(id->type == NO_INSTR); // Information already entered | 219 id->op_order_ = |
| 220 static_cast<OperandType>(op_order & ~BYTE_SIZE_OPERAND_FLAG); |
| 221 assert(id->type == NO_INSTR); // Information not already entered |
| 185 id->type = type; | 222 id->type = type; |
| 223 id->byte_size_operation = ((op_order & BYTE_SIZE_OPERAND_FLAG) != 0); |
| 186 } | 224 } |
| 187 } | 225 } |
| 188 | 226 |
| 189 | 227 |
| 190 void InstructionTable::SetTableRange(InstructionType type, byte start, | 228 void InstructionTable::SetTableRange(InstructionType type, |
| 191 byte end, const char* mnem) { | 229 byte start, |
| 230 byte end, |
| 231 bool byte_size, |
| 232 const char* mnem) { |
| 192 for (byte b = start; b <= end; b++) { | 233 for (byte b = start; b <= end; b++) { |
| 193 InstructionDesc* id = &instructions_[b]; | 234 InstructionDesc* id = &instructions_[b]; |
| 194 assert(id->type == NO_INSTR); // Information already entered | 235 assert(id->type == NO_INSTR); // Information already entered |
| 195 id->mnem = mnem; | 236 id->mnem = mnem; |
| 196 id->type = type; | 237 id->type = type; |
| 238 id->byte_size_operation = byte_size; |
| 197 } | 239 } |
| 198 } | 240 } |
| 199 | 241 |
| 200 | 242 |
| 201 void InstructionTable::AddJumpConditionalShort() { | 243 void InstructionTable::AddJumpConditionalShort() { |
| 202 for (byte b = 0x70; b <= 0x7F; b++) { | 244 for (byte b = 0x70; b <= 0x7F; b++) { |
| 203 InstructionDesc* id = &instructions_[b]; | 245 InstructionDesc* id = &instructions_[b]; |
| 204 assert(id->type == NO_INSTR); // Information already entered | 246 assert(id->type == NO_INSTR); // Information already entered |
| 205 id->mnem = NULL; // Computed depending on condition code. | 247 id->mnem = NULL; // Computed depending on condition code. |
| 206 id->type = JUMP_CONDITIONAL_SHORT_INSTR; | 248 id->type = JUMP_CONDITIONAL_SHORT_INSTR; |
| (...skipping 14 matching lines...) Expand all Loading... |
| 221 class DisassemblerX64 { | 263 class DisassemblerX64 { |
| 222 public: | 264 public: |
| 223 DisassemblerX64(const NameConverter& converter, | 265 DisassemblerX64(const NameConverter& converter, |
| 224 UnimplementedOpcodeAction unimplemented_action = | 266 UnimplementedOpcodeAction unimplemented_action = |
| 225 ABORT_ON_UNIMPLEMENTED_OPCODE) | 267 ABORT_ON_UNIMPLEMENTED_OPCODE) |
| 226 : converter_(converter), | 268 : converter_(converter), |
| 227 tmp_buffer_pos_(0), | 269 tmp_buffer_pos_(0), |
| 228 abort_on_unimplemented_( | 270 abort_on_unimplemented_( |
| 229 unimplemented_action == ABORT_ON_UNIMPLEMENTED_OPCODE), | 271 unimplemented_action == ABORT_ON_UNIMPLEMENTED_OPCODE), |
| 230 rex_(0), | 272 rex_(0), |
| 231 operand_size_(0) { | 273 operand_size_(0), |
| 274 byte_size_operand_(false) { |
| 232 tmp_buffer_[0] = '\0'; | 275 tmp_buffer_[0] = '\0'; |
| 233 } | 276 } |
| 234 | 277 |
| 235 virtual ~DisassemblerX64() { | 278 virtual ~DisassemblerX64() { |
| 236 } | 279 } |
| 237 | 280 |
| 238 // Writes one disassembled instruction into 'buffer' (0-terminated). | 281 // Writes one disassembled instruction into 'buffer' (0-terminated). |
| 239 // Returns the length of the disassembled machine instruction in bytes. | 282 // Returns the length of the disassembled machine instruction in bytes. |
| 240 int InstructionDecode(v8::internal::Vector<char> buffer, byte* instruction); | 283 int InstructionDecode(v8::internal::Vector<char> buffer, byte* instruction); |
| 241 | 284 |
| 242 private: | 285 private: |
| 286 enum OperandSize { |
| 287 BYTE_SIZE = 0, |
| 288 WORD_SIZE = 1, |
| 289 DOUBLEWORD_SIZE = 2, |
| 290 QUADWORD_SIZE = 3 |
| 291 }; |
| 243 | 292 |
| 244 const NameConverter& converter_; | 293 const NameConverter& converter_; |
| 245 v8::internal::EmbeddedVector<char, 128> tmp_buffer_; | 294 v8::internal::EmbeddedVector<char, 128> tmp_buffer_; |
| 246 unsigned int tmp_buffer_pos_; | 295 unsigned int tmp_buffer_pos_; |
| 247 bool abort_on_unimplemented_; | 296 bool abort_on_unimplemented_; |
| 248 // Prefixes parsed | 297 // Prefixes parsed |
| 249 byte rex_; | 298 byte rex_; |
| 250 byte operand_size_; | 299 byte operand_size_; |
| 300 // Byte size operand override. |
| 301 bool byte_size_operand_; |
| 251 | 302 |
| 252 void setOperandSizePrefix(byte prefix) { | 303 void setOperandSizePrefix(byte prefix) { |
| 253 ASSERT_EQ(0x66, prefix); | 304 ASSERT_EQ(0x66, prefix); |
| 254 operand_size_ = prefix; | 305 operand_size_ = prefix; |
| 255 } | 306 } |
| 256 | 307 |
| 257 void setRex(byte rex) { | 308 void setRex(byte rex) { |
| 258 ASSERT_EQ(0x40, rex & 0xF0); | 309 ASSERT_EQ(0x40, rex & 0xF0); |
| 259 rex_ = rex; | 310 rex_ = rex; |
| 260 } | 311 } |
| 261 | 312 |
| 262 bool rex() { return rex_ != 0; } | 313 bool rex() { return rex_ != 0; } |
| 263 | 314 |
| 264 bool rex_b() { return (rex_ & 0x01) != 0; } | 315 bool rex_b() { return (rex_ & 0x01) != 0; } |
| 265 | 316 |
| 266 // 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. |
| 267 int base_reg(int low_bits) { return low_bits | ((rex_ & 0x01) << 3); } | 318 int base_reg(int low_bits) { return low_bits | ((rex_ & 0x01) << 3); } |
| 268 | 319 |
| 269 bool rex_x() { return (rex_ & 0x02) != 0; } | 320 bool rex_x() { return (rex_ & 0x02) != 0; } |
| 270 | 321 |
| 271 bool rex_r() { return (rex_ & 0x04) != 0; } | 322 bool rex_r() { return (rex_ & 0x04) != 0; } |
| 272 | 323 |
| 273 bool rex_w() { return (rex_ & 0x08) != 0; } | 324 bool rex_w() { return (rex_ & 0x08) != 0; } |
| 274 | 325 |
| 275 int operand_size() { | 326 OperandSize operand_size() { |
| 276 return rex_w() ? 64 : (operand_size_ != 0) ? 16 : 32; | 327 if (byte_size_operand_) return BYTE_SIZE; |
| 328 if (rex_w()) return QUADWORD_SIZE; |
| 329 if (operand_size_ != 0) return WORD_SIZE; |
| 330 return DOUBLEWORD_SIZE; |
| 277 } | 331 } |
| 278 | 332 |
| 279 char operand_size_code() { | 333 char operand_size_code() { |
| 280 return rex_w() ? 'q' : (operand_size_ != 0) ? 'w' : 'l'; | 334 return "bwlq"[operand_size()]; |
| 281 } | 335 } |
| 282 | 336 |
| 283 const char* NameOfCPURegister(int reg) const { | 337 const char* NameOfCPURegister(int reg) const { |
| 284 return converter_.NameOfCPURegister(reg); | 338 return converter_.NameOfCPURegister(reg); |
| 285 } | 339 } |
| 286 | 340 |
| 287 const char* NameOfByteCPURegister(int reg) const { | 341 const char* NameOfByteCPURegister(int reg) const { |
| 288 return converter_.NameOfByteCPURegister(reg); | 342 return converter_.NameOfByteCPURegister(reg); |
| 289 } | 343 } |
| 290 | 344 |
| (...skipping 14 matching lines...) Expand all Loading... |
| 305 *regop = ((data & 0x38) >> 3) | (rex_r() ? 8 : 0); | 359 *regop = ((data & 0x38) >> 3) | (rex_r() ? 8 : 0); |
| 306 *rm = (data & 7) | (rex_b() ? 8 : 0); | 360 *rm = (data & 7) | (rex_b() ? 8 : 0); |
| 307 } | 361 } |
| 308 | 362 |
| 309 void get_sib(byte data, | 363 void get_sib(byte data, |
| 310 int* scale, | 364 int* scale, |
| 311 int* index, | 365 int* index, |
| 312 int* base) { | 366 int* base) { |
| 313 *scale = (data >> 6) & 3; | 367 *scale = (data >> 6) & 3; |
| 314 *index = ((data >> 3) & 7) | (rex_x() ? 8 : 0); | 368 *index = ((data >> 3) & 7) | (rex_x() ? 8 : 0); |
| 315 *base = data & 7 | (rex_b() ? 8 : 0); | 369 *base = (data & 7) | (rex_b() ? 8 : 0); |
| 316 } | 370 } |
| 317 | 371 |
| 318 typedef const char* (DisassemblerX64::*RegisterNameMapping)(int reg) const; | 372 typedef const char* (DisassemblerX64::*RegisterNameMapping)(int reg) const; |
| 319 | 373 |
| 320 int PrintRightOperandHelper(byte* modrmp, | 374 int PrintRightOperandHelper(byte* modrmp, |
| 321 RegisterNameMapping register_name); | 375 RegisterNameMapping register_name); |
| 322 int PrintRightOperand(byte* modrmp); | 376 int PrintRightOperand(byte* modrmp); |
| 323 int PrintRightByteOperand(byte* modrmp); | 377 int PrintRightByteOperand(byte* modrmp); |
| 324 int PrintOperands(const char* mnem, | 378 int PrintOperands(const char* mnem, |
| 325 OperandOrder op_order, | 379 OperandType op_order, |
| 326 byte* data); | 380 byte* data); |
| 381 int PrintImmediate(byte* data, OperandSize size); |
| 327 int PrintImmediateOp(byte* data); | 382 int PrintImmediateOp(byte* data); |
| 328 int F7Instruction(byte* data); | 383 int F7Instruction(byte* data); |
| 329 int D1D3C1Instruction(byte* data); | 384 int ShiftInstruction(byte* data); |
| 330 int JumpShort(byte* data); | 385 int JumpShort(byte* data); |
| 331 int JumpConditional(byte* data); | 386 int JumpConditional(byte* data); |
| 332 int JumpConditionalShort(byte* data); | 387 int JumpConditionalShort(byte* data); |
| 333 int SetCC(byte* data); | 388 int SetCC(byte* data); |
| 334 int FPUInstruction(byte* data); | 389 int FPUInstruction(byte* data); |
| 335 void AppendToBuffer(const char* format, ...); | 390 void AppendToBuffer(const char* format, ...); |
| 336 | 391 |
| 337 void UnimplementedInstruction() { | 392 void UnimplementedInstruction() { |
| 338 if (abort_on_unimplemented_) { | 393 if (abort_on_unimplemented_) { |
| 339 UNIMPLEMENTED(); | 394 UNIMPLEMENTED(); |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 444 AppendToBuffer("%s", (this->*register_name)(rm)); | 499 AppendToBuffer("%s", (this->*register_name)(rm)); |
| 445 return 1; | 500 return 1; |
| 446 default: | 501 default: |
| 447 UnimplementedInstruction(); | 502 UnimplementedInstruction(); |
| 448 return 1; | 503 return 1; |
| 449 } | 504 } |
| 450 UNREACHABLE(); | 505 UNREACHABLE(); |
| 451 } | 506 } |
| 452 | 507 |
| 453 | 508 |
| 509 int DisassemblerX64::PrintImmediate(byte* data, OperandSize size) { |
| 510 int64_t value; |
| 511 int count; |
| 512 switch (size) { |
| 513 case BYTE_SIZE: |
| 514 value = *data; |
| 515 count = 1; |
| 516 break; |
| 517 case WORD_SIZE: |
| 518 value = *reinterpret_cast<int16_t*>(data); |
| 519 count = 2; |
| 520 break; |
| 521 case DOUBLEWORD_SIZE: |
| 522 value = *reinterpret_cast<uint32_t*>(data); |
| 523 count = 4; |
| 524 break; |
| 525 case QUADWORD_SIZE: |
| 526 value = *reinterpret_cast<int32_t*>(data); |
| 527 count = 4; |
| 528 break; |
| 529 default: |
| 530 UNREACHABLE(); |
| 531 value = 0; // Initialize variables on all paths to satisfy the compiler. |
| 532 count = 0; |
| 533 } |
| 534 AppendToBuffer(V8_PTR_PREFIX"x", value); |
| 535 return count; |
| 536 } |
| 537 |
| 538 |
| 454 int DisassemblerX64::PrintRightOperand(byte* modrmp) { | 539 int DisassemblerX64::PrintRightOperand(byte* modrmp) { |
| 455 return PrintRightOperandHelper(modrmp, | 540 return PrintRightOperandHelper(modrmp, |
| 456 &DisassemblerX64::NameOfCPURegister); | 541 &DisassemblerX64::NameOfCPURegister); |
| 457 } | 542 } |
| 458 | 543 |
| 459 | 544 |
| 460 int DisassemblerX64::PrintRightByteOperand(byte* modrmp) { | 545 int DisassemblerX64::PrintRightByteOperand(byte* modrmp) { |
| 461 return PrintRightOperandHelper(modrmp, | 546 return PrintRightOperandHelper(modrmp, |
| 462 &DisassemblerX64::NameOfByteCPURegister); | 547 &DisassemblerX64::NameOfByteCPURegister); |
| 463 } | 548 } |
| 464 | 549 |
| 465 | 550 |
| 466 // Returns number of bytes used including the current *data. | 551 // Returns number of bytes used including the current *data. |
| 467 // Writes instruction's mnemonic, left and right operands to 'tmp_buffer_'. | 552 // Writes instruction's mnemonic, left and right operands to 'tmp_buffer_'. |
| 468 int DisassemblerX64::PrintOperands(const char* mnem, | 553 int DisassemblerX64::PrintOperands(const char* mnem, |
| 469 OperandOrder op_order, | 554 OperandType op_order, |
| 470 byte* data) { | 555 byte* data) { |
| 471 byte modrm = *data; | 556 byte modrm = *data; |
| 472 int mod, regop, rm; | 557 int mod, regop, rm; |
| 473 get_modrm(modrm, &mod, ®op, &rm); | 558 get_modrm(modrm, &mod, ®op, &rm); |
| 474 int advance = 0; | 559 int advance = 0; |
| 560 const char* register_name = |
| 561 byte_size_operand_ ? NameOfByteCPURegister(regop) |
| 562 : NameOfCPURegister(regop); |
| 475 switch (op_order) { | 563 switch (op_order) { |
| 476 case REG_OPER_OP_ORDER: { | 564 case REG_OPER_OP_ORDER: { |
| 477 AppendToBuffer("%s%c %s,", | 565 AppendToBuffer("%s%c %s,", |
| 478 mnem, | 566 mnem, |
| 479 operand_size_code(), | 567 operand_size_code(), |
| 480 NameOfCPURegister(regop)); | 568 register_name); |
| 481 advance = PrintRightOperand(data); | 569 advance = byte_size_operand_ ? PrintRightByteOperand(data) |
| 570 : PrintRightOperand(data); |
| 482 break; | 571 break; |
| 483 } | 572 } |
| 484 case OPER_REG_OP_ORDER: { | 573 case OPER_REG_OP_ORDER: { |
| 485 AppendToBuffer("%s%c ", mnem, operand_size_code()); | 574 AppendToBuffer("%s%c ", mnem, operand_size_code()); |
| 486 advance = PrintRightOperand(data); | 575 advance = byte_size_operand_ ? PrintRightByteOperand(data) |
| 487 AppendToBuffer(",%s", NameOfCPURegister(regop)); | 576 : PrintRightOperand(data); |
| 577 AppendToBuffer(",%s", register_name); |
| 488 break; | 578 break; |
| 489 } | 579 } |
| 490 default: | 580 default: |
| 491 UNREACHABLE(); | 581 UNREACHABLE(); |
| 492 break; | 582 break; |
| 493 } | 583 } |
| 494 return advance; | 584 return advance; |
| 495 } | 585 } |
| 496 | 586 |
| 497 | 587 |
| 498 // Returns number of bytes used by machine instruction, including *data byte. | 588 // Returns number of bytes used by machine instruction, including *data byte. |
| 499 // Writes immediate instructions to 'tmp_buffer_'. | 589 // Writes immediate instructions to 'tmp_buffer_'. |
| 500 int DisassemblerX64::PrintImmediateOp(byte* data) { | 590 int DisassemblerX64::PrintImmediateOp(byte* data) { |
| 501 bool sign_extension_bit = (*data & 0x02) != 0; | 591 bool byte_size_immediate = (*data & 0x02) != 0; |
| 502 byte modrm = *(data + 1); | 592 byte modrm = *(data + 1); |
| 503 int mod, regop, rm; | 593 int mod, regop, rm; |
| 504 get_modrm(modrm, &mod, ®op, &rm); | 594 get_modrm(modrm, &mod, ®op, &rm); |
| 505 const char* mnem = "Imm???"; | 595 const char* mnem = "Imm???"; |
| 506 switch (regop) { | 596 switch (regop) { |
| 507 case 0: | 597 case 0: |
| 508 mnem = "add"; | 598 mnem = "add"; |
| 509 break; | 599 break; |
| 510 case 1: | 600 case 1: |
| 511 mnem = "or"; | 601 mnem = "or"; |
| 512 break; | 602 break; |
| 513 case 2: | 603 case 2: |
| 514 mnem = "adc"; | 604 mnem = "adc"; |
| 515 break; | 605 break; |
| 516 case 4: | 606 case 4: |
| 517 mnem = "and"; | 607 mnem = "and"; |
| 518 break; | 608 break; |
| 519 case 5: | 609 case 5: |
| 520 mnem = "sub"; | 610 mnem = "sub"; |
| 521 break; | 611 break; |
| 522 case 6: | 612 case 6: |
| 523 mnem = "xor"; | 613 mnem = "xor"; |
| 524 break; | 614 break; |
| 525 case 7: | 615 case 7: |
| 526 mnem = "cmp"; | 616 mnem = "cmp"; |
| 527 break; | 617 break; |
| 528 default: | 618 default: |
| 529 UnimplementedInstruction(); | 619 UnimplementedInstruction(); |
| 530 } | 620 } |
| 531 AppendToBuffer("%s ", mnem); | 621 AppendToBuffer("%s%c ", mnem, operand_size_code()); |
| 532 int count = PrintRightOperand(data + 1); | 622 int count = PrintRightOperand(data + 1); |
| 533 if (sign_extension_bit) { | 623 AppendToBuffer(",0x"); |
| 534 AppendToBuffer(",0x%x", *(data + 1 + count)); | 624 OperandSize immediate_size = byte_size_immediate ? BYTE_SIZE : operand_size(); |
| 535 return 1 + count + 1 /*int8*/; | 625 count += PrintImmediate(data + 1 + count, immediate_size); |
| 536 } else { | 626 return 1 + count; |
| 537 AppendToBuffer(",0x%x", *reinterpret_cast<int32_t*>(data + 1 + count)); | |
| 538 return 1 + count + 4 /*int32_t*/; | |
| 539 } | |
| 540 } | 627 } |
| 541 | 628 |
| 542 | 629 |
| 543 // Returns number of bytes used, including *data. | 630 // Returns number of bytes used, including *data. |
| 544 int DisassemblerX64::F7Instruction(byte* data) { | 631 int DisassemblerX64::F7Instruction(byte* data) { |
| 545 assert(*data == 0xF7); | 632 assert(*data == 0xF7); |
| 546 byte modrm = *(data + 1); | 633 byte modrm = *(data + 1); |
| 547 int mod, regop, rm; | 634 int mod, regop, rm; |
| 548 get_modrm(modrm, &mod, ®op, &rm); | 635 get_modrm(modrm, &mod, ®op, &rm); |
| 549 if (mod == 3 && regop != 0) { | 636 if (mod == 3 && regop != 0) { |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 582 int32_t imm = *reinterpret_cast<int32_t*>(data + 1 + count); | 669 int32_t imm = *reinterpret_cast<int32_t*>(data + 1 + count); |
| 583 AppendToBuffer(",0x%x", imm); | 670 AppendToBuffer(",0x%x", imm); |
| 584 return 1 + count + 4 /*int32_t*/; | 671 return 1 + count + 4 /*int32_t*/; |
| 585 } else { | 672 } else { |
| 586 UnimplementedInstruction(); | 673 UnimplementedInstruction(); |
| 587 return 2; | 674 return 2; |
| 588 } | 675 } |
| 589 } | 676 } |
| 590 | 677 |
| 591 | 678 |
| 592 int DisassemblerX64::D1D3C1Instruction(byte* data) { | 679 int DisassemblerX64::ShiftInstruction(byte* data) { |
| 593 byte op = *data; | 680 byte op = *data & (~1); |
| 594 assert(op == 0xD1 || op == 0xD3 || op == 0xC1); | 681 if (op != 0xD0 && op != 0xD2 && op != 0xC0) { |
| 682 UnimplementedInstruction(); |
| 683 return 1; |
| 684 } |
| 595 byte modrm = *(data + 1); | 685 byte modrm = *(data + 1); |
| 596 int mod, regop, rm; | 686 int mod, regop, rm; |
| 597 get_modrm(modrm, &mod, ®op, &rm); | 687 get_modrm(modrm, &mod, ®op, &rm); |
| 598 ASSERT(regop < 8); | 688 ASSERT(regop < 8); |
| 599 int imm8 = -1; | 689 int imm8 = -1; |
| 600 int num_bytes = 2; | 690 int num_bytes = 2; |
| 601 if (mod == 3) { | 691 if (mod != 3) { |
| 602 const char* mnem = NULL; | 692 UnimplementedInstruction(); |
| 603 if (op == 0xD1) { | 693 return num_bytes; |
| 604 imm8 = 1; | 694 } |
| 605 switch (regop) { | 695 const char* mnem = NULL; |
| 606 case 2: | 696 switch (regop) { |
| 607 mnem = "rcl"; | 697 case 0: |
| 608 break; | 698 mnem = "rol"; |
| 609 case 7: | 699 break; |
| 610 mnem = "sar"; | 700 case 1: |
| 611 break; | 701 mnem = "ror"; |
| 612 case 4: | 702 break; |
| 613 mnem = "shl"; | 703 case 2: |
| 614 break; | 704 mnem = "rcl"; |
| 615 default: | 705 break; |
| 616 UnimplementedInstruction(); | 706 case 3: |
| 617 } | 707 mnem = "rcr"; |
| 618 } else if (op == 0xC1) { | 708 break; |
| 619 imm8 = *(data + 2); | 709 case 4: |
| 620 num_bytes = 3; | 710 mnem = "shl"; |
| 621 switch (regop) { | 711 break; |
| 622 case 2: | 712 case 5: |
| 623 mnem = "rcl"; | 713 mnem = "shr"; |
| 624 break; | 714 break; |
| 625 case 4: | 715 case 7: |
| 626 mnem = "shl"; | 716 mnem = "sar"; |
| 627 break; | 717 break; |
| 628 case 5: | 718 default: |
| 629 mnem = "shr"; | 719 UnimplementedInstruction(); |
| 630 break; | 720 return num_bytes; |
| 631 case 7: | 721 } |
| 632 mnem = "sar"; | 722 assert(mnem != NULL); |
| 633 break; | 723 if (op == 0xD0) { |
| 634 default: | 724 imm8 = 1; |
| 635 UnimplementedInstruction(); | 725 } else if (op == 0xC0) { |
| 636 } | 726 imm8 = *(data + 2); |
| 637 } else if (op == 0xD3) { | 727 num_bytes = 3; |
| 638 switch (regop) { | 728 } |
| 639 case 4: | 729 AppendToBuffer("%s%c %s,", |
| 640 mnem = "shl"; | 730 mnem, |
| 641 break; | 731 operand_size_code(), |
| 642 case 5: | 732 byte_size_operand_ ? NameOfByteCPURegister(rm) |
| 643 mnem = "shr"; | 733 : NameOfCPURegister(rm)); |
| 644 break; | 734 if (op == 0xD2) { |
| 645 case 7: | 735 AppendToBuffer("cl"); |
| 646 mnem = "sar"; | |
| 647 break; | |
| 648 default: | |
| 649 UnimplementedInstruction(); | |
| 650 } | |
| 651 } | |
| 652 assert(mnem != NULL); | |
| 653 AppendToBuffer("%s%c %s,", | |
| 654 mnem, | |
| 655 operand_size_code(), | |
| 656 NameOfCPURegister(rm)); | |
| 657 if (imm8 > 0) { | |
| 658 AppendToBuffer("%d", imm8); | |
| 659 } else { | |
| 660 AppendToBuffer("cl"); | |
| 661 } | |
| 662 } else { | 736 } else { |
| 663 UnimplementedInstruction(); | 737 AppendToBuffer("%d", imm8); |
| 664 } | 738 } |
| 665 return num_bytes; | 739 return num_bytes; |
| 666 } | 740 } |
| 667 | 741 |
| 668 | 742 |
| 669 // Returns number of bytes used, including *data. | 743 // Returns number of bytes used, including *data. |
| 670 int DisassemblerX64::JumpShort(byte* data) { | 744 int DisassemblerX64::JumpShort(byte* data) { |
| 671 assert(*data == 0xEB); | 745 assert(*data == 0xEB); |
| 672 byte b = *(data + 1); | 746 byte b = *(data + 1); |
| 673 byte* dest = data + static_cast<int8_t>(b) + 2; | 747 byte* dest = data + static_cast<int8_t>(b) + 2; |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 709 } | 783 } |
| 710 | 784 |
| 711 | 785 |
| 712 // Returns number of bytes used, including *data. | 786 // Returns number of bytes used, including *data. |
| 713 int DisassemblerX64::FPUInstruction(byte* data) { | 787 int DisassemblerX64::FPUInstruction(byte* data) { |
| 714 byte b1 = *data; | 788 byte b1 = *data; |
| 715 byte b2 = *(data + 1); | 789 byte b2 = *(data + 1); |
| 716 if (b1 == 0xD9) { | 790 if (b1 == 0xD9) { |
| 717 const char* mnem = NULL; | 791 const char* mnem = NULL; |
| 718 switch (b2) { | 792 switch (b2) { |
| 719 case 0xE8: | 793 case 0xE0: |
| 720 mnem = "fld1"; | 794 mnem = "fchs"; |
| 721 break; | |
| 722 case 0xEE: | |
| 723 mnem = "fldz"; | |
| 724 break; | 795 break; |
| 725 case 0xE1: | 796 case 0xE1: |
| 726 mnem = "fabs"; | 797 mnem = "fabs"; |
| 727 break; | 798 break; |
| 728 case 0xE0: | 799 case 0xE4: |
| 729 mnem = "fchs"; | 800 mnem = "ftst"; |
| 730 break; | |
| 731 case 0xF8: | |
| 732 mnem = "fprem"; | |
| 733 break; | 801 break; |
| 734 case 0xF5: | 802 case 0xF5: |
| 735 mnem = "fprem1"; | 803 mnem = "fprem1"; |
| 736 break; | 804 break; |
| 737 case 0xF7: | 805 case 0xF7: |
| 738 mnem = "fincstp"; | 806 mnem = "fincstp"; |
| 739 break; | 807 break; |
| 740 case 0xE4: | 808 case 0xE8: |
| 741 mnem = "ftst"; | 809 mnem = "fld1"; |
| 810 break; |
| 811 case 0xEE: |
| 812 mnem = "fldz"; |
| 813 break; |
| 814 case 0xF8: |
| 815 mnem = "fprem"; |
| 742 break; | 816 break; |
| 743 } | 817 } |
| 744 if (mnem != NULL) { | 818 if (mnem != NULL) { |
| 745 AppendToBuffer("%s", mnem); | 819 AppendToBuffer("%s", mnem); |
| 746 return 2; | 820 return 2; |
| 747 } else if ((b2 & 0xF8) == 0xC8) { | 821 } else if ((b2 & 0xF8) == 0xC8) { |
| 748 AppendToBuffer("fxch st%d", b2 & 0x7); | 822 AppendToBuffer("fxch st%d", b2 & 0x7); |
| 749 return 2; | 823 return 2; |
| 750 } else { | 824 } else { |
| 751 int mod, regop, rm; | 825 int mod, regop, rm; |
| (...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 899 tmp_buffer_pos_ = 0; // starting to write as position 0 | 973 tmp_buffer_pos_ = 0; // starting to write as position 0 |
| 900 byte* data = instr; | 974 byte* data = instr; |
| 901 bool processed = true; // Will be set to false if the current instruction | 975 bool processed = true; // Will be set to false if the current instruction |
| 902 // is not in 'instructions' table. | 976 // is not in 'instructions' table. |
| 903 byte current; | 977 byte current; |
| 904 | 978 |
| 905 // Scan for prefixes. | 979 // Scan for prefixes. |
| 906 while (true) { | 980 while (true) { |
| 907 current = *data; | 981 current = *data; |
| 908 if (current == 0x66) { | 982 if (current == 0x66) { |
| 909 setOperandSizePrefix(current); | 983 // If the sequence is 66 0f, it's not a prefix, but a SSE escape. |
| 984 if (*(data + 1) == 0x0F) break; |
| 910 data++; | 985 data++; |
| 911 } else if ((current & 0xF0) == 0x40) { | 986 } else if ((current & 0xF0) == 0x40) { |
| 912 setRex(current); | 987 setRex(current); |
| 913 if (rex_w()) AppendToBuffer("REX.W "); | 988 if (rex_w()) AppendToBuffer("REX.W "); |
| 914 data++; | 989 data++; |
| 915 } else { | 990 } else { |
| 916 break; | 991 break; |
| 917 } | 992 } |
| 918 } | 993 } |
| 919 | 994 |
| 920 const InstructionDesc& idesc = instruction_table.Get(current); | 995 const InstructionDesc& idesc = instruction_table.Get(current); |
| 996 byte_size_operand_ = idesc.byte_size_operation; |
| 921 switch (idesc.type) { | 997 switch (idesc.type) { |
| 922 case ZERO_OPERANDS_INSTR: | 998 case ZERO_OPERANDS_INSTR: |
| 923 AppendToBuffer(idesc.mnem); | 999 AppendToBuffer(idesc.mnem); |
| 924 data++; | 1000 data++; |
| 925 break; | 1001 break; |
| 926 | 1002 |
| 927 case TWO_OPERANDS_INSTR: | 1003 case TWO_OPERANDS_INSTR: |
| 928 data++; | 1004 data++; |
| 929 data += PrintOperands(idesc.mnem, idesc.op_order_, data); | 1005 data += PrintOperands(idesc.mnem, idesc.op_order_, data); |
| 930 break; | 1006 break; |
| (...skipping 11 matching lines...) Expand all Loading... |
| 942 break; | 1018 break; |
| 943 case PUSHPOP_INSTR: | 1019 case PUSHPOP_INSTR: |
| 944 AppendToBuffer("%s %s", | 1020 AppendToBuffer("%s %s", |
| 945 idesc.mnem, | 1021 idesc.mnem, |
| 946 NameOfCPURegister(base_reg(current & 0x07))); | 1022 NameOfCPURegister(base_reg(current & 0x07))); |
| 947 data++; | 1023 data++; |
| 948 break; | 1024 break; |
| 949 case MOVE_REG_INSTR: { | 1025 case MOVE_REG_INSTR: { |
| 950 byte* addr = NULL; | 1026 byte* addr = NULL; |
| 951 switch (operand_size()) { | 1027 switch (operand_size()) { |
| 952 case 16: | 1028 case WORD_SIZE: |
| 953 addr = reinterpret_cast<byte*>(*reinterpret_cast<int16_t*>(data + 1)); | 1029 addr = reinterpret_cast<byte*>(*reinterpret_cast<int16_t*>(data + 1)); |
| 954 data += 3; | 1030 data += 3; |
| 955 break; | 1031 break; |
| 956 case 32: | 1032 case DOUBLEWORD_SIZE: |
| 957 addr = reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data + 1)); | 1033 addr = reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data + 1)); |
| 958 data += 5; | 1034 data += 5; |
| 959 break; | 1035 break; |
| 960 case 64: | 1036 case QUADWORD_SIZE: |
| 961 addr = reinterpret_cast<byte*>(*reinterpret_cast<int64_t*>(data + 1)); | 1037 addr = reinterpret_cast<byte*>(*reinterpret_cast<int64_t*>(data + 1)); |
| 962 data += 9; | 1038 data += 9; |
| 963 break; | 1039 break; |
| 964 default: | 1040 default: |
| 965 UNREACHABLE(); | 1041 UNREACHABLE(); |
| 966 } | 1042 } |
| 967 AppendToBuffer("mov%c %s,%s", | 1043 AppendToBuffer("mov%c %s,%s", |
| 968 operand_size_code(), | 1044 operand_size_code(), |
| 969 NameOfCPURegister(base_reg(current & 0x07)), | 1045 NameOfCPURegister(base_reg(current & 0x07)), |
| 970 NameOfAddress(addr)); | 1046 NameOfAddress(addr)); |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1005 | 1081 |
| 1006 case 0x69: // fall through | 1082 case 0x69: // fall through |
| 1007 case 0x6B: { | 1083 case 0x6B: { |
| 1008 int mod, regop, rm; | 1084 int mod, regop, rm; |
| 1009 get_modrm(*(data + 1), &mod, ®op, &rm); | 1085 get_modrm(*(data + 1), &mod, ®op, &rm); |
| 1010 int32_t imm = *data == 0x6B ? *(data + 2) | 1086 int32_t imm = *data == 0x6B ? *(data + 2) |
| 1011 : *reinterpret_cast<int32_t*>(data + 2); | 1087 : *reinterpret_cast<int32_t*>(data + 2); |
| 1012 AppendToBuffer("imul %s,%s,0x%x", NameOfCPURegister(regop), | 1088 AppendToBuffer("imul %s,%s,0x%x", NameOfCPURegister(regop), |
| 1013 NameOfCPURegister(rm), imm); | 1089 NameOfCPURegister(rm), imm); |
| 1014 data += 2 + (*data == 0x6B ? 1 : 4); | 1090 data += 2 + (*data == 0x6B ? 1 : 4); |
| 1091 break; |
| 1015 } | 1092 } |
| 1016 break; | |
| 1017 | 1093 |
| 1018 case 0xF6: { | 1094 case 0xF6: { |
| 1019 int mod, regop, rm; | 1095 int mod, regop, rm; |
| 1020 get_modrm(*(data + 1), &mod, ®op, &rm); | 1096 get_modrm(*(data + 1), &mod, ®op, &rm); |
| 1021 if (mod == 3 && regop == 0) { | 1097 if (mod == 3 && regop == 0) { |
| 1022 AppendToBuffer("testb %s,%d", NameOfCPURegister(rm), *(data + 2)); | 1098 AppendToBuffer("testb %s,%d", NameOfCPURegister(rm), *(data + 2)); |
| 1023 } else { | 1099 } else { |
| 1024 UnimplementedInstruction(); | 1100 UnimplementedInstruction(); |
| 1025 } | 1101 } |
| 1026 data += 3; | 1102 data += 3; |
| 1103 break; |
| 1027 } | 1104 } |
| 1028 break; | |
| 1029 | 1105 |
| 1030 case 0x81: // fall through | 1106 case 0x81: // fall through |
| 1031 case 0x83: // 0x81 with sign extension bit set | 1107 case 0x83: // 0x81 with sign extension bit set |
| 1032 data += PrintImmediateOp(data); | 1108 data += PrintImmediateOp(data); |
| 1033 break; | 1109 break; |
| 1034 | 1110 |
| 1035 case 0x0F: { | 1111 case 0x0F: { |
| 1036 byte f0byte = *(data + 1); | 1112 byte f0byte = *(data + 1); |
| 1037 const char* f0mnem = F0Mnem(f0byte); | 1113 const char* f0mnem = F0Mnem(f0byte); |
| 1038 if (f0byte == 0x1F) { | 1114 if (f0byte == 0x1F) { |
| (...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1163 break; | 1239 break; |
| 1164 | 1240 |
| 1165 case 0x90: | 1241 case 0x90: |
| 1166 case 0x91: | 1242 case 0x91: |
| 1167 case 0x92: | 1243 case 0x92: |
| 1168 case 0x93: | 1244 case 0x93: |
| 1169 case 0x94: | 1245 case 0x94: |
| 1170 case 0x95: | 1246 case 0x95: |
| 1171 case 0x96: | 1247 case 0x96: |
| 1172 case 0x97: { | 1248 case 0x97: { |
| 1173 int reg = current & 0x7 | (rex_b() ? 8 : 0); | 1249 int reg = (current & 0x7) | (rex_b() ? 8 : 0); |
| 1174 if (reg == 0) { | 1250 if (reg == 0) { |
| 1175 AppendToBuffer("nop"); // Common name for xchg rax,rax. | 1251 AppendToBuffer("nop"); // Common name for xchg rax,rax. |
| 1176 } else { | 1252 } else { |
| 1177 AppendToBuffer("xchg%c rax, %s", | 1253 AppendToBuffer("xchg%c rax, %s", |
| 1178 operand_size_code(), | 1254 operand_size_code(), |
| 1179 NameOfByteCPURegister(reg)); | 1255 NameOfCPURegister(reg)); |
| 1180 } | 1256 } |
| 1181 } | 1257 } |
| 1182 | 1258 |
| 1183 | 1259 |
| 1184 case 0xFE: { | 1260 case 0xFE: { |
| 1185 data++; | 1261 data++; |
| 1186 int mod, regop, rm; | 1262 int mod, regop, rm; |
| 1187 get_modrm(*data, &mod, ®op, &rm); | 1263 get_modrm(*data, &mod, ®op, &rm); |
| 1188 if (mod == 3 && regop == 1) { | 1264 if (mod == 3 && regop == 1) { |
| 1189 AppendToBuffer("decb %s", NameOfCPURegister(rm)); | 1265 AppendToBuffer("decb %s", NameOfCPURegister(rm)); |
| (...skipping 12 matching lines...) Expand all Loading... |
| 1202 case 0x6A: | 1278 case 0x6A: |
| 1203 AppendToBuffer("push 0x%x", *reinterpret_cast<int8_t*>(data + 1)); | 1279 AppendToBuffer("push 0x%x", *reinterpret_cast<int8_t*>(data + 1)); |
| 1204 data += 2; | 1280 data += 2; |
| 1205 break; | 1281 break; |
| 1206 | 1282 |
| 1207 case 0xA8: | 1283 case 0xA8: |
| 1208 AppendToBuffer("test al,0x%x", *reinterpret_cast<uint8_t*>(data + 1)); | 1284 AppendToBuffer("test al,0x%x", *reinterpret_cast<uint8_t*>(data + 1)); |
| 1209 data += 2; | 1285 data += 2; |
| 1210 break; | 1286 break; |
| 1211 | 1287 |
| 1212 case 0xA9: | 1288 case 0xA9: { |
| 1213 AppendToBuffer("test%c rax,0x%x", // CHECKME! | 1289 int64_t value; |
| 1290 switch (operand_size()) { |
| 1291 case WORD_SIZE: |
| 1292 value = *reinterpret_cast<uint16_t*>(data + 1); |
| 1293 data += 3; |
| 1294 break; |
| 1295 case DOUBLEWORD_SIZE: |
| 1296 value = *reinterpret_cast<uint32_t*>(data + 1); |
| 1297 data += 5; |
| 1298 break; |
| 1299 case QUADWORD_SIZE: |
| 1300 value = *reinterpret_cast<int32_t*>(data + 1); |
| 1301 data += 5; |
| 1302 break; |
| 1303 default: |
| 1304 UNREACHABLE(); |
| 1305 } |
| 1306 break; |
| 1307 AppendToBuffer("test%c rax,0x%"V8_PTR_PREFIX"ux", |
| 1214 operand_size_code(), | 1308 operand_size_code(), |
| 1215 *reinterpret_cast<int32_t*>(data + 1)); | 1309 value); |
| 1216 data += 5; | 1310 } |
| 1217 break; | |
| 1218 | |
| 1219 case 0xD1: // fall through | 1311 case 0xD1: // fall through |
| 1220 case 0xD3: // fall through | 1312 case 0xD3: // fall through |
| 1221 case 0xC1: | 1313 case 0xC1: |
| 1222 data += D1D3C1Instruction(data); | 1314 data += ShiftInstruction(data); |
| 1315 break; |
| 1316 case 0xD0: // fall through |
| 1317 case 0xD2: // fall through |
| 1318 case 0xC0: |
| 1319 byte_size_operand_ = true; |
| 1320 data += ShiftInstruction(data); |
| 1223 break; | 1321 break; |
| 1224 | 1322 |
| 1225 case 0xD9: // fall through | 1323 case 0xD9: // fall through |
| 1226 case 0xDA: // fall through | 1324 case 0xDA: // fall through |
| 1227 case 0xDB: // fall through | 1325 case 0xDB: // fall through |
| 1228 case 0xDC: // fall through | 1326 case 0xDC: // fall through |
| 1229 case 0xDD: // fall through | 1327 case 0xDD: // fall through |
| 1230 case 0xDE: // fall through | 1328 case 0xDE: // fall through |
| 1231 case 0xDF: | 1329 case 0xDF: |
| 1232 data += FPUInstruction(data); | 1330 data += FPUInstruction(data); |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1282 NameOfXMMRegister(rm)); | 1380 NameOfXMMRegister(rm)); |
| 1283 data++; | 1381 data++; |
| 1284 } | 1382 } |
| 1285 } | 1383 } |
| 1286 } else { | 1384 } else { |
| 1287 UnimplementedInstruction(); | 1385 UnimplementedInstruction(); |
| 1288 } | 1386 } |
| 1289 break; | 1387 break; |
| 1290 | 1388 |
| 1291 case 0xF3: | 1389 case 0xF3: |
| 1292 if (*(data + 1) == 0x0F && *(data + 2) == 0x2C) { | 1390 if (*(data + 1) == 0x0F) { |
| 1293 data += 3; | 1391 if (*(data + 2) == 0x2C) { |
| 1294 data += PrintOperands("cvttss2si", REG_OPER_OP_ORDER, data); | 1392 data += 3; |
| 1393 data += PrintOperands("cvttss2si", REG_OPER_OP_ORDER, data); |
| 1394 } else { |
| 1395 UnimplementedInstruction(); |
| 1396 data += 1; |
| 1397 } |
| 1295 } else { | 1398 } else { |
| 1296 UnimplementedInstruction(); | 1399 UnimplementedInstruction(); |
| 1400 data += 1; |
| 1297 } | 1401 } |
| 1298 break; | 1402 break; |
| 1299 | 1403 |
| 1300 case 0xF7: | 1404 case 0xF7: |
| 1301 data += F7Instruction(data); | 1405 data += F7Instruction(data); |
| 1302 break; | 1406 break; |
| 1303 | 1407 |
| 1304 default: | 1408 default: |
| 1305 UnimplementedInstruction(); | 1409 UnimplementedInstruction(); |
| 1410 data += 1; |
| 1306 } | 1411 } |
| 1307 } // !processed | 1412 } // !processed |
| 1308 | 1413 |
| 1309 if (tmp_buffer_pos_ < sizeof tmp_buffer_) { | 1414 if (tmp_buffer_pos_ < sizeof tmp_buffer_) { |
| 1310 tmp_buffer_[tmp_buffer_pos_] = '\0'; | 1415 tmp_buffer_[tmp_buffer_pos_] = '\0'; |
| 1311 } | 1416 } |
| 1312 | 1417 |
| 1313 int instr_len = data - instr; | 1418 int instr_len = data - instr; |
| 1314 ASSERT(instr_len > 0); // Ensure progress. | 1419 ASSERT(instr_len > 0); // Ensure progress. |
| 1315 | 1420 |
| (...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1423 fprintf(f, "%02x", *bp); | 1528 fprintf(f, "%02x", *bp); |
| 1424 } | 1529 } |
| 1425 for (int i = 6 - (pc - prev_pc); i >= 0; i--) { | 1530 for (int i = 6 - (pc - prev_pc); i >= 0; i--) { |
| 1426 fprintf(f, " "); | 1531 fprintf(f, " "); |
| 1427 } | 1532 } |
| 1428 fprintf(f, " %s\n", buffer.start()); | 1533 fprintf(f, " %s\n", buffer.start()); |
| 1429 } | 1534 } |
| 1430 } | 1535 } |
| 1431 | 1536 |
| 1432 } // namespace disasm | 1537 } // namespace disasm |
| OLD | NEW |