| OLD | NEW |
| 1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 // A Disassembler object is used to disassemble a block of code instruction by | 5 // A Disassembler object is used to disassemble a block of code instruction by |
| 6 // instruction. The default implementation of the NameConverter object can be | 6 // instruction. The default implementation of the NameConverter object can be |
| 7 // overriden to modify register names or to do symbol lookup on addresses. | 7 // overriden to modify register names or to do symbol lookup on addresses. |
| 8 // | 8 // |
| 9 // The example below will disassemble a block of code and print it to stdout. | 9 // The example below will disassemble a block of code and print it to stdout. |
| 10 // | 10 // |
| (...skipping 281 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 292 svc); | 292 svc); |
| 293 } | 293 } |
| 294 return; | 294 return; |
| 295 } | 295 } |
| 296 } | 296 } |
| 297 | 297 |
| 298 | 298 |
| 299 // Handle all register based formatting in this function to reduce the | 299 // Handle all register based formatting in this function to reduce the |
| 300 // complexity of FormatOption. | 300 // complexity of FormatOption. |
| 301 int Decoder::FormatRegister(Instruction* instr, const char* format) { | 301 int Decoder::FormatRegister(Instruction* instr, const char* format) { |
| 302 ASSERT(format[0] == 'r'); | 302 DCHECK(format[0] == 'r'); |
| 303 if (format[1] == 'n') { // 'rn: Rn register | 303 if (format[1] == 'n') { // 'rn: Rn register |
| 304 int reg = instr->RnValue(); | 304 int reg = instr->RnValue(); |
| 305 PrintRegister(reg); | 305 PrintRegister(reg); |
| 306 return 2; | 306 return 2; |
| 307 } else if (format[1] == 'd') { // 'rd: Rd register | 307 } else if (format[1] == 'd') { // 'rd: Rd register |
| 308 int reg = instr->RdValue(); | 308 int reg = instr->RdValue(); |
| 309 PrintRegister(reg); | 309 PrintRegister(reg); |
| 310 return 2; | 310 return 2; |
| 311 } else if (format[1] == 's') { // 'rs: Rs register | 311 } else if (format[1] == 's') { // 'rs: Rs register |
| 312 int reg = instr->RsValue(); | 312 int reg = instr->RsValue(); |
| 313 PrintRegister(reg); | 313 PrintRegister(reg); |
| 314 return 2; | 314 return 2; |
| 315 } else if (format[1] == 'm') { // 'rm: Rm register | 315 } else if (format[1] == 'm') { // 'rm: Rm register |
| 316 int reg = instr->RmValue(); | 316 int reg = instr->RmValue(); |
| 317 PrintRegister(reg); | 317 PrintRegister(reg); |
| 318 return 2; | 318 return 2; |
| 319 } else if (format[1] == 't') { // 'rt: Rt register | 319 } else if (format[1] == 't') { // 'rt: Rt register |
| 320 int reg = instr->RtValue(); | 320 int reg = instr->RtValue(); |
| 321 PrintRegister(reg); | 321 PrintRegister(reg); |
| 322 return 2; | 322 return 2; |
| 323 } else if (format[1] == 'l') { | 323 } else if (format[1] == 'l') { |
| 324 // 'rlist: register list for load and store multiple instructions | 324 // 'rlist: register list for load and store multiple instructions |
| 325 ASSERT(STRING_STARTS_WITH(format, "rlist")); | 325 DCHECK(STRING_STARTS_WITH(format, "rlist")); |
| 326 int rlist = instr->RlistValue(); | 326 int rlist = instr->RlistValue(); |
| 327 int reg = 0; | 327 int reg = 0; |
| 328 Print("{"); | 328 Print("{"); |
| 329 // Print register list in ascending order, by scanning the bit mask. | 329 // Print register list in ascending order, by scanning the bit mask. |
| 330 while (rlist != 0) { | 330 while (rlist != 0) { |
| 331 if ((rlist & 1) != 0) { | 331 if ((rlist & 1) != 0) { |
| 332 PrintRegister(reg); | 332 PrintRegister(reg); |
| 333 if ((rlist >> 1) != 0) { | 333 if ((rlist >> 1) != 0) { |
| 334 Print(", "); | 334 Print(", "); |
| 335 } | 335 } |
| 336 } | 336 } |
| 337 reg++; | 337 reg++; |
| 338 rlist >>= 1; | 338 rlist >>= 1; |
| 339 } | 339 } |
| 340 Print("}"); | 340 Print("}"); |
| 341 return 5; | 341 return 5; |
| 342 } | 342 } |
| 343 UNREACHABLE(); | 343 UNREACHABLE(); |
| 344 return -1; | 344 return -1; |
| 345 } | 345 } |
| 346 | 346 |
| 347 | 347 |
| 348 // Handle all VFP register based formatting in this function to reduce the | 348 // Handle all VFP register based formatting in this function to reduce the |
| 349 // complexity of FormatOption. | 349 // complexity of FormatOption. |
| 350 int Decoder::FormatVFPRegister(Instruction* instr, const char* format) { | 350 int Decoder::FormatVFPRegister(Instruction* instr, const char* format) { |
| 351 ASSERT((format[0] == 'S') || (format[0] == 'D')); | 351 DCHECK((format[0] == 'S') || (format[0] == 'D')); |
| 352 | 352 |
| 353 VFPRegPrecision precision = | 353 VFPRegPrecision precision = |
| 354 format[0] == 'D' ? kDoublePrecision : kSinglePrecision; | 354 format[0] == 'D' ? kDoublePrecision : kSinglePrecision; |
| 355 | 355 |
| 356 int retval = 2; | 356 int retval = 2; |
| 357 int reg = -1; | 357 int reg = -1; |
| 358 if (format[1] == 'n') { | 358 if (format[1] == 'n') { |
| 359 reg = instr->VFPNRegValue(precision); | 359 reg = instr->VFPNRegValue(precision); |
| 360 } else if (format[1] == 'm') { | 360 } else if (format[1] == 'm') { |
| 361 reg = instr->VFPMRegValue(precision); | 361 reg = instr->VFPMRegValue(precision); |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 455 } | 455 } |
| 456 return 1; | 456 return 1; |
| 457 } | 457 } |
| 458 case 'b': { // 'b: byte loads or stores | 458 case 'b': { // 'b: byte loads or stores |
| 459 if (instr->HasB()) { | 459 if (instr->HasB()) { |
| 460 Print("b"); | 460 Print("b"); |
| 461 } | 461 } |
| 462 return 1; | 462 return 1; |
| 463 } | 463 } |
| 464 case 'c': { // 'cond: conditional execution | 464 case 'c': { // 'cond: conditional execution |
| 465 ASSERT(STRING_STARTS_WITH(format, "cond")); | 465 DCHECK(STRING_STARTS_WITH(format, "cond")); |
| 466 PrintCondition(instr); | 466 PrintCondition(instr); |
| 467 return 4; | 467 return 4; |
| 468 } | 468 } |
| 469 case 'd': { // 'd: vmov double immediate. | 469 case 'd': { // 'd: vmov double immediate. |
| 470 double d = instr->DoubleImmedVmov(); | 470 double d = instr->DoubleImmedVmov(); |
| 471 out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "#%g", d); | 471 out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "#%g", d); |
| 472 return 1; | 472 return 1; |
| 473 } | 473 } |
| 474 case 'f': { // 'f: bitfield instructions - v7 and above. | 474 case 'f': { // 'f: bitfield instructions - v7 and above. |
| 475 uint32_t lsbit = instr->Bits(11, 7); | 475 uint32_t lsbit = instr->Bits(11, 7); |
| 476 uint32_t width = instr->Bits(20, 16) + 1; | 476 uint32_t width = instr->Bits(20, 16) + 1; |
| 477 if (instr->Bit(21) == 0) { | 477 if (instr->Bit(21) == 0) { |
| 478 // BFC/BFI: | 478 // BFC/BFI: |
| 479 // Bits 20-16 represent most-significant bit. Covert to width. | 479 // Bits 20-16 represent most-significant bit. Covert to width. |
| 480 width -= lsbit; | 480 width -= lsbit; |
| 481 ASSERT(width > 0); | 481 DCHECK(width > 0); |
| 482 } | 482 } |
| 483 ASSERT((width + lsbit) <= 32); | 483 DCHECK((width + lsbit) <= 32); |
| 484 out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, | 484 out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, |
| 485 "#%d, #%d", lsbit, width); | 485 "#%d, #%d", lsbit, width); |
| 486 return 1; | 486 return 1; |
| 487 } | 487 } |
| 488 case 'h': { // 'h: halfword operation for extra loads and stores | 488 case 'h': { // 'h: halfword operation for extra loads and stores |
| 489 if (instr->HasH()) { | 489 if (instr->HasH()) { |
| 490 Print("h"); | 490 Print("h"); |
| 491 } else { | 491 } else { |
| 492 Print("b"); | 492 Print("b"); |
| 493 } | 493 } |
| 494 return 1; | 494 return 1; |
| 495 } | 495 } |
| 496 case 'i': { // 'i: immediate value from adjacent bits. | 496 case 'i': { // 'i: immediate value from adjacent bits. |
| 497 // Expects tokens in the form imm%02d@%02d, i.e. imm05@07, imm10@16 | 497 // Expects tokens in the form imm%02d@%02d, i.e. imm05@07, imm10@16 |
| 498 int width = (format[3] - '0') * 10 + (format[4] - '0'); | 498 int width = (format[3] - '0') * 10 + (format[4] - '0'); |
| 499 int lsb = (format[6] - '0') * 10 + (format[7] - '0'); | 499 int lsb = (format[6] - '0') * 10 + (format[7] - '0'); |
| 500 | 500 |
| 501 ASSERT((width >= 1) && (width <= 32)); | 501 DCHECK((width >= 1) && (width <= 32)); |
| 502 ASSERT((lsb >= 0) && (lsb <= 31)); | 502 DCHECK((lsb >= 0) && (lsb <= 31)); |
| 503 ASSERT((width + lsb) <= 32); | 503 DCHECK((width + lsb) <= 32); |
| 504 | 504 |
| 505 out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, | 505 out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, |
| 506 "%d", | 506 "%d", |
| 507 instr->Bits(width + lsb - 1, lsb)); | 507 instr->Bits(width + lsb - 1, lsb)); |
| 508 return 8; | 508 return 8; |
| 509 } | 509 } |
| 510 case 'l': { // 'l: branch and link | 510 case 'l': { // 'l: branch and link |
| 511 if (instr->HasLink()) { | 511 if (instr->HasLink()) { |
| 512 Print("l"); | 512 Print("l"); |
| 513 } | 513 } |
| 514 return 1; | 514 return 1; |
| 515 } | 515 } |
| 516 case 'm': { | 516 case 'm': { |
| 517 if (format[1] == 'w') { | 517 if (format[1] == 'w') { |
| 518 // 'mw: movt/movw instructions. | 518 // 'mw: movt/movw instructions. |
| 519 PrintMovwMovt(instr); | 519 PrintMovwMovt(instr); |
| 520 return 2; | 520 return 2; |
| 521 } | 521 } |
| 522 if (format[1] == 'e') { // 'memop: load/store instructions. | 522 if (format[1] == 'e') { // 'memop: load/store instructions. |
| 523 ASSERT(STRING_STARTS_WITH(format, "memop")); | 523 DCHECK(STRING_STARTS_WITH(format, "memop")); |
| 524 if (instr->HasL()) { | 524 if (instr->HasL()) { |
| 525 Print("ldr"); | 525 Print("ldr"); |
| 526 } else { | 526 } else { |
| 527 if ((instr->Bits(27, 25) == 0) && (instr->Bit(20) == 0) && | 527 if ((instr->Bits(27, 25) == 0) && (instr->Bit(20) == 0) && |
| 528 (instr->Bits(7, 6) == 3) && (instr->Bit(4) == 1)) { | 528 (instr->Bits(7, 6) == 3) && (instr->Bit(4) == 1)) { |
| 529 if (instr->Bit(5) == 1) { | 529 if (instr->Bit(5) == 1) { |
| 530 Print("strd"); | 530 Print("strd"); |
| 531 } else { | 531 } else { |
| 532 Print("ldrd"); | 532 Print("ldrd"); |
| 533 } | 533 } |
| 534 return 5; | 534 return 5; |
| 535 } | 535 } |
| 536 Print("str"); | 536 Print("str"); |
| 537 } | 537 } |
| 538 return 5; | 538 return 5; |
| 539 } | 539 } |
| 540 // 'msg: for simulator break instructions | 540 // 'msg: for simulator break instructions |
| 541 ASSERT(STRING_STARTS_WITH(format, "msg")); | 541 DCHECK(STRING_STARTS_WITH(format, "msg")); |
| 542 byte* str = | 542 byte* str = |
| 543 reinterpret_cast<byte*>(instr->InstructionBits() & 0x0fffffff); | 543 reinterpret_cast<byte*>(instr->InstructionBits() & 0x0fffffff); |
| 544 out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, | 544 out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, |
| 545 "%s", converter_.NameInCode(str)); | 545 "%s", converter_.NameInCode(str)); |
| 546 return 3; | 546 return 3; |
| 547 } | 547 } |
| 548 case 'o': { | 548 case 'o': { |
| 549 if ((format[3] == '1') && (format[4] == '2')) { | 549 if ((format[3] == '1') && (format[4] == '2')) { |
| 550 // 'off12: 12-bit offset for load and store instructions | 550 // 'off12: 12-bit offset for load and store instructions |
| 551 ASSERT(STRING_STARTS_WITH(format, "off12")); | 551 DCHECK(STRING_STARTS_WITH(format, "off12")); |
| 552 out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, | 552 out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, |
| 553 "%d", instr->Offset12Value()); | 553 "%d", instr->Offset12Value()); |
| 554 return 5; | 554 return 5; |
| 555 } else if (format[3] == '0') { | 555 } else if (format[3] == '0') { |
| 556 // 'off0to3and8to19 16-bit immediate encoded in bits 19-8 and 3-0. | 556 // 'off0to3and8to19 16-bit immediate encoded in bits 19-8 and 3-0. |
| 557 ASSERT(STRING_STARTS_WITH(format, "off0to3and8to19")); | 557 DCHECK(STRING_STARTS_WITH(format, "off0to3and8to19")); |
| 558 out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, | 558 out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, |
| 559 "%d", | 559 "%d", |
| 560 (instr->Bits(19, 8) << 4) + | 560 (instr->Bits(19, 8) << 4) + |
| 561 instr->Bits(3, 0)); | 561 instr->Bits(3, 0)); |
| 562 return 15; | 562 return 15; |
| 563 } | 563 } |
| 564 // 'off8: 8-bit offset for extra load and store instructions | 564 // 'off8: 8-bit offset for extra load and store instructions |
| 565 ASSERT(STRING_STARTS_WITH(format, "off8")); | 565 DCHECK(STRING_STARTS_WITH(format, "off8")); |
| 566 int offs8 = (instr->ImmedHValue() << 4) | instr->ImmedLValue(); | 566 int offs8 = (instr->ImmedHValue() << 4) | instr->ImmedLValue(); |
| 567 out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", offs8); | 567 out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, "%d", offs8); |
| 568 return 4; | 568 return 4; |
| 569 } | 569 } |
| 570 case 'p': { // 'pu: P and U bits for load and store instructions | 570 case 'p': { // 'pu: P and U bits for load and store instructions |
| 571 ASSERT(STRING_STARTS_WITH(format, "pu")); | 571 DCHECK(STRING_STARTS_WITH(format, "pu")); |
| 572 PrintPU(instr); | 572 PrintPU(instr); |
| 573 return 2; | 573 return 2; |
| 574 } | 574 } |
| 575 case 'r': { | 575 case 'r': { |
| 576 return FormatRegister(instr, format); | 576 return FormatRegister(instr, format); |
| 577 } | 577 } |
| 578 case 's': { | 578 case 's': { |
| 579 if (format[1] == 'h') { // 'shift_op or 'shift_rm or 'shift_sat. | 579 if (format[1] == 'h') { // 'shift_op or 'shift_rm or 'shift_sat. |
| 580 if (format[6] == 'o') { // 'shift_op | 580 if (format[6] == 'o') { // 'shift_op |
| 581 ASSERT(STRING_STARTS_WITH(format, "shift_op")); | 581 DCHECK(STRING_STARTS_WITH(format, "shift_op")); |
| 582 if (instr->TypeValue() == 0) { | 582 if (instr->TypeValue() == 0) { |
| 583 PrintShiftRm(instr); | 583 PrintShiftRm(instr); |
| 584 } else { | 584 } else { |
| 585 ASSERT(instr->TypeValue() == 1); | 585 DCHECK(instr->TypeValue() == 1); |
| 586 PrintShiftImm(instr); | 586 PrintShiftImm(instr); |
| 587 } | 587 } |
| 588 return 8; | 588 return 8; |
| 589 } else if (format[6] == 's') { // 'shift_sat. | 589 } else if (format[6] == 's') { // 'shift_sat. |
| 590 ASSERT(STRING_STARTS_WITH(format, "shift_sat")); | 590 DCHECK(STRING_STARTS_WITH(format, "shift_sat")); |
| 591 PrintShiftSat(instr); | 591 PrintShiftSat(instr); |
| 592 return 9; | 592 return 9; |
| 593 } else { // 'shift_rm | 593 } else { // 'shift_rm |
| 594 ASSERT(STRING_STARTS_WITH(format, "shift_rm")); | 594 DCHECK(STRING_STARTS_WITH(format, "shift_rm")); |
| 595 PrintShiftRm(instr); | 595 PrintShiftRm(instr); |
| 596 return 8; | 596 return 8; |
| 597 } | 597 } |
| 598 } else if (format[1] == 'v') { // 'svc | 598 } else if (format[1] == 'v') { // 'svc |
| 599 ASSERT(STRING_STARTS_WITH(format, "svc")); | 599 DCHECK(STRING_STARTS_WITH(format, "svc")); |
| 600 PrintSoftwareInterrupt(instr->SvcValue()); | 600 PrintSoftwareInterrupt(instr->SvcValue()); |
| 601 return 3; | 601 return 3; |
| 602 } else if (format[1] == 'i') { // 'sign: signed extra loads and stores | 602 } else if (format[1] == 'i') { // 'sign: signed extra loads and stores |
| 603 ASSERT(STRING_STARTS_WITH(format, "sign")); | 603 DCHECK(STRING_STARTS_WITH(format, "sign")); |
| 604 if (instr->HasSign()) { | 604 if (instr->HasSign()) { |
| 605 Print("s"); | 605 Print("s"); |
| 606 } | 606 } |
| 607 return 4; | 607 return 4; |
| 608 } | 608 } |
| 609 // 's: S field of data processing instructions | 609 // 's: S field of data processing instructions |
| 610 if (instr->HasS()) { | 610 if (instr->HasS()) { |
| 611 Print("s"); | 611 Print("s"); |
| 612 } | 612 } |
| 613 return 1; | 613 return 1; |
| 614 } | 614 } |
| 615 case 't': { // 'target: target of branch instructions | 615 case 't': { // 'target: target of branch instructions |
| 616 ASSERT(STRING_STARTS_WITH(format, "target")); | 616 DCHECK(STRING_STARTS_WITH(format, "target")); |
| 617 int off = (instr->SImmed24Value() << 2) + 8; | 617 int off = (instr->SImmed24Value() << 2) + 8; |
| 618 out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, | 618 out_buffer_pos_ += SNPrintF(out_buffer_ + out_buffer_pos_, |
| 619 "%+d -> %s", | 619 "%+d -> %s", |
| 620 off, | 620 off, |
| 621 converter_.NameOfAddress( | 621 converter_.NameOfAddress( |
| 622 reinterpret_cast<byte*>(instr) + off)); | 622 reinterpret_cast<byte*>(instr) + off)); |
| 623 return 6; | 623 return 6; |
| 624 } | 624 } |
| 625 case 'u': { // 'u: signed or unsigned multiplies | 625 case 'u': { // 'u: signed or unsigned multiplies |
| 626 // The manual gets the meaning of bit 22 backwards in the multiply | 626 // The manual gets the meaning of bit 22 backwards in the multiply |
| (...skipping 1154 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1781 v8::internal::PrintF( | 1781 v8::internal::PrintF( |
| 1782 f, "%p %08x %s\n", | 1782 f, "%p %08x %s\n", |
| 1783 prev_pc, *reinterpret_cast<int32_t*>(prev_pc), buffer.start()); | 1783 prev_pc, *reinterpret_cast<int32_t*>(prev_pc), buffer.start()); |
| 1784 } | 1784 } |
| 1785 } | 1785 } |
| 1786 | 1786 |
| 1787 | 1787 |
| 1788 } // namespace disasm | 1788 } // namespace disasm |
| 1789 | 1789 |
| 1790 #endif // V8_TARGET_ARCH_ARM | 1790 #endif // V8_TARGET_ARCH_ARM |
| OLD | NEW |