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 
Dump(std::ostream & os,const uint8_t * begin)29 size_t DisassemblerX86::Dump(std::ostream& os, const uint8_t* begin) {
30   return DumpInstruction(os, begin);
31 }
32 
Dump(std::ostream & os,const uint8_t * begin,const uint8_t * end)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 
DumpReg0(std::ostream & os,uint8_t rex,size_t reg,bool byte_operand,uint8_t size_override)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 
DumpAnyReg(std::ostream & os,uint8_t rex,size_t reg,bool byte_operand,uint8_t size_override,RegFile reg_file)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 
DumpReg(std::ostream & os,uint8_t rex,uint8_t reg,bool byte_operand,uint8_t size_override,RegFile reg_file)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 
DumpRmReg(std::ostream & os,uint8_t rex,uint8_t reg,bool byte_operand,uint8_t size_override,RegFile reg_file)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 
DumpAddrReg(std::ostream & os,uint8_t rex,uint8_t reg)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 
DumpBaseReg(std::ostream & os,uint8_t rex,uint8_t reg)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 
DumpIndexReg(std::ostream & os,uint8_t rex,uint8_t reg)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 
DumpOpcodeReg(std::ostream & os,uint8_t rex,uint8_t reg,bool byte_operand,uint8_t size_override)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 
DumpSegmentOverride(std::ostream & os,uint8_t segment_prefix)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 
DumpInstruction(std::ostream & os,const uint8_t * instr)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