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