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
58static 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.  */
77enum
78  {
79#define MNE(name) MNE_##name,
80#include MNEFILE
81#undef MNE
82    MNE_INVALID
83  };
84
85static 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
94enum
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
114enum
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
151static 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
171static 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
190static 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)
233static 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
257struct 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
315int
316i386_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}
1150