00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include <assert.h>
00029 #include <stdio.h>
00030 #include <stdarg.h>
00031
00032 #include "v8.h"
00033 #include "disasm.h"
00034
00035 namespace disasm {
00036
00037 enum OperandOrder {
00038 UNSET_OP_ORDER = 0,
00039 REG_OPER_OP_ORDER,
00040 OPER_REG_OP_ORDER
00041 };
00042
00043
00044
00045
00046
00047 struct ByteMnemonic {
00048 int b;
00049 const char* mnem;
00050 OperandOrder op_order_;
00051 };
00052
00053
00054 static ByteMnemonic two_operands_instr[] = {
00055 {0x03, "add", REG_OPER_OP_ORDER},
00056 {0x21, "and", OPER_REG_OP_ORDER},
00057 {0x23, "and", REG_OPER_OP_ORDER},
00058 {0x3B, "cmp", REG_OPER_OP_ORDER},
00059 {0x8D, "lea", REG_OPER_OP_ORDER},
00060 {0x09, "or", OPER_REG_OP_ORDER},
00061 {0x0B, "or", REG_OPER_OP_ORDER},
00062 {0x1B, "sbb", REG_OPER_OP_ORDER},
00063 {0x29, "sub", OPER_REG_OP_ORDER},
00064 {0x2B, "sub", REG_OPER_OP_ORDER},
00065 {0x85, "test", REG_OPER_OP_ORDER},
00066 {0x31, "xor", OPER_REG_OP_ORDER},
00067 {0x33, "xor", REG_OPER_OP_ORDER},
00068 {0x8A, "mov_b", REG_OPER_OP_ORDER},
00069 {0x8B, "mov", REG_OPER_OP_ORDER},
00070 {-1, "", UNSET_OP_ORDER}
00071 };
00072
00073
00074 static ByteMnemonic zero_operands_instr[] = {
00075 {0xC3, "ret", UNSET_OP_ORDER},
00076 {0xC9, "leave", UNSET_OP_ORDER},
00077 {0x90, "nop", UNSET_OP_ORDER},
00078 {0xF4, "hlt", UNSET_OP_ORDER},
00079 {0xCC, "int3", UNSET_OP_ORDER},
00080 {0x60, "pushad", UNSET_OP_ORDER},
00081 {0x61, "popad", UNSET_OP_ORDER},
00082 {0x9C, "pushfd", UNSET_OP_ORDER},
00083 {0x9D, "popfd", UNSET_OP_ORDER},
00084 {0x9E, "sahf", UNSET_OP_ORDER},
00085 {0x99, "cdq", UNSET_OP_ORDER},
00086 {0x9B, "fwait", UNSET_OP_ORDER},
00087 {-1, "", UNSET_OP_ORDER}
00088 };
00089
00090
00091 static ByteMnemonic call_jump_instr[] = {
00092 {0xE8, "call", UNSET_OP_ORDER},
00093 {0xE9, "jmp", UNSET_OP_ORDER},
00094 {-1, "", UNSET_OP_ORDER}
00095 };
00096
00097
00098 static ByteMnemonic short_immediate_instr[] = {
00099 {0x05, "add", UNSET_OP_ORDER},
00100 {0x0D, "or", UNSET_OP_ORDER},
00101 {0x15, "adc", UNSET_OP_ORDER},
00102 {0x25, "and", UNSET_OP_ORDER},
00103 {0x2D, "sub", UNSET_OP_ORDER},
00104 {0x35, "xor", UNSET_OP_ORDER},
00105 {0x3D, "cmp", UNSET_OP_ORDER},
00106 {-1, "", UNSET_OP_ORDER}
00107 };
00108
00109
00110 static const char* jump_conditional_mnem[] = {
00111 "jo", "jno", "jc", "jnc",
00112 "jz", "jnz", "jna", "ja",
00113 "js", "jns", "jpe", "jpo",
00114 "jl", "jnl", "jng", "jg"
00115 };
00116
00117
00118 enum InstructionType {
00119 NO_INSTR,
00120 ZERO_OPERANDS_INSTR,
00121 TWO_OPERANDS_INSTR,
00122 JUMP_CONDITIONAL_SHORT_INSTR,
00123 REGISTER_INSTR,
00124 MOVE_REG_INSTR,
00125 CALL_JUMP_INSTR,
00126 SHORT_IMMEDIATE_INSTR
00127 };
00128
00129
00130 struct InstructionDesc {
00131 const char* mnem;
00132 InstructionType type;
00133 OperandOrder op_order_;
00134 };
00135
00136
00137 class InstructionTable {
00138 public:
00139 InstructionTable();
00140 const InstructionDesc& Get(byte x) const { return instructions_[x]; }
00141
00142 private:
00143 InstructionDesc instructions_[256];
00144 void Clear();
00145 void Init();
00146 void CopyTable(ByteMnemonic bm[], InstructionType type);
00147 void SetTableRange(InstructionType type,
00148 byte start,
00149 byte end,
00150 const char* mnem);
00151 void AddJumpConditionalShort();
00152 };
00153
00154
00155 InstructionTable::InstructionTable() {
00156 Clear();
00157 Init();
00158 }
00159
00160
00161 void InstructionTable::Clear() {
00162 for (int i = 0; i < 256; i++) {
00163 instructions_[i].mnem = "";
00164 instructions_[i].type = NO_INSTR;
00165 instructions_[i].op_order_ = UNSET_OP_ORDER;
00166 }
00167 }
00168
00169
00170 void InstructionTable::Init() {
00171 CopyTable(two_operands_instr, TWO_OPERANDS_INSTR);
00172 CopyTable(zero_operands_instr, ZERO_OPERANDS_INSTR);
00173 CopyTable(call_jump_instr, CALL_JUMP_INSTR);
00174 CopyTable(short_immediate_instr, SHORT_IMMEDIATE_INSTR);
00175 AddJumpConditionalShort();
00176 SetTableRange(REGISTER_INSTR, 0x40, 0x47, "inc");
00177 SetTableRange(REGISTER_INSTR, 0x48, 0x4F, "dec");
00178 SetTableRange(REGISTER_INSTR, 0x50, 0x57, "push");
00179 SetTableRange(REGISTER_INSTR, 0x58, 0x5F, "pop");
00180 SetTableRange(MOVE_REG_INSTR, 0xB8, 0xBF, "mov");
00181 }
00182
00183
00184 void InstructionTable::CopyTable(ByteMnemonic bm[], InstructionType type) {
00185 for (int i = 0; bm[i].b >= 0; i++) {
00186 InstructionDesc* id = &instructions_[bm[i].b];
00187 id->mnem = bm[i].mnem;
00188 id->op_order_ = bm[i].op_order_;
00189 assert(id->type == NO_INSTR);
00190 id->type = type;
00191 }
00192 }
00193
00194
00195 void InstructionTable::SetTableRange(InstructionType type,
00196 byte start,
00197 byte end,
00198 const char* mnem) {
00199 for (byte b = start; b <= end; b++) {
00200 InstructionDesc* id = &instructions_[b];
00201 assert(id->type == NO_INSTR);
00202 id->mnem = mnem;
00203 id->type = type;
00204 }
00205 }
00206
00207
00208 void InstructionTable::AddJumpConditionalShort() {
00209 for (byte b = 0x70; b <= 0x7F; b++) {
00210 InstructionDesc* id = &instructions_[b];
00211 assert(id->type == NO_INSTR);
00212 id->mnem = jump_conditional_mnem[b & 0x0F];
00213 id->type = JUMP_CONDITIONAL_SHORT_INSTR;
00214 }
00215 }
00216
00217
00218 static InstructionTable instruction_table;
00219
00220
00221
00222 class DisassemblerIA32 {
00223 public:
00224 DisassemblerIA32(const NameConverter& converter,
00225 bool abort_on_unimplemented = true)
00226 : converter_(converter),
00227 tmp_buffer_pos_(0),
00228 abort_on_unimplemented_(abort_on_unimplemented) {
00229 tmp_buffer_[0] = '\0';
00230 }
00231
00232 virtual ~DisassemblerIA32() {}
00233
00234
00235
00236 int InstructionDecode(v8::internal::Vector<char> buffer, byte* instruction);
00237
00238 private:
00239 const NameConverter& converter_;
00240 v8::internal::EmbeddedVector<char, 128> tmp_buffer_;
00241 unsigned int tmp_buffer_pos_;
00242 bool abort_on_unimplemented_;
00243
00244
00245 enum {
00246 eax = 0,
00247 ecx = 1,
00248 edx = 2,
00249 ebx = 3,
00250 esp = 4,
00251 ebp = 5,
00252 esi = 6,
00253 edi = 7
00254 };
00255
00256
00257 const char* NameOfCPURegister(int reg) const {
00258 return converter_.NameOfCPURegister(reg);
00259 }
00260
00261
00262 const char* NameOfXMMRegister(int reg) const {
00263 return converter_.NameOfXMMRegister(reg);
00264 }
00265
00266
00267 const char* NameOfAddress(byte* addr) const {
00268 return converter_.NameOfAddress(addr);
00269 }
00270
00271
00272
00273 static void get_modrm(byte data, int* mod, int* regop, int* rm) {
00274 *mod = (data >> 6) & 3;
00275 *regop = (data & 0x38) >> 3;
00276 *rm = data & 7;
00277 }
00278
00279
00280 static void get_sib(byte data, int* scale, int* index, int* base) {
00281 *scale = (data >> 6) & 3;
00282 *index = (data >> 3) & 7;
00283 *base = data & 7;
00284 }
00285
00286
00287 int PrintRightOperand(byte* modrmp);
00288 int PrintOperands(const char* mnem, OperandOrder op_order, byte* data);
00289 int PrintImmediateOp(byte* data);
00290 int F7Instruction(byte* data);
00291 int D1D3C1Instruction(byte* data);
00292 int JumpShort(byte* data);
00293 int JumpConditional(byte* data, const char* comment);
00294 int JumpConditionalShort(byte* data, const char* comment);
00295 int FPUInstruction(byte* data);
00296 void AppendToBuffer(const char* format, ...);
00297
00298
00299 void UnimplementedInstruction() {
00300 if (abort_on_unimplemented_) {
00301 UNIMPLEMENTED();
00302 } else {
00303 AppendToBuffer("'Unimplemented Instruction'");
00304 }
00305 }
00306 };
00307
00308
00309 void DisassemblerIA32::AppendToBuffer(const char* format, ...) {
00310 v8::internal::Vector<char> buf = tmp_buffer_ + tmp_buffer_pos_;
00311 va_list args;
00312 va_start(args, format);
00313 int result = v8::internal::OS::VSNPrintF(buf, format, args);
00314 va_end(args);
00315 tmp_buffer_pos_ += result;
00316 }
00317
00318
00319
00320
00321 int DisassemblerIA32::PrintRightOperand(byte* modrmp) {
00322 int mod, regop, rm;
00323 get_modrm(*modrmp, &mod, ®op, &rm);
00324 switch (mod) {
00325 case 0:
00326 if (rm == ebp) {
00327 int32_t disp = *reinterpret_cast<int32_t*>(modrmp+1);
00328 AppendToBuffer("[0x%x]", disp);
00329 return 5;
00330 } else if (rm == esp) {
00331 byte sib = *(modrmp + 1);
00332 int scale, index, base;
00333 get_sib(sib, &scale, &index, &base);
00334 if (index == esp && base == esp && scale == 0 ) {
00335 AppendToBuffer("[%s]", NameOfCPURegister(rm));
00336 return 2;
00337 } else if (base == ebp) {
00338 int32_t disp = *reinterpret_cast<int32_t*>(modrmp + 2);
00339 AppendToBuffer("[%s*%d+0x%x]",
00340 NameOfCPURegister(index),
00341 1 << scale,
00342 disp);
00343 return 6;
00344 } else if (index != esp && base != ebp) {
00345
00346 AppendToBuffer("[%s+%s*%d]",
00347 NameOfCPURegister(base),
00348 NameOfCPURegister(index),
00349 1 << scale);
00350 return 2;
00351 } else {
00352 UnimplementedInstruction();
00353 return 1;
00354 }
00355 } else {
00356 AppendToBuffer("[%s]", NameOfCPURegister(rm));
00357 return 1;
00358 }
00359 break;
00360 case 1:
00361 case 2:
00362 if (rm == esp) {
00363 byte sib = *(modrmp + 1);
00364 int scale, index, base;
00365 get_sib(sib, &scale, &index, &base);
00366 int disp =
00367 mod == 2 ? *reinterpret_cast<int32_t*>(modrmp + 2) : *(modrmp + 2);
00368 if (index == base && index == rm && scale == 0 ) {
00369 AppendToBuffer("[%s+0x%x]", NameOfCPURegister(rm), disp);
00370 } else {
00371 AppendToBuffer("[%s+%s*%d+0x%x]",
00372 NameOfCPURegister(base),
00373 NameOfCPURegister(index),
00374 1 << scale,
00375 disp);
00376 }
00377 return mod == 2 ? 6 : 3;
00378 } else {
00379
00380 int disp =
00381 mod == 2 ? *reinterpret_cast<int32_t*>(modrmp + 1) : *(modrmp + 1);
00382 AppendToBuffer("[%s+0x%x]", NameOfCPURegister(rm), disp);
00383 return mod == 2 ? 5 : 2;
00384 }
00385 break;
00386 case 3:
00387 AppendToBuffer("%s", NameOfCPURegister(rm));
00388 return 1;
00389 default:
00390 UnimplementedInstruction();
00391 return 1;
00392 }
00393 UNREACHABLE();
00394 }
00395
00396
00397
00398
00399 int DisassemblerIA32::PrintOperands(const char* mnem,
00400 OperandOrder op_order,
00401 byte* data) {
00402 byte modrm = *data;
00403 int mod, regop, rm;
00404 get_modrm(modrm, &mod, ®op, &rm);
00405 int advance = 0;
00406 switch (op_order) {
00407 case REG_OPER_OP_ORDER: {
00408 AppendToBuffer("%s %s,", mnem, NameOfCPURegister(regop));
00409 advance = PrintRightOperand(data);
00410 break;
00411 }
00412 case OPER_REG_OP_ORDER: {
00413 AppendToBuffer("%s ", mnem);
00414 advance = PrintRightOperand(data);
00415 AppendToBuffer(",%s", NameOfCPURegister(regop));
00416 break;
00417 }
00418 default:
00419 UNREACHABLE();
00420 break;
00421 }
00422 return advance;
00423 }
00424
00425
00426
00427
00428 int DisassemblerIA32::PrintImmediateOp(byte* data) {
00429 bool sign_extension_bit = (*data & 0x02) != 0;
00430 byte modrm = *(data+1);
00431 int mod, regop, rm;
00432 get_modrm(modrm, &mod, ®op, &rm);
00433 const char* mnem = "Imm???";
00434 switch (regop) {
00435 case 0: mnem = "add"; break;
00436 case 1: mnem = "or"; break;
00437 case 2: mnem = "adc"; break;
00438 case 4: mnem = "and"; break;
00439 case 5: mnem = "sub"; break;
00440 case 6: mnem = "xor"; break;
00441 case 7: mnem = "cmp"; break;
00442 default: UnimplementedInstruction();
00443 }
00444 AppendToBuffer("%s ", mnem);
00445 int count = PrintRightOperand(data+1);
00446 if (sign_extension_bit) {
00447 AppendToBuffer(",0x%x", *(data + 1 + count));
00448 return 1 + count + 1 ;
00449 } else {
00450 AppendToBuffer(",0x%x", *reinterpret_cast<int32_t*>(data + 1 + count));
00451 return 1 + count + 4 ;
00452 }
00453 }
00454
00455
00456
00457 int DisassemblerIA32::F7Instruction(byte* data) {
00458 assert(*data == 0xF7);
00459 byte modrm = *(data+1);
00460 int mod, regop, rm;
00461 get_modrm(modrm, &mod, ®op, &rm);
00462 if (mod == 3 && regop != 0) {
00463 const char* mnem = NULL;
00464 switch (regop) {
00465 case 2: mnem = "not"; break;
00466 case 3: mnem = "neg"; break;
00467 case 4: mnem = "mul"; break;
00468 case 7: mnem = "idiv"; break;
00469 default: UnimplementedInstruction();
00470 }
00471 AppendToBuffer("%s %s", mnem, NameOfCPURegister(rm));
00472 return 2;
00473 } else if (mod == 3 && regop == eax) {
00474 int32_t imm = *reinterpret_cast<int32_t*>(data+2);
00475 AppendToBuffer("test %s,0x%x", NameOfCPURegister(rm), imm);
00476 return 6;
00477 } else if (regop == eax) {
00478 AppendToBuffer("test ");
00479 int count = PrintRightOperand(data+1);
00480 int32_t imm = *reinterpret_cast<int32_t*>(data+1+count);
00481 AppendToBuffer(",0x%x", imm);
00482 return 1+count+4 ;
00483 } else {
00484 UnimplementedInstruction();
00485 return 2;
00486 }
00487 }
00488
00489 int DisassemblerIA32::D1D3C1Instruction(byte* data) {
00490 byte op = *data;
00491 assert(op == 0xD1 || op == 0xD3 || op == 0xC1);
00492 byte modrm = *(data+1);
00493 int mod, regop, rm;
00494 get_modrm(modrm, &mod, ®op, &rm);
00495 int imm8 = -1;
00496 int num_bytes = 2;
00497 if (mod == 3) {
00498 const char* mnem = NULL;
00499 if (op == 0xD1) {
00500 imm8 = 1;
00501 switch (regop) {
00502 case edx: mnem = "rcl"; break;
00503 case edi: mnem = "sar"; break;
00504 case esp: mnem = "shl"; break;
00505 default: UnimplementedInstruction();
00506 }
00507 } else if (op == 0xC1) {
00508 imm8 = *(data+2);
00509 num_bytes = 3;
00510 switch (regop) {
00511 case edx: mnem = "rcl"; break;
00512 case esp: mnem = "shl"; break;
00513 case ebp: mnem = "shr"; break;
00514 case edi: mnem = "sar"; break;
00515 default: UnimplementedInstruction();
00516 }
00517 } else if (op == 0xD3) {
00518 switch (regop) {
00519 case esp: mnem = "shl"; break;
00520 case ebp: mnem = "shr"; break;
00521 case edi: mnem = "sar"; break;
00522 default: UnimplementedInstruction();
00523 }
00524 }
00525 assert(mnem != NULL);
00526 AppendToBuffer("%s %s,", mnem, NameOfCPURegister(rm));
00527 if (imm8 > 0) {
00528 AppendToBuffer("%d", imm8);
00529 } else {
00530 AppendToBuffer("cl");
00531 }
00532 } else {
00533 UnimplementedInstruction();
00534 }
00535 return num_bytes;
00536 }
00537
00538
00539
00540 int DisassemblerIA32::JumpShort(byte* data) {
00541 assert(*data == 0xEB);
00542 byte b = *(data+1);
00543 byte* dest = data + static_cast<int8_t>(b) + 2;
00544 AppendToBuffer("jmp %s", NameOfAddress(dest));
00545 return 2;
00546 }
00547
00548
00549
00550 int DisassemblerIA32::JumpConditional(byte* data, const char* comment) {
00551 assert(*data == 0x0F);
00552 byte cond = *(data+1) & 0x0F;
00553 byte* dest = data + *reinterpret_cast<int32_t*>(data+2) + 6;
00554 const char* mnem = jump_conditional_mnem[cond];
00555 AppendToBuffer("%s %s", mnem, NameOfAddress(dest));
00556 if (comment != NULL) {
00557 AppendToBuffer(", %s", comment);
00558 }
00559 return 6;
00560 }
00561
00562
00563
00564 int DisassemblerIA32::JumpConditionalShort(byte* data, const char* comment) {
00565 byte cond = *data & 0x0F;
00566 byte b = *(data+1);
00567 byte* dest = data + static_cast<int8_t>(b) + 2;
00568 const char* mnem = jump_conditional_mnem[cond];
00569 AppendToBuffer("%s %s", mnem, NameOfAddress(dest));
00570 if (comment != NULL) {
00571 AppendToBuffer(", %s", comment);
00572 }
00573 return 2;
00574 }
00575
00576
00577
00578 int DisassemblerIA32::FPUInstruction(byte* data) {
00579 byte b1 = *data;
00580 byte b2 = *(data + 1);
00581 if (b1 == 0xD9) {
00582 const char* mnem = NULL;
00583 switch (b2) {
00584 case 0xE8: mnem = "fld1"; break;
00585 case 0xEE: mnem = "fldz"; break;
00586 case 0xE1: mnem = "fabs"; break;
00587 case 0xE0: mnem = "fchs"; break;
00588 case 0xF8: mnem = "fprem"; break;
00589 case 0xF5: mnem = "fprem1"; break;
00590 case 0xF7: mnem = "fincstp"; break;
00591 case 0xE4: mnem = "ftst"; break;
00592 }
00593 if (mnem != NULL) {
00594 AppendToBuffer("%s", mnem);
00595 return 2;
00596 } else if ((b2 & 0xF8) == 0xC8) {
00597 AppendToBuffer("fxch st%d", b2 & 0x7);
00598 return 2;
00599 } else {
00600 int mod, regop, rm;
00601 get_modrm(*(data+1), &mod, ®op, &rm);
00602 const char* mnem = "?";
00603 switch (regop) {
00604 case eax: mnem = "fld_s"; break;
00605 case ebx: mnem = "fstp_s"; break;
00606 default: UnimplementedInstruction();
00607 }
00608 AppendToBuffer("%s ", mnem);
00609 int count = PrintRightOperand(data + 1);
00610 return count + 1;
00611 }
00612 } else if (b1 == 0xDD) {
00613 if ((b2 & 0xF8) == 0xC0) {
00614 AppendToBuffer("ffree st%d", b2 & 0x7);
00615 return 2;
00616 } else {
00617 int mod, regop, rm;
00618 get_modrm(*(data+1), &mod, ®op, &rm);
00619 const char* mnem = "?";
00620 switch (regop) {
00621 case eax: mnem = "fld_d"; break;
00622 case ebx: mnem = "fstp_d"; break;
00623 default: UnimplementedInstruction();
00624 }
00625 AppendToBuffer("%s ", mnem);
00626 int count = PrintRightOperand(data + 1);
00627 return count + 1;
00628 }
00629 } else if (b1 == 0xDB) {
00630 int mod, regop, rm;
00631 get_modrm(*(data+1), &mod, ®op, &rm);
00632 const char* mnem = "?";
00633 switch (regop) {
00634 case eax: mnem = "fild_s"; break;
00635 case edx: mnem = "fist_s"; break;
00636 case ebx: mnem = "fistp_s"; break;
00637 default: UnimplementedInstruction();
00638 }
00639 AppendToBuffer("%s ", mnem);
00640 int count = PrintRightOperand(data + 1);
00641 return count + 1;
00642 } else if (b1 == 0xDF) {
00643 if (b2 == 0xE0) {
00644 AppendToBuffer("fnstsw_ax");
00645 return 2;
00646 }
00647 int mod, regop, rm;
00648 get_modrm(*(data+1), &mod, ®op, &rm);
00649 const char* mnem = "?";
00650 switch (regop) {
00651 case ebp: mnem = "fild_d"; break;
00652 case edi: mnem = "fistp_d"; break;
00653 default: UnimplementedInstruction();
00654 }
00655 AppendToBuffer("%s ", mnem);
00656 int count = PrintRightOperand(data + 1);
00657 return count + 1;
00658 } else if (b1 == 0xDC || b1 == 0xDE) {
00659 bool is_pop = (b1 == 0xDE);
00660 if (is_pop && b2 == 0xD9) {
00661 AppendToBuffer("fcompp");
00662 return 2;
00663 }
00664 const char* mnem = "FP0xDC";
00665 switch (b2 & 0xF8) {
00666 case 0xC0: mnem = "fadd"; break;
00667 case 0xE8: mnem = "fsub"; break;
00668 case 0xC8: mnem = "fmul"; break;
00669 case 0xF8: mnem = "fdiv"; break;
00670 default: UnimplementedInstruction();
00671 }
00672 AppendToBuffer("%s%s st%d", mnem, is_pop ? "p" : "", b2 & 0x7);
00673 return 2;
00674 } else if (b1 == 0xDA && b2 == 0xE9) {
00675 const char* mnem = "fucompp";
00676 AppendToBuffer("%s", mnem);
00677 return 2;
00678 }
00679 AppendToBuffer("Unknown FP instruction");
00680 return 2;
00681 }
00682
00683
00684
00685
00686 static const char* F0Mnem(byte f0byte) {
00687 switch (f0byte) {
00688 case 0xA2: return "cpuid";
00689 case 0x31: return "rdtsc";
00690 case 0xBE: return "movsx_b";
00691 case 0xBF: return "movsx_w";
00692 case 0xB6: return "movzx_b";
00693 case 0xB7: return "movzx_w";
00694 case 0xAF: return "imul";
00695 case 0xA5: return "shld";
00696 case 0xAD: return "shrd";
00697 case 0xAB: return "bts";
00698 default: return NULL;
00699 }
00700 }
00701
00702
00703
00704 int DisassemblerIA32::InstructionDecode(v8::internal::Vector<char> out_buffer,
00705 byte* instr) {
00706 tmp_buffer_pos_ = 0;
00707 byte* data = instr;
00708
00709 const char* branch_hint = NULL;
00710
00711 if (*data == 0x3E ) {
00712 branch_hint = "predicted taken";
00713 data++;
00714 } else if (*data == 0x2E ) {
00715 branch_hint = "predicted not taken";
00716 data++;
00717 }
00718 bool processed = true;
00719
00720 const InstructionDesc& idesc = instruction_table.Get(*data);
00721 switch (idesc.type) {
00722 case ZERO_OPERANDS_INSTR:
00723 AppendToBuffer(idesc.mnem);
00724 data++;
00725 break;
00726
00727 case TWO_OPERANDS_INSTR:
00728 data++;
00729 data += PrintOperands(idesc.mnem, idesc.op_order_, data);
00730 break;
00731
00732 case JUMP_CONDITIONAL_SHORT_INSTR:
00733 data += JumpConditionalShort(data, branch_hint);
00734 break;
00735
00736 case REGISTER_INSTR:
00737 AppendToBuffer("%s %s", idesc.mnem, NameOfCPURegister(*data & 0x07));
00738 data++;
00739 break;
00740
00741 case MOVE_REG_INSTR: {
00742 byte* addr = reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data+1));
00743 AppendToBuffer("mov %s,%s",
00744 NameOfCPURegister(*data & 0x07),
00745 NameOfAddress(addr));
00746 data += 5;
00747 break;
00748 }
00749
00750 case CALL_JUMP_INSTR: {
00751 byte* addr = data + *reinterpret_cast<int32_t*>(data+1) + 5;
00752 AppendToBuffer("%s %s", idesc.mnem, NameOfAddress(addr));
00753 data += 5;
00754 break;
00755 }
00756
00757 case SHORT_IMMEDIATE_INSTR: {
00758 byte* addr = reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data+1));
00759 AppendToBuffer("%s eax, %s", idesc.mnem, NameOfAddress(addr));
00760 data += 5;
00761 break;
00762 }
00763
00764 case NO_INSTR:
00765 processed = false;
00766 break;
00767
00768 default:
00769 UNIMPLEMENTED();
00770 }
00771
00772 if (!processed) {
00773 switch (*data) {
00774 case 0xC2:
00775 AppendToBuffer("ret 0x%x", *reinterpret_cast<uint16_t*>(data+1));
00776 data += 3;
00777 break;
00778
00779 case 0x69:
00780 case 0x6B:
00781 { int mod, regop, rm;
00782 get_modrm(*(data+1), &mod, ®op, &rm);
00783 int32_t imm =
00784 *data == 0x6B ? *(data+2) : *reinterpret_cast<int32_t*>(data+2);
00785 AppendToBuffer("imul %s,%s,0x%x",
00786 NameOfCPURegister(regop),
00787 NameOfCPURegister(rm),
00788 imm);
00789 data += 2 + (*data == 0x6B ? 1 : 4);
00790 }
00791 break;
00792
00793 case 0xF6:
00794 { int mod, regop, rm;
00795 get_modrm(*(data+1), &mod, ®op, &rm);
00796 if (mod == 3 && regop == eax) {
00797 AppendToBuffer("test_b %s,%d", NameOfCPURegister(rm), *(data+2));
00798 } else {
00799 UnimplementedInstruction();
00800 }
00801 data += 3;
00802 }
00803 break;
00804
00805 case 0x81:
00806 case 0x83:
00807 data += PrintImmediateOp(data);
00808 break;
00809
00810 case 0x0F:
00811 { byte f0byte = *(data+1);
00812 const char* f0mnem = F0Mnem(f0byte);
00813 if (f0byte == 0xA2 || f0byte == 0x31) {
00814 AppendToBuffer("%s", f0mnem);
00815 data += 2;
00816 } else if ((f0byte & 0xF0) == 0x80) {
00817 data += JumpConditional(data, branch_hint);
00818 } else if (f0byte == 0xBE || f0byte == 0xBF || f0byte == 0xB6 ||
00819 f0byte == 0xB7 || f0byte == 0xAF) {
00820 data += 2;
00821 data += PrintOperands(f0mnem, REG_OPER_OP_ORDER, data);
00822 } else {
00823 data += 2;
00824 if (f0byte == 0xAB || f0byte == 0xA5 || f0byte == 0xAD) {
00825
00826 AppendToBuffer("%s ", f0mnem);
00827 int mod, regop, rm;
00828 get_modrm(*data, &mod, ®op, &rm);
00829 data += PrintRightOperand(data);
00830 if (f0byte == 0xAB) {
00831 AppendToBuffer(",%s", NameOfCPURegister(regop));
00832 } else {
00833 AppendToBuffer(",%s,cl", NameOfCPURegister(regop));
00834 }
00835 } else {
00836 UnimplementedInstruction();
00837 }
00838 }
00839 }
00840 break;
00841
00842 case 0x8F:
00843 { data++;
00844 int mod, regop, rm;
00845 get_modrm(*data, &mod, ®op, &rm);
00846 if (regop == eax) {
00847 AppendToBuffer("pop ");
00848 data += PrintRightOperand(data);
00849 }
00850 }
00851 break;
00852
00853 case 0xFF:
00854 { data++;
00855 int mod, regop, rm;
00856 get_modrm(*data, &mod, ®op, &rm);
00857 const char* mnem = NULL;
00858 switch (regop) {
00859 case esi: mnem = "push"; break;
00860 case eax: mnem = "inc"; break;
00861 case edx: mnem = "call"; break;
00862 case esp: mnem = "jmp"; break;
00863 default: mnem = "???";
00864 }
00865 AppendToBuffer("%s ", mnem);
00866 data += PrintRightOperand(data);
00867 }
00868 break;
00869
00870 case 0xC7:
00871 case 0xC6:
00872 { bool is_byte = *data == 0xC6;
00873 data++;
00874 AppendToBuffer("%s ", is_byte ? "mov_b" : "mov");
00875 data += PrintRightOperand(data);
00876 int32_t imm = is_byte ? *data : *reinterpret_cast<int32_t*>(data);
00877 AppendToBuffer(",0x%x", imm);
00878 data += is_byte ? 1 : 4;
00879 }
00880 break;
00881
00882 case 0x88:
00883 case 0x89:
00884 { bool is_byte = *data == 0x88;
00885 int mod, regop, rm;
00886 data++;
00887 get_modrm(*data, &mod, ®op, &rm);
00888 AppendToBuffer("%s ", is_byte ? "mov_b" : "mov");
00889 data += PrintRightOperand(data);
00890 AppendToBuffer(",%s", NameOfCPURegister(regop));
00891 }
00892 break;
00893
00894 case 0x66:
00895 data++;
00896 if (*data == 0x8B) {
00897 data++;
00898 data += PrintOperands("mov_w", REG_OPER_OP_ORDER, data);
00899 } else if (*data == 0x89) {
00900 data++;
00901 int mod, regop, rm;
00902 get_modrm(*data, &mod, ®op, &rm);
00903 AppendToBuffer("mov_w ");
00904 data += PrintRightOperand(data);
00905 AppendToBuffer(",%s", NameOfCPURegister(regop));
00906 } else {
00907 UnimplementedInstruction();
00908 }
00909 break;
00910
00911 case 0xFE:
00912 { data++;
00913 int mod, regop, rm;
00914 get_modrm(*data, &mod, ®op, &rm);
00915 if (mod == 3 && regop == ecx) {
00916 AppendToBuffer("dec_b %s", NameOfCPURegister(rm));
00917 } else {
00918 UnimplementedInstruction();
00919 }
00920 data++;
00921 }
00922 break;
00923
00924 case 0x68:
00925 AppendToBuffer("push 0x%x", *reinterpret_cast<int32_t*>(data+1));
00926 data += 5;
00927 break;
00928
00929 case 0x6A:
00930 AppendToBuffer("push 0x%x", *reinterpret_cast<int8_t*>(data + 1));
00931 data += 2;
00932 break;
00933
00934 case 0xA8:
00935 AppendToBuffer("test al,0x%x", *reinterpret_cast<uint8_t*>(data+1));
00936 data += 2;
00937 break;
00938
00939 case 0xA9:
00940 AppendToBuffer("test eax,0x%x", *reinterpret_cast<int32_t*>(data+1));
00941 data += 5;
00942 break;
00943
00944 case 0xD1:
00945 case 0xD3:
00946 case 0xC1:
00947 data += D1D3C1Instruction(data);
00948 break;
00949
00950 case 0xD9:
00951 case 0xDA:
00952 case 0xDB:
00953 case 0xDC:
00954 case 0xDD:
00955 case 0xDE:
00956 case 0xDF:
00957 data += FPUInstruction(data);
00958 break;
00959
00960 case 0xEB:
00961 data += JumpShort(data);
00962 break;
00963
00964 case 0xF2:
00965 if (*(data+1) == 0x0F) {
00966 byte b2 = *(data+2);
00967 if (b2 == 0x11) {
00968 AppendToBuffer("movsd ");
00969 data += 3;
00970 int mod, regop, rm;
00971 get_modrm(*data, &mod, ®op, &rm);
00972 data += PrintRightOperand(data);
00973 AppendToBuffer(",%s", NameOfXMMRegister(regop));
00974 } else if (b2 == 0x10) {
00975 data += 3;
00976 int mod, regop, rm;
00977 get_modrm(*data, &mod, ®op, &rm);
00978 AppendToBuffer("movsd %s,", NameOfXMMRegister(regop));
00979 data += PrintRightOperand(data);
00980 } else {
00981 const char* mnem = "?";
00982 switch (b2) {
00983 case 0x2A: mnem = "cvtsi2sd"; break;
00984 case 0x58: mnem = "addsd"; break;
00985 case 0x59: mnem = "mulsd"; break;
00986 case 0x5C: mnem = "subsd"; break;
00987 case 0x5E: mnem = "divsd"; break;
00988 }
00989 data += 3;
00990 int mod, regop, rm;
00991 get_modrm(*data, &mod, ®op, &rm);
00992 if (b2 == 0x2A) {
00993 AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
00994 data += PrintRightOperand(data);
00995 } else {
00996 AppendToBuffer("%s %s,%s",
00997 mnem,
00998 NameOfXMMRegister(regop),
00999 NameOfXMMRegister(rm));
01000 data++;
01001 }
01002 }
01003 } else {
01004 UnimplementedInstruction();
01005 }
01006 break;
01007
01008 case 0xF3:
01009 if (*(data+1) == 0x0F && *(data+2) == 0x2C) {
01010 data += 3;
01011 data += PrintOperands("cvttss2si", REG_OPER_OP_ORDER, data);
01012 } else {
01013 UnimplementedInstruction();
01014 }
01015 break;
01016
01017 case 0xF7:
01018 data += F7Instruction(data);
01019 break;
01020
01021 default:
01022 UnimplementedInstruction();
01023 }
01024 }
01025
01026 if (tmp_buffer_pos_ < sizeof tmp_buffer_) {
01027 tmp_buffer_[tmp_buffer_pos_] = '\0';
01028 }
01029
01030 int instr_len = data - instr;
01031 ASSERT(instr_len > 0);
01032
01033 int outp = 0;
01034
01035 for (byte* bp = instr; bp < data; bp++) {
01036 outp += v8::internal::OS::SNPrintF(out_buffer + outp,
01037 "%02x",
01038 *bp);
01039 }
01040 for (int i = 6 - instr_len; i >= 0; i--) {
01041 outp += v8::internal::OS::SNPrintF(out_buffer + outp,
01042 " ");
01043 }
01044
01045 outp += v8::internal::OS::SNPrintF(out_buffer + outp,
01046 " %s",
01047 tmp_buffer_.start());
01048 return instr_len;
01049 }
01050
01051
01052
01053
01054
01055 static const char* cpu_regs[8] = {
01056 "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi",
01057 };
01058
01059
01060 static const char* xmm_regs[8] = {
01061 "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7",
01062 };
01063
01064
01065 const char* NameConverter::NameOfAddress(byte* addr) const {
01066 static v8::internal::EmbeddedVector<char, 32> tmp_buffer;
01067 v8::internal::OS::SNPrintF(tmp_buffer, "%p", addr);
01068 return tmp_buffer.start();
01069 }
01070
01071
01072 const char* NameConverter::NameOfConstant(byte* addr) const {
01073 return NameOfAddress(addr);
01074 }
01075
01076
01077 const char* NameConverter::NameOfCPURegister(int reg) const {
01078 if (0 <= reg && reg < 8) return cpu_regs[reg];
01079 return "noreg";
01080 }
01081
01082
01083 const char* NameConverter::NameOfXMMRegister(int reg) const {
01084 if (0 <= reg && reg < 8) return xmm_regs[reg];
01085 return "noxmmreg";
01086 }
01087
01088
01089 const char* NameConverter::NameInCode(byte* addr) const {
01090
01091 UNREACHABLE();
01092 return "";
01093 }
01094
01095
01096
01097
01098 static NameConverter defaultConverter;
01099
01100 Disassembler::Disassembler() : converter_(defaultConverter) {}
01101
01102
01103 Disassembler::Disassembler(const NameConverter& converter)
01104 : converter_(converter) {}
01105
01106
01107 Disassembler::~Disassembler() {}
01108
01109
01110 int Disassembler::InstructionDecode(v8::internal::Vector<char> buffer,
01111 byte* instruction) {
01112 DisassemblerIA32 d(converter_, false );
01113 return d.InstructionDecode(buffer, instruction);
01114 }
01115
01116
01117
01118 int Disassembler::ConstantPoolSizeAt(byte* instruction) { return -1; }
01119
01120
01121 void Disassembler::Disassemble(FILE* f, byte* begin, byte* end) {
01122 Disassembler d;
01123 for (byte* pc = begin; pc < end;) {
01124 v8::internal::EmbeddedVector<char, 128> buffer;
01125 buffer[0] = '\0';
01126 byte* prev_pc = pc;
01127 pc += d.InstructionDecode(buffer, pc);
01128 fprintf(f, "%p", prev_pc);
01129 fprintf(f, " ");
01130
01131 for (byte* bp = prev_pc; bp < pc; bp++) {
01132 fprintf(f, "%02x", *bp);
01133 }
01134 for (int i = 6 - (pc - prev_pc); i >= 0; i--) {
01135 fprintf(f, " ");
01136 }
01137 fprintf(f, " %s\n", buffer.start());
01138 }
01139 }
01140
01141
01142 }