| Index: src/arm/disasm-arm.cc
|
| ===================================================================
|
| --- src/arm/disasm-arm.cc (revision 4001)
|
| +++ src/arm/disasm-arm.cc (working copy)
|
| @@ -89,6 +89,8 @@
|
| // Writes one disassembled instruction into 'buffer' (0-terminated).
|
| // Returns the length of the disassembled machine instruction in bytes.
|
| int InstructionDecode(byte* instruction);
|
| + int InstructionDecodeArm(byte* instruction);
|
| + int InstructionDecodeThumb2(const InstrThumb2& instr);
|
|
|
| private:
|
| // Bottleneck functions to print into the out_buffer.
|
| @@ -103,15 +105,21 @@
|
| int FormatVFPinstruction(Instr* instr, const char* format);
|
| void PrintCondition(Instr* instr);
|
| void PrintShiftRm(Instr* instr);
|
| + void PrintShiftRm(const InstrThumb2& instr);
|
| void PrintShiftImm(Instr* instr);
|
| + void PrintShiftImm(const InstrThumb2& instr);
|
| void PrintPU(Instr* instr);
|
| void PrintSoftwareInterrupt(SoftwareInterruptCodes swi);
|
|
|
| // Handle formatting of instructions and their options.
|
| int FormatRegister(Instr* instr, const char* option);
|
| + int FormatRegister(const InstrThumb2& instr, const char* option);
|
| int FormatOption(Instr* instr, const char* option);
|
| + int FormatOption(const InstrThumb2& instr, const char* option);
|
| void Format(Instr* instr, const char* format);
|
| + void Format(const InstrThumb2& instr, const char* format);
|
| void Unknown(Instr* instr);
|
| + void Unknown(const InstrThumb2& instr);
|
|
|
| // Each of these functions decodes one particular instruction type, a 3-bit
|
| // field in the instruction encoding.
|
| @@ -230,7 +238,33 @@
|
| }
|
| }
|
|
|
| +void Decoder::PrintShiftRm(const InstrThumb2& instr) {
|
| + int shift = instr.Type();
|
| + int shift_amount = instr.Imm();
|
| + int rm = instr.Rm();
|
|
|
| + PrintRegister(rm);
|
| +
|
| + if (instr.Variant() != VARIANT_REGISTER_SHIFTED_REGISTER) {
|
| + if (shift == no_shift) {
|
| + // Special case for using rm only.
|
| + return;
|
| + }
|
| + if (shift == RRX) {
|
| + Print(", RRX");
|
| + return;
|
| + }
|
| + out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_,
|
| + ", %s #%d",
|
| + shift_names[shift], shift_amount);
|
| + } else {
|
| + // TODO(haustein)
|
| + UNIMPLEMENTED();
|
| + }
|
| +}
|
| +
|
| +
|
| +
|
| // Print the immediate operand for the instruction. Generally used for data
|
| // processing instructions.
|
| void Decoder::PrintShiftImm(Instr* instr) {
|
| @@ -241,7 +275,12 @@
|
| "#%d", imm);
|
| }
|
|
|
| +void Decoder::PrintShiftImm(const InstrThumb2& instr) {
|
| + out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_,
|
| + "#%d", instr.Imm());
|
| +}
|
|
|
| +
|
| // Print PU formatting to reduce complexity of FormatOption.
|
| void Decoder::PrintPU(Instr* instr) {
|
| switch (instr->PUField()) {
|
| @@ -336,7 +375,40 @@
|
| return -1;
|
| }
|
|
|
| +int Decoder::FormatRegister(const InstrThumb2& instr, const char* format) {
|
| + ASSERT(format[0] == 'r');
|
| + if (format[1] == 'n') { // 'rn: Rn register
|
| + int reg = instr.Rn();
|
| + PrintRegister(reg);
|
| + return 2;
|
| + } else if (format[1] == 'd') { // 'rd: Rd register
|
| + int reg = instr.Rd();
|
| + PrintRegister(reg);
|
| + return 2;
|
| + } else if (format[1] == 's') { // 'rs: Rs register
|
| + int reg = instr.Rs();
|
| + PrintRegister(reg);
|
| + return 2;
|
| + } else if (format[1] == 'm') { // 'rm: Rm register
|
| + int reg = instr.Rm();
|
| + PrintRegister(reg);
|
| + return 2;
|
| + } else if (format[1] == 't') { // 'rt: Rt register
|
| + int reg = instr.Rt();
|
| + PrintRegister(reg);
|
| + return 2;
|
| + } else if (format[1] == 'l') {
|
| + // 'rlist: register list for load and store multiple instructions
|
| + ASSERT(STRING_STARTS_WITH(format, "rlist"));
|
| + // TODO(haustein)
|
| + UNIMPLEMENTED();
|
| + return 5;
|
| + }
|
| + UNREACHABLE();
|
| + return -1;
|
| +}
|
|
|
| +
|
| // Handle all VFP register based formatting in this function to reduce the
|
| // complexity of FormatOption.
|
| int Decoder::FormatVFPRegister(Instr* instr, const char* format) {
|
| @@ -546,7 +618,48 @@
|
| return -1;
|
| }
|
|
|
| +int Decoder::FormatOption(const InstrThumb2& instr, const char* format) {
|
| + switch (format[0]) {
|
| + // TODO(haustein) Add code for a, b, c, h, l, m, o, p, see ARM
|
| + case 'r': {
|
| + return FormatRegister(instr, format);
|
| + }
|
| + case 's': {
|
| + if (format[1] == 'h') { // 'shift_op or 'shift_rm
|
| + if (format[6] == 'o') { // 'shift_op
|
| + ASSERT(STRING_STARTS_WITH(format, "shift_op"));
|
| + if (instr.Type() == 0) {
|
| + PrintShiftRm(instr);
|
| + } else {
|
| + ASSERT(instr.Type() == 1);
|
| + PrintShiftImm(instr);
|
| + }
|
| + return 8;
|
| + } else { // 'shift_rm
|
| + ASSERT(STRING_STARTS_WITH(format, "shift_rm"));
|
| + PrintShiftRm(instr);
|
| + return 8;
|
| + }
|
| + // TODO(haustein) Add code for 'w', 'i', 's' here (see arm code)
|
| + }
|
| + // 's: S field of data processing instructions
|
| + if (instr.HasS()) {
|
| + Print("s");
|
| + }
|
| + return 1;
|
| + }
|
| + // TODO(haustein) Add code for 't', 'u', 'v', 'S', 'D', 'w' below,
|
| + // see arm code
|
| + default: {
|
| + UNIMPLEMENTED();
|
| + break;
|
| + }
|
| + }
|
| + UNREACHABLE();
|
| + return -1;
|
| +}
|
|
|
| +
|
| // Format takes a formatting string for a whole instruction and prints it into
|
| // the output buffer. All escaped options are handed to FormatOption to be
|
| // parsed further.
|
| @@ -564,6 +677,21 @@
|
| }
|
|
|
|
|
| +void Decoder::Format(const InstrThumb2& instr, const char* format) {
|
| + char cur = *format++;
|
| + while ((cur != 0) && (out_buffer_pos_ < (out_buffer_.length() - 1))) {
|
| + if (cur == '\'') { // Single quote is used as the formatting escape.
|
| + format += FormatOption(instr, format);
|
| + } else {
|
| + out_buffer_[out_buffer_pos_++] = cur;
|
| + }
|
| + cur = *format++;
|
| + }
|
| + out_buffer_[out_buffer_pos_] = '\0';
|
| +}
|
| +
|
| +
|
| +
|
| // For currently unimplemented decodings the disassembler calls Unknown(instr)
|
| // which will just print "unknown" of the instruction bits.
|
| void Decoder::Unknown(Instr* instr) {
|
| @@ -1062,6 +1190,15 @@
|
|
|
| // Disassemble the instruction at *instr_ptr into the output buffer.
|
| int Decoder::InstructionDecode(byte* instr_ptr) {
|
| + if (reinterpret_cast<int32_t>(instr_ptr) & 1) {
|
| + InstrThumb2 instr(instr_ptr);
|
| + return InstructionDecodeThumb2(instr);
|
| + } else {
|
| + return InstructionDecodeArm(instr_ptr);
|
| + }
|
| +}
|
| +
|
| +int Decoder::InstructionDecodeArm(byte* instr_ptr) {
|
| Instr* instr = Instr::At(instr_ptr);
|
| // Print raw instruction bytes.
|
| out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_,
|
| @@ -1111,6 +1248,25 @@
|
| }
|
|
|
|
|
| +int Decoder::InstructionDecodeThumb2(const InstrThumb2& instr) {
|
| + switch (instr.Op()) {
|
| + case OP_ADD:
|
| + Format(instr, "and's 'rd, 'rn, 'shift_op");
|
| + break;
|
| + case OP_AND:
|
| + Format(instr, "and's 'rd, 'rn, 'shift_op");
|
| + break;
|
| + case OP_SUB:
|
| + Format(instr, "sub's 'rd, 'rn, 'shift_op");
|
| + break;
|
| + default:
|
| + UNIMPLEMENTED();
|
| + break;
|
| + }
|
| + return instr.Size();
|
| +}
|
| +
|
| +
|
| } } // namespace assembler::arm
|
|
|
|
|
|
|