832241f2cdb366d160433a654103f5284a44e224
[platform/upstream/elfutils.git] / libcpu / i386_disasm.c
1 /* Disassembler for x86.
2    Copyright (C) 2007, 2008, 2009, 2011 Red Hat, Inc.
3    This file is part of elfutils.
4    Written by Ulrich Drepper <drepper@redhat.com>, 2007.
5
6    This file is free software; you can redistribute it and/or modify
7    it under the terms of either
8
9      * the GNU Lesser General Public License as published by the Free
10        Software Foundation; either version 3 of the License, or (at
11        your option) any later version
12
13    or
14
15      * the GNU General Public License as published by the Free
16        Software Foundation; either version 2 of the License, or (at
17        your option) any later version
18
19    or both in parallel, as here.
20
21    elfutils is distributed in the hope that it will be useful, but
22    WITHOUT ANY WARRANTY; without even the implied warranty of
23    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
24    General Public License for more details.
25
26    You should have received copies of the GNU General Public License and
27    the GNU Lesser General Public License along with this program.  If
28    not, see <http://www.gnu.org/licenses/>.  */
29
30 #ifdef HAVE_CONFIG_H
31 # include <config.h>
32 #endif
33
34 #include <assert.h>
35 #include <config.h>
36 #include <ctype.h>
37 #include <endian.h>
38 #include <errno.h>
39 #include <gelf.h>
40 #include <stddef.h>
41 #include <stdint.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <sys/param.h>
45
46 #include "../libebl/libeblP.h"
47
48 #define MACHINE_ENCODING __LITTLE_ENDIAN
49 #include "memory-access.h"
50
51
52 #ifndef MNEFILE
53 # define MNEFILE "i386.mnemonics"
54 #endif
55
56 #define MNESTRFIELD(line) MNESTRFIELD1 (line)
57 #define MNESTRFIELD1(line) str##line
58 static const union mnestr_t
59 {
60   struct
61   {
62 #define MNE(name) char MNESTRFIELD (__LINE__)[sizeof (#name)];
63 #include MNEFILE
64 #undef MNE
65   };
66   char str[0];
67 } mnestr =
68   {
69     {
70 #define MNE(name) #name,
71 #include MNEFILE
72 #undef MNE
73     }
74   };
75
76 /* The index can be stored in the instrtab.  */
77 enum
78   {
79 #define MNE(name) MNE_##name,
80 #include MNEFILE
81 #undef MNE
82     MNE_INVALID
83   };
84
85 static const unsigned short int mneidx[] =
86   {
87 #define MNE(name) \
88   [MNE_##name] = offsetof (union mnestr_t, MNESTRFIELD (__LINE__)),
89 #include MNEFILE
90 #undef MNE
91   };
92
93
94 enum
95   {
96     idx_rex_b = 0,
97     idx_rex_x,
98     idx_rex_r,
99     idx_rex_w,
100     idx_rex,
101     idx_cs,
102     idx_ds,
103     idx_es,
104     idx_fs,
105     idx_gs,
106     idx_ss,
107     idx_data16,
108     idx_addr16,
109     idx_rep,
110     idx_repne,
111     idx_lock
112   };
113
114 enum
115   {
116 #define prefbit(pref) has_##pref = 1 << idx_##pref
117     prefbit (rex_b),
118     prefbit (rex_x),
119     prefbit (rex_r),
120     prefbit (rex_w),
121     prefbit (rex),
122     prefbit (cs),
123     prefbit (ds),
124     prefbit (es),
125     prefbit (fs),
126     prefbit (gs),
127     prefbit (ss),
128     prefbit (data16),
129     prefbit (addr16),
130     prefbit (rep),
131     prefbit (repne),
132     prefbit (lock)
133 #undef prefbit
134   };
135 #define SEGMENT_PREFIXES \
136   (has_cs | has_ds | has_es | has_fs | has_gs | has_ss)
137
138 #define prefix_cs       0x2e
139 #define prefix_ds       0x3e
140 #define prefix_es       0x26
141 #define prefix_fs       0x64
142 #define prefix_gs       0x65
143 #define prefix_ss       0x36
144 #define prefix_data16   0x66
145 #define prefix_addr16   0x67
146 #define prefix_rep      0xf3
147 #define prefix_repne    0xf2
148 #define prefix_lock     0xf0
149
150
151 static const uint8_t known_prefixes[] =
152   {
153 #define newpref(pref) [idx_##pref] = prefix_##pref
154     newpref (cs),
155     newpref (ds),
156     newpref (es),
157     newpref (fs),
158     newpref (gs),
159     newpref (ss),
160     newpref (data16),
161     newpref (addr16),
162     newpref (rep),
163     newpref (repne),
164     newpref (lock)
165 #undef newpref
166   };
167 #define nknown_prefixes (sizeof (known_prefixes) / sizeof (known_prefixes[0]))
168
169
170 #if 0
171 static const char *prefix_str[] =
172   {
173 #define newpref(pref) [idx_##pref] = #pref
174     newpref (cs),
175     newpref (ds),
176     newpref (es),
177     newpref (fs),
178     newpref (gs),
179     newpref (ss),
180     newpref (data16),
181     newpref (addr16),
182     newpref (rep),
183     newpref (repne),
184     newpref (lock)
185 #undef newpref
186   };
187 #endif
188
189
190 static const char amd3dnowstr[] =
191 #define MNE_3DNOW_PAVGUSB 1
192   "pavgusb\0"
193 #define MNE_3DNOW_PFADD (MNE_3DNOW_PAVGUSB + 8)
194   "pfadd\0"
195 #define MNE_3DNOW_PFSUB (MNE_3DNOW_PFADD + 6)
196   "pfsub\0"
197 #define MNE_3DNOW_PFSUBR (MNE_3DNOW_PFSUB + 6)
198   "pfsubr\0"
199 #define MNE_3DNOW_PFACC (MNE_3DNOW_PFSUBR + 7)
200   "pfacc\0"
201 #define MNE_3DNOW_PFCMPGE (MNE_3DNOW_PFACC + 6)
202   "pfcmpge\0"
203 #define MNE_3DNOW_PFCMPGT (MNE_3DNOW_PFCMPGE + 8)
204   "pfcmpgt\0"
205 #define MNE_3DNOW_PFCMPEQ (MNE_3DNOW_PFCMPGT + 8)
206   "pfcmpeq\0"
207 #define MNE_3DNOW_PFMIN (MNE_3DNOW_PFCMPEQ + 8)
208   "pfmin\0"
209 #define MNE_3DNOW_PFMAX (MNE_3DNOW_PFMIN + 6)
210   "pfmax\0"
211 #define MNE_3DNOW_PI2FD (MNE_3DNOW_PFMAX + 6)
212   "pi2fd\0"
213 #define MNE_3DNOW_PF2ID (MNE_3DNOW_PI2FD + 6)
214   "pf2id\0"
215 #define MNE_3DNOW_PFRCP (MNE_3DNOW_PF2ID + 6)
216   "pfrcp\0"
217 #define MNE_3DNOW_PFRSQRT (MNE_3DNOW_PFRCP + 6)
218   "pfrsqrt\0"
219 #define MNE_3DNOW_PFMUL (MNE_3DNOW_PFRSQRT + 8)
220   "pfmul\0"
221 #define MNE_3DNOW_PFRCPIT1 (MNE_3DNOW_PFMUL + 6)
222   "pfrcpit1\0"
223 #define MNE_3DNOW_PFRSQIT1 (MNE_3DNOW_PFRCPIT1 + 9)
224   "pfrsqit1\0"
225 #define MNE_3DNOW_PFRCPIT2 (MNE_3DNOW_PFRSQIT1 + 9)
226   "pfrcpit2\0"
227 #define MNE_3DNOW_PMULHRW (MNE_3DNOW_PFRCPIT2 + 9)
228   "pmulhrw";
229
230 #define AMD3DNOW_LOW_IDX 0x0d
231 #define AMD3DNOW_HIGH_IDX (sizeof (amd3dnow) + AMD3DNOW_LOW_IDX - 1)
232 #define AMD3DNOW_IDX(val) ((val) - AMD3DNOW_LOW_IDX)
233 static const unsigned char amd3dnow[] =
234   {
235     [AMD3DNOW_IDX (0xbf)] = MNE_3DNOW_PAVGUSB,
236     [AMD3DNOW_IDX (0x9e)] = MNE_3DNOW_PFADD,
237     [AMD3DNOW_IDX (0x9a)] = MNE_3DNOW_PFSUB,
238     [AMD3DNOW_IDX (0xaa)] = MNE_3DNOW_PFSUBR,
239     [AMD3DNOW_IDX (0xae)] = MNE_3DNOW_PFACC,
240     [AMD3DNOW_IDX (0x90)] = MNE_3DNOW_PFCMPGE,
241     [AMD3DNOW_IDX (0xa0)] = MNE_3DNOW_PFCMPGT,
242     [AMD3DNOW_IDX (0xb0)] = MNE_3DNOW_PFCMPEQ,
243     [AMD3DNOW_IDX (0x94)] = MNE_3DNOW_PFMIN,
244     [AMD3DNOW_IDX (0xa4)] = MNE_3DNOW_PFMAX,
245     [AMD3DNOW_IDX (0x0d)] = MNE_3DNOW_PI2FD,
246     [AMD3DNOW_IDX (0x1d)] = MNE_3DNOW_PF2ID,
247     [AMD3DNOW_IDX (0x96)] = MNE_3DNOW_PFRCP,
248     [AMD3DNOW_IDX (0x97)] = MNE_3DNOW_PFRSQRT,
249     [AMD3DNOW_IDX (0xb4)] = MNE_3DNOW_PFMUL,
250     [AMD3DNOW_IDX (0xa6)] = MNE_3DNOW_PFRCPIT1,
251     [AMD3DNOW_IDX (0xa7)] = MNE_3DNOW_PFRSQIT1,
252     [AMD3DNOW_IDX (0xb6)] = MNE_3DNOW_PFRCPIT2,
253     [AMD3DNOW_IDX (0xb7)] = MNE_3DNOW_PMULHRW
254   };
255
256
257 struct output_data
258 {
259   GElf_Addr addr;
260   int *prefixes;
261   size_t opoff1;
262   size_t opoff2;
263   size_t opoff3;
264   char *bufp;
265   size_t *bufcntp;
266   size_t bufsize;
267   const uint8_t *data;
268   const uint8_t **param_start;
269   const uint8_t *end;
270   char *labelbuf;
271   size_t labelbufsize;
272   enum
273     {
274       addr_none = 0,
275       addr_abs_symbolic,
276       addr_abs_always,
277       addr_rel_symbolic,
278       addr_rel_always
279     } symaddr_use;
280   GElf_Addr symaddr;
281 };
282
283
284 #ifndef DISFILE
285 # define DISFILE "i386_dis.h"
286 #endif
287 #include DISFILE
288
289
290 #define ADD_CHAR(ch) \
291   do {                                                                        \
292     if (unlikely (bufcnt == bufsize))                                         \
293       goto enomem;                                                            \
294     buf[bufcnt++] = (ch);                                                     \
295   } while (0)
296
297 #define ADD_STRING(str) \
298   do {                                                                        \
299     const char *_str0 = (str);                                                \
300     size_t _len0 = strlen (_str0);                                            \
301     ADD_NSTRING (_str0, _len0);                                               \
302   } while (0)
303
304 #define ADD_NSTRING(str, len) \
305   do {                                                                        \
306     const char *_str = (str);                                                 \
307     size_t _len = (len);                                                      \
308     if (unlikely (bufcnt + _len > bufsize))                                   \
309       goto enomem;                                                            \
310     memcpy (buf + bufcnt, _str, _len);                                        \
311     bufcnt += _len;                                                           \
312   } while (0)
313
314
315 int
316 i386_disasm (const uint8_t **startp, const uint8_t *end, GElf_Addr addr,
317              const char *fmt, DisasmOutputCB_t outcb, DisasmGetSymCB_t symcb,
318              void *outcbarg, void *symcbarg)
319 {
320   const char *save_fmt = fmt;
321
322 #define BUFSIZE 512
323   char initbuf[BUFSIZE];
324   int prefixes;
325   size_t bufcnt;
326   size_t bufsize = BUFSIZE;
327   char *buf = initbuf;
328   const uint8_t *param_start;
329
330   struct output_data output_data =
331     {
332       .prefixes = &prefixes,
333       .bufp = buf,
334       .bufsize = bufsize,
335       .bufcntp = &bufcnt,
336       .param_start = &param_start,
337       .end = end
338     };
339
340   int retval = 0;
341   while (1)
342     {
343       prefixes = 0;
344
345       const uint8_t *data = *startp;
346       const uint8_t *begin = data;
347
348       /* Recognize all prefixes.  */
349       int last_prefix_bit = 0;
350       while (data < end)
351         {
352           unsigned int i;
353           for (i = idx_cs; i < nknown_prefixes; ++i)
354             if (known_prefixes[i] == *data)
355               break;
356           if (i == nknown_prefixes)
357             break;
358
359           prefixes |= last_prefix_bit = 1 << i;
360
361           ++data;
362         }
363
364 #ifdef X86_64
365       if (data < end && (*data & 0xf0) == 0x40)
366         prefixes |= ((*data++) & 0xf) | has_rex;
367 #endif
368
369       bufcnt = 0;
370       size_t cnt = 0;
371
372       const uint8_t *curr = match_data;
373       const uint8_t *const match_end = match_data + sizeof (match_data);
374
375       assert (data <= end);
376       if (data == end)
377         {
378           if (prefixes != 0)
379             goto print_prefix;
380
381           retval = -1;
382           goto do_ret;
383         }
384
385     next_match:
386       while (curr < match_end)
387         {
388           uint_fast8_t len = *curr++;
389           uint_fast8_t clen = len >> 4;
390           len &= 0xf;
391           const uint8_t *next_curr = curr + clen + (len - clen) * 2;
392
393           assert (len > 0);
394           assert (curr + clen + 2 * (len - clen) <= match_end);
395
396           const uint8_t *codep = data;
397           int correct_prefix = 0;
398           int opoff = 0;
399
400           if (data > begin && codep[-1] == *curr && clen > 0)
401             {
402               /* We match a prefix byte.  This is exactly one byte and
403                  is matched exactly, without a mask.  */
404               --len;
405               --clen;
406               opoff = 8;
407
408               ++curr;
409
410               assert (last_prefix_bit != 0);
411               correct_prefix = last_prefix_bit;
412             }
413
414           size_t avail = len;
415           while (clen > 0)
416             {
417               if (*codep++ != *curr++)
418                 goto not;
419               --avail;
420               --clen;
421               if (codep == end && avail > 0)
422                 goto do_ret;
423             }
424
425           while (avail > 0)
426             {
427               uint_fast8_t masked = *codep++ & *curr++;
428               if (masked != *curr++)
429                 {
430                 not:
431                   curr = next_curr;
432                   ++cnt;
433                   bufcnt = 0;
434                   goto next_match;
435                 }
436
437               --avail;
438               if (codep == end && avail > 0)
439                 goto do_ret;
440             }
441
442           if (len > end - data)
443             /* There is not enough data for the entire instruction.  The
444                caller can figure this out by looking at the pointer into
445                the input data.  */
446             goto do_ret;
447
448           assert (correct_prefix == 0
449                   || (prefixes & correct_prefix) != 0);
450           prefixes ^= correct_prefix;
451
452           if (0)
453             {
454               /* Resize the buffer.  */
455               char *oldbuf;
456             enomem:
457               oldbuf = buf;
458               if (buf == initbuf)
459                 buf = malloc (2 * bufsize);
460               else
461                 buf = realloc (buf, 2 * bufsize);
462               if (buf == NULL)
463                 {
464                   buf = oldbuf;
465                   retval = ENOMEM;
466                   goto do_ret;
467                 }
468               bufsize *= 2;
469
470               output_data.bufp = buf;
471               output_data.bufsize = bufsize;
472               bufcnt = 0;
473
474               if (data == end)
475                 {
476                   assert (prefixes != 0);
477                   goto print_prefix;
478                 }
479
480               /* gcc is not clever enough to see the following variables
481                  are not used uninitialized.  */
482               asm (""
483                    : "=mr" (opoff), "=mr" (correct_prefix), "=mr" (codep),
484                      "=mr" (next_curr), "=mr" (len));
485             }
486
487           size_t prefix_size = 0;
488
489           // XXXonly print as prefix if valid?
490           if ((prefixes & has_lock) != 0)
491             {
492               ADD_STRING ("lock ");
493               prefix_size += 5;
494             }
495
496           if (instrtab[cnt].rep)
497             {
498               if ((prefixes & has_rep) !=  0)
499                 {
500                   ADD_STRING ("rep ");
501                   prefix_size += 4;
502                 }
503             }
504           else if (instrtab[cnt].repe
505                    && (prefixes & (has_rep | has_repne)) != 0)
506             {
507               if ((prefixes & has_repne) != 0)
508                 {
509                   ADD_STRING ("repne ");
510                   prefix_size += 6;
511                 }
512               else if ((prefixes & has_rep) != 0)
513                 {
514                   ADD_STRING ("repe ");
515                   prefix_size += 5;
516                 }
517             }
518           else if ((prefixes & (has_rep | has_repne)) != 0)
519             {
520               uint_fast8_t byte;
521             print_prefix:
522               bufcnt = 0;
523               byte = *begin;
524               /* This is a prefix byte.  Print it.  */
525               switch (byte)
526                 {
527                 case prefix_rep:
528                   ADD_STRING ("rep");
529                   break;
530                 case prefix_repne:
531                   ADD_STRING ("repne");
532                   break;
533                 case prefix_cs:
534                   ADD_STRING ("cs");
535                   break;
536                 case prefix_ds:
537                   ADD_STRING ("ds");
538                   break;
539                 case prefix_es:
540                   ADD_STRING ("es");
541                   break;
542                 case prefix_fs:
543                   ADD_STRING ("fs");
544                   break;
545                 case prefix_gs:
546                   ADD_STRING ("gs");
547                   break;
548                 case prefix_ss:
549                   ADD_STRING ("ss");
550                   break;
551                 case prefix_data16:
552                   ADD_STRING ("data16");
553                   break;
554                 case prefix_addr16:
555                   ADD_STRING ("addr16");
556                   break;
557                 case prefix_lock:
558                   ADD_STRING ("lock");
559                   break;
560 #ifdef X86_64
561                 case 0x40 ... 0x4f:
562                   ADD_STRING ("rex");
563                   if (byte != 0x40)
564                     {
565                       ADD_CHAR ('.');
566                       if (byte & 0x8)
567                         ADD_CHAR ('w');
568                       if (byte & 0x4)
569                         ADD_CHAR ('r');
570                       if (byte & 0x3)
571                         ADD_CHAR ('x');
572                       if (byte & 0x1)
573                         ADD_CHAR ('b');
574                     }
575                   break;
576 #endif
577                 default:
578                   /* Cannot happen.  */
579                   puts ("unknown prefix");
580                   abort ();
581                 }
582               data = begin + 1;
583               ++addr;
584
585               goto out;
586             }
587
588           /* We have a match.  First determine how many bytes are
589              needed for the adressing mode.  */
590           param_start = codep;
591           if (instrtab[cnt].modrm)
592             {
593               uint_fast8_t modrm = codep[-1];
594
595 #ifndef X86_64
596               if (likely ((prefixes & has_addr16) != 0))
597                 {
598                   /* Account for displacement.  */
599                   if ((modrm & 0xc7) == 6 || (modrm & 0xc0) == 0x80)
600                     param_start += 2;
601                   else if ((modrm & 0xc0) == 0x40)
602                     param_start += 1;
603                 }
604               else
605 #endif
606                 {
607                   /* Account for SIB.  */
608                   if ((modrm & 0xc0) != 0xc0 && (modrm & 0x7) == 0x4)
609                     param_start += 1;
610
611                   /* Account for displacement.  */
612                   if ((modrm & 0xc7) == 5 || (modrm & 0xc0) == 0x80
613                       || ((modrm & 0xc7) == 0x4 && (codep[0] & 0x7) == 0x5))
614                     param_start += 4;
615                   else if ((modrm & 0xc0) == 0x40)
616                     param_start += 1;
617                 }
618
619               if (unlikely (param_start > end))
620                 goto not;
621             }
622
623           output_data.addr = addr + (data - begin);
624           output_data.data = data;
625
626           unsigned long string_end_idx = 0;
627           fmt = save_fmt;
628           const char *deferred_start = NULL;
629           size_t deferred_len = 0;
630           // XXX Can we get this from color.c?
631           static const char color_off[] = "\e[0m";
632           while (*fmt != '\0')
633             {
634               if (*fmt != '%')
635                 {
636                   char ch = *fmt++;
637                   if (ch == '\\')
638                     {
639                       switch ((ch = *fmt++))
640                         {
641                         case '0' ... '7':
642                           {
643                             int val = ch - '0';
644                             ch = *fmt;
645                             if (ch >= '0' && ch <= '7')
646                               {
647                                 val *= 8;
648                                 val += ch - '0';
649                                 ch = *++fmt;
650                                 if (ch >= '0' && ch <= '7' && val < 32)
651                                   {
652                                     val *= 8;
653                                     val += ch - '0';
654                                     ++fmt;
655                                   }
656                               }
657                             ch = val;
658                           }
659                           break;
660
661                         case 'n':
662                           ch = '\n';
663                           break;
664
665                         case 't':
666                           ch = '\t';
667                           break;
668
669                         default:
670                           retval = EINVAL;
671                           goto do_ret;
672                         }
673                     }
674                   else if (ch == '\e' && *fmt == '[')
675                     {
676                       deferred_start = fmt - 1;
677                       do
678                         ++fmt;
679                       while (*fmt != 'm' && *fmt != '\0');
680
681                       if (*fmt == 'm')
682                         {
683                           deferred_len = ++fmt - deferred_start;
684                           continue;
685                         }
686
687                       fmt = deferred_start + 1;
688                       deferred_start = NULL;
689                     }
690                   ADD_CHAR (ch);
691                   continue;
692                 }
693               ++fmt;
694
695               int width = 0;
696               while (isdigit (*fmt))
697                 width = width * 10 + (*fmt++ - '0');
698
699               int prec = 0;
700               if (*fmt == '.')
701                 while (isdigit (*++fmt))
702                   prec = prec * 10 + (*fmt - '0');
703
704               size_t start_idx = bufcnt;
705               size_t non_printing = 0;
706               switch (*fmt++)
707                 {
708                   char mnebuf[16];
709                   const char *str;
710
711                 case 'm':
712                   /* Mnemonic.  */
713
714                   if (unlikely (instrtab[cnt].mnemonic == MNE_INVALID))
715                     {
716                       switch (*data)
717                         {
718 #ifdef X86_64
719                         case 0x90:
720                           if (prefixes & has_rex_b)
721                             goto not;
722                           str = "nop";
723                           break;
724 #endif
725
726                         case 0x98:
727 #ifdef X86_64
728                           if (prefixes == (has_rex_w | has_rex))
729                             {
730                               str = "cltq";
731                               break;
732                             }
733 #endif
734                           if (prefixes & ~has_data16)
735                             goto print_prefix;
736                           str = prefixes & has_data16 ? "cbtw" : "cwtl";
737                           break;
738
739                         case 0x99:
740 #ifdef X86_64
741                           if (prefixes == (has_rex_w | has_rex))
742                             {
743                               str = "cqto";
744                               break;
745                             }
746 #endif
747                           if (prefixes & ~has_data16)
748                             goto print_prefix;
749                           str = prefixes & has_data16 ? "cwtd" : "cltd";
750                           break;
751
752                         case 0xe3:
753                           if (prefixes & ~has_addr16)
754                             goto print_prefix;
755 #ifdef X86_64
756                           str = prefixes & has_addr16 ? "jecxz" : "jrcxz";
757 #else
758                           str = prefixes & has_addr16 ? "jcxz" : "jecxz";
759 #endif
760                           break;
761
762                         case 0x0f:
763                           if (data[1] == 0x0f)
764                             {
765                               /* AMD 3DNOW.  We need one more byte.  */
766                               if (param_start >= end)
767                                 goto not;
768                               if (*param_start < AMD3DNOW_LOW_IDX
769                                   || *param_start > AMD3DNOW_HIGH_IDX)
770                                 goto not;
771                               unsigned int idx
772                                 = amd3dnow[AMD3DNOW_IDX (*param_start)];
773                               if (idx == 0)
774                                 goto not;
775                               str = amd3dnowstr + idx - 1;
776                               /* Eat the immediate byte indicating the
777                                  operation.  */
778                               ++param_start;
779                               break;
780                             }
781 #ifdef X86_64
782                           if (data[1] == 0xc7)
783                             {
784                               str = ((prefixes & has_rex_w)
785                                      ? "cmpxchg16b" : "cmpxchg8b");
786                               break;
787                             }
788 #endif
789                           if (data[1] == 0xc2)
790                             {
791                               if (param_start >= end)
792                                 goto not;
793                               if (*param_start > 7)
794                                 goto not;
795                               static const char cmpops[][9] =
796                                 {
797                                   [0] = "cmpeq",
798                                   [1] = "cmplt",
799                                   [2] = "cmple",
800                                   [3] = "cmpunord",
801                                   [4] = "cmpneq",
802                                   [5] = "cmpnlt",
803                                   [6] = "cmpnle",
804                                   [7] = "cmpord"
805                                 };
806                               char *cp = stpcpy (mnebuf, cmpops[*param_start]);
807                               if (correct_prefix & (has_rep | has_repne))
808                                 *cp++ = 's';
809                               else
810                                 *cp++ = 'p';
811                               if (correct_prefix & (has_data16 | has_repne))
812                                 *cp++ = 'd';
813                               else
814                                 *cp++ = 's';
815                               *cp = '\0';
816                               str = mnebuf;
817                               /* Eat the immediate byte indicating the
818                                  operation.  */
819                               ++param_start;
820                               break;
821                             }
822
823                         default:
824                           assert (! "INVALID not handled");
825                         }
826                     }
827                   else
828                     str = mnestr.str + mneidx[instrtab[cnt].mnemonic];
829
830                   if (deferred_start != NULL)
831                     {
832                       ADD_NSTRING (deferred_start, deferred_len);
833                       non_printing += deferred_len;
834                     }
835
836                   ADD_STRING (str);
837
838                   switch (instrtab[cnt].suffix)
839                     {
840                     case suffix_none:
841                       break;
842
843                     case suffix_w:
844                       if ((codep[-1] & 0xc0) != 0xc0)
845                         {
846                           char ch;
847
848                           if (data[0] & 1)
849                             {
850                               if (prefixes & has_data16)
851                                 ch = 'w';
852 #ifdef X86_64
853                               else if (prefixes & has_rex_w)
854                                 ch = 'q';
855 #endif
856                               else
857                                 ch = 'l';
858                             }
859                           else
860                             ch = 'b';
861
862                           ADD_CHAR (ch);
863                         }
864                       break;
865
866                     case suffix_w0:
867                       if ((codep[-1] & 0xc0) != 0xc0)
868                         ADD_CHAR ('l');
869                       break;
870
871                     case suffix_w1:
872                       if ((data[0] & 0x4) == 0)
873                         ADD_CHAR ('l');
874                       break;
875
876                     case suffix_W:
877                       if (prefixes & has_data16)
878                         {
879                           ADD_CHAR ('w');
880                           prefixes &= ~has_data16;
881                         }
882 #ifdef X86_64
883                       else
884                         ADD_CHAR ('q');
885 #endif
886                       break;
887
888                     case suffix_W1:
889                       if (prefixes & has_data16)
890                         {
891                           ADD_CHAR ('w');
892                           prefixes &= ~has_data16;
893                         }
894 #ifdef X86_64
895                       else if (prefixes & has_rex_w)
896                         ADD_CHAR ('q');
897 #endif
898                       break;
899
900                     case suffix_tttn:;
901                       static const char tttn[16][3] =
902                         {
903                           "o", "no", "b", "ae", "e", "ne", "be", "a",
904                           "s", "ns", "p", "np", "l", "ge", "le", "g"
905                         };
906                       ADD_STRING (tttn[codep[-1 - instrtab[cnt].modrm] & 0x0f]);
907                       break;
908
909                     case suffix_D:
910                       if ((codep[-1] & 0xc0) != 0xc0)
911                         ADD_CHAR ((data[0] & 0x04) == 0 ? 's' : 'l');
912                       break;
913
914                     default:
915                       printf("unknown suffix %d\n", instrtab[cnt].suffix);
916                       abort ();
917                     }
918
919                   if (deferred_start != NULL)
920                     {
921                       ADD_STRING (color_off);
922                       non_printing += strlen (color_off);
923                     }
924
925                   string_end_idx = bufcnt;
926                   break;
927
928                 case 'o':
929                   if (prec == 1 && instrtab[cnt].fct1 != 0)
930                     {
931                       /* First parameter.  */
932                       if (deferred_start != NULL)
933                         {
934                           ADD_NSTRING (deferred_start, deferred_len);
935                           non_printing += deferred_len;
936                         }
937
938                       if (instrtab[cnt].str1 != 0)
939                         ADD_STRING (op1_str
940                                     + op1_str_idx[instrtab[cnt].str1 - 1]);
941
942                       output_data.opoff1 = (instrtab[cnt].off1_1
943                                             + OFF1_1_BIAS - opoff);
944                       output_data.opoff2 = (instrtab[cnt].off1_2
945                                             + OFF1_2_BIAS - opoff);
946                       output_data.opoff3 = (instrtab[cnt].off1_3
947                                             + OFF1_3_BIAS - opoff);
948                       int r = op1_fct[instrtab[cnt].fct1] (&output_data);
949                       if (r < 0)
950                         goto not;
951                       if (r > 0)
952                         goto enomem;
953
954                       if (deferred_start != NULL)
955                         {
956                           ADD_STRING (color_off);
957                           non_printing += strlen (color_off);
958                         }
959
960                       string_end_idx = bufcnt;
961                     }
962                   else if (prec == 2 && instrtab[cnt].fct2 != 0)
963                     {
964                       /* Second parameter.  */
965                       if (deferred_start != NULL)
966                         {
967                           ADD_NSTRING (deferred_start, deferred_len);
968                           non_printing += deferred_len;
969                         }
970
971                       if (instrtab[cnt].str2 != 0)
972                         ADD_STRING (op2_str
973                                     + op2_str_idx[instrtab[cnt].str2 - 1]);
974
975                       output_data.opoff1 = (instrtab[cnt].off2_1
976                                             + OFF2_1_BIAS - opoff);
977                       output_data.opoff2 = (instrtab[cnt].off2_2
978                                             + OFF2_2_BIAS - opoff);
979                       output_data.opoff3 = (instrtab[cnt].off2_3
980                                             + OFF2_3_BIAS - opoff);
981                       int r = op2_fct[instrtab[cnt].fct2] (&output_data);
982                       if (r < 0)
983                         goto not;
984                       if (r > 0)
985                         goto enomem;
986
987                       if (deferred_start != NULL)
988                         {
989                           ADD_STRING (color_off);
990                           non_printing += strlen (color_off);
991                         }
992
993                       string_end_idx = bufcnt;
994                     }
995                   else if (prec == 3 && instrtab[cnt].fct3 != 0)
996                     {
997                       /* Third parameter.  */
998                       if (deferred_start != NULL)
999                         {
1000                           ADD_NSTRING (deferred_start, deferred_len);
1001                           non_printing += deferred_len;
1002                         }
1003
1004                       if (instrtab[cnt].str3 != 0)
1005                         ADD_STRING (op3_str
1006                                     + op3_str_idx[instrtab[cnt].str3 - 1]);
1007
1008                       output_data.opoff1 = (instrtab[cnt].off3_1
1009                                             + OFF3_1_BIAS - opoff);
1010                       output_data.opoff2 = (instrtab[cnt].off3_2
1011                                             + OFF3_2_BIAS - opoff);
1012 #ifdef OFF3_3_BITS
1013                       output_data.opoff3 = (instrtab[cnt].off3_3
1014                                             + OFF3_3_BIAS - opoff);
1015 #else
1016                       output_data.opoff3 = 0;
1017 #endif
1018                       int r = op3_fct[instrtab[cnt].fct3] (&output_data);
1019                       if (r < 0)
1020                         goto not;
1021                       if (r > 0)
1022                         goto enomem;
1023
1024                       if (deferred_start != NULL)
1025                         {
1026                           ADD_STRING (color_off);
1027                           non_printing += strlen (color_off);
1028                         }
1029
1030                       string_end_idx = bufcnt;
1031                     }
1032                   else
1033                     bufcnt = string_end_idx;
1034                   break;
1035
1036                 case 'e':
1037                   string_end_idx = bufcnt;
1038                   break;
1039
1040                 case 'a':
1041                   /* Pad to requested column.  */
1042                   while (bufcnt - non_printing < (size_t) width)
1043                     ADD_CHAR (' ');
1044                   width = 0;
1045                   break;
1046
1047                 case 'l':
1048                   if (deferred_start != NULL)
1049                     {
1050                       ADD_NSTRING (deferred_start, deferred_len);
1051                       non_printing += deferred_len;
1052                     }
1053
1054                   if (output_data.labelbuf != NULL
1055                       && output_data.labelbuf[0] != '\0')
1056                     {
1057                       ADD_STRING (output_data.labelbuf);
1058                       output_data.labelbuf[0] = '\0';
1059                       string_end_idx = bufcnt;
1060                     }
1061                   else if (output_data.symaddr_use != addr_none)
1062                     {
1063                       GElf_Addr symaddr = output_data.symaddr;
1064                       if (output_data.symaddr_use >= addr_rel_symbolic)
1065                         symaddr += addr + param_start - begin;
1066
1067                       // XXX Lookup symbol based on symaddr
1068                       const char *symstr = NULL;
1069                       if (symcb != NULL
1070                           && symcb (0 /* XXX */, 0 /* XXX */, symaddr,
1071                                     &output_data.labelbuf,
1072                                     &output_data.labelbufsize, symcbarg) == 0)
1073                         symstr = output_data.labelbuf;
1074
1075                       size_t bufavail = bufsize - bufcnt;
1076                       int r = 0;
1077                       if (symstr != NULL)
1078                         r = snprintf (&buf[bufcnt], bufavail, "# <%s>",
1079                                       symstr);
1080                       else if (output_data.symaddr_use == addr_abs_always
1081                                || output_data.symaddr_use == addr_rel_always)
1082                         r = snprintf (&buf[bufcnt], bufavail, "# %#" PRIx64,
1083                                       (uint64_t) symaddr);
1084
1085                       assert (r >= 0);
1086                       if ((size_t) r >= bufavail)
1087                         goto enomem;
1088                       bufcnt += r;
1089                       string_end_idx = bufcnt;
1090
1091                       output_data.symaddr_use = addr_none;
1092                     }
1093                   if (deferred_start != NULL)
1094                     {
1095                       ADD_STRING (color_off);
1096                       non_printing += strlen (color_off);
1097                     }
1098                   break;
1099
1100                 default:
1101                   abort ();
1102                 }
1103
1104               deferred_start = NULL;
1105
1106               /* Pad according to the specified width.  */
1107               while (bufcnt + prefix_size - non_printing < start_idx + width)
1108                 ADD_CHAR (' ');
1109               prefix_size = 0;
1110             }
1111
1112           if ((prefixes & SEGMENT_PREFIXES) != 0)
1113             goto print_prefix;
1114
1115           assert (string_end_idx != ~0ul);
1116           bufcnt = string_end_idx;
1117
1118           addr += param_start - begin;
1119           data = param_start;
1120
1121           goto out;
1122         }
1123
1124       /* Invalid (or at least unhandled) opcode.  */
1125       if (prefixes != 0)
1126         goto print_prefix;
1127       assert (*startp == data);
1128       ++data;
1129       ADD_STRING ("(bad)");
1130       addr += data - begin;
1131
1132     out:
1133       if (bufcnt == bufsize)
1134         goto enomem;
1135       buf[bufcnt] = '\0';
1136
1137       *startp = data;
1138       retval = outcb (buf, bufcnt, outcbarg);
1139       if (retval != 0)
1140         goto do_ret;
1141     }
1142
1143  do_ret:
1144   free (output_data.labelbuf);
1145   if (buf != initbuf)
1146     free (buf);
1147
1148   return retval;
1149 }