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 |