Home | History | Annotate | Download | only in runtime
      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 
     25 namespace art {
     26 namespace x86 {
     27 
     28 DisassemblerX86::DisassemblerX86() {}
     29 
     30 size_t DisassemblerX86::Dump(std::ostream& os, const uint8_t* begin) {
     31   return DumpInstruction(os, begin);
     32 }
     33 
     34 void DisassemblerX86::Dump(std::ostream& os, const uint8_t* begin, const uint8_t* end) {
     35   size_t length = 0;
     36   for (const uint8_t* cur = begin; cur < end; cur += length) {
     37     length = DumpInstruction(os, cur);
     38   }
     39 }
     40 
     41 static const char* gReg8Names[]  = { "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh" };
     42 static const char* gReg16Names[] = { "ax", "cx", "dx", "bx", "sp", "bp", "si", "di" };
     43 static const char* gReg32Names[] = { "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi" };
     44 
     45 static void DumpReg0(std::ostream& os, uint8_t /*rex*/, size_t reg,
     46                      bool byte_operand, uint8_t size_override) {
     47   DCHECK_LT(reg, 8u);
     48   // TODO: combine rex into size
     49   size_t size = byte_operand ? 1 : (size_override == 0x66 ? 2 : 4);
     50   switch (size) {
     51     case 1: os << gReg8Names[reg]; break;
     52     case 2: os << gReg16Names[reg]; break;
     53     case 4: os << gReg32Names[reg]; break;
     54     default: LOG(FATAL) << "unexpected size " << size;
     55   }
     56 }
     57 
     58 enum RegFile { GPR, MMX, SSE };
     59 
     60 static void DumpReg(std::ostream& os, uint8_t rex, uint8_t reg,
     61                     bool byte_operand, uint8_t size_override, RegFile reg_file) {
     62   size_t reg_num = reg;  // TODO: combine with REX.R on 64bit
     63   if (reg_file == GPR) {
     64     DumpReg0(os, rex, reg_num, byte_operand, size_override);
     65   } else if (reg_file == SSE) {
     66     os << "xmm" << reg_num;
     67   } else {
     68     os << "mm" << reg_num;
     69   }
     70 }
     71 
     72 static void DumpBaseReg(std::ostream& os, uint8_t rex, uint8_t reg) {
     73   size_t reg_num = reg;  // TODO: combine with REX.B on 64bit
     74   DumpReg0(os, rex, reg_num, false, 0);
     75 }
     76 
     77 static void DumpIndexReg(std::ostream& os, uint8_t rex, uint8_t reg) {
     78   int reg_num = reg;  // TODO: combine with REX.X on 64bit
     79   DumpReg0(os, rex, reg_num, false, 0);
     80 }
     81 
     82 enum SegmentPrefix {
     83   kCs = 0x2e,
     84   kSs = 0x36,
     85   kDs = 0x3e,
     86   kEs = 0x26,
     87   kFs = 0x64,
     88   kGs = 0x65,
     89 };
     90 
     91 static void DumpSegmentOverride(std::ostream& os, uint8_t segment_prefix) {
     92   switch (segment_prefix) {
     93     case kCs: os << "cs:"; break;
     94     case kSs: os << "ss:"; break;
     95     case kDs: os << "ds:"; break;
     96     case kEs: os << "es:"; break;
     97     case kFs: os << "fs:"; break;
     98     case kGs: os << "gs:"; break;
     99     default: break;
    100   }
    101 }
    102 
    103 size_t DisassemblerX86::DumpInstruction(std::ostream& os, const uint8_t* instr) {
    104   const uint8_t* begin_instr = instr;
    105   bool have_prefixes = true;
    106   uint8_t prefix[4] = {0, 0, 0, 0};
    107   const char** modrm_opcodes = NULL;
    108   do {
    109     switch (*instr) {
    110         // Group 1 - lock and repeat prefixes:
    111       case 0xF0:
    112       case 0xF2:
    113       case 0xF3:
    114         prefix[0] = *instr;
    115         break;
    116         // Group 2 - segment override prefixes:
    117       case kCs:
    118       case kSs:
    119       case kDs:
    120       case kEs:
    121       case kFs:
    122       case kGs:
    123         prefix[1] = *instr;
    124         break;
    125         // Group 3 - operand size override:
    126       case 0x66:
    127         prefix[2] = *instr;
    128         break;
    129         // Group 4 - address size override:
    130       case 0x67:
    131         prefix[3] = *instr;
    132         break;
    133       default:
    134         have_prefixes = false;
    135         break;
    136     }
    137     if (have_prefixes) {
    138       instr++;
    139     }
    140   } while (have_prefixes);
    141   uint8_t rex = (*instr >= 0x40 && *instr <= 0x4F) ? *instr : 0;
    142   bool has_modrm = false;
    143   bool reg_is_opcode = false;
    144   size_t immediate_bytes = 0;
    145   size_t branch_bytes = 0;
    146   std::ostringstream opcode;
    147   bool store = false;  // stores to memory (ie rm is on the left)
    148   bool load = false;  // loads from memory (ie rm is on the right)
    149   bool byte_operand = false;
    150   bool ax = false;  // implicit use of ax
    151   bool cx = false;  // implicit use of cx
    152   bool reg_in_opcode = false;  // low 3-bits of opcode encode register parameter
    153   bool no_ops = false;
    154   RegFile src_reg_file = GPR;
    155   RegFile dst_reg_file = GPR;
    156   switch (*instr) {
    157 #define DISASSEMBLER_ENTRY(opname, \
    158                      rm8_r8, rm32_r32, \
    159                      r8_rm8, r32_rm32, \
    160                      ax8_i8, ax32_i32) \
    161   case rm8_r8:   opcode << #opname; store = true; has_modrm = true; byte_operand = true; break; \
    162   case rm32_r32: opcode << #opname; store = true; has_modrm = true; break; \
    163   case r8_rm8:   opcode << #opname; load = true; has_modrm = true; byte_operand = true; break; \
    164   case r32_rm32: opcode << #opname; load = true; has_modrm = true; break; \
    165   case ax8_i8:   opcode << #opname; ax = true; immediate_bytes = 1; byte_operand = true; break; \
    166   case ax32_i32: opcode << #opname; ax = true; immediate_bytes = 4; break;
    167 
    168 DISASSEMBLER_ENTRY(add,
    169   0x00 /* RegMem8/Reg8 */,     0x01 /* RegMem32/Reg32 */,
    170   0x02 /* Reg8/RegMem8 */,     0x03 /* Reg32/RegMem32 */,
    171   0x04 /* Rax8/imm8 opcode */, 0x05 /* Rax32/imm32 */)
    172 DISASSEMBLER_ENTRY(or,
    173   0x08 /* RegMem8/Reg8 */,     0x09 /* RegMem32/Reg32 */,
    174   0x0A /* Reg8/RegMem8 */,     0x0B /* Reg32/RegMem32 */,
    175   0x0C /* Rax8/imm8 opcode */, 0x0D /* Rax32/imm32 */)
    176 DISASSEMBLER_ENTRY(adc,
    177   0x10 /* RegMem8/Reg8 */,     0x11 /* RegMem32/Reg32 */,
    178   0x12 /* Reg8/RegMem8 */,     0x13 /* Reg32/RegMem32 */,
    179   0x14 /* Rax8/imm8 opcode */, 0x15 /* Rax32/imm32 */)
    180 DISASSEMBLER_ENTRY(sbb,
    181   0x18 /* RegMem8/Reg8 */,     0x19 /* RegMem32/Reg32 */,
    182   0x1A /* Reg8/RegMem8 */,     0x1B /* Reg32/RegMem32 */,
    183   0x1C /* Rax8/imm8 opcode */, 0x1D /* Rax32/imm32 */)
    184 DISASSEMBLER_ENTRY(and,
    185   0x20 /* RegMem8/Reg8 */,     0x21 /* RegMem32/Reg32 */,
    186   0x22 /* Reg8/RegMem8 */,     0x23 /* Reg32/RegMem32 */,
    187   0x24 /* Rax8/imm8 opcode */, 0x25 /* Rax32/imm32 */)
    188 DISASSEMBLER_ENTRY(sub,
    189   0x28 /* RegMem8/Reg8 */,     0x29 /* RegMem32/Reg32 */,
    190   0x2A /* Reg8/RegMem8 */,     0x2B /* Reg32/RegMem32 */,
    191   0x2C /* Rax8/imm8 opcode */, 0x2D /* Rax32/imm32 */)
    192 DISASSEMBLER_ENTRY(xor,
    193   0x30 /* RegMem8/Reg8 */,     0x31 /* RegMem32/Reg32 */,
    194   0x32 /* Reg8/RegMem8 */,     0x33 /* Reg32/RegMem32 */,
    195   0x34 /* Rax8/imm8 opcode */, 0x35 /* Rax32/imm32 */)
    196 DISASSEMBLER_ENTRY(cmp,
    197   0x38 /* RegMem8/Reg8 */,     0x39 /* RegMem32/Reg32 */,
    198   0x3A /* Reg8/RegMem8 */,     0x3B /* Reg32/RegMem32 */,
    199   0x3C /* Rax8/imm8 opcode */, 0x3D /* Rax32/imm32 */)
    200 
    201 #undef DISASSEMBLER_ENTRY
    202   case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57:
    203     opcode << "push";
    204     reg_in_opcode = true;
    205     break;
    206   case 0x58: case 0x59: case 0x5A: case 0x5B: case 0x5C: case 0x5D: case 0x5E: case 0x5F:
    207     opcode << "pop";
    208     reg_in_opcode = true;
    209     break;
    210   case 0x68: opcode << "push"; immediate_bytes = 4; break;
    211   case 0x6A: opcode << "push"; immediate_bytes = 1; break;
    212   case 0x70: case 0x71: case 0x72: case 0x73: case 0x74: case 0x75: case 0x76: case 0x77:
    213   case 0x78: case 0x79: case 0x7A: case 0x7B: case 0x7C: case 0x7D: case 0x7E: case 0x7F:
    214     static const char* condition_codes[] =
    215     {"o", "no", "b/nae/c", "nb/ae/nc", "z/eq",  "nz/ne", "be/na", "nbe/a",
    216      "s", "ns", "p/pe",    "np/po",    "l/nge", "nl/ge", "le/ng", "nle/g"
    217     };
    218     opcode << "j" << condition_codes[*instr & 0xF];
    219     branch_bytes = 1;
    220     break;
    221   case 0x88: opcode << "mov"; store = true; has_modrm = true; byte_operand = true; break;
    222   case 0x89: opcode << "mov"; store = true; has_modrm = true; break;
    223   case 0x8A: opcode << "mov"; load = true; has_modrm = true; byte_operand = true; break;
    224   case 0x8B: opcode << "mov"; load = true; has_modrm = true; break;
    225 
    226   case 0x0F:  // 2 byte extended opcode
    227     instr++;
    228     switch (*instr) {
    229       case 0x10: case 0x11:
    230         if (prefix[0] == 0xF2) {
    231           opcode << "movsd";
    232           prefix[0] = 0;  // clear prefix now it's served its purpose as part of the opcode
    233         } else if (prefix[0] == 0xF3) {
    234           opcode << "movss";
    235           prefix[0] = 0;  // clear prefix now it's served its purpose as part of the opcode
    236         } else if (prefix[2] == 0x66) {
    237           opcode << "movupd";
    238           prefix[2] = 0;  // clear prefix now it's served its purpose as part of the opcode
    239         } else {
    240           opcode << "movups";
    241         }
    242         has_modrm = true;
    243         src_reg_file = dst_reg_file = SSE;
    244         load = *instr == 0x10;
    245         store = !load;
    246         break;
    247       case 0x2A:
    248         if (prefix[2] == 0x66) {
    249           opcode << "cvtpi2pd";
    250           prefix[2] = 0;  // clear prefix now it's served its purpose as part of the opcode
    251         } else if (prefix[0] == 0xF2) {
    252           opcode << "cvtsi2sd";
    253           prefix[0] = 0;  // clear prefix now it's served its purpose as part of the opcode
    254         } else if (prefix[0] == 0xF3) {
    255           opcode << "cvtsi2ss";
    256           prefix[0] = 0;  // clear prefix now it's served its purpose as part of the opcode
    257         } else {
    258           opcode << "cvtpi2ps";
    259         }
    260         load = true;
    261         has_modrm = true;
    262         dst_reg_file = SSE;
    263         break;
    264       case 0x2C:
    265         if (prefix[2] == 0x66) {
    266           opcode << "cvttpd2pi";
    267           prefix[2] = 0;  // clear prefix now it's served its purpose as part of the opcode
    268         } else if (prefix[0] == 0xF2) {
    269           opcode << "cvttsd2si";
    270           prefix[0] = 0;  // clear prefix now it's served its purpose as part of the opcode
    271         } else if (prefix[0] == 0xF3) {
    272           opcode << "cvttss2si";
    273           prefix[0] = 0;  // clear prefix now it's served its purpose as part of the opcode
    274         } else {
    275           opcode << "cvttps2pi";
    276         }
    277         load = true;
    278         has_modrm = true;
    279         src_reg_file = SSE;
    280         break;
    281       case 0x2D:
    282         if (prefix[2] == 0x66) {
    283           opcode << "cvtpd2pi";
    284           prefix[2] = 0;  // clear prefix now it's served its purpose as part of the opcode
    285         } else if (prefix[0] == 0xF2) {
    286           opcode << "cvtsd2si";
    287           prefix[0] = 0;  // clear prefix now it's served its purpose as part of the opcode
    288         } else if (prefix[0] == 0xF3) {
    289           opcode << "cvtss2si";
    290           prefix[0] = 0;  // clear prefix now it's served its purpose as part of the opcode
    291         } else {
    292           opcode << "cvtps2pi";
    293         }
    294         load = true;
    295         has_modrm = true;
    296         src_reg_file = SSE;
    297         break;
    298       case 0x2E:
    299         opcode << "u";
    300         // FALLTHROUGH
    301       case 0x2F:
    302         if (prefix[2] == 0x66) {
    303           opcode << "comisd";
    304           prefix[2] = 0;  // clear prefix now it's served its purpose as part of the opcode
    305         } else {
    306           opcode << "comiss";
    307         }
    308         has_modrm = true;
    309         load = true;
    310         src_reg_file = dst_reg_file = SSE;
    311         break;
    312       case 0x38:  // 3 byte extended opcode
    313         opcode << StringPrintf("unknown opcode '0F 38 %02X'", *instr);
    314         break;
    315       case 0x3A:  // 3 byte extended opcode
    316         opcode << StringPrintf("unknown opcode '0F 3A %02X'", *instr);
    317         break;
    318       case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57:
    319       case 0x58: case 0x59: case 0x5C: case 0x5D: case 0x5E: case 0x5F: {
    320         switch (*instr) {
    321           case 0x50: opcode << "movmsk"; break;
    322           case 0x51: opcode << "sqrt"; break;
    323           case 0x52: opcode << "rsqrt"; break;
    324           case 0x53: opcode << "rcp"; break;
    325           case 0x54: opcode << "and"; break;
    326           case 0x55: opcode << "andn"; break;
    327           case 0x56: opcode << "or"; break;
    328           case 0x57: opcode << "xor"; break;
    329           case 0x58: opcode << "add"; break;
    330           case 0x59: opcode << "mul"; break;
    331           case 0x5C: opcode << "sub"; break;
    332           case 0x5D: opcode << "min"; break;
    333           case 0x5E: opcode << "div"; break;
    334           case 0x5F: opcode << "max"; break;
    335           default: LOG(FATAL) << "Unreachable";
    336         }
    337         if (prefix[2] == 0x66) {
    338           opcode << "pd";
    339           prefix[2] = 0;  // clear prefix now it's served its purpose as part of the opcode
    340         } else if (prefix[0] == 0xF2) {
    341           opcode << "sd";
    342           prefix[0] = 0;  // clear prefix now it's served its purpose as part of the opcode
    343         } else if (prefix[0] == 0xF3) {
    344           opcode << "ss";
    345           prefix[0] = 0;  // clear prefix now it's served its purpose as part of the opcode
    346         } else {
    347           opcode << "ps";
    348         }
    349         load = true;
    350         has_modrm = true;
    351         src_reg_file = dst_reg_file = SSE;
    352         break;
    353       }
    354       case 0x5A:
    355         if (prefix[2] == 0x66) {
    356           opcode << "cvtpd2ps";
    357           prefix[2] = 0;  // clear prefix now it's served its purpose as part of the opcode
    358         } else if (prefix[0] == 0xF2) {
    359           opcode << "cvtsd2ss";
    360           prefix[0] = 0;  // clear prefix now it's served its purpose as part of the opcode
    361         } else if (prefix[0] == 0xF3) {
    362           opcode << "cvtss2sd";
    363           prefix[0] = 0;  // clear prefix now it's served its purpose as part of the opcode
    364         } else {
    365           opcode << "cvtps2pd";
    366         }
    367         load = true;
    368         has_modrm = true;
    369         src_reg_file = dst_reg_file = SSE;
    370         break;
    371       case 0x5B:
    372         if (prefix[2] == 0x66) {
    373           opcode << "cvtps2dq";
    374           prefix[2] = 0;  // clear prefix now it's served its purpose as part of the opcode
    375         } else if (prefix[0] == 0xF2) {
    376           opcode << "bad opcode F2 0F 5B";
    377         } else if (prefix[0] == 0xF3) {
    378           opcode << "cvttps2dq";
    379           prefix[0] = 0;  // clear prefix now it's served its purpose as part of the opcode
    380         } else {
    381           opcode << "cvtdq2ps";
    382         }
    383         load = true;
    384         has_modrm = true;
    385         src_reg_file = dst_reg_file = SSE;
    386         break;
    387       case 0x6E:
    388         if (prefix[2] == 0x66) {
    389           dst_reg_file = SSE;
    390           prefix[2] = 0;  // clear prefix now it's served its purpose as part of the opcode
    391         } else {
    392           dst_reg_file = MMX;
    393         }
    394         opcode << "movd";
    395         load = true;
    396         has_modrm = true;
    397         break;
    398       case 0x6F:
    399         if (prefix[2] == 0x66) {
    400           dst_reg_file = SSE;
    401           opcode << "movdqa";
    402           prefix[2] = 0;  // clear prefix now it's served its purpose as part of the opcode
    403         } else if (prefix[0] == 0xF3) {
    404           dst_reg_file = SSE;
    405           opcode << "movdqu";
    406           prefix[0] = 0;  // clear prefix now it's served its purpose as part of the opcode
    407         } else {
    408           dst_reg_file = MMX;
    409           opcode << "movq";
    410         }
    411         load = true;
    412         has_modrm = true;
    413         break;
    414       case 0x71:
    415         if (prefix[2] == 0x66) {
    416           dst_reg_file = SSE;
    417           prefix[2] = 0;  // clear prefix now it's served its purpose as part of the opcode
    418         } else {
    419           dst_reg_file = MMX;
    420         }
    421         static const char* x71_opcodes[] = {"unknown-71", "unknown-71", "psrlw", "unknown-71", "psraw", "unknown-71", "psllw", "unknown-71"};
    422         modrm_opcodes = x71_opcodes;
    423         reg_is_opcode = true;
    424         has_modrm = true;
    425         store = true;
    426         immediate_bytes = 1;
    427         break;
    428       case 0x72:
    429         if (prefix[2] == 0x66) {
    430           dst_reg_file = SSE;
    431           prefix[2] = 0;  // clear prefix now it's served its purpose as part of the opcode
    432         } else {
    433           dst_reg_file = MMX;
    434         }
    435         static const char* x72_opcodes[] = {"unknown-72", "unknown-72", "psrld", "unknown-72", "psrad", "unknown-72", "pslld", "unknown-72"};
    436         modrm_opcodes = x72_opcodes;
    437         reg_is_opcode = true;
    438         has_modrm = true;
    439         store = true;
    440         immediate_bytes = 1;
    441         break;
    442       case 0x73:
    443         if (prefix[2] == 0x66) {
    444           dst_reg_file = SSE;
    445           prefix[2] = 0;  // clear prefix now it's served its purpose as part of the opcode
    446         } else {
    447           dst_reg_file = MMX;
    448         }
    449         static const char* x73_opcodes[] = {"unknown-73", "unknown-73", "psrlq", "unknown-73", "unknown-73", "unknown-73", "psllq", "unknown-73"};
    450         modrm_opcodes = x73_opcodes;
    451         reg_is_opcode = true;
    452         has_modrm = true;
    453         store = true;
    454         immediate_bytes = 1;
    455         break;
    456       case 0x7E:
    457         if (prefix[2] == 0x66) {
    458           src_reg_file = SSE;
    459           prefix[2] = 0;  // clear prefix now it's served its purpose as part of the opcode
    460         } else {
    461           src_reg_file = MMX;
    462         }
    463         opcode << "movd";
    464         has_modrm = true;
    465         store = true;
    466         break;
    467       case 0x80: case 0x81: case 0x82: case 0x83: case 0x84: case 0x85: case 0x86: case 0x87:
    468       case 0x88: case 0x89: case 0x8A: case 0x8B: case 0x8C: case 0x8D: case 0x8E: case 0x8F:
    469         opcode << "j" << condition_codes[*instr & 0xF];
    470         branch_bytes = 4;
    471         break;
    472       case 0x90: case 0x91: case 0x92: case 0x93: case 0x94: case 0x95: case 0x96: case 0x97:
    473       case 0x98: case 0x99: case 0x9A: case 0x9B: case 0x9C: case 0x9D: case 0x9E: case 0x9F:
    474         opcode << "set" << condition_codes[*instr & 0xF];
    475         modrm_opcodes = NULL;
    476         reg_is_opcode = true;
    477         has_modrm = true;
    478         store = true;
    479         break;
    480       case 0xAE:
    481         if (prefix[0] == 0xF3) {
    482           prefix[0] = 0;  // clear prefix now it's served its purpose as part of the opcode
    483           static const char* xAE_opcodes[] = {"rdfsbase", "rdgsbase", "wrfsbase", "wrgsbase", "unknown-AE", "unknown-AE", "unknown-AE", "unknown-AE"};
    484           modrm_opcodes = xAE_opcodes;
    485           reg_is_opcode = true;
    486           has_modrm = true;
    487           uint8_t reg_or_opcode = (instr[1] >> 3) & 7;
    488           switch (reg_or_opcode) {
    489             case 0:
    490               prefix[1] = kFs;
    491               load = true;
    492               break;
    493             case 1:
    494               prefix[1] = kGs;
    495               load = true;
    496               break;
    497             case 2:
    498               prefix[1] = kFs;
    499               store = true;
    500               break;
    501             case 3:
    502               prefix[1] = kGs;
    503               store = true;
    504               break;
    505             default:
    506               load = true;
    507               break;
    508           }
    509         } else {
    510           static const char* xAE_opcodes[] = {"unknown-AE", "unknown-AE", "unknown-AE", "unknown-AE", "unknown-AE", "lfence", "mfence", "sfence"};
    511           modrm_opcodes = xAE_opcodes;
    512           reg_is_opcode = true;
    513           has_modrm = true;
    514           load = true;
    515           no_ops = true;
    516         }
    517         break;
    518       case 0xB1: opcode << "cmpxchg"; has_modrm = true; store = true; break;
    519       case 0xB6: opcode << "movzxb"; has_modrm = true; load = true; break;
    520       case 0xB7: opcode << "movzxw"; has_modrm = true; load = true; break;
    521       case 0xBE: opcode << "movsxb"; has_modrm = true; load = true; break;
    522       case 0xBF: opcode << "movsxw"; has_modrm = true; load = true; break;
    523       default:
    524         opcode << StringPrintf("unknown opcode '0F %02X'", *instr);
    525         break;
    526     }
    527     break;
    528   case 0x80: case 0x81: case 0x82: case 0x83:
    529     static const char* x80_opcodes[] = {"add", "or", "adc", "sbb", "and", "sub", "xor", "cmp"};
    530     modrm_opcodes = x80_opcodes;
    531     has_modrm = true;
    532     reg_is_opcode = true;
    533     store = true;
    534     byte_operand = (*instr & 1) == 0;
    535     immediate_bytes = *instr == 0x81 ? 4 : 1;
    536     break;
    537   case 0x84: case 0x85:
    538     opcode << "test";
    539     has_modrm = true;
    540     load = true;
    541     byte_operand = (*instr & 1) == 0;
    542     break;
    543   case 0x8D:
    544     opcode << "lea";
    545     has_modrm = true;
    546     load = true;
    547     break;
    548   case 0x8F:
    549     opcode << "pop";
    550     has_modrm = true;
    551     reg_is_opcode = true;
    552     store = true;
    553     break;
    554   case 0xB0: case 0xB1: case 0xB2: case 0xB3: case 0xB4: case 0xB5: case 0xB6: case 0xB7:
    555     opcode << "mov";
    556     immediate_bytes = 1;
    557     reg_in_opcode = true;
    558     break;
    559   case 0xB8: case 0xB9: case 0xBA: case 0xBB: case 0xBC: case 0xBD: case 0xBE: case 0xBF:
    560     opcode << "mov";
    561     immediate_bytes = 4;
    562     reg_in_opcode = true;
    563     break;
    564   case 0xC0: case 0xC1:
    565   case 0xD0: case 0xD1: case 0xD2: case 0xD3:
    566     static const char* shift_opcodes[] =
    567         {"rol", "ror", "rcl", "rcr", "shl", "shr", "unknown-shift", "sar"};
    568     modrm_opcodes = shift_opcodes;
    569     has_modrm = true;
    570     reg_is_opcode = true;
    571     store = true;
    572     immediate_bytes = ((*instr & 0xf0) == 0xc0) ? 1 : 0;
    573     cx = (*instr == 0xD2) || (*instr == 0xD3);
    574     byte_operand = (*instr == 0xC0);
    575     break;
    576   case 0xC3: opcode << "ret"; break;
    577   case 0xC7:
    578     static const char* c7_opcodes[] = {"mov", "unknown-c7", "unknown-c7", "unknown-c7", "unknown-c7", "unknown-c7", "unknown-c7", "unknown-c7"};
    579     modrm_opcodes = c7_opcodes;
    580     store = true;
    581     immediate_bytes = 4;
    582     has_modrm = true;
    583     reg_is_opcode = true;
    584     break;
    585   case 0xCC: opcode << "int 3"; break;
    586   case 0xE8: opcode << "call"; branch_bytes = 4; break;
    587   case 0xE9: opcode << "jmp"; branch_bytes = 4; break;
    588   case 0xEB: opcode << "jmp"; branch_bytes = 1; break;
    589   case 0xF5: opcode << "cmc"; break;
    590   case 0xF6: case 0xF7:
    591     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 /"};
    592     modrm_opcodes = f7_opcodes;
    593     has_modrm = true;
    594     reg_is_opcode = true;
    595     store = true;
    596     immediate_bytes = ((instr[1] & 0x38) == 0) ? 1 : 0;
    597     break;
    598   case 0xFF:
    599     static const char* ff_opcodes[] = {"inc", "dec", "call", "call", "jmp", "jmp", "push", "unknown-ff"};
    600     modrm_opcodes = ff_opcodes;
    601     has_modrm = true;
    602     reg_is_opcode = true;
    603     load = true;
    604     break;
    605   default:
    606     opcode << StringPrintf("unknown opcode '%02X'", *instr);
    607     break;
    608   }
    609   std::ostringstream args;
    610   if (reg_in_opcode) {
    611     DCHECK(!has_modrm);
    612     DumpReg(args, rex, *instr & 0x7, false, prefix[2], GPR);
    613   }
    614   instr++;
    615   uint32_t address_bits = 0;
    616   if (has_modrm) {
    617     uint8_t modrm = *instr;
    618     instr++;
    619     uint8_t mod = modrm >> 6;
    620     uint8_t reg_or_opcode = (modrm >> 3) & 7;
    621     uint8_t rm = modrm & 7;
    622     std::ostringstream address;
    623     if (mod == 0 && rm == 5) {  // fixed address
    624       address_bits = *reinterpret_cast<const uint32_t*>(instr);
    625       address << StringPrintf("[0x%x]", address_bits);
    626       instr += 4;
    627     } else if (rm == 4 && mod != 3) {  // SIB
    628       uint8_t sib = *instr;
    629       instr++;
    630       uint8_t ss = (sib >> 6) & 3;
    631       uint8_t index = (sib >> 3) & 7;
    632       uint8_t base = sib & 7;
    633       address << "[";
    634       if (base != 5 || mod != 0) {
    635         DumpBaseReg(address, rex, base);
    636         if (index != 4) {
    637           address << " + ";
    638         }
    639       }
    640       if (index != 4) {
    641         DumpIndexReg(address, rex, index);
    642         if (ss != 0) {
    643           address << StringPrintf(" * %d", 1 << ss);
    644         }
    645       }
    646       if (mod == 1) {
    647         address << StringPrintf(" + %d", *reinterpret_cast<const int8_t*>(instr));
    648         instr++;
    649       } else if (mod == 2) {
    650         address << StringPrintf(" + %d", *reinterpret_cast<const int32_t*>(instr));
    651         instr += 4;
    652       }
    653       address << "]";
    654     } else {
    655       if (mod == 3) {
    656         if (!no_ops) {
    657           DumpReg(address, rex, rm, byte_operand, prefix[2], load ? src_reg_file : dst_reg_file);
    658         }
    659       } else {
    660         address << "[";
    661         DumpBaseReg(address, rex, rm);
    662         if (mod == 1) {
    663           address << StringPrintf(" + %d", *reinterpret_cast<const int8_t*>(instr));
    664           instr++;
    665         } else if (mod == 2) {
    666           address << StringPrintf(" + %d", *reinterpret_cast<const int32_t*>(instr));
    667           instr += 4;
    668         }
    669         address << "]";
    670       }
    671     }
    672 
    673     if (reg_is_opcode && modrm_opcodes != NULL) {
    674       opcode << modrm_opcodes[reg_or_opcode];
    675     }
    676     if (load) {
    677       if (!reg_is_opcode) {
    678         DumpReg(args, rex, reg_or_opcode, byte_operand, prefix[2], dst_reg_file);
    679         args << ", ";
    680       }
    681       DumpSegmentOverride(args, prefix[1]);
    682       args << address.str();
    683     } else {
    684       DCHECK(store);
    685       DumpSegmentOverride(args, prefix[1]);
    686       args << address.str();
    687       if (!reg_is_opcode) {
    688         args << ", ";
    689         DumpReg(args, rex, reg_or_opcode, byte_operand, prefix[2], src_reg_file);
    690       }
    691     }
    692   }
    693   if (ax) {
    694     // If this opcode implicitly uses ax, ax is always the first arg.
    695     DumpReg(args, rex, 0 /* EAX */, byte_operand, prefix[2], GPR);
    696   }
    697   if (cx) {
    698     args << ", ";
    699     DumpReg(args, rex, 1 /* ECX */, true, prefix[2], GPR);
    700   }
    701   if (immediate_bytes > 0) {
    702     if (has_modrm || reg_in_opcode || ax || cx) {
    703       args << ", ";
    704     }
    705     if (immediate_bytes == 1) {
    706       args << StringPrintf("%d", *reinterpret_cast<const int8_t*>(instr));
    707       instr++;
    708     } else {
    709       CHECK_EQ(immediate_bytes, 4u);
    710       args << StringPrintf("%d", *reinterpret_cast<const int32_t*>(instr));
    711       instr += 4;
    712     }
    713   } else if (branch_bytes > 0) {
    714     DCHECK(!has_modrm);
    715     int32_t displacement;
    716     if (branch_bytes == 1) {
    717       displacement = *reinterpret_cast<const int8_t*>(instr);
    718       instr++;
    719     } else {
    720       CHECK_EQ(branch_bytes, 4u);
    721       displacement = *reinterpret_cast<const int32_t*>(instr);
    722       instr += 4;
    723     }
    724     args << StringPrintf("%+d (%p)", displacement, instr + displacement);
    725   }
    726   if (prefix[1] == kFs) {
    727     args << "  ; ";
    728     Thread::DumpThreadOffset(args, address_bits, 4);
    729   }
    730   std::stringstream hex;
    731   for (size_t i = 0; begin_instr + i < instr; ++i) {
    732     hex << StringPrintf("%02X", begin_instr[i]);
    733   }
    734   std::stringstream prefixed_opcode;
    735   switch (prefix[0]) {
    736     case 0xF0: prefixed_opcode << "lock "; break;
    737     case 0xF2: prefixed_opcode << "repne "; break;
    738     case 0xF3: prefixed_opcode << "repe "; break;
    739     case 0: break;
    740     default: LOG(FATAL) << "Unreachable";
    741   }
    742   prefixed_opcode << opcode.str();
    743   os << StringPrintf("%p: %22s    \t%-7s ", begin_instr, hex.str().c_str(),
    744                      prefixed_opcode.str().c_str())
    745      << args.str() << '\n';
    746   return instr - begin_instr;
    747 }  // NOLINT(readability/fn_size)
    748 
    749 }  // namespace x86
    750 }  // namespace art
    751