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