| Index: runtime/vm/disassembler_arm64.cc
|
| ===================================================================
|
| --- runtime/vm/disassembler_arm64.cc (revision 34992)
|
| +++ runtime/vm/disassembler_arm64.cc (working copy)
|
| @@ -34,6 +34,7 @@
|
| void PrintShiftExtendRm(Instr* instr);
|
| void PrintMemOperand(Instr* instr);
|
| void PrintS(Instr* instr);
|
| + void PrintCondition(Instr* instr);
|
|
|
| // Handle formatting of instructions and their options.
|
| int FormatRegister(Instr* instr, const char* option);
|
| @@ -115,6 +116,20 @@
|
| };
|
|
|
|
|
| +// These condition names are defined in a way to match the native disassembler
|
| +// formatting. See for example the command "objdump -d <binary file>".
|
| +static const char* cond_names[kMaxCondition] = {
|
| + "eq", "ne", "cs" , "cc" , "mi" , "pl" , "vs" , "vc" ,
|
| + "hi", "ls", "ge", "lt", "gt", "le", "", "invalid",
|
| +};
|
| +
|
| +
|
| +// Print the condition guarding the instruction.
|
| +void ARM64Decoder::PrintCondition(Instr* instr) {
|
| + Print(cond_names[instr->ConditionField()]);
|
| +}
|
| +
|
| +
|
| // Print the register shift operands for the instruction. Generally used for
|
| // data processing instructions.
|
| void ARM64Decoder::PrintShiftExtendRm(Instr* instr) {
|
| @@ -263,6 +278,71 @@
|
| // characters that were consumed from the formatting string.
|
| int ARM64Decoder::FormatOption(Instr* instr, const char* format) {
|
| switch (format[0]) {
|
| + case 'b': {
|
| + if (format[3] == 'i') {
|
| + ASSERT(STRING_STARTS_WITH(format, "bitimm"));
|
| + const uint64_t imm = instr->ImmLogical();
|
| + buffer_pos_ += OS::SNPrint(current_position_in_buffer(),
|
| + remaining_size_in_buffer(),
|
| + "0x%"Px64,
|
| + imm);
|
| + return 6;
|
| + } else {
|
| + ASSERT(STRING_STARTS_WITH(format, "bitpos"));
|
| + int bitpos = instr->Bits(19, 4) | (instr->Bit(31) << 5);
|
| + buffer_pos_ += OS::SNPrint(current_position_in_buffer(),
|
| + remaining_size_in_buffer(),
|
| + "#%d",
|
| + bitpos);
|
| + return 6;
|
| + }
|
| + }
|
| + case 'c': {
|
| + ASSERT(STRING_STARTS_WITH(format, "cond"));
|
| + PrintCondition(instr);
|
| + return 4;
|
| + }
|
| + case 'd': {
|
| + if (format[4] == '2') {
|
| + ASSERT(STRING_STARTS_WITH(format, "dest26"));
|
| + int64_t off = instr->SImm26Field() << 2;
|
| + uword destination = reinterpret_cast<uword>(instr) + off;
|
| + buffer_pos_ += OS::SNPrint(current_position_in_buffer(),
|
| + remaining_size_in_buffer(),
|
| + "%#" Px "",
|
| + destination);
|
| + } else {
|
| + if (format[5] == '4') {
|
| + ASSERT(STRING_STARTS_WITH(format, "dest14"));
|
| + int64_t off = instr->SImm14Field() << 2;
|
| + uword destination = reinterpret_cast<uword>(instr) + off;
|
| + buffer_pos_ += OS::SNPrint(current_position_in_buffer(),
|
| + remaining_size_in_buffer(),
|
| + "%#" Px "",
|
| + destination);
|
| + } else {
|
| + ASSERT(STRING_STARTS_WITH(format, "dest19"));
|
| + int64_t off = instr->SImm19Field() << 2;
|
| + uword destination = reinterpret_cast<uword>(instr) + off;
|
| + buffer_pos_ += OS::SNPrint(current_position_in_buffer(),
|
| + remaining_size_in_buffer(),
|
| + "%#" Px "",
|
| + destination);
|
| + }
|
| + }
|
| + return 6;
|
| + }
|
| + case 'h': {
|
| + ASSERT(STRING_STARTS_WITH(format, "hw"));
|
| + const int shift = instr->HWField() << 4;
|
| + if (shift != 0) {
|
| + buffer_pos_ += OS::SNPrint(current_position_in_buffer(),
|
| + remaining_size_in_buffer(),
|
| + "lsl %d",
|
| + shift);
|
| + }
|
| + return 2;
|
| + }
|
| case 'i': { // 'imm12, imm16
|
| uint64_t imm;
|
| int ret = 5;
|
| @@ -288,6 +368,27 @@
|
| imm);
|
| return ret;
|
| }
|
| + case 'm': {
|
| + ASSERT(STRING_STARTS_WITH(format, "memop"));
|
| + PrintMemOperand(instr);
|
| + return 5;
|
| + }
|
| + case 'p': {
|
| + ASSERT(STRING_STARTS_WITH(format, "pcrel"));
|
| + const int64_t immhi = instr->SImm19Field();
|
| + const int64_t immlo = instr->Bits(29, 2);
|
| + const int64_t off = (immhi << 2) | immlo;
|
| + const int64_t pc = reinterpret_cast<int64_t>(instr);
|
| + const int64_t dest = pc + off;
|
| + buffer_pos_ += OS::SNPrint(current_position_in_buffer(),
|
| + remaining_size_in_buffer(),
|
| + "0x%"Px64,
|
| + dest);
|
| + return 5;
|
| + }
|
| + case 'r': {
|
| + return FormatRegister(instr, format);
|
| + }
|
| case 's': { // 's: S flag.
|
| if (format[1] == 'h') {
|
| ASSERT(STRING_STARTS_WITH(format, "shift_op"));
|
| @@ -328,34 +429,6 @@
|
| UNREACHABLE();
|
| }
|
| }
|
| - case 'r': {
|
| - return FormatRegister(instr, format);
|
| - }
|
| - case 'h': {
|
| - ASSERT(STRING_STARTS_WITH(format, "hw"));
|
| - const int shift = instr->HWField() << 4;
|
| - if (shift != 0) {
|
| - buffer_pos_ += OS::SNPrint(current_position_in_buffer(),
|
| - remaining_size_in_buffer(),
|
| - "lsl %d",
|
| - shift);
|
| - }
|
| - return 2;
|
| - }
|
| - case 'm': {
|
| - ASSERT(STRING_STARTS_WITH(format, "memop"));
|
| - PrintMemOperand(instr);
|
| - return 5;
|
| - }
|
| - case 'b': {
|
| - ASSERT(STRING_STARTS_WITH(format, "bitimm"));
|
| - const uint64_t imm = instr->ImmLogical();
|
| - buffer_pos_ += OS::SNPrint(current_position_in_buffer(),
|
| - remaining_size_in_buffer(),
|
| - "0x%"Px64,
|
| - imm);
|
| - return 6;
|
| - }
|
| default: {
|
| UNREACHABLE();
|
| break;
|
| @@ -468,6 +541,16 @@
|
| }
|
|
|
|
|
| +void ARM64Decoder::DecodePCRel(Instr* instr) {
|
| + const int op = instr->Bit(31);
|
| + if (op == 0) {
|
| + Format(instr, "adr 'rd, 'pcrel");
|
| + } else {
|
| + Unknown(instr);
|
| + }
|
| +}
|
| +
|
| +
|
| void ARM64Decoder::DecodeDPImmediate(Instr* instr) {
|
| if (instr->IsMoveWideOp()) {
|
| DecodeMoveWide(instr);
|
| @@ -475,6 +558,8 @@
|
| DecodeAddSubImm(instr);
|
| } else if (instr->IsLogicalImmOp()) {
|
| DecodeLogicalImm(instr);
|
| + } else if (instr->IsPCRelOp()) {
|
| + DecodePCRel(instr);
|
| } else {
|
| Unknown(instr);
|
| }
|
| @@ -531,6 +616,44 @@
|
| }
|
|
|
|
|
| +void ARM64Decoder::DecodeCompareAndBranch(Instr* instr) {
|
| + const int op = instr->Bit(24);
|
| + if (op == 0) {
|
| + Format(instr, "cbz'sf 'rt, 'dest19");
|
| + } else {
|
| + Format(instr, "cbnz'sf 'rt, 'dest19");
|
| + }
|
| +}
|
| +
|
| +
|
| +void ARM64Decoder::DecodeConditionalBranch(Instr* instr) {
|
| + if ((instr->Bit(24) != 0) || (instr->Bit(4) != 0)) {
|
| + Unknown(instr);
|
| + return;
|
| + }
|
| + Format(instr, "b'cond 'dest19");
|
| +}
|
| +
|
| +
|
| +void ARM64Decoder::DecodeTestAndBranch(Instr* instr) {
|
| + const int op = instr->Bit(24);
|
| + if (op == 0) {
|
| + Format(instr, "tbz'sf 'rt, 'bitpos, 'dest14");
|
| + } else {
|
| + Format(instr, "tbnz'sf 'rt, 'bitpos, 'dest14");
|
| + }
|
| +}
|
| +
|
| +
|
| +void ARM64Decoder::DecodeUnconditionalBranch(Instr* instr) {
|
| + const int op = instr->Bit(31);
|
| + if (op == 0) {
|
| + Format(instr, "b 'dest26");
|
| + } else {
|
| + Format(instr, "bl 'dest26");
|
| + }
|
| +}
|
| +
|
| void ARM64Decoder::DecodeCompareBranch(Instr* instr) {
|
| if (instr->IsExceptionGenOp()) {
|
| DecodeExceptionGen(instr);
|
| @@ -538,6 +661,14 @@
|
| DecodeSystem(instr);
|
| } else if (instr->IsUnconditionalBranchRegOp()) {
|
| DecodeUnconditionalBranchReg(instr);
|
| + } else if (instr->IsCompareAndBranchOp()) {
|
| + DecodeCompareAndBranch(instr);
|
| + } else if (instr->IsConditionalBranchOp()) {
|
| + DecodeConditionalBranch(instr);
|
| + } else if (instr->IsTestAndBranchOp()) {
|
| + DecodeTestAndBranch(instr);
|
| + } else if (instr->IsUnconditionalBranchOp()) {
|
| + DecodeUnconditionalBranch(instr);
|
| } else {
|
| Unknown(instr);
|
| }
|
|
|