Home | History | Annotate | Download | only in disassembler
      1 /*
      2  * Copyright (C) 2012 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include "disassembler_x86.h"
     18 
     19 #include <iostream>
     20 
     21 #include "base/logging.h"
     22 #include "base/stringprintf.h"
     23 #include "thread.h"
     24 #include <inttypes.h>
     25 
     26 namespace art {
     27 namespace x86 {
     28 
     29 size_t DisassemblerX86::Dump(std::ostream& os, const uint8_t* begin) {
     30   return DumpInstruction(os, begin);
     31 }
     32 
     33 void DisassemblerX86::Dump(std::ostream& os, const uint8_t* begin, const uint8_t* end) {
     34   size_t length = 0;
     35   for (const uint8_t* cur = begin; cur < end; cur += length) {
     36     length = DumpInstruction(os, cur);
     37   }
     38 }
     39 
     40 static const char* gReg8Names[]  = {
     41   "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh"
     42 };
     43 static const char* gExtReg8Names[] = {
     44   "al", "cl", "dl", "bl", "spl", "bpl", "sil", "dil",
     45   "r8l", "r9l", "r10l", "r11l", "r12l", "r13l", "r14l", "r15l"
     46 };
     47 static const char* gReg16Names[] = {
     48   "ax", "cx", "dx", "bx", "sp", "bp", "si", "di",
     49   "r8w", "r9w", "r10w", "r11w", "r12w", "r13w", "r14w", "r15w"
     50 };
     51 static const char* gReg32Names[] = {
     52   "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi",
     53   "r8d", "r9d", "r10d", "r11d", "r12d", "r13d", "r14d", "r15d"
     54 };
     55 static const char* gReg64Names[] = {
     56   "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi",
     57   "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"
     58 };
     59 
     60 // 64-bit opcode REX modifier.
     61 constexpr uint8_t REX_W = 0b1000;
     62 constexpr uint8_t REX_R = 0b0100;
     63 constexpr uint8_t REX_X = 0b0010;
     64 constexpr uint8_t REX_B = 0b0001;
     65 
     66 static void DumpReg0(std::ostream& os, uint8_t rex, size_t reg,
     67                      bool byte_operand, uint8_t size_override) {
     68   DCHECK_LT(reg, (rex == 0) ? 8u : 16u);
     69   bool rex_w = (rex & REX_W) != 0;
     70   if (byte_operand) {
     71     os << ((rex == 0) ? gReg8Names[reg] : gExtReg8Names[reg]);
     72   } else if (rex_w) {
     73     os << gReg64Names[reg];
     74   } else if (size_override == 0x66) {
     75     os << gReg16Names[reg];
     76   } else {
     77     os << gReg32Names[reg];
     78   }
     79 }
     80 
     81 enum RegFile { GPR, MMX, SSE };
     82 
     83 static void DumpAnyReg(std::ostream& os, uint8_t rex, size_t reg,
     84                        bool byte_operand, uint8_t size_override, RegFile reg_file) {
     85   if (reg_file == GPR) {
     86     DumpReg0(os, rex, reg, byte_operand, size_override);
     87   } else if (reg_file == SSE) {
     88     os << "xmm" << reg;
     89   } else {
     90     os << "mm" << reg;
     91   }
     92 }
     93 
     94 static void DumpReg(std::ostream& os, uint8_t rex, uint8_t reg,
     95                     bool byte_operand, uint8_t size_override, RegFile reg_file) {
     96   bool rex_r = (rex & REX_R) != 0;
     97   size_t reg_num = rex_r ? (reg + 8) : reg;
     98   DumpAnyReg(os, rex, reg_num, byte_operand, size_override, reg_file);
     99 }
    100 
    101 static void DumpRmReg(std::ostream& os, uint8_t rex, uint8_t reg,
    102                       bool byte_operand, uint8_t size_override, RegFile reg_file) {
    103   bool rex_b = (rex & REX_B) != 0;
    104   size_t reg_num = rex_b ? (reg + 8) : reg;
    105   DumpAnyReg(os, rex, reg_num, byte_operand, size_override, reg_file);
    106 }
    107 
    108 static void DumpAddrReg(std::ostream& os, uint8_t rex, uint8_t reg) {
    109   if (rex != 0) {
    110     os << gReg64Names[reg];
    111   } else {
    112     os << gReg32Names[reg];
    113   }
    114 }
    115 
    116 static void DumpBaseReg(std::ostream& os, uint8_t rex, uint8_t reg) {
    117   bool rex_b = (rex & REX_B) != 0;
    118   size_t reg_num = rex_b ? (reg + 8) : reg;
    119   DumpAddrReg(os, rex, reg_num);
    120 }
    121 
    122 static void DumpIndexReg(std::ostream& os, uint8_t rex, uint8_t reg) {
    123   bool rex_x = (rex & REX_X) != 0;
    124   uint8_t reg_num = rex_x ? (reg + 8) : reg;
    125   DumpAddrReg(os, rex, reg_num);
    126 }
    127 
    128 static void DumpOpcodeReg(std::ostream& os, uint8_t rex, uint8_t reg,
    129                           bool byte_operand, uint8_t size_override) {
    130   bool rex_b = (rex & REX_B) != 0;
    131   size_t reg_num = rex_b ? (reg + 8) : reg;
    132   DumpReg0(os, rex, reg_num, byte_operand, size_override);
    133 }
    134 
    135 enum SegmentPrefix {
    136   kCs = 0x2e,
    137   kSs = 0x36,
    138   kDs = 0x3e,
    139   kEs = 0x26,
    140   kFs = 0x64,
    141   kGs = 0x65,
    142 };
    143 
    144 static void DumpSegmentOverride(std::ostream& os, uint8_t segment_prefix) {
    145   switch (segment_prefix) {
    146     case kCs: os << "cs:"; break;
    147     case kSs: os << "ss:"; break;
    148     case kDs: os << "ds:"; break;
    149     case kEs: os << "es:"; break;
    150     case kFs: os << "fs:"; break;
    151     case kGs: os << "gs:"; break;
    152     default: break;
    153   }
    154 }
    155 
    156 size_t DisassemblerX86::DumpInstruction(std::ostream& os, const uint8_t* instr) {
    157   const uint8_t* begin_instr = instr;
    158   bool have_prefixes = true;
    159   uint8_t prefix[4] = {0, 0, 0, 0};
    160   const char** modrm_opcodes = NULL;
    161   do {
    162     switch (*instr) {
    163         // Group 1 - lock and repeat prefixes:
    164       case 0xF0:
    165       case 0xF2:
    166       case 0xF3:
    167         prefix[0] = *instr;
    168         break;
    169         // Group 2 - segment override prefixes:
    170       case kCs:
    171       case kSs:
    172       case kDs:
    173       case kEs:
    174       case kFs:
    175       case kGs:
    176         prefix[1] = *instr;
    177         break;
    178         // Group 3 - operand size override:
    179       case 0x66:
    180         prefix[2] = *instr;
    181         break;
    182         // Group 4 - address size override:
    183       case 0x67:
    184         prefix[3] = *instr;
    185         break;
    186       default:
    187         have_prefixes = false;
    188         break;
    189     }
    190     if (have_prefixes) {
    191       instr++;
    192     }
    193   } while (have_prefixes);
    194   uint8_t rex = (supports_rex_ && (*instr >= 0x40) && (*instr <= 0x4F)) ? *instr : 0;
    195   if (rex != 0) {
    196     instr++;
    197   }
    198   bool has_modrm = false;
    199   bool reg_is_opcode = false;
    200   size_t immediate_bytes = 0;
    201   size_t branch_bytes = 0;
    202   std::ostringstream opcode;
    203   bool store = false;  // stores to memory (ie rm is on the left)
    204   bool load = false;  // loads from memory (ie rm is on the right)
    205   bool byte_operand = false;  // true when the opcode is dealing with byte operands
    206   bool byte_second_operand = false;  // true when the source operand is a byte register but the target register isn't (ie movsxb/movzxb).
    207   bool target_specific = false;  // register name depends on target (64 vs 32 bits).
    208   bool ax = false;  // implicit use of ax
    209   bool cx = false;  // implicit use of cx
    210   bool reg_in_opcode = false;  // low 3-bits of opcode encode register parameter
    211   bool no_ops = false;
    212   RegFile src_reg_file = GPR;
    213   RegFile dst_reg_file = GPR;
    214   switch (*instr) {
    215 #define DISASSEMBLER_ENTRY(opname, \
    216                      rm8_r8, rm32_r32, \
    217                      r8_rm8, r32_rm32, \
    218                      ax8_i8, ax32_i32) \
    219   case rm8_r8:   opcode << #opname; store = true; has_modrm = true; byte_operand = true; break; \
    220   case rm32_r32: opcode << #opname; store = true; has_modrm = true; break; \
    221   case r8_rm8:   opcode << #opname; load = true; has_modrm = true; byte_operand = true; break; \
    222   case r32_rm32: opcode << #opname; load = true; has_modrm = true; break; \
    223   case ax8_i8:   opcode << #opname; ax = true; immediate_bytes = 1; byte_operand = true; break; \
    224   case ax32_i32: opcode << #opname; ax = true; immediate_bytes = 4; break;
    225 
    226 DISASSEMBLER_ENTRY(add,
    227   0x00 /* RegMem8/Reg8 */,     0x01 /* RegMem32/Reg32 */,
    228   0x02 /* Reg8/RegMem8 */,     0x03 /* Reg32/RegMem32 */,
    229   0x04 /* Rax8/imm8 opcode */, 0x05 /* Rax32/imm32 */)
    230 DISASSEMBLER_ENTRY(or,
    231   0x08 /* RegMem8/Reg8 */,     0x09 /* RegMem32/Reg32 */,
    232   0x0A /* Reg8/RegMem8 */,     0x0B /* Reg32/RegMem32 */,
    233   0x0C /* Rax8/imm8 opcode */, 0x0D /* Rax32/imm32 */)
    234 DISASSEMBLER_ENTRY(adc,
    235   0x10 /* RegMem8/Reg8 */,     0x11 /* RegMem32/Reg32 */,
    236   0x12 /* Reg8/RegMem8 */,     0x13 /* Reg32/RegMem32 */,
    237   0x14 /* Rax8/imm8 opcode */, 0x15 /* Rax32/imm32 */)
    238 DISASSEMBLER_ENTRY(sbb,
    239   0x18 /* RegMem8/Reg8 */,     0x19 /* RegMem32/Reg32 */,
    240   0x1A /* Reg8/RegMem8 */,     0x1B /* Reg32/RegMem32 */,
    241   0x1C /* Rax8/imm8 opcode */, 0x1D /* Rax32/imm32 */)
    242 DISASSEMBLER_ENTRY(and,
    243   0x20 /* RegMem8/Reg8 */,     0x21 /* RegMem32/Reg32 */,
    244   0x22 /* Reg8/RegMem8 */,     0x23 /* Reg32/RegMem32 */,
    245   0x24 /* Rax8/imm8 opcode */, 0x25 /* Rax32/imm32 */)
    246 DISASSEMBLER_ENTRY(sub,
    247   0x28 /* RegMem8/Reg8 */,     0x29 /* RegMem32/Reg32 */,
    248   0x2A /* Reg8/RegMem8 */,     0x2B /* Reg32/RegMem32 */,
    249   0x2C /* Rax8/imm8 opcode */, 0x2D /* Rax32/imm32 */)
    250 DISASSEMBLER_ENTRY(xor,
    251   0x30 /* RegMem8/Reg8 */,     0x31 /* RegMem32/Reg32 */,
    252   0x32 /* Reg8/RegMem8 */,     0x33 /* Reg32/RegMem32 */,
    253   0x34 /* Rax8/imm8 opcode */, 0x35 /* Rax32/imm32 */)
    254 DISASSEMBLER_ENTRY(cmp,
    255   0x38 /* RegMem8/Reg8 */,     0x39 /* RegMem32/Reg32 */,
    256   0x3A /* Reg8/RegMem8 */,     0x3B /* Reg32/RegMem32 */,
    257   0x3C /* Rax8/imm8 opcode */, 0x3D /* Rax32/imm32 */)
    258 
    259 #undef DISASSEMBLER_ENTRY
    260   case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57:
    261     opcode << "push";
    262     reg_in_opcode = true;
    263     target_specific = true;
    264     break;
    265   case 0x58: case 0x59: case 0x5A: case 0x5B: case 0x5C: case 0x5D: case 0x5E: case 0x5F:
    266     opcode << "pop";
    267     reg_in_opcode = true;
    268     target_specific = true;
    269     break;
    270   case 0x63:
    271     if ((rex & REX_W) != 0) {
    272       opcode << "movsxd";
    273       has_modrm = true;
    274       load = true;
    275     } else {
    276       // In 32-bit mode (!supports_rex_) this is ARPL, with no REX prefix the functionality is the
    277       // same as 'mov' but the use of the instruction is discouraged.
    278       opcode << StringPrintf("unknown opcode '%02X'", *instr);
    279     }
    280     break;
    281   case 0x68: opcode << "push"; immediate_bytes = 4; break;
    282   case 0x69: opcode << "imul"; load = true; has_modrm = true; immediate_bytes = 4; break;
    283   case 0x6A: opcode << "push"; immediate_bytes = 1; break;
    284   case 0x6B: opcode << "imul"; load = true; has_modrm = true; immediate_bytes = 1; break;
    285   case 0x70: case 0x71: case 0x72: case 0x73: case 0x74: case 0x75: case 0x76: case 0x77:
    286   case 0x78: case 0x79: case 0x7A: case 0x7B: case 0x7C: case 0x7D: case 0x7E: case 0x7F:
    287     static const char* condition_codes[] =
    288     {"o", "no", "b/nae/c", "nb/ae/nc", "z/eq",  "nz/ne", "be/na", "nbe/a",
    289      "s", "ns", "p/pe",    "np/po",    "l/nge", "nl/ge", "le/ng", "nle/g"
    290     };
    291     opcode << "j" << condition_codes[*instr & 0xF];
    292     branch_bytes = 1;
    293     break;
    294   case 0x86: case 0x87:
    295     opcode << "xchg";
    296     store = true;
    297     has_modrm = true;
    298     byte_operand = (*instr == 0x86);
    299     break;
    300   case 0x88: opcode << "mov"; store = true; has_modrm = true; byte_operand = true; break;
    301   case 0x89: opcode << "mov"; store = true; has_modrm = true; break;
    302   case 0x8A: opcode << "mov"; load = true; has_modrm = true; byte_operand = true; break;
    303   case 0x8B: opcode << "mov"; load = true; has_modrm = true; break;
    304 
    305   case 0x0F:  // 2 byte extended opcode
    306     instr++;
    307     switch (*instr) {
    308       case 0x10: case 0x11:
    309         if (prefix[0] == 0xF2) {
    310           opcode << "movsd";
    311           prefix[0] = 0;  // clear prefix now it's served its purpose as part of the opcode
    312         } else if (prefix[0] == 0xF3) {
    313           opcode << "movss";
    314           prefix[0] = 0;  // clear prefix now it's served its purpose as part of the opcode
    315         } else if (prefix[2] == 0x66) {
    316           opcode << "movupd";
    317           prefix[2] = 0;  // clear prefix now it's served its purpose as part of the opcode
    318         } else {
    319           opcode << "movups";
    320         }
    321         has_modrm = true;
    322         src_reg_file = dst_reg_file = SSE;
    323         load = *instr == 0x10;
    324         store = !load;
    325         break;
    326       case 0x12: case 0x13:
    327         if (prefix[2] == 0x66) {
    328           opcode << "movlpd";
    329           prefix[2] = 0;  // clear prefix now it's served its purpose as part of the opcode
    330         } else if (prefix[0] == 0) {
    331           opcode << "movlps";
    332         }
    333         has_modrm = true;
    334         src_reg_file = dst_reg_file = SSE;
    335         load = *instr == 0x12;
    336         store = !load;
    337         break;
    338       case 0x16: case 0x17:
    339         if (prefix[2] == 0x66) {
    340           opcode << "movhpd";
    341           prefix[2] = 0;  // clear prefix now it's served its purpose as part of the opcode
    342         } else if (prefix[0] == 0) {
    343           opcode << "movhps";
    344         }
    345         has_modrm = true;
    346         src_reg_file = dst_reg_file = SSE;
    347         load = *instr == 0x16;
    348         store = !load;
    349         break;
    350       case 0x28: case 0x29:
    351         if (prefix[2] == 0x66) {
    352           opcode << "movapd";
    353           prefix[2] = 0;  // clear prefix now it's served its purpose as part of the opcode
    354         } else if (prefix[0] == 0) {
    355           opcode << "movaps";
    356         }
    357         has_modrm = true;
    358         src_reg_file = dst_reg_file = SSE;
    359         load = *instr == 0x28;
    360         store = !load;
    361         break;
    362       case 0x2A:
    363         if (prefix[2] == 0x66) {
    364           opcode << "cvtpi2pd";
    365           prefix[2] = 0;  // clear prefix now it's served its purpose as part of the opcode
    366         } else if (prefix[0] == 0xF2) {
    367           opcode << "cvtsi2sd";
    368           prefix[0] = 0;  // clear prefix now it's served its purpose as part of the opcode
    369         } else if (prefix[0] == 0xF3) {
    370           opcode << "cvtsi2ss";
    371           prefix[0] = 0;  // clear prefix now it's served its purpose as part of the opcode
    372         } else {
    373           opcode << "cvtpi2ps";
    374         }
    375         load = true;
    376         has_modrm = true;
    377         dst_reg_file = SSE;
    378         break;
    379       case 0x2C:
    380         if (prefix[2] == 0x66) {
    381           opcode << "cvttpd2pi";
    382           prefix[2] = 0;  // clear prefix now it's served its purpose as part of the opcode
    383         } else if (prefix[0] == 0xF2) {
    384           opcode << "cvttsd2si";
    385           prefix[0] = 0;  // clear prefix now it's served its purpose as part of the opcode
    386         } else if (prefix[0] == 0xF3) {
    387           opcode << "cvttss2si";
    388           prefix[0] = 0;  // clear prefix now it's served its purpose as part of the opcode
    389         } else {
    390           opcode << "cvttps2pi";
    391         }
    392         load = true;
    393         has_modrm = true;
    394         src_reg_file = SSE;
    395         break;
    396       case 0x2D:
    397         if (prefix[2] == 0x66) {
    398           opcode << "cvtpd2pi";
    399           prefix[2] = 0;  // clear prefix now it's served its purpose as part of the opcode
    400         } else if (prefix[0] == 0xF2) {
    401           opcode << "cvtsd2si";
    402           prefix[0] = 0;  // clear prefix now it's served its purpose as part of the opcode
    403         } else if (prefix[0] == 0xF3) {
    404           opcode << "cvtss2si";
    405           prefix[0] = 0;  // clear prefix now it's served its purpose as part of the opcode
    406         } else {
    407           opcode << "cvtps2pi";
    408         }
    409         load = true;
    410         has_modrm = true;
    411         src_reg_file = SSE;
    412         break;
    413       case 0x2E:
    414         opcode << "u";
    415         // FALLTHROUGH
    416       case 0x2F:
    417         if (prefix[2] == 0x66) {
    418           opcode << "comisd";
    419           prefix[2] = 0;  // clear prefix now it's served its purpose as part of the opcode
    420         } else {
    421           opcode << "comiss";
    422         }
    423         has_modrm = true;
    424         load = true;
    425         src_reg_file = dst_reg_file = SSE;
    426         break;
    427       case 0x38:  // 3 byte extended opcode
    428         instr++;
    429         if (prefix[2] == 0x66) {
    430           switch (*instr) {
    431             case 0x01:
    432               opcode << "phaddw";
    433               prefix[2] = 0;
    434               has_modrm = true;
    435               load = true;
    436               src_reg_file = dst_reg_file = SSE;
    437               break;
    438             case 0x02:
    439               opcode << "phaddd";
    440               prefix[2] = 0;
    441               has_modrm = true;
    442               load = true;
    443               src_reg_file = dst_reg_file = SSE;
    444               break;
    445             case 0x40:
    446               opcode << "pmulld";
    447               prefix[2] = 0;
    448               has_modrm = true;
    449               load = true;
    450               src_reg_file = dst_reg_file = SSE;
    451               break;
    452             default:
    453               opcode << StringPrintf("unknown opcode '0F 38 %02X'", *instr);
    454           }
    455         } else {
    456           opcode << StringPrintf("unknown opcode '0F 38 %02X'", *instr);
    457         }
    458         break;
    459       case 0x3A:  // 3 byte extended opcode
    460         instr++;
    461         if (prefix[2] == 0x66) {
    462           switch (*instr) {
    463             case 0x14:
    464               opcode << "pextrb";
    465               prefix[2] = 0;
    466               has_modrm = true;
    467               store = true;
    468               src_reg_file = SSE;
    469               immediate_bytes = 1;
    470               break;
    471             case 0x16:
    472               opcode << "pextrd";
    473               prefix[2] = 0;
    474               has_modrm = true;
    475               store = true;
    476               src_reg_file = SSE;
    477               immediate_bytes = 1;
    478               break;
    479             default:
    480               opcode << StringPrintf("unknown opcode '0F 3A %02X'", *instr);
    481           }
    482         } else {
    483           opcode << StringPrintf("unknown opcode '0F 3A %02X'", *instr);
    484         }
    485         break;
    486       case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: case 0x47:
    487       case 0x48: case 0x49: case 0x4A: case 0x4B: case 0x4C: case 0x4D: case 0x4E: case 0x4F:
    488         opcode << "cmov" << condition_codes[*instr & 0xF];
    489         has_modrm = true;
    490         load = true;
    491         break;
    492       case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57:
    493       case 0x58: case 0x59: case 0x5C: case 0x5D: case 0x5E: case 0x5F: {
    494         switch (*instr) {
    495           case 0x50: opcode << "movmsk"; break;
    496           case 0x51: opcode << "sqrt"; break;
    497           case 0x52: opcode << "rsqrt"; break;
    498           case 0x53: opcode << "rcp"; break;
    499           case 0x54: opcode << "and"; break;
    500           case 0x55: opcode << "andn"; break;
    501           case 0x56: opcode << "or"; break;
    502           case 0x57: opcode << "xor"; break;
    503           case 0x58: opcode << "add"; break;
    504           case 0x59: opcode << "mul"; break;
    505           case 0x5C: opcode << "sub"; break;
    506           case 0x5D: opcode << "min"; break;
    507           case 0x5E: opcode << "div"; break;
    508           case 0x5F: opcode << "max"; break;
    509           default: LOG(FATAL) << "Unreachable";
    510         }
    511         if (prefix[2] == 0x66) {
    512           opcode << "pd";
    513           prefix[2] = 0;  // clear prefix now it's served its purpose as part of the opcode
    514         } else if (prefix[0] == 0xF2) {
    515           opcode << "sd";
    516           prefix[0] = 0;  // clear prefix now it's served its purpose as part of the opcode
    517         } else if (prefix[0] == 0xF3) {
    518           opcode << "ss";
    519           prefix[0] = 0;  // clear prefix now it's served its purpose as part of the opcode
    520         } else {
    521           opcode << "ps";
    522         }
    523         load = true;
    524         has_modrm = true;
    525         src_reg_file = dst_reg_file = SSE;
    526         break;
    527       }
    528       case 0x5A:
    529         if (prefix[2] == 0x66) {
    530           opcode << "cvtpd2ps";
    531           prefix[2] = 0;  // clear prefix now it's served its purpose as part of the opcode
    532         } else if (prefix[0] == 0xF2) {
    533           opcode << "cvtsd2ss";
    534           prefix[0] = 0;  // clear prefix now it's served its purpose as part of the opcode
    535         } else if (prefix[0] == 0xF3) {
    536           opcode << "cvtss2sd";
    537           prefix[0] = 0;  // clear prefix now it's served its purpose as part of the opcode
    538         } else {
    539           opcode << "cvtps2pd";
    540         }
    541         load = true;
    542         has_modrm = true;
    543         src_reg_file = dst_reg_file = SSE;
    544         break;
    545       case 0x5B:
    546         if (prefix[2] == 0x66) {
    547           opcode << "cvtps2dq";
    548           prefix[2] = 0;  // clear prefix now it's served its purpose as part of the opcode
    549         } else if (prefix[0] == 0xF2) {
    550           opcode << "bad opcode F2 0F 5B";
    551         } else if (prefix[0] == 0xF3) {
    552           opcode << "cvttps2dq";
    553           prefix[0] = 0;  // clear prefix now it's served its purpose as part of the opcode
    554         } else {
    555           opcode << "cvtdq2ps";
    556         }
    557         load = true;
    558         has_modrm = true;
    559         src_reg_file = dst_reg_file = SSE;
    560         break;
    561       case 0x62:
    562         if (prefix[2] == 0x66) {
    563           src_reg_file = dst_reg_file = SSE;
    564           prefix[2] = 0;  // Clear prefix now. It has served its purpose as part of the opcode.
    565         } else {
    566           src_reg_file = dst_reg_file = MMX;
    567         }
    568         opcode << "punpckldq";
    569         load = true;
    570         has_modrm = true;
    571         break;
    572       case 0x6E:
    573         if (prefix[2] == 0x66) {
    574           dst_reg_file = SSE;
    575           prefix[2] = 0;  // clear prefix now it's served its purpose as part of the opcode
    576         } else {
    577           dst_reg_file = MMX;
    578         }
    579         opcode << "movd";
    580         load = true;
    581         has_modrm = true;
    582         break;
    583       case 0x6F:
    584         if (prefix[2] == 0x66) {
    585           src_reg_file = dst_reg_file = SSE;
    586           opcode << "movdqa";
    587           prefix[2] = 0;  // clear prefix now it's served its purpose as part of the opcode
    588         } else if (prefix[0] == 0xF3) {
    589           src_reg_file = dst_reg_file = SSE;
    590           opcode << "movdqu";
    591           prefix[0] = 0;  // clear prefix now it's served its purpose as part of the opcode
    592         } else {
    593           dst_reg_file = MMX;
    594           opcode << "movq";
    595         }
    596         load = true;
    597         has_modrm = true;
    598         break;
    599       case 0x70:
    600         if (prefix[2] == 0x66) {
    601           opcode << "pshufd";
    602           prefix[2] = 0;
    603           has_modrm = true;
    604           store = true;
    605           src_reg_file = dst_reg_file = SSE;
    606           immediate_bytes = 1;
    607         } else if (prefix[0] == 0xF2) {
    608           opcode << "pshuflw";
    609           prefix[0] = 0;
    610           has_modrm = true;
    611           store = true;
    612           src_reg_file = dst_reg_file = SSE;
    613           immediate_bytes = 1;
    614         } else {
    615           opcode << StringPrintf("unknown opcode '0F %02X'", *instr);
    616         }
    617         break;
    618       case 0x71:
    619         if (prefix[2] == 0x66) {
    620           dst_reg_file = SSE;
    621           prefix[2] = 0;  // clear prefix now it's served its purpose as part of the opcode
    622         } else {
    623           dst_reg_file = MMX;
    624         }
    625         static const char* x71_opcodes[] = {"unknown-71", "unknown-71", "psrlw", "unknown-71", "psraw", "unknown-71", "psllw", "unknown-71"};
    626         modrm_opcodes = x71_opcodes;
    627         reg_is_opcode = true;
    628         has_modrm = true;
    629         store = true;
    630         immediate_bytes = 1;
    631         break;
    632       case 0x72:
    633         if (prefix[2] == 0x66) {
    634           dst_reg_file = SSE;
    635           prefix[2] = 0;  // clear prefix now it's served its purpose as part of the opcode
    636         } else {
    637           dst_reg_file = MMX;
    638         }
    639         static const char* x72_opcodes[] = {"unknown-72", "unknown-72", "psrld", "unknown-72", "psrad", "unknown-72", "pslld", "unknown-72"};
    640         modrm_opcodes = x72_opcodes;
    641         reg_is_opcode = true;
    642         has_modrm = true;
    643         store = true;
    644         immediate_bytes = 1;
    645         break;
    646       case 0x73:
    647         if (prefix[2] == 0x66) {
    648           dst_reg_file = SSE;
    649           prefix[2] = 0;  // clear prefix now it's served its purpose as part of the opcode
    650         } else {
    651           dst_reg_file = MMX;
    652         }
    653         static const char* x73_opcodes[] = {"unknown-73", "unknown-73", "psrlq", "unknown-73", "unknown-73", "unknown-73", "psllq", "unknown-73"};
    654         modrm_opcodes = x73_opcodes;
    655         reg_is_opcode = true;
    656         has_modrm = true;
    657         store = true;
    658         immediate_bytes = 1;
    659         break;
    660       case 0x7C:
    661         if (prefix[0] == 0xF2) {
    662           opcode << "haddps";
    663           prefix[0] = 0;  // clear prefix now it's served its purpose as part of the opcode
    664         } else if (prefix[2] == 0x66) {
    665           opcode << "haddpd";
    666           prefix[2] = 0;  // clear prefix now it's served its purpose as part of the opcode
    667         } else {
    668           opcode << StringPrintf("unknown opcode '0F %02X'", *instr);
    669           break;
    670         }
    671         src_reg_file = dst_reg_file = SSE;
    672         has_modrm = true;
    673         load = true;
    674         break;
    675       case 0x7E:
    676         if (prefix[2] == 0x66) {
    677           src_reg_file = SSE;
    678           prefix[2] = 0;  // clear prefix now it's served its purpose as part of the opcode
    679         } else {
    680           src_reg_file = MMX;
    681         }
    682         opcode << "movd";
    683         has_modrm = true;
    684         store = true;
    685         break;
    686       case 0x80: case 0x81: case 0x82: case 0x83: case 0x84: case 0x85: case 0x86: case 0x87:
    687       case 0x88: case 0x89: case 0x8A: case 0x8B: case 0x8C: case 0x8D: case 0x8E: case 0x8F:
    688         opcode << "j" << condition_codes[*instr & 0xF];
    689         branch_bytes = 4;
    690         break;
    691       case 0x90: case 0x91: case 0x92: case 0x93: case 0x94: case 0x95: case 0x96: case 0x97:
    692       case 0x98: case 0x99: case 0x9A: case 0x9B: case 0x9C: case 0x9D: case 0x9E: case 0x9F:
    693         opcode << "set" << condition_codes[*instr & 0xF];
    694         modrm_opcodes = NULL;
    695         reg_is_opcode = true;
    696         has_modrm = true;
    697         store = true;
    698         break;
    699       case 0xA4:
    700         opcode << "shld";
    701         has_modrm = true;
    702         load = true;
    703         immediate_bytes = 1;
    704         break;
    705       case 0xAC:
    706         opcode << "shrd";
    707         has_modrm = true;
    708         load = true;
    709         immediate_bytes = 1;
    710         break;
    711       case 0xAE:
    712         if (prefix[0] == 0xF3) {
    713           prefix[0] = 0;  // clear prefix now it's served its purpose as part of the opcode
    714           static const char* xAE_opcodes[] = {"rdfsbase", "rdgsbase", "wrfsbase", "wrgsbase", "unknown-AE", "unknown-AE", "unknown-AE", "unknown-AE"};
    715           modrm_opcodes = xAE_opcodes;
    716           reg_is_opcode = true;
    717           has_modrm = true;
    718           uint8_t reg_or_opcode = (instr[1] >> 3) & 7;
    719           switch (reg_or_opcode) {
    720             case 0:
    721               prefix[1] = kFs;
    722               load = true;
    723               break;
    724             case 1:
    725               prefix[1] = kGs;
    726               load = true;
    727               break;
    728             case 2:
    729               prefix[1] = kFs;
    730               store = true;
    731               break;
    732             case 3:
    733               prefix[1] = kGs;
    734               store = true;
    735               break;
    736             default:
    737               load = true;
    738               break;
    739           }
    740         } else {
    741           static const char* xAE_opcodes[] = {"unknown-AE", "unknown-AE", "unknown-AE", "unknown-AE", "unknown-AE", "lfence", "mfence", "sfence"};
    742           modrm_opcodes = xAE_opcodes;
    743           reg_is_opcode = true;
    744           has_modrm = true;
    745           load = true;
    746           no_ops = true;
    747         }
    748         break;
    749       case 0xAF: opcode << "imul"; has_modrm = true; load = true; break;
    750       case 0xB1: opcode << "cmpxchg"; has_modrm = true; store = true; break;
    751       case 0xB6: opcode << "movzxb"; has_modrm = true; load = true; byte_second_operand = true; break;
    752       case 0xB7: opcode << "movzxw"; has_modrm = true; load = true; break;
    753       case 0xBE: opcode << "movsxb"; has_modrm = true; load = true; byte_second_operand = true; rex |= (rex == 0 ? 0 : 0b1000); break;
    754       case 0xBF: opcode << "movsxw"; has_modrm = true; load = true; break;
    755       case 0xC5:
    756         if (prefix[2] == 0x66) {
    757           opcode << "pextrw";
    758           prefix[2] = 0;
    759           has_modrm = true;
    760           store = true;
    761           src_reg_file = SSE;
    762           immediate_bytes = 1;
    763         } else {
    764           opcode << StringPrintf("unknown opcode '0F %02X'", *instr);
    765         }
    766         break;
    767       case 0xC6:
    768         if (prefix[2] == 0x66) {
    769           opcode << "shufpd";
    770           prefix[2] = 0;
    771         } else {
    772           opcode << "shufps";
    773         }
    774         has_modrm = true;
    775         store = true;
    776         src_reg_file = dst_reg_file = SSE;
    777         immediate_bytes = 1;
    778         break;
    779       case 0xC7:
    780         static const char* x0FxC7_opcodes[] = { "unknown-0f-c7", "cmpxchg8b", "unknown-0f-c7", "unknown-0f-c7", "unknown-0f-c7", "unknown-0f-c7", "unknown-0f-c7", "unknown-0f-c7" };
    781         modrm_opcodes = x0FxC7_opcodes;
    782         has_modrm = true;
    783         reg_is_opcode = true;
    784         store = true;
    785         break;
    786       case 0xC8: case 0xC9: case 0xCA: case 0xCB: case 0xCC: case 0xCD: case 0xCE: case 0xCF:
    787         opcode << "bswap";
    788         reg_in_opcode = true;
    789         break;
    790       case 0xDB:
    791         if (prefix[2] == 0x66) {
    792           src_reg_file = dst_reg_file = SSE;
    793           prefix[2] = 0;  // clear prefix now it's served its purpose as part of the opcode
    794         } else {
    795           src_reg_file = dst_reg_file = MMX;
    796         }
    797         opcode << "pand";
    798         prefix[2] = 0;
    799         has_modrm = true;
    800         load = true;
    801         break;
    802       case 0xD5:
    803         if (prefix[2] == 0x66) {
    804           opcode << "pmullw";
    805           prefix[2] = 0;
    806           has_modrm = true;
    807           load = true;
    808           src_reg_file = dst_reg_file = SSE;
    809         } else {
    810           opcode << StringPrintf("unknown opcode '0F %02X'", *instr);
    811         }
    812         break;
    813       case 0xEB:
    814         if (prefix[2] == 0x66) {
    815           src_reg_file = dst_reg_file = SSE;
    816           prefix[2] = 0;  // clear prefix now it's served its purpose as part of the opcode
    817         } else {
    818           src_reg_file = dst_reg_file = MMX;
    819         }
    820         opcode << "por";
    821         prefix[2] = 0;
    822         has_modrm = true;
    823         load = true;
    824         break;
    825       case 0xEF:
    826         if (prefix[2] == 0x66) {
    827           src_reg_file = dst_reg_file = SSE;
    828           prefix[2] = 0;  // clear prefix now it's served its purpose as part of the opcode
    829         } else {
    830           src_reg_file = dst_reg_file = MMX;
    831         }
    832         opcode << "pxor";
    833         prefix[2] = 0;
    834         has_modrm = true;
    835         load = true;
    836         break;
    837       case 0xF8:
    838         if (prefix[2] == 0x66) {
    839           src_reg_file = dst_reg_file = SSE;
    840           prefix[2] = 0;  // clear prefix now it's served its purpose as part of the opcode
    841         } else {
    842           src_reg_file = dst_reg_file = MMX;
    843         }
    844         opcode << "psubb";
    845         prefix[2] = 0;
    846         has_modrm = true;
    847         load = true;
    848         break;
    849       case 0xF9:
    850         if (prefix[2] == 0x66) {
    851           src_reg_file = dst_reg_file = SSE;
    852           prefix[2] = 0;  // clear prefix now it's served its purpose as part of the opcode
    853         } else {
    854           src_reg_file = dst_reg_file = MMX;
    855         }
    856         opcode << "psubw";
    857         prefix[2] = 0;
    858         has_modrm = true;
    859         load = true;
    860         break;
    861       case 0xFA:
    862         if (prefix[2] == 0x66) {
    863           src_reg_file = dst_reg_file = SSE;
    864           prefix[2] = 0;  // clear prefix now it's served its purpose as part of the opcode
    865         } else {
    866           src_reg_file = dst_reg_file = MMX;
    867         }
    868         opcode << "psubd";
    869         prefix[2] = 0;
    870         has_modrm = true;
    871         load = true;
    872         break;
    873       case 0xFC:
    874         if (prefix[2] == 0x66) {
    875           src_reg_file = dst_reg_file = SSE;
    876           prefix[2] = 0;  // clear prefix now it's served its purpose as part of the opcode
    877         } else {
    878           src_reg_file = dst_reg_file = MMX;
    879         }
    880         opcode << "paddb";
    881         prefix[2] = 0;
    882         has_modrm = true;
    883         load = true;
    884         break;
    885       case 0xFD:
    886         if (prefix[2] == 0x66) {
    887           src_reg_file = dst_reg_file = SSE;
    888           prefix[2] = 0;  // clear prefix now it's served its purpose as part of the opcode
    889         } else {
    890           src_reg_file = dst_reg_file = MMX;
    891         }
    892         opcode << "paddw";
    893         prefix[2] = 0;
    894         has_modrm = true;
    895         load = true;
    896         break;
    897       case 0xFE:
    898         if (prefix[2] == 0x66) {
    899           src_reg_file = dst_reg_file = SSE;
    900           prefix[2] = 0;  // clear prefix now it's served its purpose as part of the opcode
    901         } else {
    902           src_reg_file = dst_reg_file = MMX;
    903         }
    904         opcode << "paddd";
    905         prefix[2] = 0;
    906         has_modrm = true;
    907         load = true;
    908         break;
    909       default:
    910         opcode << StringPrintf("unknown opcode '0F %02X'", *instr);
    911         break;
    912     }
    913     break;
    914   case 0x80: case 0x81: case 0x82: case 0x83:
    915     static const char* x80_opcodes[] = {"add", "or", "adc", "sbb", "and", "sub", "xor", "cmp"};
    916     modrm_opcodes = x80_opcodes;
    917     has_modrm = true;
    918     reg_is_opcode = true;
    919     store = true;
    920     byte_operand = (*instr & 1) == 0;
    921     immediate_bytes = *instr == 0x81 ? 4 : 1;
    922     break;
    923   case 0x84: case 0x85:
    924     opcode << "test";
    925     has_modrm = true;
    926     load = true;
    927     byte_operand = (*instr & 1) == 0;
    928     break;
    929   case 0x8D:
    930     opcode << "lea";
    931     has_modrm = true;
    932     load = true;
    933     break;
    934   case 0x8F:
    935     opcode << "pop";
    936     has_modrm = true;
    937     reg_is_opcode = true;
    938     store = true;
    939     break;
    940   case 0x99:
    941     opcode << "cdq";
    942     break;
    943   case 0x9B:
    944     if (instr[1] == 0xDF && instr[2] == 0xE0) {
    945       opcode << "fstsw\tax";
    946       instr += 2;
    947     } else {
    948       opcode << StringPrintf("unknown opcode '%02X'", *instr);
    949     }
    950     break;
    951   case 0xAF:
    952     opcode << (prefix[2] == 0x66 ? "scasw" : "scasl");
    953     break;
    954   case 0xB0: case 0xB1: case 0xB2: case 0xB3: case 0xB4: case 0xB5: case 0xB6: case 0xB7:
    955     opcode << "mov";
    956     immediate_bytes = 1;
    957     byte_operand = true;
    958     reg_in_opcode = true;
    959     byte_operand = true;
    960     break;
    961   case 0xB8: case 0xB9: case 0xBA: case 0xBB: case 0xBC: case 0xBD: case 0xBE: case 0xBF:
    962     if ((rex & REX_W) != 0) {
    963       opcode << "movabsq";
    964       immediate_bytes = 8;
    965       reg_in_opcode = true;
    966       break;
    967     }
    968     opcode << "mov";
    969     immediate_bytes = 4;
    970     reg_in_opcode = true;
    971     break;
    972   case 0xC0: case 0xC1:
    973   case 0xD0: case 0xD1: case 0xD2: case 0xD3:
    974     static const char* shift_opcodes[] =
    975         {"rol", "ror", "rcl", "rcr", "shl", "shr", "unknown-shift", "sar"};
    976     modrm_opcodes = shift_opcodes;
    977     has_modrm = true;
    978     reg_is_opcode = true;
    979     store = true;
    980     immediate_bytes = ((*instr & 0xf0) == 0xc0) ? 1 : 0;
    981     cx = (*instr == 0xD2) || (*instr == 0xD3);
    982     byte_operand = (*instr == 0xC0);
    983     break;
    984   case 0xC3: opcode << "ret"; break;
    985   case 0xC6:
    986     static const char* c6_opcodes[] = {"mov", "unknown-c6", "unknown-c6", "unknown-c6", "unknown-c6", "unknown-c6", "unknown-c6", "unknown-c6"};
    987     modrm_opcodes = c6_opcodes;
    988     store = true;
    989     immediate_bytes = 1;
    990     has_modrm = true;
    991     reg_is_opcode = true;
    992     byte_operand = true;
    993     break;
    994   case 0xC7:
    995     static const char* c7_opcodes[] = {"mov", "unknown-c7", "unknown-c7", "unknown-c7", "unknown-c7", "unknown-c7", "unknown-c7", "unknown-c7"};
    996     modrm_opcodes = c7_opcodes;
    997     store = true;
    998     immediate_bytes = 4;
    999     has_modrm = true;
   1000     reg_is_opcode = true;
   1001     break;
   1002   case 0xCC: opcode << "int 3"; break;
   1003   case 0xD9:
   1004     if (instr[1] == 0xF8) {
   1005       opcode << "fprem";
   1006       instr++;
   1007     } else {
   1008       static const char* d9_opcodes[] = {"flds", "unknown-d9", "fsts", "fstps", "fldenv", "fldcw",
   1009                                          "fnstenv", "fnstcw"};
   1010       modrm_opcodes = d9_opcodes;
   1011       store = true;
   1012       has_modrm = true;
   1013       reg_is_opcode = true;
   1014     }
   1015     break;
   1016   case 0xDA:
   1017     if (instr[1] == 0xE9) {
   1018       opcode << "fucompp";
   1019       instr++;
   1020     } else {
   1021       opcode << StringPrintf("unknown opcode '%02X'", *instr);
   1022     }
   1023     break;
   1024   case 0xDB:
   1025     static const char* db_opcodes[] = {"fildl", "unknown-db", "unknown-db", "unknown-db", "unknown-db", "unknown-db", "unknown-db", "unknown-db"};
   1026     modrm_opcodes = db_opcodes;
   1027     load = true;
   1028     has_modrm = true;
   1029     reg_is_opcode = true;
   1030     break;
   1031   case 0xDD:
   1032     static const char* dd_opcodes[] = {"fldl", "fisttp", "fstl", "fstpl", "frstor", "unknown-dd", "fnsave", "fnstsw"};
   1033     modrm_opcodes = dd_opcodes;
   1034     store = true;
   1035     has_modrm = true;
   1036     reg_is_opcode = true;
   1037     break;
   1038   case 0xDF:
   1039     static const char* df_opcodes[] = {"fild", "unknown-df", "unknown-df", "unknown-df", "unknown-df", "fildll", "unknown-df", "unknown-df"};
   1040     modrm_opcodes = df_opcodes;
   1041     load = true;
   1042     has_modrm = true;
   1043     reg_is_opcode = true;
   1044     break;
   1045   case 0xE3: opcode << "jecxz"; branch_bytes = 1; break;
   1046   case 0xE8: opcode << "call"; branch_bytes = 4; break;
   1047   case 0xE9: opcode << "jmp"; branch_bytes = 4; break;
   1048   case 0xEB: opcode << "jmp"; branch_bytes = 1; break;
   1049   case 0xF5: opcode << "cmc"; break;
   1050   case 0xF6: case 0xF7:
   1051     static const char* f7_opcodes[] = {"test", "unknown-f7", "not", "neg", "mul edx:eax, eax *", "imul edx:eax, eax *", "div edx:eax, edx:eax /", "idiv edx:eax, edx:eax /"};
   1052     modrm_opcodes = f7_opcodes;
   1053     has_modrm = true;
   1054     reg_is_opcode = true;
   1055     store = true;
   1056     immediate_bytes = ((instr[1] & 0x38) == 0) ? 1 : 0;
   1057     break;
   1058   case 0xFF:
   1059     {
   1060       static const char* ff_opcodes[] = {"inc", "dec", "call", "call", "jmp", "jmp", "push", "unknown-ff"};
   1061       modrm_opcodes = ff_opcodes;
   1062       has_modrm = true;
   1063       reg_is_opcode = true;
   1064       load = true;
   1065       const uint8_t opcode_digit = (instr[1] >> 3) & 7;
   1066       // 'call', 'jmp' and 'push' are target specific instructions
   1067       if (opcode_digit == 2 || opcode_digit == 4 || opcode_digit == 6) {
   1068         target_specific = true;
   1069       }
   1070     }
   1071     break;
   1072   default:
   1073     opcode << StringPrintf("unknown opcode '%02X'", *instr);
   1074     break;
   1075   }
   1076   std::ostringstream args;
   1077   // We force the REX prefix to be available for 64-bit target
   1078   // in order to dump addr (base/index) registers correctly.
   1079   uint8_t rex64 = supports_rex_ ? (rex | 0x40) : rex;
   1080   // REX.W should be forced for 64-target and target-specific instructions (i.e., push or pop).
   1081   uint8_t rex_w = (supports_rex_ && target_specific) ? (rex | 0x48) : rex;
   1082   if (reg_in_opcode) {
   1083     DCHECK(!has_modrm);
   1084     DumpOpcodeReg(args, rex_w, *instr & 0x7, byte_operand, prefix[2]);
   1085   }
   1086   instr++;
   1087   uint32_t address_bits = 0;
   1088   if (has_modrm) {
   1089     uint8_t modrm = *instr;
   1090     instr++;
   1091     uint8_t mod = modrm >> 6;
   1092     uint8_t reg_or_opcode = (modrm >> 3) & 7;
   1093     uint8_t rm = modrm & 7;
   1094     std::ostringstream address;
   1095     if (mod == 0 && rm == 5) {
   1096       if (!supports_rex_) {  // Absolute address.
   1097         address_bits = *reinterpret_cast<const uint32_t*>(instr);
   1098         address << StringPrintf("[0x%x]", address_bits);
   1099       } else {  // 64-bit RIP relative addressing.
   1100         address << StringPrintf("[RIP + 0x%x]",  *reinterpret_cast<const uint32_t*>(instr));
   1101       }
   1102       instr += 4;
   1103     } else if (rm == 4 && mod != 3) {  // SIB
   1104       uint8_t sib = *instr;
   1105       instr++;
   1106       uint8_t scale = (sib >> 6) & 3;
   1107       uint8_t index = (sib >> 3) & 7;
   1108       uint8_t base = sib & 7;
   1109       address << "[";
   1110       if (base != 5 || mod != 0) {
   1111         DumpBaseReg(address, rex64, base);
   1112         if (index != 4) {
   1113           address << " + ";
   1114         }
   1115       }
   1116       if (index != 4) {
   1117         DumpIndexReg(address, rex64, index);
   1118         if (scale != 0) {
   1119           address << StringPrintf(" * %d", 1 << scale);
   1120         }
   1121       }
   1122       if (mod == 0) {
   1123         if (base == 5) {
   1124           if (index != 4) {
   1125             address << StringPrintf(" + %d", *reinterpret_cast<const int32_t*>(instr));
   1126           } else {
   1127             // 64-bit low 32-bit absolute address, redundant absolute address encoding on 32-bit.
   1128             address_bits = *reinterpret_cast<const uint32_t*>(instr);
   1129             address << StringPrintf("%d", address_bits);
   1130           }
   1131           instr += 4;
   1132         }
   1133       } else if (mod == 1) {
   1134         address << StringPrintf(" + %d", *reinterpret_cast<const int8_t*>(instr));
   1135         instr++;
   1136       } else if (mod == 2) {
   1137         address << StringPrintf(" + %d", *reinterpret_cast<const int32_t*>(instr));
   1138         instr += 4;
   1139       }
   1140       address << "]";
   1141     } else {
   1142       if (mod == 3) {
   1143         if (!no_ops) {
   1144           DumpRmReg(address, rex_w, rm, byte_operand || byte_second_operand,
   1145                     prefix[2], load ? src_reg_file : dst_reg_file);
   1146         }
   1147       } else {
   1148         address << "[";
   1149         DumpBaseReg(address, rex64, rm);
   1150         if (mod == 1) {
   1151           address << StringPrintf(" + %d", *reinterpret_cast<const int8_t*>(instr));
   1152           instr++;
   1153         } else if (mod == 2) {
   1154           address << StringPrintf(" + %d", *reinterpret_cast<const int32_t*>(instr));
   1155           instr += 4;
   1156         }
   1157         address << "]";
   1158       }
   1159     }
   1160 
   1161     if (reg_is_opcode && modrm_opcodes != NULL) {
   1162       opcode << modrm_opcodes[reg_or_opcode];
   1163     }
   1164 
   1165     // Add opcode suffixes to indicate size.
   1166     if (byte_operand) {
   1167       opcode << 'b';
   1168     } else if ((rex & REX_W) != 0) {
   1169       opcode << 'q';
   1170     } else if (prefix[2] == 0x66) {
   1171       opcode << 'w';
   1172     }
   1173 
   1174     if (load) {
   1175       if (!reg_is_opcode) {
   1176         DumpReg(args, rex, reg_or_opcode, byte_operand, prefix[2], dst_reg_file);
   1177         args << ", ";
   1178       }
   1179       DumpSegmentOverride(args, prefix[1]);
   1180       args << address.str();
   1181     } else {
   1182       DCHECK(store);
   1183       DumpSegmentOverride(args, prefix[1]);
   1184       args << address.str();
   1185       if (!reg_is_opcode) {
   1186         args << ", ";
   1187         DumpReg(args, rex, reg_or_opcode, byte_operand, prefix[2], src_reg_file);
   1188       }
   1189     }
   1190   }
   1191   if (ax) {
   1192     // If this opcode implicitly uses ax, ax is always the first arg.
   1193     DumpReg(args, rex, 0 /* EAX */, byte_operand, prefix[2], GPR);
   1194   }
   1195   if (cx) {
   1196     args << ", ";
   1197     DumpReg(args, rex, 1 /* ECX */, true, prefix[2], GPR);
   1198   }
   1199   if (immediate_bytes > 0) {
   1200     if (has_modrm || reg_in_opcode || ax || cx) {
   1201       args << ", ";
   1202     }
   1203     if (immediate_bytes == 1) {
   1204       args << StringPrintf("%d", *reinterpret_cast<const int8_t*>(instr));
   1205       instr++;
   1206     } else if (immediate_bytes == 4) {
   1207       if (prefix[2] == 0x66) {  // Operand size override from 32-bit to 16-bit.
   1208         args << StringPrintf("%d", *reinterpret_cast<const int16_t*>(instr));
   1209         instr += 2;
   1210       } else {
   1211         args << StringPrintf("%d", *reinterpret_cast<const int32_t*>(instr));
   1212         instr += 4;
   1213       }
   1214     } else {
   1215       CHECK_EQ(immediate_bytes, 8u);
   1216       args << StringPrintf("%" PRId64, *reinterpret_cast<const int64_t*>(instr));
   1217       instr += 8;
   1218     }
   1219   } else if (branch_bytes > 0) {
   1220     DCHECK(!has_modrm);
   1221     int32_t displacement;
   1222     if (branch_bytes == 1) {
   1223       displacement = *reinterpret_cast<const int8_t*>(instr);
   1224       instr++;
   1225     } else {
   1226       CHECK_EQ(branch_bytes, 4u);
   1227       displacement = *reinterpret_cast<const int32_t*>(instr);
   1228       instr += 4;
   1229     }
   1230     args << StringPrintf("%+d (", displacement)
   1231          << FormatInstructionPointer(instr + displacement)
   1232          << ")";
   1233   }
   1234   if (prefix[1] == kFs && !supports_rex_) {
   1235     args << "  ; ";
   1236     Thread::DumpThreadOffset<4>(args, address_bits);
   1237   }
   1238   if (prefix[1] == kGs && supports_rex_) {
   1239     args << "  ; ";
   1240     Thread::DumpThreadOffset<8>(args, address_bits);
   1241   }
   1242   std::stringstream hex;
   1243   for (size_t i = 0; begin_instr + i < instr; ++i) {
   1244     hex << StringPrintf("%02X", begin_instr[i]);
   1245   }
   1246   std::stringstream prefixed_opcode;
   1247   switch (prefix[0]) {
   1248     case 0xF0: prefixed_opcode << "lock "; break;
   1249     case 0xF2: prefixed_opcode << "repne "; break;
   1250     case 0xF3: prefixed_opcode << "repe "; break;
   1251     case 0: break;
   1252     default: LOG(FATAL) << "Unreachable";
   1253   }
   1254   prefixed_opcode << opcode.str();
   1255   os << FormatInstructionPointer(begin_instr)
   1256      << StringPrintf(": %22s    \t%-7s ", hex.str().c_str(), prefixed_opcode.str().c_str())
   1257      << args.str() << '\n';
   1258   return instr - begin_instr;
   1259 }  // NOLINT(readability/fn_size)
   1260 
   1261 }  // namespace x86
   1262 }  // namespace art
   1263