blob: a085900a40dbada8b63db0b27cb4d0f3396c80f2 [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"
33#include "disasm.h"
34
35namespace disasm {
36
37enum OperandOrder {
38 UNSET_OP_ORDER = 0,
39 REG_OPER_OP_ORDER,
40 OPER_REG_OP_ORDER
41};
42
43
44//------------------------------------------------------------------
45// Tables
46//------------------------------------------------------------------
47struct ByteMnemonic {
48 int b; // -1 terminates, otherwise must be in range (0..255)
49 const char* mnem;
50 OperandOrder op_order_;
51};
52
53
54static ByteMnemonic two_operands_instr[] = {
55 {0x03, "add", REG_OPER_OP_ORDER},
Steve Blocka7e24c12009-10-30 11:49:00 +000056 {0x09, "or", OPER_REG_OP_ORDER},
57 {0x0B, "or", REG_OPER_OP_ORDER},
58 {0x1B, "sbb", REG_OPER_OP_ORDER},
Leon Clarked91b9f72010-01-27 17:25:45 +000059 {0x21, "and", OPER_REG_OP_ORDER},
60 {0x23, "and", REG_OPER_OP_ORDER},
Steve Blocka7e24c12009-10-30 11:49:00 +000061 {0x29, "sub", OPER_REG_OP_ORDER},
Leon Clarkee46be812010-01-19 14:06:41 +000062 {0x2A, "subb", REG_OPER_OP_ORDER},
Steve Blocka7e24c12009-10-30 11:49:00 +000063 {0x2B, "sub", REG_OPER_OP_ORDER},
Leon Clarkeeab96aa2010-01-27 16:31:12 +000064 {0x31, "xor", OPER_REG_OP_ORDER},
65 {0x33, "xor", REG_OPER_OP_ORDER},
Leon Clarked91b9f72010-01-27 17:25:45 +000066 {0x38, "cmpb", OPER_REG_OP_ORDER},
67 {0x3A, "cmpb", REG_OPER_OP_ORDER},
68 {0x3B, "cmp", REG_OPER_OP_ORDER},
69 {0x84, "test_b", REG_OPER_OP_ORDER},
70 {0x85, "test", REG_OPER_OP_ORDER},
Steve Blocka7e24c12009-10-30 11:49:00 +000071 {0x87, "xchg", REG_OPER_OP_ORDER},
72 {0x8A, "mov_b", REG_OPER_OP_ORDER},
73 {0x8B, "mov", REG_OPER_OP_ORDER},
Leon Clarked91b9f72010-01-27 17:25:45 +000074 {0x8D, "lea", REG_OPER_OP_ORDER},
Steve Blocka7e24c12009-10-30 11:49:00 +000075 {-1, "", UNSET_OP_ORDER}
76};
77
78
79static ByteMnemonic zero_operands_instr[] = {
80 {0xC3, "ret", UNSET_OP_ORDER},
81 {0xC9, "leave", UNSET_OP_ORDER},
82 {0x90, "nop", UNSET_OP_ORDER},
83 {0xF4, "hlt", UNSET_OP_ORDER},
84 {0xCC, "int3", UNSET_OP_ORDER},
85 {0x60, "pushad", UNSET_OP_ORDER},
86 {0x61, "popad", UNSET_OP_ORDER},
87 {0x9C, "pushfd", UNSET_OP_ORDER},
88 {0x9D, "popfd", UNSET_OP_ORDER},
89 {0x9E, "sahf", UNSET_OP_ORDER},
90 {0x99, "cdq", UNSET_OP_ORDER},
91 {0x9B, "fwait", UNSET_OP_ORDER},
92 {-1, "", UNSET_OP_ORDER}
93};
94
95
96static ByteMnemonic call_jump_instr[] = {
97 {0xE8, "call", UNSET_OP_ORDER},
98 {0xE9, "jmp", UNSET_OP_ORDER},
99 {-1, "", UNSET_OP_ORDER}
100};
101
102
103static ByteMnemonic short_immediate_instr[] = {
104 {0x05, "add", UNSET_OP_ORDER},
105 {0x0D, "or", UNSET_OP_ORDER},
106 {0x15, "adc", UNSET_OP_ORDER},
107 {0x25, "and", UNSET_OP_ORDER},
108 {0x2D, "sub", UNSET_OP_ORDER},
109 {0x35, "xor", UNSET_OP_ORDER},
110 {0x3D, "cmp", UNSET_OP_ORDER},
111 {-1, "", UNSET_OP_ORDER}
112};
113
114
115static const char* jump_conditional_mnem[] = {
116 /*0*/ "jo", "jno", "jc", "jnc",
117 /*4*/ "jz", "jnz", "jna", "ja",
118 /*8*/ "js", "jns", "jpe", "jpo",
119 /*12*/ "jl", "jnl", "jng", "jg"
120};
121
122
123static const char* set_conditional_mnem[] = {
124 /*0*/ "seto", "setno", "setc", "setnc",
125 /*4*/ "setz", "setnz", "setna", "seta",
126 /*8*/ "sets", "setns", "setpe", "setpo",
127 /*12*/ "setl", "setnl", "setng", "setg"
128};
129
130
Steve Block3ce2e202009-11-05 08:53:23 +0000131static const char* conditional_move_mnem[] = {
132 /*0*/ "cmovo", "cmovno", "cmovc", "cmovnc",
133 /*4*/ "cmovz", "cmovnz", "cmovna", "cmova",
134 /*8*/ "cmovs", "cmovns", "cmovpe", "cmovpo",
135 /*12*/ "cmovl", "cmovnl", "cmovng", "cmovg"
136};
137
138
Steve Blocka7e24c12009-10-30 11:49:00 +0000139enum InstructionType {
140 NO_INSTR,
141 ZERO_OPERANDS_INSTR,
142 TWO_OPERANDS_INSTR,
143 JUMP_CONDITIONAL_SHORT_INSTR,
144 REGISTER_INSTR,
145 MOVE_REG_INSTR,
146 CALL_JUMP_INSTR,
147 SHORT_IMMEDIATE_INSTR
148};
149
150
151struct InstructionDesc {
152 const char* mnem;
153 InstructionType type;
154 OperandOrder op_order_;
155};
156
157
158class InstructionTable {
159 public:
160 InstructionTable();
161 const InstructionDesc& Get(byte x) const { return instructions_[x]; }
162
163 private:
164 InstructionDesc instructions_[256];
165 void Clear();
166 void Init();
167 void CopyTable(ByteMnemonic bm[], InstructionType type);
168 void SetTableRange(InstructionType type,
169 byte start,
170 byte end,
171 const char* mnem);
172 void AddJumpConditionalShort();
173};
174
175
176InstructionTable::InstructionTable() {
177 Clear();
178 Init();
179}
180
181
182void InstructionTable::Clear() {
183 for (int i = 0; i < 256; i++) {
184 instructions_[i].mnem = "";
185 instructions_[i].type = NO_INSTR;
186 instructions_[i].op_order_ = UNSET_OP_ORDER;
187 }
188}
189
190
191void InstructionTable::Init() {
192 CopyTable(two_operands_instr, TWO_OPERANDS_INSTR);
193 CopyTable(zero_operands_instr, ZERO_OPERANDS_INSTR);
194 CopyTable(call_jump_instr, CALL_JUMP_INSTR);
195 CopyTable(short_immediate_instr, SHORT_IMMEDIATE_INSTR);
196 AddJumpConditionalShort();
197 SetTableRange(REGISTER_INSTR, 0x40, 0x47, "inc");
198 SetTableRange(REGISTER_INSTR, 0x48, 0x4F, "dec");
199 SetTableRange(REGISTER_INSTR, 0x50, 0x57, "push");
200 SetTableRange(REGISTER_INSTR, 0x58, 0x5F, "pop");
201 SetTableRange(REGISTER_INSTR, 0x91, 0x97, "xchg eax,"); // 0x90 is nop.
202 SetTableRange(MOVE_REG_INSTR, 0xB8, 0xBF, "mov");
203}
204
205
206void InstructionTable::CopyTable(ByteMnemonic bm[], InstructionType type) {
207 for (int i = 0; bm[i].b >= 0; i++) {
208 InstructionDesc* id = &instructions_[bm[i].b];
209 id->mnem = bm[i].mnem;
210 id->op_order_ = bm[i].op_order_;
Steve Blockd0582a62009-12-15 09:54:21 +0000211 ASSERT_EQ(NO_INSTR, id->type); // Information not already entered.
Steve Blocka7e24c12009-10-30 11:49:00 +0000212 id->type = type;
213 }
214}
215
216
217void InstructionTable::SetTableRange(InstructionType type,
218 byte start,
219 byte end,
220 const char* mnem) {
221 for (byte b = start; b <= end; b++) {
222 InstructionDesc* id = &instructions_[b];
Steve Blockd0582a62009-12-15 09:54:21 +0000223 ASSERT_EQ(NO_INSTR, id->type); // Information not already entered.
Steve Blocka7e24c12009-10-30 11:49:00 +0000224 id->mnem = mnem;
225 id->type = type;
226 }
227}
228
229
230void InstructionTable::AddJumpConditionalShort() {
231 for (byte b = 0x70; b <= 0x7F; b++) {
232 InstructionDesc* id = &instructions_[b];
Steve Blockd0582a62009-12-15 09:54:21 +0000233 ASSERT_EQ(NO_INSTR, id->type); // Information not already entered.
Steve Blocka7e24c12009-10-30 11:49:00 +0000234 id->mnem = jump_conditional_mnem[b & 0x0F];
235 id->type = JUMP_CONDITIONAL_SHORT_INSTR;
236 }
237}
238
239
240static InstructionTable instruction_table;
241
242
243// The IA32 disassembler implementation.
244class DisassemblerIA32 {
245 public:
246 DisassemblerIA32(const NameConverter& converter,
247 bool abort_on_unimplemented = true)
248 : converter_(converter),
249 tmp_buffer_pos_(0),
250 abort_on_unimplemented_(abort_on_unimplemented) {
251 tmp_buffer_[0] = '\0';
252 }
253
254 virtual ~DisassemblerIA32() {}
255
256 // Writes one disassembled instruction into 'buffer' (0-terminated).
257 // Returns the length of the disassembled machine instruction in bytes.
258 int InstructionDecode(v8::internal::Vector<char> buffer, byte* instruction);
259
260 private:
261 const NameConverter& converter_;
262 v8::internal::EmbeddedVector<char, 128> tmp_buffer_;
263 unsigned int tmp_buffer_pos_;
264 bool abort_on_unimplemented_;
265
266
267 enum {
268 eax = 0,
269 ecx = 1,
270 edx = 2,
271 ebx = 3,
272 esp = 4,
273 ebp = 5,
274 esi = 6,
275 edi = 7
276 };
277
278
Steve Blockd0582a62009-12-15 09:54:21 +0000279 enum ShiftOpcodeExtension {
280 kROL = 0,
281 kROR = 1,
282 kRCL = 2,
283 kRCR = 3,
284 kSHL = 4,
285 KSHR = 5,
286 kSAR = 7
287 };
288
289
Steve Blocka7e24c12009-10-30 11:49:00 +0000290 const char* NameOfCPURegister(int reg) const {
291 return converter_.NameOfCPURegister(reg);
292 }
293
294
295 const char* NameOfByteCPURegister(int reg) const {
296 return converter_.NameOfByteCPURegister(reg);
297 }
298
299
300 const char* NameOfXMMRegister(int reg) const {
301 return converter_.NameOfXMMRegister(reg);
302 }
303
304
305 const char* NameOfAddress(byte* addr) const {
306 return converter_.NameOfAddress(addr);
307 }
308
309
310 // Disassembler helper functions.
311 static void get_modrm(byte data, int* mod, int* regop, int* rm) {
312 *mod = (data >> 6) & 3;
313 *regop = (data & 0x38) >> 3;
314 *rm = data & 7;
315 }
316
317
318 static void get_sib(byte data, int* scale, int* index, int* base) {
319 *scale = (data >> 6) & 3;
320 *index = (data >> 3) & 7;
321 *base = data & 7;
322 }
323
324 typedef const char* (DisassemblerIA32::*RegisterNameMapping)(int reg) const;
325
326 int PrintRightOperandHelper(byte* modrmp, RegisterNameMapping register_name);
327 int PrintRightOperand(byte* modrmp);
328 int PrintRightByteOperand(byte* modrmp);
329 int PrintOperands(const char* mnem, OperandOrder op_order, byte* data);
330 int PrintImmediateOp(byte* data);
331 int F7Instruction(byte* data);
332 int D1D3C1Instruction(byte* data);
333 int JumpShort(byte* data);
334 int JumpConditional(byte* data, const char* comment);
335 int JumpConditionalShort(byte* data, const char* comment);
336 int SetCC(byte* data);
Steve Block3ce2e202009-11-05 08:53:23 +0000337 int CMov(byte* data);
Steve Blocka7e24c12009-10-30 11:49:00 +0000338 int FPUInstruction(byte* data);
Steve Blockd0582a62009-12-15 09:54:21 +0000339 int MemoryFPUInstruction(int escape_opcode, int regop, byte* modrm_start);
340 int RegisterFPUInstruction(int escape_opcode, byte modrm_byte);
Steve Blocka7e24c12009-10-30 11:49:00 +0000341 void AppendToBuffer(const char* format, ...);
342
343
344 void UnimplementedInstruction() {
345 if (abort_on_unimplemented_) {
346 UNIMPLEMENTED();
347 } else {
348 AppendToBuffer("'Unimplemented Instruction'");
349 }
350 }
351};
352
353
354void DisassemblerIA32::AppendToBuffer(const char* format, ...) {
355 v8::internal::Vector<char> buf = tmp_buffer_ + tmp_buffer_pos_;
356 va_list args;
357 va_start(args, format);
358 int result = v8::internal::OS::VSNPrintF(buf, format, args);
359 va_end(args);
360 tmp_buffer_pos_ += result;
361}
362
363int DisassemblerIA32::PrintRightOperandHelper(
364 byte* modrmp,
365 RegisterNameMapping register_name) {
366 int mod, regop, rm;
367 get_modrm(*modrmp, &mod, &regop, &rm);
368 switch (mod) {
369 case 0:
370 if (rm == ebp) {
371 int32_t disp = *reinterpret_cast<int32_t*>(modrmp+1);
372 AppendToBuffer("[0x%x]", disp);
373 return 5;
374 } else if (rm == esp) {
375 byte sib = *(modrmp + 1);
376 int scale, index, base;
377 get_sib(sib, &scale, &index, &base);
378 if (index == esp && base == esp && scale == 0 /*times_1*/) {
379 AppendToBuffer("[%s]", (this->*register_name)(rm));
380 return 2;
381 } else if (base == ebp) {
382 int32_t disp = *reinterpret_cast<int32_t*>(modrmp + 2);
383 AppendToBuffer("[%s*%d+0x%x]",
384 (this->*register_name)(index),
385 1 << scale,
386 disp);
387 return 6;
388 } else if (index != esp && base != ebp) {
389 // [base+index*scale]
390 AppendToBuffer("[%s+%s*%d]",
391 (this->*register_name)(base),
392 (this->*register_name)(index),
393 1 << scale);
394 return 2;
395 } else {
396 UnimplementedInstruction();
397 return 1;
398 }
399 } else {
400 AppendToBuffer("[%s]", (this->*register_name)(rm));
401 return 1;
402 }
403 break;
404 case 1: // fall through
405 case 2:
406 if (rm == esp) {
407 byte sib = *(modrmp + 1);
408 int scale, index, base;
409 get_sib(sib, &scale, &index, &base);
410 int disp =
411 mod == 2 ? *reinterpret_cast<int32_t*>(modrmp + 2) : *(modrmp + 2);
412 if (index == base && index == rm /*esp*/ && scale == 0 /*times_1*/) {
413 AppendToBuffer("[%s+0x%x]", (this->*register_name)(rm), disp);
414 } else {
415 AppendToBuffer("[%s+%s*%d+0x%x]",
416 (this->*register_name)(base),
417 (this->*register_name)(index),
418 1 << scale,
419 disp);
420 }
421 return mod == 2 ? 6 : 3;
422 } else {
423 // No sib.
424 int disp =
425 mod == 2 ? *reinterpret_cast<int32_t*>(modrmp + 1) : *(modrmp + 1);
426 AppendToBuffer("[%s+0x%x]", (this->*register_name)(rm), disp);
427 return mod == 2 ? 5 : 2;
428 }
429 break;
430 case 3:
431 AppendToBuffer("%s", (this->*register_name)(rm));
432 return 1;
433 default:
434 UnimplementedInstruction();
435 return 1;
436 }
437 UNREACHABLE();
438}
439
440
441int DisassemblerIA32::PrintRightOperand(byte* modrmp) {
442 return PrintRightOperandHelper(modrmp, &DisassemblerIA32::NameOfCPURegister);
443}
444
445
446int DisassemblerIA32::PrintRightByteOperand(byte* modrmp) {
447 return PrintRightOperandHelper(modrmp,
448 &DisassemblerIA32::NameOfByteCPURegister);
449}
450
451
452// Returns number of bytes used including the current *data.
453// Writes instruction's mnemonic, left and right operands to 'tmp_buffer_'.
454int DisassemblerIA32::PrintOperands(const char* mnem,
455 OperandOrder op_order,
456 byte* data) {
457 byte modrm = *data;
458 int mod, regop, rm;
459 get_modrm(modrm, &mod, &regop, &rm);
460 int advance = 0;
461 switch (op_order) {
462 case REG_OPER_OP_ORDER: {
463 AppendToBuffer("%s %s,", mnem, NameOfCPURegister(regop));
464 advance = PrintRightOperand(data);
465 break;
466 }
467 case OPER_REG_OP_ORDER: {
468 AppendToBuffer("%s ", mnem);
469 advance = PrintRightOperand(data);
470 AppendToBuffer(",%s", NameOfCPURegister(regop));
471 break;
472 }
473 default:
474 UNREACHABLE();
475 break;
476 }
477 return advance;
478}
479
480
481// Returns number of bytes used by machine instruction, including *data byte.
482// Writes immediate instructions to 'tmp_buffer_'.
483int DisassemblerIA32::PrintImmediateOp(byte* data) {
484 bool sign_extension_bit = (*data & 0x02) != 0;
485 byte modrm = *(data+1);
486 int mod, regop, rm;
487 get_modrm(modrm, &mod, &regop, &rm);
488 const char* mnem = "Imm???";
489 switch (regop) {
490 case 0: mnem = "add"; break;
491 case 1: mnem = "or"; break;
492 case 2: mnem = "adc"; break;
493 case 4: mnem = "and"; break;
494 case 5: mnem = "sub"; break;
495 case 6: mnem = "xor"; break;
496 case 7: mnem = "cmp"; break;
497 default: UnimplementedInstruction();
498 }
499 AppendToBuffer("%s ", mnem);
500 int count = PrintRightOperand(data+1);
501 if (sign_extension_bit) {
502 AppendToBuffer(",0x%x", *(data + 1 + count));
503 return 1 + count + 1 /*int8*/;
504 } else {
505 AppendToBuffer(",0x%x", *reinterpret_cast<int32_t*>(data + 1 + count));
506 return 1 + count + 4 /*int32_t*/;
507 }
508}
509
510
511// Returns number of bytes used, including *data.
512int DisassemblerIA32::F7Instruction(byte* data) {
Steve Blockd0582a62009-12-15 09:54:21 +0000513 ASSERT_EQ(0xF7, *data);
Steve Blocka7e24c12009-10-30 11:49:00 +0000514 byte modrm = *(data+1);
515 int mod, regop, rm;
516 get_modrm(modrm, &mod, &regop, &rm);
517 if (mod == 3 && regop != 0) {
518 const char* mnem = NULL;
519 switch (regop) {
520 case 2: mnem = "not"; break;
521 case 3: mnem = "neg"; break;
522 case 4: mnem = "mul"; break;
523 case 7: mnem = "idiv"; break;
524 default: UnimplementedInstruction();
525 }
526 AppendToBuffer("%s %s", mnem, NameOfCPURegister(rm));
527 return 2;
528 } else if (mod == 3 && regop == eax) {
529 int32_t imm = *reinterpret_cast<int32_t*>(data+2);
530 AppendToBuffer("test %s,0x%x", NameOfCPURegister(rm), imm);
531 return 6;
532 } else if (regop == eax) {
533 AppendToBuffer("test ");
534 int count = PrintRightOperand(data+1);
535 int32_t imm = *reinterpret_cast<int32_t*>(data+1+count);
536 AppendToBuffer(",0x%x", imm);
537 return 1+count+4 /*int32_t*/;
538 } else {
539 UnimplementedInstruction();
540 return 2;
541 }
542}
543
544int DisassemblerIA32::D1D3C1Instruction(byte* data) {
545 byte op = *data;
Steve Blockd0582a62009-12-15 09:54:21 +0000546 ASSERT(op == 0xD1 || op == 0xD3 || op == 0xC1);
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 int imm8 = -1;
551 int num_bytes = 2;
552 if (mod == 3) {
553 const char* mnem = NULL;
Steve Blockd0582a62009-12-15 09:54:21 +0000554 switch (regop) {
555 case kROL: mnem = "rol"; break;
556 case kROR: mnem = "ror"; break;
557 case kRCL: mnem = "rcl"; break;
558 case kSHL: mnem = "shl"; break;
559 case KSHR: mnem = "shr"; break;
560 case kSAR: mnem = "sar"; break;
561 default: UnimplementedInstruction();
562 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000563 if (op == 0xD1) {
564 imm8 = 1;
Steve Blocka7e24c12009-10-30 11:49:00 +0000565 } else if (op == 0xC1) {
566 imm8 = *(data+2);
567 num_bytes = 3;
Steve Blocka7e24c12009-10-30 11:49:00 +0000568 } else if (op == 0xD3) {
Steve Blockd0582a62009-12-15 09:54:21 +0000569 // Shift/rotate by cl.
Steve Blocka7e24c12009-10-30 11:49:00 +0000570 }
Steve Blockd0582a62009-12-15 09:54:21 +0000571 ASSERT_NE(NULL, mnem);
Steve Blocka7e24c12009-10-30 11:49:00 +0000572 AppendToBuffer("%s %s,", mnem, NameOfCPURegister(rm));
573 if (imm8 > 0) {
574 AppendToBuffer("%d", imm8);
575 } else {
576 AppendToBuffer("cl");
577 }
578 } else {
579 UnimplementedInstruction();
580 }
581 return num_bytes;
582}
583
584
585// Returns number of bytes used, including *data.
586int DisassemblerIA32::JumpShort(byte* data) {
Steve Blockd0582a62009-12-15 09:54:21 +0000587 ASSERT_EQ(0xEB, *data);
Steve Blocka7e24c12009-10-30 11:49:00 +0000588 byte b = *(data+1);
589 byte* dest = data + static_cast<int8_t>(b) + 2;
590 AppendToBuffer("jmp %s", NameOfAddress(dest));
591 return 2;
592}
593
594
595// Returns number of bytes used, including *data.
596int DisassemblerIA32::JumpConditional(byte* data, const char* comment) {
Steve Blockd0582a62009-12-15 09:54:21 +0000597 ASSERT_EQ(0x0F, *data);
Steve Blocka7e24c12009-10-30 11:49:00 +0000598 byte cond = *(data+1) & 0x0F;
599 byte* dest = data + *reinterpret_cast<int32_t*>(data+2) + 6;
600 const char* mnem = jump_conditional_mnem[cond];
601 AppendToBuffer("%s %s", mnem, NameOfAddress(dest));
602 if (comment != NULL) {
603 AppendToBuffer(", %s", comment);
604 }
605 return 6; // includes 0x0F
606}
607
608
609// Returns number of bytes used, including *data.
610int DisassemblerIA32::JumpConditionalShort(byte* data, const char* comment) {
611 byte cond = *data & 0x0F;
612 byte b = *(data+1);
613 byte* dest = data + static_cast<int8_t>(b) + 2;
614 const char* mnem = jump_conditional_mnem[cond];
615 AppendToBuffer("%s %s", mnem, NameOfAddress(dest));
616 if (comment != NULL) {
617 AppendToBuffer(", %s", comment);
618 }
619 return 2;
620}
621
622
623// Returns number of bytes used, including *data.
624int DisassemblerIA32::SetCC(byte* data) {
Steve Blockd0582a62009-12-15 09:54:21 +0000625 ASSERT_EQ(0x0F, *data);
Steve Blocka7e24c12009-10-30 11:49:00 +0000626 byte cond = *(data+1) & 0x0F;
627 const char* mnem = set_conditional_mnem[cond];
628 AppendToBuffer("%s ", mnem);
629 PrintRightByteOperand(data+2);
Steve Blockd0582a62009-12-15 09:54:21 +0000630 return 3; // Includes 0x0F.
Steve Blocka7e24c12009-10-30 11:49:00 +0000631}
632
633
634// Returns number of bytes used, including *data.
Steve Block3ce2e202009-11-05 08:53:23 +0000635int DisassemblerIA32::CMov(byte* data) {
Steve Blockd0582a62009-12-15 09:54:21 +0000636 ASSERT_EQ(0x0F, *data);
Steve Block3ce2e202009-11-05 08:53:23 +0000637 byte cond = *(data + 1) & 0x0F;
638 const char* mnem = conditional_move_mnem[cond];
639 int op_size = PrintOperands(mnem, REG_OPER_OP_ORDER, data + 2);
640 return 2 + op_size; // includes 0x0F
641}
642
643
644// Returns number of bytes used, including *data.
Steve Blocka7e24c12009-10-30 11:49:00 +0000645int DisassemblerIA32::FPUInstruction(byte* data) {
Steve Blockd0582a62009-12-15 09:54:21 +0000646 byte escape_opcode = *data;
647 ASSERT_EQ(0xD8, escape_opcode & 0xF8);
648 byte modrm_byte = *(data+1);
649
650 if (modrm_byte >= 0xC0) {
651 return RegisterFPUInstruction(escape_opcode, modrm_byte);
652 } else {
653 return MemoryFPUInstruction(escape_opcode, modrm_byte, data+1);
Steve Blocka7e24c12009-10-30 11:49:00 +0000654 }
Steve Blockd0582a62009-12-15 09:54:21 +0000655}
656
657int DisassemblerIA32::MemoryFPUInstruction(int escape_opcode,
658 int modrm_byte,
659 byte* modrm_start) {
660 const char* mnem = "?";
661 int regop = (modrm_byte >> 3) & 0x7; // reg/op field of modrm byte.
662 switch (escape_opcode) {
663 case 0xD9: switch (regop) {
664 case 0: mnem = "fld_s"; break;
665 case 3: mnem = "fstp_s"; break;
666 case 7: mnem = "fstcw"; break;
667 default: UnimplementedInstruction();
668 }
669 break;
670
671 case 0xDB: switch (regop) {
672 case 0: mnem = "fild_s"; break;
673 case 1: mnem = "fisttp_s"; break;
674 case 2: mnem = "fist_s"; break;
675 case 3: mnem = "fistp_s"; break;
676 default: UnimplementedInstruction();
677 }
678 break;
679
680 case 0xDD: switch (regop) {
681 case 0: mnem = "fld_d"; break;
Andrei Popescu402d9372010-02-26 13:31:12 +0000682 case 2: mnem = "fstp"; break;
Steve Blockd0582a62009-12-15 09:54:21 +0000683 case 3: mnem = "fstp_d"; break;
684 default: UnimplementedInstruction();
685 }
686 break;
687
688 case 0xDF: switch (regop) {
689 case 5: mnem = "fild_d"; break;
690 case 7: mnem = "fistp_d"; break;
691 default: UnimplementedInstruction();
692 }
693 break;
694
695 default: UnimplementedInstruction();
696 }
697 AppendToBuffer("%s ", mnem);
698 int count = PrintRightOperand(modrm_start);
699 return count + 1;
700}
701
702int DisassemblerIA32::RegisterFPUInstruction(int escape_opcode,
703 byte modrm_byte) {
704 bool has_register = false; // Is the FPU register encoded in modrm_byte?
705 const char* mnem = "?";
706
707 switch (escape_opcode) {
708 case 0xD8:
709 UnimplementedInstruction();
710 break;
711
712 case 0xD9:
713 switch (modrm_byte & 0xF8) {
714 case 0xC8:
715 mnem = "fxch";
716 has_register = true;
717 break;
718 default:
719 switch (modrm_byte) {
720 case 0xE0: mnem = "fchs"; break;
721 case 0xE1: mnem = "fabs"; break;
722 case 0xE4: mnem = "ftst"; break;
723 case 0xE8: mnem = "fld1"; break;
Andrei Popescu402d9372010-02-26 13:31:12 +0000724 case 0xEB: mnem = "fldpi"; break;
Steve Blockd0582a62009-12-15 09:54:21 +0000725 case 0xEE: mnem = "fldz"; break;
726 case 0xF5: mnem = "fprem1"; break;
727 case 0xF7: mnem = "fincstp"; break;
728 case 0xF8: mnem = "fprem"; break;
729 case 0xFE: mnem = "fsin"; break;
730 case 0xFF: mnem = "fcos"; break;
731 default: UnimplementedInstruction();
732 }
733 }
734 break;
735
736 case 0xDA:
737 if (modrm_byte == 0xE9) {
738 mnem = "fucompp";
739 } else {
740 UnimplementedInstruction();
741 }
742 break;
743
744 case 0xDB:
745 if ((modrm_byte & 0xF8) == 0xE8) {
746 mnem = "fucomi";
747 has_register = true;
748 } else if (modrm_byte == 0xE2) {
749 mnem = "fclex";
750 } else {
751 UnimplementedInstruction();
752 }
753 break;
754
755 case 0xDC:
756 has_register = true;
757 switch (modrm_byte & 0xF8) {
758 case 0xC0: mnem = "fadd"; break;
759 case 0xE8: mnem = "fsub"; break;
760 case 0xC8: mnem = "fmul"; break;
761 case 0xF8: mnem = "fdiv"; break;
762 default: UnimplementedInstruction();
763 }
764 break;
765
766 case 0xDD:
767 has_register = true;
768 switch (modrm_byte & 0xF8) {
769 case 0xC0: mnem = "ffree"; break;
770 case 0xD8: mnem = "fstp"; break;
771 default: UnimplementedInstruction();
772 }
773 break;
774
775 case 0xDE:
776 if (modrm_byte == 0xD9) {
777 mnem = "fcompp";
778 } else {
779 has_register = true;
780 switch (modrm_byte & 0xF8) {
781 case 0xC0: mnem = "faddp"; break;
782 case 0xE8: mnem = "fsubp"; break;
783 case 0xC8: mnem = "fmulp"; break;
784 case 0xF8: mnem = "fdivp"; break;
785 default: UnimplementedInstruction();
786 }
787 }
788 break;
789
790 case 0xDF:
791 if (modrm_byte == 0xE0) {
792 mnem = "fnstsw_ax";
793 } else if ((modrm_byte & 0xF8) == 0xE8) {
794 mnem = "fucomip";
795 has_register = true;
796 }
797 break;
798
799 default: UnimplementedInstruction();
800 }
801
802 if (has_register) {
803 AppendToBuffer("%s st%d", mnem, modrm_byte & 0x7);
804 } else {
805 AppendToBuffer("%s", mnem);
806 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000807 return 2;
808}
809
810
811// Mnemonics for instructions 0xF0 byte.
812// Returns NULL if the instruction is not handled here.
813static const char* F0Mnem(byte f0byte) {
814 switch (f0byte) {
815 case 0xA2: return "cpuid";
816 case 0x31: return "rdtsc";
817 case 0xBE: return "movsx_b";
818 case 0xBF: return "movsx_w";
819 case 0xB6: return "movzx_b";
820 case 0xB7: return "movzx_w";
821 case 0xAF: return "imul";
822 case 0xA5: return "shld";
823 case 0xAD: return "shrd";
824 case 0xAB: return "bts";
825 default: return NULL;
826 }
827}
828
829
830// Disassembled instruction '*instr' and writes it into 'out_buffer'.
831int DisassemblerIA32::InstructionDecode(v8::internal::Vector<char> out_buffer,
832 byte* instr) {
833 tmp_buffer_pos_ = 0; // starting to write as position 0
834 byte* data = instr;
835 // Check for hints.
836 const char* branch_hint = NULL;
837 // We use these two prefixes only with branch prediction
838 if (*data == 0x3E /*ds*/) {
839 branch_hint = "predicted taken";
840 data++;
841 } else if (*data == 0x2E /*cs*/) {
842 branch_hint = "predicted not taken";
843 data++;
844 }
845 bool processed = true; // Will be set to false if the current instruction
846 // is not in 'instructions' table.
847 const InstructionDesc& idesc = instruction_table.Get(*data);
848 switch (idesc.type) {
849 case ZERO_OPERANDS_INSTR:
850 AppendToBuffer(idesc.mnem);
851 data++;
852 break;
853
854 case TWO_OPERANDS_INSTR:
855 data++;
856 data += PrintOperands(idesc.mnem, idesc.op_order_, data);
857 break;
858
859 case JUMP_CONDITIONAL_SHORT_INSTR:
860 data += JumpConditionalShort(data, branch_hint);
861 break;
862
863 case REGISTER_INSTR:
864 AppendToBuffer("%s %s", idesc.mnem, NameOfCPURegister(*data & 0x07));
865 data++;
866 break;
867
868 case MOVE_REG_INSTR: {
869 byte* addr = reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data+1));
870 AppendToBuffer("mov %s,%s",
871 NameOfCPURegister(*data & 0x07),
872 NameOfAddress(addr));
873 data += 5;
874 break;
875 }
876
877 case CALL_JUMP_INSTR: {
878 byte* addr = data + *reinterpret_cast<int32_t*>(data+1) + 5;
879 AppendToBuffer("%s %s", idesc.mnem, NameOfAddress(addr));
880 data += 5;
881 break;
882 }
883
884 case SHORT_IMMEDIATE_INSTR: {
885 byte* addr = reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data+1));
886 AppendToBuffer("%s eax, %s", idesc.mnem, NameOfAddress(addr));
887 data += 5;
888 break;
889 }
890
891 case NO_INSTR:
892 processed = false;
893 break;
894
895 default:
896 UNIMPLEMENTED(); // This type is not implemented.
897 }
898 //----------------------------
899 if (!processed) {
900 switch (*data) {
901 case 0xC2:
902 AppendToBuffer("ret 0x%x", *reinterpret_cast<uint16_t*>(data+1));
903 data += 3;
904 break;
905
906 case 0x69: // fall through
907 case 0x6B:
908 { int mod, regop, rm;
909 get_modrm(*(data+1), &mod, &regop, &rm);
910 int32_t imm =
911 *data == 0x6B ? *(data+2) : *reinterpret_cast<int32_t*>(data+2);
912 AppendToBuffer("imul %s,%s,0x%x",
913 NameOfCPURegister(regop),
914 NameOfCPURegister(rm),
915 imm);
916 data += 2 + (*data == 0x6B ? 1 : 4);
917 }
918 break;
919
920 case 0xF6:
921 { int mod, regop, rm;
922 get_modrm(*(data+1), &mod, &regop, &rm);
923 if (mod == 3 && regop == eax) {
924 AppendToBuffer("test_b %s,%d", NameOfCPURegister(rm), *(data+2));
925 } else {
926 UnimplementedInstruction();
927 }
928 data += 3;
929 }
930 break;
931
932 case 0x81: // fall through
933 case 0x83: // 0x81 with sign extension bit set
934 data += PrintImmediateOp(data);
935 break;
936
937 case 0x0F:
938 { byte f0byte = *(data+1);
939 const char* f0mnem = F0Mnem(f0byte);
940 if (f0byte == 0xA2 || f0byte == 0x31) {
941 AppendToBuffer("%s", f0mnem);
942 data += 2;
943 } else if ((f0byte & 0xF0) == 0x80) {
944 data += JumpConditional(data, branch_hint);
945 } else if (f0byte == 0xBE || f0byte == 0xBF || f0byte == 0xB6 ||
946 f0byte == 0xB7 || f0byte == 0xAF) {
947 data += 2;
948 data += PrintOperands(f0mnem, REG_OPER_OP_ORDER, data);
949 } else if ((f0byte & 0xF0) == 0x90) {
950 data += SetCC(data);
Steve Block3ce2e202009-11-05 08:53:23 +0000951 } else if ((f0byte & 0xF0) == 0x40) {
952 data += CMov(data);
Steve Blocka7e24c12009-10-30 11:49:00 +0000953 } else {
954 data += 2;
955 if (f0byte == 0xAB || f0byte == 0xA5 || f0byte == 0xAD) {
956 // shrd, shld, bts
957 AppendToBuffer("%s ", f0mnem);
958 int mod, regop, rm;
959 get_modrm(*data, &mod, &regop, &rm);
960 data += PrintRightOperand(data);
961 if (f0byte == 0xAB) {
962 AppendToBuffer(",%s", NameOfCPURegister(regop));
963 } else {
964 AppendToBuffer(",%s,cl", NameOfCPURegister(regop));
965 }
966 } else {
967 UnimplementedInstruction();
968 }
969 }
970 }
971 break;
972
973 case 0x8F:
974 { data++;
975 int mod, regop, rm;
976 get_modrm(*data, &mod, &regop, &rm);
977 if (regop == eax) {
978 AppendToBuffer("pop ");
979 data += PrintRightOperand(data);
980 }
981 }
982 break;
983
984 case 0xFF:
985 { data++;
986 int mod, regop, rm;
987 get_modrm(*data, &mod, &regop, &rm);
988 const char* mnem = NULL;
989 switch (regop) {
990 case esi: mnem = "push"; break;
991 case eax: mnem = "inc"; break;
992 case ecx: mnem = "dec"; break;
993 case edx: mnem = "call"; break;
994 case esp: mnem = "jmp"; break;
995 default: mnem = "???";
996 }
997 AppendToBuffer("%s ", mnem);
998 data += PrintRightOperand(data);
999 }
1000 break;
1001
1002 case 0xC7: // imm32, fall through
1003 case 0xC6: // imm8
1004 { bool is_byte = *data == 0xC6;
1005 data++;
1006 AppendToBuffer("%s ", is_byte ? "mov_b" : "mov");
1007 data += PrintRightOperand(data);
1008 int32_t imm = is_byte ? *data : *reinterpret_cast<int32_t*>(data);
1009 AppendToBuffer(",0x%x", imm);
1010 data += is_byte ? 1 : 4;
1011 }
1012 break;
1013
1014 case 0x80:
1015 { data++;
Leon Clarkee46be812010-01-19 14:06:41 +00001016 int mod, regop, rm;
1017 get_modrm(*data, &mod, &regop, &rm);
1018 const char* mnem = NULL;
Leon Clarkee46be812010-01-19 14:06:41 +00001019 switch (regop) {
1020 case 5: mnem = "subb"; break;
1021 case 7: mnem = "cmpb"; break;
1022 default: UnimplementedInstruction();
1023 }
1024 AppendToBuffer("%s ", mnem);
Steve Blocka7e24c12009-10-30 11:49:00 +00001025 data += PrintRightOperand(data);
1026 int32_t imm = *data;
1027 AppendToBuffer(",0x%x", imm);
1028 data++;
1029 }
1030 break;
1031
1032 case 0x88: // 8bit, fall through
1033 case 0x89: // 32bit
1034 { bool is_byte = *data == 0x88;
1035 int mod, regop, rm;
1036 data++;
1037 get_modrm(*data, &mod, &regop, &rm);
1038 AppendToBuffer("%s ", is_byte ? "mov_b" : "mov");
1039 data += PrintRightOperand(data);
1040 AppendToBuffer(",%s", NameOfCPURegister(regop));
1041 }
1042 break;
1043
1044 case 0x66: // prefix
1045 data++;
1046 if (*data == 0x8B) {
1047 data++;
1048 data += PrintOperands("mov_w", REG_OPER_OP_ORDER, data);
1049 } else if (*data == 0x89) {
1050 data++;
1051 int mod, regop, rm;
1052 get_modrm(*data, &mod, &regop, &rm);
1053 AppendToBuffer("mov_w ");
1054 data += PrintRightOperand(data);
1055 AppendToBuffer(",%s", NameOfCPURegister(regop));
Steve Block3ce2e202009-11-05 08:53:23 +00001056 } else if (*data == 0x0F) {
1057 data++;
1058 if (*data == 0x2F) {
1059 data++;
1060 int mod, regop, rm;
1061 get_modrm(*data, &mod, &regop, &rm);
1062 AppendToBuffer("comisd %s,%s",
1063 NameOfXMMRegister(regop),
1064 NameOfXMMRegister(rm));
1065 data++;
Leon Clarkee46be812010-01-19 14:06:41 +00001066 } else if (*data == 0x57) {
1067 data++;
1068 int mod, regop, rm;
1069 get_modrm(*data, &mod, &regop, &rm);
1070 AppendToBuffer("xorpd %s,%s",
1071 NameOfXMMRegister(regop),
1072 NameOfXMMRegister(rm));
1073 data++;
1074 } else if (*data == 0x6F) {
1075 data++;
1076 int mod, regop, rm;
1077 get_modrm(*data, &mod, &regop, &rm);
1078 AppendToBuffer("movdqa %s,", NameOfXMMRegister(regop));
1079 data += PrintRightOperand(data);
1080 } else if (*data == 0x7F) {
1081 AppendToBuffer("movdqa ");
1082 data++;
1083 int mod, regop, rm;
1084 get_modrm(*data, &mod, &regop, &rm);
1085 data += PrintRightOperand(data);
1086 AppendToBuffer(",%s", NameOfXMMRegister(regop));
Steve Block3ce2e202009-11-05 08:53:23 +00001087 } else {
1088 UnimplementedInstruction();
1089 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001090 } else {
1091 UnimplementedInstruction();
1092 }
1093 break;
1094
1095 case 0xFE:
1096 { data++;
1097 int mod, regop, rm;
1098 get_modrm(*data, &mod, &regop, &rm);
1099 if (mod == 3 && regop == ecx) {
1100 AppendToBuffer("dec_b %s", NameOfCPURegister(rm));
1101 } else {
1102 UnimplementedInstruction();
1103 }
1104 data++;
1105 }
1106 break;
1107
1108 case 0x68:
1109 AppendToBuffer("push 0x%x", *reinterpret_cast<int32_t*>(data+1));
1110 data += 5;
1111 break;
1112
1113 case 0x6A:
1114 AppendToBuffer("push 0x%x", *reinterpret_cast<int8_t*>(data + 1));
1115 data += 2;
1116 break;
1117
1118 case 0xA8:
1119 AppendToBuffer("test al,0x%x", *reinterpret_cast<uint8_t*>(data+1));
1120 data += 2;
1121 break;
1122
Leon Clarkee46be812010-01-19 14:06:41 +00001123 case 0x2C:
1124 AppendToBuffer("subb eax,0x%x", *reinterpret_cast<uint8_t*>(data+1));
1125 data += 2;
1126 break;
1127
Steve Blocka7e24c12009-10-30 11:49:00 +00001128 case 0xA9:
1129 AppendToBuffer("test eax,0x%x", *reinterpret_cast<int32_t*>(data+1));
1130 data += 5;
1131 break;
1132
1133 case 0xD1: // fall through
1134 case 0xD3: // fall through
1135 case 0xC1:
1136 data += D1D3C1Instruction(data);
1137 break;
1138
1139 case 0xD9: // fall through
1140 case 0xDA: // fall through
1141 case 0xDB: // fall through
1142 case 0xDC: // fall through
1143 case 0xDD: // fall through
1144 case 0xDE: // fall through
1145 case 0xDF:
1146 data += FPUInstruction(data);
1147 break;
1148
1149 case 0xEB:
1150 data += JumpShort(data);
1151 break;
1152
1153 case 0xF2:
1154 if (*(data+1) == 0x0F) {
1155 byte b2 = *(data+2);
1156 if (b2 == 0x11) {
1157 AppendToBuffer("movsd ");
1158 data += 3;
1159 int mod, regop, rm;
1160 get_modrm(*data, &mod, &regop, &rm);
1161 data += PrintRightOperand(data);
1162 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1163 } else if (b2 == 0x10) {
1164 data += 3;
1165 int mod, regop, rm;
1166 get_modrm(*data, &mod, &regop, &rm);
1167 AppendToBuffer("movsd %s,", NameOfXMMRegister(regop));
1168 data += PrintRightOperand(data);
1169 } else {
1170 const char* mnem = "?";
1171 switch (b2) {
1172 case 0x2A: mnem = "cvtsi2sd"; break;
1173 case 0x58: mnem = "addsd"; break;
1174 case 0x59: mnem = "mulsd"; break;
1175 case 0x5C: mnem = "subsd"; break;
1176 case 0x5E: mnem = "divsd"; break;
1177 }
1178 data += 3;
1179 int mod, regop, rm;
1180 get_modrm(*data, &mod, &regop, &rm);
1181 if (b2 == 0x2A) {
1182 AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
1183 data += PrintRightOperand(data);
1184 } else {
1185 AppendToBuffer("%s %s,%s",
1186 mnem,
1187 NameOfXMMRegister(regop),
1188 NameOfXMMRegister(rm));
1189 data++;
1190 }
1191 }
1192 } else {
1193 UnimplementedInstruction();
1194 }
1195 break;
1196
1197 case 0xF3:
Leon Clarkee46be812010-01-19 14:06:41 +00001198 if (*(data+1) == 0x0F) {
1199 if (*(data+2) == 0x2C) {
1200 data += 3;
1201 data += PrintOperands("cvttss2si", REG_OPER_OP_ORDER, data);
1202 } else if (*(data+2) == 0x6F) {
1203 data += 3;
1204 int mod, regop, rm;
1205 get_modrm(*data, &mod, &regop, &rm);
1206 AppendToBuffer("movdqu %s,", NameOfXMMRegister(regop));
1207 data += PrintRightOperand(data);
1208 } else if (*(data+2) == 0x7F) {
1209 AppendToBuffer("movdqu ");
1210 data += 3;
1211 int mod, regop, rm;
1212 get_modrm(*data, &mod, &regop, &rm);
1213 data += PrintRightOperand(data);
1214 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1215 } else {
1216 UnimplementedInstruction();
1217 }
1218 } else if (*(data+1) == 0xA5) {
1219 data += 2;
1220 AppendToBuffer("rep_movs");
Steve Blocka7e24c12009-10-30 11:49:00 +00001221 } else {
1222 UnimplementedInstruction();
1223 }
1224 break;
1225
1226 case 0xF7:
1227 data += F7Instruction(data);
1228 break;
1229
1230 default:
1231 UnimplementedInstruction();
1232 }
1233 }
1234
1235 if (tmp_buffer_pos_ < sizeof tmp_buffer_) {
1236 tmp_buffer_[tmp_buffer_pos_] = '\0';
1237 }
1238
1239 int instr_len = data - instr;
Leon Clarkee46be812010-01-19 14:06:41 +00001240 if (instr_len == 0) {
1241 printf("%02x", *data);
1242 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001243 ASSERT(instr_len > 0); // Ensure progress.
1244
1245 int outp = 0;
1246 // Instruction bytes.
1247 for (byte* bp = instr; bp < data; bp++) {
1248 outp += v8::internal::OS::SNPrintF(out_buffer + outp,
1249 "%02x",
1250 *bp);
1251 }
1252 for (int i = 6 - instr_len; i >= 0; i--) {
1253 outp += v8::internal::OS::SNPrintF(out_buffer + outp,
1254 " ");
1255 }
1256
1257 outp += v8::internal::OS::SNPrintF(out_buffer + outp,
1258 " %s",
1259 tmp_buffer_.start());
1260 return instr_len;
1261}
1262
1263
1264//------------------------------------------------------------------------------
1265
1266
1267static const char* cpu_regs[8] = {
1268 "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi"
1269};
1270
1271
1272static const char* byte_cpu_regs[8] = {
1273 "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh"
1274};
1275
1276
1277static const char* xmm_regs[8] = {
1278 "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7"
1279};
1280
1281
1282const char* NameConverter::NameOfAddress(byte* addr) const {
1283 static v8::internal::EmbeddedVector<char, 32> tmp_buffer;
1284 v8::internal::OS::SNPrintF(tmp_buffer, "%p", addr);
1285 return tmp_buffer.start();
1286}
1287
1288
1289const char* NameConverter::NameOfConstant(byte* addr) const {
1290 return NameOfAddress(addr);
1291}
1292
1293
1294const char* NameConverter::NameOfCPURegister(int reg) const {
1295 if (0 <= reg && reg < 8) return cpu_regs[reg];
1296 return "noreg";
1297}
1298
1299
1300const char* NameConverter::NameOfByteCPURegister(int reg) const {
1301 if (0 <= reg && reg < 8) return byte_cpu_regs[reg];
1302 return "noreg";
1303}
1304
1305
1306const char* NameConverter::NameOfXMMRegister(int reg) const {
1307 if (0 <= reg && reg < 8) return xmm_regs[reg];
1308 return "noxmmreg";
1309}
1310
1311
1312const char* NameConverter::NameInCode(byte* addr) const {
1313 // IA32 does not embed debug strings at the moment.
1314 UNREACHABLE();
1315 return "";
1316}
1317
1318
1319//------------------------------------------------------------------------------
1320
1321Disassembler::Disassembler(const NameConverter& converter)
1322 : converter_(converter) {}
1323
1324
1325Disassembler::~Disassembler() {}
1326
1327
1328int Disassembler::InstructionDecode(v8::internal::Vector<char> buffer,
1329 byte* instruction) {
1330 DisassemblerIA32 d(converter_, false /*do not crash if unimplemented*/);
1331 return d.InstructionDecode(buffer, instruction);
1332}
1333
1334
1335// The IA-32 assembler does not currently use constant pools.
1336int Disassembler::ConstantPoolSizeAt(byte* instruction) { return -1; }
1337
1338
1339/*static*/ void Disassembler::Disassemble(FILE* f, byte* begin, byte* end) {
1340 NameConverter converter;
1341 Disassembler d(converter);
1342 for (byte* pc = begin; pc < end;) {
1343 v8::internal::EmbeddedVector<char, 128> buffer;
1344 buffer[0] = '\0';
1345 byte* prev_pc = pc;
1346 pc += d.InstructionDecode(buffer, pc);
1347 fprintf(f, "%p", prev_pc);
1348 fprintf(f, " ");
1349
1350 for (byte* bp = prev_pc; bp < pc; bp++) {
1351 fprintf(f, "%02x", *bp);
1352 }
1353 for (int i = 6 - (pc - prev_pc); i >= 0; i--) {
1354 fprintf(f, " ");
1355 }
1356 fprintf(f, " %s\n", buffer.start());
1357 }
1358}
1359
1360
1361} // namespace disasm