blob: d1c869a2c2352295b30c1d60515b45a087b90e6c [file] [log] [blame]
Steve Blocka7e24c12009-10-30 11:49:00 +00001// Copyright 2007-2008 the V8 project authors. All rights reserved.
2// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include <assert.h>
29#include <stdio.h>
30#include <stdarg.h>
31
32#include "v8.h"
Leon Clarkef7060e22010-06-03 12:02:55 +010033
34#if defined(V8_TARGET_ARCH_IA32)
35
Steve Blocka7e24c12009-10-30 11:49:00 +000036#include "disasm.h"
37
38namespace disasm {
39
40enum OperandOrder {
41 UNSET_OP_ORDER = 0,
42 REG_OPER_OP_ORDER,
43 OPER_REG_OP_ORDER
44};
45
46
47//------------------------------------------------------------------
48// Tables
49//------------------------------------------------------------------
50struct ByteMnemonic {
51 int b; // -1 terminates, otherwise must be in range (0..255)
52 const char* mnem;
53 OperandOrder op_order_;
54};
55
56
57static ByteMnemonic two_operands_instr[] = {
58 {0x03, "add", REG_OPER_OP_ORDER},
Steve Blocka7e24c12009-10-30 11:49:00 +000059 {0x09, "or", OPER_REG_OP_ORDER},
60 {0x0B, "or", REG_OPER_OP_ORDER},
61 {0x1B, "sbb", REG_OPER_OP_ORDER},
Leon Clarked91b9f72010-01-27 17:25:45 +000062 {0x21, "and", OPER_REG_OP_ORDER},
63 {0x23, "and", REG_OPER_OP_ORDER},
Steve Blocka7e24c12009-10-30 11:49:00 +000064 {0x29, "sub", OPER_REG_OP_ORDER},
Leon Clarkee46be812010-01-19 14:06:41 +000065 {0x2A, "subb", REG_OPER_OP_ORDER},
Steve Blocka7e24c12009-10-30 11:49:00 +000066 {0x2B, "sub", REG_OPER_OP_ORDER},
Leon Clarkeeab96aa2010-01-27 16:31:12 +000067 {0x31, "xor", OPER_REG_OP_ORDER},
68 {0x33, "xor", REG_OPER_OP_ORDER},
Leon Clarked91b9f72010-01-27 17:25:45 +000069 {0x38, "cmpb", OPER_REG_OP_ORDER},
70 {0x3A, "cmpb", REG_OPER_OP_ORDER},
71 {0x3B, "cmp", REG_OPER_OP_ORDER},
72 {0x84, "test_b", REG_OPER_OP_ORDER},
73 {0x85, "test", REG_OPER_OP_ORDER},
Steve Blocka7e24c12009-10-30 11:49:00 +000074 {0x87, "xchg", REG_OPER_OP_ORDER},
75 {0x8A, "mov_b", REG_OPER_OP_ORDER},
76 {0x8B, "mov", REG_OPER_OP_ORDER},
Leon Clarked91b9f72010-01-27 17:25:45 +000077 {0x8D, "lea", REG_OPER_OP_ORDER},
Steve Blocka7e24c12009-10-30 11:49:00 +000078 {-1, "", UNSET_OP_ORDER}
79};
80
81
82static ByteMnemonic zero_operands_instr[] = {
83 {0xC3, "ret", UNSET_OP_ORDER},
84 {0xC9, "leave", UNSET_OP_ORDER},
85 {0x90, "nop", UNSET_OP_ORDER},
86 {0xF4, "hlt", UNSET_OP_ORDER},
87 {0xCC, "int3", UNSET_OP_ORDER},
88 {0x60, "pushad", UNSET_OP_ORDER},
89 {0x61, "popad", UNSET_OP_ORDER},
90 {0x9C, "pushfd", UNSET_OP_ORDER},
91 {0x9D, "popfd", UNSET_OP_ORDER},
92 {0x9E, "sahf", UNSET_OP_ORDER},
93 {0x99, "cdq", UNSET_OP_ORDER},
94 {0x9B, "fwait", UNSET_OP_ORDER},
Steve Block6ded16b2010-05-10 14:33:55 +010095 {0xFC, "cld", UNSET_OP_ORDER},
Leon Clarkef7060e22010-06-03 12:02:55 +010096 {0xAB, "stos", UNSET_OP_ORDER},
Steve Blocka7e24c12009-10-30 11:49:00 +000097 {-1, "", UNSET_OP_ORDER}
98};
99
100
101static ByteMnemonic call_jump_instr[] = {
102 {0xE8, "call", UNSET_OP_ORDER},
103 {0xE9, "jmp", UNSET_OP_ORDER},
104 {-1, "", UNSET_OP_ORDER}
105};
106
107
108static ByteMnemonic short_immediate_instr[] = {
109 {0x05, "add", UNSET_OP_ORDER},
110 {0x0D, "or", UNSET_OP_ORDER},
111 {0x15, "adc", UNSET_OP_ORDER},
112 {0x25, "and", UNSET_OP_ORDER},
113 {0x2D, "sub", UNSET_OP_ORDER},
114 {0x35, "xor", UNSET_OP_ORDER},
115 {0x3D, "cmp", UNSET_OP_ORDER},
116 {-1, "", UNSET_OP_ORDER}
117};
118
119
120static const char* jump_conditional_mnem[] = {
121 /*0*/ "jo", "jno", "jc", "jnc",
122 /*4*/ "jz", "jnz", "jna", "ja",
123 /*8*/ "js", "jns", "jpe", "jpo",
124 /*12*/ "jl", "jnl", "jng", "jg"
125};
126
127
128static const char* set_conditional_mnem[] = {
129 /*0*/ "seto", "setno", "setc", "setnc",
130 /*4*/ "setz", "setnz", "setna", "seta",
131 /*8*/ "sets", "setns", "setpe", "setpo",
132 /*12*/ "setl", "setnl", "setng", "setg"
133};
134
135
Steve Block3ce2e202009-11-05 08:53:23 +0000136static const char* conditional_move_mnem[] = {
137 /*0*/ "cmovo", "cmovno", "cmovc", "cmovnc",
138 /*4*/ "cmovz", "cmovnz", "cmovna", "cmova",
139 /*8*/ "cmovs", "cmovns", "cmovpe", "cmovpo",
140 /*12*/ "cmovl", "cmovnl", "cmovng", "cmovg"
141};
142
143
Steve Blocka7e24c12009-10-30 11:49:00 +0000144enum InstructionType {
145 NO_INSTR,
146 ZERO_OPERANDS_INSTR,
147 TWO_OPERANDS_INSTR,
148 JUMP_CONDITIONAL_SHORT_INSTR,
149 REGISTER_INSTR,
150 MOVE_REG_INSTR,
151 CALL_JUMP_INSTR,
152 SHORT_IMMEDIATE_INSTR
153};
154
155
156struct InstructionDesc {
157 const char* mnem;
158 InstructionType type;
159 OperandOrder op_order_;
160};
161
162
163class InstructionTable {
164 public:
165 InstructionTable();
166 const InstructionDesc& Get(byte x) const { return instructions_[x]; }
167
168 private:
169 InstructionDesc instructions_[256];
170 void Clear();
171 void Init();
172 void CopyTable(ByteMnemonic bm[], InstructionType type);
173 void SetTableRange(InstructionType type,
174 byte start,
175 byte end,
176 const char* mnem);
177 void AddJumpConditionalShort();
178};
179
180
181InstructionTable::InstructionTable() {
182 Clear();
183 Init();
184}
185
186
187void InstructionTable::Clear() {
188 for (int i = 0; i < 256; i++) {
189 instructions_[i].mnem = "";
190 instructions_[i].type = NO_INSTR;
191 instructions_[i].op_order_ = UNSET_OP_ORDER;
192 }
193}
194
195
196void InstructionTable::Init() {
197 CopyTable(two_operands_instr, TWO_OPERANDS_INSTR);
198 CopyTable(zero_operands_instr, ZERO_OPERANDS_INSTR);
199 CopyTable(call_jump_instr, CALL_JUMP_INSTR);
200 CopyTable(short_immediate_instr, SHORT_IMMEDIATE_INSTR);
201 AddJumpConditionalShort();
202 SetTableRange(REGISTER_INSTR, 0x40, 0x47, "inc");
203 SetTableRange(REGISTER_INSTR, 0x48, 0x4F, "dec");
204 SetTableRange(REGISTER_INSTR, 0x50, 0x57, "push");
205 SetTableRange(REGISTER_INSTR, 0x58, 0x5F, "pop");
206 SetTableRange(REGISTER_INSTR, 0x91, 0x97, "xchg eax,"); // 0x90 is nop.
207 SetTableRange(MOVE_REG_INSTR, 0xB8, 0xBF, "mov");
208}
209
210
211void InstructionTable::CopyTable(ByteMnemonic bm[], InstructionType type) {
212 for (int i = 0; bm[i].b >= 0; i++) {
213 InstructionDesc* id = &instructions_[bm[i].b];
214 id->mnem = bm[i].mnem;
215 id->op_order_ = bm[i].op_order_;
Steve Blockd0582a62009-12-15 09:54:21 +0000216 ASSERT_EQ(NO_INSTR, id->type); // Information not already entered.
Steve Blocka7e24c12009-10-30 11:49:00 +0000217 id->type = type;
218 }
219}
220
221
222void InstructionTable::SetTableRange(InstructionType type,
223 byte start,
224 byte end,
225 const char* mnem) {
226 for (byte b = start; b <= end; b++) {
227 InstructionDesc* id = &instructions_[b];
Steve Blockd0582a62009-12-15 09:54:21 +0000228 ASSERT_EQ(NO_INSTR, id->type); // Information not already entered.
Steve Blocka7e24c12009-10-30 11:49:00 +0000229 id->mnem = mnem;
230 id->type = type;
231 }
232}
233
234
235void InstructionTable::AddJumpConditionalShort() {
236 for (byte b = 0x70; b <= 0x7F; b++) {
237 InstructionDesc* id = &instructions_[b];
Steve Blockd0582a62009-12-15 09:54:21 +0000238 ASSERT_EQ(NO_INSTR, id->type); // Information not already entered.
Steve Blocka7e24c12009-10-30 11:49:00 +0000239 id->mnem = jump_conditional_mnem[b & 0x0F];
240 id->type = JUMP_CONDITIONAL_SHORT_INSTR;
241 }
242}
243
244
245static InstructionTable instruction_table;
246
247
248// The IA32 disassembler implementation.
249class DisassemblerIA32 {
250 public:
251 DisassemblerIA32(const NameConverter& converter,
252 bool abort_on_unimplemented = true)
253 : converter_(converter),
254 tmp_buffer_pos_(0),
255 abort_on_unimplemented_(abort_on_unimplemented) {
256 tmp_buffer_[0] = '\0';
257 }
258
259 virtual ~DisassemblerIA32() {}
260
261 // Writes one disassembled instruction into 'buffer' (0-terminated).
262 // Returns the length of the disassembled machine instruction in bytes.
263 int InstructionDecode(v8::internal::Vector<char> buffer, byte* instruction);
264
265 private:
266 const NameConverter& converter_;
267 v8::internal::EmbeddedVector<char, 128> tmp_buffer_;
268 unsigned int tmp_buffer_pos_;
269 bool abort_on_unimplemented_;
270
271
272 enum {
273 eax = 0,
274 ecx = 1,
275 edx = 2,
276 ebx = 3,
277 esp = 4,
278 ebp = 5,
279 esi = 6,
280 edi = 7
281 };
282
283
Steve Blockd0582a62009-12-15 09:54:21 +0000284 enum ShiftOpcodeExtension {
285 kROL = 0,
286 kROR = 1,
287 kRCL = 2,
288 kRCR = 3,
289 kSHL = 4,
290 KSHR = 5,
291 kSAR = 7
292 };
293
294
Steve Blocka7e24c12009-10-30 11:49:00 +0000295 const char* NameOfCPURegister(int reg) const {
296 return converter_.NameOfCPURegister(reg);
297 }
298
299
300 const char* NameOfByteCPURegister(int reg) const {
301 return converter_.NameOfByteCPURegister(reg);
302 }
303
304
305 const char* NameOfXMMRegister(int reg) const {
306 return converter_.NameOfXMMRegister(reg);
307 }
308
309
310 const char* NameOfAddress(byte* addr) const {
311 return converter_.NameOfAddress(addr);
312 }
313
314
315 // Disassembler helper functions.
316 static void get_modrm(byte data, int* mod, int* regop, int* rm) {
317 *mod = (data >> 6) & 3;
318 *regop = (data & 0x38) >> 3;
319 *rm = data & 7;
320 }
321
322
323 static void get_sib(byte data, int* scale, int* index, int* base) {
324 *scale = (data >> 6) & 3;
325 *index = (data >> 3) & 7;
326 *base = data & 7;
327 }
328
329 typedef const char* (DisassemblerIA32::*RegisterNameMapping)(int reg) const;
330
331 int PrintRightOperandHelper(byte* modrmp, RegisterNameMapping register_name);
332 int PrintRightOperand(byte* modrmp);
333 int PrintRightByteOperand(byte* modrmp);
Steve Block44f0eee2011-05-26 01:26:41 +0100334 int PrintRightXMMOperand(byte* modrmp);
Steve Blocka7e24c12009-10-30 11:49:00 +0000335 int PrintOperands(const char* mnem, OperandOrder op_order, byte* data);
336 int PrintImmediateOp(byte* data);
337 int F7Instruction(byte* data);
338 int D1D3C1Instruction(byte* data);
339 int JumpShort(byte* data);
340 int JumpConditional(byte* data, const char* comment);
341 int JumpConditionalShort(byte* data, const char* comment);
342 int SetCC(byte* data);
Steve Block3ce2e202009-11-05 08:53:23 +0000343 int CMov(byte* data);
Steve Blocka7e24c12009-10-30 11:49:00 +0000344 int FPUInstruction(byte* data);
Steve Blockd0582a62009-12-15 09:54:21 +0000345 int MemoryFPUInstruction(int escape_opcode, int regop, byte* modrm_start);
346 int RegisterFPUInstruction(int escape_opcode, byte modrm_byte);
Steve Blocka7e24c12009-10-30 11:49:00 +0000347 void AppendToBuffer(const char* format, ...);
348
349
350 void UnimplementedInstruction() {
351 if (abort_on_unimplemented_) {
352 UNIMPLEMENTED();
353 } else {
354 AppendToBuffer("'Unimplemented Instruction'");
355 }
356 }
357};
358
359
360void DisassemblerIA32::AppendToBuffer(const char* format, ...) {
361 v8::internal::Vector<char> buf = tmp_buffer_ + tmp_buffer_pos_;
362 va_list args;
363 va_start(args, format);
364 int result = v8::internal::OS::VSNPrintF(buf, format, args);
365 va_end(args);
366 tmp_buffer_pos_ += result;
367}
368
369int DisassemblerIA32::PrintRightOperandHelper(
370 byte* modrmp,
Steve Block44f0eee2011-05-26 01:26:41 +0100371 RegisterNameMapping direct_register_name) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000372 int mod, regop, rm;
373 get_modrm(*modrmp, &mod, &regop, &rm);
Steve Block44f0eee2011-05-26 01:26:41 +0100374 RegisterNameMapping register_name = (mod == 3) ? direct_register_name :
375 &DisassemblerIA32::NameOfCPURegister;
Steve Blocka7e24c12009-10-30 11:49:00 +0000376 switch (mod) {
377 case 0:
378 if (rm == ebp) {
379 int32_t disp = *reinterpret_cast<int32_t*>(modrmp+1);
380 AppendToBuffer("[0x%x]", disp);
381 return 5;
382 } else if (rm == esp) {
383 byte sib = *(modrmp + 1);
384 int scale, index, base;
385 get_sib(sib, &scale, &index, &base);
386 if (index == esp && base == esp && scale == 0 /*times_1*/) {
387 AppendToBuffer("[%s]", (this->*register_name)(rm));
388 return 2;
389 } else if (base == ebp) {
390 int32_t disp = *reinterpret_cast<int32_t*>(modrmp + 2);
391 AppendToBuffer("[%s*%d+0x%x]",
392 (this->*register_name)(index),
393 1 << scale,
394 disp);
395 return 6;
396 } else if (index != esp && base != ebp) {
397 // [base+index*scale]
398 AppendToBuffer("[%s+%s*%d]",
399 (this->*register_name)(base),
400 (this->*register_name)(index),
401 1 << scale);
402 return 2;
403 } else {
404 UnimplementedInstruction();
405 return 1;
406 }
407 } else {
408 AppendToBuffer("[%s]", (this->*register_name)(rm));
409 return 1;
410 }
411 break;
412 case 1: // fall through
413 case 2:
414 if (rm == esp) {
415 byte sib = *(modrmp + 1);
416 int scale, index, base;
417 get_sib(sib, &scale, &index, &base);
418 int disp =
419 mod == 2 ? *reinterpret_cast<int32_t*>(modrmp + 2) : *(modrmp + 2);
420 if (index == base && index == rm /*esp*/ && scale == 0 /*times_1*/) {
421 AppendToBuffer("[%s+0x%x]", (this->*register_name)(rm), disp);
422 } else {
423 AppendToBuffer("[%s+%s*%d+0x%x]",
424 (this->*register_name)(base),
425 (this->*register_name)(index),
426 1 << scale,
427 disp);
428 }
429 return mod == 2 ? 6 : 3;
430 } else {
431 // No sib.
432 int disp =
433 mod == 2 ? *reinterpret_cast<int32_t*>(modrmp + 1) : *(modrmp + 1);
434 AppendToBuffer("[%s+0x%x]", (this->*register_name)(rm), disp);
435 return mod == 2 ? 5 : 2;
436 }
437 break;
438 case 3:
439 AppendToBuffer("%s", (this->*register_name)(rm));
440 return 1;
441 default:
442 UnimplementedInstruction();
443 return 1;
444 }
445 UNREACHABLE();
446}
447
448
449int DisassemblerIA32::PrintRightOperand(byte* modrmp) {
450 return PrintRightOperandHelper(modrmp, &DisassemblerIA32::NameOfCPURegister);
451}
452
453
454int DisassemblerIA32::PrintRightByteOperand(byte* modrmp) {
455 return PrintRightOperandHelper(modrmp,
456 &DisassemblerIA32::NameOfByteCPURegister);
457}
458
459
Steve Block44f0eee2011-05-26 01:26:41 +0100460int DisassemblerIA32::PrintRightXMMOperand(byte* modrmp) {
461 return PrintRightOperandHelper(modrmp,
462 &DisassemblerIA32::NameOfXMMRegister);
463}
464
465
Steve Blocka7e24c12009-10-30 11:49:00 +0000466// Returns number of bytes used including the current *data.
467// Writes instruction's mnemonic, left and right operands to 'tmp_buffer_'.
468int DisassemblerIA32::PrintOperands(const char* mnem,
469 OperandOrder op_order,
470 byte* data) {
471 byte modrm = *data;
472 int mod, regop, rm;
473 get_modrm(modrm, &mod, &regop, &rm);
474 int advance = 0;
475 switch (op_order) {
476 case REG_OPER_OP_ORDER: {
477 AppendToBuffer("%s %s,", mnem, NameOfCPURegister(regop));
478 advance = PrintRightOperand(data);
479 break;
480 }
481 case OPER_REG_OP_ORDER: {
482 AppendToBuffer("%s ", mnem);
483 advance = PrintRightOperand(data);
484 AppendToBuffer(",%s", NameOfCPURegister(regop));
485 break;
486 }
487 default:
488 UNREACHABLE();
489 break;
490 }
491 return advance;
492}
493
494
495// Returns number of bytes used by machine instruction, including *data byte.
496// Writes immediate instructions to 'tmp_buffer_'.
497int DisassemblerIA32::PrintImmediateOp(byte* data) {
498 bool sign_extension_bit = (*data & 0x02) != 0;
499 byte modrm = *(data+1);
500 int mod, regop, rm;
501 get_modrm(modrm, &mod, &regop, &rm);
502 const char* mnem = "Imm???";
503 switch (regop) {
504 case 0: mnem = "add"; break;
505 case 1: mnem = "or"; break;
506 case 2: mnem = "adc"; break;
507 case 4: mnem = "and"; break;
508 case 5: mnem = "sub"; break;
509 case 6: mnem = "xor"; break;
510 case 7: mnem = "cmp"; break;
511 default: UnimplementedInstruction();
512 }
513 AppendToBuffer("%s ", mnem);
514 int count = PrintRightOperand(data+1);
515 if (sign_extension_bit) {
516 AppendToBuffer(",0x%x", *(data + 1 + count));
517 return 1 + count + 1 /*int8*/;
518 } else {
519 AppendToBuffer(",0x%x", *reinterpret_cast<int32_t*>(data + 1 + count));
520 return 1 + count + 4 /*int32_t*/;
521 }
522}
523
524
525// Returns number of bytes used, including *data.
526int DisassemblerIA32::F7Instruction(byte* data) {
Steve Blockd0582a62009-12-15 09:54:21 +0000527 ASSERT_EQ(0xF7, *data);
Steve Blocka7e24c12009-10-30 11:49:00 +0000528 byte modrm = *(data+1);
529 int mod, regop, rm;
530 get_modrm(modrm, &mod, &regop, &rm);
531 if (mod == 3 && regop != 0) {
532 const char* mnem = NULL;
533 switch (regop) {
534 case 2: mnem = "not"; break;
535 case 3: mnem = "neg"; break;
536 case 4: mnem = "mul"; break;
537 case 7: mnem = "idiv"; break;
538 default: UnimplementedInstruction();
539 }
540 AppendToBuffer("%s %s", mnem, NameOfCPURegister(rm));
541 return 2;
542 } else if (mod == 3 && regop == eax) {
543 int32_t imm = *reinterpret_cast<int32_t*>(data+2);
544 AppendToBuffer("test %s,0x%x", NameOfCPURegister(rm), imm);
545 return 6;
546 } else if (regop == eax) {
547 AppendToBuffer("test ");
548 int count = PrintRightOperand(data+1);
549 int32_t imm = *reinterpret_cast<int32_t*>(data+1+count);
550 AppendToBuffer(",0x%x", imm);
551 return 1+count+4 /*int32_t*/;
552 } else {
553 UnimplementedInstruction();
554 return 2;
555 }
556}
557
558int DisassemblerIA32::D1D3C1Instruction(byte* data) {
559 byte op = *data;
Steve Blockd0582a62009-12-15 09:54:21 +0000560 ASSERT(op == 0xD1 || op == 0xD3 || op == 0xC1);
Steve Blocka7e24c12009-10-30 11:49:00 +0000561 byte modrm = *(data+1);
562 int mod, regop, rm;
563 get_modrm(modrm, &mod, &regop, &rm);
564 int imm8 = -1;
565 int num_bytes = 2;
566 if (mod == 3) {
567 const char* mnem = NULL;
Steve Blockd0582a62009-12-15 09:54:21 +0000568 switch (regop) {
569 case kROL: mnem = "rol"; break;
570 case kROR: mnem = "ror"; break;
571 case kRCL: mnem = "rcl"; break;
Iain Merrick75681382010-08-19 15:07:18 +0100572 case kRCR: mnem = "rcr"; break;
Steve Blockd0582a62009-12-15 09:54:21 +0000573 case kSHL: mnem = "shl"; break;
574 case KSHR: mnem = "shr"; break;
575 case kSAR: mnem = "sar"; break;
576 default: UnimplementedInstruction();
577 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000578 if (op == 0xD1) {
579 imm8 = 1;
Steve Blocka7e24c12009-10-30 11:49:00 +0000580 } else if (op == 0xC1) {
581 imm8 = *(data+2);
582 num_bytes = 3;
Steve Blocka7e24c12009-10-30 11:49:00 +0000583 } else if (op == 0xD3) {
Steve Blockd0582a62009-12-15 09:54:21 +0000584 // Shift/rotate by cl.
Steve Blocka7e24c12009-10-30 11:49:00 +0000585 }
Steve Blockd0582a62009-12-15 09:54:21 +0000586 ASSERT_NE(NULL, mnem);
Steve Blocka7e24c12009-10-30 11:49:00 +0000587 AppendToBuffer("%s %s,", mnem, NameOfCPURegister(rm));
588 if (imm8 > 0) {
589 AppendToBuffer("%d", imm8);
590 } else {
591 AppendToBuffer("cl");
592 }
593 } else {
594 UnimplementedInstruction();
595 }
596 return num_bytes;
597}
598
599
600// Returns number of bytes used, including *data.
601int DisassemblerIA32::JumpShort(byte* data) {
Steve Blockd0582a62009-12-15 09:54:21 +0000602 ASSERT_EQ(0xEB, *data);
Steve Blocka7e24c12009-10-30 11:49:00 +0000603 byte b = *(data+1);
604 byte* dest = data + static_cast<int8_t>(b) + 2;
605 AppendToBuffer("jmp %s", NameOfAddress(dest));
606 return 2;
607}
608
609
610// Returns number of bytes used, including *data.
611int DisassemblerIA32::JumpConditional(byte* data, const char* comment) {
Steve Blockd0582a62009-12-15 09:54:21 +0000612 ASSERT_EQ(0x0F, *data);
Steve Blocka7e24c12009-10-30 11:49:00 +0000613 byte cond = *(data+1) & 0x0F;
614 byte* dest = data + *reinterpret_cast<int32_t*>(data+2) + 6;
615 const char* mnem = jump_conditional_mnem[cond];
616 AppendToBuffer("%s %s", mnem, NameOfAddress(dest));
617 if (comment != NULL) {
618 AppendToBuffer(", %s", comment);
619 }
620 return 6; // includes 0x0F
621}
622
623
624// Returns number of bytes used, including *data.
625int DisassemblerIA32::JumpConditionalShort(byte* data, const char* comment) {
626 byte cond = *data & 0x0F;
627 byte b = *(data+1);
628 byte* dest = data + static_cast<int8_t>(b) + 2;
629 const char* mnem = jump_conditional_mnem[cond];
630 AppendToBuffer("%s %s", mnem, NameOfAddress(dest));
631 if (comment != NULL) {
632 AppendToBuffer(", %s", comment);
633 }
634 return 2;
635}
636
637
638// Returns number of bytes used, including *data.
639int DisassemblerIA32::SetCC(byte* data) {
Steve Blockd0582a62009-12-15 09:54:21 +0000640 ASSERT_EQ(0x0F, *data);
Steve Blocka7e24c12009-10-30 11:49:00 +0000641 byte cond = *(data+1) & 0x0F;
642 const char* mnem = set_conditional_mnem[cond];
643 AppendToBuffer("%s ", mnem);
644 PrintRightByteOperand(data+2);
Steve Blockd0582a62009-12-15 09:54:21 +0000645 return 3; // Includes 0x0F.
Steve Blocka7e24c12009-10-30 11:49:00 +0000646}
647
648
649// Returns number of bytes used, including *data.
Steve Block3ce2e202009-11-05 08:53:23 +0000650int DisassemblerIA32::CMov(byte* data) {
Steve Blockd0582a62009-12-15 09:54:21 +0000651 ASSERT_EQ(0x0F, *data);
Steve Block3ce2e202009-11-05 08:53:23 +0000652 byte cond = *(data + 1) & 0x0F;
653 const char* mnem = conditional_move_mnem[cond];
654 int op_size = PrintOperands(mnem, REG_OPER_OP_ORDER, data + 2);
655 return 2 + op_size; // includes 0x0F
656}
657
658
659// Returns number of bytes used, including *data.
Steve Blocka7e24c12009-10-30 11:49:00 +0000660int DisassemblerIA32::FPUInstruction(byte* data) {
Steve Blockd0582a62009-12-15 09:54:21 +0000661 byte escape_opcode = *data;
662 ASSERT_EQ(0xD8, escape_opcode & 0xF8);
663 byte modrm_byte = *(data+1);
664
665 if (modrm_byte >= 0xC0) {
666 return RegisterFPUInstruction(escape_opcode, modrm_byte);
667 } else {
668 return MemoryFPUInstruction(escape_opcode, modrm_byte, data+1);
Steve Blocka7e24c12009-10-30 11:49:00 +0000669 }
Steve Blockd0582a62009-12-15 09:54:21 +0000670}
671
672int DisassemblerIA32::MemoryFPUInstruction(int escape_opcode,
673 int modrm_byte,
674 byte* modrm_start) {
675 const char* mnem = "?";
676 int regop = (modrm_byte >> 3) & 0x7; // reg/op field of modrm byte.
677 switch (escape_opcode) {
678 case 0xD9: switch (regop) {
679 case 0: mnem = "fld_s"; break;
680 case 3: mnem = "fstp_s"; break;
681 case 7: mnem = "fstcw"; break;
682 default: UnimplementedInstruction();
683 }
684 break;
685
686 case 0xDB: switch (regop) {
687 case 0: mnem = "fild_s"; break;
688 case 1: mnem = "fisttp_s"; break;
689 case 2: mnem = "fist_s"; break;
690 case 3: mnem = "fistp_s"; break;
691 default: UnimplementedInstruction();
692 }
693 break;
694
695 case 0xDD: switch (regop) {
696 case 0: mnem = "fld_d"; break;
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100697 case 1: mnem = "fisttp_d"; break;
698 case 2: mnem = "fst_d"; break;
Steve Blockd0582a62009-12-15 09:54:21 +0000699 case 3: mnem = "fstp_d"; break;
700 default: UnimplementedInstruction();
701 }
702 break;
703
704 case 0xDF: switch (regop) {
705 case 5: mnem = "fild_d"; break;
706 case 7: mnem = "fistp_d"; break;
707 default: UnimplementedInstruction();
708 }
709 break;
710
711 default: UnimplementedInstruction();
712 }
713 AppendToBuffer("%s ", mnem);
714 int count = PrintRightOperand(modrm_start);
715 return count + 1;
716}
717
718int DisassemblerIA32::RegisterFPUInstruction(int escape_opcode,
719 byte modrm_byte) {
720 bool has_register = false; // Is the FPU register encoded in modrm_byte?
721 const char* mnem = "?";
722
723 switch (escape_opcode) {
724 case 0xD8:
725 UnimplementedInstruction();
726 break;
727
728 case 0xD9:
729 switch (modrm_byte & 0xF8) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100730 case 0xC0:
731 mnem = "fld";
732 has_register = true;
733 break;
Steve Blockd0582a62009-12-15 09:54:21 +0000734 case 0xC8:
735 mnem = "fxch";
736 has_register = true;
737 break;
738 default:
739 switch (modrm_byte) {
740 case 0xE0: mnem = "fchs"; break;
741 case 0xE1: mnem = "fabs"; break;
742 case 0xE4: mnem = "ftst"; break;
743 case 0xE8: mnem = "fld1"; break;
Andrei Popescu402d9372010-02-26 13:31:12 +0000744 case 0xEB: mnem = "fldpi"; break;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100745 case 0xED: mnem = "fldln2"; break;
Steve Blockd0582a62009-12-15 09:54:21 +0000746 case 0xEE: mnem = "fldz"; break;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100747 case 0xF1: mnem = "fyl2x"; break;
Steve Blockd0582a62009-12-15 09:54:21 +0000748 case 0xF5: mnem = "fprem1"; break;
749 case 0xF7: mnem = "fincstp"; break;
750 case 0xF8: mnem = "fprem"; break;
751 case 0xFE: mnem = "fsin"; break;
752 case 0xFF: mnem = "fcos"; break;
753 default: UnimplementedInstruction();
754 }
755 }
756 break;
757
758 case 0xDA:
759 if (modrm_byte == 0xE9) {
760 mnem = "fucompp";
761 } else {
762 UnimplementedInstruction();
763 }
764 break;
765
766 case 0xDB:
767 if ((modrm_byte & 0xF8) == 0xE8) {
768 mnem = "fucomi";
769 has_register = true;
770 } else if (modrm_byte == 0xE2) {
771 mnem = "fclex";
772 } else {
773 UnimplementedInstruction();
774 }
775 break;
776
777 case 0xDC:
778 has_register = true;
779 switch (modrm_byte & 0xF8) {
780 case 0xC0: mnem = "fadd"; break;
781 case 0xE8: mnem = "fsub"; break;
782 case 0xC8: mnem = "fmul"; break;
783 case 0xF8: mnem = "fdiv"; break;
784 default: UnimplementedInstruction();
785 }
786 break;
787
788 case 0xDD:
789 has_register = true;
790 switch (modrm_byte & 0xF8) {
791 case 0xC0: mnem = "ffree"; break;
792 case 0xD8: mnem = "fstp"; break;
793 default: UnimplementedInstruction();
794 }
795 break;
796
797 case 0xDE:
798 if (modrm_byte == 0xD9) {
799 mnem = "fcompp";
800 } else {
801 has_register = true;
802 switch (modrm_byte & 0xF8) {
803 case 0xC0: mnem = "faddp"; break;
804 case 0xE8: mnem = "fsubp"; break;
805 case 0xC8: mnem = "fmulp"; break;
806 case 0xF8: mnem = "fdivp"; break;
807 default: UnimplementedInstruction();
808 }
809 }
810 break;
811
812 case 0xDF:
813 if (modrm_byte == 0xE0) {
814 mnem = "fnstsw_ax";
815 } else if ((modrm_byte & 0xF8) == 0xE8) {
816 mnem = "fucomip";
817 has_register = true;
818 }
819 break;
820
821 default: UnimplementedInstruction();
822 }
823
824 if (has_register) {
825 AppendToBuffer("%s st%d", mnem, modrm_byte & 0x7);
826 } else {
827 AppendToBuffer("%s", mnem);
828 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000829 return 2;
830}
831
832
833// Mnemonics for instructions 0xF0 byte.
834// Returns NULL if the instruction is not handled here.
835static const char* F0Mnem(byte f0byte) {
836 switch (f0byte) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100837 case 0x18: return "prefetch";
Steve Blocka7e24c12009-10-30 11:49:00 +0000838 case 0xA2: return "cpuid";
839 case 0x31: return "rdtsc";
840 case 0xBE: return "movsx_b";
841 case 0xBF: return "movsx_w";
842 case 0xB6: return "movzx_b";
843 case 0xB7: return "movzx_w";
844 case 0xAF: return "imul";
845 case 0xA5: return "shld";
846 case 0xAD: return "shrd";
847 case 0xAB: return "bts";
848 default: return NULL;
849 }
850}
851
852
853// Disassembled instruction '*instr' and writes it into 'out_buffer'.
854int DisassemblerIA32::InstructionDecode(v8::internal::Vector<char> out_buffer,
855 byte* instr) {
856 tmp_buffer_pos_ = 0; // starting to write as position 0
857 byte* data = instr;
858 // Check for hints.
859 const char* branch_hint = NULL;
860 // We use these two prefixes only with branch prediction
861 if (*data == 0x3E /*ds*/) {
862 branch_hint = "predicted taken";
863 data++;
864 } else if (*data == 0x2E /*cs*/) {
865 branch_hint = "predicted not taken";
866 data++;
867 }
868 bool processed = true; // Will be set to false if the current instruction
869 // is not in 'instructions' table.
870 const InstructionDesc& idesc = instruction_table.Get(*data);
871 switch (idesc.type) {
872 case ZERO_OPERANDS_INSTR:
873 AppendToBuffer(idesc.mnem);
874 data++;
875 break;
876
877 case TWO_OPERANDS_INSTR:
878 data++;
879 data += PrintOperands(idesc.mnem, idesc.op_order_, data);
880 break;
881
882 case JUMP_CONDITIONAL_SHORT_INSTR:
883 data += JumpConditionalShort(data, branch_hint);
884 break;
885
886 case REGISTER_INSTR:
887 AppendToBuffer("%s %s", idesc.mnem, NameOfCPURegister(*data & 0x07));
888 data++;
889 break;
890
891 case MOVE_REG_INSTR: {
892 byte* addr = reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data+1));
893 AppendToBuffer("mov %s,%s",
894 NameOfCPURegister(*data & 0x07),
895 NameOfAddress(addr));
896 data += 5;
897 break;
898 }
899
900 case CALL_JUMP_INSTR: {
901 byte* addr = data + *reinterpret_cast<int32_t*>(data+1) + 5;
902 AppendToBuffer("%s %s", idesc.mnem, NameOfAddress(addr));
903 data += 5;
904 break;
905 }
906
907 case SHORT_IMMEDIATE_INSTR: {
908 byte* addr = reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data+1));
909 AppendToBuffer("%s eax, %s", idesc.mnem, NameOfAddress(addr));
910 data += 5;
911 break;
912 }
913
914 case NO_INSTR:
915 processed = false;
916 break;
917
918 default:
919 UNIMPLEMENTED(); // This type is not implemented.
920 }
921 //----------------------------
922 if (!processed) {
923 switch (*data) {
924 case 0xC2:
925 AppendToBuffer("ret 0x%x", *reinterpret_cast<uint16_t*>(data+1));
926 data += 3;
927 break;
928
929 case 0x69: // fall through
930 case 0x6B:
931 { int mod, regop, rm;
932 get_modrm(*(data+1), &mod, &regop, &rm);
933 int32_t imm =
934 *data == 0x6B ? *(data+2) : *reinterpret_cast<int32_t*>(data+2);
935 AppendToBuffer("imul %s,%s,0x%x",
936 NameOfCPURegister(regop),
937 NameOfCPURegister(rm),
938 imm);
939 data += 2 + (*data == 0x6B ? 1 : 4);
940 }
941 break;
942
943 case 0xF6:
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100944 { data++;
945 int mod, regop, rm;
946 get_modrm(*data, &mod, &regop, &rm);
947 if (regop == eax) {
948 AppendToBuffer("test_b ");
Steve Block44f0eee2011-05-26 01:26:41 +0100949 data += PrintRightByteOperand(data);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100950 int32_t imm = *data;
951 AppendToBuffer(",0x%x", imm);
952 data++;
Steve Blocka7e24c12009-10-30 11:49:00 +0000953 } else {
954 UnimplementedInstruction();
955 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000956 }
957 break;
958
959 case 0x81: // fall through
960 case 0x83: // 0x81 with sign extension bit set
961 data += PrintImmediateOp(data);
962 break;
963
964 case 0x0F:
965 { byte f0byte = *(data+1);
966 const char* f0mnem = F0Mnem(f0byte);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100967 if (f0byte == 0x18) {
968 int mod, regop, rm;
969 get_modrm(*data, &mod, &regop, &rm);
970 const char* suffix[] = {"nta", "1", "2", "3"};
971 AppendToBuffer("%s%s ", f0mnem, suffix[regop & 0x03]);
972 data += PrintRightOperand(data);
973 } else if (f0byte == 0xA2 || f0byte == 0x31) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000974 AppendToBuffer("%s", f0mnem);
975 data += 2;
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100976 } else if (f0byte == 0x28) {
977 data += 2;
978 int mod, regop, rm;
979 get_modrm(*data, &mod, &regop, &rm);
980 AppendToBuffer("movaps %s,%s",
981 NameOfXMMRegister(regop),
982 NameOfXMMRegister(rm));
983 data++;
Steve Blocka7e24c12009-10-30 11:49:00 +0000984 } else if ((f0byte & 0xF0) == 0x80) {
985 data += JumpConditional(data, branch_hint);
986 } else if (f0byte == 0xBE || f0byte == 0xBF || f0byte == 0xB6 ||
987 f0byte == 0xB7 || f0byte == 0xAF) {
988 data += 2;
989 data += PrintOperands(f0mnem, REG_OPER_OP_ORDER, data);
990 } else if ((f0byte & 0xF0) == 0x90) {
991 data += SetCC(data);
Steve Block3ce2e202009-11-05 08:53:23 +0000992 } else if ((f0byte & 0xF0) == 0x40) {
993 data += CMov(data);
Steve Blocka7e24c12009-10-30 11:49:00 +0000994 } else {
995 data += 2;
996 if (f0byte == 0xAB || f0byte == 0xA5 || f0byte == 0xAD) {
997 // shrd, shld, bts
998 AppendToBuffer("%s ", f0mnem);
999 int mod, regop, rm;
1000 get_modrm(*data, &mod, &regop, &rm);
1001 data += PrintRightOperand(data);
1002 if (f0byte == 0xAB) {
1003 AppendToBuffer(",%s", NameOfCPURegister(regop));
1004 } else {
1005 AppendToBuffer(",%s,cl", NameOfCPURegister(regop));
1006 }
1007 } else {
1008 UnimplementedInstruction();
1009 }
1010 }
1011 }
1012 break;
1013
1014 case 0x8F:
1015 { data++;
1016 int mod, regop, rm;
1017 get_modrm(*data, &mod, &regop, &rm);
1018 if (regop == eax) {
1019 AppendToBuffer("pop ");
1020 data += PrintRightOperand(data);
1021 }
1022 }
1023 break;
1024
1025 case 0xFF:
1026 { data++;
1027 int mod, regop, rm;
1028 get_modrm(*data, &mod, &regop, &rm);
1029 const char* mnem = NULL;
1030 switch (regop) {
1031 case esi: mnem = "push"; break;
1032 case eax: mnem = "inc"; break;
1033 case ecx: mnem = "dec"; break;
1034 case edx: mnem = "call"; break;
1035 case esp: mnem = "jmp"; break;
1036 default: mnem = "???";
1037 }
1038 AppendToBuffer("%s ", mnem);
1039 data += PrintRightOperand(data);
1040 }
1041 break;
1042
1043 case 0xC7: // imm32, fall through
1044 case 0xC6: // imm8
1045 { bool is_byte = *data == 0xC6;
1046 data++;
Steve Block44f0eee2011-05-26 01:26:41 +01001047 if (is_byte) {
1048 AppendToBuffer("%s ", "mov_b");
1049 data += PrintRightByteOperand(data);
1050 int32_t imm = *data;
1051 AppendToBuffer(",0x%x", imm);
1052 data++;
1053 } else {
1054 AppendToBuffer("%s ", "mov");
1055 data += PrintRightOperand(data);
1056 int32_t imm = *reinterpret_cast<int32_t*>(data);
1057 AppendToBuffer(",0x%x", imm);
1058 data += 4;
1059 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001060 }
1061 break;
1062
1063 case 0x80:
1064 { data++;
Leon Clarkee46be812010-01-19 14:06:41 +00001065 int mod, regop, rm;
1066 get_modrm(*data, &mod, &regop, &rm);
1067 const char* mnem = NULL;
Leon Clarkee46be812010-01-19 14:06:41 +00001068 switch (regop) {
1069 case 5: mnem = "subb"; break;
1070 case 7: mnem = "cmpb"; break;
1071 default: UnimplementedInstruction();
1072 }
1073 AppendToBuffer("%s ", mnem);
Steve Block44f0eee2011-05-26 01:26:41 +01001074 data += PrintRightByteOperand(data);
Steve Blocka7e24c12009-10-30 11:49:00 +00001075 int32_t imm = *data;
1076 AppendToBuffer(",0x%x", imm);
1077 data++;
1078 }
1079 break;
1080
1081 case 0x88: // 8bit, fall through
1082 case 0x89: // 32bit
1083 { bool is_byte = *data == 0x88;
1084 int mod, regop, rm;
1085 data++;
1086 get_modrm(*data, &mod, &regop, &rm);
Steve Block44f0eee2011-05-26 01:26:41 +01001087 if (is_byte) {
1088 AppendToBuffer("%s ", "mov_b");
1089 data += PrintRightByteOperand(data);
1090 AppendToBuffer(",%s", NameOfByteCPURegister(regop));
1091 } else {
1092 AppendToBuffer("%s ", "mov");
1093 data += PrintRightOperand(data);
1094 AppendToBuffer(",%s", NameOfCPURegister(regop));
1095 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001096 }
1097 break;
1098
1099 case 0x66: // prefix
1100 data++;
1101 if (*data == 0x8B) {
1102 data++;
1103 data += PrintOperands("mov_w", REG_OPER_OP_ORDER, data);
1104 } else if (*data == 0x89) {
1105 data++;
1106 int mod, regop, rm;
1107 get_modrm(*data, &mod, &regop, &rm);
1108 AppendToBuffer("mov_w ");
1109 data += PrintRightOperand(data);
1110 AppendToBuffer(",%s", NameOfCPURegister(regop));
Steve Block3ce2e202009-11-05 08:53:23 +00001111 } else if (*data == 0x0F) {
1112 data++;
Steve Block6ded16b2010-05-10 14:33:55 +01001113 if (*data == 0x38) {
1114 data++;
1115 if (*data == 0x17) {
1116 data++;
1117 int mod, regop, rm;
1118 get_modrm(*data, &mod, &regop, &rm);
1119 AppendToBuffer("ptest %s,%s",
1120 NameOfXMMRegister(regop),
1121 NameOfXMMRegister(rm));
1122 data++;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001123 } else if (*data == 0x2A) {
1124 // movntdqa
1125 data++;
1126 int mod, regop, rm;
1127 get_modrm(*data, &mod, &regop, &rm);
1128 AppendToBuffer("movntdqa %s,", NameOfXMMRegister(regop));
1129 data += PrintRightOperand(data);
Steve Block6ded16b2010-05-10 14:33:55 +01001130 } else {
1131 UnimplementedInstruction();
1132 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01001133 } else if (*data == 0x3A) {
1134 data++;
1135 if (*data == 0x16) {
1136 data++;
1137 int mod, regop, rm;
1138 get_modrm(*data, &mod, &regop, &rm);
1139 int8_t imm8 = static_cast<int8_t>(data[1]);
1140 AppendToBuffer("pextrd %s,%s,%d",
Steve Block1e0659c2011-05-24 12:43:12 +01001141 NameOfCPURegister(regop),
Ben Murdochb0fe1622011-05-05 13:52:32 +01001142 NameOfXMMRegister(rm),
1143 static_cast<int>(imm8));
1144 data += 2;
Steve Block1e0659c2011-05-24 12:43:12 +01001145 } else if (*data == 0x22) {
1146 data++;
1147 int mod, regop, rm;
1148 get_modrm(*data, &mod, &regop, &rm);
1149 int8_t imm8 = static_cast<int8_t>(data[1]);
1150 AppendToBuffer("pinsrd %s,%s,%d",
1151 NameOfXMMRegister(regop),
1152 NameOfCPURegister(rm),
1153 static_cast<int>(imm8));
1154 data += 2;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001155 } else {
1156 UnimplementedInstruction();
1157 }
Steve Block6ded16b2010-05-10 14:33:55 +01001158 } else if (*data == 0x2E || *data == 0x2F) {
1159 const char* mnem = (*data == 0x2E) ? "ucomisd" : "comisd";
Steve Block3ce2e202009-11-05 08:53:23 +00001160 data++;
1161 int mod, regop, rm;
1162 get_modrm(*data, &mod, &regop, &rm);
Steve Block6ded16b2010-05-10 14:33:55 +01001163 if (mod == 0x3) {
1164 AppendToBuffer("%s %s,%s", mnem,
1165 NameOfXMMRegister(regop),
1166 NameOfXMMRegister(rm));
1167 data++;
1168 } else {
1169 AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
1170 data += PrintRightOperand(data);
1171 }
1172 } else if (*data == 0x50) {
1173 data++;
1174 int mod, regop, rm;
1175 get_modrm(*data, &mod, &regop, &rm);
1176 AppendToBuffer("movmskpd %s,%s",
1177 NameOfCPURegister(regop),
Steve Block3ce2e202009-11-05 08:53:23 +00001178 NameOfXMMRegister(rm));
1179 data++;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001180 } else if (*data == 0x54) {
1181 data++;
1182 int mod, regop, rm;
1183 get_modrm(*data, &mod, &regop, &rm);
1184 AppendToBuffer("andpd %s,%s",
1185 NameOfXMMRegister(regop),
1186 NameOfXMMRegister(rm));
1187 data++;
Leon Clarkee46be812010-01-19 14:06:41 +00001188 } else if (*data == 0x57) {
1189 data++;
1190 int mod, regop, rm;
1191 get_modrm(*data, &mod, &regop, &rm);
1192 AppendToBuffer("xorpd %s,%s",
1193 NameOfXMMRegister(regop),
1194 NameOfXMMRegister(rm));
1195 data++;
Steve Block6ded16b2010-05-10 14:33:55 +01001196 } else if (*data == 0x6E) {
1197 data++;
1198 int mod, regop, rm;
1199 get_modrm(*data, &mod, &regop, &rm);
1200 AppendToBuffer("movd %s,", NameOfXMMRegister(regop));
1201 data += PrintRightOperand(data);
Leon Clarkee46be812010-01-19 14:06:41 +00001202 } else if (*data == 0x6F) {
1203 data++;
1204 int mod, regop, rm;
1205 get_modrm(*data, &mod, &regop, &rm);
1206 AppendToBuffer("movdqa %s,", NameOfXMMRegister(regop));
Steve Block44f0eee2011-05-26 01:26:41 +01001207 data += PrintRightXMMOperand(data);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001208 } else if (*data == 0x70) {
1209 data++;
1210 int mod, regop, rm;
1211 get_modrm(*data, &mod, &regop, &rm);
1212 int8_t imm8 = static_cast<int8_t>(data[1]);
1213 AppendToBuffer("pshufd %s,%s,%d",
1214 NameOfXMMRegister(regop),
1215 NameOfXMMRegister(rm),
1216 static_cast<int>(imm8));
1217 data += 2;
Ben Murdochb8e0da22011-05-16 14:20:40 +01001218 } else if (*data == 0xF3) {
1219 data++;
1220 int mod, regop, rm;
1221 get_modrm(*data, &mod, &regop, &rm);
1222 AppendToBuffer("psllq %s,%s",
1223 NameOfXMMRegister(regop),
1224 NameOfXMMRegister(rm));
1225 data++;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001226 } else if (*data == 0x73) {
1227 data++;
1228 int mod, regop, rm;
1229 get_modrm(*data, &mod, &regop, &rm);
1230 int8_t imm8 = static_cast<int8_t>(data[1]);
Ben Murdochb8e0da22011-05-16 14:20:40 +01001231 ASSERT(regop == esi || regop == edx);
1232 AppendToBuffer("%s %s,%d",
1233 (regop == esi) ? "psllq" : "psrlq",
Ben Murdochb0fe1622011-05-05 13:52:32 +01001234 NameOfXMMRegister(rm),
1235 static_cast<int>(imm8));
1236 data += 2;
Ben Murdochb8e0da22011-05-16 14:20:40 +01001237 } else if (*data == 0xD3) {
1238 data++;
1239 int mod, regop, rm;
1240 get_modrm(*data, &mod, &regop, &rm);
1241 AppendToBuffer("psrlq %s,%s",
1242 NameOfXMMRegister(regop),
1243 NameOfXMMRegister(rm));
1244 data++;
Leon Clarkee46be812010-01-19 14:06:41 +00001245 } else if (*data == 0x7F) {
1246 AppendToBuffer("movdqa ");
1247 data++;
1248 int mod, regop, rm;
1249 get_modrm(*data, &mod, &regop, &rm);
Steve Block44f0eee2011-05-26 01:26:41 +01001250 data += PrintRightXMMOperand(data);
Leon Clarkee46be812010-01-19 14:06:41 +00001251 AppendToBuffer(",%s", NameOfXMMRegister(regop));
Ben Murdochb0fe1622011-05-05 13:52:32 +01001252 } else if (*data == 0x7E) {
1253 data++;
1254 int mod, regop, rm;
1255 get_modrm(*data, &mod, &regop, &rm);
1256 AppendToBuffer("movd ");
1257 data += PrintRightOperand(data);
1258 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1259 } else if (*data == 0xDB) {
1260 data++;
1261 int mod, regop, rm;
1262 get_modrm(*data, &mod, &regop, &rm);
1263 AppendToBuffer("pand %s,%s",
1264 NameOfXMMRegister(regop),
1265 NameOfXMMRegister(rm));
1266 data++;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001267 } else if (*data == 0xE7) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001268 data++;
1269 int mod, regop, rm;
1270 get_modrm(*data, &mod, &regop, &rm);
Steve Block44f0eee2011-05-26 01:26:41 +01001271 if (mod == 3) {
1272 AppendToBuffer("movntdq ");
1273 data += PrintRightOperand(data);
1274 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1275 } else {
1276 UnimplementedInstruction();
1277 }
Steve Block6ded16b2010-05-10 14:33:55 +01001278 } else if (*data == 0xEF) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01001279 data++;
1280 int mod, regop, rm;
1281 get_modrm(*data, &mod, &regop, &rm);
1282 AppendToBuffer("pxor %s,%s",
1283 NameOfXMMRegister(regop),
1284 NameOfXMMRegister(rm));
1285 data++;
Ben Murdochb8e0da22011-05-16 14:20:40 +01001286 } else if (*data == 0xEB) {
1287 data++;
1288 int mod, regop, rm;
1289 get_modrm(*data, &mod, &regop, &rm);
1290 AppendToBuffer("por %s,%s",
1291 NameOfXMMRegister(regop),
1292 NameOfXMMRegister(rm));
1293 data++;
Steve Block3ce2e202009-11-05 08:53:23 +00001294 } else {
1295 UnimplementedInstruction();
1296 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001297 } else {
1298 UnimplementedInstruction();
1299 }
1300 break;
1301
1302 case 0xFE:
1303 { data++;
1304 int mod, regop, rm;
1305 get_modrm(*data, &mod, &regop, &rm);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001306 if (regop == ecx) {
1307 AppendToBuffer("dec_b ");
1308 data += PrintRightOperand(data);
Steve Blocka7e24c12009-10-30 11:49:00 +00001309 } else {
1310 UnimplementedInstruction();
1311 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001312 }
1313 break;
1314
1315 case 0x68:
1316 AppendToBuffer("push 0x%x", *reinterpret_cast<int32_t*>(data+1));
1317 data += 5;
1318 break;
1319
1320 case 0x6A:
1321 AppendToBuffer("push 0x%x", *reinterpret_cast<int8_t*>(data + 1));
1322 data += 2;
1323 break;
1324
1325 case 0xA8:
1326 AppendToBuffer("test al,0x%x", *reinterpret_cast<uint8_t*>(data+1));
1327 data += 2;
1328 break;
1329
Leon Clarkee46be812010-01-19 14:06:41 +00001330 case 0x2C:
1331 AppendToBuffer("subb eax,0x%x", *reinterpret_cast<uint8_t*>(data+1));
1332 data += 2;
1333 break;
1334
Steve Blocka7e24c12009-10-30 11:49:00 +00001335 case 0xA9:
1336 AppendToBuffer("test eax,0x%x", *reinterpret_cast<int32_t*>(data+1));
1337 data += 5;
1338 break;
1339
1340 case 0xD1: // fall through
1341 case 0xD3: // fall through
1342 case 0xC1:
1343 data += D1D3C1Instruction(data);
1344 break;
1345
1346 case 0xD9: // fall through
1347 case 0xDA: // fall through
1348 case 0xDB: // fall through
1349 case 0xDC: // fall through
1350 case 0xDD: // fall through
1351 case 0xDE: // fall through
1352 case 0xDF:
1353 data += FPUInstruction(data);
1354 break;
1355
1356 case 0xEB:
1357 data += JumpShort(data);
1358 break;
1359
1360 case 0xF2:
1361 if (*(data+1) == 0x0F) {
1362 byte b2 = *(data+2);
1363 if (b2 == 0x11) {
1364 AppendToBuffer("movsd ");
1365 data += 3;
1366 int mod, regop, rm;
1367 get_modrm(*data, &mod, &regop, &rm);
Steve Block44f0eee2011-05-26 01:26:41 +01001368 data += PrintRightXMMOperand(data);
Steve Blocka7e24c12009-10-30 11:49:00 +00001369 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1370 } else if (b2 == 0x10) {
1371 data += 3;
1372 int mod, regop, rm;
1373 get_modrm(*data, &mod, &regop, &rm);
1374 AppendToBuffer("movsd %s,", NameOfXMMRegister(regop));
Steve Block44f0eee2011-05-26 01:26:41 +01001375 data += PrintRightXMMOperand(data);
1376 } else if (b2 == 0x5A) {
1377 data += 3;
1378 int mod, regop, rm;
1379 get_modrm(*data, &mod, &regop, &rm);
1380 AppendToBuffer("cvtsd2ss %s,", NameOfXMMRegister(regop));
1381 data += PrintRightXMMOperand(data);
Steve Blocka7e24c12009-10-30 11:49:00 +00001382 } else {
1383 const char* mnem = "?";
1384 switch (b2) {
1385 case 0x2A: mnem = "cvtsi2sd"; break;
Steve Block6ded16b2010-05-10 14:33:55 +01001386 case 0x2C: mnem = "cvttsd2si"; break;
1387 case 0x51: mnem = "sqrtsd"; break;
Steve Blocka7e24c12009-10-30 11:49:00 +00001388 case 0x58: mnem = "addsd"; break;
1389 case 0x59: mnem = "mulsd"; break;
1390 case 0x5C: mnem = "subsd"; break;
1391 case 0x5E: mnem = "divsd"; break;
1392 }
1393 data += 3;
1394 int mod, regop, rm;
1395 get_modrm(*data, &mod, &regop, &rm);
1396 if (b2 == 0x2A) {
Steve Block44f0eee2011-05-26 01:26:41 +01001397 AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
1398 data += PrintRightOperand(data);
Steve Block6ded16b2010-05-10 14:33:55 +01001399 } else if (b2 == 0x2C) {
Steve Block44f0eee2011-05-26 01:26:41 +01001400 AppendToBuffer("%s %s,", mnem, NameOfCPURegister(regop));
1401 data += PrintRightXMMOperand(data);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001402 } else if (b2 == 0xC2) {
1403 // Intel manual 2A, Table 3-18.
1404 const char* const pseudo_op[] = {
1405 "cmpeqsd",
1406 "cmpltsd",
1407 "cmplesd",
1408 "cmpunordsd",
1409 "cmpneqsd",
1410 "cmpnltsd",
1411 "cmpnlesd",
1412 "cmpordsd"
1413 };
1414 AppendToBuffer("%s %s,%s",
1415 pseudo_op[data[1]],
1416 NameOfXMMRegister(regop),
1417 NameOfXMMRegister(rm));
1418 data += 2;
Steve Blocka7e24c12009-10-30 11:49:00 +00001419 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01001420 AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
1421 data += PrintRightXMMOperand(data);
Steve Blocka7e24c12009-10-30 11:49:00 +00001422 }
1423 }
1424 } else {
1425 UnimplementedInstruction();
1426 }
1427 break;
1428
1429 case 0xF3:
Leon Clarkee46be812010-01-19 14:06:41 +00001430 if (*(data+1) == 0x0F) {
Steve Block44f0eee2011-05-26 01:26:41 +01001431 byte b2 = *(data+2);
1432 if (b2 == 0x11) {
1433 AppendToBuffer("movss ");
Steve Block6ded16b2010-05-10 14:33:55 +01001434 data += 3;
1435 int mod, regop, rm;
1436 get_modrm(*data, &mod, &regop, &rm);
Steve Block44f0eee2011-05-26 01:26:41 +01001437 data += PrintRightXMMOperand(data);
1438 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1439 } else if (b2 == 0x10) {
1440 data += 3;
1441 int mod, regop, rm;
1442 get_modrm(*data, &mod, &regop, &rm);
1443 AppendToBuffer("movss %s,", NameOfXMMRegister(regop));
1444 data += PrintRightXMMOperand(data);
1445 } else if (b2 == 0x2C) {
1446 data += 3;
1447 int mod, regop, rm;
1448 get_modrm(*data, &mod, &regop, &rm);
1449 AppendToBuffer("cvttss2si %s,", NameOfCPURegister(regop));
1450 data += PrintRightXMMOperand(data);
1451 } else if (b2 == 0x5A) {
1452 data += 3;
1453 int mod, regop, rm;
1454 get_modrm(*data, &mod, &regop, &rm);
1455 AppendToBuffer("cvtss2sd %s,", NameOfXMMRegister(regop));
1456 data += PrintRightXMMOperand(data);
1457 } else if (b2 == 0x6F) {
Leon Clarkee46be812010-01-19 14:06:41 +00001458 data += 3;
1459 int mod, regop, rm;
1460 get_modrm(*data, &mod, &regop, &rm);
1461 AppendToBuffer("movdqu %s,", NameOfXMMRegister(regop));
Steve Block44f0eee2011-05-26 01:26:41 +01001462 data += PrintRightXMMOperand(data);
1463 } else if (b2 == 0x7F) {
Leon Clarkee46be812010-01-19 14:06:41 +00001464 AppendToBuffer("movdqu ");
1465 data += 3;
1466 int mod, regop, rm;
1467 get_modrm(*data, &mod, &regop, &rm);
Steve Block44f0eee2011-05-26 01:26:41 +01001468 data += PrintRightXMMOperand(data);
Leon Clarkee46be812010-01-19 14:06:41 +00001469 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1470 } else {
1471 UnimplementedInstruction();
1472 }
1473 } else if (*(data+1) == 0xA5) {
1474 data += 2;
1475 AppendToBuffer("rep_movs");
Steve Block6ded16b2010-05-10 14:33:55 +01001476 } else if (*(data+1) == 0xAB) {
1477 data += 2;
1478 AppendToBuffer("rep_stos");
Steve Blocka7e24c12009-10-30 11:49:00 +00001479 } else {
1480 UnimplementedInstruction();
1481 }
1482 break;
1483
1484 case 0xF7:
1485 data += F7Instruction(data);
1486 break;
1487
1488 default:
1489 UnimplementedInstruction();
1490 }
1491 }
1492
1493 if (tmp_buffer_pos_ < sizeof tmp_buffer_) {
1494 tmp_buffer_[tmp_buffer_pos_] = '\0';
1495 }
1496
1497 int instr_len = data - instr;
Leon Clarkee46be812010-01-19 14:06:41 +00001498 if (instr_len == 0) {
1499 printf("%02x", *data);
1500 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001501 ASSERT(instr_len > 0); // Ensure progress.
1502
1503 int outp = 0;
1504 // Instruction bytes.
1505 for (byte* bp = instr; bp < data; bp++) {
1506 outp += v8::internal::OS::SNPrintF(out_buffer + outp,
1507 "%02x",
1508 *bp);
1509 }
1510 for (int i = 6 - instr_len; i >= 0; i--) {
1511 outp += v8::internal::OS::SNPrintF(out_buffer + outp,
1512 " ");
1513 }
1514
1515 outp += v8::internal::OS::SNPrintF(out_buffer + outp,
1516 " %s",
1517 tmp_buffer_.start());
1518 return instr_len;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001519} // NOLINT (function is too long)
Steve Blocka7e24c12009-10-30 11:49:00 +00001520
1521
1522//------------------------------------------------------------------------------
1523
1524
1525static const char* cpu_regs[8] = {
1526 "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi"
1527};
1528
1529
1530static const char* byte_cpu_regs[8] = {
1531 "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh"
1532};
1533
1534
1535static const char* xmm_regs[8] = {
1536 "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7"
1537};
1538
1539
1540const char* NameConverter::NameOfAddress(byte* addr) const {
Steve Block44f0eee2011-05-26 01:26:41 +01001541 v8::internal::OS::SNPrintF(tmp_buffer_, "%p", addr);
1542 return tmp_buffer_.start();
Steve Blocka7e24c12009-10-30 11:49:00 +00001543}
1544
1545
1546const char* NameConverter::NameOfConstant(byte* addr) const {
1547 return NameOfAddress(addr);
1548}
1549
1550
1551const char* NameConverter::NameOfCPURegister(int reg) const {
1552 if (0 <= reg && reg < 8) return cpu_regs[reg];
1553 return "noreg";
1554}
1555
1556
1557const char* NameConverter::NameOfByteCPURegister(int reg) const {
1558 if (0 <= reg && reg < 8) return byte_cpu_regs[reg];
1559 return "noreg";
1560}
1561
1562
1563const char* NameConverter::NameOfXMMRegister(int reg) const {
1564 if (0 <= reg && reg < 8) return xmm_regs[reg];
1565 return "noxmmreg";
1566}
1567
1568
1569const char* NameConverter::NameInCode(byte* addr) const {
1570 // IA32 does not embed debug strings at the moment.
1571 UNREACHABLE();
1572 return "";
1573}
1574
1575
1576//------------------------------------------------------------------------------
1577
1578Disassembler::Disassembler(const NameConverter& converter)
1579 : converter_(converter) {}
1580
1581
1582Disassembler::~Disassembler() {}
1583
1584
1585int Disassembler::InstructionDecode(v8::internal::Vector<char> buffer,
1586 byte* instruction) {
1587 DisassemblerIA32 d(converter_, false /*do not crash if unimplemented*/);
1588 return d.InstructionDecode(buffer, instruction);
1589}
1590
1591
1592// The IA-32 assembler does not currently use constant pools.
1593int Disassembler::ConstantPoolSizeAt(byte* instruction) { return -1; }
1594
1595
1596/*static*/ void Disassembler::Disassemble(FILE* f, byte* begin, byte* end) {
1597 NameConverter converter;
1598 Disassembler d(converter);
1599 for (byte* pc = begin; pc < end;) {
1600 v8::internal::EmbeddedVector<char, 128> buffer;
1601 buffer[0] = '\0';
1602 byte* prev_pc = pc;
1603 pc += d.InstructionDecode(buffer, pc);
1604 fprintf(f, "%p", prev_pc);
1605 fprintf(f, " ");
1606
1607 for (byte* bp = prev_pc; bp < pc; bp++) {
1608 fprintf(f, "%02x", *bp);
1609 }
1610 for (int i = 6 - (pc - prev_pc); i >= 0; i--) {
1611 fprintf(f, " ");
1612 }
1613 fprintf(f, " %s\n", buffer.start());
1614 }
1615}
1616
1617
1618} // namespace disasm
Leon Clarkef7060e22010-06-03 12:02:55 +01001619
1620#endif // V8_TARGET_ARCH_IA32