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
55static 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.  */
74enum
75  {
76#define MNE(name) MNE_##name,
77#include MNEFILE
78#undef MNE
79    MNE_INVALID
80  };
81
82static 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
91enum
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
111enum
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
148static 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
168static 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
187static 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)
230static 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
254struct 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
312int
313i386_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}
1147