blob: 58c22afcd376ea10e47b5222b557c43e3372e350 [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);
334 int PrintOperands(const char* mnem, OperandOrder op_order, byte* data);
335 int PrintImmediateOp(byte* data);
336 int F7Instruction(byte* data);
337 int D1D3C1Instruction(byte* data);
338 int JumpShort(byte* data);
339 int JumpConditional(byte* data, const char* comment);
340 int JumpConditionalShort(byte* data, const char* comment);
341 int SetCC(byte* data);
Steve Block3ce2e202009-11-05 08:53:23 +0000342 int CMov(byte* data);
Steve Blocka7e24c12009-10-30 11:49:00 +0000343 int FPUInstruction(byte* data);
Steve Blockd0582a62009-12-15 09:54:21 +0000344 int MemoryFPUInstruction(int escape_opcode, int regop, byte* modrm_start);
345 int RegisterFPUInstruction(int escape_opcode, byte modrm_byte);
Steve Blocka7e24c12009-10-30 11:49:00 +0000346 void AppendToBuffer(const char* format, ...);
347
348
349 void UnimplementedInstruction() {
350 if (abort_on_unimplemented_) {
351 UNIMPLEMENTED();
352 } else {
353 AppendToBuffer("'Unimplemented Instruction'");
354 }
355 }
356};
357
358
359void DisassemblerIA32::AppendToBuffer(const char* format, ...) {
360 v8::internal::Vector<char> buf = tmp_buffer_ + tmp_buffer_pos_;
361 va_list args;
362 va_start(args, format);
363 int result = v8::internal::OS::VSNPrintF(buf, format, args);
364 va_end(args);
365 tmp_buffer_pos_ += result;
366}
367
368int DisassemblerIA32::PrintRightOperandHelper(
369 byte* modrmp,
370 RegisterNameMapping register_name) {
371 int mod, regop, rm;
372 get_modrm(*modrmp, &mod, &regop, &rm);
373 switch (mod) {
374 case 0:
375 if (rm == ebp) {
376 int32_t disp = *reinterpret_cast<int32_t*>(modrmp+1);
377 AppendToBuffer("[0x%x]", disp);
378 return 5;
379 } else if (rm == esp) {
380 byte sib = *(modrmp + 1);
381 int scale, index, base;
382 get_sib(sib, &scale, &index, &base);
383 if (index == esp && base == esp && scale == 0 /*times_1*/) {
384 AppendToBuffer("[%s]", (this->*register_name)(rm));
385 return 2;
386 } else if (base == ebp) {
387 int32_t disp = *reinterpret_cast<int32_t*>(modrmp + 2);
388 AppendToBuffer("[%s*%d+0x%x]",
389 (this->*register_name)(index),
390 1 << scale,
391 disp);
392 return 6;
393 } else if (index != esp && base != ebp) {
394 // [base+index*scale]
395 AppendToBuffer("[%s+%s*%d]",
396 (this->*register_name)(base),
397 (this->*register_name)(index),
398 1 << scale);
399 return 2;
400 } else {
401 UnimplementedInstruction();
402 return 1;
403 }
404 } else {
405 AppendToBuffer("[%s]", (this->*register_name)(rm));
406 return 1;
407 }
408 break;
409 case 1: // fall through
410 case 2:
411 if (rm == esp) {
412 byte sib = *(modrmp + 1);
413 int scale, index, base;
414 get_sib(sib, &scale, &index, &base);
415 int disp =
416 mod == 2 ? *reinterpret_cast<int32_t*>(modrmp + 2) : *(modrmp + 2);
417 if (index == base && index == rm /*esp*/ && scale == 0 /*times_1*/) {
418 AppendToBuffer("[%s+0x%x]", (this->*register_name)(rm), disp);
419 } else {
420 AppendToBuffer("[%s+%s*%d+0x%x]",
421 (this->*register_name)(base),
422 (this->*register_name)(index),
423 1 << scale,
424 disp);
425 }
426 return mod == 2 ? 6 : 3;
427 } else {
428 // No sib.
429 int disp =
430 mod == 2 ? *reinterpret_cast<int32_t*>(modrmp + 1) : *(modrmp + 1);
431 AppendToBuffer("[%s+0x%x]", (this->*register_name)(rm), disp);
432 return mod == 2 ? 5 : 2;
433 }
434 break;
435 case 3:
436 AppendToBuffer("%s", (this->*register_name)(rm));
437 return 1;
438 default:
439 UnimplementedInstruction();
440 return 1;
441 }
442 UNREACHABLE();
443}
444
445
446int DisassemblerIA32::PrintRightOperand(byte* modrmp) {
447 return PrintRightOperandHelper(modrmp, &DisassemblerIA32::NameOfCPURegister);
448}
449
450
451int DisassemblerIA32::PrintRightByteOperand(byte* modrmp) {
452 return PrintRightOperandHelper(modrmp,
453 &DisassemblerIA32::NameOfByteCPURegister);
454}
455
456
457// Returns number of bytes used including the current *data.
458// Writes instruction's mnemonic, left and right operands to 'tmp_buffer_'.
459int DisassemblerIA32::PrintOperands(const char* mnem,
460 OperandOrder op_order,
461 byte* data) {
462 byte modrm = *data;
463 int mod, regop, rm;
464 get_modrm(modrm, &mod, &regop, &rm);
465 int advance = 0;
466 switch (op_order) {
467 case REG_OPER_OP_ORDER: {
468 AppendToBuffer("%s %s,", mnem, NameOfCPURegister(regop));
469 advance = PrintRightOperand(data);
470 break;
471 }
472 case OPER_REG_OP_ORDER: {
473 AppendToBuffer("%s ", mnem);
474 advance = PrintRightOperand(data);
475 AppendToBuffer(",%s", NameOfCPURegister(regop));
476 break;
477 }
478 default:
479 UNREACHABLE();
480 break;
481 }
482 return advance;
483}
484
485
486// Returns number of bytes used by machine instruction, including *data byte.
487// Writes immediate instructions to 'tmp_buffer_'.
488int DisassemblerIA32::PrintImmediateOp(byte* data) {
489 bool sign_extension_bit = (*data & 0x02) != 0;
490 byte modrm = *(data+1);
491 int mod, regop, rm;
492 get_modrm(modrm, &mod, &regop, &rm);
493 const char* mnem = "Imm???";
494 switch (regop) {
495 case 0: mnem = "add"; break;
496 case 1: mnem = "or"; break;
497 case 2: mnem = "adc"; break;
498 case 4: mnem = "and"; break;
499 case 5: mnem = "sub"; break;
500 case 6: mnem = "xor"; break;
501 case 7: mnem = "cmp"; break;
502 default: UnimplementedInstruction();
503 }
504 AppendToBuffer("%s ", mnem);
505 int count = PrintRightOperand(data+1);
506 if (sign_extension_bit) {
507 AppendToBuffer(",0x%x", *(data + 1 + count));
508 return 1 + count + 1 /*int8*/;
509 } else {
510 AppendToBuffer(",0x%x", *reinterpret_cast<int32_t*>(data + 1 + count));
511 return 1 + count + 4 /*int32_t*/;
512 }
513}
514
515
516// Returns number of bytes used, including *data.
517int DisassemblerIA32::F7Instruction(byte* data) {
Steve Blockd0582a62009-12-15 09:54:21 +0000518 ASSERT_EQ(0xF7, *data);
Steve Blocka7e24c12009-10-30 11:49:00 +0000519 byte modrm = *(data+1);
520 int mod, regop, rm;
521 get_modrm(modrm, &mod, &regop, &rm);
522 if (mod == 3 && regop != 0) {
523 const char* mnem = NULL;
524 switch (regop) {
525 case 2: mnem = "not"; break;
526 case 3: mnem = "neg"; break;
527 case 4: mnem = "mul"; break;
528 case 7: mnem = "idiv"; break;
529 default: UnimplementedInstruction();
530 }
531 AppendToBuffer("%s %s", mnem, NameOfCPURegister(rm));
532 return 2;
533 } else if (mod == 3 && regop == eax) {
534 int32_t imm = *reinterpret_cast<int32_t*>(data+2);
535 AppendToBuffer("test %s,0x%x", NameOfCPURegister(rm), imm);
536 return 6;
537 } else if (regop == eax) {
538 AppendToBuffer("test ");
539 int count = PrintRightOperand(data+1);
540 int32_t imm = *reinterpret_cast<int32_t*>(data+1+count);
541 AppendToBuffer(",0x%x", imm);
542 return 1+count+4 /*int32_t*/;
543 } else {
544 UnimplementedInstruction();
545 return 2;
546 }
547}
548
549int DisassemblerIA32::D1D3C1Instruction(byte* data) {
550 byte op = *data;
Steve Blockd0582a62009-12-15 09:54:21 +0000551 ASSERT(op == 0xD1 || op == 0xD3 || op == 0xC1);
Steve Blocka7e24c12009-10-30 11:49:00 +0000552 byte modrm = *(data+1);
553 int mod, regop, rm;
554 get_modrm(modrm, &mod, &regop, &rm);
555 int imm8 = -1;
556 int num_bytes = 2;
557 if (mod == 3) {
558 const char* mnem = NULL;
Steve Blockd0582a62009-12-15 09:54:21 +0000559 switch (regop) {
560 case kROL: mnem = "rol"; break;
561 case kROR: mnem = "ror"; break;
562 case kRCL: mnem = "rcl"; break;
563 case kSHL: mnem = "shl"; break;
564 case KSHR: mnem = "shr"; break;
565 case kSAR: mnem = "sar"; break;
566 default: UnimplementedInstruction();
567 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000568 if (op == 0xD1) {
569 imm8 = 1;
Steve Blocka7e24c12009-10-30 11:49:00 +0000570 } else if (op == 0xC1) {
571 imm8 = *(data+2);
572 num_bytes = 3;
Steve Blocka7e24c12009-10-30 11:49:00 +0000573 } else if (op == 0xD3) {
Steve Blockd0582a62009-12-15 09:54:21 +0000574 // Shift/rotate by cl.
Steve Blocka7e24c12009-10-30 11:49:00 +0000575 }
Steve Blockd0582a62009-12-15 09:54:21 +0000576 ASSERT_NE(NULL, mnem);
Steve Blocka7e24c12009-10-30 11:49:00 +0000577 AppendToBuffer("%s %s,", mnem, NameOfCPURegister(rm));
578 if (imm8 > 0) {
579 AppendToBuffer("%d", imm8);
580 } else {
581 AppendToBuffer("cl");
582 }
583 } else {
584 UnimplementedInstruction();
585 }
586 return num_bytes;
587}
588
589
590// Returns number of bytes used, including *data.
591int DisassemblerIA32::JumpShort(byte* data) {
Steve Blockd0582a62009-12-15 09:54:21 +0000592 ASSERT_EQ(0xEB, *data);
Steve Blocka7e24c12009-10-30 11:49:00 +0000593 byte b = *(data+1);
594 byte* dest = data + static_cast<int8_t>(b) + 2;
595 AppendToBuffer("jmp %s", NameOfAddress(dest));
596 return 2;
597}
598
599
600// Returns number of bytes used, including *data.
601int DisassemblerIA32::JumpConditional(byte* data, const char* comment) {
Steve Blockd0582a62009-12-15 09:54:21 +0000602 ASSERT_EQ(0x0F, *data);
Steve Blocka7e24c12009-10-30 11:49:00 +0000603 byte cond = *(data+1) & 0x0F;
604 byte* dest = data + *reinterpret_cast<int32_t*>(data+2) + 6;
605 const char* mnem = jump_conditional_mnem[cond];
606 AppendToBuffer("%s %s", mnem, NameOfAddress(dest));
607 if (comment != NULL) {
608 AppendToBuffer(", %s", comment);
609 }
610 return 6; // includes 0x0F
611}
612
613
614// Returns number of bytes used, including *data.
615int DisassemblerIA32::JumpConditionalShort(byte* data, const char* comment) {
616 byte cond = *data & 0x0F;
617 byte b = *(data+1);
618 byte* dest = data + static_cast<int8_t>(b) + 2;
619 const char* mnem = jump_conditional_mnem[cond];
620 AppendToBuffer("%s %s", mnem, NameOfAddress(dest));
621 if (comment != NULL) {
622 AppendToBuffer(", %s", comment);
623 }
624 return 2;
625}
626
627
628// Returns number of bytes used, including *data.
629int DisassemblerIA32::SetCC(byte* data) {
Steve Blockd0582a62009-12-15 09:54:21 +0000630 ASSERT_EQ(0x0F, *data);
Steve Blocka7e24c12009-10-30 11:49:00 +0000631 byte cond = *(data+1) & 0x0F;
632 const char* mnem = set_conditional_mnem[cond];
633 AppendToBuffer("%s ", mnem);
634 PrintRightByteOperand(data+2);
Steve Blockd0582a62009-12-15 09:54:21 +0000635 return 3; // Includes 0x0F.
Steve Blocka7e24c12009-10-30 11:49:00 +0000636}
637
638
639// Returns number of bytes used, including *data.
Steve Block3ce2e202009-11-05 08:53:23 +0000640int DisassemblerIA32::CMov(byte* data) {
Steve Blockd0582a62009-12-15 09:54:21 +0000641 ASSERT_EQ(0x0F, *data);
Steve Block3ce2e202009-11-05 08:53:23 +0000642 byte cond = *(data + 1) & 0x0F;
643 const char* mnem = conditional_move_mnem[cond];
644 int op_size = PrintOperands(mnem, REG_OPER_OP_ORDER, data + 2);
645 return 2 + op_size; // includes 0x0F
646}
647
648
649// Returns number of bytes used, including *data.
Steve Blocka7e24c12009-10-30 11:49:00 +0000650int DisassemblerIA32::FPUInstruction(byte* data) {
Steve Blockd0582a62009-12-15 09:54:21 +0000651 byte escape_opcode = *data;
652 ASSERT_EQ(0xD8, escape_opcode & 0xF8);
653 byte modrm_byte = *(data+1);
654
655 if (modrm_byte >= 0xC0) {
656 return RegisterFPUInstruction(escape_opcode, modrm_byte);
657 } else {
658 return MemoryFPUInstruction(escape_opcode, modrm_byte, data+1);
Steve Blocka7e24c12009-10-30 11:49:00 +0000659 }
Steve Blockd0582a62009-12-15 09:54:21 +0000660}
661
662int DisassemblerIA32::MemoryFPUInstruction(int escape_opcode,
663 int modrm_byte,
664 byte* modrm_start) {
665 const char* mnem = "?";
666 int regop = (modrm_byte >> 3) & 0x7; // reg/op field of modrm byte.
667 switch (escape_opcode) {
668 case 0xD9: switch (regop) {
669 case 0: mnem = "fld_s"; break;
670 case 3: mnem = "fstp_s"; break;
671 case 7: mnem = "fstcw"; break;
672 default: UnimplementedInstruction();
673 }
674 break;
675
676 case 0xDB: switch (regop) {
677 case 0: mnem = "fild_s"; break;
678 case 1: mnem = "fisttp_s"; break;
679 case 2: mnem = "fist_s"; break;
680 case 3: mnem = "fistp_s"; break;
681 default: UnimplementedInstruction();
682 }
683 break;
684
685 case 0xDD: switch (regop) {
686 case 0: mnem = "fld_d"; break;
Andrei Popescu402d9372010-02-26 13:31:12 +0000687 case 2: mnem = "fstp"; break;
Steve Blockd0582a62009-12-15 09:54:21 +0000688 case 3: mnem = "fstp_d"; break;
689 default: UnimplementedInstruction();
690 }
691 break;
692
693 case 0xDF: switch (regop) {
694 case 5: mnem = "fild_d"; break;
695 case 7: mnem = "fistp_d"; break;
696 default: UnimplementedInstruction();
697 }
698 break;
699
700 default: UnimplementedInstruction();
701 }
702 AppendToBuffer("%s ", mnem);
703 int count = PrintRightOperand(modrm_start);
704 return count + 1;
705}
706
707int DisassemblerIA32::RegisterFPUInstruction(int escape_opcode,
708 byte modrm_byte) {
709 bool has_register = false; // Is the FPU register encoded in modrm_byte?
710 const char* mnem = "?";
711
712 switch (escape_opcode) {
713 case 0xD8:
714 UnimplementedInstruction();
715 break;
716
717 case 0xD9:
718 switch (modrm_byte & 0xF8) {
719 case 0xC8:
720 mnem = "fxch";
721 has_register = true;
722 break;
723 default:
724 switch (modrm_byte) {
725 case 0xE0: mnem = "fchs"; break;
726 case 0xE1: mnem = "fabs"; break;
727 case 0xE4: mnem = "ftst"; break;
728 case 0xE8: mnem = "fld1"; break;
Andrei Popescu402d9372010-02-26 13:31:12 +0000729 case 0xEB: mnem = "fldpi"; break;
Steve Blockd0582a62009-12-15 09:54:21 +0000730 case 0xEE: mnem = "fldz"; break;
731 case 0xF5: mnem = "fprem1"; break;
732 case 0xF7: mnem = "fincstp"; break;
733 case 0xF8: mnem = "fprem"; break;
734 case 0xFE: mnem = "fsin"; break;
735 case 0xFF: mnem = "fcos"; break;
736 default: UnimplementedInstruction();
737 }
738 }
739 break;
740
741 case 0xDA:
742 if (modrm_byte == 0xE9) {
743 mnem = "fucompp";
744 } else {
745 UnimplementedInstruction();
746 }
747 break;
748
749 case 0xDB:
750 if ((modrm_byte & 0xF8) == 0xE8) {
751 mnem = "fucomi";
752 has_register = true;
753 } else if (modrm_byte == 0xE2) {
754 mnem = "fclex";
755 } else {
756 UnimplementedInstruction();
757 }
758 break;
759
760 case 0xDC:
761 has_register = true;
762 switch (modrm_byte & 0xF8) {
763 case 0xC0: mnem = "fadd"; break;
764 case 0xE8: mnem = "fsub"; break;
765 case 0xC8: mnem = "fmul"; break;
766 case 0xF8: mnem = "fdiv"; break;
767 default: UnimplementedInstruction();
768 }
769 break;
770
771 case 0xDD:
772 has_register = true;
773 switch (modrm_byte & 0xF8) {
774 case 0xC0: mnem = "ffree"; break;
775 case 0xD8: mnem = "fstp"; break;
776 default: UnimplementedInstruction();
777 }
778 break;
779
780 case 0xDE:
781 if (modrm_byte == 0xD9) {
782 mnem = "fcompp";
783 } else {
784 has_register = true;
785 switch (modrm_byte & 0xF8) {
786 case 0xC0: mnem = "faddp"; break;
787 case 0xE8: mnem = "fsubp"; break;
788 case 0xC8: mnem = "fmulp"; break;
789 case 0xF8: mnem = "fdivp"; break;
790 default: UnimplementedInstruction();
791 }
792 }
793 break;
794
795 case 0xDF:
796 if (modrm_byte == 0xE0) {
797 mnem = "fnstsw_ax";
798 } else if ((modrm_byte & 0xF8) == 0xE8) {
799 mnem = "fucomip";
800 has_register = true;
801 }
802 break;
803
804 default: UnimplementedInstruction();
805 }
806
807 if (has_register) {
808 AppendToBuffer("%s st%d", mnem, modrm_byte & 0x7);
809 } else {
810 AppendToBuffer("%s", mnem);
811 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000812 return 2;
813}
814
815
816// Mnemonics for instructions 0xF0 byte.
817// Returns NULL if the instruction is not handled here.
818static const char* F0Mnem(byte f0byte) {
819 switch (f0byte) {
820 case 0xA2: return "cpuid";
821 case 0x31: return "rdtsc";
822 case 0xBE: return "movsx_b";
823 case 0xBF: return "movsx_w";
824 case 0xB6: return "movzx_b";
825 case 0xB7: return "movzx_w";
826 case 0xAF: return "imul";
827 case 0xA5: return "shld";
828 case 0xAD: return "shrd";
829 case 0xAB: return "bts";
830 default: return NULL;
831 }
832}
833
834
835// Disassembled instruction '*instr' and writes it into 'out_buffer'.
836int DisassemblerIA32::InstructionDecode(v8::internal::Vector<char> out_buffer,
837 byte* instr) {
838 tmp_buffer_pos_ = 0; // starting to write as position 0
839 byte* data = instr;
840 // Check for hints.
841 const char* branch_hint = NULL;
842 // We use these two prefixes only with branch prediction
843 if (*data == 0x3E /*ds*/) {
844 branch_hint = "predicted taken";
845 data++;
846 } else if (*data == 0x2E /*cs*/) {
847 branch_hint = "predicted not taken";
848 data++;
849 }
850 bool processed = true; // Will be set to false if the current instruction
851 // is not in 'instructions' table.
852 const InstructionDesc& idesc = instruction_table.Get(*data);
853 switch (idesc.type) {
854 case ZERO_OPERANDS_INSTR:
855 AppendToBuffer(idesc.mnem);
856 data++;
857 break;
858
859 case TWO_OPERANDS_INSTR:
860 data++;
861 data += PrintOperands(idesc.mnem, idesc.op_order_, data);
862 break;
863
864 case JUMP_CONDITIONAL_SHORT_INSTR:
865 data += JumpConditionalShort(data, branch_hint);
866 break;
867
868 case REGISTER_INSTR:
869 AppendToBuffer("%s %s", idesc.mnem, NameOfCPURegister(*data & 0x07));
870 data++;
871 break;
872
873 case MOVE_REG_INSTR: {
874 byte* addr = reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data+1));
875 AppendToBuffer("mov %s,%s",
876 NameOfCPURegister(*data & 0x07),
877 NameOfAddress(addr));
878 data += 5;
879 break;
880 }
881
882 case CALL_JUMP_INSTR: {
883 byte* addr = data + *reinterpret_cast<int32_t*>(data+1) + 5;
884 AppendToBuffer("%s %s", idesc.mnem, NameOfAddress(addr));
885 data += 5;
886 break;
887 }
888
889 case SHORT_IMMEDIATE_INSTR: {
890 byte* addr = reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data+1));
891 AppendToBuffer("%s eax, %s", idesc.mnem, NameOfAddress(addr));
892 data += 5;
893 break;
894 }
895
896 case NO_INSTR:
897 processed = false;
898 break;
899
900 default:
901 UNIMPLEMENTED(); // This type is not implemented.
902 }
903 //----------------------------
904 if (!processed) {
905 switch (*data) {
906 case 0xC2:
907 AppendToBuffer("ret 0x%x", *reinterpret_cast<uint16_t*>(data+1));
908 data += 3;
909 break;
910
911 case 0x69: // fall through
912 case 0x6B:
913 { int mod, regop, rm;
914 get_modrm(*(data+1), &mod, &regop, &rm);
915 int32_t imm =
916 *data == 0x6B ? *(data+2) : *reinterpret_cast<int32_t*>(data+2);
917 AppendToBuffer("imul %s,%s,0x%x",
918 NameOfCPURegister(regop),
919 NameOfCPURegister(rm),
920 imm);
921 data += 2 + (*data == 0x6B ? 1 : 4);
922 }
923 break;
924
925 case 0xF6:
926 { int mod, regop, rm;
927 get_modrm(*(data+1), &mod, &regop, &rm);
928 if (mod == 3 && regop == eax) {
929 AppendToBuffer("test_b %s,%d", NameOfCPURegister(rm), *(data+2));
930 } else {
931 UnimplementedInstruction();
932 }
933 data += 3;
934 }
935 break;
936
937 case 0x81: // fall through
938 case 0x83: // 0x81 with sign extension bit set
939 data += PrintImmediateOp(data);
940 break;
941
942 case 0x0F:
943 { byte f0byte = *(data+1);
944 const char* f0mnem = F0Mnem(f0byte);
945 if (f0byte == 0xA2 || f0byte == 0x31) {
946 AppendToBuffer("%s", f0mnem);
947 data += 2;
948 } else if ((f0byte & 0xF0) == 0x80) {
949 data += JumpConditional(data, branch_hint);
950 } else if (f0byte == 0xBE || f0byte == 0xBF || f0byte == 0xB6 ||
951 f0byte == 0xB7 || f0byte == 0xAF) {
952 data += 2;
953 data += PrintOperands(f0mnem, REG_OPER_OP_ORDER, data);
954 } else if ((f0byte & 0xF0) == 0x90) {
955 data += SetCC(data);
Steve Block3ce2e202009-11-05 08:53:23 +0000956 } else if ((f0byte & 0xF0) == 0x40) {
957 data += CMov(data);
Steve Blocka7e24c12009-10-30 11:49:00 +0000958 } else {
959 data += 2;
960 if (f0byte == 0xAB || f0byte == 0xA5 || f0byte == 0xAD) {
961 // shrd, shld, bts
962 AppendToBuffer("%s ", f0mnem);
963 int mod, regop, rm;
964 get_modrm(*data, &mod, &regop, &rm);
965 data += PrintRightOperand(data);
966 if (f0byte == 0xAB) {
967 AppendToBuffer(",%s", NameOfCPURegister(regop));
968 } else {
969 AppendToBuffer(",%s,cl", NameOfCPURegister(regop));
970 }
971 } else {
972 UnimplementedInstruction();
973 }
974 }
975 }
976 break;
977
978 case 0x8F:
979 { data++;
980 int mod, regop, rm;
981 get_modrm(*data, &mod, &regop, &rm);
982 if (regop == eax) {
983 AppendToBuffer("pop ");
984 data += PrintRightOperand(data);
985 }
986 }
987 break;
988
989 case 0xFF:
990 { data++;
991 int mod, regop, rm;
992 get_modrm(*data, &mod, &regop, &rm);
993 const char* mnem = NULL;
994 switch (regop) {
995 case esi: mnem = "push"; break;
996 case eax: mnem = "inc"; break;
997 case ecx: mnem = "dec"; break;
998 case edx: mnem = "call"; break;
999 case esp: mnem = "jmp"; break;
1000 default: mnem = "???";
1001 }
1002 AppendToBuffer("%s ", mnem);
1003 data += PrintRightOperand(data);
1004 }
1005 break;
1006
1007 case 0xC7: // imm32, fall through
1008 case 0xC6: // imm8
1009 { bool is_byte = *data == 0xC6;
1010 data++;
1011 AppendToBuffer("%s ", is_byte ? "mov_b" : "mov");
1012 data += PrintRightOperand(data);
1013 int32_t imm = is_byte ? *data : *reinterpret_cast<int32_t*>(data);
1014 AppendToBuffer(",0x%x", imm);
1015 data += is_byte ? 1 : 4;
1016 }
1017 break;
1018
1019 case 0x80:
1020 { data++;
Leon Clarkee46be812010-01-19 14:06:41 +00001021 int mod, regop, rm;
1022 get_modrm(*data, &mod, &regop, &rm);
1023 const char* mnem = NULL;
Leon Clarkee46be812010-01-19 14:06:41 +00001024 switch (regop) {
1025 case 5: mnem = "subb"; break;
1026 case 7: mnem = "cmpb"; break;
1027 default: UnimplementedInstruction();
1028 }
1029 AppendToBuffer("%s ", mnem);
Steve Blocka7e24c12009-10-30 11:49:00 +00001030 data += PrintRightOperand(data);
1031 int32_t imm = *data;
1032 AppendToBuffer(",0x%x", imm);
1033 data++;
1034 }
1035 break;
1036
1037 case 0x88: // 8bit, fall through
1038 case 0x89: // 32bit
1039 { bool is_byte = *data == 0x88;
1040 int mod, regop, rm;
1041 data++;
1042 get_modrm(*data, &mod, &regop, &rm);
1043 AppendToBuffer("%s ", is_byte ? "mov_b" : "mov");
1044 data += PrintRightOperand(data);
1045 AppendToBuffer(",%s", NameOfCPURegister(regop));
1046 }
1047 break;
1048
1049 case 0x66: // prefix
1050 data++;
1051 if (*data == 0x8B) {
1052 data++;
1053 data += PrintOperands("mov_w", REG_OPER_OP_ORDER, data);
1054 } else if (*data == 0x89) {
1055 data++;
1056 int mod, regop, rm;
1057 get_modrm(*data, &mod, &regop, &rm);
1058 AppendToBuffer("mov_w ");
1059 data += PrintRightOperand(data);
1060 AppendToBuffer(",%s", NameOfCPURegister(regop));
Steve Block3ce2e202009-11-05 08:53:23 +00001061 } else if (*data == 0x0F) {
1062 data++;
Steve Block6ded16b2010-05-10 14:33:55 +01001063 if (*data == 0x38) {
1064 data++;
1065 if (*data == 0x17) {
1066 data++;
1067 int mod, regop, rm;
1068 get_modrm(*data, &mod, &regop, &rm);
1069 AppendToBuffer("ptest %s,%s",
1070 NameOfXMMRegister(regop),
1071 NameOfXMMRegister(rm));
1072 data++;
1073 } else {
1074 UnimplementedInstruction();
1075 }
1076 } else if (*data == 0x2E || *data == 0x2F) {
1077 const char* mnem = (*data == 0x2E) ? "ucomisd" : "comisd";
Steve Block3ce2e202009-11-05 08:53:23 +00001078 data++;
1079 int mod, regop, rm;
1080 get_modrm(*data, &mod, &regop, &rm);
Steve Block6ded16b2010-05-10 14:33:55 +01001081 if (mod == 0x3) {
1082 AppendToBuffer("%s %s,%s", mnem,
1083 NameOfXMMRegister(regop),
1084 NameOfXMMRegister(rm));
1085 data++;
1086 } else {
1087 AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
1088 data += PrintRightOperand(data);
1089 }
1090 } else if (*data == 0x50) {
1091 data++;
1092 int mod, regop, rm;
1093 get_modrm(*data, &mod, &regop, &rm);
1094 AppendToBuffer("movmskpd %s,%s",
1095 NameOfCPURegister(regop),
Steve Block3ce2e202009-11-05 08:53:23 +00001096 NameOfXMMRegister(rm));
1097 data++;
Leon Clarkee46be812010-01-19 14:06:41 +00001098 } else if (*data == 0x57) {
1099 data++;
1100 int mod, regop, rm;
1101 get_modrm(*data, &mod, &regop, &rm);
1102 AppendToBuffer("xorpd %s,%s",
1103 NameOfXMMRegister(regop),
1104 NameOfXMMRegister(rm));
1105 data++;
Steve Block6ded16b2010-05-10 14:33:55 +01001106 } else if (*data == 0x6E) {
1107 data++;
1108 int mod, regop, rm;
1109 get_modrm(*data, &mod, &regop, &rm);
1110 AppendToBuffer("movd %s,", NameOfXMMRegister(regop));
1111 data += PrintRightOperand(data);
Leon Clarkee46be812010-01-19 14:06:41 +00001112 } else if (*data == 0x6F) {
1113 data++;
1114 int mod, regop, rm;
1115 get_modrm(*data, &mod, &regop, &rm);
1116 AppendToBuffer("movdqa %s,", NameOfXMMRegister(regop));
1117 data += PrintRightOperand(data);
1118 } else if (*data == 0x7F) {
1119 AppendToBuffer("movdqa ");
1120 data++;
1121 int mod, regop, rm;
1122 get_modrm(*data, &mod, &regop, &rm);
1123 data += PrintRightOperand(data);
1124 AppendToBuffer(",%s", NameOfXMMRegister(regop));
Steve Block6ded16b2010-05-10 14:33:55 +01001125 } else if (*data == 0xEF) {
1126 data++;
1127 int mod, regop, rm;
1128 get_modrm(*data, &mod, &regop, &rm);
1129 AppendToBuffer("pxor %s,%s",
1130 NameOfXMMRegister(regop),
1131 NameOfXMMRegister(rm));
1132 data++;
Steve Block3ce2e202009-11-05 08:53:23 +00001133 } else {
1134 UnimplementedInstruction();
1135 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001136 } else {
1137 UnimplementedInstruction();
1138 }
1139 break;
1140
1141 case 0xFE:
1142 { data++;
1143 int mod, regop, rm;
1144 get_modrm(*data, &mod, &regop, &rm);
1145 if (mod == 3 && regop == ecx) {
1146 AppendToBuffer("dec_b %s", NameOfCPURegister(rm));
1147 } else {
1148 UnimplementedInstruction();
1149 }
1150 data++;
1151 }
1152 break;
1153
1154 case 0x68:
1155 AppendToBuffer("push 0x%x", *reinterpret_cast<int32_t*>(data+1));
1156 data += 5;
1157 break;
1158
1159 case 0x6A:
1160 AppendToBuffer("push 0x%x", *reinterpret_cast<int8_t*>(data + 1));
1161 data += 2;
1162 break;
1163
1164 case 0xA8:
1165 AppendToBuffer("test al,0x%x", *reinterpret_cast<uint8_t*>(data+1));
1166 data += 2;
1167 break;
1168
Leon Clarkee46be812010-01-19 14:06:41 +00001169 case 0x2C:
1170 AppendToBuffer("subb eax,0x%x", *reinterpret_cast<uint8_t*>(data+1));
1171 data += 2;
1172 break;
1173
Steve Blocka7e24c12009-10-30 11:49:00 +00001174 case 0xA9:
1175 AppendToBuffer("test eax,0x%x", *reinterpret_cast<int32_t*>(data+1));
1176 data += 5;
1177 break;
1178
1179 case 0xD1: // fall through
1180 case 0xD3: // fall through
1181 case 0xC1:
1182 data += D1D3C1Instruction(data);
1183 break;
1184
1185 case 0xD9: // fall through
1186 case 0xDA: // fall through
1187 case 0xDB: // fall through
1188 case 0xDC: // fall through
1189 case 0xDD: // fall through
1190 case 0xDE: // fall through
1191 case 0xDF:
1192 data += FPUInstruction(data);
1193 break;
1194
1195 case 0xEB:
1196 data += JumpShort(data);
1197 break;
1198
1199 case 0xF2:
1200 if (*(data+1) == 0x0F) {
1201 byte b2 = *(data+2);
1202 if (b2 == 0x11) {
1203 AppendToBuffer("movsd ");
1204 data += 3;
1205 int mod, regop, rm;
1206 get_modrm(*data, &mod, &regop, &rm);
1207 data += PrintRightOperand(data);
1208 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1209 } else if (b2 == 0x10) {
1210 data += 3;
1211 int mod, regop, rm;
1212 get_modrm(*data, &mod, &regop, &rm);
1213 AppendToBuffer("movsd %s,", NameOfXMMRegister(regop));
1214 data += PrintRightOperand(data);
1215 } else {
1216 const char* mnem = "?";
1217 switch (b2) {
1218 case 0x2A: mnem = "cvtsi2sd"; break;
Steve Block6ded16b2010-05-10 14:33:55 +01001219 case 0x2C: mnem = "cvttsd2si"; break;
1220 case 0x51: mnem = "sqrtsd"; break;
Steve Blocka7e24c12009-10-30 11:49:00 +00001221 case 0x58: mnem = "addsd"; break;
1222 case 0x59: mnem = "mulsd"; break;
1223 case 0x5C: mnem = "subsd"; break;
1224 case 0x5E: mnem = "divsd"; break;
1225 }
1226 data += 3;
1227 int mod, regop, rm;
1228 get_modrm(*data, &mod, &regop, &rm);
1229 if (b2 == 0x2A) {
Steve Block6ded16b2010-05-10 14:33:55 +01001230 if (mod != 0x3) {
1231 AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
1232 data += PrintRightOperand(data);
1233 } else {
1234 AppendToBuffer("%s %s,%s",
1235 mnem,
1236 NameOfXMMRegister(regop),
1237 NameOfCPURegister(rm));
1238 data++;
1239 }
1240 } else if (b2 == 0x2C) {
1241 if (mod != 0x3) {
1242 AppendToBuffer("%s %s,", mnem, NameOfCPURegister(regop));
1243 data += PrintRightOperand(data);
1244 } else {
1245 AppendToBuffer("%s %s,%s",
1246 mnem,
1247 NameOfCPURegister(regop),
1248 NameOfXMMRegister(rm));
1249 data++;
1250 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001251 } else {
Steve Block6ded16b2010-05-10 14:33:55 +01001252 if (mod != 0x3) {
1253 AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
1254 data += PrintRightOperand(data);
1255 } else {
1256 AppendToBuffer("%s %s,%s",
1257 mnem,
1258 NameOfXMMRegister(regop),
1259 NameOfXMMRegister(rm));
1260 data++;
1261 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001262 }
1263 }
1264 } else {
1265 UnimplementedInstruction();
1266 }
1267 break;
1268
1269 case 0xF3:
Leon Clarkee46be812010-01-19 14:06:41 +00001270 if (*(data+1) == 0x0F) {
1271 if (*(data+2) == 0x2C) {
1272 data += 3;
1273 data += PrintOperands("cvttss2si", REG_OPER_OP_ORDER, data);
Steve Block6ded16b2010-05-10 14:33:55 +01001274 } else if (*(data+2) == 0x5A) {
1275 data += 3;
1276 int mod, regop, rm;
1277 get_modrm(*data, &mod, &regop, &rm);
1278 AppendToBuffer("cvtss2sd %s,%s",
1279 NameOfXMMRegister(regop),
1280 NameOfXMMRegister(rm));
1281 data++;
Leon Clarkee46be812010-01-19 14:06:41 +00001282 } else if (*(data+2) == 0x6F) {
1283 data += 3;
1284 int mod, regop, rm;
1285 get_modrm(*data, &mod, &regop, &rm);
1286 AppendToBuffer("movdqu %s,", NameOfXMMRegister(regop));
1287 data += PrintRightOperand(data);
1288 } else if (*(data+2) == 0x7F) {
1289 AppendToBuffer("movdqu ");
1290 data += 3;
1291 int mod, regop, rm;
1292 get_modrm(*data, &mod, &regop, &rm);
1293 data += PrintRightOperand(data);
1294 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1295 } else {
1296 UnimplementedInstruction();
1297 }
1298 } else if (*(data+1) == 0xA5) {
1299 data += 2;
1300 AppendToBuffer("rep_movs");
Steve Block6ded16b2010-05-10 14:33:55 +01001301 } else if (*(data+1) == 0xAB) {
1302 data += 2;
1303 AppendToBuffer("rep_stos");
Steve Blocka7e24c12009-10-30 11:49:00 +00001304 } else {
1305 UnimplementedInstruction();
1306 }
1307 break;
1308
1309 case 0xF7:
1310 data += F7Instruction(data);
1311 break;
1312
1313 default:
1314 UnimplementedInstruction();
1315 }
1316 }
1317
1318 if (tmp_buffer_pos_ < sizeof tmp_buffer_) {
1319 tmp_buffer_[tmp_buffer_pos_] = '\0';
1320 }
1321
1322 int instr_len = data - instr;
Leon Clarkee46be812010-01-19 14:06:41 +00001323 if (instr_len == 0) {
1324 printf("%02x", *data);
1325 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001326 ASSERT(instr_len > 0); // Ensure progress.
1327
1328 int outp = 0;
1329 // Instruction bytes.
1330 for (byte* bp = instr; bp < data; bp++) {
1331 outp += v8::internal::OS::SNPrintF(out_buffer + outp,
1332 "%02x",
1333 *bp);
1334 }
1335 for (int i = 6 - instr_len; i >= 0; i--) {
1336 outp += v8::internal::OS::SNPrintF(out_buffer + outp,
1337 " ");
1338 }
1339
1340 outp += v8::internal::OS::SNPrintF(out_buffer + outp,
1341 " %s",
1342 tmp_buffer_.start());
1343 return instr_len;
1344}
1345
1346
1347//------------------------------------------------------------------------------
1348
1349
1350static const char* cpu_regs[8] = {
1351 "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi"
1352};
1353
1354
1355static const char* byte_cpu_regs[8] = {
1356 "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh"
1357};
1358
1359
1360static const char* xmm_regs[8] = {
1361 "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7"
1362};
1363
1364
1365const char* NameConverter::NameOfAddress(byte* addr) const {
1366 static v8::internal::EmbeddedVector<char, 32> tmp_buffer;
1367 v8::internal::OS::SNPrintF(tmp_buffer, "%p", addr);
1368 return tmp_buffer.start();
1369}
1370
1371
1372const char* NameConverter::NameOfConstant(byte* addr) const {
1373 return NameOfAddress(addr);
1374}
1375
1376
1377const char* NameConverter::NameOfCPURegister(int reg) const {
1378 if (0 <= reg && reg < 8) return cpu_regs[reg];
1379 return "noreg";
1380}
1381
1382
1383const char* NameConverter::NameOfByteCPURegister(int reg) const {
1384 if (0 <= reg && reg < 8) return byte_cpu_regs[reg];
1385 return "noreg";
1386}
1387
1388
1389const char* NameConverter::NameOfXMMRegister(int reg) const {
1390 if (0 <= reg && reg < 8) return xmm_regs[reg];
1391 return "noxmmreg";
1392}
1393
1394
1395const char* NameConverter::NameInCode(byte* addr) const {
1396 // IA32 does not embed debug strings at the moment.
1397 UNREACHABLE();
1398 return "";
1399}
1400
1401
1402//------------------------------------------------------------------------------
1403
1404Disassembler::Disassembler(const NameConverter& converter)
1405 : converter_(converter) {}
1406
1407
1408Disassembler::~Disassembler() {}
1409
1410
1411int Disassembler::InstructionDecode(v8::internal::Vector<char> buffer,
1412 byte* instruction) {
1413 DisassemblerIA32 d(converter_, false /*do not crash if unimplemented*/);
1414 return d.InstructionDecode(buffer, instruction);
1415}
1416
1417
1418// The IA-32 assembler does not currently use constant pools.
1419int Disassembler::ConstantPoolSizeAt(byte* instruction) { return -1; }
1420
1421
1422/*static*/ void Disassembler::Disassemble(FILE* f, byte* begin, byte* end) {
1423 NameConverter converter;
1424 Disassembler d(converter);
1425 for (byte* pc = begin; pc < end;) {
1426 v8::internal::EmbeddedVector<char, 128> buffer;
1427 buffer[0] = '\0';
1428 byte* prev_pc = pc;
1429 pc += d.InstructionDecode(buffer, pc);
1430 fprintf(f, "%p", prev_pc);
1431 fprintf(f, " ");
1432
1433 for (byte* bp = prev_pc; bp < pc; bp++) {
1434 fprintf(f, "%02x", *bp);
1435 }
1436 for (int i = 6 - (pc - prev_pc); i >= 0; i--) {
1437 fprintf(f, " ");
1438 }
1439 fprintf(f, " %s\n", buffer.start());
1440 }
1441}
1442
1443
1444} // namespace disasm
Leon Clarkef7060e22010-06-03 12:02:55 +01001445
1446#endif // V8_TARGET_ARCH_IA32