blob: b5ddcca19211086e965a03ccc3c3c810606587d4 [file] [log] [blame]
Ben Murdoch257744e2011-11-30 15:57:28 +00001// Copyright 2011 the V8 project authors. All rights reserved.
Steve Blocka7e24c12009-10-30 11:49:00 +00002// 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
Ben Murdoch69a99ed2011-11-30 16:03:39 +000057static const ByteMnemonic two_operands_instr[] = {
Ben Murdoch3ef787d2012-04-12 10:51:47 +010058 {0x01, "add", OPER_REG_OP_ORDER},
Steve Blocka7e24c12009-10-30 11:49:00 +000059 {0x03, "add", REG_OPER_OP_ORDER},
Steve Blocka7e24c12009-10-30 11:49:00 +000060 {0x09, "or", OPER_REG_OP_ORDER},
61 {0x0B, "or", REG_OPER_OP_ORDER},
62 {0x1B, "sbb", REG_OPER_OP_ORDER},
Leon Clarked91b9f72010-01-27 17:25:45 +000063 {0x21, "and", OPER_REG_OP_ORDER},
64 {0x23, "and", REG_OPER_OP_ORDER},
Steve Blocka7e24c12009-10-30 11:49:00 +000065 {0x29, "sub", OPER_REG_OP_ORDER},
Leon Clarkee46be812010-01-19 14:06:41 +000066 {0x2A, "subb", REG_OPER_OP_ORDER},
Steve Blocka7e24c12009-10-30 11:49:00 +000067 {0x2B, "sub", REG_OPER_OP_ORDER},
Leon Clarkeeab96aa2010-01-27 16:31:12 +000068 {0x31, "xor", OPER_REG_OP_ORDER},
69 {0x33, "xor", REG_OPER_OP_ORDER},
Leon Clarked91b9f72010-01-27 17:25:45 +000070 {0x38, "cmpb", OPER_REG_OP_ORDER},
71 {0x3A, "cmpb", REG_OPER_OP_ORDER},
72 {0x3B, "cmp", REG_OPER_OP_ORDER},
73 {0x84, "test_b", REG_OPER_OP_ORDER},
74 {0x85, "test", REG_OPER_OP_ORDER},
Steve Blocka7e24c12009-10-30 11:49:00 +000075 {0x87, "xchg", REG_OPER_OP_ORDER},
76 {0x8A, "mov_b", REG_OPER_OP_ORDER},
77 {0x8B, "mov", REG_OPER_OP_ORDER},
Leon Clarked91b9f72010-01-27 17:25:45 +000078 {0x8D, "lea", REG_OPER_OP_ORDER},
Steve Blocka7e24c12009-10-30 11:49:00 +000079 {-1, "", UNSET_OP_ORDER}
80};
81
82
Ben Murdoch69a99ed2011-11-30 16:03:39 +000083static const ByteMnemonic zero_operands_instr[] = {
Steve Blocka7e24c12009-10-30 11:49:00 +000084 {0xC3, "ret", UNSET_OP_ORDER},
85 {0xC9, "leave", UNSET_OP_ORDER},
86 {0x90, "nop", UNSET_OP_ORDER},
87 {0xF4, "hlt", UNSET_OP_ORDER},
88 {0xCC, "int3", UNSET_OP_ORDER},
89 {0x60, "pushad", UNSET_OP_ORDER},
90 {0x61, "popad", UNSET_OP_ORDER},
91 {0x9C, "pushfd", UNSET_OP_ORDER},
92 {0x9D, "popfd", UNSET_OP_ORDER},
93 {0x9E, "sahf", UNSET_OP_ORDER},
94 {0x99, "cdq", UNSET_OP_ORDER},
95 {0x9B, "fwait", UNSET_OP_ORDER},
Steve Block6ded16b2010-05-10 14:33:55 +010096 {0xFC, "cld", UNSET_OP_ORDER},
Leon Clarkef7060e22010-06-03 12:02:55 +010097 {0xAB, "stos", UNSET_OP_ORDER},
Steve Blocka7e24c12009-10-30 11:49:00 +000098 {-1, "", UNSET_OP_ORDER}
99};
100
101
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000102static const ByteMnemonic call_jump_instr[] = {
Steve Blocka7e24c12009-10-30 11:49:00 +0000103 {0xE8, "call", UNSET_OP_ORDER},
104 {0xE9, "jmp", UNSET_OP_ORDER},
105 {-1, "", UNSET_OP_ORDER}
106};
107
108
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000109static const ByteMnemonic short_immediate_instr[] = {
Steve Blocka7e24c12009-10-30 11:49:00 +0000110 {0x05, "add", UNSET_OP_ORDER},
111 {0x0D, "or", UNSET_OP_ORDER},
112 {0x15, "adc", UNSET_OP_ORDER},
113 {0x25, "and", UNSET_OP_ORDER},
114 {0x2D, "sub", UNSET_OP_ORDER},
115 {0x35, "xor", UNSET_OP_ORDER},
116 {0x3D, "cmp", UNSET_OP_ORDER},
117 {-1, "", UNSET_OP_ORDER}
118};
119
120
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100121// Generally we don't want to generate these because they are subject to partial
122// register stalls. They are included for completeness and because the cmp
123// variant is used by the RecordWrite stub. Because it does not update the
124// register it is not subject to partial register stalls.
125static ByteMnemonic byte_immediate_instr[] = {
126 {0x0c, "or", UNSET_OP_ORDER},
127 {0x24, "and", UNSET_OP_ORDER},
128 {0x34, "xor", UNSET_OP_ORDER},
129 {0x3c, "cmp", UNSET_OP_ORDER},
130 {-1, "", UNSET_OP_ORDER}
131};
132
133
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000134static const char* const jump_conditional_mnem[] = {
Steve Blocka7e24c12009-10-30 11:49:00 +0000135 /*0*/ "jo", "jno", "jc", "jnc",
136 /*4*/ "jz", "jnz", "jna", "ja",
137 /*8*/ "js", "jns", "jpe", "jpo",
138 /*12*/ "jl", "jnl", "jng", "jg"
139};
140
141
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000142static const char* const set_conditional_mnem[] = {
Steve Blocka7e24c12009-10-30 11:49:00 +0000143 /*0*/ "seto", "setno", "setc", "setnc",
144 /*4*/ "setz", "setnz", "setna", "seta",
145 /*8*/ "sets", "setns", "setpe", "setpo",
146 /*12*/ "setl", "setnl", "setng", "setg"
147};
148
149
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000150static const char* const conditional_move_mnem[] = {
Steve Block3ce2e202009-11-05 08:53:23 +0000151 /*0*/ "cmovo", "cmovno", "cmovc", "cmovnc",
152 /*4*/ "cmovz", "cmovnz", "cmovna", "cmova",
153 /*8*/ "cmovs", "cmovns", "cmovpe", "cmovpo",
154 /*12*/ "cmovl", "cmovnl", "cmovng", "cmovg"
155};
156
157
Steve Blocka7e24c12009-10-30 11:49:00 +0000158enum InstructionType {
159 NO_INSTR,
160 ZERO_OPERANDS_INSTR,
161 TWO_OPERANDS_INSTR,
162 JUMP_CONDITIONAL_SHORT_INSTR,
163 REGISTER_INSTR,
164 MOVE_REG_INSTR,
165 CALL_JUMP_INSTR,
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100166 SHORT_IMMEDIATE_INSTR,
167 BYTE_IMMEDIATE_INSTR
Steve Blocka7e24c12009-10-30 11:49:00 +0000168};
169
170
171struct InstructionDesc {
172 const char* mnem;
173 InstructionType type;
174 OperandOrder op_order_;
175};
176
177
178class InstructionTable {
179 public:
180 InstructionTable();
181 const InstructionDesc& Get(byte x) const { return instructions_[x]; }
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100182 static InstructionTable* get_instance() {
183 static InstructionTable table;
184 return &table;
185 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000186
187 private:
188 InstructionDesc instructions_[256];
189 void Clear();
190 void Init();
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000191 void CopyTable(const ByteMnemonic bm[], InstructionType type);
Steve Blocka7e24c12009-10-30 11:49:00 +0000192 void SetTableRange(InstructionType type,
193 byte start,
194 byte end,
195 const char* mnem);
196 void AddJumpConditionalShort();
197};
198
199
200InstructionTable::InstructionTable() {
201 Clear();
202 Init();
203}
204
205
206void InstructionTable::Clear() {
207 for (int i = 0; i < 256; i++) {
208 instructions_[i].mnem = "";
209 instructions_[i].type = NO_INSTR;
210 instructions_[i].op_order_ = UNSET_OP_ORDER;
211 }
212}
213
214
215void InstructionTable::Init() {
216 CopyTable(two_operands_instr, TWO_OPERANDS_INSTR);
217 CopyTable(zero_operands_instr, ZERO_OPERANDS_INSTR);
218 CopyTable(call_jump_instr, CALL_JUMP_INSTR);
219 CopyTable(short_immediate_instr, SHORT_IMMEDIATE_INSTR);
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100220 CopyTable(byte_immediate_instr, BYTE_IMMEDIATE_INSTR);
Steve Blocka7e24c12009-10-30 11:49:00 +0000221 AddJumpConditionalShort();
222 SetTableRange(REGISTER_INSTR, 0x40, 0x47, "inc");
223 SetTableRange(REGISTER_INSTR, 0x48, 0x4F, "dec");
224 SetTableRange(REGISTER_INSTR, 0x50, 0x57, "push");
225 SetTableRange(REGISTER_INSTR, 0x58, 0x5F, "pop");
226 SetTableRange(REGISTER_INSTR, 0x91, 0x97, "xchg eax,"); // 0x90 is nop.
227 SetTableRange(MOVE_REG_INSTR, 0xB8, 0xBF, "mov");
228}
229
230
Ben Murdoch69a99ed2011-11-30 16:03:39 +0000231void InstructionTable::CopyTable(const ByteMnemonic bm[],
232 InstructionType type) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000233 for (int i = 0; bm[i].b >= 0; i++) {
234 InstructionDesc* id = &instructions_[bm[i].b];
235 id->mnem = bm[i].mnem;
236 id->op_order_ = bm[i].op_order_;
Steve Blockd0582a62009-12-15 09:54:21 +0000237 ASSERT_EQ(NO_INSTR, id->type); // Information not already entered.
Steve Blocka7e24c12009-10-30 11:49:00 +0000238 id->type = type;
239 }
240}
241
242
243void InstructionTable::SetTableRange(InstructionType type,
244 byte start,
245 byte end,
246 const char* mnem) {
247 for (byte b = start; b <= end; b++) {
248 InstructionDesc* id = &instructions_[b];
Steve Blockd0582a62009-12-15 09:54:21 +0000249 ASSERT_EQ(NO_INSTR, id->type); // Information not already entered.
Steve Blocka7e24c12009-10-30 11:49:00 +0000250 id->mnem = mnem;
251 id->type = type;
252 }
253}
254
255
256void InstructionTable::AddJumpConditionalShort() {
257 for (byte b = 0x70; b <= 0x7F; b++) {
258 InstructionDesc* id = &instructions_[b];
Steve Blockd0582a62009-12-15 09:54:21 +0000259 ASSERT_EQ(NO_INSTR, id->type); // Information not already entered.
Steve Blocka7e24c12009-10-30 11:49:00 +0000260 id->mnem = jump_conditional_mnem[b & 0x0F];
261 id->type = JUMP_CONDITIONAL_SHORT_INSTR;
262 }
263}
264
265
Steve Blocka7e24c12009-10-30 11:49:00 +0000266// The IA32 disassembler implementation.
267class DisassemblerIA32 {
268 public:
269 DisassemblerIA32(const NameConverter& converter,
270 bool abort_on_unimplemented = true)
271 : converter_(converter),
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100272 instruction_table_(InstructionTable::get_instance()),
Steve Blocka7e24c12009-10-30 11:49:00 +0000273 tmp_buffer_pos_(0),
274 abort_on_unimplemented_(abort_on_unimplemented) {
275 tmp_buffer_[0] = '\0';
276 }
277
278 virtual ~DisassemblerIA32() {}
279
280 // Writes one disassembled instruction into 'buffer' (0-terminated).
281 // Returns the length of the disassembled machine instruction in bytes.
282 int InstructionDecode(v8::internal::Vector<char> buffer, byte* instruction);
283
284 private:
285 const NameConverter& converter_;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100286 InstructionTable* instruction_table_;
Steve Blocka7e24c12009-10-30 11:49:00 +0000287 v8::internal::EmbeddedVector<char, 128> tmp_buffer_;
288 unsigned int tmp_buffer_pos_;
289 bool abort_on_unimplemented_;
290
Steve Blocka7e24c12009-10-30 11:49:00 +0000291 enum {
292 eax = 0,
293 ecx = 1,
294 edx = 2,
295 ebx = 3,
296 esp = 4,
297 ebp = 5,
298 esi = 6,
299 edi = 7
300 };
301
302
Steve Blockd0582a62009-12-15 09:54:21 +0000303 enum ShiftOpcodeExtension {
304 kROL = 0,
305 kROR = 1,
306 kRCL = 2,
307 kRCR = 3,
308 kSHL = 4,
309 KSHR = 5,
310 kSAR = 7
311 };
312
313
Steve Blocka7e24c12009-10-30 11:49:00 +0000314 const char* NameOfCPURegister(int reg) const {
315 return converter_.NameOfCPURegister(reg);
316 }
317
318
319 const char* NameOfByteCPURegister(int reg) const {
320 return converter_.NameOfByteCPURegister(reg);
321 }
322
323
324 const char* NameOfXMMRegister(int reg) const {
325 return converter_.NameOfXMMRegister(reg);
326 }
327
328
329 const char* NameOfAddress(byte* addr) const {
330 return converter_.NameOfAddress(addr);
331 }
332
333
334 // Disassembler helper functions.
335 static void get_modrm(byte data, int* mod, int* regop, int* rm) {
336 *mod = (data >> 6) & 3;
337 *regop = (data & 0x38) >> 3;
338 *rm = data & 7;
339 }
340
341
342 static void get_sib(byte data, int* scale, int* index, int* base) {
343 *scale = (data >> 6) & 3;
344 *index = (data >> 3) & 7;
345 *base = data & 7;
346 }
347
348 typedef const char* (DisassemblerIA32::*RegisterNameMapping)(int reg) const;
349
350 int PrintRightOperandHelper(byte* modrmp, RegisterNameMapping register_name);
351 int PrintRightOperand(byte* modrmp);
352 int PrintRightByteOperand(byte* modrmp);
Steve Block44f0eee2011-05-26 01:26:41 +0100353 int PrintRightXMMOperand(byte* modrmp);
Steve Blocka7e24c12009-10-30 11:49:00 +0000354 int PrintOperands(const char* mnem, OperandOrder op_order, byte* data);
355 int PrintImmediateOp(byte* data);
356 int F7Instruction(byte* data);
357 int D1D3C1Instruction(byte* data);
358 int JumpShort(byte* data);
359 int JumpConditional(byte* data, const char* comment);
360 int JumpConditionalShort(byte* data, const char* comment);
361 int SetCC(byte* data);
Steve Block3ce2e202009-11-05 08:53:23 +0000362 int CMov(byte* data);
Steve Blocka7e24c12009-10-30 11:49:00 +0000363 int FPUInstruction(byte* data);
Steve Blockd0582a62009-12-15 09:54:21 +0000364 int MemoryFPUInstruction(int escape_opcode, int regop, byte* modrm_start);
365 int RegisterFPUInstruction(int escape_opcode, byte modrm_byte);
Steve Blocka7e24c12009-10-30 11:49:00 +0000366 void AppendToBuffer(const char* format, ...);
367
368
369 void UnimplementedInstruction() {
370 if (abort_on_unimplemented_) {
371 UNIMPLEMENTED();
372 } else {
373 AppendToBuffer("'Unimplemented Instruction'");
374 }
375 }
376};
377
378
379void DisassemblerIA32::AppendToBuffer(const char* format, ...) {
380 v8::internal::Vector<char> buf = tmp_buffer_ + tmp_buffer_pos_;
381 va_list args;
382 va_start(args, format);
383 int result = v8::internal::OS::VSNPrintF(buf, format, args);
384 va_end(args);
385 tmp_buffer_pos_ += result;
386}
387
388int DisassemblerIA32::PrintRightOperandHelper(
389 byte* modrmp,
Steve Block44f0eee2011-05-26 01:26:41 +0100390 RegisterNameMapping direct_register_name) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000391 int mod, regop, rm;
392 get_modrm(*modrmp, &mod, &regop, &rm);
Steve Block44f0eee2011-05-26 01:26:41 +0100393 RegisterNameMapping register_name = (mod == 3) ? direct_register_name :
394 &DisassemblerIA32::NameOfCPURegister;
Steve Blocka7e24c12009-10-30 11:49:00 +0000395 switch (mod) {
396 case 0:
397 if (rm == ebp) {
398 int32_t disp = *reinterpret_cast<int32_t*>(modrmp+1);
399 AppendToBuffer("[0x%x]", disp);
400 return 5;
401 } else if (rm == esp) {
402 byte sib = *(modrmp + 1);
403 int scale, index, base;
404 get_sib(sib, &scale, &index, &base);
405 if (index == esp && base == esp && scale == 0 /*times_1*/) {
406 AppendToBuffer("[%s]", (this->*register_name)(rm));
407 return 2;
408 } else if (base == ebp) {
409 int32_t disp = *reinterpret_cast<int32_t*>(modrmp + 2);
410 AppendToBuffer("[%s*%d+0x%x]",
411 (this->*register_name)(index),
412 1 << scale,
413 disp);
414 return 6;
415 } else if (index != esp && base != ebp) {
416 // [base+index*scale]
417 AppendToBuffer("[%s+%s*%d]",
418 (this->*register_name)(base),
419 (this->*register_name)(index),
420 1 << scale);
421 return 2;
422 } else {
423 UnimplementedInstruction();
424 return 1;
425 }
426 } else {
427 AppendToBuffer("[%s]", (this->*register_name)(rm));
428 return 1;
429 }
430 break;
431 case 1: // fall through
432 case 2:
433 if (rm == esp) {
434 byte sib = *(modrmp + 1);
435 int scale, index, base;
436 get_sib(sib, &scale, &index, &base);
437 int disp =
438 mod == 2 ? *reinterpret_cast<int32_t*>(modrmp + 2) : *(modrmp + 2);
439 if (index == base && index == rm /*esp*/ && scale == 0 /*times_1*/) {
440 AppendToBuffer("[%s+0x%x]", (this->*register_name)(rm), disp);
441 } else {
442 AppendToBuffer("[%s+%s*%d+0x%x]",
443 (this->*register_name)(base),
444 (this->*register_name)(index),
445 1 << scale,
446 disp);
447 }
448 return mod == 2 ? 6 : 3;
449 } else {
450 // No sib.
451 int disp =
452 mod == 2 ? *reinterpret_cast<int32_t*>(modrmp + 1) : *(modrmp + 1);
453 AppendToBuffer("[%s+0x%x]", (this->*register_name)(rm), disp);
454 return mod == 2 ? 5 : 2;
455 }
456 break;
457 case 3:
458 AppendToBuffer("%s", (this->*register_name)(rm));
459 return 1;
460 default:
461 UnimplementedInstruction();
462 return 1;
463 }
464 UNREACHABLE();
465}
466
467
468int DisassemblerIA32::PrintRightOperand(byte* modrmp) {
469 return PrintRightOperandHelper(modrmp, &DisassemblerIA32::NameOfCPURegister);
470}
471
472
473int DisassemblerIA32::PrintRightByteOperand(byte* modrmp) {
474 return PrintRightOperandHelper(modrmp,
475 &DisassemblerIA32::NameOfByteCPURegister);
476}
477
478
Steve Block44f0eee2011-05-26 01:26:41 +0100479int DisassemblerIA32::PrintRightXMMOperand(byte* modrmp) {
480 return PrintRightOperandHelper(modrmp,
481 &DisassemblerIA32::NameOfXMMRegister);
482}
483
484
Steve Blocka7e24c12009-10-30 11:49:00 +0000485// Returns number of bytes used including the current *data.
486// Writes instruction's mnemonic, left and right operands to 'tmp_buffer_'.
487int DisassemblerIA32::PrintOperands(const char* mnem,
488 OperandOrder op_order,
489 byte* data) {
490 byte modrm = *data;
491 int mod, regop, rm;
492 get_modrm(modrm, &mod, &regop, &rm);
493 int advance = 0;
494 switch (op_order) {
495 case REG_OPER_OP_ORDER: {
496 AppendToBuffer("%s %s,", mnem, NameOfCPURegister(regop));
497 advance = PrintRightOperand(data);
498 break;
499 }
500 case OPER_REG_OP_ORDER: {
501 AppendToBuffer("%s ", mnem);
502 advance = PrintRightOperand(data);
503 AppendToBuffer(",%s", NameOfCPURegister(regop));
504 break;
505 }
506 default:
507 UNREACHABLE();
508 break;
509 }
510 return advance;
511}
512
513
514// Returns number of bytes used by machine instruction, including *data byte.
515// Writes immediate instructions to 'tmp_buffer_'.
516int DisassemblerIA32::PrintImmediateOp(byte* data) {
517 bool sign_extension_bit = (*data & 0x02) != 0;
518 byte modrm = *(data+1);
519 int mod, regop, rm;
520 get_modrm(modrm, &mod, &regop, &rm);
521 const char* mnem = "Imm???";
522 switch (regop) {
523 case 0: mnem = "add"; break;
524 case 1: mnem = "or"; break;
525 case 2: mnem = "adc"; break;
526 case 4: mnem = "and"; break;
527 case 5: mnem = "sub"; break;
528 case 6: mnem = "xor"; break;
529 case 7: mnem = "cmp"; break;
530 default: UnimplementedInstruction();
531 }
532 AppendToBuffer("%s ", mnem);
533 int count = PrintRightOperand(data+1);
534 if (sign_extension_bit) {
535 AppendToBuffer(",0x%x", *(data + 1 + count));
536 return 1 + count + 1 /*int8*/;
537 } else {
538 AppendToBuffer(",0x%x", *reinterpret_cast<int32_t*>(data + 1 + count));
539 return 1 + count + 4 /*int32_t*/;
540 }
541}
542
543
544// Returns number of bytes used, including *data.
545int DisassemblerIA32::F7Instruction(byte* data) {
Steve Blockd0582a62009-12-15 09:54:21 +0000546 ASSERT_EQ(0xF7, *data);
Steve Blocka7e24c12009-10-30 11:49:00 +0000547 byte modrm = *(data+1);
548 int mod, regop, rm;
549 get_modrm(modrm, &mod, &regop, &rm);
550 if (mod == 3 && regop != 0) {
551 const char* mnem = NULL;
552 switch (regop) {
553 case 2: mnem = "not"; break;
554 case 3: mnem = "neg"; break;
555 case 4: mnem = "mul"; break;
556 case 7: mnem = "idiv"; break;
557 default: UnimplementedInstruction();
558 }
559 AppendToBuffer("%s %s", mnem, NameOfCPURegister(rm));
560 return 2;
561 } else if (mod == 3 && regop == eax) {
562 int32_t imm = *reinterpret_cast<int32_t*>(data+2);
563 AppendToBuffer("test %s,0x%x", NameOfCPURegister(rm), imm);
564 return 6;
565 } else if (regop == eax) {
566 AppendToBuffer("test ");
567 int count = PrintRightOperand(data+1);
568 int32_t imm = *reinterpret_cast<int32_t*>(data+1+count);
569 AppendToBuffer(",0x%x", imm);
570 return 1+count+4 /*int32_t*/;
571 } else {
572 UnimplementedInstruction();
573 return 2;
574 }
575}
576
577int DisassemblerIA32::D1D3C1Instruction(byte* data) {
578 byte op = *data;
Steve Blockd0582a62009-12-15 09:54:21 +0000579 ASSERT(op == 0xD1 || op == 0xD3 || op == 0xC1);
Steve Blocka7e24c12009-10-30 11:49:00 +0000580 byte modrm = *(data+1);
581 int mod, regop, rm;
582 get_modrm(modrm, &mod, &regop, &rm);
583 int imm8 = -1;
584 int num_bytes = 2;
585 if (mod == 3) {
586 const char* mnem = NULL;
Steve Blockd0582a62009-12-15 09:54:21 +0000587 switch (regop) {
588 case kROL: mnem = "rol"; break;
589 case kROR: mnem = "ror"; break;
590 case kRCL: mnem = "rcl"; break;
Iain Merrick75681382010-08-19 15:07:18 +0100591 case kRCR: mnem = "rcr"; break;
Steve Blockd0582a62009-12-15 09:54:21 +0000592 case kSHL: mnem = "shl"; break;
593 case KSHR: mnem = "shr"; break;
594 case kSAR: mnem = "sar"; break;
595 default: UnimplementedInstruction();
596 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000597 if (op == 0xD1) {
598 imm8 = 1;
Steve Blocka7e24c12009-10-30 11:49:00 +0000599 } else if (op == 0xC1) {
600 imm8 = *(data+2);
601 num_bytes = 3;
Steve Blocka7e24c12009-10-30 11:49:00 +0000602 } else if (op == 0xD3) {
Steve Blockd0582a62009-12-15 09:54:21 +0000603 // Shift/rotate by cl.
Steve Blocka7e24c12009-10-30 11:49:00 +0000604 }
Steve Blockd0582a62009-12-15 09:54:21 +0000605 ASSERT_NE(NULL, mnem);
Steve Blocka7e24c12009-10-30 11:49:00 +0000606 AppendToBuffer("%s %s,", mnem, NameOfCPURegister(rm));
607 if (imm8 > 0) {
608 AppendToBuffer("%d", imm8);
609 } else {
610 AppendToBuffer("cl");
611 }
612 } else {
613 UnimplementedInstruction();
614 }
615 return num_bytes;
616}
617
618
619// Returns number of bytes used, including *data.
620int DisassemblerIA32::JumpShort(byte* data) {
Steve Blockd0582a62009-12-15 09:54:21 +0000621 ASSERT_EQ(0xEB, *data);
Steve Blocka7e24c12009-10-30 11:49:00 +0000622 byte b = *(data+1);
623 byte* dest = data + static_cast<int8_t>(b) + 2;
624 AppendToBuffer("jmp %s", NameOfAddress(dest));
625 return 2;
626}
627
628
629// Returns number of bytes used, including *data.
630int DisassemblerIA32::JumpConditional(byte* data, const char* comment) {
Steve Blockd0582a62009-12-15 09:54:21 +0000631 ASSERT_EQ(0x0F, *data);
Steve Blocka7e24c12009-10-30 11:49:00 +0000632 byte cond = *(data+1) & 0x0F;
633 byte* dest = data + *reinterpret_cast<int32_t*>(data+2) + 6;
634 const char* mnem = jump_conditional_mnem[cond];
635 AppendToBuffer("%s %s", mnem, NameOfAddress(dest));
636 if (comment != NULL) {
637 AppendToBuffer(", %s", comment);
638 }
639 return 6; // includes 0x0F
640}
641
642
643// Returns number of bytes used, including *data.
644int DisassemblerIA32::JumpConditionalShort(byte* data, const char* comment) {
645 byte cond = *data & 0x0F;
646 byte b = *(data+1);
647 byte* dest = data + static_cast<int8_t>(b) + 2;
648 const char* mnem = jump_conditional_mnem[cond];
649 AppendToBuffer("%s %s", mnem, NameOfAddress(dest));
650 if (comment != NULL) {
651 AppendToBuffer(", %s", comment);
652 }
653 return 2;
654}
655
656
657// Returns number of bytes used, including *data.
658int DisassemblerIA32::SetCC(byte* data) {
Steve Blockd0582a62009-12-15 09:54:21 +0000659 ASSERT_EQ(0x0F, *data);
Steve Blocka7e24c12009-10-30 11:49:00 +0000660 byte cond = *(data+1) & 0x0F;
661 const char* mnem = set_conditional_mnem[cond];
662 AppendToBuffer("%s ", mnem);
663 PrintRightByteOperand(data+2);
Steve Blockd0582a62009-12-15 09:54:21 +0000664 return 3; // Includes 0x0F.
Steve Blocka7e24c12009-10-30 11:49:00 +0000665}
666
667
668// Returns number of bytes used, including *data.
Steve Block3ce2e202009-11-05 08:53:23 +0000669int DisassemblerIA32::CMov(byte* data) {
Steve Blockd0582a62009-12-15 09:54:21 +0000670 ASSERT_EQ(0x0F, *data);
Steve Block3ce2e202009-11-05 08:53:23 +0000671 byte cond = *(data + 1) & 0x0F;
672 const char* mnem = conditional_move_mnem[cond];
673 int op_size = PrintOperands(mnem, REG_OPER_OP_ORDER, data + 2);
674 return 2 + op_size; // includes 0x0F
675}
676
677
678// Returns number of bytes used, including *data.
Steve Blocka7e24c12009-10-30 11:49:00 +0000679int DisassemblerIA32::FPUInstruction(byte* data) {
Steve Blockd0582a62009-12-15 09:54:21 +0000680 byte escape_opcode = *data;
681 ASSERT_EQ(0xD8, escape_opcode & 0xF8);
682 byte modrm_byte = *(data+1);
683
684 if (modrm_byte >= 0xC0) {
685 return RegisterFPUInstruction(escape_opcode, modrm_byte);
686 } else {
687 return MemoryFPUInstruction(escape_opcode, modrm_byte, data+1);
Steve Blocka7e24c12009-10-30 11:49:00 +0000688 }
Steve Blockd0582a62009-12-15 09:54:21 +0000689}
690
691int DisassemblerIA32::MemoryFPUInstruction(int escape_opcode,
692 int modrm_byte,
693 byte* modrm_start) {
694 const char* mnem = "?";
695 int regop = (modrm_byte >> 3) & 0x7; // reg/op field of modrm byte.
696 switch (escape_opcode) {
697 case 0xD9: switch (regop) {
698 case 0: mnem = "fld_s"; break;
699 case 3: mnem = "fstp_s"; break;
700 case 7: mnem = "fstcw"; break;
701 default: UnimplementedInstruction();
702 }
703 break;
704
705 case 0xDB: switch (regop) {
706 case 0: mnem = "fild_s"; break;
707 case 1: mnem = "fisttp_s"; break;
708 case 2: mnem = "fist_s"; break;
709 case 3: mnem = "fistp_s"; break;
710 default: UnimplementedInstruction();
711 }
712 break;
713
714 case 0xDD: switch (regop) {
715 case 0: mnem = "fld_d"; break;
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100716 case 1: mnem = "fisttp_d"; break;
717 case 2: mnem = "fst_d"; break;
Steve Blockd0582a62009-12-15 09:54:21 +0000718 case 3: mnem = "fstp_d"; break;
719 default: UnimplementedInstruction();
720 }
721 break;
722
723 case 0xDF: switch (regop) {
724 case 5: mnem = "fild_d"; break;
725 case 7: mnem = "fistp_d"; break;
726 default: UnimplementedInstruction();
727 }
728 break;
729
730 default: UnimplementedInstruction();
731 }
732 AppendToBuffer("%s ", mnem);
733 int count = PrintRightOperand(modrm_start);
734 return count + 1;
735}
736
737int DisassemblerIA32::RegisterFPUInstruction(int escape_opcode,
738 byte modrm_byte) {
739 bool has_register = false; // Is the FPU register encoded in modrm_byte?
740 const char* mnem = "?";
741
742 switch (escape_opcode) {
743 case 0xD8:
744 UnimplementedInstruction();
745 break;
746
747 case 0xD9:
748 switch (modrm_byte & 0xF8) {
Kristian Monsen0d5e1162010-09-30 15:31:59 +0100749 case 0xC0:
750 mnem = "fld";
751 has_register = true;
752 break;
Steve Blockd0582a62009-12-15 09:54:21 +0000753 case 0xC8:
754 mnem = "fxch";
755 has_register = true;
756 break;
757 default:
758 switch (modrm_byte) {
759 case 0xE0: mnem = "fchs"; break;
760 case 0xE1: mnem = "fabs"; break;
761 case 0xE4: mnem = "ftst"; break;
762 case 0xE8: mnem = "fld1"; break;
Andrei Popescu402d9372010-02-26 13:31:12 +0000763 case 0xEB: mnem = "fldpi"; break;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100764 case 0xED: mnem = "fldln2"; break;
Steve Blockd0582a62009-12-15 09:54:21 +0000765 case 0xEE: mnem = "fldz"; break;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100766 case 0xF0: mnem = "f2xm1"; break;
Ben Murdochb0fe1622011-05-05 13:52:32 +0100767 case 0xF1: mnem = "fyl2x"; break;
Steve Blockd0582a62009-12-15 09:54:21 +0000768 case 0xF5: mnem = "fprem1"; break;
769 case 0xF7: mnem = "fincstp"; break;
770 case 0xF8: mnem = "fprem"; break;
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100771 case 0xFC: mnem = "frndint"; break;
772 case 0xFD: mnem = "fscale"; break;
Steve Blockd0582a62009-12-15 09:54:21 +0000773 case 0xFE: mnem = "fsin"; break;
774 case 0xFF: mnem = "fcos"; break;
775 default: UnimplementedInstruction();
776 }
777 }
778 break;
779
780 case 0xDA:
781 if (modrm_byte == 0xE9) {
782 mnem = "fucompp";
783 } else {
784 UnimplementedInstruction();
785 }
786 break;
787
788 case 0xDB:
789 if ((modrm_byte & 0xF8) == 0xE8) {
790 mnem = "fucomi";
791 has_register = true;
792 } else if (modrm_byte == 0xE2) {
793 mnem = "fclex";
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100794 } else if (modrm_byte == 0xE3) {
795 mnem = "fninit";
Steve Blockd0582a62009-12-15 09:54:21 +0000796 } else {
797 UnimplementedInstruction();
798 }
799 break;
800
801 case 0xDC:
802 has_register = true;
803 switch (modrm_byte & 0xF8) {
804 case 0xC0: mnem = "fadd"; break;
805 case 0xE8: mnem = "fsub"; break;
806 case 0xC8: mnem = "fmul"; break;
807 case 0xF8: mnem = "fdiv"; break;
808 default: UnimplementedInstruction();
809 }
810 break;
811
812 case 0xDD:
813 has_register = true;
814 switch (modrm_byte & 0xF8) {
815 case 0xC0: mnem = "ffree"; break;
816 case 0xD8: mnem = "fstp"; break;
817 default: UnimplementedInstruction();
818 }
819 break;
820
821 case 0xDE:
822 if (modrm_byte == 0xD9) {
823 mnem = "fcompp";
824 } else {
825 has_register = true;
826 switch (modrm_byte & 0xF8) {
827 case 0xC0: mnem = "faddp"; break;
828 case 0xE8: mnem = "fsubp"; break;
829 case 0xC8: mnem = "fmulp"; break;
830 case 0xF8: mnem = "fdivp"; break;
831 default: UnimplementedInstruction();
832 }
833 }
834 break;
835
836 case 0xDF:
837 if (modrm_byte == 0xE0) {
838 mnem = "fnstsw_ax";
839 } else if ((modrm_byte & 0xF8) == 0xE8) {
840 mnem = "fucomip";
841 has_register = true;
842 }
843 break;
844
845 default: UnimplementedInstruction();
846 }
847
848 if (has_register) {
849 AppendToBuffer("%s st%d", mnem, modrm_byte & 0x7);
850 } else {
851 AppendToBuffer("%s", mnem);
852 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000853 return 2;
854}
855
856
857// Mnemonics for instructions 0xF0 byte.
858// Returns NULL if the instruction is not handled here.
859static const char* F0Mnem(byte f0byte) {
860 switch (f0byte) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100861 case 0x18: return "prefetch";
Steve Blocka7e24c12009-10-30 11:49:00 +0000862 case 0xA2: return "cpuid";
863 case 0x31: return "rdtsc";
864 case 0xBE: return "movsx_b";
865 case 0xBF: return "movsx_w";
866 case 0xB6: return "movzx_b";
867 case 0xB7: return "movzx_w";
868 case 0xAF: return "imul";
869 case 0xA5: return "shld";
870 case 0xAD: return "shrd";
871 case 0xAB: return "bts";
872 default: return NULL;
873 }
874}
875
876
877// Disassembled instruction '*instr' and writes it into 'out_buffer'.
878int DisassemblerIA32::InstructionDecode(v8::internal::Vector<char> out_buffer,
879 byte* instr) {
880 tmp_buffer_pos_ = 0; // starting to write as position 0
881 byte* data = instr;
882 // Check for hints.
883 const char* branch_hint = NULL;
884 // We use these two prefixes only with branch prediction
885 if (*data == 0x3E /*ds*/) {
886 branch_hint = "predicted taken";
887 data++;
888 } else if (*data == 0x2E /*cs*/) {
889 branch_hint = "predicted not taken";
890 data++;
891 }
892 bool processed = true; // Will be set to false if the current instruction
893 // is not in 'instructions' table.
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100894 const InstructionDesc& idesc = instruction_table_->Get(*data);
Steve Blocka7e24c12009-10-30 11:49:00 +0000895 switch (idesc.type) {
896 case ZERO_OPERANDS_INSTR:
897 AppendToBuffer(idesc.mnem);
898 data++;
899 break;
900
901 case TWO_OPERANDS_INSTR:
902 data++;
903 data += PrintOperands(idesc.mnem, idesc.op_order_, data);
904 break;
905
906 case JUMP_CONDITIONAL_SHORT_INSTR:
907 data += JumpConditionalShort(data, branch_hint);
908 break;
909
910 case REGISTER_INSTR:
911 AppendToBuffer("%s %s", idesc.mnem, NameOfCPURegister(*data & 0x07));
912 data++;
913 break;
914
915 case MOVE_REG_INSTR: {
916 byte* addr = reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data+1));
917 AppendToBuffer("mov %s,%s",
918 NameOfCPURegister(*data & 0x07),
919 NameOfAddress(addr));
920 data += 5;
921 break;
922 }
923
924 case CALL_JUMP_INSTR: {
925 byte* addr = data + *reinterpret_cast<int32_t*>(data+1) + 5;
926 AppendToBuffer("%s %s", idesc.mnem, NameOfAddress(addr));
927 data += 5;
928 break;
929 }
930
931 case SHORT_IMMEDIATE_INSTR: {
932 byte* addr = reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data+1));
933 AppendToBuffer("%s eax, %s", idesc.mnem, NameOfAddress(addr));
934 data += 5;
935 break;
936 }
937
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100938 case BYTE_IMMEDIATE_INSTR: {
939 AppendToBuffer("%s al, 0x%x", idesc.mnem, data[1]);
940 data += 2;
941 break;
942 }
943
Steve Blocka7e24c12009-10-30 11:49:00 +0000944 case NO_INSTR:
945 processed = false;
946 break;
947
948 default:
949 UNIMPLEMENTED(); // This type is not implemented.
950 }
951 //----------------------------
952 if (!processed) {
953 switch (*data) {
954 case 0xC2:
955 AppendToBuffer("ret 0x%x", *reinterpret_cast<uint16_t*>(data+1));
956 data += 3;
957 break;
958
959 case 0x69: // fall through
960 case 0x6B:
961 { int mod, regop, rm;
962 get_modrm(*(data+1), &mod, &regop, &rm);
963 int32_t imm =
964 *data == 0x6B ? *(data+2) : *reinterpret_cast<int32_t*>(data+2);
965 AppendToBuffer("imul %s,%s,0x%x",
966 NameOfCPURegister(regop),
967 NameOfCPURegister(rm),
968 imm);
969 data += 2 + (*data == 0x6B ? 1 : 4);
970 }
971 break;
972
973 case 0xF6:
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100974 { data++;
975 int mod, regop, rm;
976 get_modrm(*data, &mod, &regop, &rm);
977 if (regop == eax) {
978 AppendToBuffer("test_b ");
Steve Block44f0eee2011-05-26 01:26:41 +0100979 data += PrintRightByteOperand(data);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100980 int32_t imm = *data;
981 AppendToBuffer(",0x%x", imm);
982 data++;
Steve Blocka7e24c12009-10-30 11:49:00 +0000983 } else {
984 UnimplementedInstruction();
985 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000986 }
987 break;
988
989 case 0x81: // fall through
990 case 0x83: // 0x81 with sign extension bit set
991 data += PrintImmediateOp(data);
992 break;
993
994 case 0x0F:
Ben Murdoch3ef787d2012-04-12 10:51:47 +0100995 { byte f0byte = data[1];
Steve Blocka7e24c12009-10-30 11:49:00 +0000996 const char* f0mnem = F0Mnem(f0byte);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100997 if (f0byte == 0x18) {
998 int mod, regop, rm;
999 get_modrm(*data, &mod, &regop, &rm);
1000 const char* suffix[] = {"nta", "1", "2", "3"};
1001 AppendToBuffer("%s%s ", f0mnem, suffix[regop & 0x03]);
1002 data += PrintRightOperand(data);
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001003 } else if (f0byte == 0x1F && data[2] == 0) {
1004 AppendToBuffer("nop"); // 3 byte nop.
1005 data += 3;
1006 } else if (f0byte == 0x1F && data[2] == 0x40 && data[3] == 0) {
1007 AppendToBuffer("nop"); // 4 byte nop.
1008 data += 4;
1009 } else if (f0byte == 0x1F && data[2] == 0x44 && data[3] == 0 &&
1010 data[4] == 0) {
1011 AppendToBuffer("nop"); // 5 byte nop.
1012 data += 5;
1013 } else if (f0byte == 0x1F && data[2] == 0x80 && data[3] == 0 &&
1014 data[4] == 0 && data[5] == 0 && data[6] == 0) {
1015 AppendToBuffer("nop"); // 7 byte nop.
1016 data += 7;
1017 } else if (f0byte == 0x1F && data[2] == 0x84 && data[3] == 0 &&
1018 data[4] == 0 && data[5] == 0 && data[6] == 0 &&
1019 data[7] == 0) {
1020 AppendToBuffer("nop"); // 8 byte nop.
1021 data += 8;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001022 } else if (f0byte == 0xA2 || f0byte == 0x31) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001023 AppendToBuffer("%s", f0mnem);
1024 data += 2;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001025 } else if (f0byte == 0x28) {
1026 data += 2;
1027 int mod, regop, rm;
1028 get_modrm(*data, &mod, &regop, &rm);
1029 AppendToBuffer("movaps %s,%s",
1030 NameOfXMMRegister(regop),
1031 NameOfXMMRegister(rm));
1032 data++;
Ben Murdoch257744e2011-11-30 15:57:28 +00001033 } else if (f0byte == 0x57) {
1034 data += 2;
1035 int mod, regop, rm;
1036 get_modrm(*data, &mod, &regop, &rm);
1037 AppendToBuffer("xorps %s,%s",
1038 NameOfXMMRegister(regop),
1039 NameOfXMMRegister(rm));
1040 data++;
Steve Blocka7e24c12009-10-30 11:49:00 +00001041 } else if ((f0byte & 0xF0) == 0x80) {
1042 data += JumpConditional(data, branch_hint);
1043 } else if (f0byte == 0xBE || f0byte == 0xBF || f0byte == 0xB6 ||
1044 f0byte == 0xB7 || f0byte == 0xAF) {
1045 data += 2;
1046 data += PrintOperands(f0mnem, REG_OPER_OP_ORDER, data);
1047 } else if ((f0byte & 0xF0) == 0x90) {
1048 data += SetCC(data);
Steve Block3ce2e202009-11-05 08:53:23 +00001049 } else if ((f0byte & 0xF0) == 0x40) {
1050 data += CMov(data);
Steve Blocka7e24c12009-10-30 11:49:00 +00001051 } else {
1052 data += 2;
1053 if (f0byte == 0xAB || f0byte == 0xA5 || f0byte == 0xAD) {
1054 // shrd, shld, bts
1055 AppendToBuffer("%s ", f0mnem);
1056 int mod, regop, rm;
1057 get_modrm(*data, &mod, &regop, &rm);
1058 data += PrintRightOperand(data);
1059 if (f0byte == 0xAB) {
1060 AppendToBuffer(",%s", NameOfCPURegister(regop));
1061 } else {
1062 AppendToBuffer(",%s,cl", NameOfCPURegister(regop));
1063 }
1064 } else {
1065 UnimplementedInstruction();
1066 }
1067 }
1068 }
1069 break;
1070
1071 case 0x8F:
1072 { data++;
1073 int mod, regop, rm;
1074 get_modrm(*data, &mod, &regop, &rm);
1075 if (regop == eax) {
1076 AppendToBuffer("pop ");
1077 data += PrintRightOperand(data);
1078 }
1079 }
1080 break;
1081
1082 case 0xFF:
1083 { data++;
1084 int mod, regop, rm;
1085 get_modrm(*data, &mod, &regop, &rm);
1086 const char* mnem = NULL;
1087 switch (regop) {
1088 case esi: mnem = "push"; break;
1089 case eax: mnem = "inc"; break;
1090 case ecx: mnem = "dec"; break;
1091 case edx: mnem = "call"; break;
1092 case esp: mnem = "jmp"; break;
1093 default: mnem = "???";
1094 }
1095 AppendToBuffer("%s ", mnem);
1096 data += PrintRightOperand(data);
1097 }
1098 break;
1099
1100 case 0xC7: // imm32, fall through
1101 case 0xC6: // imm8
1102 { bool is_byte = *data == 0xC6;
1103 data++;
Steve Block44f0eee2011-05-26 01:26:41 +01001104 if (is_byte) {
1105 AppendToBuffer("%s ", "mov_b");
1106 data += PrintRightByteOperand(data);
1107 int32_t imm = *data;
1108 AppendToBuffer(",0x%x", imm);
1109 data++;
1110 } else {
1111 AppendToBuffer("%s ", "mov");
1112 data += PrintRightOperand(data);
1113 int32_t imm = *reinterpret_cast<int32_t*>(data);
1114 AppendToBuffer(",0x%x", imm);
1115 data += 4;
1116 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001117 }
1118 break;
1119
1120 case 0x80:
1121 { data++;
Leon Clarkee46be812010-01-19 14:06:41 +00001122 int mod, regop, rm;
1123 get_modrm(*data, &mod, &regop, &rm);
1124 const char* mnem = NULL;
Leon Clarkee46be812010-01-19 14:06:41 +00001125 switch (regop) {
1126 case 5: mnem = "subb"; break;
1127 case 7: mnem = "cmpb"; break;
1128 default: UnimplementedInstruction();
1129 }
1130 AppendToBuffer("%s ", mnem);
Steve Block44f0eee2011-05-26 01:26:41 +01001131 data += PrintRightByteOperand(data);
Steve Blocka7e24c12009-10-30 11:49:00 +00001132 int32_t imm = *data;
1133 AppendToBuffer(",0x%x", imm);
1134 data++;
1135 }
1136 break;
1137
1138 case 0x88: // 8bit, fall through
1139 case 0x89: // 32bit
1140 { bool is_byte = *data == 0x88;
1141 int mod, regop, rm;
1142 data++;
1143 get_modrm(*data, &mod, &regop, &rm);
Steve Block44f0eee2011-05-26 01:26:41 +01001144 if (is_byte) {
1145 AppendToBuffer("%s ", "mov_b");
1146 data += PrintRightByteOperand(data);
1147 AppendToBuffer(",%s", NameOfByteCPURegister(regop));
1148 } else {
1149 AppendToBuffer("%s ", "mov");
1150 data += PrintRightOperand(data);
1151 AppendToBuffer(",%s", NameOfCPURegister(regop));
1152 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001153 }
1154 break;
1155
1156 case 0x66: // prefix
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001157 while (*data == 0x66) data++;
1158 if (*data == 0xf && data[1] == 0x1f) {
1159 AppendToBuffer("nop"); // 0x66 prefix
1160 } else if (*data == 0x90) {
1161 AppendToBuffer("nop"); // 0x66 prefix
1162 } else if (*data == 0x8B) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001163 data++;
1164 data += PrintOperands("mov_w", REG_OPER_OP_ORDER, data);
1165 } else if (*data == 0x89) {
1166 data++;
1167 int mod, regop, rm;
1168 get_modrm(*data, &mod, &regop, &rm);
1169 AppendToBuffer("mov_w ");
1170 data += PrintRightOperand(data);
1171 AppendToBuffer(",%s", NameOfCPURegister(regop));
Steve Block3ce2e202009-11-05 08:53:23 +00001172 } else if (*data == 0x0F) {
1173 data++;
Steve Block6ded16b2010-05-10 14:33:55 +01001174 if (*data == 0x38) {
1175 data++;
1176 if (*data == 0x17) {
1177 data++;
1178 int mod, regop, rm;
1179 get_modrm(*data, &mod, &regop, &rm);
1180 AppendToBuffer("ptest %s,%s",
1181 NameOfXMMRegister(regop),
1182 NameOfXMMRegister(rm));
1183 data++;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001184 } else if (*data == 0x2A) {
1185 // movntdqa
1186 data++;
1187 int mod, regop, rm;
1188 get_modrm(*data, &mod, &regop, &rm);
1189 AppendToBuffer("movntdqa %s,", NameOfXMMRegister(regop));
1190 data += PrintRightOperand(data);
Steve Block6ded16b2010-05-10 14:33:55 +01001191 } else {
1192 UnimplementedInstruction();
1193 }
Ben Murdochb0fe1622011-05-05 13:52:32 +01001194 } else if (*data == 0x3A) {
1195 data++;
Ben Murdoch69a99ed2011-11-30 16:03:39 +00001196 if (*data == 0x0B) {
1197 data++;
1198 int mod, regop, rm;
1199 get_modrm(*data, &mod, &regop, &rm);
1200 int8_t imm8 = static_cast<int8_t>(data[1]);
1201 AppendToBuffer("roundsd %s,%s,%d",
1202 NameOfXMMRegister(regop),
1203 NameOfXMMRegister(rm),
1204 static_cast<int>(imm8));
1205 data += 2;
1206 } else if (*data == 0x16) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01001207 data++;
1208 int mod, regop, rm;
1209 get_modrm(*data, &mod, &regop, &rm);
1210 int8_t imm8 = static_cast<int8_t>(data[1]);
1211 AppendToBuffer("pextrd %s,%s,%d",
Steve Block1e0659c2011-05-24 12:43:12 +01001212 NameOfCPURegister(regop),
Ben Murdochb0fe1622011-05-05 13:52:32 +01001213 NameOfXMMRegister(rm),
1214 static_cast<int>(imm8));
1215 data += 2;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001216 } else if (*data == 0x17) {
1217 data++;
1218 int mod, regop, rm;
1219 get_modrm(*data, &mod, &regop, &rm);
1220 int8_t imm8 = static_cast<int8_t>(data[1]);
1221 AppendToBuffer("extractps %s,%s,%d",
1222 NameOfCPURegister(regop),
1223 NameOfXMMRegister(rm),
1224 static_cast<int>(imm8));
1225 data += 2;
Steve Block1e0659c2011-05-24 12:43:12 +01001226 } else if (*data == 0x22) {
1227 data++;
1228 int mod, regop, rm;
1229 get_modrm(*data, &mod, &regop, &rm);
1230 int8_t imm8 = static_cast<int8_t>(data[1]);
1231 AppendToBuffer("pinsrd %s,%s,%d",
1232 NameOfXMMRegister(regop),
1233 NameOfCPURegister(rm),
1234 static_cast<int>(imm8));
1235 data += 2;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001236 } else {
1237 UnimplementedInstruction();
1238 }
Steve Block6ded16b2010-05-10 14:33:55 +01001239 } else if (*data == 0x2E || *data == 0x2F) {
1240 const char* mnem = (*data == 0x2E) ? "ucomisd" : "comisd";
Steve Block3ce2e202009-11-05 08:53:23 +00001241 data++;
1242 int mod, regop, rm;
1243 get_modrm(*data, &mod, &regop, &rm);
Steve Block6ded16b2010-05-10 14:33:55 +01001244 if (mod == 0x3) {
1245 AppendToBuffer("%s %s,%s", mnem,
1246 NameOfXMMRegister(regop),
1247 NameOfXMMRegister(rm));
1248 data++;
1249 } else {
1250 AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
1251 data += PrintRightOperand(data);
1252 }
1253 } else if (*data == 0x50) {
1254 data++;
1255 int mod, regop, rm;
1256 get_modrm(*data, &mod, &regop, &rm);
1257 AppendToBuffer("movmskpd %s,%s",
1258 NameOfCPURegister(regop),
Steve Block3ce2e202009-11-05 08:53:23 +00001259 NameOfXMMRegister(rm));
1260 data++;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001261 } else if (*data == 0x54) {
1262 data++;
1263 int mod, regop, rm;
1264 get_modrm(*data, &mod, &regop, &rm);
1265 AppendToBuffer("andpd %s,%s",
1266 NameOfXMMRegister(regop),
1267 NameOfXMMRegister(rm));
1268 data++;
Leon Clarkee46be812010-01-19 14:06:41 +00001269 } else if (*data == 0x57) {
1270 data++;
1271 int mod, regop, rm;
1272 get_modrm(*data, &mod, &regop, &rm);
1273 AppendToBuffer("xorpd %s,%s",
1274 NameOfXMMRegister(regop),
1275 NameOfXMMRegister(rm));
1276 data++;
Steve Block6ded16b2010-05-10 14:33:55 +01001277 } else if (*data == 0x6E) {
1278 data++;
1279 int mod, regop, rm;
1280 get_modrm(*data, &mod, &regop, &rm);
1281 AppendToBuffer("movd %s,", NameOfXMMRegister(regop));
1282 data += PrintRightOperand(data);
Leon Clarkee46be812010-01-19 14:06:41 +00001283 } else if (*data == 0x6F) {
1284 data++;
1285 int mod, regop, rm;
1286 get_modrm(*data, &mod, &regop, &rm);
1287 AppendToBuffer("movdqa %s,", NameOfXMMRegister(regop));
Steve Block44f0eee2011-05-26 01:26:41 +01001288 data += PrintRightXMMOperand(data);
Ben Murdochb0fe1622011-05-05 13:52:32 +01001289 } else if (*data == 0x70) {
1290 data++;
1291 int mod, regop, rm;
1292 get_modrm(*data, &mod, &regop, &rm);
1293 int8_t imm8 = static_cast<int8_t>(data[1]);
1294 AppendToBuffer("pshufd %s,%s,%d",
1295 NameOfXMMRegister(regop),
1296 NameOfXMMRegister(rm),
1297 static_cast<int>(imm8));
1298 data += 2;
Ben Murdoch3ef787d2012-04-12 10:51:47 +01001299 } else if (*data == 0x90) {
1300 data++;
1301 AppendToBuffer("nop"); // 2 byte nop.
Ben Murdochb8e0da22011-05-16 14:20:40 +01001302 } else if (*data == 0xF3) {
1303 data++;
1304 int mod, regop, rm;
1305 get_modrm(*data, &mod, &regop, &rm);
1306 AppendToBuffer("psllq %s,%s",
1307 NameOfXMMRegister(regop),
1308 NameOfXMMRegister(rm));
1309 data++;
Ben Murdochb0fe1622011-05-05 13:52:32 +01001310 } else if (*data == 0x73) {
1311 data++;
1312 int mod, regop, rm;
1313 get_modrm(*data, &mod, &regop, &rm);
1314 int8_t imm8 = static_cast<int8_t>(data[1]);
Ben Murdochb8e0da22011-05-16 14:20:40 +01001315 ASSERT(regop == esi || regop == edx);
1316 AppendToBuffer("%s %s,%d",
1317 (regop == esi) ? "psllq" : "psrlq",
Ben Murdochb0fe1622011-05-05 13:52:32 +01001318 NameOfXMMRegister(rm),
1319 static_cast<int>(imm8));
1320 data += 2;
Ben Murdochb8e0da22011-05-16 14:20:40 +01001321 } else if (*data == 0xD3) {
1322 data++;
1323 int mod, regop, rm;
1324 get_modrm(*data, &mod, &regop, &rm);
1325 AppendToBuffer("psrlq %s,%s",
1326 NameOfXMMRegister(regop),
1327 NameOfXMMRegister(rm));
1328 data++;
Leon Clarkee46be812010-01-19 14:06:41 +00001329 } else if (*data == 0x7F) {
1330 AppendToBuffer("movdqa ");
1331 data++;
1332 int mod, regop, rm;
1333 get_modrm(*data, &mod, &regop, &rm);
Steve Block44f0eee2011-05-26 01:26:41 +01001334 data += PrintRightXMMOperand(data);
Leon Clarkee46be812010-01-19 14:06:41 +00001335 AppendToBuffer(",%s", NameOfXMMRegister(regop));
Ben Murdochb0fe1622011-05-05 13:52:32 +01001336 } else if (*data == 0x7E) {
1337 data++;
1338 int mod, regop, rm;
1339 get_modrm(*data, &mod, &regop, &rm);
1340 AppendToBuffer("movd ");
1341 data += PrintRightOperand(data);
1342 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1343 } else if (*data == 0xDB) {
1344 data++;
1345 int mod, regop, rm;
1346 get_modrm(*data, &mod, &regop, &rm);
1347 AppendToBuffer("pand %s,%s",
1348 NameOfXMMRegister(regop),
1349 NameOfXMMRegister(rm));
1350 data++;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001351 } else if (*data == 0xE7) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001352 data++;
1353 int mod, regop, rm;
1354 get_modrm(*data, &mod, &regop, &rm);
Steve Block44f0eee2011-05-26 01:26:41 +01001355 if (mod == 3) {
1356 AppendToBuffer("movntdq ");
1357 data += PrintRightOperand(data);
1358 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1359 } else {
1360 UnimplementedInstruction();
1361 }
Steve Block6ded16b2010-05-10 14:33:55 +01001362 } else if (*data == 0xEF) {
Ben Murdochb0fe1622011-05-05 13:52:32 +01001363 data++;
1364 int mod, regop, rm;
1365 get_modrm(*data, &mod, &regop, &rm);
1366 AppendToBuffer("pxor %s,%s",
1367 NameOfXMMRegister(regop),
1368 NameOfXMMRegister(rm));
1369 data++;
Ben Murdochb8e0da22011-05-16 14:20:40 +01001370 } else if (*data == 0xEB) {
1371 data++;
1372 int mod, regop, rm;
1373 get_modrm(*data, &mod, &regop, &rm);
1374 AppendToBuffer("por %s,%s",
1375 NameOfXMMRegister(regop),
1376 NameOfXMMRegister(rm));
1377 data++;
Steve Block3ce2e202009-11-05 08:53:23 +00001378 } else {
1379 UnimplementedInstruction();
1380 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001381 } else {
1382 UnimplementedInstruction();
1383 }
1384 break;
1385
1386 case 0xFE:
1387 { data++;
1388 int mod, regop, rm;
1389 get_modrm(*data, &mod, &regop, &rm);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001390 if (regop == ecx) {
1391 AppendToBuffer("dec_b ");
1392 data += PrintRightOperand(data);
Steve Blocka7e24c12009-10-30 11:49:00 +00001393 } else {
1394 UnimplementedInstruction();
1395 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001396 }
1397 break;
1398
1399 case 0x68:
1400 AppendToBuffer("push 0x%x", *reinterpret_cast<int32_t*>(data+1));
1401 data += 5;
1402 break;
1403
1404 case 0x6A:
1405 AppendToBuffer("push 0x%x", *reinterpret_cast<int8_t*>(data + 1));
1406 data += 2;
1407 break;
1408
1409 case 0xA8:
1410 AppendToBuffer("test al,0x%x", *reinterpret_cast<uint8_t*>(data+1));
1411 data += 2;
1412 break;
1413
1414 case 0xA9:
1415 AppendToBuffer("test eax,0x%x", *reinterpret_cast<int32_t*>(data+1));
1416 data += 5;
1417 break;
1418
1419 case 0xD1: // fall through
1420 case 0xD3: // fall through
1421 case 0xC1:
1422 data += D1D3C1Instruction(data);
1423 break;
1424
1425 case 0xD9: // fall through
1426 case 0xDA: // fall through
1427 case 0xDB: // fall through
1428 case 0xDC: // fall through
1429 case 0xDD: // fall through
1430 case 0xDE: // fall through
1431 case 0xDF:
1432 data += FPUInstruction(data);
1433 break;
1434
1435 case 0xEB:
1436 data += JumpShort(data);
1437 break;
1438
1439 case 0xF2:
1440 if (*(data+1) == 0x0F) {
1441 byte b2 = *(data+2);
1442 if (b2 == 0x11) {
1443 AppendToBuffer("movsd ");
1444 data += 3;
1445 int mod, regop, rm;
1446 get_modrm(*data, &mod, &regop, &rm);
Steve Block44f0eee2011-05-26 01:26:41 +01001447 data += PrintRightXMMOperand(data);
Steve Blocka7e24c12009-10-30 11:49:00 +00001448 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1449 } else if (b2 == 0x10) {
1450 data += 3;
1451 int mod, regop, rm;
1452 get_modrm(*data, &mod, &regop, &rm);
1453 AppendToBuffer("movsd %s,", NameOfXMMRegister(regop));
Steve Block44f0eee2011-05-26 01:26:41 +01001454 data += PrintRightXMMOperand(data);
1455 } else if (b2 == 0x5A) {
1456 data += 3;
1457 int mod, regop, rm;
1458 get_modrm(*data, &mod, &regop, &rm);
1459 AppendToBuffer("cvtsd2ss %s,", NameOfXMMRegister(regop));
1460 data += PrintRightXMMOperand(data);
Steve Blocka7e24c12009-10-30 11:49:00 +00001461 } else {
1462 const char* mnem = "?";
1463 switch (b2) {
1464 case 0x2A: mnem = "cvtsi2sd"; break;
Steve Block6ded16b2010-05-10 14:33:55 +01001465 case 0x2C: mnem = "cvttsd2si"; break;
1466 case 0x51: mnem = "sqrtsd"; break;
Steve Blocka7e24c12009-10-30 11:49:00 +00001467 case 0x58: mnem = "addsd"; break;
1468 case 0x59: mnem = "mulsd"; break;
1469 case 0x5C: mnem = "subsd"; break;
1470 case 0x5E: mnem = "divsd"; break;
1471 }
1472 data += 3;
1473 int mod, regop, rm;
1474 get_modrm(*data, &mod, &regop, &rm);
1475 if (b2 == 0x2A) {
Steve Block44f0eee2011-05-26 01:26:41 +01001476 AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
1477 data += PrintRightOperand(data);
Steve Block6ded16b2010-05-10 14:33:55 +01001478 } else if (b2 == 0x2C) {
Steve Block44f0eee2011-05-26 01:26:41 +01001479 AppendToBuffer("%s %s,", mnem, NameOfCPURegister(regop));
1480 data += PrintRightXMMOperand(data);
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001481 } else if (b2 == 0xC2) {
1482 // Intel manual 2A, Table 3-18.
1483 const char* const pseudo_op[] = {
1484 "cmpeqsd",
1485 "cmpltsd",
1486 "cmplesd",
1487 "cmpunordsd",
1488 "cmpneqsd",
1489 "cmpnltsd",
1490 "cmpnlesd",
1491 "cmpordsd"
1492 };
1493 AppendToBuffer("%s %s,%s",
1494 pseudo_op[data[1]],
1495 NameOfXMMRegister(regop),
1496 NameOfXMMRegister(rm));
1497 data += 2;
Steve Blocka7e24c12009-10-30 11:49:00 +00001498 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01001499 AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
1500 data += PrintRightXMMOperand(data);
Steve Blocka7e24c12009-10-30 11:49:00 +00001501 }
1502 }
1503 } else {
1504 UnimplementedInstruction();
1505 }
1506 break;
1507
1508 case 0xF3:
Leon Clarkee46be812010-01-19 14:06:41 +00001509 if (*(data+1) == 0x0F) {
Steve Block44f0eee2011-05-26 01:26:41 +01001510 byte b2 = *(data+2);
1511 if (b2 == 0x11) {
1512 AppendToBuffer("movss ");
Steve Block6ded16b2010-05-10 14:33:55 +01001513 data += 3;
1514 int mod, regop, rm;
1515 get_modrm(*data, &mod, &regop, &rm);
Steve Block44f0eee2011-05-26 01:26:41 +01001516 data += PrintRightXMMOperand(data);
1517 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1518 } else if (b2 == 0x10) {
1519 data += 3;
1520 int mod, regop, rm;
1521 get_modrm(*data, &mod, &regop, &rm);
1522 AppendToBuffer("movss %s,", NameOfXMMRegister(regop));
1523 data += PrintRightXMMOperand(data);
1524 } else if (b2 == 0x2C) {
1525 data += 3;
1526 int mod, regop, rm;
1527 get_modrm(*data, &mod, &regop, &rm);
1528 AppendToBuffer("cvttss2si %s,", NameOfCPURegister(regop));
1529 data += PrintRightXMMOperand(data);
1530 } else if (b2 == 0x5A) {
1531 data += 3;
1532 int mod, regop, rm;
1533 get_modrm(*data, &mod, &regop, &rm);
1534 AppendToBuffer("cvtss2sd %s,", NameOfXMMRegister(regop));
1535 data += PrintRightXMMOperand(data);
1536 } else if (b2 == 0x6F) {
Leon Clarkee46be812010-01-19 14:06:41 +00001537 data += 3;
1538 int mod, regop, rm;
1539 get_modrm(*data, &mod, &regop, &rm);
1540 AppendToBuffer("movdqu %s,", NameOfXMMRegister(regop));
Steve Block44f0eee2011-05-26 01:26:41 +01001541 data += PrintRightXMMOperand(data);
1542 } else if (b2 == 0x7F) {
Leon Clarkee46be812010-01-19 14:06:41 +00001543 AppendToBuffer("movdqu ");
1544 data += 3;
1545 int mod, regop, rm;
1546 get_modrm(*data, &mod, &regop, &rm);
Steve Block44f0eee2011-05-26 01:26:41 +01001547 data += PrintRightXMMOperand(data);
Leon Clarkee46be812010-01-19 14:06:41 +00001548 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1549 } else {
1550 UnimplementedInstruction();
1551 }
1552 } else if (*(data+1) == 0xA5) {
1553 data += 2;
1554 AppendToBuffer("rep_movs");
Steve Block6ded16b2010-05-10 14:33:55 +01001555 } else if (*(data+1) == 0xAB) {
1556 data += 2;
1557 AppendToBuffer("rep_stos");
Steve Blocka7e24c12009-10-30 11:49:00 +00001558 } else {
1559 UnimplementedInstruction();
1560 }
1561 break;
1562
1563 case 0xF7:
1564 data += F7Instruction(data);
1565 break;
1566
1567 default:
1568 UnimplementedInstruction();
1569 }
1570 }
1571
1572 if (tmp_buffer_pos_ < sizeof tmp_buffer_) {
1573 tmp_buffer_[tmp_buffer_pos_] = '\0';
1574 }
1575
1576 int instr_len = data - instr;
Leon Clarkee46be812010-01-19 14:06:41 +00001577 if (instr_len == 0) {
1578 printf("%02x", *data);
1579 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001580 ASSERT(instr_len > 0); // Ensure progress.
1581
1582 int outp = 0;
1583 // Instruction bytes.
1584 for (byte* bp = instr; bp < data; bp++) {
1585 outp += v8::internal::OS::SNPrintF(out_buffer + outp,
1586 "%02x",
1587 *bp);
1588 }
1589 for (int i = 6 - instr_len; i >= 0; i--) {
1590 outp += v8::internal::OS::SNPrintF(out_buffer + outp,
1591 " ");
1592 }
1593
1594 outp += v8::internal::OS::SNPrintF(out_buffer + outp,
1595 " %s",
1596 tmp_buffer_.start());
1597 return instr_len;
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001598} // NOLINT (function is too long)
Steve Blocka7e24c12009-10-30 11:49:00 +00001599
1600
1601//------------------------------------------------------------------------------
1602
1603
1604static const char* cpu_regs[8] = {
1605 "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi"
1606};
1607
1608
1609static const char* byte_cpu_regs[8] = {
1610 "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh"
1611};
1612
1613
1614static const char* xmm_regs[8] = {
1615 "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7"
1616};
1617
1618
1619const char* NameConverter::NameOfAddress(byte* addr) const {
Steve Block44f0eee2011-05-26 01:26:41 +01001620 v8::internal::OS::SNPrintF(tmp_buffer_, "%p", addr);
1621 return tmp_buffer_.start();
Steve Blocka7e24c12009-10-30 11:49:00 +00001622}
1623
1624
1625const char* NameConverter::NameOfConstant(byte* addr) const {
1626 return NameOfAddress(addr);
1627}
1628
1629
1630const char* NameConverter::NameOfCPURegister(int reg) const {
1631 if (0 <= reg && reg < 8) return cpu_regs[reg];
1632 return "noreg";
1633}
1634
1635
1636const char* NameConverter::NameOfByteCPURegister(int reg) const {
1637 if (0 <= reg && reg < 8) return byte_cpu_regs[reg];
1638 return "noreg";
1639}
1640
1641
1642const char* NameConverter::NameOfXMMRegister(int reg) const {
1643 if (0 <= reg && reg < 8) return xmm_regs[reg];
1644 return "noxmmreg";
1645}
1646
1647
1648const char* NameConverter::NameInCode(byte* addr) const {
1649 // IA32 does not embed debug strings at the moment.
1650 UNREACHABLE();
1651 return "";
1652}
1653
1654
1655//------------------------------------------------------------------------------
1656
1657Disassembler::Disassembler(const NameConverter& converter)
1658 : converter_(converter) {}
1659
1660
1661Disassembler::~Disassembler() {}
1662
1663
1664int Disassembler::InstructionDecode(v8::internal::Vector<char> buffer,
1665 byte* instruction) {
1666 DisassemblerIA32 d(converter_, false /*do not crash if unimplemented*/);
1667 return d.InstructionDecode(buffer, instruction);
1668}
1669
1670
1671// The IA-32 assembler does not currently use constant pools.
1672int Disassembler::ConstantPoolSizeAt(byte* instruction) { return -1; }
1673
1674
1675/*static*/ void Disassembler::Disassemble(FILE* f, byte* begin, byte* end) {
1676 NameConverter converter;
1677 Disassembler d(converter);
1678 for (byte* pc = begin; pc < end;) {
1679 v8::internal::EmbeddedVector<char, 128> buffer;
1680 buffer[0] = '\0';
1681 byte* prev_pc = pc;
1682 pc += d.InstructionDecode(buffer, pc);
1683 fprintf(f, "%p", prev_pc);
1684 fprintf(f, " ");
1685
1686 for (byte* bp = prev_pc; bp < pc; bp++) {
1687 fprintf(f, "%02x", *bp);
1688 }
1689 for (int i = 6 - (pc - prev_pc); i >= 0; i--) {
1690 fprintf(f, " ");
1691 }
1692 fprintf(f, " %s\n", buffer.start());
1693 }
1694}
1695
1696
1697} // namespace disasm
Leon Clarkef7060e22010-06-03 12:02:55 +01001698
1699#endif // V8_TARGET_ARCH_IA32