| OLD | NEW |
| 1 // Copyright 2007-2008 the V8 project authors. All rights reserved. | 1 // Copyright 2007-2008 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 109 | 109 |
| 110 | 110 |
| 111 static const char* jump_conditional_mnem[] = { | 111 static const char* jump_conditional_mnem[] = { |
| 112 /*0*/ "jo", "jno", "jc", "jnc", | 112 /*0*/ "jo", "jno", "jc", "jnc", |
| 113 /*4*/ "jz", "jnz", "jna", "ja", | 113 /*4*/ "jz", "jnz", "jna", "ja", |
| 114 /*8*/ "js", "jns", "jpe", "jpo", | 114 /*8*/ "js", "jns", "jpe", "jpo", |
| 115 /*12*/ "jl", "jnl", "jng", "jg" | 115 /*12*/ "jl", "jnl", "jng", "jg" |
| 116 }; | 116 }; |
| 117 | 117 |
| 118 | 118 |
| 119 static const char* set_conditional_mnem[] = { |
| 120 /*0*/ "seto", "setno", "setc", "setnc", |
| 121 /*4*/ "setz", "setnz", "setna", "seta", |
| 122 /*8*/ "sets", "setns", "setpe", "setpo", |
| 123 /*12*/ "setl", "setnl", "setng", "setg" |
| 124 }; |
| 125 |
| 126 |
| 119 enum InstructionType { | 127 enum InstructionType { |
| 120 NO_INSTR, | 128 NO_INSTR, |
| 121 ZERO_OPERANDS_INSTR, | 129 ZERO_OPERANDS_INSTR, |
| 122 TWO_OPERANDS_INSTR, | 130 TWO_OPERANDS_INSTR, |
| 123 JUMP_CONDITIONAL_SHORT_INSTR, | 131 JUMP_CONDITIONAL_SHORT_INSTR, |
| 124 REGISTER_INSTR, | 132 REGISTER_INSTR, |
| 125 MOVE_REG_INSTR, | 133 MOVE_REG_INSTR, |
| 126 CALL_JUMP_INSTR, | 134 CALL_JUMP_INSTR, |
| 127 SHORT_IMMEDIATE_INSTR | 135 SHORT_IMMEDIATE_INSTR |
| 128 }; | 136 }; |
| (...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 254 esi = 6, | 262 esi = 6, |
| 255 edi = 7 | 263 edi = 7 |
| 256 }; | 264 }; |
| 257 | 265 |
| 258 | 266 |
| 259 const char* NameOfCPURegister(int reg) const { | 267 const char* NameOfCPURegister(int reg) const { |
| 260 return converter_.NameOfCPURegister(reg); | 268 return converter_.NameOfCPURegister(reg); |
| 261 } | 269 } |
| 262 | 270 |
| 263 | 271 |
| 272 const char* NameOfByteCPURegister(int reg) const { |
| 273 return converter_.NameOfByteCPURegister(reg); |
| 274 } |
| 275 |
| 276 |
| 264 const char* NameOfXMMRegister(int reg) const { | 277 const char* NameOfXMMRegister(int reg) const { |
| 265 return converter_.NameOfXMMRegister(reg); | 278 return converter_.NameOfXMMRegister(reg); |
| 266 } | 279 } |
| 267 | 280 |
| 268 | 281 |
| 269 const char* NameOfAddress(byte* addr) const { | 282 const char* NameOfAddress(byte* addr) const { |
| 270 return converter_.NameOfAddress(addr); | 283 return converter_.NameOfAddress(addr); |
| 271 } | 284 } |
| 272 | 285 |
| 273 | 286 |
| 274 // Disassembler helper functions. | 287 // Disassembler helper functions. |
| 275 static void get_modrm(byte data, int* mod, int* regop, int* rm) { | 288 static void get_modrm(byte data, int* mod, int* regop, int* rm) { |
| 276 *mod = (data >> 6) & 3; | 289 *mod = (data >> 6) & 3; |
| 277 *regop = (data & 0x38) >> 3; | 290 *regop = (data & 0x38) >> 3; |
| 278 *rm = data & 7; | 291 *rm = data & 7; |
| 279 } | 292 } |
| 280 | 293 |
| 281 | 294 |
| 282 static void get_sib(byte data, int* scale, int* index, int* base) { | 295 static void get_sib(byte data, int* scale, int* index, int* base) { |
| 283 *scale = (data >> 6) & 3; | 296 *scale = (data >> 6) & 3; |
| 284 *index = (data >> 3) & 7; | 297 *index = (data >> 3) & 7; |
| 285 *base = data & 7; | 298 *base = data & 7; |
| 286 } | 299 } |
| 287 | 300 |
| 301 typedef const char* (DisassemblerIA32::*RegisterNameMapping)(int reg) const; |
| 288 | 302 |
| 303 int PrintRightOperandHelper(byte* modrmp, RegisterNameMapping register_name); |
| 289 int PrintRightOperand(byte* modrmp); | 304 int PrintRightOperand(byte* modrmp); |
| 305 int PrintRightByteOperand(byte* modrmp); |
| 290 int PrintOperands(const char* mnem, OperandOrder op_order, byte* data); | 306 int PrintOperands(const char* mnem, OperandOrder op_order, byte* data); |
| 291 int PrintImmediateOp(byte* data); | 307 int PrintImmediateOp(byte* data); |
| 292 int F7Instruction(byte* data); | 308 int F7Instruction(byte* data); |
| 293 int D1D3C1Instruction(byte* data); | 309 int D1D3C1Instruction(byte* data); |
| 294 int JumpShort(byte* data); | 310 int JumpShort(byte* data); |
| 295 int JumpConditional(byte* data, const char* comment); | 311 int JumpConditional(byte* data, const char* comment); |
| 296 int JumpConditionalShort(byte* data, const char* comment); | 312 int JumpConditionalShort(byte* data, const char* comment); |
| 297 int SetCC(byte* data); | 313 int SetCC(byte* data); |
| 298 int FPUInstruction(byte* data); | 314 int FPUInstruction(byte* data); |
| 299 void AppendToBuffer(const char* format, ...); | 315 void AppendToBuffer(const char* format, ...); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 311 | 327 |
| 312 void DisassemblerIA32::AppendToBuffer(const char* format, ...) { | 328 void DisassemblerIA32::AppendToBuffer(const char* format, ...) { |
| 313 v8::internal::Vector<char> buf = tmp_buffer_ + tmp_buffer_pos_; | 329 v8::internal::Vector<char> buf = tmp_buffer_ + tmp_buffer_pos_; |
| 314 va_list args; | 330 va_list args; |
| 315 va_start(args, format); | 331 va_start(args, format); |
| 316 int result = v8::internal::OS::VSNPrintF(buf, format, args); | 332 int result = v8::internal::OS::VSNPrintF(buf, format, args); |
| 317 va_end(args); | 333 va_end(args); |
| 318 tmp_buffer_pos_ += result; | 334 tmp_buffer_pos_ += result; |
| 319 } | 335 } |
| 320 | 336 |
| 321 | 337 int DisassemblerIA32::PrintRightOperandHelper( |
| 322 // Returns number of bytes used including the current *modrmp. | 338 byte* modrmp, |
| 323 // Writes instruction's right operand to 'tmp_buffer_'. | 339 RegisterNameMapping register_name) { |
| 324 int DisassemblerIA32::PrintRightOperand(byte* modrmp) { | |
| 325 int mod, regop, rm; | 340 int mod, regop, rm; |
| 326 get_modrm(*modrmp, &mod, ®op, &rm); | 341 get_modrm(*modrmp, &mod, ®op, &rm); |
| 327 switch (mod) { | 342 switch (mod) { |
| 328 case 0: | 343 case 0: |
| 329 if (rm == ebp) { | 344 if (rm == ebp) { |
| 330 int32_t disp = *reinterpret_cast<int32_t*>(modrmp+1); | 345 int32_t disp = *reinterpret_cast<int32_t*>(modrmp+1); |
| 331 AppendToBuffer("[0x%x]", disp); | 346 AppendToBuffer("[0x%x]", disp); |
| 332 return 5; | 347 return 5; |
| 333 } else if (rm == esp) { | 348 } else if (rm == esp) { |
| 334 byte sib = *(modrmp + 1); | 349 byte sib = *(modrmp + 1); |
| 335 int scale, index, base; | 350 int scale, index, base; |
| 336 get_sib(sib, &scale, &index, &base); | 351 get_sib(sib, &scale, &index, &base); |
| 337 if (index == esp && base == esp && scale == 0 /*times_1*/) { | 352 if (index == esp && base == esp && scale == 0 /*times_1*/) { |
| 338 AppendToBuffer("[%s]", NameOfCPURegister(rm)); | 353 AppendToBuffer("[%s]", (this->*register_name)(rm)); |
| 339 return 2; | 354 return 2; |
| 340 } else if (base == ebp) { | 355 } else if (base == ebp) { |
| 341 int32_t disp = *reinterpret_cast<int32_t*>(modrmp + 2); | 356 int32_t disp = *reinterpret_cast<int32_t*>(modrmp + 2); |
| 342 AppendToBuffer("[%s*%d+0x%x]", | 357 AppendToBuffer("[%s*%d+0x%x]", |
| 343 NameOfCPURegister(index), | 358 (this->*register_name)(index), |
| 344 1 << scale, | 359 1 << scale, |
| 345 disp); | 360 disp); |
| 346 return 6; | 361 return 6; |
| 347 } else if (index != esp && base != ebp) { | 362 } else if (index != esp && base != ebp) { |
| 348 // [base+index*scale] | 363 // [base+index*scale] |
| 349 AppendToBuffer("[%s+%s*%d]", | 364 AppendToBuffer("[%s+%s*%d]", |
| 350 NameOfCPURegister(base), | 365 (this->*register_name)(base), |
| 351 NameOfCPURegister(index), | 366 (this->*register_name)(index), |
| 352 1 << scale); | 367 1 << scale); |
| 353 return 2; | 368 return 2; |
| 354 } else { | 369 } else { |
| 355 UnimplementedInstruction(); | 370 UnimplementedInstruction(); |
| 356 return 1; | 371 return 1; |
| 357 } | 372 } |
| 358 } else { | 373 } else { |
| 359 AppendToBuffer("[%s]", NameOfCPURegister(rm)); | 374 AppendToBuffer("[%s]", (this->*register_name)(rm)); |
| 360 return 1; | 375 return 1; |
| 361 } | 376 } |
| 362 break; | 377 break; |
| 363 case 1: // fall through | 378 case 1: // fall through |
| 364 case 2: | 379 case 2: |
| 365 if (rm == esp) { | 380 if (rm == esp) { |
| 366 byte sib = *(modrmp + 1); | 381 byte sib = *(modrmp + 1); |
| 367 int scale, index, base; | 382 int scale, index, base; |
| 368 get_sib(sib, &scale, &index, &base); | 383 get_sib(sib, &scale, &index, &base); |
| 369 int disp = | 384 int disp = |
| 370 mod == 2 ? *reinterpret_cast<int32_t*>(modrmp + 2) : *(modrmp + 2); | 385 mod == 2 ? *reinterpret_cast<int32_t*>(modrmp + 2) : *(modrmp + 2); |
| 371 if (index == base && index == rm /*esp*/ && scale == 0 /*times_1*/) { | 386 if (index == base && index == rm /*esp*/ && scale == 0 /*times_1*/) { |
| 372 AppendToBuffer("[%s+0x%x]", NameOfCPURegister(rm), disp); | 387 AppendToBuffer("[%s+0x%x]", (this->*register_name)(rm), disp); |
| 373 } else { | 388 } else { |
| 374 AppendToBuffer("[%s+%s*%d+0x%x]", | 389 AppendToBuffer("[%s+%s*%d+0x%x]", |
| 375 NameOfCPURegister(base), | 390 (this->*register_name)(base), |
| 376 NameOfCPURegister(index), | 391 (this->*register_name)(index), |
| 377 1 << scale, | 392 1 << scale, |
| 378 disp); | 393 disp); |
| 379 } | 394 } |
| 380 return mod == 2 ? 6 : 3; | 395 return mod == 2 ? 6 : 3; |
| 381 } else { | 396 } else { |
| 382 // No sib. | 397 // No sib. |
| 383 int disp = | 398 int disp = |
| 384 mod == 2 ? *reinterpret_cast<int32_t*>(modrmp + 1) : *(modrmp + 1); | 399 mod == 2 ? *reinterpret_cast<int32_t*>(modrmp + 1) : *(modrmp + 1); |
| 385 AppendToBuffer("[%s+0x%x]", NameOfCPURegister(rm), disp); | 400 AppendToBuffer("[%s+0x%x]", (this->*register_name)(rm), disp); |
| 386 return mod == 2 ? 5 : 2; | 401 return mod == 2 ? 5 : 2; |
| 387 } | 402 } |
| 388 break; | 403 break; |
| 389 case 3: | 404 case 3: |
| 390 AppendToBuffer("%s", NameOfCPURegister(rm)); | 405 AppendToBuffer("%s", (this->*register_name)(rm)); |
| 391 return 1; | 406 return 1; |
| 392 default: | 407 default: |
| 393 UnimplementedInstruction(); | 408 UnimplementedInstruction(); |
| 394 return 1; | 409 return 1; |
| 395 } | 410 } |
| 396 UNREACHABLE(); | 411 UNREACHABLE(); |
| 397 } | 412 } |
| 398 | 413 |
| 399 | 414 |
| 415 int DisassemblerIA32::PrintRightOperand(byte* modrmp) { |
| 416 return PrintRightOperandHelper(modrmp, &DisassemblerIA32::NameOfCPURegister); |
| 417 } |
| 418 |
| 419 |
| 420 int DisassemblerIA32::PrintRightByteOperand(byte* modrmp) { |
| 421 return PrintRightOperandHelper(modrmp, |
| 422 &DisassemblerIA32::NameOfByteCPURegister); |
| 423 } |
| 424 |
| 425 |
| 400 // Returns number of bytes used including the current *data. | 426 // Returns number of bytes used including the current *data. |
| 401 // Writes instruction's mnemonic, left and right operands to 'tmp_buffer_'. | 427 // Writes instruction's mnemonic, left and right operands to 'tmp_buffer_'. |
| 402 int DisassemblerIA32::PrintOperands(const char* mnem, | 428 int DisassemblerIA32::PrintOperands(const char* mnem, |
| 403 OperandOrder op_order, | 429 OperandOrder op_order, |
| 404 byte* data) { | 430 byte* data) { |
| 405 byte modrm = *data; | 431 byte modrm = *data; |
| 406 int mod, regop, rm; | 432 int mod, regop, rm; |
| 407 get_modrm(modrm, &mod, ®op, &rm); | 433 get_modrm(modrm, &mod, ®op, &rm); |
| 408 int advance = 0; | 434 int advance = 0; |
| 409 switch (op_order) { | 435 switch (op_order) { |
| (...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 574 AppendToBuffer(", %s", comment); | 600 AppendToBuffer(", %s", comment); |
| 575 } | 601 } |
| 576 return 2; | 602 return 2; |
| 577 } | 603 } |
| 578 | 604 |
| 579 | 605 |
| 580 // Returns number of bytes used, including *data. | 606 // Returns number of bytes used, including *data. |
| 581 int DisassemblerIA32::SetCC(byte* data) { | 607 int DisassemblerIA32::SetCC(byte* data) { |
| 582 assert(*data == 0x0F); | 608 assert(*data == 0x0F); |
| 583 byte cond = *(data+1) & 0x0F; | 609 byte cond = *(data+1) & 0x0F; |
| 584 const char* mnem = jump_conditional_mnem[cond]; | 610 const char* mnem = set_conditional_mnem[cond]; |
| 585 AppendToBuffer("set%s ", mnem); | 611 AppendToBuffer("%s ", mnem); |
| 586 PrintRightOperand(data+2); | 612 PrintRightByteOperand(data+2); |
| 587 return 3; // includes 0x0F | 613 return 3; // includes 0x0F |
| 588 } | 614 } |
| 589 | 615 |
| 590 | 616 |
| 591 // Returns number of bytes used, including *data. | 617 // Returns number of bytes used, including *data. |
| 592 int DisassemblerIA32::FPUInstruction(byte* data) { | 618 int DisassemblerIA32::FPUInstruction(byte* data) { |
| 593 byte b1 = *data; | 619 byte b1 = *data; |
| 594 byte b2 = *(data + 1); | 620 byte b2 = *(data + 1); |
| 595 if (b1 == 0xD9) { | 621 if (b1 == 0xD9) { |
| 596 const char* mnem = NULL; | 622 const char* mnem = NULL; |
| (...skipping 465 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1062 " %s", | 1088 " %s", |
| 1063 tmp_buffer_.start()); | 1089 tmp_buffer_.start()); |
| 1064 return instr_len; | 1090 return instr_len; |
| 1065 } | 1091 } |
| 1066 | 1092 |
| 1067 | 1093 |
| 1068 //------------------------------------------------------------------------------ | 1094 //------------------------------------------------------------------------------ |
| 1069 | 1095 |
| 1070 | 1096 |
| 1071 static const char* cpu_regs[8] = { | 1097 static const char* cpu_regs[8] = { |
| 1072 "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi", | 1098 "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi" |
| 1099 }; |
| 1100 |
| 1101 |
| 1102 static const char* byte_cpu_regs[8] = { |
| 1103 "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh" |
| 1073 }; | 1104 }; |
| 1074 | 1105 |
| 1075 | 1106 |
| 1076 static const char* xmm_regs[8] = { | 1107 static const char* xmm_regs[8] = { |
| 1077 "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7", | 1108 "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7" |
| 1078 }; | 1109 }; |
| 1079 | 1110 |
| 1080 | 1111 |
| 1081 const char* NameConverter::NameOfAddress(byte* addr) const { | 1112 const char* NameConverter::NameOfAddress(byte* addr) const { |
| 1082 static v8::internal::EmbeddedVector<char, 32> tmp_buffer; | 1113 static v8::internal::EmbeddedVector<char, 32> tmp_buffer; |
| 1083 v8::internal::OS::SNPrintF(tmp_buffer, "%p", addr); | 1114 v8::internal::OS::SNPrintF(tmp_buffer, "%p", addr); |
| 1084 return tmp_buffer.start(); | 1115 return tmp_buffer.start(); |
| 1085 } | 1116 } |
| 1086 | 1117 |
| 1087 | 1118 |
| 1088 const char* NameConverter::NameOfConstant(byte* addr) const { | 1119 const char* NameConverter::NameOfConstant(byte* addr) const { |
| 1089 return NameOfAddress(addr); | 1120 return NameOfAddress(addr); |
| 1090 } | 1121 } |
| 1091 | 1122 |
| 1092 | 1123 |
| 1093 const char* NameConverter::NameOfCPURegister(int reg) const { | 1124 const char* NameConverter::NameOfCPURegister(int reg) const { |
| 1094 if (0 <= reg && reg < 8) return cpu_regs[reg]; | 1125 if (0 <= reg && reg < 8) return cpu_regs[reg]; |
| 1095 return "noreg"; | 1126 return "noreg"; |
| 1096 } | 1127 } |
| 1097 | 1128 |
| 1098 | 1129 |
| 1130 const char* NameConverter::NameOfByteCPURegister(int reg) const { |
| 1131 if (0 <= reg && reg < 8) return byte_cpu_regs[reg]; |
| 1132 return "noreg"; |
| 1133 } |
| 1134 |
| 1135 |
| 1099 const char* NameConverter::NameOfXMMRegister(int reg) const { | 1136 const char* NameConverter::NameOfXMMRegister(int reg) const { |
| 1100 if (0 <= reg && reg < 8) return xmm_regs[reg]; | 1137 if (0 <= reg && reg < 8) return xmm_regs[reg]; |
| 1101 return "noxmmreg"; | 1138 return "noxmmreg"; |
| 1102 } | 1139 } |
| 1103 | 1140 |
| 1104 | 1141 |
| 1105 const char* NameConverter::NameInCode(byte* addr) const { | 1142 const char* NameConverter::NameInCode(byte* addr) const { |
| 1106 // IA32 does not embed debug strings at the moment. | 1143 // IA32 does not embed debug strings at the moment. |
| 1107 UNREACHABLE(); | 1144 UNREACHABLE(); |
| 1108 return ""; | 1145 return ""; |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1145 } | 1182 } |
| 1146 for (int i = 6 - (pc - prev_pc); i >= 0; i--) { | 1183 for (int i = 6 - (pc - prev_pc); i >= 0; i--) { |
| 1147 fprintf(f, " "); | 1184 fprintf(f, " "); |
| 1148 } | 1185 } |
| 1149 fprintf(f, " %s\n", buffer.start()); | 1186 fprintf(f, " %s\n", buffer.start()); |
| 1150 } | 1187 } |
| 1151 } | 1188 } |
| 1152 | 1189 |
| 1153 | 1190 |
| 1154 } // namespace disasm | 1191 } // namespace disasm |
| OLD | NEW |